]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
Merge tag 'powerpc-5.2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 19 May 2019 17:10:15 +0000 (10:10 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 19 May 2019 17:10:15 +0000 (10:10 -0700)
Pull powerpc fixes from Michael Ellerman:
 "One fix going back to stable, for a bug on 32-bit introduced when we
  added support for THREAD_INFO_IN_TASK.

  A fix for a typo in a recent rework of our hugetlb code that leads to
  crashes on 64-bit when using hugetlbfs with a 4K PAGE_SIZE.

  Two fixes for our recent rework of the address layout on 64-bit hash
  CPUs, both only triggered when userspace tries to access addresses
  outside the user or kernel address ranges.

  Finally a fix for a recently introduced double free in an error path
  in our cacheinfo code.

  Thanks to: Aneesh Kumar K.V, Christophe Leroy, Sachin Sant, Tobin C.
  Harding"

* tag 'powerpc-5.2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  powerpc/cacheinfo: Remove double free
  powerpc/mm/hash: Fix get_region_id() for invalid addresses
  powerpc/mm: Drop VM_BUG_ON in get_region_id()
  powerpc/mm: Fix crashes with hugepages & 4K pages
  powerpc/32s: fix flush_hash_pages() on SMP

2969 files changed:
Documentation/ABI/testing/debugfs-wilco-ec
Documentation/ABI/testing/sysfs-class-power
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/accounting/psi.txt
Documentation/admin-guide/hw-vuln/index.rst [new file with mode: 0644]
Documentation/admin-guide/hw-vuln/l1tf.rst [new file with mode: 0644]
Documentation/admin-guide/hw-vuln/mds.rst [new file with mode: 0644]
Documentation/admin-guide/index.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/l1tf.rst [deleted file]
Documentation/arm64/perf.txt [new file with mode: 0644]
Documentation/arm64/pointer-authentication.txt
Documentation/core-api/kernel-api.rst
Documentation/dev-tools/gcov.rst
Documentation/device-mapper/dm-dust.txt [new file with mode: 0644]
Documentation/device-mapper/dm-integrity.txt
Documentation/devicetree/bindings/arm/altera/socfpga-system.txt
Documentation/devicetree/bindings/arm/amlogic.txt
Documentation/devicetree/bindings/arm/atmel-sysregs.txt
Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt
Documentation/devicetree/bindings/arm/fsl.yaml
Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/omap/omap.txt
Documentation/devicetree/bindings/arm/rockchip.yaml
Documentation/devicetree/bindings/arm/stm32/stm32-syscon.txt
Documentation/devicetree/bindings/arm/sunxi.txt [deleted file]
Documentation/devicetree/bindings/arm/sunxi.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/bus/ti-sysc.txt
Documentation/devicetree/bindings/clock/xlnx,zynqmp-clk.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
Documentation/devicetree/bindings/firmware/intel,ixp4xx-network-processing-engine.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.txt
Documentation/devicetree/bindings/fpga/xlnx,zynqmp-pcap-fpga.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
Documentation/devicetree/bindings/gpu/arm,mali-midgard.txt
Documentation/devicetree/bindings/hwmon/pwm-fan.txt
Documentation/devicetree/bindings/iio/adc/imx7d-adc.txt
Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.txt
Documentation/devicetree/bindings/input/gpio-vibrator.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/input/lpc32xx-key.txt
Documentation/devicetree/bindings/input/max77650-onkey.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/microchip,qt1050.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
Documentation/devicetree/bindings/input/touchscreen/goodix.txt
Documentation/devicetree/bindings/input/touchscreen/iqs5xx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/mediatek,sysirq.txt
Documentation/devicetree/bindings/leds/backlight/lm3630a-backlight.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/leds/leds-max77650.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mailbox/marvell,armada-3700-rwtm-mailbox.txt [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/atmel,ebi.txt
Documentation/devicetree/bindings/memory-controllers/fsl/mmdc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt
Documentation/devicetree/bindings/mfd/cirrus,lochnagar.txt
Documentation/devicetree/bindings/mfd/max77620.txt
Documentation/devicetree/bindings/mfd/max77650.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/stmfx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/ti-lmu.txt
Documentation/devicetree/bindings/misc/intel,ixp4xx-queue-manager.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/atmel-nand.txt
Documentation/devicetree/bindings/mtd/denali-nand.txt
Documentation/devicetree/bindings/mtd/ingenic,jz4780-nand.txt
Documentation/devicetree/bindings/mtd/mtd-physmap.txt
Documentation/devicetree/bindings/mtd/nand-controller.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/nand.txt [deleted file]
Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/partitions/brcm,bcm963xx-cfe-nor-partitions.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/partitions/brcm,bcm963xx-imagetag.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/sunxi-nand.txt [deleted file]
Documentation/devicetree/bindings/net/keystone-netcp.txt
Documentation/devicetree/bindings/net/wireless/mediatek,mt76.txt
Documentation/devicetree/bindings/pci/designware-pcie.txt
Documentation/devicetree/bindings/pci/pci-keystone.txt
Documentation/devicetree/bindings/pci/pci.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-stmfx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/power/amlogic,meson-gx-pwrc.txt
Documentation/devicetree/bindings/power/reset/syscon-reboot.txt
Documentation/devicetree/bindings/power/supply/axp20x_usb_power.txt
Documentation/devicetree/bindings/power/supply/gpio-charger.txt
Documentation/devicetree/bindings/power/supply/ingenic,battery.txt [new file with mode: 0644]
Documentation/devicetree/bindings/power/supply/lt3651-charger.txt [new file with mode: 0644]
Documentation/devicetree/bindings/power/supply/ltc3651-charger.txt [deleted file]
Documentation/devicetree/bindings/power/supply/max77650-charger.txt [new file with mode: 0644]
Documentation/devicetree/bindings/power/supply/microchip,ucs1002.txt [new file with mode: 0644]
Documentation/devicetree/bindings/power/supply/olpc_battery.txt
Documentation/devicetree/bindings/pps/pps-gpio.txt
Documentation/devicetree/bindings/pwm/imx-tpm-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pwm-meson.txt
Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt
Documentation/devicetree/bindings/riscv/sifive-l2-cache.txt [new file with mode: 0644]
Documentation/devicetree/bindings/serial/mtk-uart.txt
Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
Documentation/devicetree/bindings/thermal/amazon,al-thermal.txt [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt
Documentation/devicetree/bindings/thermal/qcom-tsens.txt
Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
Documentation/devicetree/bindings/thermal/thermal-generic-adc.txt
Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
Documentation/devicetree/bindings/vendor-prefixes.txt [deleted file]
Documentation/devicetree/bindings/vendor-prefixes.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/fsl-imx-sc-wdt.txt [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/mtk-wdt.txt
Documentation/driver-api/gpio/driver.rst
Documentation/filesystems/autofs-mount-control.txt
Documentation/filesystems/autofs.txt
Documentation/firmware-guide/acpi/dsd/data-node-references.rst
Documentation/firmware-guide/acpi/dsd/graph.rst
Documentation/gpio/index.rst [new file with mode: 0644]
Documentation/gpio/sysfs.rst [new file with mode: 0644]
Documentation/gpio/sysfs.txt [deleted file]
Documentation/index.rst
Documentation/media/uapi/v4l/field-order.rst
Documentation/networking/rxrpc.txt
Documentation/sysctl/vm.txt
Documentation/trace/ftrace.rst
Documentation/trace/histogram.rst
Documentation/trace/postprocess/trace-vmscan-postprocess.pl
Documentation/translations/it_IT/process/license-rules.rst
Documentation/virtual/kvm/api.txt
Documentation/virtual/kvm/devices/vm.txt
Documentation/virtual/kvm/devices/xive.txt [new file with mode: 0644]
Documentation/vm/hmm.rst
Documentation/x86/amd-memory-encryption.rst [new file with mode: 0644]
Documentation/x86/amd-memory-encryption.txt [deleted file]
Documentation/x86/boot.rst [new file with mode: 0644]
Documentation/x86/boot.txt [deleted file]
Documentation/x86/conf.py [new file with mode: 0644]
Documentation/x86/earlyprintk.rst [new file with mode: 0644]
Documentation/x86/earlyprintk.txt [deleted file]
Documentation/x86/entry_64.rst [new file with mode: 0644]
Documentation/x86/entry_64.txt [deleted file]
Documentation/x86/exception-tables.rst [new file with mode: 0644]
Documentation/x86/exception-tables.txt [deleted file]
Documentation/x86/i386/IO-APIC.rst [new file with mode: 0644]
Documentation/x86/i386/IO-APIC.txt [deleted file]
Documentation/x86/i386/index.rst [new file with mode: 0644]
Documentation/x86/index.rst [new file with mode: 0644]
Documentation/x86/intel_mpx.rst [new file with mode: 0644]
Documentation/x86/intel_mpx.txt [deleted file]
Documentation/x86/kernel-stacks [deleted file]
Documentation/x86/kernel-stacks.rst [new file with mode: 0644]
Documentation/x86/mds.rst [new file with mode: 0644]
Documentation/x86/microcode.rst [new file with mode: 0644]
Documentation/x86/microcode.txt [deleted file]
Documentation/x86/mtrr.rst [new file with mode: 0644]
Documentation/x86/mtrr.txt [deleted file]
Documentation/x86/orc-unwinder.rst [new file with mode: 0644]
Documentation/x86/orc-unwinder.txt [deleted file]
Documentation/x86/pat.rst [new file with mode: 0644]
Documentation/x86/pat.txt [deleted file]
Documentation/x86/protection-keys.rst [new file with mode: 0644]
Documentation/x86/protection-keys.txt [deleted file]
Documentation/x86/pti.rst [new file with mode: 0644]
Documentation/x86/pti.txt [deleted file]
Documentation/x86/resctrl_ui.rst [new file with mode: 0644]
Documentation/x86/resctrl_ui.txt [deleted file]
Documentation/x86/tlb.rst [new file with mode: 0644]
Documentation/x86/tlb.txt [deleted file]
Documentation/x86/topology.rst [new file with mode: 0644]
Documentation/x86/topology.txt [deleted file]
Documentation/x86/usb-legacy-support.rst [new file with mode: 0644]
Documentation/x86/usb-legacy-support.txt [deleted file]
Documentation/x86/x86_64/5level-paging.rst [new file with mode: 0644]
Documentation/x86/x86_64/5level-paging.txt [deleted file]
Documentation/x86/x86_64/boot-options.rst [new file with mode: 0644]
Documentation/x86/x86_64/boot-options.txt [deleted file]
Documentation/x86/x86_64/cpu-hotplug-spec [deleted file]
Documentation/x86/x86_64/cpu-hotplug-spec.rst [new file with mode: 0644]
Documentation/x86/x86_64/fake-numa-for-cpusets [deleted file]
Documentation/x86/x86_64/fake-numa-for-cpusets.rst [new file with mode: 0644]
Documentation/x86/x86_64/index.rst [new file with mode: 0644]
Documentation/x86/x86_64/machinecheck [deleted file]
Documentation/x86/x86_64/machinecheck.rst [new file with mode: 0644]
Documentation/x86/x86_64/mm.rst [new file with mode: 0644]
Documentation/x86/x86_64/mm.txt [deleted file]
Documentation/x86/x86_64/uefi.rst [new file with mode: 0644]
Documentation/x86/x86_64/uefi.txt [deleted file]
Documentation/x86/zero-page.rst [new file with mode: 0644]
Documentation/x86/zero-page.txt [deleted file]
Documentation/xilinx/eemi.txt
MAINTAINERS
arch/Kconfig
arch/alpha/include/asm/segment.h [deleted file]
arch/alpha/kernel/smc37c669.c
arch/alpha/kernel/smc37c93x.c
arch/alpha/kernel/syscalls/syscall.tbl
arch/alpha/mm/init.c
arch/arc/include/asm/uaccess.h
arch/arc/mm/init.c
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/Makefile
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/am335x-baltos-ir2110.dts
arch/arm/boot/dts/am335x-baltos-ir3220.dts
arch/arm/boot/dts/am335x-baltos-ir5221.dts
arch/arm/boot/dts/am335x-baltos-leds.dtsi
arch/arm/boot/dts/am335x-baltos.dtsi
arch/arm/boot/dts/am335x-base0033.dts
arch/arm/boot/dts/am335x-bone-common.dtsi
arch/arm/boot/dts/am335x-boneblack-common.dtsi
arch/arm/boot/dts/am335x-boneblack-wireless.dts
arch/arm/boot/dts/am335x-boneblue.dts
arch/arm/boot/dts/am335x-bonegreen-common.dtsi
arch/arm/boot/dts/am335x-bonegreen-wireless.dts
arch/arm/boot/dts/am335x-chiliboard.dts
arch/arm/boot/dts/am335x-chilisom.dtsi
arch/arm/boot/dts/am335x-cm-t335.dts
arch/arm/boot/dts/am335x-evm.dts
arch/arm/boot/dts/am335x-evmsk.dts
arch/arm/boot/dts/am335x-icev2.dts
arch/arm/boot/dts/am335x-igep0033.dtsi
arch/arm/boot/dts/am335x-lxm.dts
arch/arm/boot/dts/am335x-moxa-uc-2100-common.dtsi
arch/arm/boot/dts/am335x-moxa-uc-2101.dts
arch/arm/boot/dts/am335x-moxa-uc-8100-me-t.dts
arch/arm/boot/dts/am335x-nano.dts
arch/arm/boot/dts/am335x-osd3358-sm-red.dts
arch/arm/boot/dts/am335x-osd335x-common.dtsi
arch/arm/boot/dts/am335x-pcm-953.dtsi
arch/arm/boot/dts/am335x-pdu001.dts
arch/arm/boot/dts/am335x-pepper.dts
arch/arm/boot/dts/am335x-phycore-som.dtsi
arch/arm/boot/dts/am335x-pocketbeagle.dts
arch/arm/boot/dts/am335x-sancloud-bbe.dts
arch/arm/boot/dts/am335x-sbc-t335.dts
arch/arm/boot/dts/am335x-shc.dts
arch/arm/boot/dts/am335x-sl50.dts
arch/arm/boot/dts/am335x-wega.dtsi
arch/arm/boot/dts/am43x-epos-evm.dts
arch/arm/boot/dts/am5718.dtsi [new file with mode: 0644]
arch/arm/boot/dts/am571x-idk.dts
arch/arm/boot/dts/am5728.dtsi [new file with mode: 0644]
arch/arm/boot/dts/am572x-idk.dts
arch/arm/boot/dts/am5748.dtsi [new file with mode: 0644]
arch/arm/boot/dts/am574x-idk.dts
arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
arch/arm/boot/dts/am57xx-cl-som-am57x.dts
arch/arm/boot/dts/armada-38x.dtsi
arch/arm/boot/dts/aspeed-ast2500-evb.dts
arch/arm/boot/dts/aspeed-bmc-facebook-cmm.dts
arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.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-witherspoon.dts
arch/arm/boot/dts/aspeed-g4.dtsi
arch/arm/boot/dts/aspeed-g5.dtsi
arch/arm/boot/dts/at91-sama5d27_som1.dtsi
arch/arm/boot/dts/at91-sama5d27_som1_ek.dts
arch/arm/boot/dts/at91-sama5d2_xplained.dts
arch/arm/boot/dts/at91-sama5d4_xplained.dts
arch/arm/boot/dts/at91-sama5d4ek.dts
arch/arm/boot/dts/at91-vinco.dts
arch/arm/boot/dts/at91sam9260ek.dts
arch/arm/boot/dts/at91sam9xe.dtsi
arch/arm/boot/dts/axp81x.dtsi
arch/arm/boot/dts/dra7-l4.dtsi
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/emev2-kzm9d.dts
arch/arm/boot/dts/exynos3250.dtsi
arch/arm/boot/dts/exynos4.dtsi
arch/arm/boot/dts/exynos4210-origen.dts
arch/arm/boot/dts/exynos4210-smdkv310.dts
arch/arm/boot/dts/exynos4210-trats.dts
arch/arm/boot/dts/exynos4210-universal_c210.dts
arch/arm/boot/dts/exynos4412-odroidu3.dts
arch/arm/boot/dts/exynos4412-origen.dts
arch/arm/boot/dts/exynos4412-smdk4412.dts
arch/arm/boot/dts/exynos4412-trats2.dts
arch/arm/boot/dts/exynos4412.dtsi
arch/arm/boot/dts/exynos5250-smdk5250.dts
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/boot/dts/exynos5260-pinctrl.dtsi
arch/arm/boot/dts/exynos5260-xyref5260.dts
arch/arm/boot/dts/exynos5260.dtsi
arch/arm/boot/dts/exynos5410-odroidxu.dts
arch/arm/boot/dts/exynos5410-smdk5410.dts
arch/arm/boot/dts/exynos5420-arndale-octa.dts
arch/arm/boot/dts/exynos5420-smdk5420.dts
arch/arm/boot/dts/exynos5420.dtsi
arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi
arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
arch/arm/boot/dts/exynos54xx.dtsi
arch/arm/boot/dts/gemini-dlink-dir-685.dts
arch/arm/boot/dts/imx35.dtsi
arch/arm/boot/dts/imx50-kobo-aura.dts [new file with mode: 0644]
arch/arm/boot/dts/imx50.dtsi
arch/arm/boot/dts/imx51-zii-rdu1.dts
arch/arm/boot/dts/imx51.dtsi
arch/arm/boot/dts/imx53-m53.dtsi
arch/arm/boot/dts/imx53-m53menlo.dts [new file with mode: 0644]
arch/arm/boot/dts/imx53.dtsi
arch/arm/boot/dts/imx6-logicpd-baseboard.dtsi
arch/arm/boot/dts/imx6dl-eckelmann-ci4x10.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6dl-riotboard.dts
arch/arm/boot/dts/imx6dl-sabreauto.dts
arch/arm/boot/dts/imx6q-ba16.dtsi
arch/arm/boot/dts/imx6q-gw54xx.dts
arch/arm/boot/dts/imx6q-logicpd.dts
arch/arm/boot/dts/imx6q-marsboard.dts
arch/arm/boot/dts/imx6q-tbs2910.dts
arch/arm/boot/dts/imx6q-zii-rdu2.dts
arch/arm/boot/dts/imx6qdl-apf6.dtsi
arch/arm/boot/dts/imx6qdl-emcon.dtsi
arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
arch/arm/boot/dts/imx6qdl-gw551x.dtsi
arch/arm/boot/dts/imx6qdl-gw5903.dtsi
arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
arch/arm/boot/dts/imx6qdl-sabresd.dtsi
arch/arm/boot/dts/imx6qdl-sr-som.dtsi
arch/arm/boot/dts/imx6qdl-var-dart.dtsi
arch/arm/boot/dts/imx6qdl-wandboard.dtsi
arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi
arch/arm/boot/dts/imx6qdl.dtsi
arch/arm/boot/dts/imx6qp-zii-rdu2.dts
arch/arm/boot/dts/imx6sl.dtsi
arch/arm/boot/dts/imx6sll.dtsi
arch/arm/boot/dts/imx6sx-sabreauto.dts
arch/arm/boot/dts/imx6sx-sdb.dtsi
arch/arm/boot/dts/imx6sx.dtsi
arch/arm/boot/dts/imx6ul.dtsi
arch/arm/boot/dts/imx7-mba7.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx7-tqma7.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx7d-mba7.dts [new file with mode: 0644]
arch/arm/boot/dts/imx7d-pico.dtsi
arch/arm/boot/dts/imx7d-tqma7.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx7d-zii-rpu2.dts [new file with mode: 0644]
arch/arm/boot/dts/imx7d.dtsi
arch/arm/boot/dts/imx7s-mba7.dts [new file with mode: 0644]
arch/arm/boot/dts/imx7s-tqma7.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx7s-warp.dts
arch/arm/boot/dts/imx7s.dtsi
arch/arm/boot/dts/imx7ulp.dtsi
arch/arm/boot/dts/intel-ixp42x-linksys-nslu2.dts [new file with mode: 0644]
arch/arm/boot/dts/intel-ixp42x.dtsi [new file with mode: 0644]
arch/arm/boot/dts/intel-ixp43x-gateworks-gw2358.dts [new file with mode: 0644]
arch/arm/boot/dts/intel-ixp43x.dtsi [new file with mode: 0644]
arch/arm/boot/dts/intel-ixp45x-ixp46x.dtsi [new file with mode: 0644]
arch/arm/boot/dts/intel-ixp4xx.dtsi [new file with mode: 0644]
arch/arm/boot/dts/lpc3250-ea3250.dts
arch/arm/boot/dts/lpc3250-phy3250.dts
arch/arm/boot/dts/lpc32xx.dtsi
arch/arm/boot/dts/ls1021a-moxa-uc-8410a.dts
arch/arm/boot/dts/ls1021a-qds.dts
arch/arm/boot/dts/ls1021a-twr.dts
arch/arm/boot/dts/ls1021a.dtsi
arch/arm/boot/dts/meson.dtsi
arch/arm/boot/dts/meson8.dtsi
arch/arm/boot/dts/meson8b-ec100.dts
arch/arm/boot/dts/meson8b-odroidc1.dts
arch/arm/boot/dts/meson8b.dtsi
arch/arm/boot/dts/omap2420-n810.dts
arch/arm/boot/dts/omap4-duovero.dtsi
arch/arm/boot/dts/omap4-l4-abe.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap4-mcpdm.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap4-panda-common.dtsi
arch/arm/boot/dts/omap4-sdp.dts
arch/arm/boot/dts/omap4-var-som-om44.dtsi
arch/arm/boot/dts/omap4.dtsi
arch/arm/boot/dts/omap5-board-common.dtsi
arch/arm/boot/dts/omap5-l4-abe.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/qcom-apq8064.dtsi
arch/arm/boot/dts/qcom-ipq4019.dtsi
arch/arm/boot/dts/qcom-mdm9615.dtsi
arch/arm/boot/dts/qcom-msm8660.dtsi
arch/arm/boot/dts/qcom-pma8084.dtsi
arch/arm/boot/dts/r7s72100-rskrza1.dts
arch/arm/boot/dts/r8a73a4-ape6evm.dts
arch/arm/boot/dts/r8a77470-iwg23s-sbc.dts
arch/arm/boot/dts/r8a77470.dtsi
arch/arm/boot/dts/r8a7778-bockw.dts
arch/arm/boot/dts/r8a7779-marzen.dts
arch/arm/boot/dts/r8a7792-blanche.dts
arch/arm/boot/dts/r8a7792.dtsi
arch/arm/boot/dts/r8a7794-alt.dts
arch/arm/boot/dts/rk3036-kylin.dts
arch/arm/boot/dts/rk3036.dtsi
arch/arm/boot/dts/rk3066a-marsboard.dts
arch/arm/boot/dts/rk3066a-mk808.dts
arch/arm/boot/dts/rk3066a-rayeager.dts
arch/arm/boot/dts/rk3066a.dtsi
arch/arm/boot/dts/rk3188-px3-evb.dts
arch/arm/boot/dts/rk3188-radxarock.dts
arch/arm/boot/dts/rk3188.dtsi
arch/arm/boot/dts/rk322x.dtsi
arch/arm/boot/dts/rk3288-evb-act8846.dts
arch/arm/boot/dts/rk3288-evb.dtsi
arch/arm/boot/dts/rk3288-fennec.dts
arch/arm/boot/dts/rk3288-firefly-beta.dts
arch/arm/boot/dts/rk3288-firefly-reload-core.dtsi
arch/arm/boot/dts/rk3288-firefly-reload.dts
arch/arm/boot/dts/rk3288-firefly.dts
arch/arm/boot/dts/rk3288-firefly.dtsi
arch/arm/boot/dts/rk3288-miqi.dts
arch/arm/boot/dts/rk3288-phycore-rdk.dts
arch/arm/boot/dts/rk3288-phycore-som.dtsi
arch/arm/boot/dts/rk3288-r89.dts
arch/arm/boot/dts/rk3288-rock2-som.dtsi
arch/arm/boot/dts/rk3288-rock2-square.dts
arch/arm/boot/dts/rk3288-tinker-s.dts
arch/arm/boot/dts/rk3288-tinker.dtsi
arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi
arch/arm/boot/dts/rk3288-veyron-brain.dts
arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
arch/arm/boot/dts/rk3288-veyron-jaq.dts
arch/arm/boot/dts/rk3288-veyron-jerry.dts
arch/arm/boot/dts/rk3288-veyron-mickey.dts
arch/arm/boot/dts/rk3288-veyron-mighty.dts [new file with mode: 0644]
arch/arm/boot/dts/rk3288-veyron-minnie.dts
arch/arm/boot/dts/rk3288-veyron-pinky.dts
arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi
arch/arm/boot/dts/rk3288-veyron-speedy.dts
arch/arm/boot/dts/rk3288-veyron.dtsi
arch/arm/boot/dts/rk3288-vyasa.dts
arch/arm/boot/dts/rk3288.dtsi
arch/arm/boot/dts/rv1108-elgin-r1.dts
arch/arm/boot/dts/rv1108.dtsi
arch/arm/boot/dts/s5pv210-goni.dts
arch/arm/boot/dts/s5pv210.dtsi
arch/arm/boot/dts/sama5d2.dtsi
arch/arm/boot/dts/sama5d36ek_cmp.dts
arch/arm/boot/dts/sama5d3xcm_cmp.dtsi
arch/arm/boot/dts/sama5d3xmb_cmp.dtsi
arch/arm/boot/dts/sama5d4.dtsi
arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts
arch/arm/boot/dts/ste-dbx5x0.dtsi
arch/arm/boot/dts/ste-href-stuib.dtsi
arch/arm/boot/dts/ste-href-tvk1281618.dtsi
arch/arm/boot/dts/stm32f429.dtsi
arch/arm/boot/dts/stm32f769-disco.dts
arch/arm/boot/dts/stm32h743-pinctrl.dtsi
arch/arm/boot/dts/stm32h743.dtsi
arch/arm/boot/dts/stm32h743i-disco.dts
arch/arm/boot/dts/stm32h743i-eval.dts
arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
arch/arm/boot/dts/stm32mp157a-dk1.dts [new file with mode: 0644]
arch/arm/boot/dts/stm32mp157c-dk2.dts [new file with mode: 0644]
arch/arm/boot/dts/stm32mp157c-ed1.dts
arch/arm/boot/dts/stm32mp157c.dtsi
arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts
arch/arm/boot/dts/sun4i-a10-cubieboard.dts
arch/arm/boot/dts/sun4i-a10-dserve-dsrv9703c.dts
arch/arm/boot/dts/sun4i-a10-hyundai-a7hd.dts
arch/arm/boot/dts/sun4i-a10-inet1.dts
arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts
arch/arm/boot/dts/sun4i-a10-marsboard.dts
arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
arch/arm/boot/dts/sun4i-a10-pcduino.dts
arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts
arch/arm/boot/dts/sun4i-a10.dtsi
arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts
arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
arch/arm/boot/dts/sun5i-a13-empire-electronix-d709.dts
arch/arm/boot/dts/sun5i-a13-hsg-h702.dts
arch/arm/boot/dts/sun5i-a13-licheepi-one.dts
arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
arch/arm/boot/dts/sun5i-a13-olinuxino.dts
arch/arm/boot/dts/sun5i-a13-q8-tablet.dts
arch/arm/boot/dts/sun5i-a13-utoo-p66.dts
arch/arm/boot/dts/sun5i-gr8-chip-pro.dts
arch/arm/boot/dts/sun5i-gr8-evb.dts
arch/arm/boot/dts/sun5i-r8-chip.dts
arch/arm/boot/dts/sun5i-reference-design-tablet.dtsi
arch/arm/boot/dts/sun5i.dtsi
arch/arm/boot/dts/sun6i-a31-colombus.dts
arch/arm/boot/dts/sun6i-a31-hummingbird.dts
arch/arm/boot/dts/sun6i-a31-i7.dts
arch/arm/boot/dts/sun6i-a31.dtsi
arch/arm/boot/dts/sun6i-a31s-primo81.dts
arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
arch/arm/boot/dts/sun7i-a20-bananapi.dts
arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
arch/arm/boot/dts/sun7i-a20-olimex-som204-evb.dts
arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts
arch/arm/boot/dts/sun7i-a20-orangepi.dts
arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts
arch/arm/boot/dts/sun7i-a20-pcduino3.dts
arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts
arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts
arch/arm/boot/dts/sun7i-a20.dtsi
arch/arm/boot/dts/sun8i-a23-a33.dtsi
arch/arm/boot/dts/sun8i-a23-q8-tablet.dts
arch/arm/boot/dts/sun8i-a33-q8-tablet.dts
arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
arch/arm/boot/dts/sun8i-a33.dtsi
arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts
arch/arm/boot/dts/sun8i-a83t.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-m1-plus.dts
arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts
arch/arm/boot/dts/sun8i-h3-nanopi-neo-air.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-h3-orangepi-plus.dts
arch/arm/boot/dts/sun8i-h3-orangepi-zero-plus2.dts
arch/arm/boot/dts/sun8i-h3-rervision-dvk.dts [new file with mode: 0644]
arch/arm/boot/dts/sun8i-h3.dtsi
arch/arm/boot/dts/sun8i-q8-common.dtsi
arch/arm/boot/dts/sun8i-r16-nintendo-nes-classic.dts
arch/arm/boot/dts/sun8i-r16-parrot.dts
arch/arm/boot/dts/sun8i-r40.dtsi
arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts
arch/arm/boot/dts/sun8i-v3s.dtsi
arch/arm/boot/dts/sun8i-v40-bananapi-m2-berry.dts
arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
arch/arm/boot/dts/sun9i-a80-optimus.dts
arch/arm/boot/dts/sun9i-a80.dtsi
arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi
arch/arm/boot/dts/sunxi-h3-h5.dtsi
arch/arm/boot/dts/sunxi-libretech-all-h3-cc.dtsi
arch/arm/boot/dts/tegra124-apalis-emc.dtsi
arch/arm/boot/dts/tegra124-apalis-eval.dts
arch/arm/boot/dts/tegra124-apalis-v1.2-eval.dts
arch/arm/boot/dts/tegra124-apalis-v1.2.dtsi
arch/arm/boot/dts/tegra124-apalis.dtsi
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/tegra30.dtsi
arch/arm/boot/dts/vf610-zii-cfu1.dts
arch/arm/boot/dts/vf610-zii-dev-rev-b.dts
arch/arm/boot/dts/vf610-zii-dev-rev-c.dts
arch/arm/boot/dts/vf610-zii-dev.dtsi
arch/arm/boot/dts/vf610-zii-scu4-aib.dts
arch/arm/boot/dts/vf610-zii-spb4.dts [new file with mode: 0644]
arch/arm/boot/dts/vf610-zii-ssmb-dtu.dts
arch/arm/boot/dts/vf610-zii-ssmb-spu3.dts
arch/arm/common/sa1111.c
arch/arm/configs/aspeed_g4_defconfig
arch/arm/configs/aspeed_g5_defconfig
arch/arm/configs/at91_dt_defconfig
arch/arm/configs/clps711x_defconfig
arch/arm/configs/cm_x2xx_defconfig
arch/arm/configs/cm_x300_defconfig
arch/arm/configs/colibri_pxa270_defconfig
arch/arm/configs/corgi_defconfig
arch/arm/configs/davinci_all_defconfig
arch/arm/configs/em_x270_defconfig
arch/arm/configs/ep93xx_defconfig
arch/arm/configs/eseries_pxa_defconfig
arch/arm/configs/exynos_defconfig
arch/arm/configs/imx_v4_v5_defconfig
arch/arm/configs/imx_v6_v7_defconfig
arch/arm/configs/ixp4xx_defconfig
arch/arm/configs/keystone_defconfig
arch/arm/configs/lpc32xx_defconfig
arch/arm/configs/mini2440_defconfig
arch/arm/configs/mmp2_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/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/pxa3xx_defconfig
arch/arm/configs/pxa_defconfig
arch/arm/configs/qcom_defconfig
arch/arm/configs/s3c2410_defconfig
arch/arm/configs/s3c6400_defconfig
arch/arm/configs/sama5_defconfig
arch/arm/configs/shmobile_defconfig
arch/arm/configs/socfpga_defconfig
arch/arm/configs/spear13xx_defconfig
arch/arm/configs/spear3xx_defconfig
arch/arm/configs/spear6xx_defconfig
arch/arm/configs/spitz_defconfig
arch/arm/configs/tango4_defconfig
arch/arm/configs/tegra_defconfig
arch/arm/configs/trizeps4_defconfig
arch/arm/configs/u300_defconfig
arch/arm/firmware/Kconfig [deleted file]
arch/arm/firmware/Makefile [deleted file]
arch/arm/firmware/trusted_foundations.c [deleted file]
arch/arm/include/asm/Kbuild
arch/arm/include/asm/domain.h
arch/arm/include/asm/firmware.h
arch/arm/include/asm/futex.h
arch/arm/include/asm/hardirq.h
arch/arm/include/asm/kvm_emulate.h
arch/arm/include/asm/kvm_host.h
arch/arm/include/asm/limits.h [deleted file]
arch/arm/include/asm/processor.h
arch/arm/include/asm/trusted_foundations.h [deleted file]
arch/arm/include/asm/uaccess.h
arch/arm/kernel/atags.h
arch/arm/kernel/smp.c
arch/arm/mach-davinci/board-da830-evm.c
arch/arm/mach-davinci/board-da850-evm.c
arch/arm/mach-davinci/board-dm355-evm.c
arch/arm/mach-davinci/board-dm644x-evm.c
arch/arm/mach-davinci/board-omapl138-hawk.c
arch/arm/mach-davinci/da830.c
arch/arm/mach-davinci/da850.c
arch/arm/mach-davinci/devices-da8xx.c
arch/arm/mach-davinci/dm355.c
arch/arm/mach-davinci/dm365.c
arch/arm/mach-davinci/dm644x.c
arch/arm/mach-davinci/dm646x.c
arch/arm/mach-dove/common.c
arch/arm/mach-ep93xx/adssphere.c
arch/arm/mach-ep93xx/clock.c
arch/arm/mach-ep93xx/core.c
arch/arm/mach-ep93xx/dma.c
arch/arm/mach-ep93xx/edb93xx.c
arch/arm/mach-ep93xx/gesbc9312.c
arch/arm/mach-ep93xx/gpio-ep93xx.h [new file with mode: 0644]
arch/arm/mach-ep93xx/hardware.h [new file with mode: 0644]
arch/arm/mach-ep93xx/include/mach/gpio-ep93xx.h [deleted file]
arch/arm/mach-ep93xx/include/mach/hardware.h [deleted file]
arch/arm/mach-ep93xx/include/mach/platform.h [deleted file]
arch/arm/mach-ep93xx/micro9.c
arch/arm/mach-ep93xx/platform.h [new file with mode: 0644]
arch/arm/mach-ep93xx/simone.c
arch/arm/mach-ep93xx/snappercl15.c
arch/arm/mach-ep93xx/ts72xx.c
arch/arm/mach-ep93xx/vision_ep9307.c
arch/arm/mach-exynos/Kconfig
arch/arm/mach-exynos/Makefile
arch/arm/mach-exynos/common.h
arch/arm/mach-exynos/exynos.c
arch/arm/mach-exynos/firmware.c
arch/arm/mach-exynos/mcpm-exynos.c
arch/arm/mach-exynos/platsmp.c
arch/arm/mach-exynos/smc.h
arch/arm/mach-exynos/suspend.c
arch/arm/mach-imx/devices/platform-fec.c
arch/arm/mach-imx/devices/platform-gpio_keys.c
arch/arm/mach-imx/devices/platform-imx2-wdt.c
arch/arm/mach-imx/devices/platform-mxc_nand.c
arch/arm/mach-imx/hardware.h
arch/arm/mach-imx/pm-imx6.c
arch/arm/mach-integrator/impd1.c
arch/arm/mach-iop13xx/pci.c
arch/arm/mach-iop13xx/tpmi.c
arch/arm/mach-ixp4xx/Kconfig
arch/arm/mach-ixp4xx/Makefile
arch/arm/mach-ixp4xx/avila-pci.c
arch/arm/mach-ixp4xx/avila-setup.c
arch/arm/mach-ixp4xx/common-pci.c
arch/arm/mach-ixp4xx/common.c
arch/arm/mach-ixp4xx/coyote-pci.c
arch/arm/mach-ixp4xx/coyote-setup.c
arch/arm/mach-ixp4xx/dsmg600-pci.c
arch/arm/mach-ixp4xx/dsmg600-setup.c
arch/arm/mach-ixp4xx/fsg-pci.c
arch/arm/mach-ixp4xx/fsg-setup.c
arch/arm/mach-ixp4xx/gateway7001-pci.c
arch/arm/mach-ixp4xx/gateway7001-setup.c
arch/arm/mach-ixp4xx/gtwx5715-pci.c
arch/arm/mach-ixp4xx/gtwx5715-setup.c
arch/arm/mach-ixp4xx/include/mach/entry-macro.S [deleted file]
arch/arm/mach-ixp4xx/include/mach/irqs.h [deleted file]
arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
arch/arm/mach-ixp4xx/include/mach/npe.h [deleted file]
arch/arm/mach-ixp4xx/include/mach/qmgr.h [deleted file]
arch/arm/mach-ixp4xx/irqs.h [new file with mode: 0644]
arch/arm/mach-ixp4xx/ixdp425-pci.c
arch/arm/mach-ixp4xx/ixdp425-setup.c
arch/arm/mach-ixp4xx/ixdpg425-pci.c
arch/arm/mach-ixp4xx/ixp4xx-of.c [new file with mode: 0644]
arch/arm/mach-ixp4xx/ixp4xx_npe.c [deleted file]
arch/arm/mach-ixp4xx/ixp4xx_qmgr.c [deleted file]
arch/arm/mach-ixp4xx/nas100d-pci.c
arch/arm/mach-ixp4xx/nas100d-setup.c
arch/arm/mach-ixp4xx/nslu2-pci.c
arch/arm/mach-ixp4xx/nslu2-setup.c
arch/arm/mach-ixp4xx/wg302v2-pci.c
arch/arm/mach-ixp4xx/wg302v2-setup.c
arch/arm/mach-ks8695/include/mach/hardware.h
arch/arm/mach-lpc32xx/phy3250.c
arch/arm/mach-mediatek/mediatek.c
arch/arm/mach-mv78xx0/common.c
arch/arm/mach-omap1/include/mach/hardware.h
arch/arm/mach-omap2/common.h
arch/arm/mach-omap2/i2c.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/mmc.h
arch/arm/mach-omap2/omap-wakeupgen.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod.h
arch/arm/mach-omap2/omap_hwmod_2420_data.c
arch/arm/mach-omap2/omap_hwmod_2430_data.c
arch/arm/mach-omap2/omap_hwmod_2xxx_interconnect_data.c
arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
arch/arm/mach-omap2/omap_hwmod_33xx_43xx_common_data.h
arch/arm/mach-omap2/omap_hwmod_33xx_43xx_interconnect_data.c
arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
arch/arm/mach-omap2/omap_hwmod_33xx_data.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/omap_hwmod_43xx_data.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mach-omap2/omap_hwmod_54xx_data.c
arch/arm/mach-omap2/omap_hwmod_7xx_data.c
arch/arm/mach-omap2/omap_hwmod_81xx_data.c
arch/arm/mach-omap2/pm33xx-core.c
arch/arm/mach-omap2/sleep43xx.S
arch/arm/mach-omap2/sr_device.c
arch/arm/mach-orion5x/common.c
arch/arm/mach-prima2/common.c
arch/arm/mach-pxa/balloon3.c
arch/arm/mach-pxa/colibri-pxa270.c
arch/arm/mach-pxa/colibri-pxa300.c
arch/arm/mach-pxa/colibri-pxa320.c
arch/arm/mach-pxa/colibri-pxa3xx.c
arch/arm/mach-pxa/gumstix.c
arch/arm/mach-pxa/lpd270.c
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/trizeps4.c
arch/arm/mach-pxa/viper.c
arch/arm/mach-rockchip/platsmp.c
arch/arm/mach-rockchip/pm.c
arch/arm/mach-rockchip/rockchip.c
arch/arm/mach-s3c24xx/include/mach/hardware.h
arch/arm/mach-s3c64xx/mach-crag6410-module.c
arch/arm/mach-sa1100/include/mach/memory.h
arch/arm/mach-sa1100/neponset.c
arch/arm/mach-shmobile/pm-rcar-gen2.c
arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
arch/arm/mach-stm32/Kconfig
arch/arm/mach-sunxi/mc_smp.c
arch/arm/mach-sunxi/platsmp.c
arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/cpuidle-tegra114.c
arch/arm/mach-tegra/cpuidle-tegra20.c
arch/arm/mach-tegra/cpuidle-tegra30.c
arch/arm/mach-tegra/iomap.h
arch/arm/mach-tegra/irammap.h
arch/arm/mach-tegra/pm.c
arch/arm/mach-tegra/reset-handler.S
arch/arm/mach-tegra/reset.c
arch/arm/mach-tegra/reset.h
arch/arm/mach-tegra/sleep-tegra20.S
arch/arm/mach-tegra/sleep-tegra30.S
arch/arm/mach-tegra/sleep.S
arch/arm/mach-tegra/tegra.c
arch/arm/mach-u300/regulator.c
arch/arm/mach-w90x900/include/mach/hardware.h
arch/arm/mach-zynq/common.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/init.c
arch/arm/plat-pxa/ssp.c
arch/arm/tools/syscall.tbl
arch/arm/vdso/Makefile
arch/arm/xen/p2m.c
arch/arm64/Kconfig
arch/arm64/Kconfig.platforms
arch/arm64/boot/dts/Makefile
arch/arm64/boot/dts/allwinner/Makefile
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-oceanic-5205-5inmfd.dts [new file with mode: 0644]
arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi
arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
arch/arm64/boot/dts/allwinner/sun50i-h5-emlid-neutis-n5-devboard.dts
arch/arm64/boot/dts/allwinner/sun50i-h5-emlid-neutis-n5.dtsi
arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts
arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.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-h5-orangepi-zero-plus.dts
arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts
arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts [new file with mode: 0644]
arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts [new file with mode: 0644]
arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi
arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts
arch/arm64/boot/dts/amlogic/Makefile
arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts [new file with mode: 0644]
arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts
arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts
arch/arm64/boot/dts/amlogic/meson-g12a.dtsi
arch/arm64/boot/dts/amlogic/meson-gxl-s905d-phicomm-n1.dts
arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
arch/arm64/boot/dts/bitmain/bm1880-sophon-edge.dts
arch/arm64/boot/dts/bitmain/bm1880.dtsi
arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi
arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
arch/arm64/boot/dts/exynos/exynos5433.dtsi
arch/arm64/boot/dts/exynos/exynos7.dtsi
arch/arm64/boot/dts/freescale/Makefile
arch/arm64/boot/dts/freescale/fsl-ls1012a-oxalis.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-rdb.dts
arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts
arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
arch/arm64/boot/dts/freescale/fsl-lx2160a-rdb.dts
arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
arch/arm64/boot/dts/freescale/imx8mm-evk.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mm.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mq-evk.dts
arch/arm64/boot/dts/freescale/imx8mq-zii-ultra-rmb3.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mq-zii-ultra-zest.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mq-zii-ultra.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mq.dtsi
arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
arch/arm64/boot/dts/freescale/imx8qxp.dtsi
arch/arm64/boot/dts/hisilicon/hi3660.dtsi
arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
arch/arm64/boot/dts/hisilicon/hi3670.dtsi
arch/arm64/boot/dts/hisilicon/hikey970-pinctrl.dtsi
arch/arm64/boot/dts/intel/Makefile [new file with mode: 0644]
arch/arm64/boot/dts/intel/socfpga_agilex.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts [new file with mode: 0644]
arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts
arch/arm64/boot/dts/mediatek/mt2712e.dtsi
arch/arm64/boot/dts/mediatek/mt8173.dtsi
arch/arm64/boot/dts/mediatek/mt8183-pinfunc.h [new file with mode: 0644]
arch/arm64/boot/dts/nvidia/Makefile
arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
arch/arm64/boot/dts/nvidia/tegra186-p3310.dtsi
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/tegra210-p2180.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 [new file with mode: 0644]
arch/arm64/boot/dts/nvidia/tegra210-smaug.dts
arch/arm64/boot/dts/nvidia/tegra210.dtsi
arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi
arch/arm64/boot/dts/qcom/apq8096-db820c-pmic-pins.dtsi
arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi
arch/arm64/boot/dts/qcom/msm8916.dtsi
arch/arm64/boot/dts/qcom/msm8996-pins.dtsi
arch/arm64/boot/dts/qcom/msm8996.dtsi
arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi
arch/arm64/boot/dts/qcom/msm8998.dtsi
arch/arm64/boot/dts/qcom/pm8005.dtsi
arch/arm64/boot/dts/qcom/pm8998.dtsi
arch/arm64/boot/dts/qcom/pmi8994.dtsi
arch/arm64/boot/dts/qcom/pmi8998.dtsi
arch/arm64/boot/dts/qcom/pms405.dtsi
arch/arm64/boot/dts/qcom/qcs404-evb-1000.dts
arch/arm64/boot/dts/qcom/qcs404-evb-4000.dts
arch/arm64/boot/dts/qcom/qcs404-evb.dtsi
arch/arm64/boot/dts/qcom/qcs404.dtsi
arch/arm64/boot/dts/qcom/sdm845-mtp.dts
arch/arm64/boot/dts/qcom/sdm845.dtsi
arch/arm64/boot/dts/renesas/cat875.dtsi
arch/arm64/boot/dts/renesas/r8a774a1.dtsi
arch/arm64/boot/dts/renesas/r8a774c0-cat874.dts
arch/arm64/boot/dts/renesas/r8a774c0.dtsi
arch/arm64/boot/dts/renesas/r8a7795.dtsi
arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts
arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts
arch/arm64/boot/dts/renesas/r8a7796.dtsi
arch/arm64/boot/dts/renesas/r8a77965.dtsi
arch/arm64/boot/dts/renesas/r8a77980.dtsi
arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts
arch/arm64/boot/dts/renesas/r8a77990.dtsi
arch/arm64/boot/dts/renesas/r8a77995-draak.dts
arch/arm64/boot/dts/renesas/salvator-common.dtsi
arch/arm64/boot/dts/rockchip/Makefile
arch/arm64/boot/dts/rockchip/px30-evb.dts
arch/arm64/boot/dts/rockchip/rk3328-evb.dts
arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts
arch/arm64/boot/dts/rockchip/rk3328-rock64.dts
arch/arm64/boot/dts/rockchip/rk3328.dtsi
arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi
arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts
arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts
arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi
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-ficus.dts
arch/arm64/boot/dts/rockchip/rk3399-gru-bob.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-gru.dtsi
arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts
arch/arm64/boot/dts/rockchip/rk3399-nanopi-neo4.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi
arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts
arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts
arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi
arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dts
arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi
arch/arm64/boot/dts/rockchip/rk3399.dtsi
arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm016-dc2.dts
arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts
arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revB.dts
arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revA.dts
arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts
arch/arm64/boot/dts/xilinx/zynqmp-zcu111-revA.dts
arch/arm64/configs/defconfig
arch/arm64/include/asm/Kbuild
arch/arm64/include/asm/boot.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/fpsimd.h
arch/arm64/include/asm/hugetlb.h
arch/arm64/include/asm/kvm_asm.h
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/kvm_hyp.h
arch/arm64/include/asm/kvm_ptrauth.h [new file with mode: 0644]
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/unistd.h
arch/arm64/include/asm/unistd32.h
arch/arm64/include/uapi/asm/kvm.h
arch/arm64/kernel/asm-offsets.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/fpsimd.c
arch/arm64/kernel/perf_event.c
arch/arm64/kernel/signal.c
arch/arm64/kvm/Makefile
arch/arm64/kvm/fpsimd.c
arch/arm64/kvm/guest.c
arch/arm64/kvm/handle_exit.c
arch/arm64/kvm/hyp/entry.S
arch/arm64/kvm/hyp/switch.c
arch/arm64/kvm/pmu.c [new file with mode: 0644]
arch/arm64/kvm/reset.c
arch/arm64/kvm/sys_regs.c
arch/arm64/kvm/sys_regs.h
arch/arm64/mm/init.c
arch/arm64/mm/mmu.c
arch/c6x/include/asm/Kbuild
arch/c6x/mm/init.c
arch/h8300/Kconfig
arch/h8300/include/asm/Kbuild
arch/h8300/include/asm/uaccess.h [deleted file]
arch/h8300/kernel/setup.c
arch/h8300/mm/init.c
arch/hexagon/Kconfig
arch/hexagon/include/asm/Kbuild
arch/hexagon/include/asm/uaccess.h
arch/hexagon/mm/init.c
arch/ia64/Kconfig
arch/ia64/include/asm/segment.h [deleted file]
arch/ia64/kernel/machvec.c
arch/ia64/kernel/syscalls/syscall.tbl
arch/ia64/mm/init.c
arch/m68k/Kconfig
arch/m68k/kernel/syscalls/syscall.tbl
arch/m68k/mm/init.c
arch/microblaze/kernel/syscalls/syscall.tbl
arch/microblaze/mm/init.c
arch/mips/Kconfig
arch/mips/alchemy/common/platform.c
arch/mips/ath79/clock.c
arch/mips/ath79/setup.c
arch/mips/configs/bcm47xx_defconfig
arch/mips/configs/ci20_defconfig
arch/mips/configs/db1xxx_defconfig
arch/mips/configs/generic/board-ni169445.config
arch/mips/configs/generic/board-ocelot.config
arch/mips/configs/ip22_defconfig
arch/mips/configs/ip27_defconfig
arch/mips/configs/loongson1b_defconfig
arch/mips/configs/loongson1c_defconfig
arch/mips/configs/qi_lb60_defconfig
arch/mips/configs/rb532_defconfig
arch/mips/configs/rbtx49xx_defconfig
arch/mips/configs/xway_defconfig
arch/mips/generic/init.c
arch/mips/include/asm/Kbuild
arch/mips/include/asm/bitops.h
arch/mips/include/asm/mach-ip27/topology.h
arch/mips/include/asm/pci/bridge.h
arch/mips/include/asm/sn/irq_alloc.h [new file with mode: 0644]
arch/mips/include/asm/xtalk/xtalk.h
arch/mips/kernel/cpu-bugs64.c
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/kernel/syscalls/syscall_n32.tbl
arch/mips/kernel/syscalls/syscall_n64.tbl
arch/mips/kernel/syscalls/syscall_o32.tbl
arch/mips/mm/gup.c
arch/mips/mm/init.c
arch/mips/pci/Makefile
arch/mips/pci/ops-bridge.c [deleted file]
arch/mips/pci/pci-ip27.c
arch/mips/pci/pci-xtalk-bridge.c [new file with mode: 0644]
arch/mips/sgi-ip22/ip22-platform.c
arch/mips/sgi-ip27/ip27-init.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sgi-ip27/ip27-xtalk.c
arch/mips/txx9/generic/setup.c
arch/nds32/Kconfig
arch/nds32/include/asm/Kbuild
arch/nds32/include/asm/assembler.h
arch/nds32/include/asm/barrier.h
arch/nds32/include/asm/bitfield.h
arch/nds32/include/asm/cache.h
arch/nds32/include/asm/cache_info.h
arch/nds32/include/asm/cacheflush.h
arch/nds32/include/asm/current.h
arch/nds32/include/asm/delay.h
arch/nds32/include/asm/elf.h
arch/nds32/include/asm/fixmap.h
arch/nds32/include/asm/futex.h
arch/nds32/include/asm/highmem.h
arch/nds32/include/asm/io.h
arch/nds32/include/asm/irqflags.h
arch/nds32/include/asm/l2_cache.h
arch/nds32/include/asm/linkage.h
arch/nds32/include/asm/memory.h
arch/nds32/include/asm/mmu.h
arch/nds32/include/asm/mmu_context.h
arch/nds32/include/asm/module.h
arch/nds32/include/asm/nds32.h
arch/nds32/include/asm/page.h
arch/nds32/include/asm/pgalloc.h
arch/nds32/include/asm/pgtable.h
arch/nds32/include/asm/proc-fns.h
arch/nds32/include/asm/processor.h
arch/nds32/include/asm/ptrace.h
arch/nds32/include/asm/shmparam.h
arch/nds32/include/asm/string.h
arch/nds32/include/asm/swab.h
arch/nds32/include/asm/syscall.h
arch/nds32/include/asm/syscalls.h
arch/nds32/include/asm/thread_info.h
arch/nds32/include/asm/tlb.h
arch/nds32/include/asm/tlbflush.h
arch/nds32/include/asm/uaccess.h
arch/nds32/include/asm/unistd.h
arch/nds32/include/asm/vdso.h
arch/nds32/include/asm/vdso_datapage.h
arch/nds32/include/asm/vdso_timer_info.h
arch/nds32/include/uapi/asm/auxvec.h
arch/nds32/include/uapi/asm/byteorder.h
arch/nds32/include/uapi/asm/cachectl.h
arch/nds32/include/uapi/asm/param.h
arch/nds32/include/uapi/asm/ptrace.h
arch/nds32/include/uapi/asm/sigcontext.h
arch/nds32/include/uapi/asm/unistd.h
arch/nds32/kernel/.gitignore [new file with mode: 0644]
arch/nds32/kernel/cacheinfo.c
arch/nds32/kernel/ex-exit.S
arch/nds32/kernel/ftrace.c
arch/nds32/kernel/head.S
arch/nds32/kernel/nds32_ksyms.c
arch/nds32/kernel/vdso.c
arch/nds32/kernel/vdso/.gitignore [new file with mode: 0644]
arch/nds32/kernel/vdso/Makefile
arch/nds32/kernel/vdso/gettimeofday.c
arch/nds32/mm/init.c
arch/nios2/Kconfig
arch/nios2/include/asm/Kbuild
arch/nios2/mm/init.c
arch/openrisc/include/asm/Kbuild
arch/openrisc/kernel/ptrace.c
arch/openrisc/kernel/setup.c
arch/openrisc/kernel/traps.c
arch/openrisc/mm/init.c
arch/openrisc/mm/tlb.c
arch/parisc/include/asm/Kbuild
arch/parisc/include/asm/cache.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/drivers.c
arch/parisc/kernel/firmware.c
arch/parisc/kernel/ftrace.c
arch/parisc/kernel/head.S
arch/parisc/kernel/inventory.c
arch/parisc/kernel/pci.c
arch/parisc/kernel/perf_images.h
arch/parisc/kernel/process.c
arch/parisc/kernel/processor.c
arch/parisc/kernel/syscall.S
arch/parisc/kernel/syscalls/syscall.tbl
arch/parisc/kernel/time.c
arch/parisc/kernel/unwind.c
arch/parisc/kernel/vmlinux.lds.S
arch/parisc/mm/init.c
arch/powerpc/Kconfig
arch/powerpc/configs/40x/kilauea_defconfig
arch/powerpc/configs/40x/obs600_defconfig
arch/powerpc/configs/44x/canyonlands_defconfig
arch/powerpc/configs/44x/eiger_defconfig
arch/powerpc/configs/44x/sequoia_defconfig
arch/powerpc/configs/44x/warp_defconfig
arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
arch/powerpc/configs/85xx-hw.config
arch/powerpc/configs/85xx/ge_imp3a_defconfig
arch/powerpc/configs/85xx/socrates_defconfig
arch/powerpc/configs/85xx/tqm8548_defconfig
arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
arch/powerpc/configs/86xx-hw.config
arch/powerpc/configs/mpc512x_defconfig
arch/powerpc/configs/mpc83xx_defconfig
arch/powerpc/configs/pasemi_defconfig
arch/powerpc/configs/ppc44x_defconfig
arch/powerpc/include/asm/book3s/64/hugetlb.h
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/include/asm/livepatch.h
arch/powerpc/include/asm/xive.h
arch/powerpc/include/uapi/asm/kvm.h
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/syscalls/syscall.tbl
arch/powerpc/kernel/sysfs.c
arch/powerpc/kvm/Makefile
arch/powerpc/kvm/book3s.c
arch/powerpc/kvm/book3s_64_mmu_hv.c
arch/powerpc/kvm/book3s_64_vio.c
arch/powerpc/kvm/book3s_64_vio_hv.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_builtin.c
arch/powerpc/kvm/book3s_hv_rm_mmu.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_xive.c
arch/powerpc/kvm/book3s_xive.h
arch/powerpc/kvm/book3s_xive_native.c [new file with mode: 0644]
arch/powerpc/kvm/book3s_xive_template.c
arch/powerpc/kvm/e500_mmu.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/mm/book3s64/iommu_api.c
arch/powerpc/mm/book3s64/radix_tlb.c
arch/powerpc/mm/mem.c
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/powernv/npu-dma.c
arch/powerpc/sysdev/tsi108_dev.c
arch/powerpc/sysdev/xive/native.c
arch/riscv/Kconfig
arch/riscv/Makefile
arch/riscv/include/asm/Kbuild
arch/riscv/include/asm/bug.h
arch/riscv/include/asm/cacheflush.h
arch/riscv/include/asm/csr.h
arch/riscv/include/asm/elf.h
arch/riscv/include/asm/futex.h
arch/riscv/include/asm/irqflags.h
arch/riscv/include/asm/mmu_context.h
arch/riscv/include/asm/ptrace.h
arch/riscv/include/asm/sbi.h
arch/riscv/include/asm/sifive_l2_cache.h [new file with mode: 0644]
arch/riscv/include/asm/thread_info.h
arch/riscv/include/asm/uaccess.h
arch/riscv/kernel/asm-offsets.c
arch/riscv/kernel/cpu.c
arch/riscv/kernel/entry.S
arch/riscv/kernel/head.S
arch/riscv/kernel/irq.c
arch/riscv/kernel/perf_event.c
arch/riscv/kernel/reset.c
arch/riscv/kernel/setup.c
arch/riscv/kernel/signal.c
arch/riscv/kernel/smp.c
arch/riscv/kernel/smpboot.c
arch/riscv/kernel/stacktrace.c
arch/riscv/kernel/traps.c
arch/riscv/kernel/vdso/Makefile
arch/riscv/mm/Makefile
arch/riscv/mm/cacheflush.c
arch/riscv/mm/context.c [new file with mode: 0644]
arch/riscv/mm/fault.c
arch/riscv/mm/init.c
arch/riscv/mm/sifive_l2_cache.c [new file with mode: 0644]
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/boot/Makefile
arch/s390/boot/compressed/vmlinux.lds.S
arch/s390/configs/defconfig [new file with mode: 0644]
arch/s390/defconfig [deleted file]
arch/s390/include/asm/cpacf.h
arch/s390/include/asm/hugetlb.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/livepatch.h
arch/s390/include/asm/segment.h [deleted file]
arch/s390/include/uapi/asm/kvm.h
arch/s390/kernel/ptrace.c
arch/s390/kernel/syscalls/syscall.tbl
arch/s390/kvm/Kconfig
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/vsie.c
arch/s390/mm/init.c
arch/s390/mm/kasan_init.c
arch/s390/tools/gen_facilities.c
arch/sh/Kconfig
arch/sh/boards/board-apsh4a3a.c
arch/sh/boards/board-apsh4ad0a.c
arch/sh/boards/board-edosk7705.c
arch/sh/boards/board-edosk7760.c
arch/sh/boards/board-espt.c
arch/sh/boards/board-urquell.c
arch/sh/boards/mach-dreamcast/irq.c
arch/sh/boards/mach-microdev/setup.c
arch/sh/boards/mach-sdk7786/fpga.c
arch/sh/boards/mach-sdk7786/setup.c
arch/sh/boards/mach-sdk7786/sram.c
arch/sh/boards/mach-se/7343/irq.c
arch/sh/boards/mach-se/7722/irq.c
arch/sh/configs/ap325rxa_defconfig
arch/sh/configs/ecovec24_defconfig
arch/sh/configs/migor_defconfig
arch/sh/configs/sdk7786_defconfig
arch/sh/configs/se7724_defconfig
arch/sh/configs/titan_defconfig
arch/sh/drivers/pci/pci-sh7751.c
arch/sh/drivers/pci/pci-sh7780.c
arch/sh/drivers/pci/pcie-sh7786.c
arch/sh/include/asm/Kbuild
arch/sh/kernel/syscalls/syscall.tbl
arch/sh/mm/gup.c
arch/sh/mm/init.c
arch/sh/mm/pmb.c
arch/sh/mm/uncached.c
arch/sparc/Kconfig
arch/sparc/include/asm/pgtable_64.h
arch/sparc/kernel/syscalls/syscall.tbl
arch/sparc/kernel/time_64.c
arch/sparc/mm/gup.c
arch/sparc/mm/init_32.c
arch/sparc/mm/init_64.c
arch/um/Kconfig
arch/um/drivers/Kconfig
arch/um/drivers/ubd_kern.c
arch/um/include/asm/pgtable.h
arch/um/kernel/irq.c
arch/um/kernel/mem.c
arch/um/kernel/skas/uaccess.c
arch/um/kernel/time.c
arch/um/os-Linux/signal.c
arch/um/os-Linux/umid.c
arch/unicore32/Kconfig
arch/unicore32/configs/unicore32_defconfig
arch/unicore32/include/asm/Kbuild
arch/unicore32/include/asm/memory.h
arch/unicore32/mm/init.c
arch/unicore32/mm/ioremap.c
arch/unicore32/mm/mmu.c
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/entry/common.c
arch/x86/entry/entry_64.S
arch/x86/entry/syscalls/syscall_32.tbl
arch/x86/entry/syscalls/syscall_64.tbl
arch/x86/entry/vdso/vdso2c.c
arch/x86/events/amd/iommu.c
arch/x86/events/intel/bts.c
arch/x86/events/intel/core.c
arch/x86/events/perf_event.h
arch/x86/include/asm/arch_hweight.h
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/e820/api.h
arch/x86/include/asm/ftrace.h
arch/x86/include/asm/hugetlb.h
arch/x86/include/asm/hyperv-tlfs.h
arch/x86/include/asm/irqflags.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/livepatch.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/processor.h
arch/x86/include/asm/text-patching.h
arch/x86/include/asm/vdso.h
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/intel_epb.c
arch/x86/kernel/e820.c
arch/x86/kernel/ftrace.c
arch/x86/kernel/ftrace_32.S
arch/x86/kernel/ftrace_64.S
arch/x86/kernel/kprobes/core.c
arch/x86/kernel/nmi.c
arch/x86/kernel/tsc.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/hyperv.c
arch/x86/kvm/kvm_cache_regs.h
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu.c
arch/x86/kvm/mtrr.c
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/svm.c
arch/x86/kvm/vmx/capabilities.h
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/pmu_intel.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/vmx/vmx.h
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/mm/hugetlbpage.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/mem_encrypt.c
arch/x86/mm/mm_internal.h
arch/x86/pci/irq.c
arch/x86/platform/olpc/olpc_dt.c
arch/x86/platform/pvh/enlighten.c
arch/x86/xen/efi.c
arch/x86/xen/enlighten_pv.c
arch/x86/xen/enlighten_pvh.c
arch/x86/xen/time.c
arch/x86/xen/xen-ops.h
arch/xtensa/Kconfig
arch/xtensa/boot/boot-redboot/bootstrap.S
arch/xtensa/include/asm/asmmacro.h
arch/xtensa/include/asm/atomic.h
arch/xtensa/include/asm/barrier.h
arch/xtensa/include/asm/bitops.h
arch/xtensa/include/asm/cache.h
arch/xtensa/include/asm/checksum.h
arch/xtensa/include/asm/cmpxchg.h
arch/xtensa/include/asm/coprocessor.h
arch/xtensa/include/asm/core.h [new file with mode: 0644]
arch/xtensa/include/asm/futex.h
arch/xtensa/include/asm/initialize_mmu.h
arch/xtensa/include/asm/io.h
arch/xtensa/include/asm/irq.h
arch/xtensa/include/asm/irqflags.h
arch/xtensa/include/asm/pci-bridge.h
arch/xtensa/include/asm/pci.h
arch/xtensa/include/asm/pgalloc.h
arch/xtensa/include/asm/processor.h
arch/xtensa/include/asm/ptrace.h
arch/xtensa/include/asm/segment.h [deleted file]
arch/xtensa/include/asm/vectors.h
arch/xtensa/kernel/hw_breakpoint.c
arch/xtensa/kernel/setup.c
arch/xtensa/kernel/smp.c
arch/xtensa/kernel/syscalls/syscall.tbl
arch/xtensa/kernel/vmlinux.lds.S
arch/xtensa/lib/checksum.S
arch/xtensa/lib/memcopy.S
arch/xtensa/lib/memset.S
arch/xtensa/lib/strncpy_user.S
arch/xtensa/lib/strnlen_user.S
arch/xtensa/lib/usercopy.S
arch/xtensa/mm/init.c
arch/xtensa/platforms/iss/simdisk.c
arch/xtensa/platforms/xt2000/include/platform/hardware.h
arch/xtensa/platforms/xt2000/include/platform/serial.h
arch/xtensa/platforms/xtfpga/setup.c
block/bio-integrity.c
drivers/acpi/acpi_apd.c
drivers/acpi/arm64/iort.c
drivers/acpi/device_sysfs.c
drivers/acpi/pci_mcfg.c
drivers/acpi/pci_root.c
drivers/acpi/sleep.c
drivers/ata/pata_ep93xx.c
drivers/ata/sata_rcar.c
drivers/base/cpu.c
drivers/base/memory.c
drivers/base/power/domain.c
drivers/block/brd.c
drivers/block/rbd.c
drivers/bus/tegra-aconnect.c
drivers/bus/ti-sysc.c
drivers/clk/axs10x/i2s_pll_clock.c
drivers/clk/axs10x/pll_clock.c
drivers/clk/bcm/clk-bcm2835-aux.c
drivers/clk/bcm/clk-bcm2835.c
drivers/clk/bcm/clk-kona.c
drivers/clk/berlin/berlin2-div.c
drivers/clk/berlin/bg2.c
drivers/clk/berlin/bg2q.c
drivers/clk/clk-fixed-mmio.c
drivers/clk/clk-fractional-divider.c
drivers/clk/clk-hsdk-pll.c
drivers/clk/clk-multiplier.c
drivers/clk/davinci/pll-da850.c
drivers/clk/h8300/clk-div.c
drivers/clk/h8300/clk-h8s2678.c
drivers/clk/hisilicon/clk-hi3660-stub.c
drivers/clk/imx/clk-composite-8m.c
drivers/clk/imx/clk-frac-pll.c
drivers/clk/imx/clk-imx21.c
drivers/clk/imx/clk-imx27.c
drivers/clk/imx/clk-pfdv2.c
drivers/clk/imx/clk-pllv4.c
drivers/clk/imx/clk-sccg-pll.c
drivers/clk/ingenic/cgu.c
drivers/clk/ingenic/jz4740-cgu.c
drivers/clk/ingenic/jz4770-cgu.c
drivers/clk/ingenic/jz4780-cgu.c
drivers/clk/loongson1/clk-loongson1c.c
drivers/clk/microchip/clk-core.c
drivers/clk/microchip/clk-pic32mzda.c
drivers/clk/mvebu/armada-37xx-periph.c
drivers/clk/mvebu/armada-37xx-tbg.c
drivers/clk/mvebu/clk-corediv.c
drivers/clk/nxp/clk-lpc18xx-ccu.c
drivers/clk/nxp/clk-lpc18xx-cgu.c
drivers/clk/nxp/clk-lpc32xx.c
drivers/clk/pxa/clk-pxa.c
drivers/clk/renesas/clk-r8a73a4.c
drivers/clk/renesas/clk-r8a7740.c
drivers/clk/renesas/clk-rcar-gen2.c
drivers/clk/renesas/clk-rz.c
drivers/clk/renesas/clk-sh73a0.c
drivers/clk/renesas/r9a06g032-clocks.c
drivers/clk/renesas/rcar-usb2-clock-sel.c
drivers/clk/renesas/renesas-cpg-mssr.c
drivers/clk/rockchip/clk-half-divider.c
drivers/clk/rockchip/clk-px30.c
drivers/clk/rockchip/clk-rk3036.c
drivers/clk/rockchip/clk-rk3128.c
drivers/clk/rockchip/clk-rk3188.c
drivers/clk/rockchip/clk-rk3228.c
drivers/clk/rockchip/clk-rk3288.c
drivers/clk/rockchip/clk-rk3328.c
drivers/clk/rockchip/clk-rk3368.c
drivers/clk/rockchip/clk-rk3399.c
drivers/clk/rockchip/clk-rv1108.c
drivers/clk/rockchip/clk.c
drivers/clk/samsung/clk-cpu.c
drivers/clk/samsung/clk-exynos-clkout.c
drivers/clk/samsung/clk-exynos3250.c
drivers/clk/samsung/clk-exynos4.c
drivers/clk/samsung/clk-exynos5-subcmu.c
drivers/clk/samsung/clk-exynos5250.c
drivers/clk/samsung/clk-pll.c
drivers/clk/samsung/clk-s3c2410-dclk.c
drivers/clk/samsung/clk-s3c2412.c
drivers/clk/samsung/clk-s3c2443.c
drivers/clk/samsung/clk.c
drivers/clk/sifive/fu540-prci.c
drivers/clk/socfpga/clk-gate-s10.c
drivers/clk/socfpga/clk-periph-s10.c
drivers/clk/socfpga/clk-pll-s10.c
drivers/clk/st/clkgen-mux.c
drivers/clk/sunxi-ng/ccu-sun4i-a10.c
drivers/clk/sunxi-ng/ccu-sun50i-a64.c
drivers/clk/sunxi-ng/ccu-sun50i-h6.c
drivers/clk/sunxi-ng/ccu-sun5i.c
drivers/clk/sunxi-ng/ccu-sun6i-a31.c
drivers/clk/sunxi-ng/ccu-sun8i-a23.c
drivers/clk/sunxi-ng/ccu-sun8i-a33.c
drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
drivers/clk/sunxi-ng/ccu-sun8i-h3.c
drivers/clk/sunxi-ng/ccu-sun8i-r40.c
drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
drivers/clk/sunxi-ng/ccu-sun9i-a80.c
drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
drivers/clk/sunxi-ng/ccu_div.c
drivers/clk/sunxi-ng/ccu_frac.c
drivers/clk/sunxi-ng/ccu_gate.c
drivers/clk/sunxi-ng/ccu_mmc_timing.c
drivers/clk/sunxi-ng/ccu_mp.c
drivers/clk/sunxi-ng/ccu_mult.c
drivers/clk/sunxi-ng/ccu_mux.c
drivers/clk/sunxi-ng/ccu_nk.c
drivers/clk/sunxi-ng/ccu_nkm.c
drivers/clk/sunxi-ng/ccu_nkmp.c
drivers/clk/sunxi-ng/ccu_nm.c
drivers/clk/sunxi-ng/ccu_phase.c
drivers/clk/sunxi-ng/ccu_sdm.c
drivers/clk/sunxi/clk-a10-mod1.c
drivers/clk/sunxi/clk-a10-pll2.c
drivers/clk/sunxi/clk-a10-ve.c
drivers/clk/sunxi/clk-a20-gmac.c
drivers/clk/sunxi/clk-mod0.c
drivers/clk/sunxi/clk-simple-gates.c
drivers/clk/sunxi/clk-sun4i-display.c
drivers/clk/sunxi/clk-sun4i-pll3.c
drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
drivers/clk/sunxi/clk-sun8i-apb0.c
drivers/clk/sunxi/clk-sun8i-bus-gates.c
drivers/clk/sunxi/clk-sun8i-mbus.c
drivers/clk/sunxi/clk-sun9i-cpus.c
drivers/clk/sunxi/clk-sun9i-mmc.c
drivers/clk/sunxi/clk-sunxi.c
drivers/clk/sunxi/clk-usb.c
drivers/clk/tegra/clk-emc.c
drivers/clk/tegra/clk-periph-fixed.c
drivers/clk/tegra/clk-sdmmc-mux.c
drivers/clk/tegra/clk.c
drivers/clk/ti/adpll.c
drivers/clk/ti/clk.c
drivers/clk/ti/fapll.c
drivers/clk/versatile/clk-sp810.c
drivers/clk/x86/clk-pmc-atom.c
drivers/clk/zynqmp/clkc.c
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/timer-ixp4xx.c [new file with mode: 0644]
drivers/cpufreq/cpufreq.c
drivers/cpufreq/loongson1-cpufreq.c
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/caamalg_qi.c
drivers/crypto/caam/caamalg_qi2.c
drivers/crypto/caam/error.c
drivers/crypto/caam/jr.c
drivers/crypto/caam/regs.h
drivers/crypto/chelsio/chcr_algo.c
drivers/crypto/chelsio/chcr_core.c
drivers/crypto/chelsio/chcr_ipsec.c
drivers/crypto/ixp4xx_crypto.c
drivers/dax/Kconfig
drivers/dax/device.c
drivers/dax/pmem/core.c
drivers/dma-buf/dma-fence.c
drivers/edac/Kconfig
drivers/edac/edac_mc.c
drivers/firewire/core-iso.c
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/arm_scmi/driver.c
drivers/firmware/imx/Makefile
drivers/firmware/imx/imx-scu-irq.c [new file with mode: 0644]
drivers/firmware/imx/imx-scu.c
drivers/firmware/imx/scu-pd.c
drivers/firmware/trusted_foundations.c [new file with mode: 0644]
drivers/firmware/xilinx/zynqmp-debug.c
drivers/firmware/xilinx/zynqmp.c
drivers/fpga/Kconfig
drivers/fpga/Makefile
drivers/fpga/dfl-afu-dma-region.c
drivers/fpga/zynqmp-fpga.c [new file with mode: 0644]
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-74x164.c
drivers/gpio/gpio-74xx-mmio.c
drivers/gpio/gpio-amdpt.c
drivers/gpio/gpio-aspeed.c
drivers/gpio/gpio-bcm-kona.c
drivers/gpio/gpio-cadence.c
drivers/gpio/gpio-clps711x.c
drivers/gpio/gpio-dwapb.c
drivers/gpio/gpio-ftgpio010.c
drivers/gpio/gpio-hlwd.c
drivers/gpio/gpio-iop.c
drivers/gpio/gpio-ixp4xx.c [new file with mode: 0644]
drivers/gpio/gpio-janz-ttl.c
drivers/gpio/gpio-loongson1.c
drivers/gpio/gpio-lpc18xx.c
drivers/gpio/gpio-max77650.c [new file with mode: 0644]
drivers/gpio/gpio-mb86s7x.c
drivers/gpio/gpio-mlxbf.c [new file with mode: 0644]
drivers/gpio/gpio-mmio.c
drivers/gpio/gpio-mt7621.c
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpio-mxc.c
drivers/gpio/gpio-octeon.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-pxa.c
drivers/gpio/gpio-rcar.c
drivers/gpio/gpio-sch.c
drivers/gpio/gpio-spear-spics.c
drivers/gpio/gpio-sprd.c
drivers/gpio/gpio-sta2x11.c
drivers/gpio/gpio-stp-xway.c
drivers/gpio/gpio-tb10x.c
drivers/gpio/gpio-tegra.c
drivers/gpio/gpio-timberdale.c
drivers/gpio/gpio-ts4800.c
drivers/gpio/gpio-uniphier.c
drivers/gpio/gpio-vf610.c
drivers/gpio/gpio-xgene-sb.c
drivers/gpio/gpio-xlp.c
drivers/gpio/gpio-zx.c
drivers/gpio/gpio-zynq.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
drivers/gpu/drm/Kconfig
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c
drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h
drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
drivers/gpu/drm/amd/amdgpu/vega10_ih.c
drivers/gpu/drm/amd/amdkfd/kfd_topology.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/bridge/Kconfig
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
drivers/gpu/drm/fsl-dcu/Kconfig
drivers/gpu/drm/i915/Kconfig
drivers/gpu/drm/i915/gvt/debugfs.c
drivers/gpu/drm/i915/gvt/dmabuf.c
drivers/gpu/drm/i915/gvt/gtt.c
drivers/gpu/drm/i915/gvt/gtt.h
drivers/gpu/drm/i915/gvt/handlers.c
drivers/gpu/drm/i915/gvt/mmio_context.c
drivers/gpu/drm/i915/gvt/reg.h
drivers/gpu/drm/i915/gvt/scheduler.c
drivers/gpu/drm/i915/i915_gem_userptr.c
drivers/gpu/drm/i915/i915_request.c
drivers/gpu/drm/i915/intel_breadcrumbs.c
drivers/gpu/drm/i915/intel_context.c
drivers/gpu/drm/i915/intel_context_types.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_fbc.c
drivers/gpu/drm/i915/intel_guc_submission.c
drivers/gpu/drm/i915/intel_pipe_crc.c
drivers/gpu/drm/msm/adreno/a6xx_gmu.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
drivers/gpu/drm/msm/msm_atomic.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem.h
drivers/gpu/drm/nouveau/Kconfig
drivers/gpu/drm/nouveau/dispnv50/disp.h
drivers/gpu/drm/nouveau/dispnv50/head.c
drivers/gpu/drm/nouveau/dispnv50/wimmc37b.c
drivers/gpu/drm/nouveau/dispnv50/wndw.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
drivers/gpu/drm/panfrost/panfrost_device.c
drivers/gpu/drm/panfrost/panfrost_drv.c
drivers/gpu/drm/pl111/pl111_display.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_mn.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.c
drivers/gpu/drm/shmobile/Kconfig
drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
drivers/gpu/drm/tilcdc/Kconfig
drivers/gpu/drm/vc4/vc4_dsi.c
drivers/gpu/drm/via/via_dmablit.c
drivers/gpu/drm/xen/xen_drm_front_gem.c
drivers/hid/hid-input.c
drivers/hwmon/aspeed-pwm-tacho.c
drivers/hwmon/gpio-fan.c
drivers/hwmon/hwmon.c
drivers/hwmon/mlxreg-fan.c
drivers/hwmon/npcm750-pwm-fan.c
drivers/hwmon/pwm-fan.c
drivers/iio/inkern.c
drivers/infiniband/core/addr.c
drivers/infiniband/core/nldev.c
drivers/infiniband/core/umem.c
drivers/infiniband/core/umem_odp.c
drivers/infiniband/hw/hfi1/user_pages.c
drivers/infiniband/hw/mlx5/devx.c
drivers/infiniband/hw/mthca/mthca_memfree.c
drivers/infiniband/hw/ocrdma/ocrdma_ah.c
drivers/infiniband/hw/ocrdma/ocrdma_hw.c
drivers/infiniband/hw/qib/qib_user_pages.c
drivers/infiniband/hw/qib/qib_user_sdma.c
drivers/infiniband/hw/usnic/usnic_uiom.c
drivers/input/evdev.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/ep93xx_keypad.c
drivers/input/keyboard/qt1050.c [new file with mode: 0644]
drivers/input/keyboard/snvs_pwrkey.c
drivers/input/keyboard/sun4i-lradc-keys.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/gpio-vibra.c [new file with mode: 0644]
drivers/input/misc/ixp4xx-beeper.c
drivers/input/misc/max77650-onkey.c [new file with mode: 0644]
drivers/input/mouse/psmouse-base.c
drivers/input/rmi4/rmi_f54.c
drivers/input/serio/Kconfig
drivers/input/serio/hyperv-keyboard.c
drivers/input/serio/i8042.c
drivers/input/serio/libps2.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/edt-ft5x06.c
drivers/input/touchscreen/goodix.c
drivers/input/touchscreen/iqs5xx.c [new file with mode: 0644]
drivers/iommu/Kconfig
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/amd_iommu_types.h
drivers/iommu/arm-smmu-regs.h
drivers/iommu/arm-smmu-v3.c
drivers/iommu/arm-smmu.c
drivers/iommu/dma-iommu.c
drivers/iommu/dmar.c
drivers/iommu/intel-iommu.c
drivers/iommu/intel-pasid.c
drivers/iommu/intel-svm.c
drivers/iommu/intel_irq_remapping.c
drivers/iommu/iommu.c
drivers/iommu/msm_iommu.c
drivers/iommu/mtk_iommu.c
drivers/iommu/tegra-smmu.c
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/irq-ixp4xx.c [new file with mode: 0644]
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-max77650.c [new file with mode: 0644]
drivers/lightnvm/core.c
drivers/lightnvm/pblk-cache.c
drivers/lightnvm/pblk-core.c
drivers/lightnvm/pblk-gc.c
drivers/lightnvm/pblk-init.c
drivers/lightnvm/pblk-map.c
drivers/lightnvm/pblk-rb.c
drivers/lightnvm/pblk-read.c
drivers/lightnvm/pblk-recovery.c
drivers/lightnvm/pblk-write.c
drivers/lightnvm/pblk.h
drivers/mailbox/Kconfig
drivers/mailbox/Makefile
drivers/mailbox/armada-37xx-rwtm-mailbox.c [new file with mode: 0644]
drivers/mailbox/imx-mailbox.c
drivers/mailbox/mtk-cmdq-mailbox.c
drivers/mailbox/stm32-ipcc.c
drivers/md/Kconfig
drivers/md/Makefile
drivers/md/dm-cache-metadata.c
drivers/md/dm-crypt.c
drivers/md/dm-delay.c
drivers/md/dm-dust.c [new file with mode: 0644]
drivers/md/dm-exception-store.h
drivers/md/dm-init.c
drivers/md/dm-integrity.c
drivers/md/dm-ioctl.c
drivers/md/dm-mpath.c
drivers/md/dm-rq.c
drivers/md/dm-snap.c
drivers/md/dm-target.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-writecache.c
drivers/md/dm-zoned-metadata.c
drivers/md/dm-zoned-target.c
drivers/md/dm.c
drivers/md/persistent-data/dm-space-map-common.c
drivers/media/common/videobuf2/videobuf2-core.c
drivers/media/common/videobuf2/videobuf2-dma-contig.c
drivers/media/common/videobuf2/videobuf2-dma-sg.c
drivers/media/platform/atmel/atmel-isc-regs.h
drivers/media/platform/atmel/atmel-isc.c
drivers/media/platform/coda/coda-common.c
drivers/media/platform/davinci/vpbe.c
drivers/media/platform/omap/omap_vout.c
drivers/media/platform/rcar-vin/rcar-csi2.c
drivers/media/platform/tegra-cec/tegra_cec.c
drivers/media/v4l2-core/videobuf-dma-sg.c
drivers/memory/atmel-ebi.c
drivers/memory/emif.h
drivers/memory/tegra/mc.c
drivers/memory/tegra/mc.h
drivers/memory/tegra/tegra114.c
drivers/memory/tegra/tegra124-emc.c
drivers/memory/tegra/tegra124.c
drivers/memory/tegra/tegra20.c
drivers/memory/tegra/tegra210.c
drivers/memory/tegra/tegra30.c
drivers/memory/ti-emif-pm.c
drivers/memory/ti-emif-sram-pm.S
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/ab8500-debugfs.c
drivers/mfd/altera-sysmgr.c [new file with mode: 0644]
drivers/mfd/atmel-hlcdc.c
drivers/mfd/axp20x-i2c.c
drivers/mfd/axp20x.c
drivers/mfd/cros_ec.c
drivers/mfd/cros_ec_dev.c
drivers/mfd/cs47l35-tables.c
drivers/mfd/cs47l90-tables.c
drivers/mfd/da9063-core.c
drivers/mfd/da9063-i2c.c
drivers/mfd/da9063-irq.c
drivers/mfd/intel-lpss-pci.c
drivers/mfd/intel-lpss.c
drivers/mfd/intel_quark_i2c_gpio.c
drivers/mfd/intel_soc_pmic_chtwc.c
drivers/mfd/max77620.c
drivers/mfd/max77650.c [new file with mode: 0644]
drivers/mfd/mfd-core.c
drivers/mfd/rk808.c
drivers/mfd/sec-core.c
drivers/mfd/sec-irq.c
drivers/mfd/ssbi.c
drivers/mfd/stmfx.c [new file with mode: 0644]
drivers/mfd/sun6i-prcm.c
drivers/mfd/syscon.c
drivers/mfd/t7l66xb.c
drivers/mfd/tc6387xb.c
drivers/mfd/tc6393xb.c
drivers/mfd/tps65912-spi.c
drivers/mfd/twl6040.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/aspeed-lpc-ctrl.c [deleted file]
drivers/misc/aspeed-lpc-snoop.c [deleted file]
drivers/misc/aspeed-p2a-ctrl.c [deleted file]
drivers/misc/genwqe/card_utils.c
drivers/misc/pci_endpoint_test.c
drivers/misc/vmw_vmci/vmci_host.c
drivers/misc/vmw_vmci/vmci_queue_pair.c
drivers/mmc/host/meson-mx-sdio.c
drivers/mmc/host/mvsdio.c
drivers/mmc/host/pxamci.c
drivers/mtd/Kconfig
drivers/mtd/Makefile
drivers/mtd/afs.c [deleted file]
drivers/mtd/bcm63xxpart.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/chips/cfi_util.c
drivers/mtd/devices/Kconfig
drivers/mtd/devices/phram.c
drivers/mtd/lpddr/lpddr_cmds.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/physmap-core.c
drivers/mtd/maps/physmap-gemini.c
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/maps/uclinux.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/core.c
drivers/mtd/nand/onenand/onenand_base.c
drivers/mtd/nand/onenand/onenand_bbt.c
drivers/mtd/nand/raw/Kconfig
drivers/mtd/nand/raw/Makefile
drivers/mtd/nand/raw/atmel/nand-controller.c
drivers/mtd/nand/raw/atmel/pmecc.c
drivers/mtd/nand/raw/atmel/pmecc.h
drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
drivers/mtd/nand/raw/brcmnand/brcmnand.c
drivers/mtd/nand/raw/denali.c
drivers/mtd/nand/raw/denali.h
drivers/mtd/nand/raw/denali_dt.c
drivers/mtd/nand/raw/denali_pci.c
drivers/mtd/nand/raw/diskonchip.c
drivers/mtd/nand/raw/fsl_elbc_nand.c
drivers/mtd/nand/raw/fsl_ifc_nand.c
drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
drivers/mtd/nand/raw/hisi504_nand.c
drivers/mtd/nand/raw/ingenic/Kconfig [new file with mode: 0644]
drivers/mtd/nand/raw/ingenic/Makefile [new file with mode: 0644]
drivers/mtd/nand/raw/ingenic/ingenic_ecc.c [new file with mode: 0644]
drivers/mtd/nand/raw/ingenic/ingenic_ecc.h [new file with mode: 0644]
drivers/mtd/nand/raw/ingenic/ingenic_nand.c [new file with mode: 0644]
drivers/mtd/nand/raw/ingenic/jz4725b_bch.c [new file with mode: 0644]
drivers/mtd/nand/raw/ingenic/jz4740_ecc.c [new file with mode: 0644]
drivers/mtd/nand/raw/ingenic/jz4740_nand.c [new file with mode: 0644]
drivers/mtd/nand/raw/ingenic/jz4780_bch.c [new file with mode: 0644]
drivers/mtd/nand/raw/internals.h
drivers/mtd/nand/raw/jz4740_nand.c [deleted file]
drivers/mtd/nand/raw/jz4780_bch.c [deleted file]
drivers/mtd/nand/raw/jz4780_bch.h [deleted file]
drivers/mtd/nand/raw/jz4780_nand.c [deleted file]
drivers/mtd/nand/raw/marvell_nand.c
drivers/mtd/nand/raw/meson_nand.c
drivers/mtd/nand/raw/mtk_nand.c
drivers/mtd/nand/raw/nand_amd.c
drivers/mtd/nand/raw/nand_base.c
drivers/mtd/nand/raw/nand_bbt.c
drivers/mtd/nand/raw/nand_esmt.c
drivers/mtd/nand/raw/nand_hynix.c
drivers/mtd/nand/raw/nand_jedec.c
drivers/mtd/nand/raw/nand_macronix.c
drivers/mtd/nand/raw/nand_micron.c
drivers/mtd/nand/raw/nand_onfi.c
drivers/mtd/nand/raw/nand_samsung.c
drivers/mtd/nand/raw/nand_toshiba.c
drivers/mtd/nand/raw/nandsim.c
drivers/mtd/nand/raw/nuc900_nand.c
drivers/mtd/nand/raw/omap2.c
drivers/mtd/nand/raw/omap_elm.c
drivers/mtd/nand/raw/qcom_nandc.c
drivers/mtd/nand/raw/sh_flctl.c
drivers/mtd/nand/raw/sunxi_nand.c
drivers/mtd/nand/raw/tegra_nand.c
drivers/mtd/nand/raw/vf610_nfc.c
drivers/mtd/nand/spi/core.c
drivers/mtd/nand/spi/gigadevice.c
drivers/mtd/nand/spi/macronix.c
drivers/mtd/nand/spi/micron.c
drivers/mtd/nand/spi/toshiba.c
drivers/mtd/nand/spi/winbond.c
drivers/mtd/parsers/Kconfig
drivers/mtd/parsers/Makefile
drivers/mtd/parsers/afs.c [new file with mode: 0644]
drivers/mtd/parsers/parser_imagetag.c [new file with mode: 0644]
drivers/mtd/sm_ftl.c
drivers/mtd/spi-nor/intel-spi-pci.c
drivers/mtd/spi-nor/intel-spi.c
drivers/mtd/spi-nor/spi-nor.c
drivers/mtd/tests/mtd_nandecctest.c
drivers/mtd/ubi/wl.c
drivers/net/bonding/bond_options.c
drivers/net/ethernet/allwinner/sun4i-emac.c
drivers/net/ethernet/arc/emac_main.c
drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
drivers/net/ethernet/cirrus/Kconfig
drivers/net/ethernet/cirrus/ep93xx_eth.c
drivers/net/ethernet/davicom/dm9000.c
drivers/net/ethernet/freescale/fec_mpc52xx.c
drivers/net/ethernet/freescale/fman/mac.c
drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/ucc_geth.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/ibm/ibmvnic.h
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/mellanox/mlx5/core/eq.c
drivers/net/ethernet/mellanox/mlxsw/Kconfig
drivers/net/ethernet/micrel/ks8851.c
drivers/net/ethernet/micrel/ks8851_mll.c
drivers/net/ethernet/nxp/lpc_eth.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/seeq/sgiseeq.c
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
drivers/net/ethernet/ti/Makefile
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/ethernet/xilinx/xilinx_emaclite.c
drivers/net/ethernet/xscale/ixp4xx_eth.c
drivers/net/ieee802154/ca8210.c
drivers/net/phy/mdio-mux-meson-g12a.c
drivers/net/phy/realtek.c
drivers/net/wan/ixp4xx_hss.c
drivers/net/wireless/mediatek/mt76/eeprom.c
drivers/nvdimm/label.c
drivers/nvdimm/namespace_devs.c
drivers/nvdimm/nd.h
drivers/nvme/host/core.c
drivers/nvme/host/fabrics.c
drivers/nvme/host/fc.c
drivers/nvme/host/lightnvm.c
drivers/nvme/host/multipath.c
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/host/trace.h
drivers/nvmem/zynqmp_nvmem.c
drivers/of/of_net.c
drivers/pci/Makefile
drivers/pci/bus.c
drivers/pci/controller/dwc/Kconfig
drivers/pci/controller/dwc/Makefile
drivers/pci/controller/dwc/pci-dra7xx.c
drivers/pci/controller/dwc/pci-imx6.c
drivers/pci/controller/dwc/pci-keystone.c
drivers/pci/controller/dwc/pci-layerscape-ep.c
drivers/pci/controller/dwc/pci-layerscape.c
drivers/pci/controller/dwc/pcie-al.c [new file with mode: 0644]
drivers/pci/controller/dwc/pcie-artpec6.c
drivers/pci/controller/dwc/pcie-designware-ep.c
drivers/pci/controller/dwc/pcie-designware-host.c
drivers/pci/controller/dwc/pcie-designware-plat.c
drivers/pci/controller/dwc/pcie-designware.c
drivers/pci/controller/dwc/pcie-designware.h
drivers/pci/controller/dwc/pcie-qcom.c
drivers/pci/controller/dwc/pcie-uniphier.c
drivers/pci/controller/pci-aardvark.c
drivers/pci/controller/pci-host-generic.c
drivers/pci/controller/pci-hyperv.c
drivers/pci/controller/pci-tegra.c
drivers/pci/controller/pcie-iproc-msi.c
drivers/pci/controller/pcie-iproc.c
drivers/pci/controller/pcie-mediatek.c
drivers/pci/controller/pcie-rcar.c
drivers/pci/controller/pcie-rockchip-ep.c
drivers/pci/controller/pcie-rockchip-host.c
drivers/pci/controller/pcie-xilinx-nwl.c
drivers/pci/controller/pcie-xilinx.c
drivers/pci/endpoint/functions/pci-epf-test.c
drivers/pci/endpoint/pci-epf-core.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/pciehp_pci.c
drivers/pci/hotplug/rpadlpar_core.c
drivers/pci/hotplug/rpaphp_slot.c
drivers/pci/msi.c
drivers/pci/of.c
drivers/pci/p2pdma.c
drivers/pci/pci-acpi.c
drivers/pci/pci-stub.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer.c
drivers/pci/pcie/aer_inject.c
drivers/pci/pcie/aspm.c
drivers/pci/pcie/bw_notification.c
drivers/pci/pcie/dpc.c
drivers/pci/pcie/pme.c
drivers/pci/probe.c
drivers/pci/proc.c
drivers/pci/quirks.c
drivers/pci/search.c
drivers/pci/setup-bus.c
drivers/pci/slot.c
drivers/pci/switch/switchtec.c
drivers/pci/xen-pcifront.c
drivers/pcmcia/omap_cf.c
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/pinctrl-mcp23s08.c
drivers/pinctrl/pinctrl-stmfx.c [new file with mode: 0644]
drivers/platform/chrome/Kconfig
drivers/platform/chrome/Makefile
drivers/platform/chrome/chromeos_laptop.c
drivers/platform/chrome/cros_ec_debugfs.c
drivers/platform/chrome/cros_ec_proto.c
drivers/platform/chrome/cros_ec_rpmsg.c [new file with mode: 0644]
drivers/platform/chrome/cros_ec_spi.c
drivers/platform/chrome/cros_ec_trace.c [new file with mode: 0644]
drivers/platform/chrome/cros_ec_trace.h [new file with mode: 0644]
drivers/platform/chrome/cros_usbpd_logger.c [new file with mode: 0644]
drivers/platform/chrome/wilco_ec/debugfs.c
drivers/platform/chrome/wilco_ec/mailbox.c
drivers/platform/goldfish/goldfish_pipe.c
drivers/platform/mellanox/Kconfig
drivers/platform/mellanox/Makefile
drivers/platform/mellanox/mlxbf-tmfifo-regs.h [new file with mode: 0644]
drivers/platform/mellanox/mlxbf-tmfifo.c [new file with mode: 0644]
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/alienware-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/dell-rbtn.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_mrfld_pwrbtn.c [new file with mode: 0644]
drivers/platform/x86/intel_pmc_core.c
drivers/platform/x86/intel_pmc_core.h
drivers/platform/x86/intel_pmc_ipc.c
drivers/platform/x86/intel_punit_ipc.c
drivers/platform/x86/mlx-platform.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/touchscreen_dmi.c
drivers/power/reset/at91-sama5d2_shdwc.c
drivers/power/reset/syscon-reboot.c
drivers/power/supply/Kconfig
drivers/power/supply/Makefile
drivers/power/supply/ab8500_bmdata.c
drivers/power/supply/axp20x_usb_power.c
drivers/power/supply/axp288_charger.c
drivers/power/supply/axp288_fuel_gauge.c
drivers/power/supply/bq27xxx_battery.c
drivers/power/supply/charger-manager.c
drivers/power/supply/cpcap-battery.c
drivers/power/supply/cpcap-charger.c
drivers/power/supply/gpio-charger.c
drivers/power/supply/ingenic-battery.c [new file with mode: 0644]
drivers/power/supply/lt3651-charger.c [new file with mode: 0644]
drivers/power/supply/ltc3651-charger.c [deleted file]
drivers/power/supply/max14656_charger_detector.c
drivers/power/supply/max77650-charger.c [new file with mode: 0644]
drivers/power/supply/olpc_battery.c
drivers/power/supply/power_supply_core.c
drivers/power/supply/power_supply_sysfs.c
drivers/power/supply/ucs1002_power.c [new file with mode: 0644]
drivers/pps/clients/pps-gpio.c
drivers/pwm/Kconfig
drivers/pwm/Makefile
drivers/pwm/core.c
drivers/pwm/pwm-berlin.c
drivers/pwm/pwm-ep93xx.c
drivers/pwm/pwm-img.c
drivers/pwm/pwm-imx-tpm.c [new file with mode: 0644]
drivers/pwm/pwm-imx27.c
drivers/pwm/pwm-meson.c
drivers/pwm/pwm-pca9685.c
drivers/pwm/pwm-samsung.c
drivers/pwm/pwm-tiehrpwm.c
drivers/pwm/sysfs.c
drivers/rapidio/devices/rio_mport_cdev.c
drivers/rapidio/rio_cm.c
drivers/reset/reset-zynqmp.c
drivers/rtc/rtc-omap.c
drivers/rtc/rtc-wilco-ec.c
drivers/s390/block/dasd_eckd.c
drivers/s390/cio/qdio_main.c
drivers/s390/cio/trace.c
drivers/s390/cio/trace.h
drivers/s390/virtio/virtio_ccw.c
drivers/sbus/char/oradax.c
drivers/scsi/st.c
drivers/sh/intc/userimask.c
drivers/soc/Kconfig
drivers/soc/Makefile
drivers/soc/amlogic/meson-gx-pwrc-vpu.c
drivers/soc/amlogic/meson-gx-socinfo.c
drivers/soc/aspeed/Kconfig [new file with mode: 0644]
drivers/soc/aspeed/Makefile [new file with mode: 0644]
drivers/soc/aspeed/aspeed-lpc-ctrl.c [new file with mode: 0644]
drivers/soc/aspeed/aspeed-lpc-snoop.c [new file with mode: 0644]
drivers/soc/aspeed/aspeed-p2a-ctrl.c [new file with mode: 0644]
drivers/soc/imx/Makefile
drivers/soc/imx/gpc.c
drivers/soc/imx/gpcv2.c
drivers/soc/imx/soc-imx8.c [new file with mode: 0644]
drivers/soc/ixp4xx/Kconfig [new file with mode: 0644]
drivers/soc/ixp4xx/Makefile [new file with mode: 0644]
drivers/soc/ixp4xx/ixp4xx-npe.c [new file with mode: 0644]
drivers/soc/ixp4xx/ixp4xx-qmgr.c [new file with mode: 0644]
drivers/soc/mediatek/mtk-pmic-wrap.c
drivers/soc/qcom/cmd-db.c
drivers/soc/qcom/qmi_interface.c
drivers/soc/qcom/rmtfs_mem.c
drivers/soc/qcom/rpmh-rsc.c
drivers/soc/renesas/renesas-soc.c
drivers/soc/rockchip/grf.c
drivers/soc/tegra/pmc.c
drivers/soc/ti/Kconfig
drivers/soc/ti/pm33xx.c
drivers/soc/xilinx/zynqmp_pm_domains.c
drivers/soc/xilinx/zynqmp_power.c
drivers/spi/spi-rockchip.c
drivers/spi/spi-zynqmp-gqspi.c
drivers/staging/gasket/gasket_page_table.c
drivers/staging/media/imx/imx-ic-prpencvf.c
drivers/staging/media/imx/imx-media-capture.c
drivers/staging/media/imx/imx-media-csi.c
drivers/staging/media/imx/imx-media.h
drivers/staging/media/imx/imx7-media-csi.c
drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c
drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c
drivers/staging/olpc_dcon/Kconfig
drivers/tee/optee/core.c
drivers/tee/tee_shm.c
drivers/thermal/Kconfig
drivers/thermal/Makefile
drivers/thermal/broadcom/sr-thermal.c
drivers/thermal/cpu_cooling.c
drivers/thermal/intel/Kconfig
drivers/thermal/intel/int340x_thermal/int3403_thermal.c
drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
drivers/thermal/of-thermal.c
drivers/thermal/qcom/Kconfig
drivers/thermal/qcom/Makefile
drivers/thermal/qcom/tsens-8916.c [deleted file]
drivers/thermal/qcom/tsens-8960.c
drivers/thermal/qcom/tsens-8974.c [deleted file]
drivers/thermal/qcom/tsens-common.c
drivers/thermal/qcom/tsens-v0_1.c [new file with mode: 0644]
drivers/thermal/qcom/tsens-v1.c [new file with mode: 0644]
drivers/thermal/qcom/tsens-v2.c
drivers/thermal/qcom/tsens.c
drivers/thermal/qcom/tsens.h
drivers/thermal/qoriq_thermal.c
drivers/thermal/rcar_gen3_thermal.c
drivers/thermal/rcar_thermal.c
drivers/thermal/rockchip_thermal.c
drivers/thermal/st/Kconfig
drivers/thermal/st/stm_thermal.c
drivers/thermal/tegra/Kconfig
drivers/thermal/tegra/soctherm.c
drivers/thermal/tegra/soctherm.h
drivers/thermal/tegra/tegra124-soctherm.c
drivers/thermal/tegra/tegra132-soctherm.c
drivers/thermal/tegra/tegra210-soctherm.c
drivers/thermal/thermal-generic-adc.c
drivers/thermal/thermal_core.c
drivers/thermal/thermal_mmio.c [new file with mode: 0644]
drivers/tty/hvc/hvc_riscv_sbi.c
drivers/tty/sysrq.c
drivers/usb/host/ohci-da8xx.c
drivers/usb/misc/Kconfig
drivers/vfio/mdev/mdev_core.c
drivers/vfio/mdev/mdev_private.h
drivers/vfio/mdev/mdev_sysfs.c
drivers/vfio/pci/vfio_pci.c
drivers/vfio/pci/vfio_pci_config.c
drivers/vfio/pci/vfio_pci_nvlink2.c
drivers/vfio/platform/reset/vfio_platform_amdxgbe.c
drivers/vfio/platform/vfio_platform_common.c
drivers/vfio/vfio.c
drivers/vfio/vfio_iommu_spapr_tce.c
drivers/vfio/vfio_iommu_type1.c
drivers/vhost/scsi.c
drivers/vhost/vhost.c
drivers/video/backlight/Kconfig
drivers/video/backlight/lm3630a_bl.c
drivers/video/backlight/pwm_bl.c
drivers/video/fbdev/Kconfig
drivers/video/fbdev/Makefile
drivers/video/fbdev/amba-clcd-nomadik.c [deleted file]
drivers/video/fbdev/amba-clcd-nomadik.h [deleted file]
drivers/video/fbdev/amba-clcd-versatile.c [deleted file]
drivers/video/fbdev/amba-clcd-versatile.h [deleted file]
drivers/video/fbdev/amba-clcd.c
drivers/video/fbdev/atafb.c
drivers/video/fbdev/atafb_iplan2p2.c
drivers/video/fbdev/atafb_iplan2p4.c
drivers/video/fbdev/atafb_iplan2p8.c
drivers/video/fbdev/atafb_mfb.c
drivers/video/fbdev/atmel_lcdfb.c
drivers/video/fbdev/core/fbcmap.c
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbmem.c
drivers/video/fbdev/core/modedb.c
drivers/video/fbdev/fb-puv3.c
drivers/video/fbdev/hgafb.c
drivers/video/fbdev/imsttfb.c
drivers/video/fbdev/macfb.c
drivers/video/fbdev/mmp/Kconfig
drivers/video/fbdev/mxsfb.c
drivers/video/fbdev/nuc900fb.c
drivers/video/fbdev/omap/Kconfig
drivers/video/fbdev/omap2/omapfb/Kconfig
drivers/video/fbdev/omap2/omapfb/displays/Kconfig
drivers/video/fbdev/omap2/omapfb/dss/Kconfig
drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c
drivers/video/fbdev/pvr2fb.c
drivers/video/fbdev/s3c2410fb.c
drivers/video/fbdev/savage/savagefb_driver.c
drivers/video/fbdev/sm712.h
drivers/video/fbdev/sm712fb.c
drivers/video/fbdev/udlfb.c
drivers/video/fbdev/uvesafb.c
drivers/video/fbdev/vesafb.c
drivers/video/fbdev/xen-fbfront.c
drivers/virt/fsl_hypervisor.c
drivers/virtio/virtio_ring.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/alim7101_wdt.c
drivers/watchdog/armada_37xx_wdt.c
drivers/watchdog/asm9260_wdt.c
drivers/watchdog/aspeed_wdt.c
drivers/watchdog/at91sam9_wdt.c
drivers/watchdog/ath79_wdt.c
drivers/watchdog/atlas7_wdt.c
drivers/watchdog/bcm2835_wdt.c
drivers/watchdog/bcm7038_wdt.c
drivers/watchdog/bcm_kona_wdt.c
drivers/watchdog/bd70528_wdt.c [new file with mode: 0644]
drivers/watchdog/cadence_wdt.c
drivers/watchdog/coh901327_wdt.c
drivers/watchdog/da9052_wdt.c
drivers/watchdog/da9055_wdt.c
drivers/watchdog/da9062_wdt.c
drivers/watchdog/da9063_wdt.c
drivers/watchdog/davinci_wdt.c
drivers/watchdog/digicolor_wdt.c
drivers/watchdog/dw_wdt.c
drivers/watchdog/ebc-c384_wdt.c
drivers/watchdog/ep93xx_wdt.c
drivers/watchdog/f71808e_wdt.c
drivers/watchdog/ftwdt010_wdt.c
drivers/watchdog/gpio_wdt.c
drivers/watchdog/hpwdt.c
drivers/watchdog/i6300esb.c
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/imgpdc_wdt.c
drivers/watchdog/imx2_wdt.c
drivers/watchdog/imx_sc_wdt.c [new file with mode: 0644]
drivers/watchdog/intel-mid_wdt.c
drivers/watchdog/intel_scu_watchdog.c
drivers/watchdog/ixp4xx_wdt.c
drivers/watchdog/jz4740_wdt.c
drivers/watchdog/kempld_wdt.c
drivers/watchdog/lantiq_wdt.c
drivers/watchdog/loongson1_wdt.c
drivers/watchdog/lpc18xx_wdt.c
drivers/watchdog/machzwd.c
drivers/watchdog/max63xx_wdt.c
drivers/watchdog/max77620_wdt.c
drivers/watchdog/mena21_wdt.c
drivers/watchdog/menf21bmc_wdt.c
drivers/watchdog/meson_gxbb_wdt.c
drivers/watchdog/meson_wdt.c
drivers/watchdog/mlx_wdt.c
drivers/watchdog/moxart_wdt.c
drivers/watchdog/mpc8xxx_wdt.c
drivers/watchdog/mt7621_wdt.c
drivers/watchdog/mtk_wdt.c
drivers/watchdog/ni903x_wdt.c
drivers/watchdog/nic7018_wdt.c
drivers/watchdog/npcm_wdt.c
drivers/watchdog/nuc900_wdt.c
drivers/watchdog/of_xilinx_wdt.c
drivers/watchdog/omap_wdt.c
drivers/watchdog/orion_wdt.c
drivers/watchdog/pic32-dmt.c
drivers/watchdog/pic32-wdt.c
drivers/watchdog/pm8916_wdt.c
drivers/watchdog/pnx4008_wdt.c
drivers/watchdog/qcom-wdt.c
drivers/watchdog/renesas_wdt.c
drivers/watchdog/rn5t618_wdt.c
drivers/watchdog/rt2880_wdt.c
drivers/watchdog/rtd119x_wdt.c
drivers/watchdog/rza_wdt.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sama5d4_wdt.c
drivers/watchdog/sb_wdog.c
drivers/watchdog/sbsa_gwdt.c
drivers/watchdog/shwdt.c
drivers/watchdog/sirfsoc_wdt.c
drivers/watchdog/sp5100_tco.c
drivers/watchdog/sprd_wdt.c
drivers/watchdog/st_lpc_wdt.c
drivers/watchdog/stm32_iwdg.c
drivers/watchdog/stmp3xxx_rtc_wdt.c
drivers/watchdog/stpmic1_wdt.c
drivers/watchdog/sunxi_wdt.c
drivers/watchdog/tangox_wdt.c
drivers/watchdog/tegra_wdt.c
drivers/watchdog/tqmx86_wdt.c
drivers/watchdog/ts4800_wdt.c
drivers/watchdog/ts72xx_wdt.c
drivers/watchdog/twl4030_wdt.c
drivers/watchdog/txx9wdt.c
drivers/watchdog/uniphier_wdt.c
drivers/watchdog/ux500_wdt.c
drivers/watchdog/watchdog_core.c
drivers/watchdog/wdat_wdt.c
drivers/watchdog/wm831x_wdt.c
drivers/watchdog/xen_wdt.c
drivers/watchdog/ziirave_wdt.c
drivers/watchdog/zx2967_wdt.c
drivers/xen/gntdev.c
drivers/xen/privcmd-buf.c
drivers/xen/xen-pciback/xenbus.c
drivers/xen/xenbus/xenbus_dev_frontend.c
fs/afs/addr_list.c
fs/afs/afs.h
fs/afs/callback.c
fs/afs/cell.c
fs/afs/cmservice.c
fs/afs/dir.c
fs/afs/dir_silly.c
fs/afs/dynroot.c
fs/afs/file.c
fs/afs/flock.c
fs/afs/fs_probe.c
fs/afs/fsclient.c
fs/afs/inode.c
fs/afs/internal.h
fs/afs/proc.c
fs/afs/rotate.c
fs/afs/rxrpc.c
fs/afs/security.c
fs/afs/server.c
fs/afs/super.c
fs/afs/vl_list.c
fs/afs/vl_probe.c
fs/afs/vl_rotate.c
fs/afs/vlclient.c
fs/afs/write.c
fs/afs/xattr.c
fs/afs/yfsclient.c
fs/binfmt_elf.c
fs/block_dev.c
fs/cachefiles/namei.c
fs/ceph/caps.c
fs/ceph/debugfs.c
fs/ceph/export.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/locks.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/ceph/mdsmap.c
fs/ceph/quota.c
fs/ceph/super.c
fs/ceph/super.h
fs/cifs/dns_resolve.c
fs/coda/psdev.c
fs/configfs/dir.c
fs/dax.c
fs/eventfd.c
fs/exec.c
fs/ext2/inode.c
fs/f2fs/acl.c
fs/f2fs/checkpoint.c
fs/f2fs/data.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/gc.c
fs/f2fs/inline.c
fs/f2fs/inode.c
fs/f2fs/namei.c
fs/f2fs/node.c
fs/f2fs/recovery.c
fs/f2fs/segment.c
fs/f2fs/segment.h
fs/f2fs/super.c
fs/f2fs/xattr.c
fs/f2fs/xattr.h
fs/fat/file.c
fs/fsopen.c
fs/fuse/control.c
fs/fuse/cuse.c
fs/fuse/dev.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/gfs2/sys.c
fs/hostfs/hostfs.h
fs/hugetlbfs/inode.c
fs/io_uring.c
fs/lockd/clntlock.c
fs/lockd/svc.c
fs/locks.c
fs/nfs/callback.c
fs/nfs/callback_xdr.c
fs/nfs/client.c
fs/nfs/dns_resolve.c
fs/nfsd/export.c
fs/nfsd/netns.h
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4idmap.c
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4recover.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsd.h
fs/nfsd/nfssvc.c
fs/nfsd/nfsxdr.c
fs/nfsd/state.h
fs/nfsd/vfs.c
fs/nfsd/vfs.h
fs/notify/fsnotify.c
fs/notify/mark.c
fs/ocfs2/dir.c
fs/ocfs2/export.c
fs/ocfs2/ocfs2_fs.h
fs/orangefs/orangefs-bufmap.c
fs/overlayfs/copy_up.c
fs/overlayfs/dir.c
fs/overlayfs/file.c
fs/overlayfs/inode.c
fs/overlayfs/overlayfs.h
fs/proc/base.c
fs/proc/task_mmu.c
fs/quota/dquot.c
fs/quota/quota_v1.c
fs/quota/quota_v2.c
fs/reiserfs/journal.c
fs/reiserfs/xattr.c
fs/sync.c
fs/ubifs/auth.c
fs/ubifs/debug.c
fs/ubifs/dir.c
fs/ubifs/file.c
fs/ubifs/find.c
fs/ubifs/ioctl.c
fs/ubifs/journal.c
fs/ubifs/misc.h
fs/ubifs/orphan.c
fs/ubifs/sb.c
fs/ubifs/super.c
fs/ubifs/tnc.c
fs/ubifs/ubifs.h
fs/ubifs/xattr.c
fs/udf/namei.c
fs/udf/super.c
fs/userfaultfd.c
include/acpi/acpi_bus.h
include/acpi/acpixf.h
include/acpi/platform/aclinux.h
include/asm-generic/hugetlb.h
include/asm-generic/segment.h [deleted file]
include/asm-generic/shmparam.h
include/asm-generic/sizes.h [deleted file]
include/asm-generic/uaccess.h
include/asm-generic/vmlinux.lds.h
include/dt-bindings/clock/xlnx,zynqmp-clk.h [deleted file]
include/dt-bindings/clock/xlnx-zynqmp-clk.h [new file with mode: 0644]
include/dt-bindings/firmware/imx/rsrc.h
include/dt-bindings/pinctrl/am33xx.h
include/dt-bindings/pinctrl/omap.h
include/dt-bindings/power/r8a77965-sysc.h
include/dt-bindings/thermal/tegra124-soctherm.h
include/linux/acpi.h
include/linux/amba/clcd.h
include/linux/armada-37xx-rwtm-mailbox.h [new file with mode: 0644]
include/linux/balloon_compaction.h
include/linux/binfmts.h
include/linux/bitops.h
include/linux/ceph/ceph_fs.h
include/linux/ceph/messenger.h
include/linux/ceph/osdmap.h
include/linux/clk-provider.h
include/linux/compiler.h
include/linux/compiler_types.h
include/linux/cper.h
include/linux/cpu.h
include/linux/cpufreq.h
include/linux/cpumask.h
include/linux/device-mapper.h
include/linux/dns_resolver.h
include/linux/f2fs_fs.h
include/linux/firmware/imx/sci.h
include/linux/firmware/trusted_foundations.h [new file with mode: 0644]
include/linux/firmware/xlnx-zynqmp.h
include/linux/fscrypt.h
include/linux/fsnotify.h
include/linux/fsnotify_backend.h
include/linux/ftrace.h
include/linux/gfp.h
include/linux/gpio/driver.h
include/linux/gpio/machine.h
include/linux/hmm.h
include/linux/huge_mm.h
include/linux/hugetlb.h
include/linux/iio/consumer.h
include/linux/intel-iommu.h
include/linux/iommu.h
include/linux/iova.h
include/linux/ipc_namespace.h
include/linux/irqchip/irq-ixp4xx.h [new file with mode: 0644]
include/linux/kernel.h
include/linux/kthread.h
include/linux/kvm_host.h
include/linux/latencytop.h
include/linux/lightnvm.h
include/linux/list.h
include/linux/list_bl.h
include/linux/list_sort.h
include/linux/lockd/bind.h
include/linux/mdev.h
include/linux/memblock.h
include/linux/memcontrol.h
include/linux/memory.h
include/linux/memory_hotplug.h
include/linux/mfd/altera-sysmgr.h [new file with mode: 0644]
include/linux/mfd/cros_ec.h
include/linux/mfd/cros_ec_commands.h
include/linux/mfd/da9063/core.h
include/linux/mfd/da9063/registers.h
include/linux/mfd/max77620.h
include/linux/mfd/max77650.h [new file with mode: 0644]
include/linux/mfd/stmfx.h [new file with mode: 0644]
include/linux/mfd/syscon/atmel-matrix.h
include/linux/mfd/syscon/atmel-mc.h
include/linux/mfd/syscon/atmel-smc.h
include/linux/mfd/syscon/atmel-st.h
include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
include/linux/mlx5/mlx5_ifc.h
include/linux/mm.h
include/linux/mm_inline.h
include/linux/mm_types.h
include/linux/mmu_notifier.h
include/linux/mmzone.h
include/linux/module.h
include/linux/msi.h
include/linux/mtd/bbm.h
include/linux/mtd/nand.h
include/linux/mtd/nand_bch.h
include/linux/mtd/onenand.h
include/linux/mtd/rawnand.h
include/linux/mtd/spinand.h
include/linux/nvme.h
include/linux/overflow.h
include/linux/pagemap.h
include/linux/pci-ecam.h
include/linux/pci-epc.h
include/linux/pci-epf.h
include/linux/pci.h
include/linux/pci_hotplug.h
include/linux/percpu.h
include/linux/perf_event.h
include/linux/platform_data/elm.h
include/linux/platform_data/eth-ep93xx.h [new file with mode: 0644]
include/linux/platform_data/gpio-omap.h
include/linux/platform_data/keypad-ep93xx.h
include/linux/platform_data/lm3630a_bl.h
include/linux/platform_data/pm33xx.h
include/linux/platform_data/ti-sysc.h
include/linux/platform_data/timer-ixp4xx.h [new file with mode: 0644]
include/linux/platform_data/wilco-ec.h
include/linux/platform_data/x86/asus-wmi.h
include/linux/platform_data/xtalk-bridge.h [new file with mode: 0644]
include/linux/plist.h
include/linux/pm_domain.h
include/linux/poll.h
include/linux/power_supply.h
include/linux/pps-gpio.h
include/linux/printk.h
include/linux/psi.h
include/linux/psi_types.h
include/linux/pwm.h
include/linux/qcom-geni-se.h
include/linux/random.h
include/linux/reboot.h
include/linux/reset.h
include/linux/rtc/rtc-omap.h [new file with mode: 0644]
include/linux/sched.h
include/linux/sched/signal.h
include/linux/slab_def.h
include/linux/soc/cirrus/ep93xx.h [new file with mode: 0644]
include/linux/soc/ixp4xx/npe.h [new file with mode: 0644]
include/linux/soc/ixp4xx/qmgr.h [new file with mode: 0644]
include/linux/sunrpc/svc.h
include/linux/sunrpc/svc_xprt.h
include/linux/sunrpc/svcsock.h
include/linux/switchtec.h
include/linux/thermal.h
include/linux/ti-emif-sram.h
include/linux/tracepoint.h
include/linux/userfaultfd_k.h
include/linux/virtio.h
include/linux/vmstat.h
include/linux/wait_bit.h
include/media/davinci/vpbe.h
include/net/af_rxrpc.h
include/net/dsa.h
include/soc/at91/atmel-sfr.h
include/sound/hdaudio.h
include/trace/define_trace.h
include/trace/events/compaction.h
include/trace/events/f2fs.h
include/trace/events/gpio.h
include/trace/events/rcu.h
include/trace/events/sched.h
include/trace/events/vmscan.h
include/trace/events/writeback.h
include/uapi/asm-generic/unistd.h
include/uapi/linux/bpf.h
include/uapi/linux/fs.h
include/uapi/linux/fuse.h
include/uapi/linux/input-event-codes.h
include/uapi/linux/kvm.h
include/uapi/linux/netfilter/nf_tables.h
include/uapi/linux/nfsd/cld.h
include/uapi/linux/pci_regs.h
include/uapi/linux/switchtec_ioctl.h
include/uapi/rdma/rdma_netlink.h
include/video/udlfb.h
init/Kconfig
init/initramfs.c
init/main.c
ipc/ipc_sysctl.c
ipc/mqueue.c
ipc/msgutil.c
ipc/util.c
ipc/util.h
kernel/Makefile
kernel/bpf/core.c
kernel/bpf/verifier.c
kernel/cgroup/cgroup.c
kernel/compat.c
kernel/debug/gdbstub.c
kernel/debug/kdb/Makefile
kernel/debug/kdb/kdb_io.c
kernel/debug/kdb/kdb_main.c
kernel/debug/kdb/kdb_support.c
kernel/events/uprobes.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/gcov/Kconfig
kernel/gcov/Makefile
kernel/gcov/base.c
kernel/gcov/clang.c [new file with mode: 0644]
kernel/gcov/gcc_3_4.c
kernel/gcov/gcc_4_7.c
kernel/gcov/gcc_base.c [new file with mode: 0644]
kernel/gcov/gcov.h
kernel/kexec_file.c
kernel/kthread.c
kernel/latencytop.c
kernel/livepatch/core.c
kernel/locking/rwsem-xadd.c
kernel/memremap.c
kernel/module-internal.h
kernel/module.c
kernel/notifier.c
kernel/panic.c
kernel/pid.c
kernel/printk/printk.c
kernel/rcu/rcu.h
kernel/rcu/tree.c
kernel/reboot.c
kernel/sched/psi.c
kernel/signal.c
kernel/sys.c
kernel/sysctl.c
kernel/time/ntp.c
kernel/trace/Kconfig
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/ring_buffer_benchmark.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_events.c
kernel/trace/trace_events_filter.c
kernel/trace/trace_events_hist.c
kernel/trace/trace_events_trigger.c
kernel/trace/trace_kdb.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_probe.c
kernel/trace/trace_probe.h
kernel/trace/trace_probe_tmpl.h
kernel/trace/trace_selftest.c
kernel/trace/trace_uprobe.c
kernel/user.c
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/bitmap.c
lib/cordic.c [deleted file]
lib/div64.c [deleted file]
lib/gcd.c [deleted file]
lib/hweight.c
lib/int_sqrt.c [deleted file]
lib/iov_iter.c
lib/lcm.c [deleted file]
lib/list_sort.c
lib/math/Kconfig [new file with mode: 0644]
lib/math/Makefile [new file with mode: 0644]
lib/math/cordic.c [new file with mode: 0644]
lib/math/div64.c [new file with mode: 0644]
lib/math/gcd.c [new file with mode: 0644]
lib/math/int_pow.c [new file with mode: 0644]
lib/math/int_sqrt.c [new file with mode: 0644]
lib/math/lcm.c [new file with mode: 0644]
lib/math/prime_numbers.c [new file with mode: 0644]
lib/math/rational.c [new file with mode: 0644]
lib/math/reciprocal_div.c [new file with mode: 0644]
lib/plist.c
lib/prime_numbers.c [deleted file]
lib/rational.c [deleted file]
lib/reciprocal_div.c [deleted file]
lib/sort.c
lib/test_bitmap.c
lib/test_sysctl.c
lib/test_vmalloc.c
lib/vsprintf.c
mm/Kconfig
mm/Kconfig.debug
mm/Makefile
mm/cma.c
mm/cma_debug.c
mm/compaction.c
mm/debug.c
mm/filemap.c
mm/gup.c
mm/gup_benchmark.c
mm/hmm.c
mm/huge_memory.c
mm/hugetlb.c
mm/khugepaged.c
mm/ksm.c
mm/madvise.c
mm/memblock.c
mm/memcontrol.c
mm/memfd.c
mm/memory.c
mm/memory_hotplug.c
mm/migrate.c
mm/mincore.c
mm/mmu_notifier.c
mm/mprotect.c
mm/mremap.c
mm/nommu.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_isolation.c
mm/percpu-internal.h
mm/percpu-km.c
mm/percpu-stats.c
mm/percpu.c
mm/rmap.c
mm/shmem.c
mm/shuffle.c [new file with mode: 0644]
mm/shuffle.h [new file with mode: 0644]
mm/slab.c
mm/slob.c
mm/slub.c
mm/sparse.c
mm/swap.c
mm/swap_state.c
mm/userfaultfd.c
mm/util.c
mm/vmalloc.c
mm/vmscan.c
mm/workingset.c
mm/z3fold.c
net/bridge/br_if.c
net/bridge/netfilter/ebtables.c
net/ceph/cls_lock_client.c
net/ceph/debugfs.c
net/ceph/messenger.c
net/ceph/mon_client.c
net/ceph/osd_client.c
net/ceph/pagevec.c
net/core/flow_dissector.c
net/dccp/proto.c
net/dns_resolver/dns_query.c
net/dsa/slave.c
net/dsa/tag_brcm.c
net/netfilter/core.c
net/netfilter/nf_conntrack_h323_asn1.c
net/netfilter/nf_conntrack_h323_main.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_flow_table_core.c
net/netfilter/nf_flow_table_ip.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_flow_offload.c
net/qrtr/qrtr.c
net/rds/info.c
net/rds/rdma.c
net/rxrpc/af_rxrpc.c
net/rxrpc/ar-internal.h
net/rxrpc/call_object.c
net/rxrpc/conn_client.c
net/rxrpc/sendmsg.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/cache.c
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c
net/sunrpc/svcauth_unix.c
net/sunrpc/svcsock.c
net/xdp/xdp_umem.c
samples/pidfd/.gitignore [new file with mode: 0644]
samples/vfs/.gitignore [new file with mode: 0644]
scripts/bpf_helpers_doc.py
scripts/gcc-plugins/arm_ssp_per_task_plugin.c
scripts/gdb/linux/clk.py [new file with mode: 0644]
scripts/gdb/linux/config.py [new file with mode: 0644]
scripts/gdb/linux/constants.py.in
scripts/gdb/linux/cpus.py
scripts/gdb/linux/lists.py
scripts/gdb/linux/proc.py
scripts/gdb/linux/rbtree.py [new file with mode: 0644]
scripts/gdb/linux/symbols.py
scripts/gdb/linux/tasks.py
scripts/gdb/linux/timerlist.py [new file with mode: 0644]
scripts/gdb/linux/utils.py
scripts/gdb/vmlinux-gdb.py
scripts/kconfig/confdata.c
scripts/kconfig/gconf.c
scripts/kconfig/lexer.l
scripts/kconfig/lkc.h
scripts/kconfig/lxdialog/BIG.FAT.WARNING
scripts/kconfig/mconf.c
scripts/kconfig/nconf-cfg.sh [changed mode: 0644->0755]
scripts/kconfig/nconf.c
security/selinux/hooks.c
security/tomoyo/Kconfig
security/tomoyo/common.c
security/tomoyo/network.c
security/tomoyo/realpath.c
security/tomoyo/util.c
sound/hda/hdac_device.c
sound/hda/hdac_sysfs.c
sound/pci/hda/patch_realtek.c
sound/soc/cirrus/edb93xx.c
sound/soc/cirrus/ep93xx-ac97.c
sound/soc/cirrus/ep93xx-i2s.c
sound/soc/cirrus/simone.c
sound/soc/cirrus/snappercl15.c
sound/soc/mxs/mxs-saif.c
tools/arch/s390/include/uapi/asm/kvm.h
tools/include/uapi/linux/bpf.h
tools/lib/bpf/libbpf.c
tools/lib/bpf/libbpf_internal.h [new file with mode: 0644]
tools/lib/bpf/libbpf_probes.c
tools/objtool/Documentation/stack-validation.txt
tools/objtool/check.c
tools/pci/Makefile
tools/pci/pcitest.c
tools/power/x86/turbostat/Makefile
tools/power/x86/x86_energy_perf_policy/Makefile
tools/testing/ktest/ktest.pl
tools/testing/ktest/sample.conf
tools/testing/nvdimm/Kbuild
tools/testing/nvdimm/dax_pmem_compat_test.c [new file with mode: 0644]
tools/testing/nvdimm/dax_pmem_core_test.c [new file with mode: 0644]
tools/testing/nvdimm/dax_pmem_test.c [new file with mode: 0644]
tools/testing/nvdimm/test/nfit.c
tools/testing/nvdimm/watermark.h
tools/testing/selftests/.gitignore
tools/testing/selftests/Makefile
tools/testing/selftests/bpf/.gitignore
tools/testing/selftests/bpf/verifier/jump.c
tools/testing/selftests/breakpoints/breakpoint_test.c
tools/testing/selftests/breakpoints/breakpoint_test_arm64.c
tools/testing/selftests/breakpoints/step_after_suspend_test.c
tools/testing/selftests/capabilities/test_execve.c
tools/testing/selftests/drivers/.gitignore [new file with mode: 0644]
tools/testing/selftests/exec/.gitignore
tools/testing/selftests/exec/Makefile
tools/testing/selftests/exec/recursion-depth.c [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/ftrace/tracing-error-log.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/functions
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-extended-error-support.tc [deleted file]
tools/testing/selftests/futex/functional/futex_requeue_pi.c
tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c
tools/testing/selftests/futex/functional/futex_wait_timeout.c
tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c
tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
tools/testing/selftests/kselftest.h
tools/testing/selftests/kselftest/prefix.pl [new file with mode: 0755]
tools/testing/selftests/kselftest/runner.sh [new file with mode: 0644]
tools/testing/selftests/kvm/.gitignore
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/dirty_log_test.c
tools/testing/selftests/kvm/include/kvm_util.h
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/x86_64/kvm_create_max_vcpus.c [new file with mode: 0644]
tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c [new file with mode: 0644]
tools/testing/selftests/lib.mk
tools/testing/selftests/membarrier/membarrier_test.c
tools/testing/selftests/pidfd/.gitignore [new file with mode: 0644]
tools/testing/selftests/pidfd/pidfd_test.c
tools/testing/selftests/rseq/Makefile
tools/testing/selftests/rseq/rseq-arm.h
tools/testing/selftests/rseq/rseq-arm64.h
tools/testing/selftests/rseq/rseq-mips.h
tools/testing/selftests/rseq/rseq-ppc.h
tools/testing/selftests/rseq/rseq-s390.h
tools/testing/selftests/rseq/rseq-x86.h
tools/testing/selftests/rseq/rseq.c
tools/testing/selftests/rseq/rseq.h
tools/testing/selftests/sigaltstack/sas.c
tools/testing/selftests/sync/sync_test.c
tools/testing/selftests/sysctl/sysctl.sh
tools/virtio/ringtest/ptr_ring.c
virt/kvm/Kconfig
virt/kvm/arm/arm.c
virt/kvm/kvm_main.c

index f814f112e213bf50b08e1f29f5f8591e2f10592e..73a5a66ddca655ce547e9f1bf9e343bebbedf065 100644 (file)
@@ -1,23 +1,46 @@
+What:          /sys/kernel/debug/wilco_ec/h1_gpio
+Date:          April 2019
+KernelVersion: 5.2
+Description:
+               As part of Chrome OS's FAFT (Fully Automated Firmware Testing)
+               tests, we need to ensure that the H1 chip is properly setting
+               some GPIO lines. The h1_gpio attribute exposes the state
+               of the lines:
+               - ENTRY_TO_FACT_MODE in BIT(0)
+               - SPI_CHROME_SEL in BIT(1)
+
+               Output will formatted with "0x%02x\n".
+
 What:          /sys/kernel/debug/wilco_ec/raw
 Date:          January 2019
 KernelVersion: 5.1
 Description:
                Write and read raw mailbox commands to the EC.
 
-               For writing:
-               Bytes 0-1 indicate the message type:
-                       00 F0 = Execute Legacy Command
-                       00 F2 = Read/Write NVRAM Property
-               Byte 2 provides the command code
-               Bytes 3+ consist of the data passed in the request
+               You can write a hexadecimal sentence to raw, and that series of
+               bytes will be sent to the EC. Then, you can read the bytes of
+               response by reading from raw.
 
-               At least three bytes are required, for the msg type and command,
-               with additional bytes optional for additional data.
+               For writing, bytes 0-1 indicate the message type, one of enum
+               wilco_ec_msg_type. Byte 2+ consist of the data passed in the
+               request, starting at MBOX[0]
+
+               At least three bytes are required for writing, two for the type
+               and at least a single byte of data. Only the first
+               EC_MAILBOX_DATA_SIZE bytes of MBOX will be used.
 
                Example:
                // Request EC info type 3 (EC firmware build date)
-               $ echo 00 f0 38 00 03 00 > raw
+               // Corresponds with sending type 0x00f0 with
+               // MBOX = [38, 00, 03, 00]
+               $ echo 00 f0 38 00 03 00 > /sys/kernel/debug/wilco_ec/raw
                // View the result. The decoded ASCII result "12/21/18" is
                // included after the raw hex.
-               $ cat raw
-               00 31 32 2f 32 31 2f 31 38 00 38 00 01 00 2f 00  .12/21/18.8...
+               // Corresponds with MBOX = [00, 00, 31, 32, 2f, 32, 31, 38, ...]
+               $ cat /sys/kernel/debug/wilco_ec/raw
+               00 00 31 32 2f 32 31 2f 31 38 00 38 00 01 00 2f 00  ..12/21/18.8...
+
+               Note that the first 32 bytes of the received MBOX[] will be
+               printed, even if some of the data is junk. It is up to you to
+               know how many of the first bytes of data are the actual
+               response.
index 5e23e22dce1b514d133ac6371163da37fe5a7ed1..b77e30b9014efb862f12e71f3e5efcee7431b805 100644 (file)
@@ -114,15 +114,60 @@ Description:
                Access: Read
                Valid values: Represented in microamps
 
+What:          /sys/class/power_supply/<supply_name>/charge_control_limit
+Date:          Oct 2012
+Contact:       linux-pm@vger.kernel.org
+Description:
+               Maximum allowable charging current. Used for charge rate
+               throttling for thermal cooling or improving battery health.
+
+               Access: Read, Write
+               Valid values: Represented in microamps
+
+What:          /sys/class/power_supply/<supply_name>/charge_control_limit_max
+Date:          Oct 2012
+Contact:       linux-pm@vger.kernel.org
+Description:
+               Maximum legal value for the charge_control_limit property.
+
+               Access: Read
+               Valid values: Represented in microamps
+
+What:          /sys/class/power_supply/<supply_name>/charge_control_start_threshold
+Date:          April 2019
+Contact:       linux-pm@vger.kernel.org
+Description:
+               Represents a battery percentage level, below which charging will
+               begin.
+
+               Access: Read, Write
+               Valid values: 0 - 100 (percent)
+
+What:          /sys/class/power_supply/<supply_name>/charge_control_end_threshold
+Date:          April 2019
+Contact:       linux-pm@vger.kernel.org
+Description:
+               Represents a battery percentage level, above which charging will
+               stop.
+
+               Access: Read, Write
+               Valid values: 0 - 100 (percent)
+
 What:          /sys/class/power_supply/<supply_name>/charge_type
 Date:          July 2009
 Contact:       linux-pm@vger.kernel.org
 Description:
                Represents the type of charging currently being applied to the
-               battery.
+               battery. "Trickle", "Fast", and "Standard" all mean different
+               charging speeds. "Adaptive" means that the charger uses some
+               algorithm to adjust the charge rate dynamically, without
+               any user configuration required. "Custom" means that the charger
+               uses the charge_control_* properties as configuration for some
+               different algorithm.
 
-               Access: Read
-               Valid values: "Unknown", "N/A", "Trickle", "Fast"
+               Access: Read, Write
+               Valid values: "Unknown", "N/A", "Trickle", "Fast", "Standard",
+                             "Adaptive", "Custom"
 
 What:          /sys/class/power_supply/<supply_name>/charge_term_current
 Date:          July 2014
index 4fb76c0e8d30a147a200de73e415d8df665e95c5..1528239f69b2fea8a2f595dac7ebd379cf97714a 100644 (file)
@@ -484,6 +484,7 @@ What:               /sys/devices/system/cpu/vulnerabilities
                /sys/devices/system/cpu/vulnerabilities/spectre_v2
                /sys/devices/system/cpu/vulnerabilities/spec_store_bypass
                /sys/devices/system/cpu/vulnerabilities/l1tf
+               /sys/devices/system/cpu/vulnerabilities/mds
 Date:          January 2018
 Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
 Description:   Information about CPU vulnerabilities
@@ -496,8 +497,7 @@ Description:        Information about CPU vulnerabilities
                "Vulnerable"      CPU is affected and no mitigation in effect
                "Mitigation: $M"  CPU is affected and mitigation $M is in effect
 
-               Details about the l1tf file can be found in
-               Documentation/admin-guide/l1tf.rst
+               See also: Documentation/admin-guide/hw-vuln/index.rst
 
 What:          /sys/devices/system/cpu/smt
                /sys/devices/system/cpu/smt/active
index 7e71c9c1d8e9c7eee70ef957610b483a58739232..5cbe5659e3b7ab0a381a5ee3444e24646cc558ed 100644 (file)
@@ -63,6 +63,110 @@ as well as medium and long term trends. The total absolute stall time
 spikes which wouldn't necessarily make a dent in the time averages,
 or to average trends over custom time frames.
 
+Monitoring for pressure thresholds
+==================================
+
+Users can register triggers and use poll() to be woken up when resource
+pressure exceeds certain thresholds.
+
+A trigger describes the maximum cumulative stall time over a specific
+time window, e.g. 100ms of total stall time within any 500ms window to
+generate a wakeup event.
+
+To register a trigger user has to open psi interface file under
+/proc/pressure/ representing the resource to be monitored and write the
+desired threshold and time window. The open file descriptor should be
+used to wait for trigger events using select(), poll() or epoll().
+The following format is used:
+
+<some|full> <stall amount in us> <time window in us>
+
+For example writing "some 150000 1000000" into /proc/pressure/memory
+would add 150ms threshold for partial memory stall measured within
+1sec time window. Writing "full 50000 1000000" into /proc/pressure/io
+would add 50ms threshold for full io stall measured within 1sec time window.
+
+Triggers can be set on more than one psi metric and more than one trigger
+for the same psi metric can be specified. However for each trigger a separate
+file descriptor is required to be able to poll it separately from others,
+therefore for each trigger a separate open() syscall should be made even
+when opening the same psi interface file.
+
+Monitors activate only when system enters stall state for the monitored
+psi metric and deactivates upon exit from the stall state. While system is
+in the stall state psi signal growth is monitored at a rate of 10 times per
+tracking window.
+
+The kernel accepts window sizes ranging from 500ms to 10s, therefore min
+monitoring update interval is 50ms and max is 1s. Min limit is set to
+prevent overly frequent polling. Max limit is chosen as a high enough number
+after which monitors are most likely not needed and psi averages can be used
+instead.
+
+When activated, psi monitor stays active for at least the duration of one
+tracking window to avoid repeated activations/deactivations when system is
+bouncing in and out of the stall state.
+
+Notifications to the userspace are rate-limited to one per tracking window.
+
+The trigger will de-register when the file descriptor used to define the
+trigger  is closed.
+
+Userspace monitor usage example
+===============================
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <poll.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * Monitor memory partial stall with 1s tracking window size
+ * and 150ms threshold.
+ */
+int main() {
+       const char trig[] = "some 150000 1000000";
+       struct pollfd fds;
+       int n;
+
+       fds.fd = open("/proc/pressure/memory", O_RDWR | O_NONBLOCK);
+       if (fds.fd < 0) {
+               printf("/proc/pressure/memory open error: %s\n",
+                       strerror(errno));
+               return 1;
+       }
+       fds.events = POLLPRI;
+
+       if (write(fds.fd, trig, strlen(trig) + 1) < 0) {
+               printf("/proc/pressure/memory write error: %s\n",
+                       strerror(errno));
+               return 1;
+       }
+
+       printf("waiting for events...\n");
+       while (1) {
+               n = poll(&fds, 1, -1);
+               if (n < 0) {
+                       printf("poll error: %s\n", strerror(errno));
+                       return 1;
+               }
+               if (fds.revents & POLLERR) {
+                       printf("got POLLERR, event source is gone\n");
+                       return 0;
+               }
+               if (fds.revents & POLLPRI) {
+                       printf("event triggered!\n");
+               } else {
+                       printf("unknown event received: 0x%x\n", fds.revents);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
 Cgroup2 interface
 =================
 
@@ -71,3 +175,6 @@ mounted, pressure stall information is also tracked for tasks grouped
 into cgroups. Each subdirectory in the cgroupfs mountpoint contains
 cpu.pressure, memory.pressure, and io.pressure files; the format is
 the same as the /proc/pressure/ files.
+
+Per-cgroup psi monitors can be specified and used the same way as
+system-wide ones.
diff --git a/Documentation/admin-guide/hw-vuln/index.rst b/Documentation/admin-guide/hw-vuln/index.rst
new file mode 100644 (file)
index 0000000..ffc064c
--- /dev/null
@@ -0,0 +1,13 @@
+========================
+Hardware vulnerabilities
+========================
+
+This section describes CPU vulnerabilities and provides an overview of the
+possible mitigations along with guidance for selecting mitigations if they
+are configurable at compile, boot or run time.
+
+.. toctree::
+   :maxdepth: 1
+
+   l1tf
+   mds
diff --git a/Documentation/admin-guide/hw-vuln/l1tf.rst b/Documentation/admin-guide/hw-vuln/l1tf.rst
new file mode 100644 (file)
index 0000000..31653a9
--- /dev/null
@@ -0,0 +1,615 @@
+L1TF - L1 Terminal Fault
+========================
+
+L1 Terminal Fault is a hardware vulnerability which allows unprivileged
+speculative access to data which is available in the Level 1 Data Cache
+when the page table entry controlling the virtual address, which is used
+for the access, has the Present bit cleared or other reserved bits set.
+
+Affected processors
+-------------------
+
+This vulnerability affects a wide range of Intel processors. The
+vulnerability is not present on:
+
+   - Processors from AMD, Centaur and other non Intel vendors
+
+   - Older processor models, where the CPU family is < 6
+
+   - A range of Intel ATOM processors (Cedarview, Cloverview, Lincroft,
+     Penwell, Pineview, Silvermont, Airmont, Merrifield)
+
+   - The Intel XEON PHI family
+
+   - Intel processors which have the ARCH_CAP_RDCL_NO bit set in the
+     IA32_ARCH_CAPABILITIES MSR. If the bit is set the CPU is not affected
+     by the Meltdown vulnerability either. These CPUs should become
+     available by end of 2018.
+
+Whether a processor is affected or not can be read out from the L1TF
+vulnerability file in sysfs. See :ref:`l1tf_sys_info`.
+
+Related CVEs
+------------
+
+The following CVE entries are related to the L1TF vulnerability:
+
+   =============  =================  ==============================
+   CVE-2018-3615  L1 Terminal Fault  SGX related aspects
+   CVE-2018-3620  L1 Terminal Fault  OS, SMM related aspects
+   CVE-2018-3646  L1 Terminal Fault  Virtualization related aspects
+   =============  =================  ==============================
+
+Problem
+-------
+
+If an instruction accesses a virtual address for which the relevant page
+table entry (PTE) has the Present bit cleared or other reserved bits set,
+then speculative execution ignores the invalid PTE and loads the referenced
+data if it is present in the Level 1 Data Cache, as if the page referenced
+by the address bits in the PTE was still present and accessible.
+
+While this is a purely speculative mechanism and the instruction will raise
+a page fault when it is retired eventually, the pure act of loading the
+data and making it available to other speculative instructions opens up the
+opportunity for side channel attacks to unprivileged malicious code,
+similar to the Meltdown attack.
+
+While Meltdown breaks the user space to kernel space protection, L1TF
+allows to attack any physical memory address in the system and the attack
+works across all protection domains. It allows an attack of SGX and also
+works from inside virtual machines because the speculation bypasses the
+extended page table (EPT) protection mechanism.
+
+
+Attack scenarios
+----------------
+
+1. Malicious user space
+^^^^^^^^^^^^^^^^^^^^^^^
+
+   Operating Systems store arbitrary information in the address bits of a
+   PTE which is marked non present. This allows a malicious user space
+   application to attack the physical memory to which these PTEs resolve.
+   In some cases user-space can maliciously influence the information
+   encoded in the address bits of the PTE, thus making attacks more
+   deterministic and more practical.
+
+   The Linux kernel contains a mitigation for this attack vector, PTE
+   inversion, which is permanently enabled and has no performance
+   impact. The kernel ensures that the address bits of PTEs, which are not
+   marked present, never point to cacheable physical memory space.
+
+   A system with an up to date kernel is protected against attacks from
+   malicious user space applications.
+
+2. Malicious guest in a virtual machine
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+   The fact that L1TF breaks all domain protections allows malicious guest
+   OSes, which can control the PTEs directly, and malicious guest user
+   space applications, which run on an unprotected guest kernel lacking the
+   PTE inversion mitigation for L1TF, to attack physical host memory.
+
+   A special aspect of L1TF in the context of virtualization is symmetric
+   multi threading (SMT). The Intel implementation of SMT is called
+   HyperThreading. The fact that Hyperthreads on the affected processors
+   share the L1 Data Cache (L1D) is important for this. As the flaw allows
+   only to attack data which is present in L1D, a malicious guest running
+   on one Hyperthread can attack the data which is brought into the L1D by
+   the context which runs on the sibling Hyperthread of the same physical
+   core. This context can be host OS, host user space or a different guest.
+
+   If the processor does not support Extended Page Tables, the attack is
+   only possible, when the hypervisor does not sanitize the content of the
+   effective (shadow) page tables.
+
+   While solutions exist to mitigate these attack vectors fully, these
+   mitigations are not enabled by default in the Linux kernel because they
+   can affect performance significantly. The kernel provides several
+   mechanisms which can be utilized to address the problem depending on the
+   deployment scenario. The mitigations, their protection scope and impact
+   are described in the next sections.
+
+   The default mitigations and the rationale for choosing them are explained
+   at the end of this document. See :ref:`default_mitigations`.
+
+.. _l1tf_sys_info:
+
+L1TF system information
+-----------------------
+
+The Linux kernel provides a sysfs interface to enumerate the current L1TF
+status of the system: whether the system is vulnerable, and which
+mitigations are active. The relevant sysfs file is:
+
+/sys/devices/system/cpu/vulnerabilities/l1tf
+
+The possible values in this file are:
+
+  ===========================   ===============================
+  'Not affected'               The processor is not vulnerable
+  'Mitigation: PTE Inversion'  The host protection is active
+  ===========================   ===============================
+
+If KVM/VMX is enabled and the processor is vulnerable then the following
+information is appended to the 'Mitigation: PTE Inversion' part:
+
+  - SMT status:
+
+    =====================  ================
+    'VMX: SMT vulnerable'  SMT is enabled
+    'VMX: SMT disabled'    SMT is disabled
+    =====================  ================
+
+  - L1D Flush mode:
+
+    ================================  ====================================
+    'L1D vulnerable'                 L1D flushing is disabled
+
+    'L1D conditional cache flushes'   L1D flush is conditionally enabled
+
+    'L1D cache flushes'                      L1D flush is unconditionally enabled
+    ================================  ====================================
+
+The resulting grade of protection is discussed in the following sections.
+
+
+Host mitigation mechanism
+-------------------------
+
+The kernel is unconditionally protected against L1TF attacks from malicious
+user space running on the host.
+
+
+Guest mitigation mechanisms
+---------------------------
+
+.. _l1d_flush:
+
+1. L1D flush on VMENTER
+^^^^^^^^^^^^^^^^^^^^^^^
+
+   To make sure that a guest cannot attack data which is present in the L1D
+   the hypervisor flushes the L1D before entering the guest.
+
+   Flushing the L1D evicts not only the data which should not be accessed
+   by a potentially malicious guest, it also flushes the guest
+   data. Flushing the L1D has a performance impact as the processor has to
+   bring the flushed guest data back into the L1D. Depending on the
+   frequency of VMEXIT/VMENTER and the type of computations in the guest
+   performance degradation in the range of 1% to 50% has been observed. For
+   scenarios where guest VMEXIT/VMENTER are rare the performance impact is
+   minimal. Virtio and mechanisms like posted interrupts are designed to
+   confine the VMEXITs to a bare minimum, but specific configurations and
+   application scenarios might still suffer from a high VMEXIT rate.
+
+   The kernel provides two L1D flush modes:
+    - conditional ('cond')
+    - unconditional ('always')
+
+   The conditional mode avoids L1D flushing after VMEXITs which execute
+   only audited code paths before the corresponding VMENTER. These code
+   paths have been verified that they cannot expose secrets or other
+   interesting data to an attacker, but they can leak information about the
+   address space layout of the hypervisor.
+
+   Unconditional mode flushes L1D on all VMENTER invocations and provides
+   maximum protection. It has a higher overhead than the conditional
+   mode. The overhead cannot be quantified correctly as it depends on the
+   workload scenario and the resulting number of VMEXITs.
+
+   The general recommendation is to enable L1D flush on VMENTER. The kernel
+   defaults to conditional mode on affected processors.
+
+   **Note**, that L1D flush does not prevent the SMT problem because the
+   sibling thread will also bring back its data into the L1D which makes it
+   attackable again.
+
+   L1D flush can be controlled by the administrator via the kernel command
+   line and sysfs control files. See :ref:`mitigation_control_command_line`
+   and :ref:`mitigation_control_kvm`.
+
+.. _guest_confinement:
+
+2. Guest VCPU confinement to dedicated physical cores
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+   To address the SMT problem, it is possible to make a guest or a group of
+   guests affine to one or more physical cores. The proper mechanism for
+   that is to utilize exclusive cpusets to ensure that no other guest or
+   host tasks can run on these cores.
+
+   If only a single guest or related guests run on sibling SMT threads on
+   the same physical core then they can only attack their own memory and
+   restricted parts of the host memory.
+
+   Host memory is attackable, when one of the sibling SMT threads runs in
+   host OS (hypervisor) context and the other in guest context. The amount
+   of valuable information from the host OS context depends on the context
+   which the host OS executes, i.e. interrupts, soft interrupts and kernel
+   threads. The amount of valuable data from these contexts cannot be
+   declared as non-interesting for an attacker without deep inspection of
+   the code.
+
+   **Note**, that assigning guests to a fixed set of physical cores affects
+   the ability of the scheduler to do load balancing and might have
+   negative effects on CPU utilization depending on the hosting
+   scenario. Disabling SMT might be a viable alternative for particular
+   scenarios.
+
+   For further information about confining guests to a single or to a group
+   of cores consult the cpusets documentation:
+
+   https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt
+
+.. _interrupt_isolation:
+
+3. Interrupt affinity
+^^^^^^^^^^^^^^^^^^^^^
+
+   Interrupts can be made affine to logical CPUs. This is not universally
+   true because there are types of interrupts which are truly per CPU
+   interrupts, e.g. the local timer interrupt. Aside of that multi queue
+   devices affine their interrupts to single CPUs or groups of CPUs per
+   queue without allowing the administrator to control the affinities.
+
+   Moving the interrupts, which can be affinity controlled, away from CPUs
+   which run untrusted guests, reduces the attack vector space.
+
+   Whether the interrupts with are affine to CPUs, which run untrusted
+   guests, provide interesting data for an attacker depends on the system
+   configuration and the scenarios which run on the system. While for some
+   of the interrupts it can be assumed that they won't expose interesting
+   information beyond exposing hints about the host OS memory layout, there
+   is no way to make general assumptions.
+
+   Interrupt affinity can be controlled by the administrator via the
+   /proc/irq/$NR/smp_affinity[_list] files. Limited documentation is
+   available at:
+
+   https://www.kernel.org/doc/Documentation/IRQ-affinity.txt
+
+.. _smt_control:
+
+4. SMT control
+^^^^^^^^^^^^^^
+
+   To prevent the SMT issues of L1TF it might be necessary to disable SMT
+   completely. Disabling SMT can have a significant performance impact, but
+   the impact depends on the hosting scenario and the type of workloads.
+   The impact of disabling SMT needs also to be weighted against the impact
+   of other mitigation solutions like confining guests to dedicated cores.
+
+   The kernel provides a sysfs interface to retrieve the status of SMT and
+   to control it. It also provides a kernel command line interface to
+   control SMT.
+
+   The kernel command line interface consists of the following options:
+
+     =========== ==========================================================
+     nosmt      Affects the bring up of the secondary CPUs during boot. The
+                kernel tries to bring all present CPUs online during the
+                boot process. "nosmt" makes sure that from each physical
+                core only one - the so called primary (hyper) thread is
+                activated. Due to a design flaw of Intel processors related
+                to Machine Check Exceptions the non primary siblings have
+                to be brought up at least partially and are then shut down
+                again.  "nosmt" can be undone via the sysfs interface.
+
+     nosmt=force Has the same effect as "nosmt" but it does not allow to
+                undo the SMT disable via the sysfs interface.
+     =========== ==========================================================
+
+   The sysfs interface provides two files:
+
+   - /sys/devices/system/cpu/smt/control
+   - /sys/devices/system/cpu/smt/active
+
+   /sys/devices/system/cpu/smt/control:
+
+     This file allows to read out the SMT control state and provides the
+     ability to disable or (re)enable SMT. The possible states are:
+
+       ==============  ===================================================
+       on              SMT is supported by the CPU and enabled. All
+                       logical CPUs can be onlined and offlined without
+                       restrictions.
+
+       off             SMT is supported by the CPU and disabled. Only
+                       the so called primary SMT threads can be onlined
+                       and offlined without restrictions. An attempt to
+                       online a non-primary sibling is rejected
+
+       forceoff        Same as 'off' but the state cannot be controlled.
+                       Attempts to write to the control file are rejected.
+
+       notsupported    The processor does not support SMT. It's therefore
+                       not affected by the SMT implications of L1TF.
+                       Attempts to write to the control file are rejected.
+       ==============  ===================================================
+
+     The possible states which can be written into this file to control SMT
+     state are:
+
+     - on
+     - off
+     - forceoff
+
+   /sys/devices/system/cpu/smt/active:
+
+     This file reports whether SMT is enabled and active, i.e. if on any
+     physical core two or more sibling threads are online.
+
+   SMT control is also possible at boot time via the l1tf kernel command
+   line parameter in combination with L1D flush control. See
+   :ref:`mitigation_control_command_line`.
+
+5. Disabling EPT
+^^^^^^^^^^^^^^^^
+
+  Disabling EPT for virtual machines provides full mitigation for L1TF even
+  with SMT enabled, because the effective page tables for guests are
+  managed and sanitized by the hypervisor. Though disabling EPT has a
+  significant performance impact especially when the Meltdown mitigation
+  KPTI is enabled.
+
+  EPT can be disabled in the hypervisor via the 'kvm-intel.ept' parameter.
+
+There is ongoing research and development for new mitigation mechanisms to
+address the performance impact of disabling SMT or EPT.
+
+.. _mitigation_control_command_line:
+
+Mitigation control on the kernel command line
+---------------------------------------------
+
+The kernel command line allows to control the L1TF mitigations at boot
+time with the option "l1tf=". The valid arguments for this option are:
+
+  ============  =============================================================
+  full         Provides all available mitigations for the L1TF
+               vulnerability. Disables SMT and enables all mitigations in
+               the hypervisors, i.e. unconditional L1D flushing
+
+               SMT control and L1D flush control via the sysfs interface
+               is still possible after boot.  Hypervisors will issue a
+               warning when the first VM is started in a potentially
+               insecure configuration, i.e. SMT enabled or L1D flush
+               disabled.
+
+  full,force   Same as 'full', but disables SMT and L1D flush runtime
+               control. Implies the 'nosmt=force' command line option.
+               (i.e. sysfs control of SMT is disabled.)
+
+  flush                Leaves SMT enabled and enables the default hypervisor
+               mitigation, i.e. conditional L1D flushing
+
+               SMT control and L1D flush control via the sysfs interface
+               is still possible after boot.  Hypervisors will issue a
+               warning when the first VM is started in a potentially
+               insecure configuration, i.e. SMT enabled or L1D flush
+               disabled.
+
+  flush,nosmt  Disables SMT and enables the default hypervisor mitigation,
+               i.e. conditional L1D flushing.
+
+               SMT control and L1D flush control via the sysfs interface
+               is still possible after boot.  Hypervisors will issue a
+               warning when the first VM is started in a potentially
+               insecure configuration, i.e. SMT enabled or L1D flush
+               disabled.
+
+  flush,nowarn Same as 'flush', but hypervisors will not warn when a VM is
+               started in a potentially insecure configuration.
+
+  off          Disables hypervisor mitigations and doesn't emit any
+               warnings.
+               It also drops the swap size and available RAM limit restrictions
+               on both hypervisor and bare metal.
+
+  ============  =============================================================
+
+The default is 'flush'. For details about L1D flushing see :ref:`l1d_flush`.
+
+
+.. _mitigation_control_kvm:
+
+Mitigation control for KVM - module parameter
+-------------------------------------------------------------
+
+The KVM hypervisor mitigation mechanism, flushing the L1D cache when
+entering a guest, can be controlled with a module parameter.
+
+The option/parameter is "kvm-intel.vmentry_l1d_flush=". It takes the
+following arguments:
+
+  ============  ==============================================================
+  always       L1D cache flush on every VMENTER.
+
+  cond         Flush L1D on VMENTER only when the code between VMEXIT and
+               VMENTER can leak host memory which is considered
+               interesting for an attacker. This still can leak host memory
+               which allows e.g. to determine the hosts address space layout.
+
+  never                Disables the mitigation
+  ============  ==============================================================
+
+The parameter can be provided on the kernel command line, as a module
+parameter when loading the modules and at runtime modified via the sysfs
+file:
+
+/sys/module/kvm_intel/parameters/vmentry_l1d_flush
+
+The default is 'cond'. If 'l1tf=full,force' is given on the kernel command
+line, then 'always' is enforced and the kvm-intel.vmentry_l1d_flush
+module parameter is ignored and writes to the sysfs file are rejected.
+
+.. _mitigation_selection:
+
+Mitigation selection guide
+--------------------------
+
+1. No virtualization in use
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+   The system is protected by the kernel unconditionally and no further
+   action is required.
+
+2. Virtualization with trusted guests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+   If the guest comes from a trusted source and the guest OS kernel is
+   guaranteed to have the L1TF mitigations in place the system is fully
+   protected against L1TF and no further action is required.
+
+   To avoid the overhead of the default L1D flushing on VMENTER the
+   administrator can disable the flushing via the kernel command line and
+   sysfs control files. See :ref:`mitigation_control_command_line` and
+   :ref:`mitigation_control_kvm`.
+
+
+3. Virtualization with untrusted guests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+3.1. SMT not supported or disabled
+""""""""""""""""""""""""""""""""""
+
+  If SMT is not supported by the processor or disabled in the BIOS or by
+  the kernel, it's only required to enforce L1D flushing on VMENTER.
+
+  Conditional L1D flushing is the default behaviour and can be tuned. See
+  :ref:`mitigation_control_command_line` and :ref:`mitigation_control_kvm`.
+
+3.2. EPT not supported or disabled
+""""""""""""""""""""""""""""""""""
+
+  If EPT is not supported by the processor or disabled in the hypervisor,
+  the system is fully protected. SMT can stay enabled and L1D flushing on
+  VMENTER is not required.
+
+  EPT can be disabled in the hypervisor via the 'kvm-intel.ept' parameter.
+
+3.3. SMT and EPT supported and active
+"""""""""""""""""""""""""""""""""""""
+
+  If SMT and EPT are supported and active then various degrees of
+  mitigations can be employed:
+
+  - L1D flushing on VMENTER:
+
+    L1D flushing on VMENTER is the minimal protection requirement, but it
+    is only potent in combination with other mitigation methods.
+
+    Conditional L1D flushing is the default behaviour and can be tuned. See
+    :ref:`mitigation_control_command_line` and :ref:`mitigation_control_kvm`.
+
+  - Guest confinement:
+
+    Confinement of guests to a single or a group of physical cores which
+    are not running any other processes, can reduce the attack surface
+    significantly, but interrupts, soft interrupts and kernel threads can
+    still expose valuable data to a potential attacker. See
+    :ref:`guest_confinement`.
+
+  - Interrupt isolation:
+
+    Isolating the guest CPUs from interrupts can reduce the attack surface
+    further, but still allows a malicious guest to explore a limited amount
+    of host physical memory. This can at least be used to gain knowledge
+    about the host address space layout. The interrupts which have a fixed
+    affinity to the CPUs which run the untrusted guests can depending on
+    the scenario still trigger soft interrupts and schedule kernel threads
+    which might expose valuable information. See
+    :ref:`interrupt_isolation`.
+
+The above three mitigation methods combined can provide protection to a
+certain degree, but the risk of the remaining attack surface has to be
+carefully analyzed. For full protection the following methods are
+available:
+
+  - Disabling SMT:
+
+    Disabling SMT and enforcing the L1D flushing provides the maximum
+    amount of protection. This mitigation is not depending on any of the
+    above mitigation methods.
+
+    SMT control and L1D flushing can be tuned by the command line
+    parameters 'nosmt', 'l1tf', 'kvm-intel.vmentry_l1d_flush' and at run
+    time with the matching sysfs control files. See :ref:`smt_control`,
+    :ref:`mitigation_control_command_line` and
+    :ref:`mitigation_control_kvm`.
+
+  - Disabling EPT:
+
+    Disabling EPT provides the maximum amount of protection as well. It is
+    not depending on any of the above mitigation methods. SMT can stay
+    enabled and L1D flushing is not required, but the performance impact is
+    significant.
+
+    EPT can be disabled in the hypervisor via the 'kvm-intel.ept'
+    parameter.
+
+3.4. Nested virtual machines
+""""""""""""""""""""""""""""
+
+When nested virtualization is in use, three operating systems are involved:
+the bare metal hypervisor, the nested hypervisor and the nested virtual
+machine.  VMENTER operations from the nested hypervisor into the nested
+guest will always be processed by the bare metal hypervisor. If KVM is the
+bare metal hypervisor it will:
+
+ - Flush the L1D cache on every switch from the nested hypervisor to the
+   nested virtual machine, so that the nested hypervisor's secrets are not
+   exposed to the nested virtual machine;
+
+ - Flush the L1D cache on every switch from the nested virtual machine to
+   the nested hypervisor; this is a complex operation, and flushing the L1D
+   cache avoids that the bare metal hypervisor's secrets are exposed to the
+   nested virtual machine;
+
+ - Instruct the nested hypervisor to not perform any L1D cache flush. This
+   is an optimization to avoid double L1D flushing.
+
+
+.. _default_mitigations:
+
+Default mitigations
+-------------------
+
+  The kernel default mitigations for vulnerable processors are:
+
+  - PTE inversion to protect against malicious user space. This is done
+    unconditionally and cannot be controlled. The swap storage is limited
+    to ~16TB.
+
+  - L1D conditional flushing on VMENTER when EPT is enabled for
+    a guest.
+
+  The kernel does not by default enforce the disabling of SMT, which leaves
+  SMT systems vulnerable when running untrusted guests with EPT enabled.
+
+  The rationale for this choice is:
+
+  - Force disabling SMT can break existing setups, especially with
+    unattended updates.
+
+  - If regular users run untrusted guests on their machine, then L1TF is
+    just an add on to other malware which might be embedded in an untrusted
+    guest, e.g. spam-bots or attacks on the local network.
+
+    There is no technical way to prevent a user from running untrusted code
+    on their machines blindly.
+
+  - It's technically extremely unlikely and from today's knowledge even
+    impossible that L1TF can be exploited via the most popular attack
+    mechanisms like JavaScript because these mechanisms have no way to
+    control PTEs. If this would be possible and not other mitigation would
+    be possible, then the default might be different.
+
+  - The administrators of cloud and hosting setups have to carefully
+    analyze the risk for their scenarios and make the appropriate
+    mitigation choices, which might even vary across their deployed
+    machines and also result in other changes of their overall setup.
+    There is no way for the kernel to provide a sensible default for this
+    kind of scenarios.
diff --git a/Documentation/admin-guide/hw-vuln/mds.rst b/Documentation/admin-guide/hw-vuln/mds.rst
new file mode 100644 (file)
index 0000000..e3a796c
--- /dev/null
@@ -0,0 +1,308 @@
+MDS - Microarchitectural Data Sampling
+======================================
+
+Microarchitectural Data Sampling is a hardware vulnerability which allows
+unprivileged speculative access to data which is available in various CPU
+internal buffers.
+
+Affected processors
+-------------------
+
+This vulnerability affects a wide range of Intel processors. The
+vulnerability is not present on:
+
+   - Processors from AMD, Centaur and other non Intel vendors
+
+   - Older processor models, where the CPU family is < 6
+
+   - Some Atoms (Bonnell, Saltwell, Goldmont, GoldmontPlus)
+
+   - Intel processors which have the ARCH_CAP_MDS_NO bit set in the
+     IA32_ARCH_CAPABILITIES MSR.
+
+Whether a processor is affected or not can be read out from the MDS
+vulnerability file in sysfs. See :ref:`mds_sys_info`.
+
+Not all processors are affected by all variants of MDS, but the mitigation
+is identical for all of them so the kernel treats them as a single
+vulnerability.
+
+Related CVEs
+------------
+
+The following CVE entries are related to the MDS vulnerability:
+
+   ==============  =====  ===================================================
+   CVE-2018-12126  MSBDS  Microarchitectural Store Buffer Data Sampling
+   CVE-2018-12130  MFBDS  Microarchitectural Fill Buffer Data Sampling
+   CVE-2018-12127  MLPDS  Microarchitectural Load Port Data Sampling
+   CVE-2019-11091  MDSUM  Microarchitectural Data Sampling Uncacheable Memory
+   ==============  =====  ===================================================
+
+Problem
+-------
+
+When performing store, load, L1 refill operations, processors write data
+into temporary microarchitectural structures (buffers). The data in the
+buffer can be forwarded to load operations as an optimization.
+
+Under certain conditions, usually a fault/assist caused by a load
+operation, data unrelated to the load memory address can be speculatively
+forwarded from the buffers. Because the load operation causes a fault or
+assist and its result will be discarded, the forwarded data will not cause
+incorrect program execution or state changes. But a malicious operation
+may be able to forward this speculative data to a disclosure gadget which
+allows in turn to infer the value via a cache side channel attack.
+
+Because the buffers are potentially shared between Hyper-Threads cross
+Hyper-Thread attacks are possible.
+
+Deeper technical information is available in the MDS specific x86
+architecture section: :ref:`Documentation/x86/mds.rst <mds>`.
+
+
+Attack scenarios
+----------------
+
+Attacks against the MDS vulnerabilities can be mounted from malicious non
+priviledged user space applications running on hosts or guest. Malicious
+guest OSes can obviously mount attacks as well.
+
+Contrary to other speculation based vulnerabilities the MDS vulnerability
+does not allow the attacker to control the memory target address. As a
+consequence the attacks are purely sampling based, but as demonstrated with
+the TLBleed attack samples can be postprocessed successfully.
+
+Web-Browsers
+^^^^^^^^^^^^
+
+  It's unclear whether attacks through Web-Browsers are possible at
+  all. The exploitation through Java-Script is considered very unlikely,
+  but other widely used web technologies like Webassembly could possibly be
+  abused.
+
+
+.. _mds_sys_info:
+
+MDS system information
+-----------------------
+
+The Linux kernel provides a sysfs interface to enumerate the current MDS
+status of the system: whether the system is vulnerable, and which
+mitigations are active. The relevant sysfs file is:
+
+/sys/devices/system/cpu/vulnerabilities/mds
+
+The possible values in this file are:
+
+  .. list-table::
+
+     * - 'Not affected'
+       - The processor is not vulnerable
+     * - 'Vulnerable'
+       - The processor is vulnerable, but no mitigation enabled
+     * - 'Vulnerable: Clear CPU buffers attempted, no microcode'
+       - The processor is vulnerable but microcode is not updated.
+
+         The mitigation is enabled on a best effort basis. See :ref:`vmwerv`
+     * - 'Mitigation: Clear CPU buffers'
+       - The processor is vulnerable and the CPU buffer clearing mitigation is
+         enabled.
+
+If the processor is vulnerable then the following information is appended
+to the above information:
+
+    ========================  ============================================
+    'SMT vulnerable'          SMT is enabled
+    'SMT mitigated'           SMT is enabled and mitigated
+    'SMT disabled'            SMT is disabled
+    'SMT Host state unknown'  Kernel runs in a VM, Host SMT state unknown
+    ========================  ============================================
+
+.. _vmwerv:
+
+Best effort mitigation mode
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+  If the processor is vulnerable, but the availability of the microcode based
+  mitigation mechanism is not advertised via CPUID the kernel selects a best
+  effort mitigation mode.  This mode invokes the mitigation instructions
+  without a guarantee that they clear the CPU buffers.
+
+  This is done to address virtualization scenarios where the host has the
+  microcode update applied, but the hypervisor is not yet updated to expose
+  the CPUID to the guest. If the host has updated microcode the protection
+  takes effect otherwise a few cpu cycles are wasted pointlessly.
+
+  The state in the mds sysfs file reflects this situation accordingly.
+
+
+Mitigation mechanism
+-------------------------
+
+The kernel detects the affected CPUs and the presence of the microcode
+which is required.
+
+If a CPU is affected and the microcode is available, then the kernel
+enables the mitigation by default. The mitigation can be controlled at boot
+time via a kernel command line option. See
+:ref:`mds_mitigation_control_command_line`.
+
+.. _cpu_buffer_clear:
+
+CPU buffer clearing
+^^^^^^^^^^^^^^^^^^^
+
+  The mitigation for MDS clears the affected CPU buffers on return to user
+  space and when entering a guest.
+
+  If SMT is enabled it also clears the buffers on idle entry when the CPU
+  is only affected by MSBDS and not any other MDS variant, because the
+  other variants cannot be protected against cross Hyper-Thread attacks.
+
+  For CPUs which are only affected by MSBDS the user space, guest and idle
+  transition mitigations are sufficient and SMT is not affected.
+
+.. _virt_mechanism:
+
+Virtualization mitigation
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+  The protection for host to guest transition depends on the L1TF
+  vulnerability of the CPU:
+
+  - CPU is affected by L1TF:
+
+    If the L1D flush mitigation is enabled and up to date microcode is
+    available, the L1D flush mitigation is automatically protecting the
+    guest transition.
+
+    If the L1D flush mitigation is disabled then the MDS mitigation is
+    invoked explicit when the host MDS mitigation is enabled.
+
+    For details on L1TF and virtualization see:
+    :ref:`Documentation/admin-guide/hw-vuln//l1tf.rst <mitigation_control_kvm>`.
+
+  - CPU is not affected by L1TF:
+
+    CPU buffers are flushed before entering the guest when the host MDS
+    mitigation is enabled.
+
+  The resulting MDS protection matrix for the host to guest transition:
+
+  ============ ===== ============= ============ =================
+   L1TF         MDS   VMX-L1FLUSH   Host MDS     MDS-State
+
+   Don't care   No    Don't care    N/A          Not affected
+
+   Yes          Yes   Disabled      Off          Vulnerable
+
+   Yes          Yes   Disabled      Full         Mitigated
+
+   Yes          Yes   Enabled       Don't care   Mitigated
+
+   No           Yes   N/A           Off          Vulnerable
+
+   No           Yes   N/A           Full         Mitigated
+  ============ ===== ============= ============ =================
+
+  This only covers the host to guest transition, i.e. prevents leakage from
+  host to guest, but does not protect the guest internally. Guests need to
+  have their own protections.
+
+.. _xeon_phi:
+
+XEON PHI specific considerations
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+  The XEON PHI processor family is affected by MSBDS which can be exploited
+  cross Hyper-Threads when entering idle states. Some XEON PHI variants allow
+  to use MWAIT in user space (Ring 3) which opens an potential attack vector
+  for malicious user space. The exposure can be disabled on the kernel
+  command line with the 'ring3mwait=disable' command line option.
+
+  XEON PHI is not affected by the other MDS variants and MSBDS is mitigated
+  before the CPU enters a idle state. As XEON PHI is not affected by L1TF
+  either disabling SMT is not required for full protection.
+
+.. _mds_smt_control:
+
+SMT control
+^^^^^^^^^^^
+
+  All MDS variants except MSBDS can be attacked cross Hyper-Threads. That
+  means on CPUs which are affected by MFBDS or MLPDS it is necessary to
+  disable SMT for full protection. These are most of the affected CPUs; the
+  exception is XEON PHI, see :ref:`xeon_phi`.
+
+  Disabling SMT can have a significant performance impact, but the impact
+  depends on the type of workloads.
+
+  See the relevant chapter in the L1TF mitigation documentation for details:
+  :ref:`Documentation/admin-guide/hw-vuln/l1tf.rst <smt_control>`.
+
+
+.. _mds_mitigation_control_command_line:
+
+Mitigation control on the kernel command line
+---------------------------------------------
+
+The kernel command line allows to control the MDS mitigations at boot
+time with the option "mds=". The valid arguments for this option are:
+
+  ============  =============================================================
+  full         If the CPU is vulnerable, enable all available mitigations
+               for the MDS vulnerability, CPU buffer clearing on exit to
+               userspace and when entering a VM. Idle transitions are
+               protected as well if SMT is enabled.
+
+               It does not automatically disable SMT.
+
+  full,nosmt   The same as mds=full, with SMT disabled on vulnerable
+               CPUs.  This is the complete mitigation.
+
+  off          Disables MDS mitigations completely.
+
+  ============  =============================================================
+
+Not specifying this option is equivalent to "mds=full".
+
+
+Mitigation selection guide
+--------------------------
+
+1. Trusted userspace
+^^^^^^^^^^^^^^^^^^^^
+
+   If all userspace applications are from a trusted source and do not
+   execute untrusted code which is supplied externally, then the mitigation
+   can be disabled.
+
+
+2. Virtualization with trusted guests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+   The same considerations as above versus trusted user space apply.
+
+3. Virtualization with untrusted guests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+   The protection depends on the state of the L1TF mitigations.
+   See :ref:`virt_mechanism`.
+
+   If the MDS mitigation is enabled and SMT is disabled, guest to host and
+   guest to guest attacks are prevented.
+
+.. _mds_default_mitigations:
+
+Default mitigations
+-------------------
+
+  The kernel default mitigations for vulnerable processors are:
+
+  - Enable CPU buffer clearing
+
+  The kernel does not by default enforce the disabling of SMT, which leaves
+  SMT systems vulnerable when running untrusted code. The same rationale as
+  for L1TF applies.
+  See :ref:`Documentation/admin-guide/hw-vuln//l1tf.rst <default_mitigations>`.
index 5b8286fdd91ba33804a91a830c5d102233b997c2..8001917ee012b429954c13b1d26f6ad65a972dc4 100644 (file)
@@ -17,14 +17,12 @@ etc.
    kernel-parameters
    devices
 
-This section describes CPU vulnerabilities and provides an overview of the
-possible mitigations along with guidance for selecting mitigations if they
-are configurable at compile, boot or run time.
+This section describes CPU vulnerabilities and their mitigations.
 
 .. toctree::
    :maxdepth: 1
 
-   l1tf
+   hw-vuln/index
 
 Here is a set of documents aimed at users who are trying to track down
 problems and bugs in particular.
index 08df588057036e2eba4c4fcc38281ddc98a8711f..52e6fbb042cc5cfe04d8ae1bedbc2b5c4e14c104 100644 (file)
        ip=             [IP_PNP]
                        See Documentation/filesystems/nfs/nfsroot.txt.
 
+       ipcmni_extend   [KNL] Extend the maximum number of unique System V
+                       IPC identifiers from 32,768 to 16,777,216.
+
        irqaffinity=    [SMP] Set the default irq affinity mask
                        The argument is a cpu list, as described above.
 
 
                        Default is 'flush'.
 
-                       For details see: Documentation/admin-guide/l1tf.rst
+                       For details see: Documentation/admin-guide/hw-vuln/l1tf.rst
 
        l2cr=           [PPC]
 
                        Format: <first>,<last>
                        Specifies range of consoles to be captured by the MDA.
 
+       mds=            [X86,INTEL]
+                       Control mitigation for the Micro-architectural Data
+                       Sampling (MDS) vulnerability.
+
+                       Certain CPUs are vulnerable to an exploit against CPU
+                       internal buffers which can forward information to a
+                       disclosure gadget under certain conditions.
+
+                       In vulnerable processors, the speculatively
+                       forwarded data can be used in a cache side channel
+                       attack, to access data to which the attacker does
+                       not have direct access.
+
+                       This parameter controls the MDS mitigation. The
+                       options are:
+
+                       full       - Enable MDS mitigation on vulnerable CPUs
+                       full,nosmt - Enable MDS mitigation and disable
+                                    SMT on vulnerable CPUs
+                       off        - Unconditionally disable MDS mitigation
+
+                       Not specifying this option is equivalent to
+                       mds=full.
+
+                       For details see: Documentation/admin-guide/hw-vuln/mds.rst
+
        mem=nn[KMG]     [KNL,BOOT] Force usage of a specific amount of memory
                        Amount of memory to be used when the kernel is not able
                        to see the whole system memory or for test.
                                               spec_store_bypass_disable=off [X86,PPC]
                                               ssbd=force-off [ARM64]
                                               l1tf=off [X86]
+                                              mds=off [X86]
 
                        auto (default)
                                Mitigate all CPU vulnerabilities, but leave SMT
                                if needed.  This is for users who always want to
                                be fully mitigated, even if it means losing SMT.
                                Equivalent to: l1tf=flush,nosmt [X86]
+                                              mds=full,nosmt [X86]
 
        mminit_loglevel=
                        [KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this
                        This will also cause panics on machine check exceptions.
                        Useful together with panic=30 to trigger a reboot.
 
+       page_alloc.shuffle=
+                       [KNL] Boolean flag to control whether the page allocator
+                       should randomize its free lists. The randomization may
+                       be automatically enabled if the kernel detects it is
+                       running on a platform with a direct-mapped memory-side
+                       cache, and this parameter can be used to
+                       override/disable that behavior. The state of the flag
+                       can be read from sysfs at:
+                       /sys/module/page_alloc/parameters/shuffle.
+
        page_owner=     [KNL] Boot-time page_owner enabling option.
                        Storage of the information about who allocated
                        each page is disabled in default. With this switch,
                                [[,]s[mp]#### \
                                [[,]b[ios] | a[cpi] | k[bd] | t[riple] | e[fi] | p[ci]] \
                                [[,]f[orce]
-                       Where reboot_mode is one of warm (soft) or cold (hard) or gpio,
+                       Where reboot_mode is one of warm (soft) or cold (hard) or gpio
+                                       (prefix with 'panic_' to set mode for panic
+                                       reboot only),
                              reboot_type is one of bios, acpi, kbd, triple, efi, or pci,
                              reboot_force is either force or not specified,
                              reboot_cpu is s[mp]#### with #### being the processor
                        with /sys/devices/system/xen_memory/xen_memory0/scrub_pages.
                        Default value controlled with CONFIG_XEN_SCRUB_PAGES_DEFAULT.
 
+       xen_timer_slop= [X86-64,XEN]
+                       Set the timer slop (in nanoseconds) for the virtual Xen
+                       timers (default is 100000). This adjusts the minimum
+                       delta of virtualized Xen timers, where lower values
+                       improve timer resolution at the expense of processing
+                       more timer interrupts.
+
        xirc2ps_cs=     [NET,PCMCIA]
                        Format:
                        <irq>,<irq_mask>,<io>,<full_duplex>,<do_sound>,<lockup_hack>[,<irq2>[,<irq3>[,<irq4>]]]
diff --git a/Documentation/admin-guide/l1tf.rst b/Documentation/admin-guide/l1tf.rst
deleted file mode 100644 (file)
index 9af9773..0000000
+++ /dev/null
@@ -1,614 +0,0 @@
-L1TF - L1 Terminal Fault
-========================
-
-L1 Terminal Fault is a hardware vulnerability which allows unprivileged
-speculative access to data which is available in the Level 1 Data Cache
-when the page table entry controlling the virtual address, which is used
-for the access, has the Present bit cleared or other reserved bits set.
-
-Affected processors
--------------------
-
-This vulnerability affects a wide range of Intel processors. The
-vulnerability is not present on:
-
-   - Processors from AMD, Centaur and other non Intel vendors
-
-   - Older processor models, where the CPU family is < 6
-
-   - A range of Intel ATOM processors (Cedarview, Cloverview, Lincroft,
-     Penwell, Pineview, Silvermont, Airmont, Merrifield)
-
-   - The Intel XEON PHI family
-
-   - Intel processors which have the ARCH_CAP_RDCL_NO bit set in the
-     IA32_ARCH_CAPABILITIES MSR. If the bit is set the CPU is not affected
-     by the Meltdown vulnerability either. These CPUs should become
-     available by end of 2018.
-
-Whether a processor is affected or not can be read out from the L1TF
-vulnerability file in sysfs. See :ref:`l1tf_sys_info`.
-
-Related CVEs
-------------
-
-The following CVE entries are related to the L1TF vulnerability:
-
-   =============  =================  ==============================
-   CVE-2018-3615  L1 Terminal Fault  SGX related aspects
-   CVE-2018-3620  L1 Terminal Fault  OS, SMM related aspects
-   CVE-2018-3646  L1 Terminal Fault  Virtualization related aspects
-   =============  =================  ==============================
-
-Problem
--------
-
-If an instruction accesses a virtual address for which the relevant page
-table entry (PTE) has the Present bit cleared or other reserved bits set,
-then speculative execution ignores the invalid PTE and loads the referenced
-data if it is present in the Level 1 Data Cache, as if the page referenced
-by the address bits in the PTE was still present and accessible.
-
-While this is a purely speculative mechanism and the instruction will raise
-a page fault when it is retired eventually, the pure act of loading the
-data and making it available to other speculative instructions opens up the
-opportunity for side channel attacks to unprivileged malicious code,
-similar to the Meltdown attack.
-
-While Meltdown breaks the user space to kernel space protection, L1TF
-allows to attack any physical memory address in the system and the attack
-works across all protection domains. It allows an attack of SGX and also
-works from inside virtual machines because the speculation bypasses the
-extended page table (EPT) protection mechanism.
-
-
-Attack scenarios
-----------------
-
-1. Malicious user space
-^^^^^^^^^^^^^^^^^^^^^^^
-
-   Operating Systems store arbitrary information in the address bits of a
-   PTE which is marked non present. This allows a malicious user space
-   application to attack the physical memory to which these PTEs resolve.
-   In some cases user-space can maliciously influence the information
-   encoded in the address bits of the PTE, thus making attacks more
-   deterministic and more practical.
-
-   The Linux kernel contains a mitigation for this attack vector, PTE
-   inversion, which is permanently enabled and has no performance
-   impact. The kernel ensures that the address bits of PTEs, which are not
-   marked present, never point to cacheable physical memory space.
-
-   A system with an up to date kernel is protected against attacks from
-   malicious user space applications.
-
-2. Malicious guest in a virtual machine
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-   The fact that L1TF breaks all domain protections allows malicious guest
-   OSes, which can control the PTEs directly, and malicious guest user
-   space applications, which run on an unprotected guest kernel lacking the
-   PTE inversion mitigation for L1TF, to attack physical host memory.
-
-   A special aspect of L1TF in the context of virtualization is symmetric
-   multi threading (SMT). The Intel implementation of SMT is called
-   HyperThreading. The fact that Hyperthreads on the affected processors
-   share the L1 Data Cache (L1D) is important for this. As the flaw allows
-   only to attack data which is present in L1D, a malicious guest running
-   on one Hyperthread can attack the data which is brought into the L1D by
-   the context which runs on the sibling Hyperthread of the same physical
-   core. This context can be host OS, host user space or a different guest.
-
-   If the processor does not support Extended Page Tables, the attack is
-   only possible, when the hypervisor does not sanitize the content of the
-   effective (shadow) page tables.
-
-   While solutions exist to mitigate these attack vectors fully, these
-   mitigations are not enabled by default in the Linux kernel because they
-   can affect performance significantly. The kernel provides several
-   mechanisms which can be utilized to address the problem depending on the
-   deployment scenario. The mitigations, their protection scope and impact
-   are described in the next sections.
-
-   The default mitigations and the rationale for choosing them are explained
-   at the end of this document. See :ref:`default_mitigations`.
-
-.. _l1tf_sys_info:
-
-L1TF system information
------------------------
-
-The Linux kernel provides a sysfs interface to enumerate the current L1TF
-status of the system: whether the system is vulnerable, and which
-mitigations are active. The relevant sysfs file is:
-
-/sys/devices/system/cpu/vulnerabilities/l1tf
-
-The possible values in this file are:
-
-  ===========================   ===============================
-  'Not affected'               The processor is not vulnerable
-  'Mitigation: PTE Inversion'  The host protection is active
-  ===========================   ===============================
-
-If KVM/VMX is enabled and the processor is vulnerable then the following
-information is appended to the 'Mitigation: PTE Inversion' part:
-
-  - SMT status:
-
-    =====================  ================
-    'VMX: SMT vulnerable'  SMT is enabled
-    'VMX: SMT disabled'    SMT is disabled
-    =====================  ================
-
-  - L1D Flush mode:
-
-    ================================  ====================================
-    'L1D vulnerable'                 L1D flushing is disabled
-
-    'L1D conditional cache flushes'   L1D flush is conditionally enabled
-
-    'L1D cache flushes'                      L1D flush is unconditionally enabled
-    ================================  ====================================
-
-The resulting grade of protection is discussed in the following sections.
-
-
-Host mitigation mechanism
--------------------------
-
-The kernel is unconditionally protected against L1TF attacks from malicious
-user space running on the host.
-
-
-Guest mitigation mechanisms
----------------------------
-
-.. _l1d_flush:
-
-1. L1D flush on VMENTER
-^^^^^^^^^^^^^^^^^^^^^^^
-
-   To make sure that a guest cannot attack data which is present in the L1D
-   the hypervisor flushes the L1D before entering the guest.
-
-   Flushing the L1D evicts not only the data which should not be accessed
-   by a potentially malicious guest, it also flushes the guest
-   data. Flushing the L1D has a performance impact as the processor has to
-   bring the flushed guest data back into the L1D. Depending on the
-   frequency of VMEXIT/VMENTER and the type of computations in the guest
-   performance degradation in the range of 1% to 50% has been observed. For
-   scenarios where guest VMEXIT/VMENTER are rare the performance impact is
-   minimal. Virtio and mechanisms like posted interrupts are designed to
-   confine the VMEXITs to a bare minimum, but specific configurations and
-   application scenarios might still suffer from a high VMEXIT rate.
-
-   The kernel provides two L1D flush modes:
-    - conditional ('cond')
-    - unconditional ('always')
-
-   The conditional mode avoids L1D flushing after VMEXITs which execute
-   only audited code paths before the corresponding VMENTER. These code
-   paths have been verified that they cannot expose secrets or other
-   interesting data to an attacker, but they can leak information about the
-   address space layout of the hypervisor.
-
-   Unconditional mode flushes L1D on all VMENTER invocations and provides
-   maximum protection. It has a higher overhead than the conditional
-   mode. The overhead cannot be quantified correctly as it depends on the
-   workload scenario and the resulting number of VMEXITs.
-
-   The general recommendation is to enable L1D flush on VMENTER. The kernel
-   defaults to conditional mode on affected processors.
-
-   **Note**, that L1D flush does not prevent the SMT problem because the
-   sibling thread will also bring back its data into the L1D which makes it
-   attackable again.
-
-   L1D flush can be controlled by the administrator via the kernel command
-   line and sysfs control files. See :ref:`mitigation_control_command_line`
-   and :ref:`mitigation_control_kvm`.
-
-.. _guest_confinement:
-
-2. Guest VCPU confinement to dedicated physical cores
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-   To address the SMT problem, it is possible to make a guest or a group of
-   guests affine to one or more physical cores. The proper mechanism for
-   that is to utilize exclusive cpusets to ensure that no other guest or
-   host tasks can run on these cores.
-
-   If only a single guest or related guests run on sibling SMT threads on
-   the same physical core then they can only attack their own memory and
-   restricted parts of the host memory.
-
-   Host memory is attackable, when one of the sibling SMT threads runs in
-   host OS (hypervisor) context and the other in guest context. The amount
-   of valuable information from the host OS context depends on the context
-   which the host OS executes, i.e. interrupts, soft interrupts and kernel
-   threads. The amount of valuable data from these contexts cannot be
-   declared as non-interesting for an attacker without deep inspection of
-   the code.
-
-   **Note**, that assigning guests to a fixed set of physical cores affects
-   the ability of the scheduler to do load balancing and might have
-   negative effects on CPU utilization depending on the hosting
-   scenario. Disabling SMT might be a viable alternative for particular
-   scenarios.
-
-   For further information about confining guests to a single or to a group
-   of cores consult the cpusets documentation:
-
-   https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt
-
-.. _interrupt_isolation:
-
-3. Interrupt affinity
-^^^^^^^^^^^^^^^^^^^^^
-
-   Interrupts can be made affine to logical CPUs. This is not universally
-   true because there are types of interrupts which are truly per CPU
-   interrupts, e.g. the local timer interrupt. Aside of that multi queue
-   devices affine their interrupts to single CPUs or groups of CPUs per
-   queue without allowing the administrator to control the affinities.
-
-   Moving the interrupts, which can be affinity controlled, away from CPUs
-   which run untrusted guests, reduces the attack vector space.
-
-   Whether the interrupts with are affine to CPUs, which run untrusted
-   guests, provide interesting data for an attacker depends on the system
-   configuration and the scenarios which run on the system. While for some
-   of the interrupts it can be assumed that they won't expose interesting
-   information beyond exposing hints about the host OS memory layout, there
-   is no way to make general assumptions.
-
-   Interrupt affinity can be controlled by the administrator via the
-   /proc/irq/$NR/smp_affinity[_list] files. Limited documentation is
-   available at:
-
-   https://www.kernel.org/doc/Documentation/IRQ-affinity.txt
-
-.. _smt_control:
-
-4. SMT control
-^^^^^^^^^^^^^^
-
-   To prevent the SMT issues of L1TF it might be necessary to disable SMT
-   completely. Disabling SMT can have a significant performance impact, but
-   the impact depends on the hosting scenario and the type of workloads.
-   The impact of disabling SMT needs also to be weighted against the impact
-   of other mitigation solutions like confining guests to dedicated cores.
-
-   The kernel provides a sysfs interface to retrieve the status of SMT and
-   to control it. It also provides a kernel command line interface to
-   control SMT.
-
-   The kernel command line interface consists of the following options:
-
-     =========== ==========================================================
-     nosmt      Affects the bring up of the secondary CPUs during boot. The
-                kernel tries to bring all present CPUs online during the
-                boot process. "nosmt" makes sure that from each physical
-                core only one - the so called primary (hyper) thread is
-                activated. Due to a design flaw of Intel processors related
-                to Machine Check Exceptions the non primary siblings have
-                to be brought up at least partially and are then shut down
-                again.  "nosmt" can be undone via the sysfs interface.
-
-     nosmt=force Has the same effect as "nosmt" but it does not allow to
-                undo the SMT disable via the sysfs interface.
-     =========== ==========================================================
-
-   The sysfs interface provides two files:
-
-   - /sys/devices/system/cpu/smt/control
-   - /sys/devices/system/cpu/smt/active
-
-   /sys/devices/system/cpu/smt/control:
-
-     This file allows to read out the SMT control state and provides the
-     ability to disable or (re)enable SMT. The possible states are:
-
-       ==============  ===================================================
-       on              SMT is supported by the CPU and enabled. All
-                       logical CPUs can be onlined and offlined without
-                       restrictions.
-
-       off             SMT is supported by the CPU and disabled. Only
-                       the so called primary SMT threads can be onlined
-                       and offlined without restrictions. An attempt to
-                       online a non-primary sibling is rejected
-
-       forceoff        Same as 'off' but the state cannot be controlled.
-                       Attempts to write to the control file are rejected.
-
-       notsupported    The processor does not support SMT. It's therefore
-                       not affected by the SMT implications of L1TF.
-                       Attempts to write to the control file are rejected.
-       ==============  ===================================================
-
-     The possible states which can be written into this file to control SMT
-     state are:
-
-     - on
-     - off
-     - forceoff
-
-   /sys/devices/system/cpu/smt/active:
-
-     This file reports whether SMT is enabled and active, i.e. if on any
-     physical core two or more sibling threads are online.
-
-   SMT control is also possible at boot time via the l1tf kernel command
-   line parameter in combination with L1D flush control. See
-   :ref:`mitigation_control_command_line`.
-
-5. Disabling EPT
-^^^^^^^^^^^^^^^^
-
-  Disabling EPT for virtual machines provides full mitigation for L1TF even
-  with SMT enabled, because the effective page tables for guests are
-  managed and sanitized by the hypervisor. Though disabling EPT has a
-  significant performance impact especially when the Meltdown mitigation
-  KPTI is enabled.
-
-  EPT can be disabled in the hypervisor via the 'kvm-intel.ept' parameter.
-
-There is ongoing research and development for new mitigation mechanisms to
-address the performance impact of disabling SMT or EPT.
-
-.. _mitigation_control_command_line:
-
-Mitigation control on the kernel command line
----------------------------------------------
-
-The kernel command line allows to control the L1TF mitigations at boot
-time with the option "l1tf=". The valid arguments for this option are:
-
-  ============  =============================================================
-  full         Provides all available mitigations for the L1TF
-               vulnerability. Disables SMT and enables all mitigations in
-               the hypervisors, i.e. unconditional L1D flushing
-
-               SMT control and L1D flush control via the sysfs interface
-               is still possible after boot.  Hypervisors will issue a
-               warning when the first VM is started in a potentially
-               insecure configuration, i.e. SMT enabled or L1D flush
-               disabled.
-
-  full,force   Same as 'full', but disables SMT and L1D flush runtime
-               control. Implies the 'nosmt=force' command line option.
-               (i.e. sysfs control of SMT is disabled.)
-
-  flush                Leaves SMT enabled and enables the default hypervisor
-               mitigation, i.e. conditional L1D flushing
-
-               SMT control and L1D flush control via the sysfs interface
-               is still possible after boot.  Hypervisors will issue a
-               warning when the first VM is started in a potentially
-               insecure configuration, i.e. SMT enabled or L1D flush
-               disabled.
-
-  flush,nosmt  Disables SMT and enables the default hypervisor mitigation,
-               i.e. conditional L1D flushing.
-
-               SMT control and L1D flush control via the sysfs interface
-               is still possible after boot.  Hypervisors will issue a
-               warning when the first VM is started in a potentially
-               insecure configuration, i.e. SMT enabled or L1D flush
-               disabled.
-
-  flush,nowarn Same as 'flush', but hypervisors will not warn when a VM is
-               started in a potentially insecure configuration.
-
-  off          Disables hypervisor mitigations and doesn't emit any
-               warnings.
-               It also drops the swap size and available RAM limit restrictions
-               on both hypervisor and bare metal.
-
-  ============  =============================================================
-
-The default is 'flush'. For details about L1D flushing see :ref:`l1d_flush`.
-
-
-.. _mitigation_control_kvm:
-
-Mitigation control for KVM - module parameter
--------------------------------------------------------------
-
-The KVM hypervisor mitigation mechanism, flushing the L1D cache when
-entering a guest, can be controlled with a module parameter.
-
-The option/parameter is "kvm-intel.vmentry_l1d_flush=". It takes the
-following arguments:
-
-  ============  ==============================================================
-  always       L1D cache flush on every VMENTER.
-
-  cond         Flush L1D on VMENTER only when the code between VMEXIT and
-               VMENTER can leak host memory which is considered
-               interesting for an attacker. This still can leak host memory
-               which allows e.g. to determine the hosts address space layout.
-
-  never                Disables the mitigation
-  ============  ==============================================================
-
-The parameter can be provided on the kernel command line, as a module
-parameter when loading the modules and at runtime modified via the sysfs
-file:
-
-/sys/module/kvm_intel/parameters/vmentry_l1d_flush
-
-The default is 'cond'. If 'l1tf=full,force' is given on the kernel command
-line, then 'always' is enforced and the kvm-intel.vmentry_l1d_flush
-module parameter is ignored and writes to the sysfs file are rejected.
-
-
-Mitigation selection guide
---------------------------
-
-1. No virtualization in use
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-   The system is protected by the kernel unconditionally and no further
-   action is required.
-
-2. Virtualization with trusted guests
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-   If the guest comes from a trusted source and the guest OS kernel is
-   guaranteed to have the L1TF mitigations in place the system is fully
-   protected against L1TF and no further action is required.
-
-   To avoid the overhead of the default L1D flushing on VMENTER the
-   administrator can disable the flushing via the kernel command line and
-   sysfs control files. See :ref:`mitigation_control_command_line` and
-   :ref:`mitigation_control_kvm`.
-
-
-3. Virtualization with untrusted guests
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-3.1. SMT not supported or disabled
-""""""""""""""""""""""""""""""""""
-
-  If SMT is not supported by the processor or disabled in the BIOS or by
-  the kernel, it's only required to enforce L1D flushing on VMENTER.
-
-  Conditional L1D flushing is the default behaviour and can be tuned. See
-  :ref:`mitigation_control_command_line` and :ref:`mitigation_control_kvm`.
-
-3.2. EPT not supported or disabled
-""""""""""""""""""""""""""""""""""
-
-  If EPT is not supported by the processor or disabled in the hypervisor,
-  the system is fully protected. SMT can stay enabled and L1D flushing on
-  VMENTER is not required.
-
-  EPT can be disabled in the hypervisor via the 'kvm-intel.ept' parameter.
-
-3.3. SMT and EPT supported and active
-"""""""""""""""""""""""""""""""""""""
-
-  If SMT and EPT are supported and active then various degrees of
-  mitigations can be employed:
-
-  - L1D flushing on VMENTER:
-
-    L1D flushing on VMENTER is the minimal protection requirement, but it
-    is only potent in combination with other mitigation methods.
-
-    Conditional L1D flushing is the default behaviour and can be tuned. See
-    :ref:`mitigation_control_command_line` and :ref:`mitigation_control_kvm`.
-
-  - Guest confinement:
-
-    Confinement of guests to a single or a group of physical cores which
-    are not running any other processes, can reduce the attack surface
-    significantly, but interrupts, soft interrupts and kernel threads can
-    still expose valuable data to a potential attacker. See
-    :ref:`guest_confinement`.
-
-  - Interrupt isolation:
-
-    Isolating the guest CPUs from interrupts can reduce the attack surface
-    further, but still allows a malicious guest to explore a limited amount
-    of host physical memory. This can at least be used to gain knowledge
-    about the host address space layout. The interrupts which have a fixed
-    affinity to the CPUs which run the untrusted guests can depending on
-    the scenario still trigger soft interrupts and schedule kernel threads
-    which might expose valuable information. See
-    :ref:`interrupt_isolation`.
-
-The above three mitigation methods combined can provide protection to a
-certain degree, but the risk of the remaining attack surface has to be
-carefully analyzed. For full protection the following methods are
-available:
-
-  - Disabling SMT:
-
-    Disabling SMT and enforcing the L1D flushing provides the maximum
-    amount of protection. This mitigation is not depending on any of the
-    above mitigation methods.
-
-    SMT control and L1D flushing can be tuned by the command line
-    parameters 'nosmt', 'l1tf', 'kvm-intel.vmentry_l1d_flush' and at run
-    time with the matching sysfs control files. See :ref:`smt_control`,
-    :ref:`mitigation_control_command_line` and
-    :ref:`mitigation_control_kvm`.
-
-  - Disabling EPT:
-
-    Disabling EPT provides the maximum amount of protection as well. It is
-    not depending on any of the above mitigation methods. SMT can stay
-    enabled and L1D flushing is not required, but the performance impact is
-    significant.
-
-    EPT can be disabled in the hypervisor via the 'kvm-intel.ept'
-    parameter.
-
-3.4. Nested virtual machines
-""""""""""""""""""""""""""""
-
-When nested virtualization is in use, three operating systems are involved:
-the bare metal hypervisor, the nested hypervisor and the nested virtual
-machine.  VMENTER operations from the nested hypervisor into the nested
-guest will always be processed by the bare metal hypervisor. If KVM is the
-bare metal hypervisor it will:
-
- - Flush the L1D cache on every switch from the nested hypervisor to the
-   nested virtual machine, so that the nested hypervisor's secrets are not
-   exposed to the nested virtual machine;
-
- - Flush the L1D cache on every switch from the nested virtual machine to
-   the nested hypervisor; this is a complex operation, and flushing the L1D
-   cache avoids that the bare metal hypervisor's secrets are exposed to the
-   nested virtual machine;
-
- - Instruct the nested hypervisor to not perform any L1D cache flush. This
-   is an optimization to avoid double L1D flushing.
-
-
-.. _default_mitigations:
-
-Default mitigations
--------------------
-
-  The kernel default mitigations for vulnerable processors are:
-
-  - PTE inversion to protect against malicious user space. This is done
-    unconditionally and cannot be controlled. The swap storage is limited
-    to ~16TB.
-
-  - L1D conditional flushing on VMENTER when EPT is enabled for
-    a guest.
-
-  The kernel does not by default enforce the disabling of SMT, which leaves
-  SMT systems vulnerable when running untrusted guests with EPT enabled.
-
-  The rationale for this choice is:
-
-  - Force disabling SMT can break existing setups, especially with
-    unattended updates.
-
-  - If regular users run untrusted guests on their machine, then L1TF is
-    just an add on to other malware which might be embedded in an untrusted
-    guest, e.g. spam-bots or attacks on the local network.
-
-    There is no technical way to prevent a user from running untrusted code
-    on their machines blindly.
-
-  - It's technically extremely unlikely and from today's knowledge even
-    impossible that L1TF can be exploited via the most popular attack
-    mechanisms like JavaScript because these mechanisms have no way to
-    control PTEs. If this would be possible and not other mitigation would
-    be possible, then the default might be different.
-
-  - The administrators of cloud and hosting setups have to carefully
-    analyze the risk for their scenarios and make the appropriate
-    mitigation choices, which might even vary across their deployed
-    machines and also result in other changes of their overall setup.
-    There is no way for the kernel to provide a sensible default for this
-    kind of scenarios.
diff --git a/Documentation/arm64/perf.txt b/Documentation/arm64/perf.txt
new file mode 100644 (file)
index 0000000..0d6a7d8
--- /dev/null
@@ -0,0 +1,85 @@
+Perf Event Attributes
+=====================
+
+Author: Andrew Murray <andrew.murray@arm.com>
+Date: 2019-03-06
+
+exclude_user
+------------
+
+This attribute excludes userspace.
+
+Userspace always runs at EL0 and thus this attribute will exclude EL0.
+
+
+exclude_kernel
+--------------
+
+This attribute excludes the kernel.
+
+The kernel runs at EL2 with VHE and EL1 without. Guest kernels always run
+at EL1.
+
+For the host this attribute will exclude EL1 and additionally EL2 on a VHE
+system.
+
+For the guest this attribute will exclude EL1. Please note that EL2 is
+never counted within a guest.
+
+
+exclude_hv
+----------
+
+This attribute excludes the hypervisor.
+
+For a VHE host this attribute is ignored as we consider the host kernel to
+be the hypervisor.
+
+For a non-VHE host this attribute will exclude EL2 as we consider the
+hypervisor to be any code that runs at EL2 which is predominantly used for
+guest/host transitions.
+
+For the guest this attribute has no effect. Please note that EL2 is
+never counted within a guest.
+
+
+exclude_host / exclude_guest
+----------------------------
+
+These attributes exclude the KVM host and guest, respectively.
+
+The KVM host may run at EL0 (userspace), EL1 (non-VHE kernel) and EL2 (VHE
+kernel or non-VHE hypervisor).
+
+The KVM guest may run at EL0 (userspace) and EL1 (kernel).
+
+Due to the overlapping exception levels between host and guests we cannot
+exclusively rely on the PMU's hardware exception filtering - therefore we
+must enable/disable counting on the entry and exit to the guest. This is
+performed differently on VHE and non-VHE systems.
+
+For non-VHE systems we exclude EL2 for exclude_host - upon entering and
+exiting the guest we disable/enable the event as appropriate based on the
+exclude_host and exclude_guest attributes.
+
+For VHE systems we exclude EL1 for exclude_guest and exclude both EL0,EL2
+for exclude_host. Upon entering and exiting the guest we modify the event
+to include/exclude EL0 as appropriate based on the exclude_host and
+exclude_guest attributes.
+
+The statements above also apply when these attributes are used within a
+non-VHE guest however please note that EL2 is never counted within a guest.
+
+
+Accuracy
+--------
+
+On non-VHE hosts we enable/disable counters on the entry/exit of host/guest
+transition at EL2 - however there is a period of time between
+enabling/disabling the counters and entering/exiting the guest. We are
+able to eliminate counters counting host events on the boundaries of guest
+entry/exit when counting guest events by filtering out EL2 for
+exclude_host. However when using !exclude_hv there is a small blackout
+window at the guest entry/exit where host events are not captured.
+
+On VHE systems there are no blackout windows.
index 5baca42ba146dd56c6c3e1ca433173290fe9ef5c..fc71b33de87ed1fc58cfd26d4a9a7f0f40c2adff 100644 (file)
@@ -87,7 +87,21 @@ used to get and set the keys for a thread.
 Virtualization
 --------------
 
-Pointer authentication is not currently supported in KVM guests. KVM
-will mask the feature bits from ID_AA64ISAR1_EL1, and attempted use of
-the feature will result in an UNDEFINED exception being injected into
-the guest.
+Pointer authentication is enabled in KVM guest when each virtual cpu is
+initialised by passing flags KVM_ARM_VCPU_PTRAUTH_[ADDRESS/GENERIC] and
+requesting these two separate cpu features to be enabled. The current KVM
+guest implementation works by enabling both features together, so both
+these userspace flags are checked before enabling pointer authentication.
+The separate userspace flag will allow to have no userspace ABI changes
+if support is added in the future to allow these two features to be
+enabled independently of one another.
+
+As Arm Architecture specifies that Pointer Authentication feature is
+implemented along with the VHE feature so KVM arm64 ptrauth code relies
+on VHE mode to be present.
+
+Additionally, when these vcpu feature flags are not set then KVM will
+filter out the Pointer Authentication system key registers from
+KVM_GET/SET_REG_* ioctls and mask those features from cpufeature ID
+register. Any attempt to use the Pointer Authentication instructions will
+result in an UNDEFINED exception being injected into the guest.
index 71f5d2fe39b7ea9cc1130128c9ae9d511a453de4..a29c99d1333190677c6717d0f1d04bb7104b75b2 100644 (file)
@@ -147,10 +147,10 @@ Division Functions
 .. kernel-doc:: include/linux/math64.h
    :internal:
 
-.. kernel-doc:: lib/div64.c
+.. kernel-doc:: lib/math/div64.c
    :functions: div_s64_rem div64_u64_rem div64_u64 div64_s64
 
-.. kernel-doc:: lib/gcd.c
+.. kernel-doc:: lib/math/gcd.c
    :export:
 
 UUID/GUID
index 69a7d90c320ad983f1120b9f6eab4eb12b6712d4..46aae52a41d014fd057d3cd90c60586351d858e1 100644 (file)
@@ -34,10 +34,6 @@ Configure the kernel with::
         CONFIG_DEBUG_FS=y
         CONFIG_GCOV_KERNEL=y
 
-select the gcc's gcov format, default is autodetect based on gcc version::
-
-        CONFIG_GCOV_FORMAT_AUTODETECT=y
-
 and to get coverage data for the entire kernel::
 
         CONFIG_GCOV_PROFILE_ALL=y
@@ -169,6 +165,20 @@ b) gcov is run on the BUILD machine
       [user@build] gcov -o /tmp/coverage/tmp/out/init main.c
 
 
+Note on compilers
+-----------------
+
+GCC and LLVM gcov tools are not necessarily compatible. Use gcov_ to work with
+GCC-generated .gcno and .gcda files, and use llvm-cov_ for Clang.
+
+.. _gcov: http://gcc.gnu.org/onlinedocs/gcc/Gcov.html
+.. _llvm-cov: https://llvm.org/docs/CommandGuide/llvm-cov.html
+
+Build differences between GCC and Clang gcov are handled by Kconfig. It
+automatically selects the appropriate gcov format depending on the detected
+toolchain.
+
+
 Troubleshooting
 ---------------
 
diff --git a/Documentation/device-mapper/dm-dust.txt b/Documentation/device-mapper/dm-dust.txt
new file mode 100644 (file)
index 0000000..954d402
--- /dev/null
@@ -0,0 +1,272 @@
+dm-dust
+=======
+
+This target emulates the behavior of bad sectors at arbitrary
+locations, and the ability to enable the emulation of the failures
+at an arbitrary time.
+
+This target behaves similarly to a linear target.  At a given time,
+the user can send a message to the target to start failing read
+requests on specific blocks (to emulate the behavior of a hard disk
+drive with bad sectors).
+
+When the failure behavior is enabled (i.e.: when the output of
+"dmsetup status" displays "fail_read_on_bad_block"), reads of blocks
+in the "bad block list" will fail with EIO ("Input/output error").
+
+Writes of blocks in the "bad block list will result in the following:
+
+1. Remove the block from the "bad block list".
+2. Successfully complete the write.
+
+This emulates the "remapped sector" behavior of a drive with bad
+sectors.
+
+Normally, a drive that is encountering bad sectors will most likely
+encounter more bad sectors, at an unknown time or location.
+With dm-dust, the user can use the "addbadblock" and "removebadblock"
+messages to add arbitrary bad blocks at new locations, and the
+"enable" and "disable" messages to modulate the state of whether the
+configured "bad blocks" will be treated as bad, or bypassed.
+This allows the pre-writing of test data and metadata prior to
+simulating a "failure" event where bad sectors start to appear.
+
+Table parameters:
+-----------------
+<device_path> <offset> <blksz>
+
+Mandatory parameters:
+    <device_path>: path to the block device.
+    <offset>: offset to data area from start of device_path
+    <blksz>: block size in bytes
+            (minimum 512, maximum 1073741824, must be a power of 2)
+
+Usage instructions:
+-------------------
+
+First, find the size (in 512-byte sectors) of the device to be used:
+
+$ sudo blockdev --getsz /dev/vdb1
+33552384
+
+Create the dm-dust device:
+(For a device with a block size of 512 bytes)
+$ sudo dmsetup create dust1 --table '0 33552384 dust /dev/vdb1 0 512'
+
+(For a device with a block size of 4096 bytes)
+$ sudo dmsetup create dust1 --table '0 33552384 dust /dev/vdb1 0 4096'
+
+Check the status of the read behavior ("bypass" indicates that all I/O
+will be passed through to the underlying device):
+$ sudo dmsetup status dust1
+0 33552384 dust 252:17 bypass
+
+$ sudo dd if=/dev/mapper/dust1 of=/dev/null bs=512 count=128 iflag=direct
+128+0 records in
+128+0 records out
+
+$ sudo dd if=/dev/zero of=/dev/mapper/dust1 bs=512 count=128 oflag=direct
+128+0 records in
+128+0 records out
+
+Adding and removing bad blocks:
+-------------------------------
+
+At any time (i.e.: whether the device has the "bad block" emulation
+enabled or disabled), bad blocks may be added or removed from the
+device via the "addbadblock" and "removebadblock" messages:
+
+$ sudo dmsetup message dust1 0 addbadblock 60
+kernel: device-mapper: dust: badblock added at block 60
+
+$ sudo dmsetup message dust1 0 addbadblock 67
+kernel: device-mapper: dust: badblock added at block 67
+
+$ sudo dmsetup message dust1 0 addbadblock 72
+kernel: device-mapper: dust: badblock added at block 72
+
+These bad blocks will be stored in the "bad block list".
+While the device is in "bypass" mode, reads and writes will succeed:
+
+$ sudo dmsetup status dust1
+0 33552384 dust 252:17 bypass
+
+Enabling block read failures:
+-----------------------------
+
+To enable the "fail read on bad block" behavior, send the "enable" message:
+
+$ sudo dmsetup message dust1 0 enable
+kernel: device-mapper: dust: enabling read failures on bad sectors
+
+$ sudo dmsetup status dust1
+0 33552384 dust 252:17 fail_read_on_bad_block
+
+With the device in "fail read on bad block" mode, attempting to read a
+block will encounter an "Input/output error":
+
+$ sudo dd if=/dev/mapper/dust1 of=/dev/null bs=512 count=1 skip=67 iflag=direct
+dd: error reading '/dev/mapper/dust1': Input/output error
+0+0 records in
+0+0 records out
+0 bytes copied, 0.00040651 s, 0.0 kB/s
+
+...and writing to the bad blocks will remove the blocks from the list,
+therefore emulating the "remap" behavior of hard disk drives:
+
+$ sudo dd if=/dev/zero of=/dev/mapper/dust1 bs=512 count=128 oflag=direct
+128+0 records in
+128+0 records out
+
+kernel: device-mapper: dust: block 60 removed from badblocklist by write
+kernel: device-mapper: dust: block 67 removed from badblocklist by write
+kernel: device-mapper: dust: block 72 removed from badblocklist by write
+kernel: device-mapper: dust: block 87 removed from badblocklist by write
+
+Bad block add/remove error handling:
+------------------------------------
+
+Attempting to add a bad block that already exists in the list will
+result in an "Invalid argument" error, as well as a helpful message:
+
+$ sudo dmsetup message dust1 0 addbadblock 88
+device-mapper: message ioctl on dust1  failed: Invalid argument
+kernel: device-mapper: dust: block 88 already in badblocklist
+
+Attempting to remove a bad block that doesn't exist in the list will
+result in an "Invalid argument" error, as well as a helpful message:
+
+$ sudo dmsetup message dust1 0 removebadblock 87
+device-mapper: message ioctl on dust1  failed: Invalid argument
+kernel: device-mapper: dust: block 87 not found in badblocklist
+
+Counting the number of bad blocks in the bad block list:
+--------------------------------------------------------
+
+To count the number of bad blocks configured in the device, run the
+following message command:
+
+$ sudo dmsetup message dust1 0 countbadblocks
+
+A message will print with the number of bad blocks currently
+configured on the device:
+
+kernel: device-mapper: dust: countbadblocks: 895 badblock(s) found
+
+Querying for specific bad blocks:
+---------------------------------
+
+To find out if a specific block is in the bad block list, run the
+following message command:
+
+$ sudo dmsetup message dust1 0 queryblock 72
+
+The following message will print if the block is in the list:
+device-mapper: dust: queryblock: block 72 found in badblocklist
+
+The following message will print if the block is in the list:
+device-mapper: dust: queryblock: block 72 not found in badblocklist
+
+The "queryblock" message command will work in both the "enabled"
+and "disabled" modes, allowing the verification of whether a block
+will be treated as "bad" without having to issue I/O to the device,
+or having to "enable" the bad block emulation.
+
+Clearing the bad block list:
+----------------------------
+
+To clear the bad block list (without needing to individually run
+a "removebadblock" message command for every block), run the
+following message command:
+
+$ sudo dmsetup message dust1 0 clearbadblocks
+
+After clearing the bad block list, the following message will appear:
+
+kernel: device-mapper: dust: clearbadblocks: badblocks cleared
+
+If there were no bad blocks to clear, the following message will
+appear:
+
+kernel: device-mapper: dust: clearbadblocks: no badblocks found
+
+Message commands list:
+----------------------
+
+Below is a list of the messages that can be sent to a dust device:
+
+Operations on blocks (requires a <blknum> argument):
+
+addbadblock <blknum>
+queryblock <blknum>
+removebadblock <blknum>
+
+...where <blknum> is a block number within range of the device
+  (corresponding to the block size of the device.)
+
+Single argument message commands:
+
+countbadblocks
+clearbadblocks
+disable
+enable
+quiet
+
+Device removal:
+---------------
+
+When finished, remove the device via the "dmsetup remove" command:
+
+$ sudo dmsetup remove dust1
+
+Quiet mode:
+-----------
+
+On test runs with many bad blocks, it may be desirable to avoid
+excessive logging (from bad blocks added, removed, or "remapped").
+This can be done by enabling "quiet mode" via the following message:
+
+$ sudo dmsetup message dust1 0 quiet
+
+This will suppress log messages from add / remove / removed by write
+operations.  Log messages from "countbadblocks" or "queryblock"
+message commands will still print in quiet mode.
+
+The status of quiet mode can be seen by running "dmsetup status":
+
+$ sudo dmsetup status dust1
+0 33552384 dust 252:17 fail_read_on_bad_block quiet
+
+To disable quiet mode, send the "quiet" message again:
+
+$ sudo dmsetup message dust1 0 quiet
+
+$ sudo dmsetup status dust1
+0 33552384 dust 252:17 fail_read_on_bad_block verbose
+
+(The presence of "verbose" indicates normal logging.)
+
+"Why not...?"
+-------------
+
+scsi_debug has a "medium error" mode that can fail reads on one
+specified sector (sector 0x1234, hardcoded in the source code), but
+it uses RAM for the persistent storage, which drastically decreases
+the potential device size.
+
+dm-flakey fails all I/O from all block locations at a specified time
+frequency, and not a given point in time.
+
+When a bad sector occurs on a hard disk drive, reads to that sector
+are failed by the device, usually resulting in an error code of EIO
+("I/O error") or ENODATA ("No data available").  However, a write to
+the sector may succeed, and result in the sector becoming readable
+after the device controller no longer experiences errors reading the
+sector (or after a reallocation of the sector).  However, there may
+be bad sectors that occur on the device in the future, in a different,
+unpredictable location.
+
+This target seeks to provide a device that can exhibit the behavior
+of a bad sector at a known sector location, at a known time, based
+on a large storage device (at least tens of gigabytes, not occupying
+system memory).
index 297251b0d2d5715872449d0b4c556a0fb72cd4dc..d63d78ffeb7308fc8f8bf0c9eabbe89b1c028fb4 100644 (file)
@@ -21,6 +21,13 @@ mode it calculates and verifies the integrity tag internally. In this
 mode, the dm-integrity target can be used to detect silent data
 corruption on the disk or in the I/O path.
 
+There's an alternate mode of operation where dm-integrity uses bitmap
+instead of a journal. If a bit in the bitmap is 1, the corresponding
+region's data and integrity tags are not synchronized - if the machine
+crashes, the unsynchronized regions will be recalculated. The bitmap mode
+is faster than the journal mode, because we don't have to write the data
+twice, but it is also less reliable, because if data corruption happens
+when the machine crashes, it may not be detected.
 
 When loading the target for the first time, the kernel driver will format
 the device. But it will only format the device if the superblock contains
@@ -59,6 +66,10 @@ Target arguments:
                either both data and tag or none of them are written. The
                journaled mode degrades write throughput twice because the
                data have to be written twice.
+       B - bitmap mode - data and metadata are written without any
+               synchronization, the driver maintains a bitmap of dirty
+               regions where data and metadata don't match. This mode can
+               only be used with internal hash.
        R - recovery mode - in this mode, journal is not replayed,
                checksums are not checked and writes to the device are not
                allowed. This mode is useful for data recovery if the
@@ -79,6 +90,10 @@ interleave_sectors:number
        a power of two. If the device is already formatted, the value from
        the superblock is used.
 
+meta_device:device
+       Don't interleave the data and metadata on on device. Use a
+       separate device for metadata.
+
 buffer_sectors:number
        The number of sectors in one buffer. The value is rounded down to
        a power of two.
@@ -146,6 +161,15 @@ block_size:number
        Supported values are 512, 1024, 2048 and 4096 bytes.  If not
        specified the default block size is 512 bytes.
 
+sectors_per_bit:number
+       In the bitmap mode, this parameter specifies the number of
+       512-byte sectors that corresponds to one bitmap bit.
+
+bitmap_flush_interval:number
+       The bitmap flush interval in milliseconds. The metadata buffers
+       are synchronized when this interval expires.
+
+
 The journal mode (D/J), buffer_sectors, journal_watermark, commit_time can
 be changed when reloading the target (load an inactive table and swap the
 tables with suspend and resume). The other arguments should not be changed
@@ -167,7 +191,13 @@ The layout of the formatted block device:
          provides (i.e. the size of the device minus the size of all
          metadata and padding). The user of this target should not send
          bios that access data beyond the "provided data sectors" limit.
-       * flags - a flag is set if journal_mac is used
+       * flags
+         SB_FLAG_HAVE_JOURNAL_MAC - a flag is set if journal_mac is used
+         SB_FLAG_RECALCULATING - recalculating is in progress
+         SB_FLAG_DIRTY_BITMAP - journal area contains the bitmap of dirty
+               blocks
+       * log2(sectors per block)
+       * a position where recalculating finished
 * journal
        The journal is divided into sections, each section contains:
        * metadata area (4kiB), it contains journal entries
index f4d04a0672824087de6987b6be4dfd5c4fd2bf84..82edbaaa3f85beeafdf3b96c957776f8b03e90fc 100644 (file)
@@ -11,3 +11,15 @@ Example:
                reg = <0xffd08000 0x1000>;
                cpu1-start-addr = <0xffd080c4>;
        };
+
+ARM64 - Stratix10
+Required properties:
+- compatible : "altr,sys-mgr-s10"
+- reg : Should contain 1 register range(address and length)
+        for system manager register.
+
+Example:
+        sysmgr@ffd12000 {
+               compatible = "altr,sys-mgr-s10";
+               reg = <0xffd12000 0x228>;
+       };
index 7f40cb5f490bd741184103ee3c2683d8cd3346c4..061f7b98a07f14e2e7d24761e9895e5b9dc81de5 100644 (file)
@@ -110,6 +110,7 @@ Board compatible values (alphabetically, grouped by SoC):
 
   - "amlogic,u200" (Meson g12a s905d2)
   - "amediatech,x96-max" (Meson g12a s905x2)
+  - "seirobotics,sei510" (Meson g12a s905x2)
 
 Amlogic Meson Firmware registers Interface
 ------------------------------------------
index e61d00e25b9572487231438ec668392d7d46e3fc..9fbde401a0909c94ca0cc12ae6b3550cb5d540a7 100644 (file)
@@ -84,7 +84,7 @@ SHDWC SAMA5D2-Compatible Shutdown Controller
 1) shdwc node
 
 required properties:
-- compatible: should be "atmel,sama5d2-shdwc".
+- compatible: should be "atmel,sama5d2-shdwc" or "microchip,sam9x60-shdwc".
 - reg: should contain registers location and length
 - clocks: phandle to input clock.
 - #address-cells: should be one. The cell is the wake-up input index.
@@ -96,6 +96,9 @@ optional properties:
   microseconds. It's usually a board-related property.
 - atmel,wakeup-rtc-timer: boolean to enable Real-Time Clock wake-up.
 
+optional microchip,sam9x60-shdwc properties:
+- atmel,wakeup-rtt-timer: boolean to enable Real-time Timer Wake-up.
+
 The node contains child nodes for each wake-up input that the platform uses.
 
 2) input nodes
index 72d481c8dd4843c54d28ee3238d2fa23d85bb4c5..5d7dbabbb78449ae22f8a2a12174a00e6e292f12 100644 (file)
@@ -22,9 +22,11 @@ Required properties:
 -------------------
 - compatible:  should be "fsl,imx-scu".
 - mbox-names:  should include "tx0", "tx1", "tx2", "tx3",
-                              "rx0", "rx1", "rx2", "rx3".
-- mboxes:      List of phandle of 4 MU channels for tx and 4 MU channels
-               for rx. All 8 MU channels must be in the same MU instance.
+                              "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
@@ -34,6 +36,7 @@ Required properties:
                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
@@ -42,10 +45,18 @@ Required properties:
                          &lsio_mu1 1 0
                          &lsio_mu1 1 1
                          &lsio_mu1 1 2
-                         &lsio_mu1 1 3>;
+                         &lsio_mu1 1 3
+                         &lsio_mu1 3 3>;
                See Documentation/devicetree/bindings/mailbox/fsl,mu.txt
                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:
 ============================================================
 
@@ -124,6 +135,10 @@ Required properties:
 
 Example (imx8qxp):
 -------------
+aliases {
+       mu1 = &lsio_mu1;
+};
+
 lsio_mu1: mailbox@5d1c0000 {
        ...
        #mbox-cells = <2>;
@@ -133,7 +148,8 @@ firmware {
        scu {
                compatible = "fsl,imx-scu";
                mbox-names = "tx0", "tx1", "tx2", "tx3",
-                            "rx0", "rx1", "rx2", "rx3";
+                            "rx0", "rx1", "rx2", "rx3",
+                            "gip3";
                mboxes = <&lsio_mu1 0 0
                          &lsio_mu1 0 1
                          &lsio_mu1 0 2
@@ -141,7 +157,8 @@ firmware {
                          &lsio_mu1 1 0
                          &lsio_mu1 1 1
                          &lsio_mu1 1 2
-                         &lsio_mu1 1 3>;
+                         &lsio_mu1 1 3
+                         &lsio_mu1 3 3>;
 
                clk: clk {
                        compatible = "fsl,imx8qxp-clk", "fsl,scu-clk";
index 7e2cd6ad26bd40492dbd4dc2b8d47e54f910bd90..407138ebc0d0a934f33b79f569c96f22a849bc49 100644 (file)
@@ -51,6 +51,13 @@ properties:
           - const: i2se,duckbill-2
           - const: fsl,imx28
 
+      - description: i.MX50 based Boards
+        items:
+          - enum:
+              - fsl,imx50-evk
+              - kobo,aura
+          - const: fsl,imx50
+
       - description: i.MX51 Babbage Board
         items:
           - enum:
@@ -67,6 +74,7 @@ properties:
               - fsl,imx53-evk
               - fsl,imx53-qsb
               - fsl,imx53-smd
+              - menlo,m53menlo
           - const: fsl,imx53
 
       - description: i.MX6Q based Boards
@@ -90,6 +98,7 @@ properties:
       - description: i.MX6DL based Boards
         items:
           - enum:
+              - eckelmann,imx6dl-ci4x10
               - fsl,imx6dl-sabreauto      # i.MX6 DualLite/Solo SABRE Automotive Board
               - fsl,imx6dl-sabresd        # i.MX6 DualLite SABRE Smart Device Board
               - technologic,imx6dl-ts4900
@@ -137,10 +146,18 @@ properties:
           - const: fsl,imx6ull # This seems odd. Should be last?
           - const: fsl,imx6ulz
 
+      - description: i.MX7S based Boards
+        items:
+          - enum:
+              - tq,imx7s-mba7             # i.MX7S TQ MBa7 with TQMa7S SoM
+          - const: fsl,imx7s
+
       - description: i.MX7D based Boards
         items:
           - enum:
               - fsl,imx7d-sdb             # i.MX7 SabreSD Board
+              - tq,imx7d-mba7             # i.MX7D TQ MBa7 with TQMa7D SoM
+              - zii,imx7d-rpu2            # ZII RPU2 Board
           - const: fsl,imx7d
 
       - description:
@@ -154,6 +171,12 @@ properties:
           - const: compulab,cl-som-imx7
           - const: fsl,imx7d
 
+      - description: i.MX8MM based Boards
+        items:
+          - enum:
+              - fsl,imx8mm-evk            # i.MX8MM EVK Board
+          - const: fsl,imx8mm
+
       - description: i.MX8QXP based Boards
         items:
           - enum:
@@ -176,6 +199,19 @@ properties:
               - fsl,vf610
               - fsl,vf610m4
 
+      - description: ZII's VF610 based Boards
+        items:
+          - enum:
+              - zii,vf610cfu1      # ZII VF610 CFU1 Board
+              - zii,vf610dev-c     # ZII VF610 Development Board, Rev C
+              - zii,vf610dev-b     # ZII VF610 Development Board, Rev B
+              - zii,vf610scu4-aib  # ZII VF610 SCU4 AIB
+              - zii,vf610dtu       # ZII VF610 SSMB DTU Board
+              - zii,vf610spu3      # ZII VF610 SSMB SPU3 Board
+              - zii,vf610spb4      # ZII VF610 SPB4 Board
+          - const: zii,vf610dev
+          - const: fsl,vf610
+
       - description: LS1012A based Boards
         items:
           - enum:
diff --git a/Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml b/Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml
new file mode 100644 (file)
index 0000000..f4f7451
--- /dev/null
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/intel-ixp4xx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Intel IXP4xx Device Tree Bindings
+
+maintainers:
+  - Linus Walleij <linus.walleij@linaro.org>
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - linksys,nslu2
+          - const: intel,ixp42x
+      - items:
+          - enum:
+              - gateworks,gw2358
+          - const: intel,ixp43x
index 2ecc712bf7075da21bd29104024a9c0fc15186f6..1c1e48fd94b553c2681591c5489a84e26c72ac4b 100644 (file)
@@ -92,6 +92,9 @@ SoCs:
 - DRA718
   compatible = "ti,dra718", "ti,dra722", "ti,dra72", "ti,dra7"
 
+- AM5748
+  compatible = "ti,am5748", "ti,dra762", "ti,dra7"
+
 - AM5728
   compatible = "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7"
 
@@ -184,6 +187,9 @@ Boards:
 - AM57XX SBC-AM57x
   compatible = "compulab,sbc-am57x", "compulab,cl-som-am57x", "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7"
 
+- AM5748 IDK
+  compatible = "ti,am5748-idk", "ti,am5748", "ti,dra762", "ti,dra7";
+
 - AM5728 IDK
   compatible = "ti,am5728-idk", "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7"
 
index 061a03edf9c829848d56ac3c79b1094cfc5cf808..5c6bbf10abc9c1624f586afc08c239c8878dcf24 100644 (file)
@@ -97,6 +97,7 @@ properties:
           - enum:
               - friendlyarm,nanopc-t4
               - friendlyarm,nanopi-m4
+              - friendlyarm,nanopi-neo4
           - const: rockchip,rk3399
 
       - description: GeekBuying GeekBox
@@ -146,7 +147,7 @@ properties:
           - const: google,gru
           - const: rockchip,rk3399
 
-      - description: Google Jaq (Haier Chromebook 11 and more)
+      - description: Google Jaq (Haier Chromebook 11 and more w/ uSD)
         items:
           - const: google,veyron-jaq-rev5
           - const: google,veyron-jaq-rev4
@@ -159,6 +160,12 @@ properties:
 
       - description: Google Jerry (Hisense Chromebook C11 and more)
         items:
+          - const: google,veyron-jerry-rev15
+          - const: google,veyron-jerry-rev14
+          - const: google,veyron-jerry-rev13
+          - const: google,veyron-jerry-rev12
+          - const: google,veyron-jerry-rev11
+          - const: google,veyron-jerry-rev10
           - const: google,veyron-jerry-rev7
           - const: google,veyron-jerry-rev6
           - const: google,veyron-jerry-rev5
@@ -199,6 +206,17 @@ properties:
           - const: google,veyron
           - const: rockchip,rk3288
 
+      - description: Google Mighty (Haier Chromebook 11 and more w/ SD)
+        items:
+          - const: google,veyron-mighty-rev5
+          - const: google,veyron-mighty-rev4
+          - const: google,veyron-mighty-rev3
+          - const: google,veyron-mighty-rev2
+          - const: google,veyron-mighty-rev1
+          - const: google,veyron-mighty
+          - const: google,veyron
+          - const: rockchip,rk3288
+
       - description: Google Minnie (Asus Chromebook Flip C100P)
         items:
           - const: google,veyron-minnie-rev4
@@ -308,6 +326,11 @@ properties:
           - const: netxeon,r89
           - const: rockchip,rk3288
 
+      - description: Orange Pi RK3399 board
+        items:
+          - const: rockchip,rk3399-orangepi
+          - const: rockchip,rk3399
+
       - description: Phytec phyCORE-RK3288 Rapid Development Kit
         items:
           - const: phytec,rk3288-pcm-947
index 99980aee26e5fe748512ed78da9f50315ea1abb3..c92d411fd02381bf1a5cb2f03e3c72de05d1a52b 100644 (file)
@@ -5,10 +5,12 @@ Properties:
                  - " st,stm32mp157-syscfg " - for stm32mp157 based SoCs,
                  second value must be always "syscon".
    - reg : offset and length of the register set.
+   - clocks: phandle to the syscfg clock
 
  Example:
          syscfg: syscon@50020000 {
                  compatible = "st,stm32mp157-syscfg", "syscon";
                  reg = <0x50020000 0x400>;
+                 clocks = <&rcc SYSCFG>;
          };
 
diff --git a/Documentation/devicetree/bindings/arm/sunxi.txt b/Documentation/devicetree/bindings/arm/sunxi.txt
deleted file mode 100644 (file)
index 9254cbe..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-Allwinner sunXi Platforms Device Tree Bindings
-
-Each device tree must specify which Allwinner SoC it uses,
-using one of the following compatible strings:
-
-  allwinner,sun4i-a10
-  allwinner,sun5i-a10s
-  allwinner,sun5i-a13
-  allwinner,sun5i-r8
-  allwinner,sun6i-a31
-  allwinner,sun7i-a20
-  allwinner,sun8i-a23
-  allwinner,sun8i-a33
-  allwinner,sun8i-a83t
-  allwinner,sun8i-h2-plus
-  allwinner,sun8i-h3
-  allwinner,sun8i-r40
-  allwinner,sun8i-t3
-  allwinner,sun8i-v3s
-  allwinner,sun9i-a80
-  allwinner,sun50i-a64
-  allwinner,suniv-f1c100s
-  nextthing,gr8
diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml
new file mode 100644 (file)
index 0000000..285f4fc
--- /dev/null
@@ -0,0 +1,807 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR X11)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/sunxi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner platforms device tree bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+
+      - description: Allwinner A23 Evaluation Board
+        items:
+          - const: allwinner,sun8i-a23-evb
+          - const: allwinner,sun8i-a23
+
+      - description: Allwinner A31 APP4 Evaluation Board
+        items:
+          - const: allwinner,app4-evb1
+          - const: allwinner,sun6i-a31
+
+      - description: Allwinner A83t Homlet Evaluation Board v2
+        items:
+          - const: allwinner,h8homlet-v2
+          - const: allwinner,sun8i-a83t
+
+      - description: Allwinner GA10H Quad Core Tablet v1.1
+        items:
+          - const: allwinner,ga10h-v1.1
+          - const: allwinner,sun8i-a33
+
+      - description: Allwinner GT90H Tablet v4
+        items:
+          - const: allwinner,gt90h-v4
+          - const: allwinner,sun8i-a23
+
+      - description: Allwinner R16 EVB (Parrot)
+        items:
+          - const: allwinner,parrot
+          - const: allwinner,sun8i-a33
+
+      - description: Amarula A64 Relic
+        items:
+          - const: amarula,a64-relic
+          - const: allwinner,sun50i-a64
+
+      - description: Auxtek T003 A10s HDMI TV Stick
+        items:
+          - const: allwinner,auxtek-t003
+          - const: allwinner,sun5i-a10s
+
+      - description: Auxtek T004 A10s HDMI TV Stick
+        items:
+          - const: allwinner,auxtek-t004
+          - const: allwinner,sun5i-a10s
+
+      - description: BA10 TV Box
+        items:
+          - const: allwinner,ba10-tvbox
+          - const: allwinner,sun4i-a10
+
+      - description: BananaPi
+        items:
+          - const: lemaker,bananapi
+          - const: allwinner,sun7i-a20
+
+      - description: BananaPi M1 Plus
+        items:
+          - const: sinovoip,bpi-m1-plus
+          - const: allwinner,sun7i-a20
+
+      - description: BananaPi M2
+        items:
+          - const: sinovoip,bpi-m2
+          - const: allwinner,sun6i-a31s
+
+      - description: BananaPi M2 Berry
+        items:
+          - const: sinovoip,bpi-m2-berry
+          - const: allwinner,sun8i-r40
+
+      - description: BananaPi M2 Plus
+        items:
+          - const: sinovoip,bpi-m2-plus
+          - const: allwinner,sun8i-h3
+
+      - description: BananaPi M2 Plus
+        items:
+          - const: sinovoip,bpi-m2-plus
+          - const: allwinner,sun50i-h5
+
+      - description: BananaPi M2 Plus v1.2
+        items:
+          - const: bananapi,bpi-m2-plus-v1.2
+          - const: allwinner,sun8i-h3
+
+      - description: BananaPi M2 Plus v1.2
+        items:
+          - const: bananapi,bpi-m2-plus-v1.2
+          - const: allwinner,sun50i-h5
+
+      - description: BananaPi M2 Magic
+        items:
+          - const: sinovoip,bananapi-m2m
+          - const: allwinner,sun8i-a33
+
+      - description: BananaPi M2 Ultra
+        items:
+          - const: sinovoip,bpi-m2-ultra
+          - const: allwinner,sun8i-r40
+
+      - description: BananaPi M2 Zero
+        items:
+          - const: sinovoip,bpi-m2-zero
+          - const: allwinner,sun8i-h2-plus
+
+      - description: BananaPi M3
+        items:
+          - const: sinovoip,bpi-m3
+          - const: allwinner,sun8i-a83t
+
+      - description: BananaPi M64
+        items:
+          - const: sinovoip,bananapi-m64
+          - const: allwinner,sun50i-a64
+
+      - description: BananaPro
+        items:
+          - const: lemaker,bananapro
+          - const: allwinner,sun7i-a20
+
+      - description: Beelink GS1
+        items:
+          - const: azw,beelink-gs1
+          - const: allwinner,sun50i-h6
+
+      - description: Beelink X2
+        items:
+          - const: roofull,beelink-x2
+          - const: allwinner,sun8i-h3
+
+      - description: Chuwi V7 CW0825
+        items:
+          - const: chuwi,v7-cw0825
+          - const: allwinner,sun4i-a10
+
+      - description: Colorfly E708 Q1 Tablet
+        items:
+          - const: colorfly,e708-q1
+          - const: allwinner,sun6i-a31s
+
+      - description: CSQ CS908 Set Top Box
+        items:
+          - const: csq,cs908
+          - const: allwinner,sun6i-a31s
+
+      - description: Cubietech Cubieboard
+        items:
+          - const: cubietech,a10-cubieboard
+          - const: allwinner,sun4i-a10
+
+      - description: Cubietech Cubieboard2
+        items:
+          - const: cubietech,cubieboard2
+          - const: allwinner,sun7i-a20
+
+      - description: Cubietech Cubieboard4
+        items:
+          - const: cubietech,a80-cubieboard4
+          - const: allwinner,sun9i-a80
+
+      - description: Cubietech Cubietruck
+        items:
+          - const: cubietech,cubietruck
+          - const: allwinner,sun7i-a20
+
+      - description: Cubietech Cubietruck Plus
+        items:
+          - const: cubietech,cubietruck-plus
+          - const: allwinner,sun8i-a83t
+
+      - description: Difrnce DIT4350
+        items:
+          - const: difrnce,dit4350
+          - const: allwinner,sun5i-a13
+
+      - description: Dserve DSRV9703C
+        items:
+          - const: dserve,dsrv9703c
+          - const: allwinner,sun4i-a10
+
+      - description: Empire Electronix D709 Tablet
+        items:
+          - const: empire-electronix,d709
+          - const: allwinner,sun5i-a13
+
+      - description: Empire Electronix M712 Tablet
+        items:
+          - const: empire-electronix,m712
+          - const: allwinner,sun5i-a13
+
+      - description: FriendlyARM NanoPi A64
+        items:
+          - const: friendlyarm,nanopi-a64
+          - const: allwinner,sun50i-a64
+
+      - description: FriendlyARM NanoPi M1
+        items:
+          - const: friendlyarm,nanopi-m1
+          - const: allwinner,sun8i-h3
+
+      - description: FriendlyARM NanoPi M1 Plus
+        items:
+          - const: friendlyarm,nanopi-m1-plus
+          - const: allwinner,sun8i-h3
+
+      - description: FriendlyARM NanoPi Neo
+        items:
+          - const: friendlyarm,nanopi-neo
+          - const: allwinner,sun8i-h3
+
+      - description: FriendlyARM NanoPi Neo 2
+        items:
+          - const: friendlyarm,nanopi-neo2
+          - const: allwinner,sun50i-h5
+
+      - description: FriendlyARM NanoPi Neo Air
+        items:
+          - const: friendlyarm,nanopi-neo-air
+          - const: allwinner,sun8i-h3
+
+      - description: FriendlyARM NanoPi Neo Plus2
+        items:
+          - const: friendlyarm,nanopi-neo-plus2
+          - const: allwinner,sun50i-h5
+
+      - description: Gemei G9 Tablet
+        items:
+          - const: gemei,g9
+          - const: allwinner,sun4i-a10
+
+      - description: Hyundai A7HD
+        items:
+          - const: hyundai,a7hd
+          - const: allwinner,sun4i-a10
+
+      - description: HSG H702
+        items:
+          - const: hsg,h702
+          - const: allwinner,sun5i-a13
+
+      - description: I12 TV Box
+        items:
+          - const: allwinner,i12-tvbox
+          - const: allwinner,sun7i-a20
+
+      - description: ICNova A20 SWAC
+        items:
+          - const: swac,icnova-a20-swac
+          - const: incircuit,icnova-a20
+          - const: allwinner,sun7i-a20
+
+      - description: INet-1
+        items:
+          - const: inet-tek,inet1
+          - const: allwinner,sun4i-a10
+
+      - description: iNet-86DZ Rev 01
+        items:
+          - const: primux,inet86dz
+          - const: allwinner,sun8i-a23
+
+      - description: iNet-9F Rev 03
+        items:
+          - const: inet-tek,inet9f-rev03
+          - const: allwinner,sun4i-a10
+
+      - description: iNet-97F Rev 02
+        items:
+          - const: primux,inet97fv2
+          - const: allwinner,sun4i-a10
+
+      - description: iNet-98V Rev 02
+        items:
+          - const: primux,inet98v-rev2
+          - const: allwinner,sun5i-a13
+
+      - description: iNet D978 Rev 02 Tablet
+        items:
+          - const: primux,inet-d978-rev2
+          - const: allwinner,sun8i-a33
+
+      - description: iNet Q972 Tablet
+        items:
+          - const: inet-tek,inet-q972
+          - const: allwinner,sun6i-a31s
+
+      - description: Itead Ibox A20
+        items:
+          - const: itead,itead-ibox-a20
+          - const: allwinner,sun7i-a20
+
+      - description: Itead Iteaduino Plus A10
+        items:
+          - const: itead,iteaduino-plus-a10
+          - const: allwinner,sun4i-a10
+
+      - description: Jesurun Q5
+        items:
+          - const: jesurun,q5
+          - const: allwinner,sun4i-a10
+
+      - description: Lamobo R1
+        items:
+          - const: lamobo,lamobo-r1
+          - const: allwinner,sun7i-a20
+
+      - description: Libre Computer Board ALL-H3-CC H2+
+        items:
+          - const: libretech,all-h3-cc-h2-plus
+          - const: allwinner,sun8i-h2-plus
+
+      - description: Libre Computer Board ALL-H3-CC H3
+        items:
+          - const: libretech,all-h3-cc-h3
+          - const: allwinner,sun8i-h3
+
+      - description: Libre Computer Board ALL-H3-CC H5
+        items:
+          - const: libretech,all-h3-cc-h5
+          - const: allwinner,sun50i-h5
+
+      - description: Lichee Pi One
+        items:
+          - const: licheepi,licheepi-one
+          - const: allwinner,sun5i-a13
+
+      - description: Lichee Pi Zero
+        items:
+          - const: licheepi,licheepi-zero
+          - const: allwinner,sun8i-v3s
+
+      - description: Lichee Pi Zero (with Dock)
+        items:
+          - const: licheepi,licheepi-zero-dock
+          - const: licheepi,licheepi-zero
+          - const: allwinner,sun8i-v3s
+
+      - description: Linksprite PCDuino
+        items:
+          - const: linksprite,a10-pcduino
+          - const: allwinner,sun4i-a10
+
+      - description: Linksprite PCDuino2
+        items:
+          - const: linksprite,a10-pcduino2
+          - const: allwinner,sun4i-a10
+
+      - description: Linksprite PCDuino3
+        items:
+          - const: linksprite,pcduino3
+          - const: allwinner,sun7i-a20
+
+      - description: Linksprite PCDuino3 Nano
+        items:
+          - const: linksprite,pcduino3-nano
+          - const: allwinner,sun7i-a20
+
+      - description: HAOYU Electronics Marsboard A10
+        items:
+          - const: haoyu,a10-marsboard
+          - const: allwinner,sun4i-a10
+
+      - description: MapleBoard MP130
+        items:
+          - const: mapleboard,mp130
+          - const: allwinner,sun8i-h3
+
+      - description: Mele A1000
+        items:
+          - const: mele,a1000
+          - const: allwinner,sun4i-a10
+
+      - description: Mele A1000G Quad Set Top Box
+        items:
+          - const: mele,a1000g-quad
+          - const: allwinner,sun6i-a31
+
+      - description: Mele I7 Quad Set Top Box
+        items:
+          - const: mele,i7
+          - const: allwinner,sun6i-a31
+
+      - description: Mele M3
+        items:
+          - const: mele,m3
+          - const: allwinner,sun7i-a20
+
+      - description: Mele M9 Set Top Box
+        items:
+          - const: mele,m9
+          - const: allwinner,sun6i-a31
+
+      - description: Merrii A20 Hummingboard
+        items:
+          - const: merrii,a20-hummingbird
+          - const: allwinner,sun7i-a20
+
+      - description: Merrii A31 Hummingboard
+        items:
+          - const: merrii,a31-hummingbird
+          - const: allwinner,sun6i-a31
+
+      - description: Merrii A80 Optimus
+        items:
+          - const: merrii,a80-optimus
+          - const: allwinner,sun9i-a80
+
+      - description: Miniand Hackberry
+        items:
+          - const: miniand,hackberry
+          - const: allwinner,sun4i-a10
+
+      - description: MK802
+        items:
+          - const: allwinner,mk802
+          - const: allwinner,sun4i-a10
+
+      - description: MK802-A10s
+        items:
+          - const: allwinner,a10s-mk802
+          - const: allwinner,sun5i-a10s
+
+      - description: MK802-II
+        items:
+          - const: allwinner,mk802ii
+          - const: allwinner,sun4i-a10
+
+      - description: MK808c
+        items:
+          - const: allwinner,mk808c
+          - const: allwinner,sun7i-a20
+
+      - description: MSI Primo81 Tablet
+        items:
+          - const: msi,primo81
+          - const: allwinner,sun6i-a31s
+
+      - description: Emlid Neutis N5 Developper Board
+        items:
+          - const: emlid,neutis-n5-devboard
+          - const: emlid,neutis-n5
+          - const: allwinner,sun50i-h5
+
+      - description: NextThing Co. CHIP
+        items:
+          - const: nextthing,chip
+          - const: allwinner,sun5i-r8
+          - const: allwinner,sun5i-a13
+
+      - description: NextThing Co. CHIP Pro
+        items:
+          - const: nextthing,chip-pro
+          - const: nextthing,gr8
+
+      - description: NextThing Co. GR8 Evaluation Board
+        items:
+          - const: nextthing,gr8-evb
+          - const: nextthing,gr8
+
+      - description: Nintendo NES Classic
+        items:
+          - const: nintendo,nes-classic
+          - const: allwinner,sun8i-r16
+          - const: allwinner,sun8i-a33
+
+      - description: Nintendo Super NES Classic
+        items:
+          - const: nintendo,super-nes-classic
+          - const: nintendo,nes-classic
+          - const: allwinner,sun8i-r16
+          - const: allwinner,sun8i-a33
+
+      - description: Oceanic 5inMFD (5205)
+        items:
+          - const: oceanic,5205-5inmfd
+          - const: allwinner,sun50i-a64
+
+      - description: Olimex A10-OlinuXino LIME
+        items:
+          - const: olimex,a10-olinuxino-lime
+          - const: allwinner,sun4i-a10
+
+      - description: Olimex A10s-OlinuXino Micro
+        items:
+          - const: olimex,a10s-olinuxino-micro
+          - const: allwinner,sun5i-a10s
+
+      - description: Olimex A13-OlinuXino
+        items:
+          - const: olimex,a13-olinuxino
+          - const: allwinner,sun5i-a13
+
+      - description: Olimex A13-OlinuXino Micro
+        items:
+          - const: olimex,a13-olinuxino-micro
+          - const: allwinner,sun5i-a13
+
+      - description: Olimex A20-Olimex SOM Evaluation Board
+        items:
+          - const: olimex,a20-olimex-som-evb
+          - const: allwinner,sun7i-a20
+
+      - description: Olimex A20-Olimex SOM Evaluation Board (with eMMC)
+        items:
+          - const: olimex,a20-olimex-som-evb-emmc
+          - const: allwinner,sun7i-a20
+
+      - description: Olimex A20-OlinuXino LIME
+        items:
+          - const: olimex,a20-olinuxino-lime
+          - const: allwinner,sun7i-a20
+
+      - description: Olimex A20-OlinuXino LIME2
+        items:
+          - const: olimex,a20-olinuxino-lime2
+          - const: allwinner,sun7i-a20
+
+      - description: Olimex A20-OlinuXino LIME2 (with eMMC)
+        items:
+          - const: olimex,a20-olinuxino-lime2-emmc
+          - const: allwinner,sun7i-a20
+
+      - description: Olimex A20-OlinuXino Micro
+        items:
+          - const: olimex,a20-olinuxino-micro
+          - const: allwinner,sun7i-a20
+
+      - description: Olimex A20-OlinuXino Micro (with eMMC)
+        items:
+          - const: olimex,a20-olinuxino-micro-emmc
+          - const: allwinner,sun7i-a20
+
+      - description: Olimex A20-SOM204 Evaluation Board
+        items:
+          - const: olimex,a20-olimex-som204-evb
+          - const: allwinner,sun7i-a20
+
+      - description: Olimex A20-SOM204 Evaluation Board (with eMMC)
+        items:
+          - const: olimex,a20-olimex-som204-evb-emmc
+          - const: allwinner,sun7i-a20
+
+      - description: Olimex A33-OlinuXino
+        items:
+          - const: olimex,a33-olinuxino
+          - const: allwinner,sun8i-a33
+
+      - description: Olimex A64-OlinuXino
+        items:
+          - const: olimex,a64-olinuxino
+          - const: allwinner,sun50i-a64
+
+      - description: Olimex A64 Teres-I
+        items:
+          - const: olimex,a64-teres-i
+          - const: allwinner,sun50i-a64
+
+      - description: Pine64
+        items:
+          - const: pine64,pine64
+          - const: allwinner,sun50i-a64
+
+      - description: Pine64+
+        items:
+          - const: pine64,pine64-plus
+          - const: allwinner,sun50i-a64
+
+      - description: Pine64 PineH64
+        items:
+          - const: pine64,pine-h64
+          - const: allwinner,sun50i-h6
+
+      - description: Pine64 LTS
+        items:
+          - const: pine64,pine64-lts
+          - const: allwinner,sun50i-r18
+          - const: allwinner,sun50i-a64
+
+      - description: Pine64 Pinebook
+        items:
+          - const: pine64,pinebook
+          - const: allwinner,sun50i-a64
+
+      - description: Pine64 SoPine Baseboard
+        items:
+          - const: pine64,sopine-baseboard
+          - const: pine64,sopine
+          - const: allwinner,sun50i-a64
+
+      - description: PineRiver Mini X-Plus
+        items:
+          - const: pineriver,mini-xplus
+          - const: allwinner,sun4i-a10
+
+      - description: Point of View Protab2-IPS9
+        items:
+          - const: pov,protab2-ips9
+          - const: allwinner,sun4i-a10
+
+      - description: Polaroid MID2407PXE03 Tablet
+        items:
+          - const: polaroid,mid2407pxe03
+          - const: allwinner,sun8i-a23
+
+      - description: Polaroid MID2809PXE04 Tablet
+        items:
+          - const: polaroid,mid2809pxe04
+          - const: allwinner,sun8i-a23
+
+      - description: Q8 A13 Tablet
+        items:
+          - const: allwinner,q8-a13
+          - const: allwinner,sun5i-a13
+
+      - description: Q8 A23 Tablet
+        items:
+          - const: allwinner,q8-a23
+          - const: allwinner,sun8i-a23
+
+      - description: Q8 A33 Tablet
+        items:
+          - const: allwinner,q8-a33
+          - const: allwinner,sun8i-a33
+
+      - description: Qihua CQA3T BV3
+        items:
+          - const: qihua,t3-cqa3t-bv3
+          - const: allwinner,sun8i-t3
+          - const: allwinner,sun8i-r40
+
+      - description: R7 A10s HDMI TV Stick
+        items:
+          - const: allwinner,r7-tv-dongle
+          - const: allwinner,sun5i-a10s
+
+      - description: RerVision H3-DVK
+        items:
+          - const: rervision,h3-dvk
+          - const: allwinner,sun8i-h3
+
+      - description: Sinlinx SinA31s Core Board
+        items:
+          - const: sinlinx,sina31s
+          - const: allwinner,sun6i-a31s
+
+      - description: Sinlinx SinA31s Development Board
+        items:
+          - const: sinlinx,sina31s-sdk
+          - const: allwinner,sun6i-a31s
+
+      - description: Sinlinx SinA33
+        items:
+          - const: sinlinx,sina33
+          - const: allwinner,sun8i-a33
+
+      - description: TBS A711 Tablet
+        items:
+          - const: tbs-biometrics,a711
+          - const: allwinner,sun8i-a83t
+
+      - description: Utoo P66
+        items:
+          - const: utoo,p66
+          - const: allwinner,sun5i-a13
+
+      - description: Wexler TAB7200
+        items:
+          - const: wexler,tab7200
+          - const: allwinner,sun7i-a20
+
+      - description: WITS A31 Colombus Evaluation Board
+        items:
+          - const: wits,colombus
+          - const: allwinner,sun6i-a31
+
+      - description: WITS Pro A20 DKT
+        items:
+          - const: wits,pro-a20-dkt
+          - const: allwinner,sun7i-a20
+
+      - description: Wobo i5
+        items:
+          - const: wobo,a10s-wobo-i5
+          - const: allwinner,sun5i-a10s
+
+      - description: Yones TopTech BS1078 v2 Tablet
+        items:
+          - const: yones-toptech,bs1078-v2
+          - const: allwinner,sun6i-a31s
+
+      - description: Xunlong OrangePi
+        items:
+          - const: xunlong,orangepi
+          - const: allwinner,sun7i-a20
+
+      - description: Xunlong OrangePi 2
+        items:
+          - const: xunlong,orangepi-2
+          - const: allwinner,sun8i-h3
+
+      - description: Xunlong OrangePi 3
+        items:
+          - const: xunlong,orangepi-3
+          - const: allwinner,sun50i-h6
+
+      - description: Xunlong OrangePi Lite
+        items:
+          - const: xunlong,orangepi-lite
+          - const: allwinner,sun8i-h3
+
+      - description: Xunlong OrangePi Lite2
+        items:
+          - const: xunlong,orangepi-lite2
+          - const: allwinner,sun50i-h6
+
+      - description: Xunlong OrangePi Mini
+        items:
+          - const: xunlong,orangepi-mini
+          - const: allwinner,sun7i-a20
+
+      - description: Xunlong OrangePi One
+        items:
+          - const: xunlong,orangepi-one
+          - const: allwinner,sun8i-h3
+
+      - description: Xunlong OrangePi One Plus
+        items:
+          - const: xunlong,orangepi-one-plus
+          - const: allwinner,sun50i-h6
+
+      - description: Xunlong OrangePi PC
+        items:
+          - const: xunlong,orangepi-pc
+          - const: allwinner,sun8i-h3
+
+      - description: Xunlong OrangePi PC 2
+        items:
+          - const: xunlong,orangepi-pc2
+          - const: allwinner,sun50i-h5
+
+      - description: Xunlong OrangePi PC Plus
+        items:
+          - const: xunlong,orangepi-pc-plus
+          - const: allwinner,sun8i-h3
+
+      - description: Xunlong OrangePi Plus
+        items:
+          - const: xunlong,orangepi-plus
+          - const: allwinner,sun8i-h3
+
+      - description: Xunlong OrangePi Plus 2E
+        items:
+          - const: xunlong,orangepi-plus2e
+          - const: allwinner,sun8i-h3
+
+      - description: Xunlong OrangePi Prime
+        items:
+          - const: xunlong,orangepi-prime
+          - const: allwinner,sun50i-h5
+
+      - description: Xunlong OrangePi R1
+        items:
+          - const: xunlong,orangepi-r1
+          - const: allwinner,sun8i-h2-plus
+
+      - description: Xunlong OrangePi Win
+        items:
+          - const: xunlong,orangepi-win
+          - const: allwinner,sun50i-a64
+
+      - description: Xunlong OrangePi Zero
+        items:
+          - const: xunlong,orangepi-zero
+          - const: allwinner,sun8i-h2-plus
+
+      - description: Xunlong OrangePi Zero Plus
+        items:
+          - const: xunlong,orangepi-zero-plus
+          - const: allwinner,sun50i-h5
+
+      - description: Xunlong OrangePi Zero Plus2
+        items:
+          - const: xunlong,orangepi-zero-plus2
+          - const: allwinner,sun50i-h5
+
+      - description: Xunlong OrangePi Zero Plus2
+        items:
+          - const: xunlong,orangepi-zero-plus2-h3
+          - const: allwinner,sun8i-h3
index 85a23f551f024ca3e2c4e8c12b6aa2093d146341..233eb829420445cd03a1911dfa8eff848907867b 100644 (file)
@@ -94,6 +94,8 @@ Optional properties:
 
 - ti,no-idle-on-init   interconnect target module should not be idled at init
 
+- ti,no-idle           interconnect target module should not be idled
+
 Example: Single instance of MUSB controller on omap4 using interconnect ranges
 using offsets from l4_cfg second segment (0x4a000000 + 0x80000 = 0x4a0ab000):
 
@@ -131,6 +133,6 @@ using offsets from l4_cfg second segment (0x4a000000 + 0x80000 = 0x4a0ab000):
                };
        };
 
-Note that other SoCs, such as am335x can have multipe child devices. On am335x
+Note that other SoCs, such as am335x can have multiple child devices. On am335x
 there are two MUSB instances, two USB PHY instances, and a single CPPI41 DMA
-instance as children of a single interconnet target module.
+instance as children of a single interconnect target module.
diff --git a/Documentation/devicetree/bindings/clock/xlnx,zynqmp-clk.txt b/Documentation/devicetree/bindings/clock/xlnx,zynqmp-clk.txt
new file mode 100644 (file)
index 0000000..391ee1a
--- /dev/null
@@ -0,0 +1,63 @@
+--------------------------------------------------------------------------
+Device Tree Clock bindings for the Zynq Ultrascale+ MPSoC controlled using
+Zynq MPSoC firmware interface
+--------------------------------------------------------------------------
+The clock controller is a h/w block of Zynq Ultrascale+ MPSoC clock
+tree. It reads required input clock frequencies from the devicetree and acts
+as clock provider for all clock consumers of PS clocks.
+
+See clock_bindings.txt for more information on the generic clock bindings.
+
+Required properties:
+ - #clock-cells:       Must be 1
+ - compatible:         Must contain:   "xlnx,zynqmp-clk"
+ - clocks:             List of clock specifiers which are external input
+                       clocks to the given clock controller. Please refer
+                       the next section to find the input clocks for a
+                       given controller.
+ - clock-names:                List of clock names which are exteral input clocks
+                       to the given clock controller. Please refer to the
+                       clock bindings for more details.
+
+Input clocks for zynqmp Ultrascale+ clock controller:
+
+The Zynq UltraScale+ MPSoC has one primary and four alternative reference clock
+inputs. These required clock inputs are:
+ - pss_ref_clk (PS reference clock)
+ - video_clk (reference clock for video system )
+ - pss_alt_ref_clk (alternative PS reference clock)
+ - aux_ref_clk
+ - gt_crx_ref_clk (transceiver reference clock)
+
+The following strings are optional parameters to the 'clock-names' property in
+order to provide an optional (E)MIO clock source:
+ - swdt0_ext_clk
+ - swdt1_ext_clk
+ - gem0_emio_clk
+ - gem1_emio_clk
+ - gem2_emio_clk
+ - gem3_emio_clk
+ - mio_clk_XX          # with XX = 00..77
+ - mio_clk_50_or_51    #for the mux clock to gem tsu from 50 or 51
+
+
+Output clocks are registered based on clock information received
+from firmware. Output clocks indexes are mentioned in
+include/dt-bindings/clock/xlnx-zynqmp-clk.h.
+
+-------
+Example
+-------
+
+firmware {
+       zynqmp_firmware: zynqmp-firmware {
+               compatible = "xlnx,zynqmp-firmware";
+               method = "smc";
+               zynqmp_clk: clock-controller {
+                       #clock-cells = <1>;
+                       compatible = "xlnx,zynqmp-clk";
+                       clocks = <&pss_ref_clk>, <&video_clk>, <&pss_alt_ref_clk>, <&aux_ref_clk>, <&gt_crx_ref_clk>;
+                       clock-names = "pss_ref_clk", "video_clk", "pss_alt_ref_clk","aux_ref_clk", "gt_crx_ref_clk";
+               };
+       };
+};
index 3c9a57a8443b25903474293dd3e3181a29958d7c..9d8bbac27d8b9dae370f087bf85fce15c610d894 100644 (file)
@@ -9,6 +9,7 @@ Required properties:
       "fsl,imx53-sdma"
       "fsl,imx6q-sdma"
       "fsl,imx7d-sdma"
+      "fsl,imx8mq-sdma"
   The -to variants should be preferred since they allow to determine the
   correct ROM script addresses needed for the driver to work without additional
   firmware.
diff --git a/Documentation/devicetree/bindings/firmware/intel,ixp4xx-network-processing-engine.yaml b/Documentation/devicetree/bindings/firmware/intel,ixp4xx-network-processing-engine.yaml
new file mode 100644 (file)
index 0000000..8cb136c
--- /dev/null
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 Linaro Ltd.
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/firmware/intel-ixp4xx-network-processing-engine.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Intel IXP4xx Network Processing Engine
+
+maintainers:
+  - Linus Walleij <linus.walleij@linaro.org>
+
+description: |
+  On the IXP4xx SoCs, the Network Processing Engine (NPE) is a small
+  processor that can load a firmware to perform offloading of networking
+  and crypto tasks. It also manages the MDIO bus to the ethernet PHYs
+  on the IXP4xx platform. All IXP4xx platforms have three NPEs at
+  consecutive memory locations. They are all included in the same
+  device node since they are not independent of each other.
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - const: intel,ixp4xx-network-processing-engine
+
+  reg:
+    minItems: 3
+    maxItems: 3
+    items:
+      - description: NPE0 register range
+      - description: NPE1 register range
+      - description: NPE2 register range
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    npe@c8006000 {
+         compatible = "intel,ixp4xx-network-processing-engine";
+         reg = <0xc8006000 0x1000>, <0xc8007000 0x1000>, <0xc8008000 0x1000>;
+    };
index 614bac55df86bd00f21cf12cfa63147ae6020550..a4fe136be2bae888a5ee6089fdd48ce19e574712 100644 (file)
@@ -17,53 +17,6 @@ Required properties:
                  - "smc" : SMC #0, following the SMCCC
                  - "hvc" : HVC #0, following the SMCCC
 
---------------------------------------------------------------------------
-Device Tree Clock bindings for the Zynq Ultrascale+ MPSoC controlled using
-Zynq MPSoC firmware interface
---------------------------------------------------------------------------
-The clock controller is a h/w block of Zynq Ultrascale+ MPSoC clock
-tree. It reads required input clock frequencies from the devicetree and acts
-as clock provider for all clock consumers of PS clocks.
-
-See clock_bindings.txt for more information on the generic clock bindings.
-
-Required properties:
- - #clock-cells:       Must be 1
- - compatible:         Must contain:   "xlnx,zynqmp-clk"
- - clocks:             List of clock specifiers which are external input
-                       clocks to the given clock controller. Please refer
-                       the next section to find the input clocks for a
-                       given controller.
- - clock-names:                List of clock names which are exteral input clocks
-                       to the given clock controller. Please refer to the
-                       clock bindings for more details.
-
-Input clocks for zynqmp Ultrascale+ clock controller:
-
-The Zynq UltraScale+ MPSoC has one primary and four alternative reference clock
-inputs. These required clock inputs are:
- - pss_ref_clk (PS reference clock)
- - video_clk (reference clock for video system )
- - pss_alt_ref_clk (alternative PS reference clock)
- - aux_ref_clk
- - gt_crx_ref_clk (transceiver reference clock)
-
-The following strings are optional parameters to the 'clock-names' property in
-order to provide an optional (E)MIO clock source:
- - swdt0_ext_clk
- - swdt1_ext_clk
- - gem0_emio_clk
- - gem1_emio_clk
- - gem2_emio_clk
- - gem3_emio_clk
- - mio_clk_XX          # with XX = 00..77
- - mio_clk_50_or_51    #for the mux clock to gem tsu from 50 or 51
-
-
-Output clocks are registered based on clock information received
-from firmware. Output clocks indexes are mentioned in
-include/dt-bindings/clock/xlnx,zynqmp-clk.h.
-
 -------
 Example
 -------
@@ -72,11 +25,6 @@ firmware {
        zynqmp_firmware: zynqmp-firmware {
                compatible = "xlnx,zynqmp-firmware";
                method = "smc";
-               zynqmp_clk: clock-controller {
-                       #clock-cells = <1>;
-                       compatible = "xlnx,zynqmp-clk";
-                       clocks = <&pss_ref_clk>, <&video_clk>, <&pss_alt_ref_clk>, <&aux_ref_clk>, <&gt_crx_ref_clk>;
-                       clock-names = "pss_ref_clk", "video_clk", "pss_alt_ref_clk","aux_ref_clk", "gt_crx_ref_clk";
-               };
+               ...
        };
 };
diff --git a/Documentation/devicetree/bindings/fpga/xlnx,zynqmp-pcap-fpga.txt b/Documentation/devicetree/bindings/fpga/xlnx,zynqmp-pcap-fpga.txt
new file mode 100644 (file)
index 0000000..3052bf6
--- /dev/null
@@ -0,0 +1,25 @@
+Devicetree bindings for Zynq Ultrascale MPSoC FPGA Manager.
+The ZynqMP SoC uses the PCAP (Processor configuration Port) to configure the
+Programmable Logic (PL). The configuration uses  the firmware interface.
+
+Required properties:
+- compatible: should contain "xlnx,zynqmp-pcap-fpga"
+
+Example for full FPGA configuration:
+
+       fpga-region0 {
+               compatible = "fpga-region";
+               fpga-mgr = <&zynqmp_pcap>;
+               #address-cells = <0x1>;
+               #size-cells = <0x1>;
+       };
+
+       firmware {
+               zynqmp_firmware: zynqmp-firmware {
+                       compatible = "xlnx,zynqmp-firmware";
+                       method = "smc";
+                       zynqmp_pcap: pcap {
+                               compatible = "xlnx,zynqmp-pcap-fpga";
+                       };
+               };
+       };
index fb144e2b65226601677f4f5de591f1904c03a805..dab537c20def4ce15dfa4c2200d34f775b257fde 100644 (file)
@@ -2,6 +2,7 @@
 
 Required properties:
  - compatible: Has to contain one of the following:
+       nxp,pca6416
        nxp,pca9505
        nxp,pca9534
        nxp,pca9535
@@ -30,6 +31,7 @@ Required properties:
        ti,tca6424
        ti,tca9539
        ti,tca9554
+       onnn,cat9554
        onnn,pca9654
        exar,xra1202
  - gpio-controller: if used as gpio expander.
index 18a2cde2e5f3a96c89067ea5cafd60fe4c71a0bc..1b1a74129141f3eec51936ec2429b269b10f920f 100644 (file)
@@ -37,6 +37,20 @@ Optional properties:
 - operating-points-v2 : Refer to Documentation/devicetree/bindings/opp/opp.txt
   for details.
 
+- resets : Phandle of the GPU reset line.
+
+Vendor-specific bindings
+------------------------
+
+The Mali GPU is integrated very differently from one SoC to
+another. In order to accomodate those differences, you have the option
+to specify one more vendor-specific compatible, among:
+
+- "amlogic,meson-gxm-mali"
+  Required properties:
+  - resets : Should contain phandles of :
+    + GPU reset line
+    + GPU APB glue reset line
 
 Example for a Mali-T760:
 
index 6ced829b0e588532a397f80b732a5abe938fd0a8..41b76762953a2c8c182d26e6d6a53d3cb880dc1b 100644 (file)
@@ -21,8 +21,6 @@ Optional properties:
 Example:
        fan0: pwm-fan {
                compatible = "pwm-fan";
-               cooling-min-state = <0>;
-               cooling-max-state = <3>;
                #cooling-cells = <2>;
                pwms = <&pwm 0 10000 0>;
                cooling-levels = <0 102 170 230>;
index 5c184b9406693f68b28ecb3e4fcfda32470c92ec..f1f3a552459b3801cc92949b9b09dfcd901808d1 100644 (file)
@@ -10,6 +10,7 @@ Required properties:
 - clocks: The root clock of the ADC controller
 - clock-names: Must contain "adc", matching entry in the clocks property
 - vref-supply: The regulator supply ADC reference voltage
+- #io-channel-cells: Must be 1 as per ../iio-bindings.txt
 
 Example:
 adc1: adc@30610000 {
@@ -19,4 +20,5 @@ adc1: adc@30610000 {
        clocks = <&clks IMX7D_ADC_ROOT_CLK>;
        clock-names = "adc";
        vref-supply = <&reg_vcc_3v3_mcu>;
+       #io-channel-cells = <1>;
 };
index c81993f8d8c391d00e8dd1d1ddcd011131d592e2..c8787688122af921211a48d997c4935c2faabe5d 100644 (file)
@@ -13,6 +13,7 @@ VADC node:
     Definition: Should contain "qcom,spmi-vadc".
                 Should contain "qcom,spmi-adc5" for PMIC5 ADC driver.
                 Should contain "qcom,spmi-adc-rev2" for PMIC rev2 ADC driver.
+                Should contain "qcom,pms405-adc" for PMS405 PMIC
 
 - reg:
     Usage: required
diff --git a/Documentation/devicetree/bindings/input/gpio-vibrator.yaml b/Documentation/devicetree/bindings/input/gpio-vibrator.yaml
new file mode 100644 (file)
index 0000000..903475f
--- /dev/null
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/bindings/input/gpio-vibrator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: GPIO vibrator
+
+maintainers:
+  - Luca Weiss <luca@z3ntu.xyz>
+
+description: |+
+  Registers a GPIO device as vibrator, where the on/off capability is controlled by a GPIO.
+
+properties:
+  compatible:
+    const: gpio-vibrator
+
+  enable-gpios:
+    maxItems: 1
+
+  vcc-supply:
+    description: Regulator that provides power
+
+required:
+  - compatible
+  - enable-gpios
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    vibrator {
+        compatible = "gpio-vibrator";
+        enable-gpios = <&msmgpio 86 GPIO_ACTIVE_HIGH>;
+        vcc-supply = <&pm8941_l18>;
+    };
index bcf62f856358d095916ffe50de4f9d6e65abae50..2b075a080d303bab7fc2353093ef09f9770edc0f 100644 (file)
@@ -8,6 +8,7 @@ Required Properties:
 - reg: Physical base address of the controller and length of memory mapped
   region.
 - interrupts: The interrupt number to the cpu.
+- clocks: phandle to clock controller plus clock-specifier pair
 - nxp,debounce-delay-ms: Debounce delay in ms
 - nxp,scan-delay-ms: Repeated scan period in ms
 - linux,keymap: the key-code to be reported when the key is pressed
@@ -22,7 +23,9 @@ Example:
        key@40050000 {
                compatible = "nxp,lpc3220-key";
                reg = <0x40050000 0x1000>;
-               interrupts = <54 0>;
+               clocks = <&clk LPC32XX_CLK_KEY>;
+               interrupt-parent = <&sic1>;
+               interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
                keypad,num-rows = <1>;
                keypad,num-columns = <1>;
                nxp,debounce-delay-ms = <3>;
diff --git a/Documentation/devicetree/bindings/input/max77650-onkey.txt b/Documentation/devicetree/bindings/input/max77650-onkey.txt
new file mode 100644 (file)
index 0000000..477dc74
--- /dev/null
@@ -0,0 +1,26 @@
+Onkey driver for MAX77650 PMIC from Maxim Integrated.
+
+This module is part of the MAX77650 MFD device. For more details
+see Documentation/devicetree/bindings/mfd/max77650.txt.
+
+The onkey controller is represented as a sub-node of the PMIC node on
+the device tree.
+
+Required properties:
+--------------------
+- compatible:          Must be "maxim,max77650-onkey".
+
+Optional properties:
+- linux,code:          The key-code to be reported when the key is pressed.
+                       Defaults to KEY_POWER.
+- maxim,onkey-slide:   The system's button is a slide switch, not the default
+                       push button.
+
+Example:
+--------
+
+       onkey {
+               compatible = "maxim,max77650-onkey";
+               linux,code = <KEY_END>;
+               maxim,onkey-slide;
+       };
diff --git a/Documentation/devicetree/bindings/input/microchip,qt1050.txt b/Documentation/devicetree/bindings/input/microchip,qt1050.txt
new file mode 100644 (file)
index 0000000..80e75f9
--- /dev/null
@@ -0,0 +1,78 @@
+Microchip AT42QT1050 Five-channel Touch Sensor IC
+
+The AT42QT1050 (QT1050) is a QTouchADC sensor device. The device can sense from
+one to five keys, dependent on mode. The QT1050 includes all signal processing
+functions necessary to provide stable sensing under a wide variety of changing
+conditions, and the outputs are fully debounced.
+
+The touchkey device node should be placed inside an I2C bus node.
+
+Required properties:
+- compatible: Must be "microchip,qt1050"
+- reg: The I2C address of the device
+- interrupts: The sink for the touchpad's IRQ output,
+  see ../interrupt-controller/interrupts.txt
+
+Optional properties:
+- wakeup-source: touch keys can be used as a wakeup source
+
+Each button (key) is represented as a sub-node:
+
+Each not specified key or key with linux,code set to KEY_RESERVED gets disabled
+in HW.
+
+Subnode properties:
+- linux,code: Keycode to emit.
+- reg: The key number. Valid values: 0, 1, 2, 3, 4.
+
+Optional subnode-properties:
+
+If a optional property is missing or has a invalid value the default value is
+taken.
+
+- microchip,pre-charge-time-ns:
+  Each touchpad need some time to precharge. The value depends on the mechanical
+  layout.
+  Valid value range: 0 - 637500; values must be a multiple of 2500;
+  default is 0.
+- microchip,average-samples:
+  Number of data samples which are averaged for each read.
+  Valid values: 1, 4, 16, 64, 256, 1024, 4096, 16384; default is 1.
+- microchip,average-scaling:
+  The scaling factor which is used to scale the average-samples.
+  Valid values: 1, 2, 4, 8, 16, 32, 64, 128; default is 1.
+- microchip,threshold:
+  Number of counts to register a touch detection.
+  Valid value range: 0 - 255; default is 20.
+
+Example:
+QT1050 with 3 non continuous keys, key2 and key4 are disabled.
+
+touchkeys@41 {
+       compatible = "microchip,qt1050";
+       reg = <0x41>;
+       interrupt-parent = <&gpio0>;
+       interrupts = <17 IRQ_TYPE_EDGE_FALLING>;
+
+       up@0 {
+               reg = <0>;
+               linux,code = <KEY_UP>;
+               microchip,average-samples = <64>;
+               microchip,average-scaling = <16>;
+               microchip,pre-charge-time-ns = <10000>;
+       };
+
+       right@1 {
+               reg = <1>;
+               linux,code = <KEY_RIGHT>;
+               microchip,average-samples = <64>;
+               microchip,average-scaling = <8>;
+       };
+
+       down@3 {
+               reg = <3>;
+               linux,code = <KEY_DOWN>;
+               microchip,average-samples = <256>;
+               microchip,average-scaling = <16>;
+       };
+};
index 1458c3179a63a2e7ea223814169247b97f77ddc3..496125c6bfb7d28168f1afe203f0ba3c716a9563 100644 (file)
@@ -2,12 +2,14 @@ Allwinner sun4i low res adc attached tablet keys
 ------------------------------------------------
 
 Required properties:
- - compatible: "allwinner,sun4i-a10-lradc-keys"
+ - compatible: should be one of the following string:
+               "allwinner,sun4i-a10-lradc-keys"
+               "allwinner,sun8i-a83t-r-lradc"
  - reg: mmio address range of the chip
  - interrupts: interrupt to which the chip is connected
  - vref-supply: powersupply for the lradc reference voltage
 
-Each key is represented as a sub-node of "allwinner,sun4i-a10-lradc-keys":
+Each key is represented as a sub-node of the compatible mentioned above:
 
 Required subnode-properties:
        - label: Descriptive name of the key.
index 8cf0b4d38a7e374e3c5d3eb3cfbcaf28e03dd377..fc03ea4cf5ab395d530d966ba74ae3c1c08ffc54 100644 (file)
@@ -3,6 +3,7 @@ Device tree bindings for Goodix GT9xx series touchscreen controller
 Required properties:
 
  - compatible          : Should be "goodix,gt1151"
+                                or "goodix,gt5663"
                                 or "goodix,gt5688"
                                 or "goodix,gt911"
                                 or "goodix,gt9110"
@@ -19,6 +20,8 @@ Optional properties:
  - irq-gpios           : GPIO pin used for IRQ. The driver uses the
                          interrupt gpio pin as output to reset the device.
  - reset-gpios         : GPIO pin used for reset
+ - AVDD28-supply       : Analog power supply regulator on AVDD28 pin
+ - VDDIO-supply                : GPIO power supply regulator on VDDIO pin
  - touchscreen-inverted-x
  - touchscreen-inverted-y
  - touchscreen-size-x
diff --git a/Documentation/devicetree/bindings/input/touchscreen/iqs5xx.txt b/Documentation/devicetree/bindings/input/touchscreen/iqs5xx.txt
new file mode 100644 (file)
index 0000000..efa0820
--- /dev/null
@@ -0,0 +1,80 @@
+Azoteq IQS550/572/525 Trackpad/Touchscreen Controller
+
+Required properties:
+
+- compatible                   : Must be equal to one of the following:
+                                 "azoteq,iqs550"
+                                 "azoteq,iqs572"
+                                 "azoteq,iqs525"
+
+- reg                          : I2C slave address for the device.
+
+- interrupts                   : GPIO to which the device's active-high RDY
+                                 output is connected (see [0]).
+
+- reset-gpios                  : GPIO to which the device's active-low NRST
+                                 input is connected (see [1]).
+
+Optional properties:
+
+- touchscreen-min-x            : See [2].
+
+- touchscreen-min-y            : See [2].
+
+- touchscreen-size-x           : See [2]. If this property is omitted, the
+                                 maximum x-coordinate is specified by the
+                                 device's "X Resolution" register.
+
+- touchscreen-size-y           : See [2]. If this property is omitted, the
+                                 maximum y-coordinate is specified by the
+                                 device's "Y Resolution" register.
+
+- touchscreen-max-pressure     : See [2]. Pressure is expressed as the sum of
+                                 the deltas across all channels impacted by a
+                                 touch event. A channel's delta is calculated
+                                 as its count value minus a reference, where
+                                 the count value is inversely proportional to
+                                 the channel's capacitance.
+
+- touchscreen-fuzz-x           : See [2].
+
+- touchscreen-fuzz-y           : See [2].
+
+- touchscreen-fuzz-pressure    : See [2].
+
+- touchscreen-inverted-x       : See [2]. Inversion is applied relative to that
+                                 which may already be specified by the device's
+                                 FLIP_X and FLIP_Y register fields.
+
+- touchscreen-inverted-y       : See [2]. Inversion is applied relative to that
+                                 which may already be specified by the device's
+                                 FLIP_X and FLIP_Y register fields.
+
+- touchscreen-swapped-x-y      : See [2]. Swapping is applied relative to that
+                                 which may already be specified by the device's
+                                 SWITCH_XY_AXIS register field.
+
+[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+[1]: Documentation/devicetree/bindings/gpio/gpio.txt
+[2]: Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
+
+Example:
+
+       &i2c1 {
+               /* ... */
+
+               touchscreen@74 {
+                       compatible = "azoteq,iqs550";
+                       reg = <0x74>;
+                       interrupt-parent = <&gpio>;
+                       interrupts = <17 4>;
+                       reset-gpios = <&gpio 27 1>;
+
+                       touchscreen-size-x = <640>;
+                       touchscreen-size-y = <480>;
+
+                       touchscreen-max-pressure = <16000>;
+               };
+
+               /* ... */
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml b/Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml
new file mode 100644 (file)
index 0000000..bae10e2
--- /dev/null
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2018 Linaro Ltd.
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/interrupt/intel-ixp4xx-interrupt.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Intel IXP4xx XScale Networking Processors Interrupt Controller
+
+maintainers:
+  - Linus Walleij <linus.walleij@linaro.org>
+
+description: |
+  This interrupt controller is found in the Intel IXP4xx processors.
+  Some processors have 32 interrupts, some have up to 64 interrupts.
+  The exact number of interrupts is determined from the compatible
+  string.
+
+  The distinct IXP4xx families with different interrupt controller
+  variations are IXP42x, IXP43x, IXP45x and IXP46x. Those four
+  families were the only ones to reach the developer and consumer
+  market.
+
+properties:
+  compatible:
+    items:
+      - enum:
+        - intel,ixp42x-interrupt
+        - intel,ixp43x-interrupt
+        - intel,ixp45x-interrupt
+        - intel,ixp46x-interrupt
+
+  reg:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 2
+
+required:
+  - compatible
+  - reg
+  - interrupt-controller
+  - '#interrupt-cells'
+
+examples:
+  - |
+    intcon: interrupt-controller@c8003000 {
+        compatible = "intel,ixp43x-interrupt";
+        reg = <0xc8003000 0x100>;
+        interrupt-controller;
+        #interrupt-cells = <2>;
+    };
index c5d589108a9476059beba306b13e7f3f33fa5daf..0e312fea2a5dee12ae04c8328f3b701aab2a0476 100644 (file)
@@ -1,15 +1,18 @@
-+Mediatek MT65xx/MT67xx/MT81xx sysirq
+MediaTek sysirq
 
-Mediatek SOCs sysirq support controllable irq inverter for each GIC SPI
+MediaTek SOCs sysirq support controllable irq inverter for each GIC SPI
 interrupt.
 
 Required properties:
 - compatible: should be
+       "mediatek,mt8516-sysirq", "mediatek,mt6577-sysirq": for MT8516
+       "mediatek,mt8183-sysirq", "mediatek,mt6577-sysirq": for MT8183
        "mediatek,mt8173-sysirq", "mediatek,mt6577-sysirq": for MT8173
        "mediatek,mt8135-sysirq", "mediatek,mt6577-sysirq": for MT8135
        "mediatek,mt8127-sysirq", "mediatek,mt6577-sysirq": for MT8127
        "mediatek,mt7622-sysirq", "mediatek,mt6577-sysirq": for MT7622
        "mediatek,mt7623-sysirq", "mediatek,mt6577-sysirq": for MT7623
+       "mediatek,mt7629-sysirq", "mediatek,mt6577-sysirq": for MT7629
        "mediatek,mt6795-sysirq", "mediatek,mt6577-sysirq": for MT6795
        "mediatek,mt6797-sysirq", "mediatek,mt6577-sysirq": for MT6797
        "mediatek,mt6765-sysirq", "mediatek,mt6577-sysirq": for MT6765
diff --git a/Documentation/devicetree/bindings/leds/backlight/lm3630a-backlight.yaml b/Documentation/devicetree/bindings/leds/backlight/lm3630a-backlight.yaml
new file mode 100644 (file)
index 0000000..4d61fe0
--- /dev/null
@@ -0,0 +1,129 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/backlight/lm3630a-backlight.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI LM3630A High-Efficiency Dual-String White LED
+
+maintainers:
+  - Lee Jones <lee.jones@linaro.org>
+  - Daniel Thompson <daniel.thompson@linaro.org>
+  - Jingoo Han <jingoohan1@gmail.com>
+
+description: |
+  The LM3630A is a current-mode boost converter which supplies the power and
+  controls the current in up to two strings of 10 LEDs per string.
+  https://www.ti.com/product/LM3630A
+
+properties:
+  compatible:
+    const: ti,lm3630a
+
+  reg:
+    maxItems: 1
+
+  ti,linear-mapping-mode:
+    description: |
+      Enable linear mapping mode. If disabled, then it will use exponential
+      mapping mode in which the ramp up/down appears to have a more uniform
+      transition to the human eye.
+    type: boolean
+
+required:
+  - compatible
+  - reg
+
+patternProperties:
+  "^led@[01]$":
+    type: object
+    description: |
+      Properties for a string of connected LEDs.
+
+    properties:
+      reg:
+        description: |
+          The control bank that is used to program the two current sinks. The
+          LM3630A has two control banks (A and B) and are represented as 0 or 1
+          in this property. The two current sinks can be controlled
+          independently with both banks, or bank A can be configured to control
+          both sinks with the led-sources property.
+        maxItems: 1
+        minimum: 0
+        maximum: 1
+
+      label:
+        maxItems: 1
+
+      led-sources:
+        allOf:
+          - minItems: 1
+            maxItems: 2
+            items:
+              minimum: 0
+              maximum: 1
+
+      default-brightness:
+        description: Default brightness level on boot.
+        minimum: 0
+        maximum: 255
+
+      max-brightness:
+        description: Maximum brightness that is allowed during runtime.
+        minimum: 0
+        maximum: 255
+
+    required:
+      - reg
+
+    additionalProperties: false
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        led-controller@38 {
+                compatible = "ti,lm3630a";
+                reg = <0x38>;
+
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                led@0 {
+                        reg = <0>;
+                        led-sources = <0 1>;
+                        label = "lcd-backlight";
+                        default-brightness = <200>;
+                        max-brightness = <255>;
+                };
+        };
+    };
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        led-controller@38 {
+                compatible = "ti,lm3630a";
+                reg = <0x38>;
+
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                led@0 {
+                        reg = <0>;
+                        default-brightness = <150>;
+                        ti,linear-mapping-mode;
+                };
+
+                led@1 {
+                        reg = <1>;
+                        default-brightness = <225>;
+                        ti,linear-mapping-mode;
+                };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/leds/leds-max77650.txt b/Documentation/devicetree/bindings/leds/leds-max77650.txt
new file mode 100644 (file)
index 0000000..3a67115
--- /dev/null
@@ -0,0 +1,57 @@
+LED driver for MAX77650 PMIC from Maxim Integrated.
+
+This module is part of the MAX77650 MFD device. For more details
+see Documentation/devicetree/bindings/mfd/max77650.txt.
+
+The LED controller is represented as a sub-node of the PMIC node on
+the device tree.
+
+This device has three current sinks.
+
+Required properties:
+--------------------
+- compatible:          Must be "maxim,max77650-led"
+- #address-cells:      Must be <1>.
+- #size-cells:         Must be <0>.
+
+Each LED is represented as a sub-node of the LED-controller node. Up to
+three sub-nodes can be defined.
+
+Required properties of the sub-node:
+------------------------------------
+
+- reg:                 Must be <0>, <1> or <2>.
+
+Optional properties of the sub-node:
+------------------------------------
+
+- label:               See Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger: See Documentation/devicetree/bindings/leds/common.txt
+
+For more details, please refer to the generic GPIO DT binding document
+<devicetree/bindings/gpio/gpio.txt>.
+
+Example:
+--------
+
+       leds {
+               compatible = "maxim,max77650-led";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               led@0 {
+                       reg = <0>;
+                       label = "blue:usr0";
+               };
+
+               led@1 {
+                       reg = <1>;
+                       label = "red:usr1";
+                       linux,default-trigger = "heartbeat";
+               };
+
+               led@2 {
+                       reg = <2>;
+                       label = "green:usr2";
+               };
+       };
diff --git a/Documentation/devicetree/bindings/mailbox/marvell,armada-3700-rwtm-mailbox.txt b/Documentation/devicetree/bindings/mailbox/marvell,armada-3700-rwtm-mailbox.txt
new file mode 100644 (file)
index 0000000..282ab81
--- /dev/null
@@ -0,0 +1,16 @@
+* rWTM BIU Mailbox driver for Armada 37xx
+
+Required properties:
+- compatible:  must be "marvell,armada-3700-rwtm-mailbox"
+- reg:         physical base address of the mailbox and length of memory mapped
+               region
+- interrupts:  the IRQ line for the mailbox
+- #mbox-cells: must be 1
+
+Example:
+       rwtm: mailbox@b0000 {
+               compatible = "marvell,armada-3700-rwtm-mailbox";
+               reg = <0xb0000 0x100>;
+               interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+               #mbox-cells = <1>;
+       };
index 9bb5f57e206627408e3ee73d803f22855066be12..94bf7896a688af8b1f97ef378274078ebb35458f 100644 (file)
@@ -15,6 +15,7 @@ Required properties:
                        "atmel,at91sam9g45-ebi"
                        "atmel,at91sam9x5-ebi"
                        "atmel,sama5d3-ebi"
+                       "microchip,sam9x60-ebi"
 
 - reg:                 Contains offset/length value for EBI memory mapping.
                        This property might contain several entries if the EBI
diff --git a/Documentation/devicetree/bindings/memory-controllers/fsl/mmdc.txt b/Documentation/devicetree/bindings/memory-controllers/fsl/mmdc.txt
new file mode 100644 (file)
index 0000000..bcc36c5
--- /dev/null
@@ -0,0 +1,35 @@
+Freescale Multi Mode DDR controller (MMDC)
+
+Required properties :
+- compatible : should be one of following:
+       for i.MX6Q/i.MX6DL:
+       - "fsl,imx6q-mmdc";
+       for i.MX6QP:
+       - "fsl,imx6qp-mmdc", "fsl,imx6q-mmdc";
+       for i.MX6SL:
+       - "fsl,imx6sl-mmdc", "fsl,imx6q-mmdc";
+       for i.MX6SLL:
+       - "fsl,imx6sll-mmdc", "fsl,imx6q-mmdc";
+       for i.MX6SX:
+       - "fsl,imx6sx-mmdc", "fsl,imx6q-mmdc";
+       for i.MX6UL/i.MX6ULL/i.MX6ULZ:
+       - "fsl,imx6ul-mmdc", "fsl,imx6q-mmdc";
+       for i.MX7ULP:
+       - "fsl,imx7ulp-mmdc", "fsl,imx6q-mmdc";
+- reg : address and size of MMDC DDR controller registers
+
+Optional properties :
+- clocks : the clock provided by the SoC to access the MMDC registers
+
+Example :
+       mmdc0: memory-controller@21b0000 { /* MMDC0 */
+               compatible = "fsl,imx6q-mmdc";
+               reg = <0x021b0000 0x4000>;
+               clocks = <&clks IMX6QDL_CLK_MMDC_P0_IPG>;
+       };
+
+       mmdc1: memory-controller@21b4000 { /* MMDC1 */
+               compatible = "fsl,imx6q-mmdc";
+               reg = <0x021b4000 0x4000>;
+               status = "disabled";
+       };
index 3f643ef121ff51ade6dd0205d5d3ec770cebf6f9..5f8880cc757e1d8cea12fadaf798533e173f4dd1 100644 (file)
@@ -7,6 +7,7 @@ Required properties:
    "atmel,sama5d2-hlcdc"
    "atmel,sama5d3-hlcdc"
    "atmel,sama5d4-hlcdc"
+   "microchip,sam9x60-hlcdc"
  - reg: base address and size of the HLCDC device registers.
  - clock-names: the name of the 3 clocks requested by the HLCDC device.
    Should contain "periph_clk", "sys_clk" and "slow_clk".
index 004b0158cf4d79595062e36ddbc3c6c4520de90d..3bf92ad37fa1bb7404b212868d38b979b448cba8 100644 (file)
@@ -19,6 +19,8 @@ And these documents for the required sub-node binding details:
   [4] Clock: ../clock/cirrus,lochnagar.txt
   [5] Pinctrl: ../pinctrl/cirrus,lochnagar.txt
   [6] Regulator: ../regulator/cirrus,lochnagar.txt
+  [7] Sound: ../sound/cirrus,lochnagar.txt
+  [8] Hardware Monitor: ../hwmon/cirrus,lochnagar.txt
 
 Required properties:
 
@@ -41,6 +43,11 @@ Optional sub-nodes:
   - Bindings for the regulator components, see [6]. Only available on
     Lochnagar 2.
 
+  - lochnagar-sc : Binding for the sound card components, see [7].
+                   Only available on Lochnagar 2.
+  - lochnagar-hwmon : Binding for the hardware monitor components, see [8].
+                      Only available on Lochnagar 2.
+
 Optional properties:
 
   - present-gpios : Host present line, indicating the presence of a
@@ -65,4 +72,14 @@ lochnagar: lochnagar@22 {
                compatible = "cirrus,lochnagar-pinctrl";
                ...
        };
+
+       lochnagar-sc {
+               compatible = "cirrus,lochnagar2-soundcard";
+               ...
+       };
+
+       lochnagar-hwmon {
+               compatible = "cirrus,lochnagar2-hwmon";
+               ...
+       };
 };
index 9c16d51cc15b913ce900c622741eb51904224686..5a642a51d58e6fd0da2cd4d3d76ad1a8bef409af 100644 (file)
@@ -4,7 +4,8 @@ Required properties:
 -------------------
 - compatible: Must be one of
                "maxim,max77620"
-               "maxim,max20024".
+               "maxim,max20024"
+               "maxim,max77663"
 - reg: I2C device address.
 
 Optional properties:
@@ -17,6 +18,11 @@ Optional properties:
                        IRQ numbers for different interrupt source of MAX77620
                        are defined at dt-bindings/mfd/max77620.h.
 
+- system-power-controller: Indicates that this PMIC is controlling the
+                          system power, see [1] for more details.
+
+[1] Documentation/devicetree/bindings/power/power-controller.txt
+
 Optional subnodes and their properties:
 =======================================
 
@@ -105,6 +111,7 @@ Optional properties:
 Here supported time periods by device in microseconds are as follows:
 MAX77620 supports 40, 80, 160, 320, 640, 1280, 2560 and 5120 microseconds.
 MAX20024 supports 20, 40, 80, 160, 320, 640, 1280 and 2540 microseconds.
+MAX77663 supports 20, 40, 80, 160, 320, 640, 1280 and 2540 microseconds.
 
 -maxim,power-ok-control: configure map power ok bit
                        1: Enables POK(Power OK) to control nRST_IO and GPIO1
diff --git a/Documentation/devicetree/bindings/mfd/max77650.txt b/Documentation/devicetree/bindings/mfd/max77650.txt
new file mode 100644 (file)
index 0000000..b529d8d
--- /dev/null
@@ -0,0 +1,46 @@
+MAX77650 ultra low-power PMIC from Maxim Integrated.
+
+Required properties:
+-------------------
+- compatible:          Must be "maxim,max77650"
+- reg:                 I2C device address.
+- interrupts:          The interrupt on the parent the controller is
+                       connected to.
+- interrupt-controller: Marks the device node as an interrupt controller.
+- #interrupt-cells:    Must be <2>.
+
+- gpio-controller:     Marks the device node as a gpio controller.
+- #gpio-cells:         Must be <2>. The first cell is the pin number and
+                       the second cell is used to specify the gpio active
+                       state.
+
+Optional properties:
+--------------------
+gpio-line-names:       Single string containing the name of the GPIO line.
+
+The GPIO-controller module is represented as part of the top-level PMIC
+node. The device exposes a single GPIO line.
+
+For device-tree bindings of other sub-modules (regulator, power supply,
+LEDs and onkey) refer to the binding documents under the respective
+sub-system directories.
+
+For more details on GPIO bindings, please refer to the generic GPIO DT
+binding document <devicetree/bindings/gpio/gpio.txt>.
+
+Example:
+--------
+
+       pmic@48 {
+               compatible = "maxim,max77650";
+               reg = <0x48>;
+
+               interrupt-controller;
+               interrupt-parent = <&gpio2>;
+               #interrupt-cells = <2>;
+               interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+               gpio-line-names = "max77650-charger";
+       };
diff --git a/Documentation/devicetree/bindings/mfd/stmfx.txt b/Documentation/devicetree/bindings/mfd/stmfx.txt
new file mode 100644 (file)
index 0000000..f0c2f7f
--- /dev/null
@@ -0,0 +1,28 @@
+STMicroelectonics Multi-Function eXpander (STMFX) Core bindings
+
+ST Multi-Function eXpander (STMFX) is a slave controller using I2C for
+communication with the main MCU. Its main features are GPIO expansion, main
+MCU IDD measurement (IDD is the amount of current that flows through VDD) and
+resistive touchscreen controller.
+
+Required properties:
+- compatible: should be "st,stmfx-0300".
+- reg: I2C slave address of the device.
+- interrupts: interrupt specifier triggered by MFX_IRQ_OUT signal.
+  Please refer to ../interrupt-controller/interrupt.txt
+
+Optional properties:
+- drive-open-drain: configure MFX_IRQ_OUT as open drain.
+- vdd-supply: phandle of the regulator supplying STMFX.
+
+Example:
+
+       stmfx: stmfx@42 {
+               compatible = "st,stmfx-0300";
+               reg = <0x42>;
+               interrupts = <8 IRQ_TYPE_EDGE_RISING>;
+               interrupt-parent = <&gpioi>;
+               vdd-supply = <&v3v3>;
+       };
+
+Please refer to ../pinctrl/pinctrl-stmfx.txt for STMFX GPIO expander function bindings.
index 980394d701a7275f5a26738ec13d90c349998d3b..86ca786d54fc1a4ce28b83066b886d8c7d5167a2 100644 (file)
@@ -104,8 +104,8 @@ lm3632@11 {
        regulators {
                compatible = "ti,lm363x-regulator";
 
-               ti,lcm-en1-gpio = <&pioC 0 GPIO_ACTIVE_HIGH>; /* PC0 */
-               ti,lcm-en2-gpio = <&pioC 1 GPIO_ACTIVE_HIGH>; /* PC1 */
+               enable-gpios = <&pioC 0 GPIO_ACTIVE_HIGH>,
+                              <&pioC 1 GPIO_ACTIVE_HIGH>;
 
                vboost {
                        regulator-name = "lcd_boost";
diff --git a/Documentation/devicetree/bindings/misc/intel,ixp4xx-queue-manager.yaml b/Documentation/devicetree/bindings/misc/intel,ixp4xx-queue-manager.yaml
new file mode 100644 (file)
index 0000000..d2313b1
--- /dev/null
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 Linaro Ltd.
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/misc/intel-ixp4xx-ahb-queue-manager.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Intel IXP4xx AHB Queue Manager
+
+maintainers:
+  - Linus Walleij <linus.walleij@linaro.org>
+
+description: |
+  The IXP4xx AHB Queue Manager maintains queues as circular buffers in
+  an 8KB embedded SRAM along with hardware pointers. It is used by both
+  the XScale processor and the NPEs (Network Processing Units) in the
+  IXP4xx for accelerating queues, especially for networking. Clients pick
+  queues from the queue manager with foo-queue = <&qmgr N> where the
+  &qmgr is a phandle to the queue manager and N is the queue resource
+  number. The queue resources available and their specific purpose
+  on a certain IXP4xx system will vary.
+
+properties:
+  compatible:
+    items:
+      - const: intel,ixp4xx-ahb-queue-manager
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    items:
+      - description: Interrupt for queues 0-31
+      - description: Interrupt for queues 32-63
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    qmgr: queue-manager@60000000 {
+         compatible = "intel,ixp4xx-ahb-queue-manager";
+         reg = <0x60000000 0x4000>;
+         interrupts = <3 IRQ_TYPE_LEVEL_HIGH>, <4 IRQ_TYPE_LEVEL_HIGH>;
+    };
index 07242d1417735c56576bc59742284957259a4660..36c4bea675d5a6b0753e478b746a0894a67ea7bf 100644 (file)
@@ -13,6 +13,8 @@ Required Properties:
 
 * compatible: should be one of the following.
   - "hisilicon,hi3660-dw-mshc": for controllers with hi3660 specific extensions.
+  - "hisilicon,hi3670-dw-mshc", "hisilicon,hi3660-dw-mshc": for controllers
+     with hi3670 specific extensions.
   - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific extensions.
   - "hisilicon,hi6220-dw-mshc": for controllers with hi6220 specific extensions.
 
diff --git a/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml b/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml
new file mode 100644 (file)
index 0000000..fbd4da3
--- /dev/null
@@ -0,0 +1,97 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/allwinner,sun4i-a10-nand.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A10 NAND Controller Device Tree Bindings
+
+allOf:
+  - $ref: "nand-controller.yaml"
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  "#address-cells": true
+  "#size-cells": true
+
+  compatible:
+    enum:
+      - allwinner,sun4i-a10-nand
+      - allwinner,sun8i-a23-nand-controller
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Bus Clock
+      - description: Module Clock
+
+  clock-names:
+    items:
+      - const: ahb
+      - const: mod
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    const: ahb
+
+  dmas:
+    maxItems: 1
+
+  dma-names:
+    const: rxtx
+
+  pinctrl-names: true
+
+patternProperties:
+  "^pinctrl-[0-9]+$": true
+
+  "^nand@[a-f0-9]+$":
+    properties:
+      reg:
+        maxItems: 1
+        minimum: 0
+        maximum: 7
+
+      nand-ecc-mode: true
+
+      nand-ecc-algo:
+        const: bch
+
+      nand-ecc-step-size:
+        enum: [ 512, 1024 ]
+
+      nand-ecc-strength:
+        maximum: 80
+
+      allwinner,rb:
+        description:
+          Contains the native Ready/Busy IDs.
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32-array
+          - minItems: 1
+            maxItems: 2
+            items:
+              minimum: 0
+              maximum: 1
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+...
index 9bb66e476672b3fa66b707f8f960d4a53ff2eb1d..68b51dc588163fce2e06c33a9190673e6dc116bc 100644 (file)
@@ -14,6 +14,7 @@ Required properties:
        "atmel,at91sam9261-nand-controller"
        "atmel,at91sam9g45-nand-controller"
        "atmel,sama5d3-nand-controller"
+       "microchip,sam9x60-nand-controller"
 - ranges: empty ranges property to forward EBI ranges definitions.
 - #address-cells: should be set to 2.
 - #size-cells: should be set to 1.
index f33da87827410fffe9d799fcc7a780b73c010fb0..b14b6751c2f3d804cd3dfddab2923423b0012402 100644 (file)
@@ -7,34 +7,48 @@ Required properties:
       "socionext,uniphier-denali-nand-v5b"  - for Socionext UniPhier (v5b)
   - reg : should contain registers location and length for data and reg.
   - reg-names: Should contain the reg names "nand_data" and "denali_reg"
+  - #address-cells: should be 1. The cell encodes the chip select connection.
+  - #size-cells : should be 0.
   - interrupts : The interrupt number.
   - clocks: should contain phandle of the controller core clock, the bus
     interface clock, and the ECC circuit clock.
   - clock-names: should contain "nand", "nand_x", "ecc"
 
-Optional properties:
-  - nand-ecc-step-size: see nand.txt for details.  If present, the value must be
-      512        for "altr,socfpga-denali-nand"
-      1024       for "socionext,uniphier-denali-nand-v5a"
-      1024       for "socionext,uniphier-denali-nand-v5b"
-  - nand-ecc-strength: see nand.txt for details.  Valid values are:
-      8, 15      for "altr,socfpga-denali-nand"
-      8, 16, 24  for "socionext,uniphier-denali-nand-v5a"
-      8, 16      for "socionext,uniphier-denali-nand-v5b"
-  - nand-ecc-maximize: see nand.txt for details
-
-The device tree may optionally contain sub-nodes describing partitions of the
+Sub-nodes:
+  Sub-nodes represent available NAND chips.
+
+  Required properties:
+    - reg: should contain the bank ID of the controller to which each chip
+      select is connected.
+
+  Optional properties:
+    - nand-ecc-step-size: see nand.txt for details.
+      If present, the value must be
+        512        for "altr,socfpga-denali-nand"
+        1024       for "socionext,uniphier-denali-nand-v5a"
+        1024       for "socionext,uniphier-denali-nand-v5b"
+    - nand-ecc-strength: see nand.txt for details. Valid values are:
+        8, 15      for "altr,socfpga-denali-nand"
+        8, 16, 24  for "socionext,uniphier-denali-nand-v5a"
+        8, 16      for "socionext,uniphier-denali-nand-v5b"
+    - nand-ecc-maximize: see nand.txt for details
+
+The chip nodes may optionally contain sub-nodes describing partitions of the
 address space. See partition.txt for more detail.
 
 Examples:
 
 nand: nand@ff900000 {
        #address-cells = <1>;
-       #size-cells = <1>;
+       #size-cells = <0>;
        compatible = "altr,socfpga-denali-nand";
        reg = <0xff900000 0x20>, <0xffb80000 0x1000>;
        reg-names = "nand_data", "denali_reg";
        clocks = <&nand_clk>, <&nand_x_clk>, <&nand_ecc_clk>;
        clock-names = "nand", "nand_x", "ecc";
        interrupts = <0 144 4>;
+
+       nand@0 {
+               reg = <0>;
+       }
 };
index 29ea5853ca9147bbc7f8277e33925193792b91c9..c02259353327e03c2518164fd492b539fbcc5425 100644 (file)
@@ -1,4 +1,4 @@
-* Ingenic JZ4780 NAND/BCH
+* Ingenic JZ4780 NAND/ECC
 
 This file documents the device tree bindings for NAND flash devices on the
 JZ4780. NAND devices are connected to the NEMC controller (described in
@@ -6,15 +6,18 @@ memory-controllers/ingenic,jz4780-nemc.txt), and thus NAND device nodes must
 be children of the NEMC node.
 
 Required NAND controller device properties:
-- compatible: Should be set to "ingenic,jz4780-nand".
+- compatible: Should be one of:
+  * ingenic,jz4740-nand
+  * ingenic,jz4725b-nand
+  * ingenic,jz4780-nand
 - reg: For each bank with a NAND chip attached, should specify a bank number,
   an offset of 0 and a size of 0x1000000 (i.e. the whole NEMC bank).
 
 Optional NAND controller device properties:
-- ingenic,bch-controller: To make use of the hardware BCH controller, this
-  property must contain a phandle for the BCH controller node. The required
+- ecc-engine: To make use of the hardware ECC controller, this
+  property must contain a phandle for the ECC controller node. The required
   properties for this node are described below. If this is not specified,
-  software BCH will be used instead.
+  software ECC will be used instead.
 
 Optional children nodes:
 - Individual NAND chips are children of the NAND controller node.
@@ -45,7 +48,7 @@ nemc: nemc@13410000 {
                #address-cells = <1>;
                #size-cells = <0>;
 
-               ingenic,bch-controller = <&bch>;
+               ecc-engine = <&bch>;
 
                nand@1 {
                        reg = <1>;
@@ -67,14 +70,17 @@ nemc: nemc@13410000 {
        };
 };
 
-The BCH controller is a separate SoC component used for error correction on
+The ECC controller is a separate SoC component used for error correction on
 NAND devices. The following is a description of the device properties for a
-BCH controller.
-
-Required BCH properties:
-- compatible: Should be set to "ingenic,jz4780-bch".
-- reg: Should specify the BCH controller registers location and length.
-- clocks: Clock for the BCH controller.
+ECC controller.
+
+Required ECC properties:
+- compatible: Should be one of:
+  * ingenic,jz4740-ecc
+  * ingenic,jz4725b-bch
+  * ingenic,jz4780-bch
+- reg: Should specify the ECC controller registers location and length.
+- clocks: Clock for the ECC controller.
 
 Example:
 
index 7df0dcaccb7d9691e00f741ece0b7fdf547fb6a4..c69f4f065d239fd29f5752da5ebf9cbf2f0a1207 100644 (file)
@@ -96,3 +96,19 @@ An example using SRAM:
                bank-width = <2>;
        };
 
+An example using gpio-addrs
+
+       flash@20000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cfi-flash", "jedec-flash";
+               reg = <0x20000000 0x02000000>;
+               ranges = <0 0x00000000 0x02000000
+                         1 0x02000000 0x02000000>;
+               bank-width = <2>;
+               addr-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+               partition@0 {
+                       label = "test-part1";
+                       reg = <0 0x04000000>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/mtd/nand-controller.yaml b/Documentation/devicetree/bindings/mtd/nand-controller.yaml
new file mode 100644 (file)
index 0000000..199ba5a
--- /dev/null
@@ -0,0 +1,143 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/nand-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NAND Chip and NAND Controller Generic Binding
+
+maintainers:
+  - Miquel Raynal <miquel.raynal@bootlin.com>
+  - Richard Weinberger <richard@nod.at>
+
+description: |
+  The NAND controller should be represented with its own DT node, and
+  all NAND chips attached to this controller should be defined as
+  children nodes of the NAND controller. This representation should be
+  enforced even for simple controllers supporting only one chip.
+
+  The ECC strength and ECC step size properties define the user
+  desires in terms of correction capability of a controller. Together,
+  they request the ECC engine to correct {strength} bit errors per
+  {size} bytes.
+
+  The interpretation of these parameters is implementation-defined, so
+  not all implementations must support all possible
+  combinations. However, implementations are encouraged to further
+  specify the value(s) they support.
+
+properties:
+  $nodename:
+    pattern: "^nand-controller(@.*)?"
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  ranges: true
+
+patternProperties:
+  "^nand@[a-f0-9]$":
+    properties:
+      reg:
+        description:
+          Contains the native Ready/Busy IDs.
+
+      nand-ecc-mode:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/string
+          - enum: [ none, soft, hw, hw_syndrome, hw_oob_first, on-die ]
+        description:
+          Desired ECC engine, either hardware (most of the time
+          embedded in the NAND controller) or software correction
+          (Linux will handle the calculations). soft_bch is deprecated
+          and should be replaced by soft and nand-ecc-algo.
+
+      nand-ecc-algo:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/string
+          - enum: [ hamming, bch, rs ]
+        description:
+          Desired ECC algorithm.
+
+      nand-bus-width:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32
+          - enum: [ 8, 16 ]
+          - default: 8
+        description:
+          Bus width to the NAND chip
+
+      nand-on-flash-bbt:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          With this property, the OS will search the device for a Bad
+          Block Table (BBT). If not found, it will create one, reserve
+          a few blocks at the end of the device to store it and update
+          it as the device ages. Otherwise, the out-of-band area of a
+          few pages of all the blocks will be scanned at boot time to
+          find Bad Block Markers (BBM). These markers will help to
+          build a volatile BBT in RAM.
+
+      nand-ecc-strength:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32
+          - minimum: 1
+        description:
+          Maximum number of bits that can be corrected per ECC step.
+
+      nand-ecc-step-size:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32
+          - minimum: 1
+        description:
+          Number of data bytes covered by a single ECC step.
+
+      nand-ecc-maximize:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          Whether or not the ECC strength should be maximized. The
+          maximum ECC strength is both controller and chip
+          dependent. The ECC engine has to select the ECC config
+          providing the best strength and taking the OOB area size
+          constraint into account. This is particularly useful when
+          only the in-band area is used by the upper layers, and you
+          want to make your NAND as reliable as possible.
+
+      nand-is-boot-medium:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          Whether or not the NAND chip is a boot medium. Drivers might
+          use this information to select ECC algorithms supported by
+          the boot ROM or similar restrictions.
+
+      nand-rb:
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+        description:
+          Contains the native Ready/Busy IDs.
+
+    required:
+      - reg
+
+required:
+  - "#address-cells"
+  - "#size-cells"
+
+examples:
+  - |
+    nand-controller {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      /* controller specific properties */
+
+      nand@0 {
+        reg = <0>;
+        nand-ecc-mode = "soft";
+        nand-ecc-algo = "bch";
+
+        /* controller specific properties */
+      };
+    };
diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt
deleted file mode 100644 (file)
index e949c77..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-* NAND chip and NAND controller generic binding
-
-NAND controller/NAND chip representation:
-
-The NAND controller should be represented with its own DT node, and all
-NAND chips attached to this controller should be defined as children nodes
-of the NAND controller. This representation should be enforced even for
-simple controllers supporting only one chip.
-
-Mandatory NAND controller properties:
-- #address-cells: depends on your controller. Should at least be 1 to
-                 encode the CS line id.
-- #size-cells: depends on your controller. Put zero unless you need a
-              mapping between CS lines and dedicated memory regions
-
-Optional NAND controller properties
-- ranges: only needed if you need to define a mapping between CS lines and
-         memory regions
-
-Optional NAND chip properties:
-
-- nand-ecc-mode : String, operation mode of the NAND ecc mode.
-                 Supported values are: "none", "soft", "hw", "hw_syndrome",
-                 "hw_oob_first", "on-die".
-                 Deprecated values:
-                 "soft_bch": use "soft" and nand-ecc-algo instead
-- nand-ecc-algo: string, algorithm of NAND ECC.
-                Valid values are: "hamming", "bch", "rs".
-- nand-bus-width : 8 or 16 bus width if not present 8
-- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
-
-- nand-ecc-strength: integer representing the number of bits to correct
-                    per ECC step.
-
-- nand-ecc-step-size: integer representing the number of data bytes
-                     that are covered by a single ECC step.
-
-- nand-ecc-maximize: boolean used to specify that you want to maximize ECC
-                    strength. The maximum ECC strength is both controller and
-                    chip dependent. The controller side has to select the ECC
-                    config providing the best strength and taking the OOB area
-                    size constraint into account.
-                    This is particularly useful when only the in-band area is
-                    used by the upper layers, and you want to make your NAND
-                    as reliable as possible.
-- nand-is-boot-medium: Whether the NAND chip is a boot medium. Drivers might use
-                      this information to select ECC algorithms supported by
-                      the boot ROM or similar restrictions.
-
-- nand-rb: shall contain the native Ready/Busy ids.
-
-The ECC strength and ECC step size properties define the correction capability
-of a controller. Together, they say a controller can correct "{strength} bit
-errors per {size} bytes".
-
-The interpretation of these parameters is implementation-defined, so not all
-implementations must support all possible combinations. However, implementations
-are encouraged to further specify the value(s) they support.
-
-Example:
-
-       nand-controller {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               /* controller specific properties */
-
-               nand@0 {
-                       reg = <0>;
-                       nand-ecc-mode = "soft";
-                       nand-ecc-algo = "bch";
-
-                       /* controller specific properties */
-               };
-       };
diff --git a/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.txt b/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.txt
new file mode 100644 (file)
index 0000000..d5c5616
--- /dev/null
@@ -0,0 +1,17 @@
+ARM AFS - ARM Firmware Suite Partitions
+=======================================
+
+The ARM Firmware Suite is a flash partitioning system found on the
+ARM reference designs: Integrator AP, Integrator CP, Versatile AB,
+Versatile PB, the RealView family, Versatile Express and Juno.
+
+Required properties:
+- compatible : (required) must be "arm,arm-firmware-suite"
+
+Example:
+
+flash@0 {
+       partitions {
+               compatible = "arm,arm-firmware-suite";
+       };
+};
diff --git a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm963xx-cfe-nor-partitions.txt b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm963xx-cfe-nor-partitions.txt
new file mode 100644 (file)
index 0000000..9f630e9
--- /dev/null
@@ -0,0 +1,24 @@
+Broadcom BCM963XX CFE Loader NOR Flash Partitions
+=================================================
+
+Most Broadcom BCM63XX SoC based devices follow the Broadcom reference layout for
+NOR. The first erase block used for the CFE bootloader, the last for an
+NVRAM partition, and the remainder in-between for one to two firmware partitions
+at fixed offsets. A valid firmware partition is identified by the ImageTag
+header found at beginning of the second erase block, containing the rootfs and
+kernel offsets and sizes within the firmware partition.
+
+Required properties:
+- compatible : must be "brcm,bcm963xx-cfe-nor-partitions"
+
+Example:
+
+flash@1fc00000 {
+       compatible = "cfi-flash";
+       reg = <0x1fc00000 0x400000>;
+       bank-width = <2>;
+
+       partitions {
+               compatible = "brcm,bcm963xx-cfe-nor-partitions";
+       };
+};
diff --git a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm963xx-imagetag.txt b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm963xx-imagetag.txt
new file mode 100644 (file)
index 0000000..f8b7418
--- /dev/null
@@ -0,0 +1,45 @@
+Broadcom BCM963XX ImageTag Partition Container
+==============================================
+
+Some Broadcom BCM63XX SoC based devices contain additional, non discoverable
+partitions or non standard bootloader partition sizes. For these a mixed layout
+needs to be used with an explicit firmware partition.
+
+The BCM963XX ImageTag is a simple firmware header describing the offsets and
+sizes of the rootfs and kernel parts contained in the firmware.
+
+Required properties:
+- compatible : must be "brcm,bcm963xx-imagetag"
+
+Example:
+
+flash@1e000000 {
+       compatible = "cfi-flash";
+       reg = <0x1e000000 0x2000000>;
+       bank-width = <2>;
+
+       partitions {
+               compatible = "fixed-partitions";
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               cfe@0 {
+                       reg = <0x0 0x10000>;
+                       read-only;
+               };
+
+               firmware@10000 {
+                       reg = <0x10000 0x7d0000>;
+                       compatible = "brcm,bcm963xx-imagetag";
+               };
+
+               caldata@7e0000 {
+                       reg = <0x7e0000 0x10000>;
+                       read-only;
+               };
+
+               nvram@7f0000 {
+                       reg = <0x7f0000 0x10000>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt
deleted file mode 100644 (file)
index dcd5a5d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-Allwinner NAND Flash Controller (NFC)
-
-Required properties:
-- compatible : "allwinner,sun4i-a10-nand".
-- reg : shall contain registers location and length for data and reg.
-- interrupts : shall define the nand controller interrupt.
-- #address-cells: shall be set to 1. Encode the nand CS.
-- #size-cells : shall be set to 0.
-- clocks : shall reference nand controller clocks.
-- clock-names : nand controller internal clock names. Shall contain :
-    * "ahb" : AHB gating clock
-    * "mod" : nand controller clock
-
-Optional properties:
-- dmas : shall reference DMA channel associated to the NAND controller.
-- dma-names : shall be "rxtx".
-
-Optional children nodes:
-Children nodes represent the available nand chips.
-
-Optional properties:
-- reset : phandle + reset specifier pair
-- reset-names : must contain "ahb"
-- allwinner,rb : shall contain the native Ready/Busy ids.
-- nand-ecc-mode : one of the supported ECC modes ("hw", "soft", "soft_bch" or
-                 "none")
-
-see Documentation/devicetree/bindings/mtd/nand.txt for generic bindings.
-
-
-Examples:
-nfc: nand@1c03000 {
-       compatible = "allwinner,sun4i-a10-nand";
-       reg = <0x01c03000 0x1000>;
-       interrupts = <0 37 1>;
-       clocks = <&ahb_gates 13>, <&nand_clk>;
-       clock-names = "ahb", "mod";
-       #address-cells = <1>;
-       #size-cells = <0>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
-
-       nand@0 {
-               reg = <0>;
-               allwinner,rb = <0>;
-               nand-ecc-mode = "soft_bch";
-       };
-};
index 3a65aabc76a247eb420746b542b31515fdb96725..6262c2f293b056cb2f8fc14e317f188a018f9dfe 100644 (file)
@@ -139,9 +139,9 @@ Optional properties:
                        sub-module attached to this interface.
 
 The MAC address will be determined using the optional properties defined in
-ethernet.txt, as provided by the of_get_mac_address API and only if efuse-mac
-is set to 0. If any of the optional MAC address properties are not present,
-then the driver will use random MAC address.
+ethernet.txt and only if efuse-mac is set to 0. If all of the optional MAC
+address properties are not present, then the driver will use a random MAC
+address.
 
 Example binding:
 
index 74665502f4cfd60a0a49692e31a2ad54e48c2682..7e675dafc256ee716df4de317b077f45194a96d9 100644 (file)
@@ -16,8 +16,8 @@ Optional properties:
 - ieee80211-freq-limit: See ieee80211.txt
 - mediatek,mtd-eeprom: Specify a MTD partition + offset containing EEPROM data
 
-The driver is using of_get_mac_address API, so the MAC address can be as well
-be set with corresponding optional properties defined in net/ethernet.txt.
+The MAC address can as well be set with corresponding optional properties
+defined in net/ethernet.txt.
 
 Optional nodes:
 - led: Properties for a connected LED
index c124f9bc11f3a46579887ec06fd270af372d577b..5561a1c060d0dff2396117af1408ffbb2a3a4530 100644 (file)
@@ -4,8 +4,11 @@ Required properties:
 - compatible:
        "snps,dw-pcie" for RC mode;
        "snps,dw-pcie-ep" for EP mode;
-- reg: Should contain the configuration address space.
-- reg-names: Must be "config" for the PCIe configuration space.
+- reg: For designware cores version < 4.80 contains the configuration
+       address space. For designware core version >= 4.80, contains
+       the configuration and ATU address space
+- reg-names: Must be "config" for the PCIe configuration space and "atu" for
+            the ATU address space.
     (The old way of getting the configuration address space from "ranges"
     is deprecated and should be avoided.)
 - num-lanes: number of lanes to use
index 2030ee0dc4f91215a9d15949acace949e9b94406..47202a2938f2efc9ae0b975960b6ebdfc45e1404 100644 (file)
@@ -11,16 +11,24 @@ described here as well as properties that are not applicable.
 
 Required Properties:-
 
-compatibility: "ti,keystone-pcie"
-reg:   index 1 is the base address and length of DW application registers.
-       index 2 is the base address and length of PCI device ID register.
+compatibility: Should be "ti,keystone-pcie" for RC on Keystone2 SoC
+              Should be "ti,am654-pcie-rc" for RC on AM654x SoC
+reg: Three register ranges as listed in the reg-names property
+reg-names: "dbics" for the DesignWare PCIe registers, "app" for the
+          TI specific application registers, "config" for the
+          configuration space address
 
 pcie_msi_intc : Interrupt controller device node for MSI IRQ chip
        interrupt-cells: should be set to 1
        interrupts: GIC interrupt lines connected to PCI MSI interrupt lines
+       (required if the compatible is "ti,keystone-pcie")
+msi-map: As specified in Documentation/devicetree/bindings/pci/pci-msi.txt
+        (required if the compatible is "ti,am654-pcie-rc".
 
 ti,syscon-pcie-id : phandle to the device control module required to set device
                    id and vendor id.
+ti,syscon-pcie-mode : phandle to the device control module required to configure
+                     PCI in either RC mode or EP mode.
 
  Example:
        pcie_msi_intc: msi-interrupt-controller {
@@ -61,3 +69,47 @@ Optional properties:-
 DesignWare DT Properties not applicable for Keystone PCI
 
 1. pcie_bus clock-names not used.  Instead, a phandle to phys is used.
+
+AM654 PCIe Endpoint
+===================
+
+Required Properties:-
+
+compatibility: Should be "ti,am654-pcie-ep" for EP on AM654x SoC
+reg: Four register ranges as listed in the reg-names property
+reg-names: "dbics" for the DesignWare PCIe registers, "app" for the
+          TI specific application registers, "atu" for the
+          Address Translation Unit configuration registers and
+          "addr_space" used to map remote RC address space
+num-ib-windows: As specified in
+               Documentation/devicetree/bindings/pci/designware-pcie.txt
+num-ob-windows: As specified in
+               Documentation/devicetree/bindings/pci/designware-pcie.txt
+num-lanes: As specified in
+          Documentation/devicetree/bindings/pci/designware-pcie.txt
+power-domains: As documented by the generic PM domain bindings in
+              Documentation/devicetree/bindings/power/power_domain.txt.
+ti,syscon-pcie-mode: phandle to the device control module required to configure
+                     PCI in either RC mode or EP mode.
+
+Optional properties:-
+
+phys: list of PHY specifiers (used by generic PHY framework)
+phy-names: must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the
+               number of lanes as specified in *num-lanes* property.
+("phys" and "phy-names" DT bindings are specified in
+Documentation/devicetree/bindings/phy/phy-bindings.txt)
+interrupts: platform interrupt for error interrupts.
+
+pcie-ep {
+       compatible = "ti,am654-pcie-ep";
+       reg =  <0x5500000 0x1000>, <0x5501000 0x1000>,
+              <0x10000000 0x8000000>, <0x5506000 0x1000>;
+       reg-names = "app", "dbics", "addr_space", "atu";
+       power-domains = <&k3_pds 120>;
+       ti,syscon-pcie-mode = <&pcie0_mode>;
+       num-lanes = <1>;
+       num-ib-windows = <16>;
+       num-ob-windows = <16>;
+       interrupts = <GIC_SPI 340 IRQ_TYPE_EDGE_RISING>;
+};
index c77981c5dd18f6edff3affcb40cd88720633b5db..92c01db610df21f7efe0d6cf93659e259069254c 100644 (file)
@@ -24,3 +24,53 @@ driver implementation may support the following properties:
    unsupported link speed, for instance, trying to do training for
    unsupported link speed, etc.  Must be '4' for gen4, '3' for gen3, '2'
    for gen2, and '1' for gen1. Any other values are invalid.
+
+PCI-PCI Bridge properties
+-------------------------
+
+PCIe root ports and switch ports may be described explicitly in the device
+tree, as children of the host bridge node. Even though those devices are
+discoverable by probing, it might be necessary to describe properties that
+aren't provided by standard PCIe capabilities.
+
+Required properties:
+
+- reg:
+   Identifies the PCI-PCI bridge. As defined in the IEEE Std 1275-1994
+   document, it is a five-cell address encoded as (phys.hi phys.mid
+   phys.lo size.hi size.lo). phys.hi should contain the device's BDF as
+   0b00000000 bbbbbbbb dddddfff 00000000. The other cells should be zero.
+
+   The bus number is defined by firmware, through the standard bridge
+   configuration mechanism. If this port is a switch port, then firmware
+   allocates the bus number and writes it into the Secondary Bus Number
+   register of the bridge directly above this port. Otherwise, the bus
+   number of a root port is the first number in the bus-range property,
+   defaulting to zero.
+
+   If firmware leaves the ARI Forwarding Enable bit set in the bridge
+   above this port, then phys.hi contains the 8-bit function number as
+   0b00000000 bbbbbbbb ffffffff 00000000. Note that the PCIe specification
+   recommends that firmware only leaves ARI enabled when it knows that the
+   OS is ARI-aware.
+
+Optional properties:
+
+- external-facing:
+   When present, the port is external-facing. All bridges and endpoints
+   downstream of this port are external to the machine. The OS can, for
+   example, use this information to identify devices that cannot be
+   trusted with relaxed DMA protection, as users could easily attach
+   malicious devices to this port.
+
+Example:
+
+pcie@10000000 {
+       compatible = "pci-host-ecam-generic";
+       ...
+       pcie@0008 {
+               /* Root port 00:01.0 is external-facing */
+               reg = <0x00000800 0 0 0 0>;
+               external-facing;
+       };
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-stmfx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-stmfx.txt
new file mode 100644 (file)
index 0000000..c1b4c18
--- /dev/null
@@ -0,0 +1,116 @@
+STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander bindings
+
+ST Multi-Function eXpander (STMFX) offers up to 24 GPIOs expansion.
+Please refer to ../mfd/stmfx.txt for STMFX Core bindings.
+
+Required properties:
+- compatible: should be "st,stmfx-0300-pinctrl".
+- #gpio-cells: should be <2>, the first cell is the GPIO number and the second
+  cell is the gpio flags in accordance with <dt-bindings/gpio/gpio.h>.
+- gpio-controller: marks the device as a GPIO controller.
+- #interrupt-cells: should be <2>, the first cell is the GPIO number and the
+  second cell is the interrupt flags in accordance with
+  <dt-bindings/interrupt-controller/irq.h>.
+- interrupt-controller: marks the device as an interrupt controller.
+- gpio-ranges: specifies the mapping between gpio controller and pin
+  controller pins. Check "Concerning gpio-ranges property" below.
+Please refer to ../gpio/gpio.txt.
+
+Please refer to pinctrl-bindings.txt for pin configuration.
+
+Required properties for pin configuration sub-nodes:
+- pins: list of pins to which the configuration applies.
+
+Optional properties for pin configuration sub-nodes (pinconf-generic ones):
+- bias-disable: disable any bias on the pin.
+- bias-pull-up: the pin will be pulled up.
+- bias-pull-pin-default: use the pin-default pull state.
+- bias-pull-down: the pin will be pulled down.
+- drive-open-drain: the pin will be driven with open drain.
+- drive-push-pull: the pin will be driven actively high and low.
+- output-high: the pin will be configured as an output driving high level.
+- output-low: the pin will be configured as an output driving low level.
+
+Note that STMFX pins[15:0] are called "gpio[15:0]", and STMFX pins[23:16] are
+called "agpio[7:0]". Example, to refer to pin 18 of STMFX, use "agpio2".
+
+Concerning gpio-ranges property:
+- if all STMFX pins[24:0] are available (no other STMFX function in use), you
+  should use gpio-ranges = <&stmfx_pinctrl 0 0 24>;
+- if agpio[3:0] are not available (STMFX Touchscreen function in use), you
+  should use gpio-ranges = <&stmfx_pinctrl 0 0 16>, <&stmfx_pinctrl 20 20 4>;
+- if agpio[7:4] are not available (STMFX IDD function in use), you
+  should use gpio-ranges = <&stmfx_pinctrl 0 0 20>;
+
+
+Example:
+
+       stmfx: stmfx@42 {
+               ...
+
+               stmfx_pinctrl: stmfx-pin-controller {
+                       compatible = "st,stmfx-0300-pinctrl";
+                       #gpio-cells = <2>;
+                       #interrupt-cells = <2>;
+                       gpio-controller;
+                       interrupt-controller;
+                       gpio-ranges = <&stmfx_pinctrl 0 0 24>;
+
+                       joystick_pins: joystick {
+                               pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4";
+                               drive-push-pull;
+                               bias-pull-up;
+                       };
+               };
+       };
+
+Example of STMFX GPIO consumers:
+
+       joystick {
+               compatible = "gpio-keys";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               pinctrl-0 = <&joystick_pins>;
+               pinctrl-names = "default";
+               button-0 {
+                       label = "JoySel";
+                       linux,code = <KEY_ENTER>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <0 IRQ_TYPE_EDGE_RISING>;
+               };
+               button-1 {
+                       label = "JoyDown";
+                       linux,code = <KEY_DOWN>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <1 IRQ_TYPE_EDGE_RISING>;
+               };
+               button-2 {
+                       label = "JoyLeft";
+                       linux,code = <KEY_LEFT>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <2 IRQ_TYPE_EDGE_RISING>;
+               };
+               button-3 {
+                       label = "JoyRight";
+                       linux,code = <KEY_RIGHT>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <3 IRQ_TYPE_EDGE_RISING>;
+               };
+               button-4 {
+                       label = "JoyUp";
+                       linux,code = <KEY_UP>;
+                       interrupt-parent = <&stmfx_pinctrl>;
+                       interrupts = <4 IRQ_TYPE_EDGE_RISING>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               orange {
+                       gpios = <&stmfx_pinctrl 17 1>;
+               };
+
+               blue {
+                       gpios = <&stmfx_pinctrl 19 1>;
+               };
+       }
index 1cd050b4054ca28295417595c732825a534b091a..0fdc3dd1125e8eb43aaf2c1a28a5aa1733bd8f45 100644 (file)
@@ -16,7 +16,9 @@ Device Tree Bindings:
 ---------------------
 
 Required properties:
-- compatible: should be "amlogic,meson-gx-pwrc-vpu" for the Meson GX SoCs
+- compatible: should be one of the following :
+       - "amlogic,meson-gx-pwrc-vpu" for the Meson GX SoCs
+       - "amlogic,meson-g12a-pwrc-vpu" for the Meson G12A SoCs
 - #power-domain-cells: should be 0
 - amlogic,hhi-sysctrl: phandle to the HHI sysctrl node
 - resets: phandles to the reset lines needed for this power demain sequence
index 11906316b43d0860133efce69c70f5a3e5a52157..e23dea8344f818508ffdab858a81a9147a23278e 100644 (file)
@@ -3,13 +3,20 @@ Generic SYSCON mapped register reset driver
 This is a generic reset driver using syscon to map the reset register.
 The reset is generally performed with a write to the reset register
 defined by the register map pointed by syscon reference plus the offset
-with the mask defined in the reboot node.
+with the value and mask defined in the reboot node.
 
 Required properties:
 - compatible: should contain "syscon-reboot"
 - regmap: this is phandle to the register map node
 - offset: offset in the register map for the reboot register (in bytes)
-- mask: the reset value written to the reboot register (32 bit access)
+- value: the reset value written to the reboot register (32 bit access)
+
+Optional properties:
+- mask: update only the register bits defined by the mask (32 bit)
+
+Legacy usage:
+If a node doesn't contain a value property but contains a mask property, the
+mask property is used as the value.
 
 Default will be little endian mode, 32 bit access only.
 
index ba8d35f66cbe292e4ee42dd22b64c621467430dc..b2d4968fde7de0016ac1f9c402ddf3625cf0bf56 100644 (file)
@@ -4,6 +4,7 @@ Required Properties:
 -compatible: One of: "x-powers,axp202-usb-power-supply"
                      "x-powers,axp221-usb-power-supply"
                      "x-powers,axp223-usb-power-supply"
+                    "x-powers,axp813-usb-power-supply"
 
 The AXP223 PMIC shares most of its behaviour with the AXP221 but has slight
 variations such as the former being able to set the VBUS power supply max
index adbb5dc5b6e9ec05f54986a0bd40fccc36372a7c..0fb33b2c62a6028defc2517fd22fb9bd5506e53b 100644 (file)
@@ -14,13 +14,17 @@ Required properties :
      usb-cdp (USB charging downstream port)
      usb-aca (USB accessory charger adapter)
 
+Optional properties:
+ - charge-status-gpios: GPIO indicating whether a battery is charging.
+
 Example:
 
        usb_charger: charger {
                compatible = "gpio-charger";
                charger-type = "usb-sdp";
-               gpios = <&gpf0 2 0 0 0>;
-       }
+               gpios = <&gpd 28 GPIO_ACTIVE_LOW>;
+               charge-status-gpios = <&gpc 27 GPIO_ACTIVE_LOW>;
+       };
 
        battery {
                power-supplies = <&usb_charger>;
diff --git a/Documentation/devicetree/bindings/power/supply/ingenic,battery.txt b/Documentation/devicetree/bindings/power/supply/ingenic,battery.txt
new file mode 100644 (file)
index 0000000..66430bf
--- /dev/null
@@ -0,0 +1,31 @@
+* Ingenic JZ47xx battery bindings
+
+Required properties:
+
+- compatible: Must be "ingenic,jz4740-battery".
+- io-channels: phandle and IIO specifier pair to the IIO device.
+  Format described in iio-bindings.txt.
+- monitored-battery: phandle to a "simple-battery" compatible node.
+
+The "monitored-battery" property must be a phandle to a node using the format
+described in battery.txt, with the following properties being required:
+
+- voltage-min-design-microvolt: Drained battery voltage.
+- voltage-max-design-microvolt: Fully charged battery voltage.
+
+Example:
+
+#include <dt-bindings/iio/adc/ingenic,adc.h>
+
+simple_battery: battery {
+       compatible = "simple-battery";
+       voltage-min-design-microvolt = <3600000>;
+       voltage-max-design-microvolt = <4200000>;
+};
+
+ingenic_battery {
+       compatible = "ingenic,jz4740-battery";
+       io-channels = <&adc INGENIC_ADC_BATTERY>;
+       io-channel-names = "battery";
+       monitored-battery = <&simple_battery>;
+};
diff --git a/Documentation/devicetree/bindings/power/supply/lt3651-charger.txt b/Documentation/devicetree/bindings/power/supply/lt3651-charger.txt
new file mode 100644 (file)
index 0000000..40811ff
--- /dev/null
@@ -0,0 +1,29 @@
+Analog Devices LT3651 Charger Power Supply bindings: lt3651-charger
+
+Required properties:
+- compatible: Should contain one of the following:
+ * "lltc,ltc3651-charger", (DEPRECATED: Use "lltc,lt3651-charger")
+ * "lltc,lt3651-charger"
+ - lltc,acpr-gpios: Connect to ACPR output. See remark below.
+
+Optional properties:
+ - lltc,fault-gpios: Connect to FAULT output. See remark below.
+ - lltc,chrg-gpios: Connect to CHRG output. See remark below.
+
+The lt3651 outputs are open-drain type and active low. The driver assumes the
+GPIO reports "active" when the output is asserted, so if the pins have been
+connected directly, the GPIO flags should be set to active low also.
+
+The driver will attempt to aquire interrupts for all GPIOs to detect changes in
+line state. If the system is not capabale of providing interrupts, the driver
+cannot report changes and userspace will need to periodically read the sysfs
+attributes to detect changes.
+
+Example:
+
+       charger: battery-charger {
+               compatible = "lltc,lt3651-charger";
+               lltc,acpr-gpios = <&gpio0 68 GPIO_ACTIVE_LOW>;
+               lltc,fault-gpios = <&gpio0 64 GPIO_ACTIVE_LOW>;
+               lltc,chrg-gpios = <&gpio0 63 GPIO_ACTIVE_LOW>;
+       };
diff --git a/Documentation/devicetree/bindings/power/supply/ltc3651-charger.txt b/Documentation/devicetree/bindings/power/supply/ltc3651-charger.txt
deleted file mode 100644 (file)
index 71f2840..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-ltc3651-charger
-
-Required properties:
- - compatible: "lltc,ltc3651-charger"
- - lltc,acpr-gpios: Connect to ACPR output. See remark below.
-
-Optional properties:
- - lltc,fault-gpios: Connect to FAULT output. See remark below.
- - lltc,chrg-gpios: Connect to CHRG output. See remark below.
-
-The ltc3651 outputs are open-drain type and active low. The driver assumes the
-GPIO reports "active" when the output is asserted, so if the pins have been
-connected directly, the GPIO flags should be set to active low also.
-
-The driver will attempt to aquire interrupts for all GPIOs to detect changes in
-line state. If the system is not capabale of providing interrupts, the driver
-cannot report changes and userspace will need to periodically read the sysfs
-attributes to detect changes.
-
-Example:
-
-       charger: battery-charger {
-               compatible = "lltc,ltc3651-charger";
-               lltc,acpr-gpios = <&gpio0 68 GPIO_ACTIVE_LOW>;
-               lltc,fault-gpios = <&gpio0 64 GPIO_ACTIVE_LOW>;
-               lltc,chrg-gpios = <&gpio0 63 GPIO_ACTIVE_LOW>;
-       };
diff --git a/Documentation/devicetree/bindings/power/supply/max77650-charger.txt b/Documentation/devicetree/bindings/power/supply/max77650-charger.txt
new file mode 100644 (file)
index 0000000..e6d0fb6
--- /dev/null
@@ -0,0 +1,28 @@
+Battery charger driver for MAX77650 PMIC from Maxim Integrated.
+
+This module is part of the MAX77650 MFD device. For more details
+see Documentation/devicetree/bindings/mfd/max77650.txt.
+
+The charger is represented as a sub-node of the PMIC node on the device tree.
+
+Required properties:
+--------------------
+- compatible:          Must be "maxim,max77650-charger"
+
+Optional properties:
+--------------------
+- input-voltage-min-microvolt: Minimum CHGIN regulation voltage. Must be one
+                               of: 4000000, 4100000, 4200000, 4300000,
+                               4400000, 4500000, 4600000, 4700000.
+- input-current-limit-microamp:        CHGIN input current limit (in microamps). Must
+                               be one of: 95000, 190000, 285000, 380000,
+                               475000.
+
+Example:
+--------
+
+       charger {
+               compatible = "maxim,max77650-charger";
+               input-voltage-min-microvolt = <4200000>;
+               input-current-limit-microamp = <285000>;
+       };
diff --git a/Documentation/devicetree/bindings/power/supply/microchip,ucs1002.txt b/Documentation/devicetree/bindings/power/supply/microchip,ucs1002.txt
new file mode 100644 (file)
index 0000000..1d284ad
--- /dev/null
@@ -0,0 +1,27 @@
+Microchip UCS1002 USB Port Power Controller
+
+Required properties:
+- compatible           : Should be "microchip,ucs1002";
+- reg                  : I2C slave address
+
+Optional properties:
+- interrupts           : A list of interrupts lines present (could be either
+                         corresponding to A_DET# pin, ALERT# pin, or both)
+- interrupt-names      : A list of interrupt names. Should contain (if
+                         present):
+                         - "a_det" for line connected to A_DET# pin
+                         - "alert" for line connected to ALERT# pin
+                         Both are expected to be IRQ_TYPE_EDGE_BOTH
+Example:
+
+&i2c3 {
+       charger@32 {
+               compatible = "microchip,ucs1002";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_ucs1002_pins>;
+               reg = <0x32>;
+               interrupts-extended = <&gpio5 2 IRQ_TYPE_EDGE_BOTH>,
+                                     <&gpio3 21 IRQ_TYPE_EDGE_BOTH>;
+               interrupt-names = "a_det", "alert";
+       };
+};
index c8901b3992d9cac28620df3063be44233d282233..8d87d6b35a989ebaf74f89bcdf7f7927b47deeb4 100644 (file)
@@ -2,4 +2,4 @@ OLPC battery
 ~~~~~~~~~~~~
 
 Required properties:
-  - compatible : "olpc,xo1-battery"
+  - compatible : "olpc,xo1-battery" or "olpc,xo1.5-battery"
index 3683874832ae10a03c9fe842299d315e4d305d7d..9012a2a02e14dd6275b7e11e40c9bf5bae1e5c1f 100644 (file)
@@ -7,6 +7,10 @@ Required properties:
 - compatible: should be "pps-gpio"
 - gpios: one PPS GPIO in the format described by ../gpio/gpio.txt
 
+Additional required properties for the PPS ECHO functionality:
+- echo-gpios: one PPS ECHO GPIO in the format described by ../gpio/gpio.txt
+- echo-active-ms: duration in ms of the active portion of the echo pulse
+
 Optional properties:
 - assert-falling-edge: when present, assert is indicated by a falling edge
                        (instead of by a rising edge)
@@ -19,5 +23,8 @@ Example:
                gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>;
                assert-falling-edge;
 
+               echo-gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>;
+               echo-active-ms = <100>;
+
                compatible = "pps-gpio";
        };
diff --git a/Documentation/devicetree/bindings/pwm/imx-tpm-pwm.txt b/Documentation/devicetree/bindings/pwm/imx-tpm-pwm.txt
new file mode 100644 (file)
index 0000000..3ba958d
--- /dev/null
@@ -0,0 +1,22 @@
+Freescale i.MX TPM PWM controller
+
+Required properties:
+- compatible : Should be "fsl,imx7ulp-pwm".
+- reg: Physical base address and length of the controller's registers.
+- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of the cells format.
+- clocks : The clock provided by the SoC to drive the PWM.
+- interrupts: The interrupt for the PWM controller.
+
+Note: The TPM counter and period counter are shared between multiple channels, so all channels
+should use same period setting.
+
+Example:
+
+tpm4: pwm@40250000 {
+       compatible = "fsl,imx7ulp-pwm";
+       reg = <0x40250000 0x1000>;
+       assigned-clocks = <&pcc2 IMX7ULP_CLK_LPTPM4>;
+       assigned-clock-parents = <&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>;
+       clocks = <&pcc2 IMX7ULP_CLK_LPTPM4>;
+       #pwm-cells = <3>;
+};
index 1fa3f718213342f20e910a224b95e23efede87be..891632354065269d490cab32c08f184b8c2181d2 100644 (file)
@@ -7,6 +7,9 @@ Required properties:
                          or "amlogic,meson-gxbb-ao-pwm"
                          or "amlogic,meson-axg-ee-pwm"
                          or "amlogic,meson-axg-ao-pwm"
+                         or "amlogic,meson-g12a-ee-pwm"
+                         or "amlogic,meson-g12a-ao-pwm-ab"
+                         or "amlogic,meson-g12a-ao-pwm-cd"
 - #pwm-cells: Should be 3. See pwm.txt in this directory for a description of
   the cells format.
 
index 944fe356bb4569600619b3434dafeddadd164b18..31c4577157dd7a43acdb3f3bcc8dea0850731d07 100644 (file)
@@ -4,6 +4,7 @@ Required properties:
 - compatible: Must be "ti,<soc>-ehrpwm".
   for am33xx  - compatible = "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm";
   for am4372  - compatible = "ti,am4372-ehrpwm", "ti-am3352-ehrpwm", "ti,am33xx-ehrpwm";
+  for am654   - compatible = "ti,am654-ehrpwm", "ti-am3352-ehrpwm";
   for da850   - compatible = "ti,da850-ehrpwm", "ti-am3352-ehrpwm", "ti,am33xx-ehrpwm";
   for dra746 - compatible = "ti,dra746-ehrpwm", "ti-am3352-ehrpwm";
 - #pwm-cells: should be 3. See pwm.txt in this directory for a description of
index 2bf3344b2a026955454ee8a6d62556f18f16cd34..2df4bddeb688918126fd45d9325adf1f6d861988 100644 (file)
@@ -5,11 +5,12 @@ Please also refer to reset.txt in this directory for common reset
 controller binding usage.
 
 The reset controller registers are part of the system-ctl block on
-hi3660 SoC.
+hi3660 and hi3670 SoCs.
 
 Required properties:
-- compatible: should be
-                "hisilicon,hi3660-reset"
+- compatible: should be one of the following:
+                "hisilicon,hi3660-reset" for HI3660
+                "hisilicon,hi3670-reset", "hisilicon,hi3660-reset" for HI3670
 - hisi,rst-syscon: phandle of the reset's syscon.
 - #reset-cells : Specifies the number of cells needed to encode a
   reset source.  The type shall be a <u32> and the value shall be 2.
diff --git a/Documentation/devicetree/bindings/riscv/sifive-l2-cache.txt b/Documentation/devicetree/bindings/riscv/sifive-l2-cache.txt
new file mode 100644 (file)
index 0000000..73d8f19
--- /dev/null
@@ -0,0 +1,51 @@
+SiFive L2 Cache Controller
+--------------------------
+The SiFive Level 2 Cache Controller is used to provide access to fast copies
+of memory for masters in a Core Complex. The Level 2 Cache Controller also
+acts as directory-based coherency manager.
+All the properties in ePAPR/DeviceTree specification applies for this platform
+
+Required Properties:
+--------------------
+- compatible: Should be "sifive,fu540-c000-ccache" and "cache"
+
+- cache-block-size: Specifies the block size in bytes of the cache.
+  Should be 64
+
+- cache-level: Should be set to 2 for a level 2 cache
+
+- cache-sets: Specifies the number of associativity sets of the cache.
+  Should be 1024
+
+- cache-size: Specifies the size in bytes of the cache. Should be 2097152
+
+- cache-unified: Specifies the cache is a unified cache
+
+- interrupts: Must contain 3 entries (DirError, DataError and DataFail signals)
+
+- reg: Physical base address and size of L2 cache controller registers map
+
+Optional Properties:
+--------------------
+- next-level-cache: phandle to the next level cache if present.
+
+- memory-region: reference to the reserved-memory for the L2 Loosely Integrated
+  Memory region. The reserved memory node should be defined as per the bindings
+  in reserved-memory.txt
+
+
+Example:
+
+       cache-controller@2010000 {
+               compatible = "sifive,fu540-c000-ccache", "cache";
+               cache-block-size = <64>;
+               cache-level = <2>;
+               cache-sets = <1024>;
+               cache-size = <2097152>;
+               cache-unified;
+               interrupt-parent = <&plic0>;
+               interrupts = <1 2 3>;
+               reg = <0x0 0x2010000 0x0 0x1000>;
+               next-level-cache = <&L25 &L40 &L36>;
+               memory-region = <&l2_lim>;
+       };
index bcfb13194f16364b0ac77a4391a26c0bb34206d0..c6b5262eb352e9569b0be3353a9ec81bae5f2ae5 100644 (file)
@@ -1,4 +1,4 @@
-* Mediatek Universal Asynchronous Receiver/Transmitter (UART)
+* MediaTek Universal Asynchronous Receiver/Transmitter (UART)
 
 Required properties:
 - compatible should contain:
@@ -13,10 +13,12 @@ Required properties:
   * "mediatek,mt6797-uart" for MT6797 compatible UARTS
   * "mediatek,mt7622-uart" for MT7622 compatible UARTS
   * "mediatek,mt7623-uart" for MT7623 compatible UARTS
+  * "mediatek,mt7629-uart" for MT7629 compatible UARTS
   * "mediatek,mt8127-uart" for MT8127 compatible UARTS
   * "mediatek,mt8135-uart" for MT8135 compatible UARTS
   * "mediatek,mt8173-uart" for MT8173 compatible UARTS
   * "mediatek,mt8183-uart", "mediatek,mt6577-uart" for MT8183 compatible UARTS
+  * "mediatek,mt8516-uart" for MT8516 compatible UARTS
   * "mediatek,mt6577-uart" for MT6577 and all of the above
 
 - reg: The base address of the UART register bank.
index 5a2ef1726e2a20d4651950c5095ce8f109ed0013..7a32404c61140cdd77565a7e8ed4ceea6962e5be 100644 (file)
@@ -25,6 +25,7 @@ Required properties in pwrap device node.
        "mediatek,mt8135-pwrap" for MT8135 SoCs
        "mediatek,mt8173-pwrap" for MT8173 SoCs
        "mediatek,mt8183-pwrap" for MT8183 SoCs
+       "mediatek,mt8516-pwrap" for MT8516 SoCs
 - interrupts: IRQ for pwrap in SOC
 - reg-names: Must include the following entries:
   "pwrap": Main registers base
index d6fe16f094af5c42973639efaf9e7e448091d34d..876693a7ada5222a94bf14f3f13e1085a6566959 100644 (file)
@@ -23,6 +23,7 @@ Required properties:
        - "mediatek,mt7622-scpsys"
        - "mediatek,mt7623-scpsys", "mediatek,mt2701-scpsys": For MT7623 SoC
        - "mediatek,mt7623a-scpsys": For MT7623A SoC
+       - "mediatek,mt7629-scpsys", "mediatek,mt7622-scpsys": For MT7629 SoC
        - "mediatek,mt8173-scpsys"
 - #power-domain-cells: Must be 1
 - reg: Address range of the SCPSYS unit
@@ -33,8 +34,8 @@ Required properties:
        Required clocks for MT2701 or MT7623: "mm", "mfg", "ethif"
        Required clocks for MT2712: "mm", "mfg", "venc", "jpgdec", "audio", "vdec"
        Required clocks for MT6797: "mm", "mfg", "vdec"
-       Required clocks for MT7622: "hif_sel"
-       Required clocks for MT7622A: "ethif"
+       Required clocks for MT7622 or MT7629: "hif_sel"
+       Required clocks for MT7623A: "ethif"
        Required clocks for MT8173: "mm", "mfg", "venc", "venc_lt"
 
 Optional properties:
diff --git a/Documentation/devicetree/bindings/thermal/amazon,al-thermal.txt b/Documentation/devicetree/bindings/thermal/amazon,al-thermal.txt
new file mode 100644 (file)
index 0000000..703979d
--- /dev/null
@@ -0,0 +1,33 @@
+Amazon's Annapurna Labs Thermal Sensor
+
+Simple thermal device that allows temperature reading by a single MMIO
+transaction.
+
+Required properties:
+- compatible: "amazon,al-thermal".
+- reg: The physical base address and length of the sensor's registers.
+- #thermal-sensor-cells: Must be 1. See ./thermal.txt for a description.
+
+Example:
+       thermal: thermal {
+               compatible = "amazon,al-thermal";
+               reg = <0x0 0x05002860 0x0 0x1>;
+               #thermal-sensor-cells = <0x1>;
+       };
+
+       thermal-zones {
+               thermal-z0 {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&thermal 0>;
+                       trips {
+                               critical {
+                                       temperature = <105000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+
+               };
+       };
+
index b6c0ae53d4dca345f3b751df5b39217497d075fa..f02f38527a6b6397a73f0c3c3935918c7d1d64fb 100644 (file)
@@ -52,13 +52,47 @@ Required properties :
         Must set as following values:
         TEGRA_SOCTHERM_THROT_LEVEL_LOW, TEGRA_SOCTHERM_THROT_LEVEL_MED
         TEGRA_SOCTHERM_THROT_LEVEL_HIGH, TEGRA_SOCTHERM_THROT_LEVEL_NONE
+      - nvidia,gpu-throt-level: This property is for Tegra124 and Tegra210.
+        It is the level of pulse skippers, which used to throttle clock
+        frequencies. It indicates gpu clock throttling depth and can be
+        programmed to any of the following values which represent a throttling
+        percentage:
+        TEGRA_SOCTHERM_THROT_LEVEL_NONE (0%)
+        TEGRA_SOCTHERM_THROT_LEVEL_LOW (50%),
+        TEGRA_SOCTHERM_THROT_LEVEL_MED (75%),
+        TEGRA_SOCTHERM_THROT_LEVEL_HIGH (85%).
       - #cooling-cells: Should be 1. This cooling device only support on/off state.
         See ./thermal.txt for a description of this property.
 
+      Optional properties: The following properties are T210 specific and
+      valid only for OCx throttle events.
+      - nvidia,count-threshold: Specifies the number of OC events that are
+        required for triggering an interrupt. Interrupts are not triggered if
+        the property is missing. A value of 0 will interrupt on every OC alarm.
+      - nvidia,polarity-active-low: Configures the polarity of the OC alaram
+        signal. If present, this means assert low, otherwise assert high.
+      - nvidia,alarm-filter: Number of clocks to filter event. When the filter
+        expires (which means the OC event has not occurred for a long time),
+        the counter is cleared and filter is rearmed. Default value is 0.
+      - nvidia,throttle-period-us: Specifies the number of uSec for which
+        throttling is engaged after the OC event is deasserted. Default value
+        is 0.
+
+Optional properties:
+- nvidia,thermtrips : When present, this property specifies the temperature at
+  which the soctherm hardware will assert the thermal trigger signal to the
+  Power Management IC, which can be configured to reset or shutdown the device.
+  It is an array of pairs where each pair represents a tsensor id followed by a
+  temperature in milli Celcius. In the absence of this property the critical
+  trip point will be used for thermtrip temperature.
+
 Note:
-- the "critical" type trip points will be set to SOC_THERM hardware as the
-shut down temperature. Once the temperature of this thermal zone is higher
-than it, the system will be shutdown or reset by hardware.
+- the "critical" type trip points will be used to set the temperature at which
+the SOC_THERM hardware will assert a thermal trigger if the "nvidia,thermtrips"
+property is missing. When the thermtrips property is present, the breach of a
+critical trip point is reported back to the thermal framework to implement
+software shutdown.
+
 - the "hot" type trip points will be set to SOC_THERM hardware as the throttle
 temperature. Once the the temperature of this thermal zone is higher
 than it, it will trigger the HW throttle event.
@@ -79,25 +113,32 @@ Example :
 
                #thermal-sensor-cells = <1>;
 
+               nvidia,thermtrips = <TEGRA124_SOCTHERM_SENSOR_CPU 102500
+                                    TEGRA124_SOCTHERM_SENSOR_GPU 103000>;
+
                throttle-cfgs {
                        /*
                         * When the "heavy" cooling device triggered,
-                        * the HW will skip cpu clock's pulse in 85% depth
+                        * the HW will skip cpu clock's pulse in 85% depth,
+                        * skip gpu clock's pulse in 85% level
                         */
                        throttle_heavy: heavy {
                                nvidia,priority = <100>;
                                nvidia,cpu-throt-percent = <85>;
+                               nvidia,gpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_HIGH>;
 
                                #cooling-cells = <1>;
                        };
 
                        /*
                         * When the "light" cooling device triggered,
-                        * the HW will skip cpu clock's pulse in 50% depth
+                        * the HW will skip cpu clock's pulse in 50% depth,
+                        * skip gpu clock's pulse in 50% level
                         */
                        throttle_light: light {
                                nvidia,priority = <80>;
                                nvidia,cpu-throt-percent = <50>;
+                               nvidia,gpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_LOW>;
 
                                #cooling-cells = <1>;
                        };
@@ -107,6 +148,17 @@ Example :
                         * arbiter will select the highest priority as the final throttle
                         * settings to skip cpu pulse.
                         */
+
+                       throttle_oc1: oc1 {
+                               nvidia,priority = <50>;
+                               nvidia,polarity-active-low;
+                               nvidia,count-threshold = <100>;
+                               nvidia,alarm-filter = <5100000>;
+                               nvidia,throttle-period-us = <0>;
+                               nvidia,cpu-throt-percent = <75>;
+                               nvidia,gpu-throt-level =
+                                               <TEGRA_SOCTHERM_THROT_LEVEL_MED>;
+                        };
                };
        };
 
index 1d9e8cf6101819244d2e59ebf79bd6db43d46f8b..673cc1831ee9d04f3d9bc9987b518773df000bcb 100644 (file)
@@ -6,11 +6,14 @@ Required properties:
     - "qcom,msm8916-tsens" (MSM8916)
     - "qcom,msm8974-tsens" (MSM8974)
     - "qcom,msm8996-tsens" (MSM8996)
+    - "qcom,qcs404-tsens", "qcom,tsens-v1" (QCS404)
     - "qcom,msm8998-tsens", "qcom,tsens-v2" (MSM8998)
     - "qcom,sdm845-tsens", "qcom,tsens-v2" (SDM845)
   The generic "qcom,tsens-v2" property must be used as a fallback for any SoC
   with version 2 of the TSENS IP. MSM8996 is the only exception because the
   generic property did not exist when support was added.
+  Similarly, the generic "qcom,tsens-v1" property must be used as a fallback for
+  any SoC with version 1 of the TSENS IP.
 
 - reg: Address range of the thermal registers.
   New platforms containing v2.x.y of the TSENS IP must specify the SROT and TM
@@ -39,3 +42,14 @@ tsens0: thermal-sensor@c263000 {
                #qcom,sensors = <13>;
                #thermal-sensor-cells = <1>;
        };
+
+Example 3 (for any platform containing v1 of the TSENS IP):
+tsens: thermal-sensor@4a9000 {
+               compatible = "qcom,qcs404-tsens", "qcom,tsens-v1";
+               reg = <0x004a9000 0x1000>, /* TM */
+                     <0x004a8000 0x1000>; /* SROT */
+               nvmem-cells = <&tsens_caldata>;
+               nvmem-cell-names = "calib";
+               #qcom,sensors = <10>;
+               #thermal-sensor-cells = <1>;
+       };
index 43d744e5305ef3fd4f1577ec69fd8db41dc2be56..c6aac9bcacf1cd673244ba8a3d7dce8b38088889 100644 (file)
@@ -2,6 +2,7 @@
 
 Required properties:
 - compatible : should be "rockchip,<name>-tsadc"
+   "rockchip,px30-tsadc":   found on PX30 SoCs
    "rockchip,rv1108-tsadc": found on RV1108 SoCs
    "rockchip,rk3228-tsadc": found on RK3228 SoCs
    "rockchip,rk3288-tsadc": found on RK3288 SoCs
index d72355502b786d02d51c2d8d21e834e2351266b3..691a09db2fefca3a13ba655fcb323d69e55c90e4 100644 (file)
@@ -8,16 +8,22 @@ temperature using voltage-temperature lookup table.
 Required properties:
 ===================
 - compatible:               Must be "generic-adc-thermal".
+- #thermal-sensor-cells:     Should be 1. See ./thermal.txt for a description
+                            of this property.
+Optional properties:
+===================
 - temperature-lookup-table:  Two dimensional array of Integer; lookup table
                             to map the relation between ADC value and
                             temperature. When ADC is read, the value is
                             looked up on the table to get the equivalent
                             temperature.
+
                             The first value of the each row of array is the
                             temperature in milliCelsius and second value of
                             the each row of array is the ADC read value.
-- #thermal-sensor-cells:     Should be 1. See ./thermal.txt for a description
-                            of this property.
+
+                            If not specified, driver assumes the ADC channel
+                            gives milliCelsius directly.
 
 Example :
 #include <dt-bindings/thermal/thermal.h>
diff --git a/Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml b/Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml
new file mode 100644 (file)
index 0000000..a36a074
--- /dev/null
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2018 Linaro Ltd.
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/timer/intel-ixp4xx-timer.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Intel IXP4xx XScale Networking Processors Timers
+
+maintainers:
+  - Linus Walleij <linus.walleij@linaro.org>
+
+description: This timer is found in the Intel IXP4xx processors.
+
+properties:
+  compatible:
+    items:
+      - const: intel,ixp4xx-timer
+
+  reg:
+    description: Should contain registers location and length
+
+  interrupts:
+    minItems: 1
+    maxItems: 2
+    items:
+      - description: Timer 1 interrupt
+      - description: Timer 2 interrupt
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    timer@c8005000 {
+        compatible = "intel,ixp4xx-timer";
+        reg = <0xc8005000 0x100>;
+        interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
+    };
index ff7c567a7972a1b44ab2698bbd216211f80ebb8f..74c3eadad8444de12e3f68e410b2054f97a379d6 100644 (file)
@@ -17,6 +17,7 @@ Required properties:
        * "mediatek,mt8127-timer" for MT8127 compatible timers (GPT)
        * "mediatek,mt8135-timer" for MT8135 compatible timers (GPT)
        * "mediatek,mt8173-timer" for MT8173 compatible timers (GPT)
+       * "mediatek,mt8516-timer" for MT8516 compatible timers (GPT)
        * "mediatek,mt6577-timer" for MT6577 and all above compatible timers (GPT)
 
        For those SoCs that use SYST
index 56bccde9953a33f91e36bde107dc9c4ae475c8e0..a74720486ee29d775170715ac9f8497feab7a0b5 100644 (file)
@@ -11,6 +11,7 @@ Required properties:
                          the appropriate jedec string:
                            "qcom,msm8994-ufshc", "qcom,ufshc", "jedec,ufs-2.0"
                            "qcom,msm8996-ufshc", "qcom,ufshc", "jedec,ufs-2.0"
+                           "qcom,msm8998-ufshc", "qcom,ufshc", "jedec,ufs-2.0"
                            "qcom,sdm845-ufshc", "qcom,ufshc", "jedec,ufs-2.0"
 - interrupts        : <interrupt mapping for UFS host controller IRQ>
 - reg               : <registers mapping>
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
deleted file mode 100644 (file)
index 9ed3999..0000000
+++ /dev/null
@@ -1,468 +0,0 @@
-Device tree binding vendor prefix registry.  Keep list in alphabetical order.
-
-This isn't an exhaustive list, but you should add new prefixes to it before
-using them to avoid name-space collisions.
-
-abilis Abilis Systems
-abracon        Abracon Corporation
-actions        Actions Semiconductor Co., Ltd.
-active-semi    Active-Semi International Inc
-ad     Avionic Design GmbH
-adafruit       Adafruit Industries, LLC
-adapteva       Adapteva, Inc.
-adaptrum       Adaptrum, Inc.
-adh    AD Holdings Plc.
-adi    Analog Devices, Inc.
-advantech      Advantech Corporation
-aeroflexgaisler        Aeroflex Gaisler AB
-al     Annapurna Labs
-allo   Allo.com
-allwinner      Allwinner Technology Co., Ltd.
-alphascale     AlphaScale Integrated Circuits Systems, Inc.
-altr   Altera Corp.
-amarula        Amarula Solutions
-amazon Amazon.com, Inc.
-amcc   Applied Micro Circuits Corporation (APM, formally AMCC)
-amd    Advanced Micro Devices (AMD), Inc.
-amediatech     Shenzhen Amediatech Technology Co., Ltd
-amlogic        Amlogic, Inc.
-ampire Ampire Co., Ltd.
-ams    AMS AG
-amstaos        AMS-Taos Inc.
-analogix       Analogix Semiconductor, Inc.
-andestech      Andes Technology Corporation
-apm    Applied Micro Circuits Corporation (APM)
-aptina Aptina Imaging
-arasan Arasan Chip Systems
-archermind ArcherMind Technology (Nanjing) Co., Ltd.
-arctic Arctic Sand
-arcx   arcx Inc. / Archronix Inc.
-aries  Aries Embedded GmbH
-arm    ARM Ltd.
-armadeus       ARMadeus Systems SARL
-arrow  Arrow Electronics
-artesyn        Artesyn Embedded Technologies Inc.
-asahi-kasei    Asahi Kasei Corp.
-aspeed ASPEED Technology Inc.
-asus   AsusTek Computer Inc.
-atlas  Atlas Scientific LLC
-atmel  Atmel Corporation
-auo    AU Optronics Corporation
-auvidea Auvidea GmbH
-avago  Avago Technologies
-avia   avia semiconductor
-avic   Shanghai AVIC Optoelectronics Co., Ltd.
-avnet  Avnet, Inc.
-axentia        Axentia Technologies AB
-axis   Axis Communications AB
-bananapi BIPAI KEJI LIMITED
-bhf    Beckhoff Automation GmbH & Co. KG
-bitmain        Bitmain Technologies
-boe    BOE Technology Group Co., Ltd.
-bosch  Bosch Sensortec GmbH
-boundary       Boundary Devices Inc.
-brcm   Broadcom Corporation
-buffalo        Buffalo, Inc.
-bticino Bticino International
-calxeda        Calxeda
-capella        Capella Microsystems, Inc
-cascoda        Cascoda, Ltd.
-catalyst       Catalyst Semiconductor, Inc.
-cavium Cavium, Inc.
-cdns   Cadence Design Systems Inc.
-cdtech CDTech(H.K.) Electronics Limited
-ceva   Ceva, Inc.
-chipidea       Chipidea, Inc
-chipone                ChipOne
-chipspark      ChipSPARK
-chrp   Common Hardware Reference Platform
-chunghwa       Chunghwa Picture Tubes Ltd.
-ciaa   Computadora Industrial Abierta Argentina
-cirrus Cirrus Logic, Inc.
-cloudengines   Cloud Engines, Inc.
-cnm    Chips&Media, Inc.
-cnxt   Conexant Systems, Inc.
-compulab       CompuLab Ltd.
-cortina        Cortina Systems, Inc.
-cosmic Cosmic Circuits
-crane  Crane Connectivity Solutions
-creative       Creative Technology Ltd
-crystalfontz   Crystalfontz America, Inc.
-csky   Hangzhou C-SKY Microsystems Co., Ltd
-cubietech      Cubietech, Ltd.
-cypress        Cypress Semiconductor Corporation
-cznic  CZ.NIC, z.s.p.o.
-dallas Maxim Integrated Products (formerly Dallas Semiconductor)
-dataimage      DataImage, Inc.
-davicom        DAVICOM Semiconductor, Inc.
-delta  Delta Electronics, Inc.
-denx   Denx Software Engineering
-devantech      Devantech, Ltd.
-dh     DH electronics GmbH
-digi   Digi International Inc.
-digilent       Diglent, Inc.
-dioo   Dioo Microcircuit Co., Ltd
-dlc    DLC Display Co., Ltd.
-dlg    Dialog Semiconductor
-dlink  D-Link Corporation
-dmo    Data Modul AG
-domintech      Domintech Co., Ltd.
-dongwoon       Dongwoon Anatech
-dptechnics     DPTechnics
-dragino        Dragino Technology Co., Limited
-ea     Embedded Artists AB
-ebs-systart EBS-SYSTART GmbH
-ebv    EBV Elektronik
-eckelmann      Eckelmann AG
-edt    Emerging Display Technologies
-eeti   eGalax_eMPIA Technology Inc
-elan   Elan Microelectronic Corp.
-elgin  Elgin S/A.
-embest Shenzhen Embest Technology Co., Ltd.
-emlid  Emlid, Ltd.
-emmicro        EM Microelectronic
-emtrion        emtrion GmbH
-endless        Endless Mobile, Inc.
-energymicro    Silicon Laboratories (formerly Energy Micro AS)
-engicam        Engicam S.r.l.
-epcos  EPCOS AG
-epfl   Ecole Polytechnique Fédérale de Lausanne
-epson  Seiko Epson Corp.
-est    ESTeem Wireless Modems
-ettus  NI Ettus Research
-eukrea  Eukréa Electromatique
-everest        Everest Semiconductor Co. Ltd.
-everspin       Everspin Technologies, Inc.
-exar   Exar Corporation
-excito Excito
-ezchip EZchip Semiconductor
-facebook       Facebook
-fairphone      Fairphone B.V.
-faraday        Faraday Technology Corporation
-fastrax        Fastrax Oy
-fcs    Fairchild Semiconductor
-feiyang        Shenzhen Fly Young Technology Co.,LTD.
-firefly        Firefly
-focaltech      FocalTech Systems Co.,Ltd
-friendlyarm    Guangzhou FriendlyARM Computer Tech Co., Ltd
-fsl    Freescale Semiconductor
-fujitsu        Fujitsu Ltd.
-gateworks      Gateworks Corporation
-gcw Game Consoles Worldwide
-ge     General Electric Company
-geekbuying     GeekBuying
-gef    GE Fanuc Intelligent Platforms Embedded Systems, Inc.
-GEFanuc        GE Fanuc Intelligent Platforms Embedded Systems, Inc.
-geniatech      Geniatech, Inc.
-giantec        Giantec Semiconductor, Inc.
-giantplus      Giantplus Technology Co., Ltd.
-globalscale    Globalscale Technologies, Inc.
-globaltop      GlobalTop Technology, Inc.
-gmt    Global Mixed-mode Technology, Inc.
-goodix Shenzhen Huiding Technology Co., Ltd.
-google Google, Inc.
-grinn  Grinn
-grmn   Garmin Limited
-gumstix        Gumstix, Inc.
-gw     Gateworks Corporation
-hannstar       HannStar Display Corporation
-haoyu  Haoyu Microelectronic Co. Ltd.
-hardkernel     Hardkernel Co., Ltd
-hideep HiDeep Inc.
-himax  Himax Technologies, Inc.
-hisilicon      Hisilicon Limited.
-hit    Hitachi Ltd.
-hitex  Hitex Development Tools
-holt   Holt Integrated Circuits, Inc.
-honeywell      Honeywell
-hp     Hewlett Packard
-holtek Holtek Semiconductor, Inc.
-hwacom HwaCom Systems Inc.
-i2se   I2SE GmbH
-ibm    International Business Machines (IBM)
-icplus IC Plus Corp.
-idt    Integrated Device Technologies, Inc.
-ifi    Ingenieurburo Fur Ic-Technologie (I/F/I)
-ilitek ILI Technology Corporation (ILITEK)
-img    Imagination Technologies Ltd.
-infineon Infineon Technologies
-inforce        Inforce Computing
-ingenic        Ingenic Semiconductor
-innolux        Innolux Corporation
-inside-secure  INSIDE Secure
-intel  Intel Corporation
-intercontrol   Inter Control Group
-invensense     InvenSense Inc.
-inversepath    Inverse Path
-iom    Iomega Corporation
-isee   ISEE 2007 S.L.
-isil   Intersil
-issi   Integrated Silicon Solutions Inc.
-itead  ITEAD Intelligent Systems Co.Ltd
-iwave  iWave Systems Technologies Pvt. Ltd.
-jdi    Japan Display Inc.
-jedec  JEDEC Solid State Technology Association
-jianda Jiandangjing Technology Co., Ltd.
-karo   Ka-Ro electronics GmbH
-keithkoep      Keith & Koep GmbH
-keymile        Keymile GmbH
-khadas Khadas
-kiebackpeter    Kieback & Peter GmbH
-kinetic Kinetic Technologies
-kingdisplay    King & Display Technology Co., Ltd.
-kingnovel      Kingnovel Technology Co., Ltd.
-kionix Kionix, Inc.
-koe    Kaohsiung Opto-Electronics Inc.
-kosagi Sutajio Ko-Usagi PTE Ltd.
-kyo    Kyocera Corporation
-lacie  LaCie
-laird  Laird PLC
-lantiq Lantiq Semiconductor
-lattice        Lattice Semiconductor
-lego   LEGO Systems A/S
-lemaker        Shenzhen LeMaker Technology Co., Ltd.
-lenovo Lenovo Group Ltd.
-lg     LG Corporation
-libretech      Shenzhen Libre Technology Co., Ltd
-licheepi       Lichee Pi
-linaro Linaro Limited
-linksys        Belkin International, Inc. (Linksys)
-linux  Linux-specific binding
-linx   Linx Technologies
-lltc   Linear Technology Corporation
-logicpd        Logic PD, Inc.
-lsi    LSI Corp. (LSI Logic)
-lwn    Liebherr-Werk Nenzing GmbH
-macnica        Macnica Americas
-marvell        Marvell Technology Group Ltd.
-maxbotix       MaxBotix Inc.
-maxim  Maxim Integrated Products
-mbvl   Mobiveil Inc.
-mcube  mCube
-meas   Measurement Specialties
-mediatek       MediaTek Inc.
-megachips      MegaChips
-mele   Shenzhen MeLE Digital Technology Ltd.
-melexis        Melexis N.V.
-melfas MELFAS Inc.
-mellanox       Mellanox Technologies
-memsic MEMSIC Inc.
-merrii Merrii Technology Co., Ltd.
-micrel Micrel Inc.
-microchip      Microchip Technology Inc.
-microcrystal   Micro Crystal AG
-micron Micron Technology Inc.
-mikroe         MikroElektronika d.o.o.
-minix  MINIX Technology Ltd.
-miramems       MiraMEMS Sensing Technology Co., Ltd.
-mitsubishi     Mitsubishi Electric Corporation
-mosaixtech     Mosaix Technologies, Inc.
-motorola       Motorola, Inc.
-moxa   Moxa Inc.
-mpl    MPL AG
-mqmaker        mqmaker Inc.
-mscc   Microsemi Corporation
-msi    Micro-Star International Co. Ltd.
-mti    Imagination Technologies Ltd. (formerly MIPS Technologies Inc.)
-multi-inno     Multi-Inno Technology Co.,Ltd
-mundoreader    Mundo Reader S.L.
-murata Murata Manufacturing Co., Ltd.
-mxicy  Macronix International Co., Ltd.
-myir   MYIR Tech Limited
-national       National Semiconductor
-nec    NEC LCD Technologies, Ltd.
-neonode                Neonode Inc.
-netgear        NETGEAR
-netlogic       Broadcom Corporation (formerly NetLogic Microsystems)
-netron-dy      Netron DY
-netxeon                Shenzhen Netxeon Technology CO., LTD
-nexbox Nexbox
-nextthing      Next Thing Co.
-newhaven       Newhaven Display International
-ni     National Instruments
-nintendo       Nintendo
-nlt    NLT Technologies, Ltd.
-nokia  Nokia
-nordic Nordic Semiconductor
-novtech NovTech, Inc.
-nutsboard      NutsBoard
-nuvoton        Nuvoton Technology Corporation
-nvd    New Vision Display
-nvidia NVIDIA
-nxp    NXP Semiconductors
-okaya  Okaya Electric America, Inc.
-oki    Oki Electric Industry Co., Ltd.
-olimex OLIMEX Ltd.
-olpc   One Laptop Per Child
-onion  Onion Corporation
-onnn   ON Semiconductor Corp.
-ontat  On Tat Industrial Company
-opalkelly      Opal Kelly Incorporated
-opencores      OpenCores.org
-openrisc       OpenRISC.io
-option Option NV
-oranth Shenzhen Oranth Technology Co., Ltd.
-ORCL   Oracle Corporation
-orisetech      Orise Technology
-ortustech      Ortus Technology Co., Ltd.
-osddisplays    OSD Displays
-ovti   OmniVision Technologies
-oxsemi Oxford Semiconductor, Ltd.
-panasonic      Panasonic Corporation
-parade Parade Technologies Inc.
-pda    Precision Design Associates, Inc.
-pericom        Pericom Technology Inc.
-pervasive      Pervasive Displays, Inc.
-phicomm PHICOMM Co., Ltd.
-phytec PHYTEC Messtechnik GmbH
-picochip       Picochip Ltd
-pine64 Pine64
-pixcir  PIXCIR MICROELECTRONICS Co., Ltd
-plantower Plantower Co., Ltd
-plathome       Plat'Home Co., Ltd.
-plda   PLDA
-plx    Broadcom Corporation (formerly PLX Technology)
-pni    PNI Sensor Corporation
-portwell       Portwell Inc.
-poslab Poslab Technology Co., Ltd.
-powervr        PowerVR (deprecated, use img)
-probox2        PROBOX2 (by W2COMP Co., Ltd.)
-pulsedlight    PulsedLight, Inc
-qca    Qualcomm Atheros, Inc.
-qcom   Qualcomm Technologies, Inc
-qemu   QEMU, a generic and open source machine emulator and virtualizer
-qi     Qi Hardware
-qiaodian       QiaoDian XianShi Corporation
-qnap   QNAP Systems, Inc.
-radxa  Radxa
-raidsonic      RaidSonic Technology GmbH
-ralink Mediatek/Ralink Technology Corp.
-ramtron        Ramtron International
-raspberrypi    Raspberry Pi Foundation
-raydium        Raydium Semiconductor Corp.
-rda    Unisoc Communications, Inc.
-realtek Realtek Semiconductor Corp.
-renesas        Renesas Electronics Corporation
-richtek        Richtek Technology Corporation
-ricoh  Ricoh Co. Ltd.
-rikomagic      Rikomagic Tech Corp. Ltd
-riscv  RISC-V Foundation
-rockchip       Fuzhou Rockchip Electronics Co., Ltd
-rocktech       ROCKTECH DISPLAYS LIMITED
-rohm   ROHM Semiconductor Co., Ltd
-ronbo   Ronbo Electronics
-roofull        Shenzhen Roofull Technology Co, Ltd
-samsung        Samsung Semiconductor
-samtec Samtec/Softing company
-sancloud       Sancloud Ltd
-sandisk        Sandisk Corporation
-sbs    Smart Battery System
-schindler      Schindler
-seagate        Seagate Technology PLC
-semtech        Semtech Corporation
-sensirion      Sensirion AG
-sff    Small Form Factor Committee
-sgd    Solomon Goldentek Display Corporation
-sgx    SGX Sensortech
-sharp  Sharp Corporation
-shimafuji      Shimafuji Electric, Inc.
-si-en  Si-En Technology Ltd.
-sifive SiFive, Inc.
-sigma  Sigma Designs, Inc.
-sii    Seiko Instruments, Inc.
-sil    Silicon Image
-silabs Silicon Laboratories
-silead Silead Inc.
-silergy        Silergy Corp.
-siliconmitus   Silicon Mitus, Inc.
-simtek
-sirf   SiRF Technology, Inc.
-sis    Silicon Integrated Systems Corp.
-sitronix       Sitronix Technology Corporation
-skyworks       Skyworks Solutions, Inc.
-smsc   Standard Microsystems Corporation
-snps   Synopsys, Inc.
-socionext      Socionext Inc.
-solidrun       SolidRun
-solomon        Solomon Systech Limited
-sony   Sony Corporation
-spansion       Spansion Inc.
-sprd   Spreadtrum Communications Inc.
-sst    Silicon Storage Technology, Inc.
-st     STMicroelectronics
-starry Starry Electronic Technology (ShenZhen) Co., LTD
-startek        Startek
-ste    ST-Ericsson
-stericsson     ST-Ericsson
-summit Summit microelectronics
-sunchip        Shenzhen Sunchip Technology Co., Ltd
-SUNW   Sun Microsystems, Inc
-swir   Sierra Wireless
-syna   Synaptics Inc.
-synology       Synology, Inc.
-tbs    TBS Technologies
-tbs-biometrics Touchless Biometric Systems AG
-tcg    Trusted Computing Group
-tcl    Toby Churchill Ltd.
-technexion     TechNexion
-technologic    Technologic Systems
-tempo  Tempo Semiconductor
-techstar       Shenzhen Techstar Electronics Co., Ltd.
-terasic        Terasic Inc.
-thine  THine Electronics, Inc.
-ti     Texas Instruments
-tianma Tianma Micro-electronics Co., Ltd.
-tlm    Trusted Logic Mobility
-tmt    Tecon Microprocessor Technologies, LLC.
-topeet  Topeet
-toradex        Toradex AG
-toshiba        Toshiba Corporation
-toumaz Toumaz
-tpk    TPK U.S.A. LLC
-tplink TP-LINK Technologies Co., Ltd.
-tpo    TPO
-tronfy Tronfy
-tronsmart      Tronsmart
-truly  Truly Semiconductors Limited
-tsd    Theobroma Systems Design und Consulting GmbH
-tyan   Tyan Computer Corporation
-u-blox u-blox
-ucrobotics     uCRobotics
-ubnt   Ubiquiti Networks
-udoo   Udoo
-uniwest        United Western Technologies Corp (UniWest)
-upisemi        uPI Semiconductor Corp.
-urt    United Radiant Technology Corporation
-usi    Universal Scientific Industrial Co., Ltd.
-v3     V3 Semiconductor
-vamrs  Vamrs Ltd.
-variscite      Variscite Ltd.
-via    VIA Technologies, Inc.
-virtio Virtual I/O Device Specification, developed by the OASIS consortium
-vishay Vishay Intertechnology, Inc
-vitesse        Vitesse Semiconductor Corporation
-vivante        Vivante Corporation
-vocore VoCore Studio
-voipac Voipac Technologies s.r.o.
-vot    Vision Optical Technology Co., Ltd.
-wd     Western Digital Corp.
-wetek  WeTek Electronics, limited.
-wexler Wexler
-whwave  Shenzhen whwave Electronics, Inc.
-wi2wi  Wi2Wi, Inc.
-winbond Winbond Electronics corp.
-winstar        Winstar Display Corp.
-wlf    Wolfson Microelectronics
-wm     Wondermedia Technologies, Inc.
-x-powers       X-Powers
-xes    Extreme Engineering Solutions (X-ES)
-xillybus       Xillybus Ltd.
-xlnx   Xilinx
-xunlong        Shenzhen Xunlong Software CO.,Limited
-ysoft  Y Soft Corporation a.s.
-zarlink        Zarlink Semiconductor
-zeitec ZEITEC Semiconductor Co., LTD.
-zidoo  Shenzhen Zidoo Technology Co., Ltd.
-zii    Zodiac Inflight Innovations
-zte    ZTE Corp.
-zyxel  ZyXEL Communications Corp.
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
new file mode 100644 (file)
index 0000000..33a65a4
--- /dev/null
@@ -0,0 +1,977 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/vendor-prefixes.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Devicetree Vendor Prefix Registry
+
+maintainers:
+  - Rob Herring <robh@kernel.org>
+
+select: true
+
+properties: {}
+
+patternProperties:
+  # Prefixes which are not vendors, but followed the pattern
+  # DO NOT ADD NEW PROPERTIES TO THIS LIST
+  "^(at25|devbus|dmacap|dsa|exynos|gpio-fan|gpio|gpmc|hdmi|i2c-gpio),.*": true
+  "^(keypad|m25p|max8952|max8997|max8998|mpmc),.*": true
+  "^(pinctrl-single|#pinctrl-single|PowerPC),.*": true
+  "^(pl022|pxa-mmc|rcar_sound|rotary-encoder|s5m8767|sdhci),.*": true
+  "^(simple-audio-card|simple-graph-card|st-plgpio|st-spics|ts),.*": true
+
+  # Keep list in alphabetical order.
+  "^abilis,.*":
+    description: Abilis Systems
+  "^abracon,.*":
+    description: Abracon Corporation
+  "^actions,.*":
+    description: Actions Semiconductor Co., Ltd.
+  "^active-semi,.*":
+    description: Active-Semi International Inc
+  "^ad,.*":
+    description: Avionic Design GmbH
+  "^adafruit,.*":
+    description: Adafruit Industries, LLC
+  "^adapteva,.*":
+    description: Adapteva, Inc.
+  "^adaptrum,.*":
+    description: Adaptrum, Inc.
+  "^adh,.*":
+    description: AD Holdings Plc.
+  "^adi,.*":
+    description: Analog Devices, Inc.
+  "^advantech,.*":
+    description: Advantech Corporation
+  "^aeroflexgaisler,.*":
+    description: Aeroflex Gaisler AB
+  "^al,.*":
+    description: Annapurna Labs
+  "^allo,.*":
+    description: Allo.com
+  "^allwinner,.*":
+    description: Allwinner Technology Co., Ltd.
+  "^alphascale,.*":
+    description: AlphaScale Integrated Circuits Systems, Inc.
+  "^altr,.*":
+    description: Altera Corp.
+  "^amarula,.*":
+    description: Amarula Solutions
+  "^amazon,.*":
+    description: Amazon.com, Inc.
+  "^amcc,.*":
+    description: Applied Micro Circuits Corporation (APM, formally AMCC)
+  "^amd,.*":
+    description: Advanced Micro Devices (AMD), Inc.
+  "^amediatech,.*":
+    description: Shenzhen Amediatech Technology Co., Ltd
+  "^amlogic,.*":
+    description: Amlogic, Inc.
+  "^ampire,.*":
+    description: Ampire Co., Ltd.
+  "^ams,.*":
+    description: AMS AG
+  "^amstaos,.*":
+    description: AMS-Taos Inc.
+  "^analogix,.*":
+    description: Analogix Semiconductor, Inc.
+  "^andestech,.*":
+    description: Andes Technology Corporation
+  "^apm,.*":
+    description: Applied Micro Circuits Corporation (APM)
+  "^aptina,.*":
+    description: Aptina Imaging
+  "^arasan,.*":
+    description: Arasan Chip Systems
+  "^archermind,.*":
+    description: ArcherMind Technology (Nanjing) Co., Ltd.
+  "^arctic,.*":
+    description: Arctic Sand
+  "^arcx,.*":
+    description: arcx Inc. / Archronix Inc.
+  "^aries,.*":
+    description: Aries Embedded GmbH
+  "^arm,.*":
+    description: ARM Ltd.
+  "^armadeus,.*":
+    description: ARMadeus Systems SARL
+  "^arrow,.*":
+    description: Arrow Electronics
+  "^artesyn,.*":
+    description: Artesyn Embedded Technologies Inc.
+  "^asahi-kasei,.*":
+    description: Asahi Kasei Corp.
+  "^aspeed,.*":
+    description: ASPEED Technology Inc.
+  "^asus,.*":
+    description: AsusTek Computer Inc.
+  "^atlas,.*":
+    description: Atlas Scientific LLC
+  "^atmel,.*":
+    description: Atmel Corporation
+  "^auo,.*":
+    description: AU Optronics Corporation
+  "^auvidea,.*":
+    description: Auvidea GmbH
+  "^avago,.*":
+    description: Avago Technologies
+  "^avia,.*":
+    description: avia semiconductor
+  "^avic,.*":
+    description: Shanghai AVIC Optoelectronics Co., Ltd.
+  "^avnet,.*":
+    description: Avnet, Inc.
+  "^axentia,.*":
+    description: Axentia Technologies AB
+  "^axis,.*":
+    description: Axis Communications AB
+  "^azoteq,.*":
+    description: Azoteq (Pty) Ltd
+  "^azw,.*":
+    description: Shenzhen AZW Technology Co., Ltd.
+  "^bananapi,.*":
+    description: BIPAI KEJI LIMITED
+  "^bhf,.*":
+    description: Beckhoff Automation GmbH & Co. KG
+  "^bitmain,.*":
+    description: Bitmain Technologies
+  "^boe,.*":
+    description: BOE Technology Group Co., Ltd.
+  "^bosch,.*":
+    description: Bosch Sensortec GmbH
+  "^boundary,.*":
+    description: Boundary Devices Inc.
+  "^brcm,.*":
+    description: Broadcom Corporation
+  "^buffalo,.*":
+    description: Buffalo, Inc.
+  "^bticino,.*":
+    description: Bticino International
+  "^calxeda,.*":
+    description: Calxeda
+  "^capella,.*":
+    description: Capella Microsystems, Inc
+  "^cascoda,.*":
+    description: Cascoda, Ltd.
+  "^catalyst,.*":
+    description: Catalyst Semiconductor, Inc.
+  "^cavium,.*":
+    description: Cavium, Inc.
+  "^cdns,.*":
+    description: Cadence Design Systems Inc.
+  "^cdtech,.*":
+    description: CDTech(H.K.) Electronics Limited
+  "^ceva,.*":
+    description: Ceva, Inc.
+  "^chipidea,.*":
+    description: Chipidea, Inc
+  "^chipone,.*":
+    description: ChipOne
+  "^chipspark,.*":
+    description: ChipSPARK
+  "^chrp,.*":
+    description: Common Hardware Reference Platform
+  "^chunghwa,.*":
+    description: Chunghwa Picture Tubes Ltd.
+  "^ciaa,.*":
+    description: Computadora Industrial Abierta Argentina
+  "^cirrus,.*":
+    description: Cirrus Logic, Inc.
+  "^cloudengines,.*":
+    description: Cloud Engines, Inc.
+  "^cnm,.*":
+    description: Chips&Media, Inc.
+  "^cnxt,.*":
+    description: Conexant Systems, Inc.
+  "^compulab,.*":
+    description: CompuLab Ltd.
+  "^cortina,.*":
+    description: Cortina Systems, Inc.
+  "^cosmic,.*":
+    description: Cosmic Circuits
+  "^crane,.*":
+    description: Crane Connectivity Solutions
+  "^creative,.*":
+    description: Creative Technology Ltd
+  "^crystalfontz,.*":
+    description: Crystalfontz America, Inc.
+  "^csky,.*":
+    description: Hangzhou C-SKY Microsystems Co., Ltd
+  "^cubietech,.*":
+    description: Cubietech, Ltd.
+  "^cypress,.*":
+    description: Cypress Semiconductor Corporation
+  "^cznic,.*":
+    description: CZ.NIC, z.s.p.o.
+  "^dallas,.*":
+    description: Maxim Integrated Products (formerly Dallas Semiconductor)
+  "^dataimage,.*":
+    description: DataImage, Inc.
+  "^davicom,.*":
+    description: DAVICOM Semiconductor, Inc.
+  "^delta,.*":
+    description: Delta Electronics, Inc.
+  "^denx,.*":
+    description: Denx Software Engineering
+  "^devantech,.*":
+    description: Devantech, Ltd.
+  "^dh,.*":
+    description: DH electronics GmbH
+  "^digi,.*":
+    description: Digi International Inc.
+  "^digilent,.*":
+    description: Diglent, Inc.
+  "^dioo,.*":
+    description: Dioo Microcircuit Co., Ltd
+  "^dlc,.*":
+    description: DLC Display Co., Ltd.
+  "^dlg,.*":
+    description: Dialog Semiconductor
+  "^dlink,.*":
+    description: D-Link Corporation
+  "^dmo,.*":
+    description: Data Modul AG
+  "^domintech,.*":
+    description: Domintech Co., Ltd.
+  "^dongwoon,.*":
+    description: Dongwoon Anatech
+  "^dptechnics,.*":
+    description: DPTechnics
+  "^dragino,.*":
+    description: Dragino Technology Co., Limited
+  "^ea,.*":
+    description: Embedded Artists AB
+  "^ebs-systart,.*":
+    description: EBS-SYSTART GmbH
+  "^ebv,.*":
+    description: EBV Elektronik
+  "^eckelmann,.*":
+    description: Eckelmann AG
+  "^edt,.*":
+    description: Emerging Display Technologies
+  "^eeti,.*":
+    description: eGalax_eMPIA Technology Inc
+  "^elan,.*":
+    description: Elan Microelectronic Corp.
+  "^elgin,.*":
+    description: Elgin S/A.
+  "^embest,.*":
+    description: Shenzhen Embest Technology Co., Ltd.
+  "^emlid,.*":
+    description: Emlid, Ltd.
+  "^emmicro,.*":
+    description: EM Microelectronic
+  "^emtrion,.*":
+    description: emtrion GmbH
+  "^endless,.*":
+    description: Endless Mobile, Inc.
+  "^energymicro,.*":
+    description: Silicon Laboratories (formerly Energy Micro AS)
+  "^engicam,.*":
+    description: Engicam S.r.l.
+  "^epcos,.*":
+    description: EPCOS AG
+  "^epfl,.*":
+    description: Ecole Polytechnique Fédérale de Lausanne
+  "^epson,.*":
+    description: Seiko Epson Corp.
+  "^est,.*":
+    description: ESTeem Wireless Modems
+  "^ettus,.*":
+    description: NI Ettus Research
+  "^eukrea,.*":
+    description: Eukréa Electromatique
+  "^everest,.*":
+    description: Everest Semiconductor Co. Ltd.
+  "^everspin,.*":
+    description: Everspin Technologies, Inc.
+  "^exar,.*":
+    description: Exar Corporation
+  "^excito,.*":
+    description: Excito
+  "^ezchip,.*":
+    description: EZchip Semiconductor
+  "^facebook,.*":
+    description: Facebook
+  "^fairphone,.*":
+    description: Fairphone B.V.
+  "^faraday,.*":
+    description: Faraday Technology Corporation
+  "^fastrax,.*":
+    description: Fastrax Oy
+  "^fcs,.*":
+    description: Fairchild Semiconductor
+  "^feiyang,.*":
+    description: Shenzhen Fly Young Technology Co.,LTD.
+  "^firefly,.*":
+    description: Firefly
+  "^focaltech,.*":
+    description: FocalTech Systems Co.,Ltd
+  "^friendlyarm,.*":
+    description: Guangzhou FriendlyARM Computer Tech Co., Ltd
+  "^fsl,.*":
+    description: Freescale Semiconductor
+  "^fujitsu,.*":
+    description: Fujitsu Ltd.
+  "^gateworks,.*":
+    description: Gateworks Corporation
+  "^gcw,.*":
+    description: Game Consoles Worldwide
+  "^ge,.*":
+    description: General Electric Company
+  "^geekbuying,.*":
+    description: GeekBuying
+  "^gef,.*":
+    description: GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+  "^GEFanuc,.*":
+    description: GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+  "^geniatech,.*":
+    description: Geniatech, Inc.
+  "^giantec,.*":
+    description: Giantec Semiconductor, Inc.
+  "^giantplus,.*":
+    description: Giantplus Technology Co., Ltd.
+  "^globalscale,.*":
+    description: Globalscale Technologies, Inc.
+  "^globaltop,.*":
+    description: GlobalTop Technology, Inc.
+  "^gmt,.*":
+    description: Global Mixed-mode Technology, Inc.
+  "^goodix,.*":
+    description: Shenzhen Huiding Technology Co., Ltd.
+  "^google,.*":
+    description: Google, Inc.
+  "^grinn,.*":
+    description: Grinn
+  "^grmn,.*":
+    description: Garmin Limited
+  "^gumstix,.*":
+    description: Gumstix, Inc.
+  "^gw,.*":
+    description: Gateworks Corporation
+  "^hannstar,.*":
+    description: HannStar Display Corporation
+  "^haoyu,.*":
+    description: Haoyu Microelectronic Co. Ltd.
+  "^hardkernel,.*":
+    description: Hardkernel Co., Ltd
+  "^hideep,.*":
+    description: HiDeep Inc.
+  "^himax,.*":
+    description: Himax Technologies, Inc.
+  "^hisilicon,.*":
+    description: Hisilicon Limited.
+  "^hit,.*":
+    description: Hitachi Ltd.
+  "^hitex,.*":
+    description: Hitex Development Tools
+  "^holt,.*":
+    description: Holt Integrated Circuits, Inc.
+  "^honeywell,.*":
+    description: Honeywell
+  "^hp,.*":
+    description: Hewlett Packard
+  "^holtek,.*":
+    description: Holtek Semiconductor, Inc.
+  "^hwacom,.*":
+    description: HwaCom Systems Inc.
+  "^i2se,.*":
+    description: I2SE GmbH
+  "^ibm,.*":
+    description: International Business Machines (IBM)
+  "^icplus,.*":
+    description: IC Plus Corp.
+  "^idt,.*":
+    description: Integrated Device Technologies, Inc.
+  "^ifi,.*":
+    description: Ingenieurburo Fur Ic-Technologie (I/F/I)
+  "^ilitek,.*":
+    description: ILI Technology Corporation (ILITEK)
+  "^img,.*":
+    description: Imagination Technologies Ltd.
+  "^infineon,.*":
+    description: Infineon Technologies
+  "^inforce,.*":
+    description: Inforce Computing
+  "^ingenic,.*":
+    description: Ingenic Semiconductor
+  "^innolux,.*":
+    description: Innolux Corporation
+  "^inside-secure,.*":
+    description: INSIDE Secure
+  "^intel,.*":
+    description: Intel Corporation
+  "^intercontrol,.*":
+    description: Inter Control Group
+  "^invensense,.*":
+    description: InvenSense Inc.
+  "^inversepath,.*":
+    description: Inverse Path
+  "^iom,.*":
+    description: Iomega Corporation
+  "^isee,.*":
+    description: ISEE 2007 S.L.
+  "^isil,.*":
+    description: Intersil
+  "^issi,.*":
+    description: Integrated Silicon Solutions Inc.
+  "^itead,.*":
+    description: ITEAD Intelligent Systems Co.Ltd
+  "^iwave,.*":
+    description: iWave Systems Technologies Pvt. Ltd.
+  "^jdi,.*":
+    description: Japan Display Inc.
+  "^jedec,.*":
+    description: JEDEC Solid State Technology Association
+  "^jianda,.*":
+    description: Jiandangjing Technology Co., Ltd.
+  "^karo,.*":
+    description: Ka-Ro electronics GmbH
+  "^keithkoep,.*":
+    description: Keith & Koep GmbH
+  "^keymile,.*":
+    description: Keymile GmbH
+  "^khadas,.*":
+    description: Khadas
+  "^kiebackpeter,.*":
+    description: Kieback & Peter GmbH
+  "^kinetic,.*":
+    description: Kinetic Technologies
+  "^kingdisplay,.*":
+    description: King & Display Technology Co., Ltd.
+  "^kingnovel,.*":
+    description: Kingnovel Technology Co., Ltd.
+  "^kionix,.*":
+    description: Kionix, Inc.
+  "^kobo,.*":
+    description: Rakuten Kobo Inc.
+  "^koe,.*":
+    description: Kaohsiung Opto-Electronics Inc.
+  "^kosagi,.*":
+    description: Sutajio Ko-Usagi PTE Ltd.
+  "^kyo,.*":
+    description: Kyocera Corporation
+  "^lacie,.*":
+    description: LaCie
+  "^laird,.*":
+    description: Laird PLC
+  "^lantiq,.*":
+    description: Lantiq Semiconductor
+  "^lattice,.*":
+    description: Lattice Semiconductor
+  "^lego,.*":
+    description: LEGO Systems A/S
+  "^lemaker,.*":
+    description: Shenzhen LeMaker Technology Co., Ltd.
+  "^lenovo,.*":
+    description: Lenovo Group Ltd.
+  "^lg,.*":
+    description: LG Corporation
+  "^libretech,.*":
+    description: Shenzhen Libre Technology Co., Ltd
+  "^licheepi,.*":
+    description: Lichee Pi
+  "^linaro,.*":
+    description: Linaro Limited
+  "^linksys,.*":
+    description: Belkin International, Inc. (Linksys)
+  "^linux,.*":
+    description: Linux-specific binding
+  "^linx,.*":
+    description: Linx Technologies
+  "^lltc,.*":
+    description: Linear Technology Corporation
+  "^logicpd,.*":
+    description: Logic PD, Inc.
+  "^lsi,.*":
+    description: LSI Corp. (LSI Logic)
+  "^lwn,.*":
+    description: Liebherr-Werk Nenzing GmbH
+  "^macnica,.*":
+    description: Macnica Americas
+  "^marvell,.*":
+    description: Marvell Technology Group Ltd.
+  "^maxbotix,.*":
+    description: MaxBotix Inc.
+  "^maxim,.*":
+    description: Maxim Integrated Products
+  "^mbvl,.*":
+    description: Mobiveil Inc.
+  "^mcube,.*":
+    description: mCube
+  "^meas,.*":
+    description: Measurement Specialties
+  "^mediatek,.*":
+    description: MediaTek Inc.
+  "^megachips,.*":
+    description: MegaChips
+  "^mele,.*":
+    description: Shenzhen MeLE Digital Technology Ltd.
+  "^melexis,.*":
+    description: Melexis N.V.
+  "^melfas,.*":
+    description: MELFAS Inc.
+  "^mellanox,.*":
+    description: Mellanox Technologies
+  "^memsic,.*":
+    description: MEMSIC Inc.
+  "^menlo,.*":
+    description: Menlo Systems GmbH
+  "^merrii,.*":
+    description: Merrii Technology Co., Ltd.
+  "^micrel,.*":
+    description: Micrel Inc.
+  "^microchip,.*":
+    description: Microchip Technology Inc.
+  "^microcrystal,.*":
+    description: Micro Crystal AG
+  "^micron,.*":
+    description: Micron Technology Inc.
+  "^mikroe,.*":
+    description: MikroElektronika d.o.o.
+  "^minix,.*":
+    description: MINIX Technology Ltd.
+  "^miramems,.*":
+    description: MiraMEMS Sensing Technology Co., Ltd.
+  "^mitsubishi,.*":
+    description: Mitsubishi Electric Corporation
+  "^mosaixtech,.*":
+    description: Mosaix Technologies, Inc.
+  "^motorola,.*":
+    description: Motorola, Inc.
+  "^moxa,.*":
+    description: Moxa Inc.
+  "^mpl,.*":
+    description: MPL AG
+  "^mqmaker,.*":
+    description: mqmaker Inc.
+  "^mscc,.*":
+    description: Microsemi Corporation
+  "^msi,.*":
+    description: Micro-Star International Co. Ltd.
+  "^mti,.*":
+    description: Imagination Technologies Ltd. (formerly MIPS Technologies Inc.)
+  "^multi-inno,.*":
+    description: Multi-Inno Technology Co.,Ltd
+  "^mundoreader,.*":
+    description: Mundo Reader S.L.
+  "^murata,.*":
+    description: Murata Manufacturing Co., Ltd.
+  "^mxicy,.*":
+    description: Macronix International Co., Ltd.
+  "^myir,.*":
+    description: MYIR Tech Limited
+  "^national,.*":
+    description: National Semiconductor
+  "^nec,.*":
+    description: NEC LCD Technologies, Ltd.
+  "^neonode,.*":
+    description: Neonode Inc.
+  "^netgear,.*":
+    description: NETGEAR
+  "^netlogic,.*":
+    description: Broadcom Corporation (formerly NetLogic Microsystems)
+  "^netron-dy,.*":
+    description: Netron DY
+  "^netxeon,.*":
+    description: Shenzhen Netxeon Technology CO., LTD
+  "^nexbox,.*":
+    description: Nexbox
+  "^nextthing,.*":
+    description: Next Thing Co.
+  "^newhaven,.*":
+    description: Newhaven Display International
+  "^ni,.*":
+    description: National Instruments
+  "^nintendo,.*":
+    description: Nintendo
+  "^nlt,.*":
+    description: NLT Technologies, Ltd.
+  "^nokia,.*":
+    description: Nokia
+  "^nordic,.*":
+    description: Nordic Semiconductor
+  "^novtech,.*":
+    description: NovTech, Inc.
+  "^nutsboard,.*":
+    description: NutsBoard
+  "^nuvoton,.*":
+    description: Nuvoton Technology Corporation
+  "^nvd,.*":
+    description: New Vision Display
+  "^nvidia,.*":
+    description: NVIDIA
+  "^nxp,.*":
+    description: NXP Semiconductors
+  "^oceanic,.*":
+    description: Oceanic Systems (UK) Ltd.
+  "^okaya,.*":
+    description: Okaya Electric America, Inc.
+  "^oki,.*":
+    description: Oki Electric Industry Co., Ltd.
+  "^olimex,.*":
+    description: OLIMEX Ltd.
+  "^olpc,.*":
+    description: One Laptop Per Child
+  "^onion,.*":
+    description: Onion Corporation
+  "^onnn,.*":
+    description: ON Semiconductor Corp.
+  "^ontat,.*":
+    description: On Tat Industrial Company
+  "^opalkelly,.*":
+    description: Opal Kelly Incorporated
+  "^opencores,.*":
+    description: OpenCores.org
+  "^openrisc,.*":
+    description: OpenRISC.io
+  "^option,.*":
+    description: Option NV
+  "^oranth,.*":
+    description: Shenzhen Oranth Technology Co., Ltd.
+  "^ORCL,.*":
+    description: Oracle Corporation
+  "^orisetech,.*":
+    description: Orise Technology
+  "^ortustech,.*":
+    description: Ortus Technology Co., Ltd.
+  "^osddisplays,.*":
+    description: OSD Displays
+  "^ovti,.*":
+    description: OmniVision Technologies
+  "^oxsemi,.*":
+    description: Oxford Semiconductor, Ltd.
+  "^panasonic,.*":
+    description: Panasonic Corporation
+  "^parade,.*":
+    description: Parade Technologies Inc.
+  "^pda,.*":
+    description: Precision Design Associates, Inc.
+  "^pericom,.*":
+    description: Pericom Technology Inc.
+  "^pervasive,.*":
+    description: Pervasive Displays, Inc.
+  "^phicomm,.*":
+    description: PHICOMM Co., Ltd.
+  "^phytec,.*":
+    description: PHYTEC Messtechnik GmbH
+  "^picochip,.*":
+    description: Picochip Ltd
+  "^pine64,.*":
+    description: Pine64
+  "^pixcir,.*":
+    description: PIXCIR MICROELECTRONICS Co., Ltd
+  "^plantower,.*":
+    description: Plantower Co., Ltd
+  "^plathome,.*":
+    description: Plat'Home Co., Ltd.
+  "^plda,.*":
+    description: PLDA
+  "^plx,.*":
+    description: Broadcom Corporation (formerly PLX Technology)
+  "^pni,.*":
+    description: PNI Sensor Corporation
+  "^portwell,.*":
+    description: Portwell Inc.
+  "^poslab,.*":
+    description: Poslab Technology Co., Ltd.
+  "^powervr,.*":
+    description: PowerVR (deprecated, use img)
+  "^probox2,.*":
+    description: PROBOX2 (by W2COMP Co., Ltd.)
+  "^pulsedlight,.*":
+    description: PulsedLight, Inc
+  "^qca,.*":
+    description: Qualcomm Atheros, Inc.
+  "^qcom,.*":
+    description: Qualcomm Technologies, Inc
+  "^qemu,.*":
+    description: QEMU, a generic and open source machine emulator and virtualizer
+  "^qi,.*":
+    description: Qi Hardware
+  "^qiaodian,.*":
+    description: QiaoDian XianShi Corporation
+  "^qnap,.*":
+    description: QNAP Systems, Inc.
+  "^radxa,.*":
+    description: Radxa
+  "^raidsonic,.*":
+    description: RaidSonic Technology GmbH
+  "^ralink,.*":
+    description: Mediatek/Ralink Technology Corp.
+  "^ramtron,.*":
+    description: Ramtron International
+  "^raspberrypi,.*":
+    description: Raspberry Pi Foundation
+  "^raydium,.*":
+    description: Raydium Semiconductor Corp.
+  "^rda,.*":
+    description: Unisoc Communications, Inc.
+  "^realtek,.*":
+    description: Realtek Semiconductor Corp.
+  "^renesas,.*":
+    description: Renesas Electronics Corporation
+  "^richtek,.*":
+    description: Richtek Technology Corporation
+  "^ricoh,.*":
+    description: Ricoh Co. Ltd.
+  "^rikomagic,.*":
+    description: Rikomagic Tech Corp. Ltd
+  "^riscv,.*":
+    description: RISC-V Foundation
+  "^rockchip,.*":
+    description: Fuzhou Rockchip Electronics Co., Ltd
+  "^rocktech,.*":
+    description: ROCKTECH DISPLAYS LIMITED
+  "^rohm,.*":
+    description: ROHM Semiconductor Co., Ltd
+  "^ronbo,.*":
+    description: Ronbo Electronics
+  "^roofull,.*":
+    description: Shenzhen Roofull Technology Co, Ltd
+  "^samsung,.*":
+    description: Samsung Semiconductor
+  "^samtec,.*":
+    description: Samtec/Softing company
+  "^sancloud,.*":
+    description: Sancloud Ltd
+  "^sandisk,.*":
+    description: Sandisk Corporation
+  "^sbs,.*":
+    description: Smart Battery System
+  "^schindler,.*":
+    description: Schindler
+  "^seagate,.*":
+    description: Seagate Technology PLC
+  "^seirobotics,.*":
+    description: Shenzhen SEI Robotics Co., Ltd
+  "^semtech,.*":
+    description: Semtech Corporation
+  "^sensirion,.*":
+    description: Sensirion AG
+  "^sff,.*":
+    description: Small Form Factor Committee
+  "^sgd,.*":
+    description: Solomon Goldentek Display Corporation
+  "^sgx,.*":
+    description: SGX Sensortech
+  "^sharp,.*":
+    description: Sharp Corporation
+  "^shimafuji,.*":
+    description: Shimafuji Electric, Inc.
+  "^si-en,.*":
+    description: Si-En Technology Ltd.
+  "^si-linux,.*":
+    description: Silicon Linux Corporation
+  "^sifive,.*":
+    description: SiFive, Inc.
+  "^sigma,.*":
+    description: Sigma Designs, Inc.
+  "^sii,.*":
+    description: Seiko Instruments, Inc.
+  "^sil,.*":
+    description: Silicon Image
+  "^silabs,.*":
+    description: Silicon Laboratories
+  "^silead,.*":
+    description: Silead Inc.
+  "^silergy,.*":
+    description: Silergy Corp.
+  "^siliconmitus,.*":
+    description: Silicon Mitus, Inc.
+  "^simte,.*":
+    description: k
+  "^sirf,.*":
+    description: SiRF Technology, Inc.
+  "^sis,.*":
+    description: Silicon Integrated Systems Corp.
+  "^sitronix,.*":
+    description: Sitronix Technology Corporation
+  "^skyworks,.*":
+    description: Skyworks Solutions, Inc.
+  "^smsc,.*":
+    description: Standard Microsystems Corporation
+  "^snps,.*":
+    description: Synopsys, Inc.
+  "^socionext,.*":
+    description: Socionext Inc.
+  "^solidrun,.*":
+    description: SolidRun
+  "^solomon,.*":
+    description: Solomon Systech Limited
+  "^sony,.*":
+    description: Sony Corporation
+  "^spansion,.*":
+    description: Spansion Inc.
+  "^sprd,.*":
+    description: Spreadtrum Communications Inc.
+  "^sst,.*":
+    description: Silicon Storage Technology, Inc.
+  "^st,.*":
+    description: STMicroelectronics
+  "^starry,.*":
+    description: Starry Electronic Technology (ShenZhen) Co., LTD
+  "^startek,.*":
+    description: Startek
+  "^ste,.*":
+    description: ST-Ericsson
+  "^stericsson,.*":
+    description: ST-Ericsson
+  "^summit,.*":
+    description: Summit microelectronics
+  "^sunchip,.*":
+    description: Shenzhen Sunchip Technology Co., Ltd
+  "^SUNW,.*":
+    description: Sun Microsystems, Inc
+  "^swir,.*":
+    description: Sierra Wireless
+  "^syna,.*":
+    description: Synaptics Inc.
+  "^synology,.*":
+    description: Synology, Inc.
+  "^tbs,.*":
+    description: TBS Technologies
+  "^tbs-biometrics,.*":
+    description: Touchless Biometric Systems AG
+  "^tcg,.*":
+    description: Trusted Computing Group
+  "^tcl,.*":
+    description: Toby Churchill Ltd.
+  "^technexion,.*":
+    description: TechNexion
+  "^technologic,.*":
+    description: Technologic Systems
+  "^tempo,.*":
+    description: Tempo Semiconductor
+  "^techstar,.*":
+    description: Shenzhen Techstar Electronics Co., Ltd.
+  "^terasic,.*":
+    description: Terasic Inc.
+  "^thine,.*":
+    description: THine Electronics, Inc.
+  "^ti,.*":
+    description: Texas Instruments
+  "^tianma,.*":
+    description: Tianma Micro-electronics Co., Ltd.
+  "^tlm,.*":
+    description: Trusted Logic Mobility
+  "^tmt,.*":
+    description: Tecon Microprocessor Technologies, LLC.
+  "^topeet,.*":
+    description: Topeet
+  "^toradex,.*":
+    description: Toradex AG
+  "^toshiba,.*":
+    description: Toshiba Corporation
+  "^toumaz,.*":
+    description: Toumaz
+  "^tpk,.*":
+    description: TPK U.S.A. LLC
+  "^tplink,.*":
+    description: TP-LINK Technologies Co., Ltd.
+  "^tpo,.*":
+    description: TPO
+  "^tq,.*":
+    description: TQ Systems GmbH
+  "^tronfy,.*":
+    description: Tronfy
+  "^tronsmart,.*":
+    description: Tronsmart
+  "^truly,.*":
+    description: Truly Semiconductors Limited
+  "^tsd,.*":
+    description: Theobroma Systems Design und Consulting GmbH
+  "^tyan,.*":
+    description: Tyan Computer Corporation
+  "^u-blox,.*":
+    description: u-blox
+  "^ucrobotics,.*":
+    description: uCRobotics
+  "^ubnt,.*":
+    description: Ubiquiti Networks
+  "^udoo,.*":
+    description: Udoo
+  "^uniwest,.*":
+    description: United Western Technologies Corp (UniWest)
+  "^upisemi,.*":
+    description: uPI Semiconductor Corp.
+  "^urt,.*":
+    description: United Radiant Technology Corporation
+  "^usi,.*":
+    description: Universal Scientific Industrial Co., Ltd.
+  "^v3,.*":
+    description: V3 Semiconductor
+  "^vamrs,.*":
+    description: Vamrs Ltd.
+  "^variscite,.*":
+    description: Variscite Ltd.
+  "^via,.*":
+    description: VIA Technologies, Inc.
+  "^virtio,.*":
+    description: Virtual I/O Device Specification, developed by the OASIS consortium
+  "^vishay,.*":
+    description: Vishay Intertechnology, Inc
+  "^vitesse,.*":
+    description: Vitesse Semiconductor Corporation
+  "^vivante,.*":
+    description: Vivante Corporation
+  "^vocore,.*":
+    description: VoCore Studio
+  "^voipac,.*":
+    description: Voipac Technologies s.r.o.
+  "^vot,.*":
+    description: Vision Optical Technology Co., Ltd.
+  "^wd,.*":
+    description: Western Digital Corp.
+  "^wetek,.*":
+    description: WeTek Electronics, limited.
+  "^wexler,.*":
+    description: Wexler
+  "^whwave,.*":
+    description: Shenzhen whwave Electronics, Inc.
+  "^wi2wi,.*":
+    description: Wi2Wi, Inc.
+  "^winbond,.*":
+    description: Winbond Electronics corp.
+  "^winstar,.*":
+    description: Winstar Display Corp.
+  "^wlf,.*":
+    description: Wolfson Microelectronics
+  "^wm,.*":
+    description: Wondermedia Technologies, Inc.
+  "^x-powers,.*":
+    description: X-Powers
+  "^xes,.*":
+    description: Extreme Engineering Solutions (X-ES)
+  "^xillybus,.*":
+    description: Xillybus Ltd.
+  "^xlnx,.*":
+    description: Xilinx
+  "^xunlong,.*":
+    description: Shenzhen Xunlong Software CO.,Limited
+  "^ysoft,.*":
+    description: Y Soft Corporation a.s.
+  "^zarlink,.*":
+    description: Zarlink Semiconductor
+  "^zeitec,.*":
+    description: ZEITEC Semiconductor Co., LTD.
+  "^zidoo,.*":
+    description: Shenzhen Zidoo Technology Co., Ltd.
+  "^zii,.*":
+    description: Zodiac Inflight Innovations
+  "^zte,.*":
+    description: ZTE Corp.
+  "^zyxel,.*":
+    description: ZyXEL Communications Corp.
+
+  # Normal property name match without a comma
+  # These should catch all node/property names without a prefix
+  "^[a-zA-Z0-9#][a-zA-Z0-9+\\-._@]{0,63}$": true
+  "^[a-zA-Z0-9+\\-._]*@[0-9a-zA-Z,]*$": true
+  "^#.*": true
+
+additionalProperties: false
+
+...
diff --git a/Documentation/devicetree/bindings/watchdog/fsl-imx-sc-wdt.txt b/Documentation/devicetree/bindings/watchdog/fsl-imx-sc-wdt.txt
new file mode 100644 (file)
index 0000000..02b87e9
--- /dev/null
@@ -0,0 +1,24 @@
+* Freescale i.MX System Controller Watchdog
+
+i.MX system controller watchdog is for i.MX SoCs with system controller inside,
+the watchdog is managed by system controller, users can ONLY communicate with
+system controller from secure mode for watchdog operations, so Linux i.MX system
+controller watchdog driver will call ARM SMC API and trap into ARM-Trusted-Firmware
+for watchdog operations, ARM-Trusted-Firmware is running at secure EL3 mode and
+it will request system controller to execute the watchdog operation passed from
+Linux kernel.
+
+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.
+
+Examples:
+
+watchdog {
+       compatible = "fsl,imx8qxp-sc-wdt", "fsl,imx-sc-wdt";
+       timeout-sec = <60>;
+};
index 8682d6a93e5b7ef74e358a8e118e4dcceab1f254..fd380eb28df59f725d34fa8d816c3f866c882edb 100644 (file)
@@ -9,6 +9,7 @@ Required properties:
        "mediatek,mt7622-wdt", "mediatek,mt6589-wdt": for MT7622
        "mediatek,mt7623-wdt", "mediatek,mt6589-wdt": for MT7623
        "mediatek,mt7629-wdt", "mediatek,mt6589-wdt": for MT7629
+       "mediatek,mt8516-wdt", "mediatek,mt6589-wdt": for MT8516
 
 - reg : Specifies base physical address and size of the registers.
 
index 3043167fc557e2a239421ddcead6992d59018830..1ce7fcd0f989442598c00ed4540023ad68fb54af 100644 (file)
@@ -1,10 +1,8 @@
-================================
-GPIO Descriptor Driver Interface
-================================
+=====================
+GPIO Driver Interface
+=====================
 
-This document serves as a guide for GPIO chip drivers writers. Note that it
-describes the new descriptor-based interface. For a description of the
-deprecated integer-based GPIO interface please refer to gpio-legacy.txt.
+This document serves as a guide for writers of GPIO chip drivers.
 
 Each GPIO controller driver needs to include the following header, which defines
 the structures used to define a GPIO driver:
@@ -15,32 +13,49 @@ the structures used to define a GPIO driver:
 Internal Representation of GPIOs
 ================================
 
-Inside a GPIO driver, individual GPIOs are identified by their hardware number,
-which is a unique number between 0 and n, n being the number of GPIOs managed by
-the chip. This number is purely internal: the hardware number of a particular
-GPIO descriptor is never made visible outside of the driver.
-
-On top of this internal number, each GPIO also need to have a global number in
-the integer GPIO namespace so that it can be used with the legacy GPIO
+A GPIO chip handles one or more GPIO lines. To be considered a GPIO chip, the
+lines must conform to the definition: General Purpose Input/Output. If the
+line is not general purpose, it is not GPIO and should not be handled by a
+GPIO chip. The use case is the indicative: certain lines in a system may be
+called GPIO but serve a very particular purpose thus not meeting the criteria
+of a general purpose I/O. On the other hand a LED driver line may be used as a
+GPIO and should therefore still be handled by a GPIO chip driver.
+
+Inside a GPIO driver, individual GPIO lines are identified by their hardware
+number, sometime also referred to as ``offset``, which is a unique number
+between 0 and n-1, n being the number of GPIOs managed by the chip.
+
+The hardware GPIO number should be something intuitive to the hardware, for
+example if a system uses a memory-mapped set of I/O-registers where 32 GPIO
+lines are handled by one bit per line in a 32-bit register, it makes sense to
+use hardware offsets 0..31 for these, corresponding to bits 0..31 in the
+register.
+
+This number is purely internal: the hardware number of a particular GPIO
+line is never made visible outside of the driver.
+
+On top of this internal number, each GPIO line also needs to have a global
+number in the integer GPIO namespace so that it can be used with the legacy GPIO
 interface. Each chip must thus have a "base" number (which can be automatically
-assigned), and for each GPIO the global number will be (base + hardware number).
-Although the integer representation is considered deprecated, it still has many
-users and thus needs to be maintained.
+assigned), and for each GPIO line the global number will be (base + hardware
+number). Although the integer representation is considered deprecated, it still
+has many users and thus needs to be maintained.
 
-So for example one platform could use numbers 32-159 for GPIOs, with a
+So for example one platform could use global numbers 32-159 for GPIOs, with a
 controller defining 128 GPIOs at a "base" of 32 ; while another platform uses
-numbers 0..63 with one set of GPIO controllers, 64-79 with another type of GPIO
-controller, and on one particular board 80-95 with an FPGA. The numbers need not
-be contiguous; either of those platforms could also use numbers 2000-2063 to
-identify GPIOs in a bank of I2C GPIO expanders.
+global numbers 0..63 with one set of GPIO controllers, 64-79 with another type
+of GPIO controller, and on one particular board 80-95 with an FPGA. The legacy
+numbers need not be contiguous; either of those platforms could also use numbers
+2000-2063 to identify GPIO lines in a bank of I2C GPIO expanders.
 
 
 Controller Drivers: gpio_chip
 =============================
 
 In the gpiolib framework each GPIO controller is packaged as a "struct
-gpio_chip" (see linux/gpio/driver.h for its complete definition) with members
-common to each controller of that type:
+gpio_chip" (see <linux/gpio/driver.h> for its complete definition) with members
+common to each controller of that type, these should be assigned by the
+driver code:
 
  - methods to establish GPIO line direction
  - methods used to access GPIO line values
@@ -48,12 +63,12 @@ common to each controller of that type:
  - method to return the IRQ number associated to a given GPIO line
  - flag saying whether calls to its methods may sleep
  - optional line names array to identify lines
- - optional debugfs dump method (showing extra state like pullup config)
+ - optional debugfs dump method (showing extra state information)
  - optional base number (will be automatically assigned if omitted)
  - optional label for diagnostics and GPIO chip mapping using platform data
 
 The code implementing a gpio_chip should support multiple instances of the
-controller, possibly using the driver model. That code will configure each
+controller, preferably using the driver model. That code will configure each
 gpio_chip and issue ``gpiochip_add[_data]()`` or ``devm_gpiochip_add_data()``.
 Removing a GPIO controller should be rare; use ``[devm_]gpiochip_remove()``
 when it is unavoidable.
@@ -62,24 +77,28 @@ Often a gpio_chip is part of an instance-specific structure with states not
 exposed by the GPIO interfaces, such as addressing, power management, and more.
 Chips such as audio codecs will have complex non-GPIO states.
 
-Any debugfs dump method should normally ignore signals which haven't been
-requested as GPIOs. They can use gpiochip_is_requested(), which returns either
-NULL or the label associated with that GPIO when it was requested.
+Any debugfs dump method should normally ignore lines which haven't been
+requested. They can use gpiochip_is_requested(), which returns either
+NULL or the label associated with that GPIO line when it was requested.
 
-RT_FULL: the GPIO driver should not use spinlock_t or any sleepable APIs
-(like PM runtime) in its gpio_chip implementation (.get/.set and direction
-control callbacks) if it is expected to call GPIO APIs from atomic context
-on -RT (inside hard IRQ handlers and similar contexts). Normally this should
-not be required.
+Realtime considerations: the GPIO driver should not use spinlock_t or any
+sleepable APIs (like PM runtime) in its gpio_chip implementation (.get/.set
+and direction control callbacks) if it is expected to call GPIO APIs from
+atomic context on realtime kernels (inside hard IRQ handlers and similar
+contexts). Normally this should not be required.
 
 
 GPIO electrical configuration
 -----------------------------
 
-GPIOs can be configured for several electrical modes of operation by using the
-.set_config() callback. Currently this API supports setting debouncing and
-single-ended modes (open drain/open source). These settings are described
-below.
+GPIO lines can be configured for several electrical modes of operation by using
+the .set_config() callback. Currently this API supports setting:
+
+- Debouncing
+- Single-ended modes (open drain/open source)
+- Pull up and pull down resistor enablement
+
+These settings are described below.
 
 The .set_config() callback uses the same enumerators and configuration
 semantics as the generic pin control drivers. This is not a coincidence: it is
@@ -94,8 +113,8 @@ description needs to provide "GPIO ranges" mapping the GPIO line offsets to pin
 numbers on the pin controller so they can properly cross-reference each other.
 
 
-GPIOs with debounce support
----------------------------
+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
@@ -111,8 +130,8 @@ a certain number of milliseconds for debouncing, or just "on/off" if that time
 is not configurable.
 
 
-GPIOs with open drain/source support
-------------------------------------
+GPIO lines with open drain/source support
+-----------------------------------------
 
 Open drain (CMOS) or open collector (TTL) means the line is not actively driven
 high: instead you provide the drain/collector as output, so when the transistor
@@ -132,13 +151,13 @@ This configuration is normally used as a way to achieve one of two things:
 - Level-shifting: to reach a logical level higher than that of the silicon
   where the output resides.
 
-- inverse wire-OR on an I/O line, for example a GPIO line, making it possible
+- Inverse wire-OR on an I/O line, for example a GPIO line, making it possible
   for any driving stage on the line to drive it low even if any other output
   to the same line is simultaneously driving it high. A special case of this
   is driving the SCL and SDA lines of an I2C bus, which is by definition a
   wire-OR bus.
 
-Both usecases require that the line be equipped with a pull-up resistor. This
+Both use cases require that the line be equipped with a pull-up resistor. This
 resistor will make the line tend to high level unless one of the transistors on
 the rail actively pulls it down.
 
@@ -208,27 +227,91 @@ For open source configuration the same principle is used, just that instead
 of actively driving the line low, it is set to input.
 
 
+GPIO lines with pull up/down resistor support
+---------------------------------------------
+
+A GPIO line can support pull-up/down using the .set_config() callback. This
+means that a pull up or pull-down resistor is available on the output of the
+GPIO line, and this resistor is software controlled.
+
+In discrete designs, a pull-up or pull-down resistor is simply soldered on
+the circuit board. This is not something we deal or model in software. The
+most you will think about these lines is that they will very likely be
+configured as open drain or open source (see the section above).
+
+The .set_config() callback can only turn pull up or down on and off, and will
+no have any semantic knowledge about the resistance used. It will only say
+switch a bit in a register enabling or disabling pull-up or pull-down.
+
+If the GPIO line supports shunting in different resistance values for the
+pull-up or pull-down resistor, the GPIO chip callback .set_config() will not
+suffice. For these complex use cases, a combined GPIO chip and pin controller
+need to be implemented, as the pin config interface of a pin controller
+supports more versatile control over electrical properties and can handle
+different pull-up or pull-down resistance values.
+
+
 GPIO drivers providing IRQs
----------------------------
+===========================
+
 It is custom that GPIO drivers (GPIO chips) are also providing interrupts,
 most often cascaded off a parent interrupt controller, and in some special
 cases the GPIO logic is melded with a SoC's primary interrupt controller.
 
-The IRQ portions of the GPIO block are implemented using an irqchip, using
+The IRQ portions of the GPIO block are implemented using an irq_chip, using
 the header <linux/irq.h>. So basically such a driver is utilizing two sub-
 systems simultaneously: gpio and irq.
 
-RT_FULL: a realtime compliant GPIO driver should not use spinlock_t or any
-sleepable APIs (like PM runtime) as part of its irq_chip implementation.
+It is legal for any IRQ consumer to request an IRQ from any irqchip even if it
+is a combined GPIO+IRQ driver. The basic premise is that gpio_chip and
+irq_chip are orthogonal, and offering their services independent of each
+other.
 
-* spinlock_t should be replaced with raw_spinlock_t [1].
-* If sleepable APIs have to be used, these can be done from the .irq_bus_lock()
+gpiod_to_irq() is just a convenience function to figure out the IRQ for a
+certain GPIO line and should not be relied upon to have been called before
+the IRQ is used.
+
+Always prepare the hardware and make it ready for action in respective
+callbacks from the GPIO and irq_chip APIs. Do not rely on gpiod_to_irq() having
+been called first.
+
+We can divide GPIO irqchips in two broad categories:
+
+- CASCADED INTERRUPT CHIPS: this means that the GPIO chip has one common
+  interrupt output line, which is triggered by any enabled GPIO line on that
+  chip. The interrupt output line will then be routed to an parent interrupt
+  controller one level up, in the most simple case the systems primary
+  interrupt controller. This is modeled by an irqchip that will inspect bits
+  inside the GPIO controller to figure out which line fired it. The irqchip
+  part of the driver needs to inspect registers to figure this out and it
+  will likely also need to acknowledge that it is handling the interrupt
+  by clearing some bit (sometime implicitly, by just reading a status
+  register) and it will often need to set up the configuration such as
+  edge sensitivity (rising or falling edge, or high/low level interrupt for
+  example).
+
+- HIERARCHICAL INTERRUPT CHIPS: this means that each GPIO line has a dedicated
+  irq line to a parent interrupt controller one level up. There is no need
+  to inquire the GPIO hardware to figure out which line has figured, but it
+  may still be necessary to acknowledge the interrupt and set up the
+  configuration such as edge sensitivity.
+
+Realtime considerations: a realtime compliant GPIO driver should not use
+spinlock_t or any sleepable APIs (like PM runtime) as part of its irqchip
+implementation.
+
+- spinlock_t should be replaced with raw_spinlock_t [1].
+- If sleepable APIs have to be used, these can be done from the .irq_bus_lock()
   and .irq_bus_unlock() callbacks, as these are the only slowpath callbacks
   on an irqchip. Create the callbacks if needed [2].
 
-GPIO irqchips usually fall in one of two categories:
 
-* CHAINED GPIO irqchips: these are usually the type that is embedded on
+Cascaded GPIO irqchips
+----------------------
+
+Cascaded GPIO irqchips usually fall in one of three categories:
+
+- CHAINED CASCADED GPIO IRQCHIPS: these are usually the type that is embedded on
   an SoC. This means that there is a fast IRQ flow handler for the GPIOs that
   gets called in a chain from the parent IRQ handler, most typically the
   system interrupt controller. This means that the GPIO irqchip handler will
@@ -245,16 +328,19 @@ GPIO irqchips usually fall in one of two categories:
   struct gpio_chip, as everything happens directly in the callbacks: no
   slow bus traffic like I2C can be used.
 
-  RT_FULL: Note, chained IRQ handlers will not be forced threaded on -RT.
-  As result, spinlock_t or any sleepable APIs (like PM runtime) can't be used
-  in chained IRQ handler.
-  If required (and if it can't be converted to the nested threaded GPIO irqchip)
-  a chained IRQ handler can be converted to generic irq handler and this way
-  it will be a threaded IRQ handler on -RT and a hard IRQ handler on non-RT
-  (for example, see [3]).
-  Know W/A: The generic_handle_irq() is expected to be called with IRQ disabled,
+  Realtime considerations: Note that chained IRQ handlers will not be forced
+  threaded on -RT. As a result, spinlock_t or any sleepable APIs (like PM
+  runtime) can't be used in a chained IRQ handler.
+
+  If required (and if it can't be converted to the nested threaded GPIO irqchip,
+  see below) a chained IRQ handler can be converted to generic irq handler and
+  this way it will become a threaded IRQ handler on -RT and a hard IRQ handler
+  on non-RT (for example, see [3]).
+
+  The generic_handle_irq() is expected to be called with IRQ disabled,
   so the IRQ core will complain if it is called from an IRQ handler which is
-  forced to a thread. The "fake?" raw lock can be used to W/A this problem::
+  forced to a thread. The "fake?" raw lock can be used to work around this
+  problem::
 
        raw_spinlock_t wa_lock;
        static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
@@ -263,7 +349,7 @@ GPIO irqchips usually fall in one of two categories:
                generic_handle_irq(irq_find_mapping(bank->chip.irq.domain, bit));
                raw_spin_unlock_irqrestore(&bank->wa_lock, wa_lock_flags);
 
-* GENERIC CHAINED GPIO irqchips: these are the same as "CHAINED GPIO irqchips",
+- GENERIC CHAINED GPIO IRQCHIPS: these are the same as "CHAINED GPIO irqchips",
   but chained IRQ handlers are not used. Instead GPIO IRQs dispatching is
   performed by generic IRQ handler which is configured using request_irq().
   The GPIO irqchip will then end up calling something like this sequence in
@@ -273,16 +359,19 @@ GPIO irqchips usually fall in one of two categories:
         for each detected GPIO IRQ
             generic_handle_irq(...);
 
-  RT_FULL: Such kind of handlers will be forced threaded on -RT, as result IRQ
-  core will complain that generic_handle_irq() is called with IRQ enabled and
-  the same W/A as for "CHAINED GPIO irqchips" can be applied.
+  Realtime considerations: this kind of handlers will be forced threaded on -RT,
+  and as result the IRQ core will complain that generic_handle_irq() is called
+  with IRQ enabled and the same work around as for "CHAINED GPIO irqchips" can
+  be applied.
+
+- NESTED THREADED GPIO IRQCHIPS: these are off-chip GPIO expanders and any
+  other GPIO irqchip residing on the other side of a sleeping bus such as I2C
+  or SPI.
 
-* NESTED THREADED GPIO irqchips: these are off-chip GPIO expanders and any
-  other GPIO irqchip residing on the other side of a sleeping bus. Of course
-  such drivers that need slow bus traffic to read out IRQ status and similar,
-  traffic which may in turn incur other IRQs to happen, cannot be handled
-  in a quick IRQ handler with IRQs disabled. Instead they need to spawn a
-  thread and then mask the parent IRQ line until the interrupt is handled
+  Of course such drivers that need slow bus traffic to read out IRQ status and
+  similar, traffic which may in turn incur other IRQs to happen, cannot be
+  handled in a quick IRQ handler with IRQs disabled. Instead they need to spawn
+  a thread and then mask the parent IRQ line until the interrupt is handled
   by the driver. The hallmark of this driver is to call something like
   this in its interrupt handler::
 
@@ -294,36 +383,46 @@ GPIO irqchips usually fall in one of two categories:
   flag on struct gpio_chip to true, indicating that this chip may sleep
   when accessing the GPIOs.
 
+  These kinds of irqchips are inherently realtime tolerant as they are
+  already set up to handle sleeping contexts.
+
+
+Infrastructure helpers for GPIO irqchips
+----------------------------------------
+
 To help out in handling the set-up and management of GPIO irqchips and the
 associated irqdomain and resource allocation callbacks, the gpiolib has
 some helpers that can be enabled by selecting the GPIOLIB_IRQCHIP Kconfig
 symbol:
 
-* gpiochip_irqchip_add(): adds a chained irqchip to a gpiochip. It will pass
-  the struct gpio_chip* for the chip to all IRQ callbacks, so the callbacks
-  need to embed the gpio_chip in its state container and obtain a pointer
-  to the container using container_of().
+- gpiochip_irqchip_add(): adds a chained cascaded irqchip to a gpiochip. It
+  will pass the struct gpio_chip* for the chip to all IRQ callbacks, so the
+  callbacks need to embed the gpio_chip in its state container and obtain a
+  pointer to the container using container_of().
   (See Documentation/driver-model/design-patterns.txt)
 
-* gpiochip_irqchip_add_nested(): adds a nested irqchip to a gpiochip.
+- gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip,
+  as discussed above regarding different types of cascaded irqchips. The
+  cascaded irq has to be handled by a threaded interrupt handler.
   Apart from that it works exactly like the chained irqchip.
 
-* gpiochip_set_chained_irqchip(): sets up a chained irq handler for a
+- gpiochip_set_chained_irqchip(): sets up a chained cascaded irq handler for a
   gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler
-  data. (Notice handler data, since the irqchip data is likely used by the
-  parent irqchip!).
+  data. Notice that we pass is as the handler data, since the irqchip data is
+  likely used by the parent irqchip.
 
-* gpiochip_set_nested_irqchip(): sets up a nested irq handler for a
+- gpiochip_set_nested_irqchip(): sets up a nested cascaded irq handler for a
   gpio_chip from a parent IRQ. As the parent IRQ has usually been
   explicitly requested by the driver, this does very little more than
   mark all the child IRQs as having the other IRQ as parent.
 
-If there is a need to exclude certain GPIOs from the IRQ domain, you can
-set .irq.need_valid_mask of the gpiochip before gpiochip_add_data() is
-called. This allocates an .irq.valid_mask with as many bits set as there
-are GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this
-mask. The mask must be filled in before gpiochip_irqchip_add() or
-gpiochip_irqchip_add_nested() is called.
+If there is a need to exclude certain GPIO lines from the IRQ domain handled by
+these helpers, we can set .irq.need_valid_mask of the gpiochip before
+[devm_]gpiochip_add_data() is called. This allocates an .irq.valid_mask with as
+many bits set as there are GPIO lines in the chip, each bit representing line
+0..n-1. Drivers can exclude GPIO lines by clearing bits from this mask. The mask
+must be filled in before gpiochip_irqchip_add() or gpiochip_irqchip_add_nested()
+is called.
 
 To use the helpers please keep the following in mind:
 
@@ -333,33 +432,24 @@ To use the helpers please keep the following in mind:
 
 - Nominally set all handlers to handle_bad_irq() in the setup call and pass
   handle_bad_irq() as flow handler parameter in gpiochip_irqchip_add() if it is
-  expected for GPIO driver that irqchip .set_type() callback have to be called
-  before using/enabling GPIO IRQ. Then set the handler to handle_level_irq()
-  and/or handle_edge_irq() in the irqchip .set_type() callback depending on
-  what your controller supports.
+  expected for GPIO driver that irqchip .set_type() callback will be called
+  before using/enabling each GPIO IRQ. Then set the handler to
+  handle_level_irq() and/or handle_edge_irq() in the irqchip .set_type()
+  callback depending on what your controller supports and what is requested
+  by the consumer.
 
-It is legal for any IRQ consumer to request an IRQ from any irqchip no matter
-if that is a combined GPIO+IRQ driver. The basic premise is that gpio_chip and
-irq_chip are orthogonal, and offering their services independent of each
-other.
-
-gpiod_to_irq() is just a convenience function to figure out the IRQ for a
-certain GPIO line and should not be relied upon to have been called before
-the IRQ is used.
 
-So always prepare the hardware and make it ready for action in respective
-callbacks from the GPIO and irqchip APIs. Do not rely on gpiod_to_irq() having
-been called first.
+Locking IRQ usage
+-----------------
 
-This orthogonality leads to ambiguities that we need to solve: if there is
-competition inside the subsystem which side is using the resource (a certain
-GPIO line and register for example) it needs to deny certain operations and
-keep track of usage inside of the gpiolib subsystem. This is why the API
-below exists.
+Since GPIO and irq_chip are orthogonal, we can get conflicts between different
+use cases. For example a GPIO line used for IRQs should be an input line,
+it does not make sense to fire interrupts on an output GPIO.
 
+If there is competition inside the subsystem which side is using the
+resource (a certain GPIO line and register for example) it needs to deny
+certain operations and keep track of usage inside of the gpiolib subsystem.
 
-Locking IRQ usage
------------------
 Input GPIOs can be used as IRQ signals. When this happens, a driver is requested
 to mark the GPIO as being used as an IRQ::
 
@@ -380,9 +470,15 @@ assigned.
 
 Disabling and enabling IRQs
 ---------------------------
+
+In some (fringe) use cases, a driver may be using a GPIO line as input for IRQs,
+but occasionally switch that line over to drive output and then back to being
+an input with interrupts again. This happens on things like CEC (Consumer
+Electronics Control).
+
 When a GPIO is used as an IRQ signal, then gpiolib also needs to know if
 the IRQ is enabled or disabled. In order to inform gpiolib about this,
-a driver should call::
+the irqchip driver should call::
 
        void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset)
 
@@ -398,40 +494,45 @@ irqchip.
 When using the gpiolib irqchip helpers, these callbacks are automatically
 assigned.
 
+
 Real-Time compliance for GPIO IRQ chips
 ---------------------------------------
 
-Any provider of irqchips needs to be carefully tailored to support Real Time
+Any provider of irqchips needs to be carefully tailored to support Real-Time
 preemption. It is desirable that all irqchips in the GPIO subsystem keep this
 in mind and do the proper testing to assure they are real time-enabled.
-So, pay attention on above " RT_FULL:" notes, please.
-The following is a checklist to follow when preparing a driver for real
-time-compliance:
 
-- ensure spinlock_t is not used as part irq_chip implementation;
-- ensure that sleepable APIs are not used as part irq_chip implementation.
+So, pay attention on above realtime considerations in the documentation.
+
+The following is a checklist to follow when preparing a driver for real-time
+compliance:
+
+- ensure spinlock_t is not used as part irq_chip implementation
+- ensure that sleepable APIs are not used as part irq_chip implementation
   If sleepable APIs have to be used, these can be done from the .irq_bus_lock()
-  and .irq_bus_unlock() callbacks;
+  and .irq_bus_unlock() callbacks
 - Chained GPIO irqchips: ensure spinlock_t or any sleepable APIs are not used
-  from chained IRQ handler;
+  from the chained IRQ handler
 - Generic chained GPIO irqchips: take care about generic_handle_irq() calls and
-  apply corresponding W/A;
-- Chained GPIO irqchips: get rid of chained IRQ handler and use generic irq
-  handler if possible :)
-- regmap_mmio: Sry, but you are in trouble :( if MMIO regmap is used as for
-  GPIO IRQ chip implementation;
-- Test your driver with the appropriate in-kernel real time test cases for both
-  level and edge IRQs.
+  apply corresponding work-around
+- Chained GPIO irqchips: get rid of the chained IRQ handler and use generic irq
+  handler if possible
+- regmap_mmio: it is possible to disable internal locking in regmap by setting
+  .disable_locking and handling the locking in the GPIO driver
+- Test your driver with the appropriate in-kernel real-time test cases for both
+  level and edge IRQs
+
+* [1] http://www.spinics.net/lists/linux-omap/msg120425.html
+* [2] https://lkml.org/lkml/2015/9/25/494
+* [3] https://lkml.org/lkml/2015/9/25/495
 
 
 Requesting self-owned GPIO pins
--------------------------------
+===============================
 
 Sometimes it is useful to allow a GPIO chip driver to request its own GPIO
-descriptors through the gpiolib API. Using gpio_request() for this purpose
-does not help since it pins the module to the kernel forever (it calls
-try_module_get()). A GPIO driver can use the following functions instead
-to request and free descriptors without being pinned to the kernel forever::
+descriptors through the gpiolib API. A GPIO driver can use the following
+functions to request and free descriptors::
 
        struct gpio_desc *gpiochip_request_own_desc(struct gpio_desc *desc,
                                                    u16 hwnum,
@@ -446,7 +547,3 @@ gpiochip_free_own_desc().
 These functions must be used with care since they do not affect module use
 count. Do not use the functions to request gpio descriptors not owned by the
 calling driver.
-
-* [1] http://www.spinics.net/lists/linux-omap/msg120425.html
-* [2] https://lkml.org/lkml/2015/9/25/494
-* [3] https://lkml.org/lkml/2015/9/25/495
index 45edad6933cc4fe151455a44734196688e40cf2a..acc02fc579938b8193b0f4eac7ad6a19be00efb5 100644 (file)
@@ -354,8 +354,10 @@ this ioctl is called until no further expire candidates are found.
 
 The call requires an initialized struct autofs_dev_ioctl with the
 ioctlfd field set to the descriptor obtained from the open call. In
-addition an immediate expire, independent of the mount timeout, can be
-requested by setting the how field of struct args_expire to 1. If no
+addition an immediate expire that's independent of the mount timeout,
+and a forced expire that's independent of whether the mount is busy,
+can be requested by setting the how field of struct args_expire to
+AUTOFS_EXP_IMMEDIATE or AUTOFS_EXP_FORCED, respectively . If no
 expire candidates can be found the ioctl returns -1 with errno set to
 EAGAIN.
 
index 373ad25852d35bf40de7bbdb00a77f186e82e128..3af38c7fd26d121efedc592c5d182b067b0bd0b2 100644 (file)
@@ -116,7 +116,7 @@ that purpose there is another flag.
 **DCACHE_MANAGE_TRANSIT**
 
 If a dentry has DCACHE_MANAGE_TRANSIT set then two very different but
-related behaviors are invoked, both using the `d_op->d_manage()`
+related behaviours are invoked, both using the `d_op->d_manage()`
 dentry operation.
 
 Firstly, before checking to see if any filesystem is mounted on the
@@ -193,8 +193,8 @@ VFS remain in RCU-walk mode, but can only tell it to get out of
 RCU-walk mode by returning `-ECHILD`.
 
 So `d_manage()`, when called with `rcu_walk` set, should either return
--ECHILD if there is any reason to believe it is unsafe to end the
-mounted filesystem, and otherwise should return 0.
+-ECHILD if there is any reason to believe it is unsafe to enter the
+mounted filesystem, otherwise it should return 0.
 
 autofs will return `-ECHILD` if an expiry of the filesystem has been
 initiated or is being considered, otherwise it returns 0.
@@ -210,7 +210,7 @@ mounts that were created by `d_automount()` returning a filesystem to be
 mounted.  As autofs doesn't return such a filesystem but leaves the
 mounting to the automount daemon, it must involve the automount daemon
 in unmounting as well.  This also means that autofs has more control
-of expiry.
+over expiry.
 
 The VFS also supports "expiry" of mounts using the MNT_EXPIRE flag to
 the `umount` system call.  Unmounting with MNT_EXPIRE will fail unless
@@ -225,7 +225,7 @@ unmount any filesystems mounted on the autofs filesystem or remove any
 symbolic links or empty directories any time it likes.  If the unmount
 or removal is successful the filesystem will be returned to the state
 it was before the mount or creation, so that any access of the name
-will trigger normal auto-mount processing.  In particlar, `rmdir` and
+will trigger normal auto-mount processing.  In particular, `rmdir` and
 `unlink` do not leave negative entries in the dcache as a normal
 filesystem would, so an attempt to access a recently-removed object is
 passed to autofs for handling.
@@ -240,11 +240,18 @@ Normally the daemon only wants to remove entries which haven't been
 used for a while.  For this purpose autofs maintains a "`last_used`"
 time stamp on each directory or symlink.  For symlinks it genuinely
 does record the last time the symlink was "used" or followed to find
-out where it points to.  For directories the field is a slight
-misnomer.  It actually records the last time that autofs checked if
-the directory or one of its descendents was busy and found that it
-was.  This is just as useful and doesn't require updating the field so
-often.
+out where it points to.  For directories the field is used slightly
+differently.  The field is updated at mount time and during expire
+checks if it is found to be in use (ie. open file descriptor or
+process working directory) and during path walks. The update done
+during path walks prevents frequent expire and immediate mount of
+frequently accessed automounts. But in the case where a GUI continually
+access or an application frequently scans an autofs directory tree
+there can be an accumulation of mounts that aren't actually being
+used. To cater for this case the "`strictexpire`" autofs mount option
+can be used to avoid the "`last_used`" update on path walk thereby
+preventing this apparent inability to expire mounts that aren't
+really in use.
 
 The daemon is able to ask autofs if anything is due to be expired,
 using an `ioctl` as discussed later.  For a *direct* mount, autofs
@@ -255,8 +262,12 @@ up.
 
 There is an option with indirect mounts to consider each of the leaves
 that has been mounted on instead of considering the top-level names.
-This is intended for compatability with version 4 of autofs and should
-be considered as deprecated.
+This was originally intended for compatibility with version 4 of autofs
+and should be considered as deprecated for Sun Format automount maps.
+However, it may be used again for amd format mount maps (which are
+generally indirect maps) because the amd automounter allows for the
+setting of an expire timeout for individual mounts. But there are
+some difficulties in making the needed changes for this.
 
 When autofs considers a directory it checks the `last_used` time and
 compares it with the "timeout" value set when the filesystem was
@@ -273,7 +284,7 @@ mounts.  If it finds something in the root directory to expire it will
 return the name of that thing.  Once a name has been returned the
 automount daemon needs to unmount any filesystems mounted below the
 name normally.  As described above, this is unsafe for non-toplevel
-mounts in a version-5 autofs.  For this reason the current `automountd`
+mounts in a version-5 autofs.  For this reason the current `automount(8)`
 does not use this ioctl.
 
 The second mechanism uses either the **AUTOFS_DEV_IOCTL_EXPIRE_CMD** or
@@ -345,7 +356,7 @@ The `wait_queue_token` is a unique number which can identify a
 particular request to be acknowledged.  When a message is sent over
 the pipe the affected dentry is marked as either "active" or
 "expiring" and other accesses to it block until the message is
-acknowledged using one of the ioctls below and the relevant
+acknowledged using one of the ioctls below with the relevant
 `wait_queue_token`.
 
 Communicating with autofs: root directory ioctls
@@ -367,15 +378,14 @@ The available ioctl commands are:
     This mode is also entered if a write to the pipe fails.
 - **AUTOFS_IOC_PROTOVER**:  This returns the protocol version in use.
 - **AUTOFS_IOC_PROTOSUBVER**: Returns the protocol sub-version which
-    is really a version number for the implementation.  It is
-    currently 2.
+    is really a version number for the implementation.
 - **AUTOFS_IOC_SETTIMEOUT**:  This passes a pointer to an unsigned
     long.  The value is used to set the timeout for expiry, and
     the current timeout value is stored back through the pointer.
 - **AUTOFS_IOC_ASKUMOUNT**:  Returns, in the pointed-to `int`, 1 if
     the filesystem could be unmounted.  This is only a hint as
     the situation could change at any instant.  This call can be
-    use to avoid a more expensive full unmount attempt.
+    used to avoid a more expensive full unmount attempt.
 - **AUTOFS_IOC_EXPIRE**: as described above, this asks if there is
     anything suitable to expire.  A pointer to a packet:
 
@@ -400,6 +410,11 @@ The available ioctl commands are:
      **AUTOFS_EXP_IMMEDIATE** causes `last_used` time to be ignored
      and objects are expired if the are not in use.
 
+     **AUTOFS_EXP_FORCED** causes the in use status to be ignored
+     and objects are expired ieven if they are in use. This assumes
+     that the daemon has requested this because it is capable of
+     performing the umount.
+
      **AUTOFS_EXP_LEAVES** will select a leaf rather than a top-level
      name to expire.  This is only safe when *maxproto* is 4.
 
@@ -415,7 +430,7 @@ which can be used to communicate directly with the autofs filesystem.
 It requires CAP_SYS_ADMIN for access.
 
 The `ioctl`s that can be used on this device are described in a separate
-document `autofs-mount-control.txt`, and are summarized briefly here.
+document `autofs-mount-control.txt`, and are summarised briefly here.
 Each ioctl is passed a pointer to an `autofs_dev_ioctl` structure:
 
         struct autofs_dev_ioctl {
@@ -511,6 +526,21 @@ directories.
 Catatonic mode can only be left via the
 **AUTOFS_DEV_IOCTL_OPENMOUNT_CMD** ioctl on the `/dev/autofs`.
 
+The "ignore" mount option
+-------------------------
+
+The "ignore" mount option can be used to provide a generic indicator
+to applications that the mount entry should be ignored when displaying
+mount information.
+
+In other OSes that provide autofs and that provide a mount list to user
+space based on the kernel mount list a no-op mount option ("ignore" is
+the one use on the most common OSes) is allowed so that autofs file
+system users can optionally use it.
+
+This is intended to be used by user space programs to exclude autofs
+mounts from consideration when reading the mounts list.
+
 autofs, name spaces, and shared mounts
 --------------------------------------
 
index 1351984e767c8c69dda03cdd968f61c0d0452ff8..febccbc5689d089d7f7ca064cc275b1681156af9 100644 (file)
@@ -45,8 +45,8 @@ the ANOD object which is also the final target node of the reference.
            Name (_DSD, Package () {
                ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
                Package () {
-                   Package () { "node@0", NOD0 },
-                   Package () { "node@1", NOD1 },
+                   Package () { "node@0", "NOD0" },
+                   Package () { "node@1", "NOD1" },
                }
            })
            Name (NOD0, Package() {
@@ -58,7 +58,7 @@ the ANOD object which is also the final target node of the reference.
            Name (NOD1, Package() {
                ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
                Package () {
-                   Package () { "anothernode", ANOD },
+                   Package () { "anothernode", "ANOD" },
                }
            })
            Name (ANOD, Package() {
index e0baed35b037ed06ec5f78e1a7b2e1d5b09e53c1..1a6ce7afba5ead79edb91c0c8a179cb20f058104 100644 (file)
@@ -45,7 +45,7 @@ with "port" and must be followed by the "@" character and the number of the
 port as its key. The target object it refers to should be called "PRTX", where
 "X" is the number of the port. An example of such a package would be::
 
-    Package() { "port@4", PRT4 }
+    Package() { "port@4", "PRT4" }
 
 Further on, endpoints are located under the port nodes. The hierarchical
 data extension key of the endpoint nodes must begin with
@@ -54,7 +54,7 @@ endpoint. The object it refers to should be called "EPXY", where "X" is the
 number of the port and "Y" is the number of the endpoint. An example of such a
 package would be::
 
-    Package() { "endpoint@0", EP40 }
+    Package() { "endpoint@0", "EP40" }
 
 Each port node contains a property extension key "port", the value of which is
 the number of the port. Each endpoint is similarly numbered with a property
@@ -82,68 +82,68 @@ A simple example of this is show below::
 
     Scope (\_SB.PCI0.I2C2)
     {
-        Device (CAM0)
-        {
-            Name (_DSD, Package () {
-                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
-                Package () {
-                    Package () { "compatible", Package () { "nokia,smia" } },
-                },
-                ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
-                Package () {
-                    Package () { "port@0", PRT0 },
-                }
-            })
-            Name (PRT0, Package() {
-                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
-                Package () {
-                    Package () { "reg", 0 },
-                },
-                ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
-                Package () {
-                    Package () { "endpoint@0", EP00 },
-                }
-            })
-            Name (EP00, Package() {
-                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
-                Package () {
-                    Package () { "reg", 0 },
-                    Package () { "remote-endpoint", Package() { \_SB.PCI0.ISP, "port@4", "endpoint@0" } },
-                }
-            })
-        }
+       Device (CAM0)
+       {
+           Name (_DSD, Package () {
+               ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+               Package () {
+                   Package () { "compatible", Package () { "nokia,smia" } },
+               },
+               ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
+               Package () {
+                   Package () { "port@0", "PRT0" },
+               }
+           })
+           Name (PRT0, Package() {
+               ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+               Package () {
+                   Package () { "reg", 0 },
+               },
+               ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
+               Package () {
+                   Package () { "endpoint@0", "EP00" },
+               }
+           })
+           Name (EP00, Package() {
+               ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+               Package () {
+                   Package () { "reg", 0 },
+                   Package () { "remote-endpoint", Package() { \_SB.PCI0.ISP, "port@4", "endpoint@0" } },
+               }
+           })
+       }
     }
 
     Scope (\_SB.PCI0)
     {
-        Device (ISP)
-        {
-            Name (_DSD, Package () {
-                ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
-                Package () {
-                    Package () { "port@4", PRT4 },
-                }
-            })
-
-            Name (PRT4, Package() {
-                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
-                Package () {
-                    Package () { "reg", 4 }, /* CSI-2 port number */
-                },
-                ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
-                Package () {
-                    Package () { "endpoint@0", EP40 },
-                }
-            })
-
-            Name (EP40, Package() {
-                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
-                Package () {
-                    Package () { "reg", 0 },
-                    Package () { "remote-endpoint", Package () { \_SB.PCI0.I2C2.CAM0, "port@0", "endpoint@0" } },
-                }
-            })
-        }
+       Device (ISP)
+       {
+           Name (_DSD, Package () {
+               ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
+               Package () {
+                   Package () { "port@4", "PRT4" },
+               }
+           })
+
+           Name (PRT4, Package() {
+               ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+               Package () {
+                   Package () { "reg", 4 }, /* CSI-2 port number */
+               },
+               ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
+               Package () {
+                   Package () { "endpoint@0", "EP40" },
+               }
+           })
+
+           Name (EP40, Package() {
+               ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+               Package () {
+                   Package () { "reg", 0 },
+                   Package () { "remote-endpoint", Package () { \_SB.PCI0.I2C2.CAM0, "port@0", "endpoint@0" } },
+               }
+           })
+       }
     }
 
 Here, the port 0 of the "CAM0" device is connected to the port 4 of
diff --git a/Documentation/gpio/index.rst b/Documentation/gpio/index.rst
new file mode 100644 (file)
index 0000000..09a4a55
--- /dev/null
@@ -0,0 +1,17 @@
+:orphan:
+
+====
+gpio
+====
+
+.. toctree::
+    :maxdepth: 1
+
+    sysfs
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/gpio/sysfs.rst b/Documentation/gpio/sysfs.rst
new file mode 100644 (file)
index 0000000..ec09ffd
--- /dev/null
@@ -0,0 +1,167 @@
+GPIO Sysfs Interface for Userspace
+==================================
+
+.. warning::
+
+  THIS ABI IS DEPRECATED, THE ABI DOCUMENTATION HAS BEEN MOVED TO
+  Documentation/ABI/obsolete/sysfs-gpio AND NEW USERSPACE CONSUMERS
+  ARE SUPPOSED TO USE THE CHARACTER DEVICE ABI. THIS OLD SYSFS ABI WILL
+  NOT BE DEVELOPED (NO NEW FEATURES), IT WILL JUST BE MAINTAINED.
+
+Refer to the examples in tools/gpio/* for an introduction to the new
+character device ABI. Also see the userspace header in
+include/uapi/linux/gpio.h
+
+The deprecated sysfs ABI
+------------------------
+Platforms which use the "gpiolib" implementors framework may choose to
+configure a sysfs user interface to GPIOs. This is different from the
+debugfs interface, since it provides control over GPIO direction and
+value instead of just showing a gpio state summary. Plus, it could be
+present on production systems without debugging support.
+
+Given appropriate hardware documentation for the system, userspace could
+know for example that GPIO #23 controls the write protect line used to
+protect boot loader segments in flash memory. System upgrade procedures
+may need to temporarily remove that protection, first importing a GPIO,
+then changing its output state, then updating the code before re-enabling
+the write protection. In normal use, GPIO #23 would never be touched,
+and the kernel would have no need to know about it.
+
+Again depending on appropriate hardware documentation, on some systems
+userspace GPIO can be used to determine system configuration data that
+standard kernels won't know about. And for some tasks, simple userspace
+GPIO drivers could be all that the system really needs.
+
+DO NOT ABUSE SYSFS TO CONTROL HARDWARE THAT HAS PROPER KERNEL DRIVERS.
+PLEASE READ THE DOCUMENT AT Documentation/driver-api/gpio/drivers-on-gpio.rst
+TO AVOID REINVENTING KERNEL WHEELS IN USERSPACE. I MEAN IT. REALLY.
+
+Paths in Sysfs
+--------------
+There are three kinds of entries in /sys/class/gpio:
+
+   -   Control interfaces used to get userspace control over GPIOs;
+
+   -   GPIOs themselves; and
+
+   -   GPIO controllers ("gpio_chip" instances).
+
+That's in addition to standard files including the "device" symlink.
+
+The control interfaces are write-only:
+
+    /sys/class/gpio/
+
+       "export" ...
+               Userspace may ask the kernel to export control of
+               a GPIO to userspace by writing its number to this file.
+
+               Example:  "echo 19 > export" will create a "gpio19" node
+               for GPIO #19, if that's not requested by kernel code.
+
+       "unexport" ...
+               Reverses the effect of exporting to userspace.
+
+               Example:  "echo 19 > unexport" will remove a "gpio19"
+               node exported using the "export" file.
+
+GPIO signals have paths like /sys/class/gpio/gpio42/ (for GPIO #42)
+and have the following read/write attributes:
+
+    /sys/class/gpio/gpioN/
+
+       "direction" ...
+               reads as either "in" or "out". This value may
+               normally be written. Writing as "out" defaults to
+               initializing the value as low. To ensure glitch free
+               operation, values "low" and "high" may be written to
+               configure the GPIO as an output with that initial value.
+
+               Note that this attribute *will not exist* if the kernel
+               doesn't support changing the direction of a GPIO, or
+               it was exported by kernel code that didn't explicitly
+               allow userspace to reconfigure this GPIO's direction.
+
+       "value" ...
+               reads as either 0 (low) or 1 (high). If the GPIO
+               is configured as an output, this value may be written;
+               any nonzero value is treated as high.
+
+               If the pin can be configured as interrupt-generating interrupt
+               and if it has been configured to generate interrupts (see the
+               description of "edge"), you can poll(2) on that file and
+               poll(2) will return whenever the interrupt was triggered. If
+               you use poll(2), set the events POLLPRI and POLLERR. If you
+               use select(2), set the file descriptor in exceptfds. After
+               poll(2) returns, either lseek(2) to the beginning of the sysfs
+               file and read the new value or close the file and re-open it
+               to read the value.
+
+       "edge" ...
+               reads as either "none", "rising", "falling", or
+               "both". Write these strings to select the signal edge(s)
+               that will make poll(2) on the "value" file return.
+
+               This file exists only if the pin can be configured as an
+               interrupt generating input pin.
+
+       "active_low" ...
+               reads as either 0 (false) or 1 (true). Write
+               any nonzero value to invert the value attribute both
+               for reading and writing. Existing and subsequent
+               poll(2) support configuration via the edge attribute
+               for "rising" and "falling" edges will follow this
+               setting.
+
+GPIO controllers have paths like /sys/class/gpio/gpiochip42/ (for the
+controller implementing GPIOs starting at #42) and have the following
+read-only attributes:
+
+    /sys/class/gpio/gpiochipN/
+
+       "base" ...
+               same as N, the first GPIO managed by this chip
+
+       "label" ...
+               provided for diagnostics (not always unique)
+
+       "ngpio" ...
+               how many GPIOs this manages (N to N + ngpio - 1)
+
+Board documentation should in most cases cover what GPIOs are used for
+what purposes. However, those numbers are not always stable; GPIOs on
+a daughtercard might be different depending on the base board being used,
+or other cards in the stack. In such cases, you may need to use the
+gpiochip nodes (possibly in conjunction with schematics) to determine
+the correct GPIO number to use for a given signal.
+
+
+Exporting from Kernel code
+--------------------------
+Kernel code can explicitly manage exports of GPIOs which have already been
+requested using gpio_request()::
+
+       /* export the GPIO to userspace */
+       int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
+
+       /* reverse gpio_export() */
+       void gpiod_unexport(struct gpio_desc *desc);
+
+       /* create a sysfs link to an exported GPIO node */
+       int gpiod_export_link(struct device *dev, const char *name,
+                     struct gpio_desc *desc);
+
+After a kernel driver requests a GPIO, it may only be made available in
+the sysfs interface by gpiod_export(). The driver can control whether the
+signal direction may change. This helps drivers prevent userspace code
+from accidentally clobbering important system state.
+
+This explicit exporting can help with debugging (by making some kinds
+of experiments easier), or can provide an always-there interface that's
+suitable for documenting as part of a board support package.
+
+After the GPIO has been exported, gpiod_export_link() allows creating
+symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can
+use this to provide the interface under their own device in sysfs with
+a descriptive name.
diff --git a/Documentation/gpio/sysfs.txt b/Documentation/gpio/sysfs.txt
deleted file mode 100644 (file)
index 58eeab8..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-GPIO Sysfs Interface for Userspace
-==================================
-
-THIS ABI IS DEPRECATED, THE ABI DOCUMENTATION HAS BEEN MOVED TO
-Documentation/ABI/obsolete/sysfs-gpio AND NEW USERSPACE CONSUMERS
-ARE SUPPOSED TO USE THE CHARACTER DEVICE ABI. THIS OLD SYSFS ABI WILL
-NOT BE DEVELOPED (NO NEW FEATURES), IT WILL JUST BE MAINTAINED.
-
-Refer to the examples in tools/gpio/* for an introduction to the new
-character device ABI. Also see the userspace header in
-include/uapi/linux/gpio.h
-
-The deprecated sysfs ABI
-------------------------
-Platforms which use the "gpiolib" implementors framework may choose to
-configure a sysfs user interface to GPIOs. This is different from the
-debugfs interface, since it provides control over GPIO direction and
-value instead of just showing a gpio state summary. Plus, it could be
-present on production systems without debugging support.
-
-Given appropriate hardware documentation for the system, userspace could
-know for example that GPIO #23 controls the write protect line used to
-protect boot loader segments in flash memory. System upgrade procedures
-may need to temporarily remove that protection, first importing a GPIO,
-then changing its output state, then updating the code before re-enabling
-the write protection. In normal use, GPIO #23 would never be touched,
-and the kernel would have no need to know about it.
-
-Again depending on appropriate hardware documentation, on some systems
-userspace GPIO can be used to determine system configuration data that
-standard kernels won't know about. And for some tasks, simple userspace
-GPIO drivers could be all that the system really needs.
-
-DO NOT ABUSE SYSFS TO CONTROL HARDWARE THAT HAS PROPER KERNEL DRIVERS.
-PLEASE READ THE DOCUMENT AT Documentation/driver-api/gpio/drivers-on-gpio.rst
-TO AVOID REINVENTING KERNEL WHEELS IN USERSPACE. I MEAN IT. REALLY.
-
-Paths in Sysfs
---------------
-There are three kinds of entries in /sys/class/gpio:
-
-   -   Control interfaces used to get userspace control over GPIOs;
-
-   -   GPIOs themselves; and
-
-   -   GPIO controllers ("gpio_chip" instances).
-
-That's in addition to standard files including the "device" symlink.
-
-The control interfaces are write-only:
-
-    /sys/class/gpio/
-
-       "export" ... Userspace may ask the kernel to export control of
-               a GPIO to userspace by writing its number to this file.
-
-               Example:  "echo 19 > export" will create a "gpio19" node
-               for GPIO #19, if that's not requested by kernel code.
-
-       "unexport" ... Reverses the effect of exporting to userspace.
-
-               Example:  "echo 19 > unexport" will remove a "gpio19"
-               node exported using the "export" file.
-
-GPIO signals have paths like /sys/class/gpio/gpio42/ (for GPIO #42)
-and have the following read/write attributes:
-
-    /sys/class/gpio/gpioN/
-
-       "direction" ... reads as either "in" or "out". This value may
-               normally be written. Writing as "out" defaults to
-               initializing the value as low. To ensure glitch free
-               operation, values "low" and "high" may be written to
-               configure the GPIO as an output with that initial value.
-
-               Note that this attribute *will not exist* if the kernel
-               doesn't support changing the direction of a GPIO, or
-               it was exported by kernel code that didn't explicitly
-               allow userspace to reconfigure this GPIO's direction.
-
-       "value" ... reads as either 0 (low) or 1 (high). If the GPIO
-               is configured as an output, this value may be written;
-               any nonzero value is treated as high.
-
-               If the pin can be configured as interrupt-generating interrupt
-               and if it has been configured to generate interrupts (see the
-               description of "edge"), you can poll(2) on that file and
-               poll(2) will return whenever the interrupt was triggered. If
-               you use poll(2), set the events POLLPRI and POLLERR. If you
-               use select(2), set the file descriptor in exceptfds. After
-               poll(2) returns, either lseek(2) to the beginning of the sysfs
-               file and read the new value or close the file and re-open it
-               to read the value.
-
-       "edge" ... reads as either "none", "rising", "falling", or
-               "both". Write these strings to select the signal edge(s)
-               that will make poll(2) on the "value" file return.
-
-               This file exists only if the pin can be configured as an
-               interrupt generating input pin.
-
-       "active_low" ... reads as either 0 (false) or 1 (true). Write
-               any nonzero value to invert the value attribute both
-               for reading and writing. Existing and subsequent
-               poll(2) support configuration via the edge attribute
-               for "rising" and "falling" edges will follow this
-               setting.
-
-GPIO controllers have paths like /sys/class/gpio/gpiochip42/ (for the
-controller implementing GPIOs starting at #42) and have the following
-read-only attributes:
-
-    /sys/class/gpio/gpiochipN/
-
-       "base" ... same as N, the first GPIO managed by this chip
-
-       "label" ... provided for diagnostics (not always unique)
-
-        "ngpio" ... how many GPIOs this manages (N to N + ngpio - 1)
-
-Board documentation should in most cases cover what GPIOs are used for
-what purposes. However, those numbers are not always stable; GPIOs on
-a daughtercard might be different depending on the base board being used,
-or other cards in the stack. In such cases, you may need to use the
-gpiochip nodes (possibly in conjunction with schematics) to determine
-the correct GPIO number to use for a given signal.
-
-
-Exporting from Kernel code
---------------------------
-Kernel code can explicitly manage exports of GPIOs which have already been
-requested using gpio_request():
-
-       /* export the GPIO to userspace */
-       int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
-
-       /* reverse gpio_export() */
-       void gpiod_unexport(struct gpio_desc *desc);
-
-       /* create a sysfs link to an exported GPIO node */
-       int gpiod_export_link(struct device *dev, const char *name,
-                     struct gpio_desc *desc);
-
-After a kernel driver requests a GPIO, it may only be made available in
-the sysfs interface by gpiod_export(). The driver can control whether the
-signal direction may change. This helps drivers prevent userspace code
-from accidentally clobbering important system state.
-
-This explicit exporting can help with debugging (by making some kinds
-of experiments easier), or can provide an always-there interface that's
-suitable for documenting as part of a board support package.
-
-After the GPIO has been exported, gpiod_export_link() allows creating
-symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can
-use this to provide the interface under their own device in sysfs with
-a descriptive name.
index fec80fee512a820497874ca7e6cc6efb42261cf3..a7566ef624112abb79087bd6ce6fe3b361f57276 100644 (file)
@@ -112,7 +112,9 @@ implementation.
 .. toctree::
    :maxdepth: 2
 
+   x86/index
    sh/index
+   x86/index
 
 Filesystem Documentation
 ------------------------
index 3fb473e3b8e2e205d4e0d6692a891d560eec3781..d640e922a9748c795ec670f4375098372052f6dd 100644 (file)
@@ -75,12 +75,11 @@ enum v4l2_field
 
     * - ``V4L2_FIELD_ANY``
       - 0
-      - Applications request this field order when any one of the
-       ``V4L2_FIELD_NONE``, ``V4L2_FIELD_TOP``, ``V4L2_FIELD_BOTTOM``, or
-       ``V4L2_FIELD_INTERLACED`` formats is acceptable. Drivers choose
-       depending on hardware capabilities or e. g. the requested image
-       size, and return the actual field order. Drivers must never return
-       ``V4L2_FIELD_ANY``. If multiple field orders are possible the
+      - Applications request this field order when any field format
+       is acceptable. Drivers choose depending on hardware capabilities or
+       e.g. the requested image size, and return the actual field order.
+       Drivers must never return ``V4L2_FIELD_ANY``.
+       If multiple field orders are possible the
        driver must choose one of the possible field orders during
        :ref:`VIDIOC_S_FMT <VIDIOC_G_FMT>` or
        :ref:`VIDIOC_TRY_FMT <VIDIOC_G_FMT>`. struct
@@ -88,9 +87,8 @@ enum v4l2_field
        ``V4L2_FIELD_ANY``.
     * - ``V4L2_FIELD_NONE``
       - 1
-      - Images are in progressive format, not interlaced. The driver may
-       also indicate this order when it cannot distinguish between
-       ``V4L2_FIELD_TOP`` and ``V4L2_FIELD_BOTTOM``.
+      - Images are in progressive (frame-based) format, not interlaced
+        (field-based).
     * - ``V4L2_FIELD_TOP``
       - 2
       - Images consist of the top (aka odd) field only.
index cd7303d7fa25dac9ae38d0e73186f3687b7872a7..180e07d956a7049f119a8ebac7dfa2241b6c0a56 100644 (file)
@@ -796,7 +796,9 @@ The kernel interface functions are as follows:
                                s64 tx_total_len,
                                gfp_t gfp,
                                rxrpc_notify_rx_t notify_rx,
-                               bool upgrade);
+                               bool upgrade,
+                               bool intr,
+                               unsigned int debug_id);
 
      This allocates the infrastructure to make a new RxRPC call and assigns
      call and connection numbers.  The call will be made on the UDP port that
@@ -824,6 +826,13 @@ The kernel interface functions are as follows:
      the server upgrade the service to a better one.  The resultant service ID
      is returned by rxrpc_kernel_recv_data().
 
+     intr should be set to true if the call should be interruptible.  If this
+     is not set, this function may not return until a channel has been
+     allocated; if it is set, the function may return -ERESTARTSYS.
+
+     debug_id is the call debugging ID to be used for tracing.  This can be
+     obtained by atomically incrementing rxrpc_debug_id.
+
      If this function is successful, an opaque reference to the RxRPC call is
      returned.  The caller now holds a reference on this and it must be
      properly ended.
@@ -1056,6 +1065,16 @@ The kernel interface functions are as follows:
      This value can be used to determine if the remote client has been
      restarted as it shouldn't change otherwise.
 
+ (*) Set the maxmimum lifespan on a call.
+
+       void rxrpc_kernel_set_max_life(struct socket *sock,
+                                      struct rxrpc_call *call,
+                                      unsigned long hard_timeout)
+
+     This sets the maximum lifespan on a call to hard_timeout (which is in
+     jiffies).  In the event of the timeout occurring, the call will be
+     aborted and -ETIME or -ETIMEDOUT will be returned.
+
 
 =======================
 CONFIGURABLE PARAMETERS
index 3f13d8599337ea8a010d3a33ae605201691a427e..749322060f10061829bcaefd14e31096b50a8529 100644 (file)
@@ -61,6 +61,7 @@ Currently, these files are in /proc/sys/vm:
 - stat_refresh
 - numa_stat
 - swappiness
+- unprivileged_userfaultfd
 - user_reserve_kbytes
 - vfs_cache_pressure
 - watermark_boost_factor
@@ -818,6 +819,17 @@ The default value is 60.
 
 ==============================================================
 
+unprivileged_userfaultfd
+
+This flag controls whether unprivileged users can use the userfaultfd
+system calls.  Set this to 1 to allow unprivileged users to use the
+userfaultfd system calls, or set this to 0 to restrict userfaultfd to only
+privileged users (with SYS_CAP_PTRACE capability).
+
+The default value is 1.
+
+==============================================================
+
 - user_reserve_kbytes
 
 When overcommit_memory is set to 2, "never overcommit" mode, reserve
index c3b9bd2fd512e64451bae4003bbc36ff92c952f8..f60079259669132e4745eede87b4bda933f3a6a5 100644 (file)
@@ -765,6 +765,37 @@ Here is the list of current tracers that may be configured.
        tracers from tracing simply echo "nop" into
        current_tracer.
 
+Error conditions
+----------------
+
+  For most ftrace commands, failure modes are obvious and communicated
+  using standard return codes.
+
+  For other more involved commands, extended error information may be
+  available via the tracing/error_log file.  For the commands that
+  support it, reading the tracing/error_log file after an error will
+  display more detailed information about what went wrong, if
+  information is available.  The tracing/error_log file is a circular
+  error log displaying a small number (currently, 8) of ftrace errors
+  for the last (8) failed commands.
+
+  The extended error information and usage takes the form shown in
+  this example::
+
+    # echo xxx > /sys/kernel/debug/tracing/events/sched/sched_wakeup/trigger
+    echo: write error: Invalid argument
+
+    # cat /sys/kernel/debug/tracing/error_log
+    [ 5348.887237] location: error: Couldn't yyy: zzz
+      Command: xxx
+               ^
+    [ 7517.023364] location: error: Bad rrr: sss
+      Command: ppp qqq
+                   ^
+
+  To clear the error log, echo the empty string into it::
+
+    # echo > /sys/kernel/debug/tracing/error_log
 
 Examples of using the tracer
 ----------------------------
index f95d94d19c226fc01d5ebb34cdda1be658285c6f..fb621a1c263868082d42bcc886138293d7252c3a 100644 (file)
@@ -199,20 +199,8 @@ Extended error information
 
   For some error conditions encountered when invoking a hist trigger
   command, extended error information is available via the
-  corresponding event's 'hist' file.  Reading the hist file after an
-  error will display more detailed information about what went wrong,
-  if information is available.  This extended error information will
-  be available until the next hist trigger command for that event.
-
-  If available for a given error condition, the extended error
-  information and usage takes the following form::
-
-    # echo xxx > /sys/kernel/debug/tracing/events/sched/sched_wakeup/trigger
-    echo: write error: Invalid argument
-
-    # cat /sys/kernel/debug/tracing/events/sched/sched_wakeup/hist
-    ERROR: Couldn't yyy: zzz
-      Last command: xxx
+  tracing/error_log file.  See Error Conditions in
+  :file:`Documentation/trace/ftrace.rst` for details.
 
 6.2 'hist' trigger examples
 ---------------------------
@@ -1915,7 +1903,10 @@ The following commonly-used handler.action pairs are available:
 
     The 'matching.event' specification is simply the fully qualified
     event name of the event that matches the target event for the
-    onmatch() functionality, in the form 'system.event_name'.
+    onmatch() functionality, in the form 'system.event_name'. Histogram
+    keys of both events are compared to find if events match. In case
+    multiple histogram keys are used, they all must match in the specified
+    order.
 
     Finally, the number and type of variables/fields in the 'param
     list' must match the number and types of the fields in the
@@ -1978,9 +1969,9 @@ The following commonly-used handler.action pairs are available:
              /sys/kernel/debug/tracing/events/sched/sched_waking/trigger
 
     Then, when the corresponding thread is actually scheduled onto the
-    CPU by a sched_switch event, calculate the latency and use that
-    along with another variable and an event field to generate a
-    wakeup_latency synthetic event::
+    CPU by a sched_switch event (saved_pid matches next_pid), calculate
+    the latency and use that along with another variable and an event field
+    to generate a wakeup_latency synthetic event::
 
       # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:\
               onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,\
index 66bfd8396877f933a1f70fffc87cbf09e9254772..995da15b16cab8a6d6fb051b65c8e113c3e7423e 100644 (file)
@@ -113,7 +113,7 @@ my $regex_kswapd_wake_default = 'nid=([0-9]*) order=([0-9]*)';
 my $regex_kswapd_sleep_default = 'nid=([0-9]*)';
 my $regex_wakeup_kswapd_default = 'nid=([0-9]*) zid=([0-9]*) order=([0-9]*) gfp_flags=([A-Z_|]*)';
 my $regex_lru_isolate_default = 'isolate_mode=([0-9]*) classzone_idx=([0-9]*) order=([0-9]*) nr_requested=([0-9]*) nr_scanned=([0-9]*) nr_skipped=([0-9]*) nr_taken=([0-9]*) lru=([a-z_]*)';
-my $regex_lru_shrink_inactive_default = 'nid=([0-9]*) nr_scanned=([0-9]*) nr_reclaimed=([0-9]*) nr_dirty=([0-9]*) nr_writeback=([0-9]*) nr_congested=([0-9]*) nr_immediate=([0-9]*) nr_activate=([0-9]*) nr_ref_keep=([0-9]*) nr_unmap_fail=([0-9]*) priority=([0-9]*) flags=([A-Z_|]*)';
+my $regex_lru_shrink_inactive_default = 'nid=([0-9]*) nr_scanned=([0-9]*) nr_reclaimed=([0-9]*) nr_dirty=([0-9]*) nr_writeback=([0-9]*) nr_congested=([0-9]*) nr_immediate=([0-9]*) nr_activate_anon=([0-9]*) nr_activate_file=([0-9]*) nr_ref_keep=([0-9]*) nr_unmap_fail=([0-9]*) priority=([0-9]*) flags=([A-Z_|]*)';
 my $regex_lru_shrink_active_default = 'lru=([A-Z_]*) nr_scanned=([0-9]*) nr_rotated=([0-9]*) priority=([0-9]*)';
 my $regex_writepage_default = 'page=([0-9a-f]*) pfn=([0-9]*) flags=([A-Z_|]*)';
 
@@ -212,7 +212,8 @@ $regex_lru_shrink_inactive = generate_traceevent_regex(
                        "vmscan/mm_vmscan_lru_shrink_inactive",
                        $regex_lru_shrink_inactive_default,
                        "nid", "nr_scanned", "nr_reclaimed", "nr_dirty", "nr_writeback",
-                       "nr_congested", "nr_immediate", "nr_activate", "nr_ref_keep",
+                       "nr_congested", "nr_immediate", "nr_activate_anon",
+                       "nr_activate_file", "nr_ref_keep",
                        "nr_unmap_fail", "priority", "flags");
 $regex_lru_shrink_active = generate_traceevent_regex(
                        "vmscan/mm_vmscan_lru_shrink_active",
@@ -407,7 +408,7 @@ EVENT_PROCESS:
                        }
 
                        my $nr_reclaimed = $3;
-                       my $flags = $12;
+                       my $flags = $13;
                        my $file = 0;
                        if ($flags =~ /RECLAIM_WB_FILE/) {
                                $file = 1;
index 91a8794ffd79ec5c6cfb362fd08a8f382215f388..f058e06996dccda0defd6c8f66ed04037aec308f 100644 (file)
@@ -249,13 +249,13 @@ essere categorizzate in:
 
 |
 
-2. Licenze non raccomandate:
+2. Licenze deprecate:
 
    Questo tipo di licenze dovrebbero essere usate solo per codice già esistente
    o quando si prende codice da altri progetti.  Le licenze sono disponibili
    nei sorgenti del kernel nella cartella::
 
-     LICENSES/other/
+     LICENSES/deprecated/
 
    I file in questa cartella contengono il testo completo della licenza e i
    `Metatag`_.  Il nome di questi file è lo stesso usato come identificatore
@@ -263,14 +263,14 @@ essere categorizzate in:
 
    Esempi::
 
-     LICENSES/other/ISC
+     LICENSES/deprecated/ISC
 
    Contiene il testo della licenza Internet System Consortium e i suoi
    metatag::
 
-     LICENSES/other/ZLib
+     LICENSES/deprecated/GPL-1.0
 
-   Contiene il testo della licenza ZLIB e i suoi metatag.
+   Contiene il testo della versione 1 della licenza GPL e i suoi metatag.
 
    Metatag:
 
@@ -294,7 +294,55 @@ essere categorizzate in:
 
 |
 
-3. _`Eccezioni`:
+3. Solo per doppie licenze
+
+   Queste licenze dovrebbero essere usate solamente per codice licenziato in
+   combinazione con un'altra licenza che solitamente è quella preferita.
+   Queste licenze sono disponibili nei sorgenti del kernel nella cartella::
+
+     LICENSES/dual
+
+   I file in questa cartella contengono il testo completo della rispettiva
+   licenza e i suoi `Metatags`_.  I nomi dei file sono identici agli
+   identificatori di licenza SPDX che dovrebbero essere usati nei file
+   sorgenti.
+
+   Esempi::
+
+     LICENSES/dual/MPL-1.1
+
+   Questo file contiene il testo della versione 1.1 della licenza *Mozilla
+   Pulic License* e i metatag necessari::
+
+     LICENSES/dual/Apache-2.0
+
+   Questo file contiene il testo della versione 2.0 della licenza Apache e i
+   metatag necessari.
+
+   Metatag:
+
+   I requisiti per le 'altre' ('*other*') licenze sono identici a quelli per le
+   `Licenze raccomandate`_.
+
+   Esempio del formato del file::
+
+   Valid-License-Identifier: MPL-1.1
+   SPDX-URL: https://spdx.org/licenses/MPL-1.1.html
+   Usage-Guide:
+     Do NOT use. The MPL-1.1 is not GPL2 compatible. It may only be used for
+     dual-licensed files where the other license is GPL2 compatible.
+     If you end up using this it MUST be used together with a GPL2 compatible
+     license using "OR".
+     To use the Mozilla Public License version 1.1 put the following SPDX
+     tag/value pair into a comment according to the placement guidelines in
+     the licensing rules documentation:
+   SPDX-License-Identifier: MPL-1.1
+   License-Text:
+     Full license text
+
+|
+
+4. _`Eccezioni`:
 
    Alcune licenze possono essere corrette con delle eccezioni che forniscono
    diritti aggiuntivi.  Queste eccezioni sono disponibili nei sorgenti del
index 64b38dfcc243964bfdccc905908c1d39b965817d..ba6c42c576ddd9a8c0a9c6f58ba038db5a8fdb46 100644 (file)
@@ -69,23 +69,6 @@ by and on behalf of the VM's process may not be freed/unaccounted when
 the VM is shut down.
 
 
-It is important to note that althought VM ioctls may only be issued from
-the process that created the VM, a VM's lifecycle is associated with its
-file descriptor, not its creator (process).  In other words, the VM and
-its resources, *including the associated address space*, are not freed
-until the last reference to the VM's file descriptor has been released.
-For example, if fork() is issued after ioctl(KVM_CREATE_VM), the VM will
-not be freed until both the parent (original) process and its child have
-put their references to the VM's file descriptor.
-
-Because a VM's resources are not freed until the last reference to its
-file descriptor is released, creating additional references to a VM via
-via fork(), dup(), etc... without careful consideration is strongly
-discouraged and may have unwanted side effects, e.g. memory allocated
-by and on behalf of the VM's process may not be freed/unaccounted when
-the VM is shut down.
-
-
 3. Extensions
 -------------
 
@@ -347,7 +330,7 @@ They must be less than the value that KVM_CHECK_EXTENSION returns for
 the KVM_CAP_MULTI_ADDRESS_SPACE capability.
 
 The bits in the dirty bitmap are cleared before the ioctl returns, unless
-KVM_CAP_MANUAL_DIRTY_LOG_PROTECT is enabled.  For more information,
+KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is enabled.  For more information,
 see the description of the capability.
 
 4.9 KVM_SET_MEMORY_ALIAS
@@ -1117,9 +1100,8 @@ struct kvm_userspace_memory_region {
 This ioctl allows the user to create, modify or delete a guest physical
 memory slot.  Bits 0-15 of "slot" specify the slot id and this value
 should be less than the maximum number of user memory slots supported per
-VM.  The maximum allowed slots can be queried using KVM_CAP_NR_MEMSLOTS,
-if this capability is supported by the architecture.  Slots may not
-overlap in guest physical address space.
+VM.  The maximum allowed slots can be queried using KVM_CAP_NR_MEMSLOTS.
+Slots may not overlap in guest physical address space.
 
 If KVM_CAP_MULTI_ADDRESS_SPACE is available, bits 16-31 of "slot"
 specifies the address space which is being modified.  They must be
@@ -1901,6 +1883,12 @@ Architectures: all
 Type: vcpu ioctl
 Parameters: struct kvm_one_reg (in)
 Returns: 0 on success, negative value on failure
+Errors:
+  ENOENT:   no such register
+  EINVAL:   invalid register ID, or no such register
+  EPERM:    (arm64) register access not allowed before vcpu finalization
+(These error codes are indicative only: do not rely on a specific error
+code being returned in a specific situation.)
 
 struct kvm_one_reg {
        __u64 id;
@@ -1985,6 +1973,7 @@ registers, find a list below:
   PPC   | KVM_REG_PPC_TLB3PS            | 32
   PPC   | KVM_REG_PPC_EPTCFG            | 32
   PPC   | KVM_REG_PPC_ICP_STATE         | 64
+  PPC   | KVM_REG_PPC_VP_STATE          | 128
   PPC   | KVM_REG_PPC_TB_OFFSET         | 64
   PPC   | KVM_REG_PPC_SPMC1             | 32
   PPC   | KVM_REG_PPC_SPMC2             | 32
@@ -2137,6 +2126,37 @@ contains elements ranging from 32 to 128 bits. The index is a 32bit
 value in the kvm_regs structure seen as a 32bit array.
   0x60x0 0000 0010 <index into the kvm_regs struct:16>
 
+Specifically:
+    Encoding            Register  Bits  kvm_regs member
+----------------------------------------------------------------
+  0x6030 0000 0010 0000 X0          64  regs.regs[0]
+  0x6030 0000 0010 0002 X1          64  regs.regs[1]
+    ...
+  0x6030 0000 0010 003c X30         64  regs.regs[30]
+  0x6030 0000 0010 003e SP          64  regs.sp
+  0x6030 0000 0010 0040 PC          64  regs.pc
+  0x6030 0000 0010 0042 PSTATE      64  regs.pstate
+  0x6030 0000 0010 0044 SP_EL1      64  sp_el1
+  0x6030 0000 0010 0046 ELR_EL1     64  elr_el1
+  0x6030 0000 0010 0048 SPSR_EL1    64  spsr[KVM_SPSR_EL1] (alias SPSR_SVC)
+  0x6030 0000 0010 004a SPSR_ABT    64  spsr[KVM_SPSR_ABT]
+  0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
+  0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
+  0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
+  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
+  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
+    ...
+  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
+  0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
+  0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
+
+(*) These encodings are not accepted for SVE-enabled vcpus.  See
+    KVM_ARM_VCPU_INIT.
+
+    The equivalent register content can be accessed via bits [127:0] of
+    the corresponding SVE Zn registers instead for vcpus that have SVE
+    enabled (see below).
+
 arm64 CCSIDR registers are demultiplexed by CSSELR value:
   0x6020 0000 0011 00 <csselr:8>
 
@@ -2146,6 +2166,64 @@ arm64 system registers have the following id bit patterns:
 arm64 firmware pseudo-registers have the following bit pattern:
   0x6030 0000 0014 <regno:16>
 
+arm64 SVE registers have the following bit patterns:
+  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
+  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
+  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
+  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
+
+Access to register IDs where 2048 * slice >= 128 * max_vq will fail with
+ENOENT.  max_vq is the vcpu's maximum supported vector length in 128-bit
+quadwords: see (**) below.
+
+These registers are only accessible on vcpus for which SVE is enabled.
+See KVM_ARM_VCPU_INIT for details.
+
+In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
+accessible until the vcpu's SVE configuration has been finalized
+using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
+and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
+
+KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
+lengths supported by the vcpu to be discovered and configured by
+userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
+or KVM_SET_ONE_REG, the value of this register is of type
+__u64[KVM_ARM64_SVE_VLS_WORDS], and encodes the set of vector lengths as
+follows:
+
+__u64 vector_lengths[KVM_ARM64_SVE_VLS_WORDS];
+
+if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
+    ((vector_lengths[(vq - KVM_ARM64_SVE_VQ_MIN) / 64] >>
+               ((vq - KVM_ARM64_SVE_VQ_MIN) % 64)) & 1))
+       /* Vector length vq * 16 bytes supported */
+else
+       /* Vector length vq * 16 bytes not supported */
+
+(**) The maximum value vq for which the above condition is true is
+max_vq.  This is the maximum vector length available to the guest on
+this vcpu, and determines which register slices are visible through
+this ioctl interface.
+
+(See Documentation/arm64/sve.txt for an explanation of the "vq"
+nomenclature.)
+
+KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
+KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
+the host supports.
+
+Userspace may subsequently modify it if desired until the vcpu's SVE
+configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
+
+Apart from simply removing all vector lengths from the host set that
+exceed some value, support for arbitrarily chosen sets of vector lengths
+is hardware-dependent and may not be available.  Attempting to configure
+an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
+EINVAL.
+
+After the vcpu's SVE configuration is finalized, further attempts to
+write this register will fail with EPERM.
+
 
 MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
 the register group type:
@@ -2198,6 +2276,12 @@ Architectures: all
 Type: vcpu ioctl
 Parameters: struct kvm_one_reg (in and out)
 Returns: 0 on success, negative value on failure
+Errors include:
+  ENOENT:   no such register
+  EINVAL:   invalid register ID, or no such register
+  EPERM:    (arm64) register access not allowed before vcpu finalization
+(These error codes are indicative only: do not rely on a specific error
+code being returned in a specific situation.)
 
 This ioctl allows to receive the value of a single register implemented
 in a vcpu. The register to read is indicated by the "id" field of the
@@ -2690,6 +2774,49 @@ Possible features:
        - KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
          Depends on KVM_CAP_ARM_PMU_V3.
 
+       - KVM_ARM_VCPU_PTRAUTH_ADDRESS: Enables Address Pointer authentication
+         for arm64 only.
+         Depends on KVM_CAP_ARM_PTRAUTH_ADDRESS.
+         If KVM_CAP_ARM_PTRAUTH_ADDRESS and KVM_CAP_ARM_PTRAUTH_GENERIC are
+         both present, then both KVM_ARM_VCPU_PTRAUTH_ADDRESS and
+         KVM_ARM_VCPU_PTRAUTH_GENERIC must be requested or neither must be
+         requested.
+
+       - KVM_ARM_VCPU_PTRAUTH_GENERIC: Enables Generic Pointer authentication
+         for arm64 only.
+         Depends on KVM_CAP_ARM_PTRAUTH_GENERIC.
+         If KVM_CAP_ARM_PTRAUTH_ADDRESS and KVM_CAP_ARM_PTRAUTH_GENERIC are
+         both present, then both KVM_ARM_VCPU_PTRAUTH_ADDRESS and
+         KVM_ARM_VCPU_PTRAUTH_GENERIC must be requested or neither must be
+         requested.
+
+       - KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
+         Depends on KVM_CAP_ARM_SVE.
+         Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+
+          * After KVM_ARM_VCPU_INIT:
+
+             - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
+               initial value of this pseudo-register indicates the best set of
+               vector lengths possible for a vcpu on this host.
+
+          * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+
+             - KVM_RUN and KVM_GET_REG_LIST are not available;
+
+             - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
+               the scalable archietctural SVE registers
+               KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
+               KVM_REG_ARM64_SVE_FFR;
+
+             - KVM_REG_ARM64_SVE_VLS may optionally be written using
+               KVM_SET_ONE_REG, to modify the set of vector lengths available
+               for the vcpu.
+
+          * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+
+             - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
+               no longer be written using KVM_SET_ONE_REG.
 
 4.83 KVM_ARM_PREFERRED_TARGET
 
@@ -3809,7 +3936,7 @@ to I/O ports.
 
 4.117 KVM_CLEAR_DIRTY_LOG (vm ioctl)
 
-Capability: KVM_CAP_MANUAL_DIRTY_LOG_PROTECT
+Capability: KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2
 Architectures: x86, arm, arm64, mips
 Type: vm ioctl
 Parameters: struct kvm_dirty_log (in)
@@ -3842,10 +3969,10 @@ the address space for which you want to return the dirty bitmap.
 They must be less than the value that KVM_CHECK_EXTENSION returns for
 the KVM_CAP_MULTI_ADDRESS_SPACE capability.
 
-This ioctl is mostly useful when KVM_CAP_MANUAL_DIRTY_LOG_PROTECT
+This ioctl is mostly useful when KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2
 is enabled; for more information, see the description of the capability.
 However, it can always be used as long as KVM_CHECK_EXTENSION confirms
-that KVM_CAP_MANUAL_DIRTY_LOG_PROTECT is present.
+that KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is present.
 
 4.118 KVM_GET_SUPPORTED_HV_CPUID
 
@@ -3904,6 +4031,40 @@ number of valid entries in the 'entries' array, which is then filled.
 'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
 userspace should not expect to get any particular value there.
 
+4.119 KVM_ARM_VCPU_FINALIZE
+
+Architectures: arm, arm64
+Type: vcpu ioctl
+Parameters: int feature (in)
+Returns: 0 on success, -1 on error
+Errors:
+  EPERM:     feature not enabled, needs configuration, or already finalized
+  EINVAL:    feature unknown or not present
+
+Recognised values for feature:
+  arm64      KVM_ARM_VCPU_SVE (requires KVM_CAP_ARM_SVE)
+
+Finalizes the configuration of the specified vcpu feature.
+
+The vcpu must already have been initialised, enabling the affected feature, by
+means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
+features[].
+
+For affected vcpu features, this is a mandatory step that must be performed
+before the vcpu is fully usable.
+
+Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
+configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
+that should be performaned and how to do it are feature-dependent.
+
+Other calls that depend on a particular feature being finalized, such as
+KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
+-EPERM unless the feature has already been finalized by means of a
+KVM_ARM_VCPU_FINALIZE call.
+
+See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
+using this ioctl.
+
 5. The kvm_run structure
 ------------------------
 
@@ -4505,6 +4666,15 @@ struct kvm_sync_regs {
         struct kvm_vcpu_events events;
 };
 
+6.75 KVM_CAP_PPC_IRQ_XIVE
+
+Architectures: ppc
+Target: vcpu
+Parameters: args[0] is the XIVE device fd
+            args[1] is the XIVE CPU number (server ID) for this vcpu
+
+This capability connects the vcpu to an in-kernel XIVE device.
+
 7. Capabilities that can be enabled on VMs
 ------------------------------------------
 
@@ -4798,7 +4968,7 @@ and injected exceptions.
 * For the new DR6 bits, note that bit 16 is set iff the #DB exception
   will clear DR6.RTM.
 
-7.18 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT
+7.18 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2
 
 Architectures: x86, arm, arm64, mips
 Parameters: args[0] whether feature should be enabled or not
@@ -4821,6 +4991,11 @@ while userspace can see false reports of dirty pages.  Manual reprotection
 helps reducing this time, improving guest performance and reducing the
 number of dirty log false positives.
 
+KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 was previously available under the name
+KVM_CAP_MANUAL_DIRTY_LOG_PROTECT, but the implementation had bugs that make
+it hard or impossible to use it correctly.  The availability of
+KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 signals that those bugs are fixed.
+Userspace should not try to use KVM_CAP_MANUAL_DIRTY_LOG_PROTECT.
 
 8. Other capabilities.
 ----------------------
index 95ca68d663a4c111eb99b280e6d1d60c85461804..4ffb82b0246838d3022fb094b3996fa8de84e9ec 100644 (file)
@@ -141,7 +141,8 @@ struct kvm_s390_vm_cpu_subfunc {
        u8 pcc[16];           # valid with Message-Security-Assist-Extension 4
        u8 ppno[16];          # valid with Message-Security-Assist-Extension 5
        u8 kma[16];           # valid with Message-Security-Assist-Extension 8
-       u8 reserved[1808];    # reserved for future instructions
+       u8 kdsa[16];          # valid with Message-Security-Assist-Extension 9
+       u8 reserved[1792];    # reserved for future instructions
 };
 
 Parameters: address of a buffer to load the subfunction blocks from.
diff --git a/Documentation/virtual/kvm/devices/xive.txt b/Documentation/virtual/kvm/devices/xive.txt
new file mode 100644 (file)
index 0000000..9a24a45
--- /dev/null
@@ -0,0 +1,197 @@
+POWER9 eXternal Interrupt Virtualization Engine (XIVE Gen1)
+==========================================================
+
+Device types supported:
+  KVM_DEV_TYPE_XIVE     POWER9 XIVE Interrupt Controller generation 1
+
+This device acts as a VM interrupt controller. It provides the KVM
+interface to configure the interrupt sources of a VM in the underlying
+POWER9 XIVE interrupt controller.
+
+Only one XIVE instance may be instantiated. A guest XIVE device
+requires a POWER9 host and the guest OS should have support for the
+XIVE native exploitation interrupt mode. If not, it should run using
+the legacy interrupt mode, referred as XICS (POWER7/8).
+
+* Device Mappings
+
+  The KVM device exposes different MMIO ranges of the XIVE HW which
+  are required for interrupt management. These are exposed to the
+  guest in VMAs populated with a custom VM fault handler.
+
+  1. Thread Interrupt Management Area (TIMA)
+
+  Each thread has an associated Thread Interrupt Management context
+  composed of a set of registers. These registers let the thread
+  handle priority management and interrupt acknowledgment. The most
+  important are :
+
+      - Interrupt Pending Buffer     (IPB)
+      - Current Processor Priority   (CPPR)
+      - Notification Source Register (NSR)
+
+  They are exposed to software in four different pages each proposing
+  a view with a different privilege. The first page is for the
+  physical thread context and the second for the hypervisor. Only the
+  third (operating system) and the fourth (user level) are exposed the
+  guest.
+
+  2. Event State Buffer (ESB)
+
+  Each source is associated with an Event State Buffer (ESB) with
+  either a pair of even/odd pair of pages which provides commands to
+  manage the source: to trigger, to EOI, to turn off the source for
+  instance.
+
+  3. Device pass-through
+
+  When a device is passed-through into the guest, the source
+  interrupts are from a different HW controller (PHB4) and the ESB
+  pages exposed to the guest should accommadate this change.
+
+  The passthru_irq helpers, kvmppc_xive_set_mapped() and
+  kvmppc_xive_clr_mapped() are called when the device HW irqs are
+  mapped into or unmapped from the guest IRQ number space. The KVM
+  device extends these helpers to clear the ESB pages of the guest IRQ
+  number being mapped and then lets the VM fault handler repopulate.
+  The handler will insert the ESB page corresponding to the HW
+  interrupt of the device being passed-through or the initial IPI ESB
+  page if the device has being removed.
+
+  The ESB remapping is fully transparent to the guest and the OS
+  device driver. All handling is done within VFIO and the above
+  helpers in KVM-PPC.
+
+* Groups:
+
+  1. KVM_DEV_XIVE_GRP_CTRL
+  Provides global controls on the device
+  Attributes:
+    1.1 KVM_DEV_XIVE_RESET (write only)
+    Resets the interrupt controller configuration for sources and event
+    queues. To be used by kexec and kdump.
+    Errors: none
+
+    1.2 KVM_DEV_XIVE_EQ_SYNC (write only)
+    Sync all the sources and queues and mark the EQ pages dirty. This
+    to make sure that a consistent memory state is captured when
+    migrating the VM.
+    Errors: none
+
+  2. KVM_DEV_XIVE_GRP_SOURCE (write only)
+  Initializes a new source in the XIVE device and mask it.
+  Attributes:
+    Interrupt source number  (64-bit)
+  The kvm_device_attr.addr points to a __u64 value:
+  bits:     | 63   ....  2 |   1   |   0
+  values:   |    unused    | level | type
+  - type:  0:MSI 1:LSI
+  - level: assertion level in case of an LSI.
+  Errors:
+    -E2BIG:  Interrupt source number is out of range
+    -ENOMEM: Could not create a new source block
+    -EFAULT: Invalid user pointer for attr->addr.
+    -ENXIO:  Could not allocate underlying HW interrupt
+
+  3. KVM_DEV_XIVE_GRP_SOURCE_CONFIG (write only)
+  Configures source targeting
+  Attributes:
+    Interrupt source number  (64-bit)
+  The kvm_device_attr.addr points to a __u64 value:
+  bits:     | 63   ....  33 |  32  | 31 .. 3 |  2 .. 0
+  values:   |    eisn       | mask |  server | priority
+  - priority: 0-7 interrupt priority level
+  - server: CPU number chosen to handle the interrupt
+  - mask: mask flag (unused)
+  - eisn: Effective Interrupt Source Number
+  Errors:
+    -ENOENT: Unknown source number
+    -EINVAL: Not initialized source number
+    -EINVAL: Invalid priority
+    -EINVAL: Invalid CPU number.
+    -EFAULT: Invalid user pointer for attr->addr.
+    -ENXIO:  CPU event queues not configured or configuration of the
+             underlying HW interrupt failed
+    -EBUSY:  No CPU available to serve interrupt
+
+  4. KVM_DEV_XIVE_GRP_EQ_CONFIG (read-write)
+  Configures an event queue of a CPU
+  Attributes:
+    EQ descriptor identifier (64-bit)
+  The EQ descriptor identifier is a tuple (server, priority) :
+  bits:     | 63   ....  32 | 31 .. 3 |  2 .. 0
+  values:   |    unused     |  server | priority
+  The kvm_device_attr.addr points to :
+    struct kvm_ppc_xive_eq {
+       __u32 flags;
+       __u32 qshift;
+       __u64 qaddr;
+       __u32 qtoggle;
+       __u32 qindex;
+       __u8  pad[40];
+    };
+  - flags: queue flags
+    KVM_XIVE_EQ_ALWAYS_NOTIFY (required)
+       forces notification without using the coalescing mechanism
+       provided by the XIVE END ESBs.
+  - qshift: queue size (power of 2)
+  - qaddr: real address of queue
+  - qtoggle: current queue toggle bit
+  - qindex: current queue index
+  - pad: reserved for future use
+  Errors:
+    -ENOENT: Invalid CPU number
+    -EINVAL: Invalid priority
+    -EINVAL: Invalid flags
+    -EINVAL: Invalid queue size
+    -EINVAL: Invalid queue address
+    -EFAULT: Invalid user pointer for attr->addr.
+    -EIO:    Configuration of the underlying HW failed
+
+  5. KVM_DEV_XIVE_GRP_SOURCE_SYNC (write only)
+  Synchronize the source to flush event notifications
+  Attributes:
+    Interrupt source number  (64-bit)
+  Errors:
+    -ENOENT: Unknown source number
+    -EINVAL: Not initialized source number
+
+* VCPU state
+
+  The XIVE IC maintains VP interrupt state in an internal structure
+  called the NVT. When a VP is not dispatched on a HW processor
+  thread, this structure can be updated by HW if the VP is the target
+  of an event notification.
+
+  It is important for migration to capture the cached IPB from the NVT
+  as it synthesizes the priorities of the pending interrupts. We
+  capture a bit more to report debug information.
+
+  KVM_REG_PPC_VP_STATE (2 * 64bits)
+  bits:     |  63  ....  32  |  31  ....  0  |
+  values:   |   TIMA word0   |   TIMA word1  |
+  bits:     | 127       ..........       64  |
+  values:   |            unused              |
+
+* Migration:
+
+  Saving the state of a VM using the XIVE native exploitation mode
+  should follow a specific sequence. When the VM is stopped :
+
+  1. Mask all sources (PQ=01) to stop the flow of events.
+
+  2. Sync the XIVE device with the KVM control KVM_DEV_XIVE_EQ_SYNC to
+  flush any in-flight event notification and to stabilize the EQs. At
+  this stage, the EQ pages are marked dirty to make sure they are
+  transferred in the migration sequence.
+
+  3. Capture the state of the source targeting, the EQs configuration
+  and the state of thread interrupt context registers.
+
+  Restore is similar :
+
+  1. Restore the EQ configuration. As targeting depends on it.
+  2. Restore targeting
+  3. Restore the thread interrupt contexts
+  4. Restore the source states
+  5. Let the vCPU run
index 44205f0b671fa0b473a2c1321c768fce202c44f3..ec1efa32af3cafb0b309c2653ebc008cbdccd860 100644 (file)
@@ -189,20 +189,10 @@ the driver callback returns.
 When the device driver wants to populate a range of virtual addresses, it can
 use either::
 
-  int hmm_vma_get_pfns(struct vm_area_struct *vma,
-                      struct hmm_range *range,
-                      unsigned long start,
-                      unsigned long end,
-                      hmm_pfn_t *pfns);
-  int hmm_vma_fault(struct vm_area_struct *vma,
-                    struct hmm_range *range,
-                    unsigned long start,
-                    unsigned long end,
-                    hmm_pfn_t *pfns,
-                    bool write,
-                    bool block);
-
-The first one (hmm_vma_get_pfns()) will only fetch present CPU page table
+  long hmm_range_snapshot(struct hmm_range *range);
+  long hmm_range_fault(struct hmm_range *range, bool block);
+
+The first one (hmm_range_snapshot()) will only fetch present CPU page table
 entries and will not trigger a page fault on missing or non-present entries.
 The second one does trigger a page fault on missing or read-only entry if the
 write parameter is true. Page faults use the generic mm page fault code path
@@ -220,25 +210,56 @@ respect in order to keep things properly synchronized. The usage pattern is::
  {
       struct hmm_range range;
       ...
+
+      range.start = ...;
+      range.end = ...;
+      range.pfns = ...;
+      range.flags = ...;
+      range.values = ...;
+      range.pfn_shift = ...;
+      hmm_range_register(&range);
+
+      /*
+       * Just wait for range to be valid, safe to ignore return value as we
+       * will use the return value of hmm_range_snapshot() below under the
+       * mmap_sem to ascertain the validity of the range.
+       */
+      hmm_range_wait_until_valid(&range, TIMEOUT_IN_MSEC);
+
  again:
-      ret = hmm_vma_get_pfns(vma, &range, start, end, pfns);
-      if (ret)
+      down_read(&mm->mmap_sem);
+      ret = hmm_range_snapshot(&range);
+      if (ret) {
+          up_read(&mm->mmap_sem);
+          if (ret == -EAGAIN) {
+            /*
+             * No need to check hmm_range_wait_until_valid() return value
+             * on retry we will get proper error with hmm_range_snapshot()
+             */
+            hmm_range_wait_until_valid(&range, TIMEOUT_IN_MSEC);
+            goto again;
+          }
+          hmm_mirror_unregister(&range);
           return ret;
+      }
       take_lock(driver->update);
-      if (!hmm_vma_range_done(vma, &range)) {
+      if (!range.valid) {
           release_lock(driver->update);
+          up_read(&mm->mmap_sem);
           goto again;
       }
 
       // Use pfns array content to update device page table
 
+      hmm_mirror_unregister(&range);
       release_lock(driver->update);
+      up_read(&mm->mmap_sem);
       return 0;
  }
 
 The driver->update lock is the same lock that the driver takes inside its
-update() callback. That lock must be held before hmm_vma_range_done() to avoid
-any race with a concurrent CPU page table update.
+update() callback. That lock must be held before checking the range.valid
+field to avoid any race with a concurrent CPU page table update.
 
 HMM implements all this on top of the mmu_notifier API because we wanted a
 simpler API and also to be able to perform optimizations latter on like doing
@@ -255,6 +276,41 @@ report commands as executed is serialized (there is no point in doing this
 concurrently).
 
 
+Leverage default_flags and pfn_flags_mask
+=========================================
+
+The hmm_range struct has 2 fields default_flags and pfn_flags_mask that allows
+to set fault or snapshot policy for a whole range instead of having to set them
+for each entries in the range.
+
+For instance if the device flags for device entries are:
+    VALID (1 << 63)
+    WRITE (1 << 62)
+
+Now let say that device driver wants to fault with at least read a range then
+it does set:
+    range->default_flags = (1 << 63)
+    range->pfn_flags_mask = 0;
+
+and calls hmm_range_fault() as described above. This will fill fault all page
+in the range with at least read permission.
+
+Now let say driver wants to do the same except for one page in the range for
+which its want to have write. Now driver set:
+    range->default_flags = (1 << 63);
+    range->pfn_flags_mask = (1 << 62);
+    range->pfns[index_of_write] = (1 << 62);
+
+With this HMM will fault in all page with at least read (ie valid) and for the
+address == range->start + (index_of_write << PAGE_SHIFT) it will fault with
+write permission ie if the CPU pte does not have write permission set then HMM
+will call handle_mm_fault().
+
+Note that HMM will populate the pfns array with write permission for any entry
+that have write permission within the CPU pte no matter what are the values set
+in default_flags or pfn_flags_mask.
+
+
 Represent and manage device memory from core kernel point of view
 =================================================================
 
diff --git a/Documentation/x86/amd-memory-encryption.rst b/Documentation/x86/amd-memory-encryption.rst
new file mode 100644 (file)
index 0000000..c48d452
--- /dev/null
@@ -0,0 +1,97 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====================
+AMD Memory Encryption
+=====================
+
+Secure Memory Encryption (SME) and Secure Encrypted Virtualization (SEV) are
+features found on AMD processors.
+
+SME provides the ability to mark individual pages of memory as encrypted using
+the standard x86 page tables.  A page that is marked encrypted will be
+automatically decrypted when read from DRAM and encrypted when written to
+DRAM.  SME can therefore be used to protect the contents of DRAM from physical
+attacks on the system.
+
+SEV enables running encrypted virtual machines (VMs) in which the code and data
+of the guest VM are secured so that a decrypted version is available only
+within the VM itself. SEV guest VMs have the concept of private and shared
+memory. Private memory is encrypted with the guest-specific key, while shared
+memory may be encrypted with hypervisor key. When SME is enabled, the hypervisor
+key is the same key which is used in SME.
+
+A page is encrypted when a page table entry has the encryption bit set (see
+below on how to determine its position).  The encryption bit can also be
+specified in the cr3 register, allowing the PGD table to be encrypted. Each
+successive level of page tables can also be encrypted by setting the encryption
+bit in the page table entry that points to the next table. This allows the full
+page table hierarchy to be encrypted. Note, this means that just because the
+encryption bit is set in cr3, doesn't imply the full hierarchy is encrypted.
+Each page table entry in the hierarchy needs to have the encryption bit set to
+achieve that. So, theoretically, you could have the encryption bit set in cr3
+so that the PGD is encrypted, but not set the encryption bit in the PGD entry
+for a PUD which results in the PUD pointed to by that entry to not be
+encrypted.
+
+When SEV is enabled, instruction pages and guest page tables are always treated
+as private. All the DMA operations inside the guest must be performed on shared
+memory. Since the memory encryption bit is controlled by the guest OS when it
+is operating in 64-bit or 32-bit PAE mode, in all other modes the SEV hardware
+forces the memory encryption bit to 1.
+
+Support for SME and SEV can be determined through the CPUID instruction. The
+CPUID function 0x8000001f reports information related to SME::
+
+       0x8000001f[eax]:
+               Bit[0] indicates support for SME
+               Bit[1] indicates support for SEV
+       0x8000001f[ebx]:
+               Bits[5:0]  pagetable bit number used to activate memory
+                          encryption
+               Bits[11:6] reduction in physical address space, in bits, when
+                          memory encryption is enabled (this only affects
+                          system physical addresses, not guest physical
+                          addresses)
+
+If support for SME is present, MSR 0xc00100010 (MSR_K8_SYSCFG) can be used to
+determine if SME is enabled and/or to enable memory encryption::
+
+       0xc0010010:
+               Bit[23]   0 = memory encryption features are disabled
+                         1 = memory encryption features are enabled
+
+If SEV is supported, MSR 0xc0010131 (MSR_AMD64_SEV) can be used to determine if
+SEV is active::
+
+       0xc0010131:
+               Bit[0]    0 = memory encryption is not active
+                         1 = memory encryption is active
+
+Linux relies on BIOS to set this bit if BIOS has determined that the reduction
+in the physical address space as a result of enabling memory encryption (see
+CPUID information above) will not conflict with the address space resource
+requirements for the system.  If this bit is not set upon Linux startup then
+Linux itself will not set it and memory encryption will not be possible.
+
+The state of SME in the Linux kernel can be documented as follows:
+
+       - Supported:
+         The CPU supports SME (determined through CPUID instruction).
+
+       - Enabled:
+         Supported and bit 23 of MSR_K8_SYSCFG is set.
+
+       - Active:
+         Supported, Enabled and the Linux kernel is actively applying
+         the encryption bit to page table entries (the SME mask in the
+         kernel is non-zero).
+
+SME can also be enabled and activated in the BIOS. If SME is enabled and
+activated in the BIOS, then all memory accesses will be encrypted and it will
+not be necessary to activate the Linux memory encryption support.  If the BIOS
+merely enables SME (sets bit 23 of the MSR_K8_SYSCFG), then Linux can activate
+memory encryption by default (CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT=y) or
+by supplying mem_encrypt=on on the kernel command line.  However, if BIOS does
+not enable SME, then Linux will not be able to activate memory encryption, even
+if configured to do so by default or the mem_encrypt=on command line parameter
+is specified.
diff --git a/Documentation/x86/amd-memory-encryption.txt b/Documentation/x86/amd-memory-encryption.txt
deleted file mode 100644 (file)
index afc41f5..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-Secure Memory Encryption (SME) and Secure Encrypted Virtualization (SEV) are
-features found on AMD processors.
-
-SME provides the ability to mark individual pages of memory as encrypted using
-the standard x86 page tables.  A page that is marked encrypted will be
-automatically decrypted when read from DRAM and encrypted when written to
-DRAM.  SME can therefore be used to protect the contents of DRAM from physical
-attacks on the system.
-
-SEV enables running encrypted virtual machines (VMs) in which the code and data
-of the guest VM are secured so that a decrypted version is available only
-within the VM itself. SEV guest VMs have the concept of private and shared
-memory. Private memory is encrypted with the guest-specific key, while shared
-memory may be encrypted with hypervisor key. When SME is enabled, the hypervisor
-key is the same key which is used in SME.
-
-A page is encrypted when a page table entry has the encryption bit set (see
-below on how to determine its position).  The encryption bit can also be
-specified in the cr3 register, allowing the PGD table to be encrypted. Each
-successive level of page tables can also be encrypted by setting the encryption
-bit in the page table entry that points to the next table. This allows the full
-page table hierarchy to be encrypted. Note, this means that just because the
-encryption bit is set in cr3, doesn't imply the full hierarchy is encrypted.
-Each page table entry in the hierarchy needs to have the encryption bit set to
-achieve that. So, theoretically, you could have the encryption bit set in cr3
-so that the PGD is encrypted, but not set the encryption bit in the PGD entry
-for a PUD which results in the PUD pointed to by that entry to not be
-encrypted.
-
-When SEV is enabled, instruction pages and guest page tables are always treated
-as private. All the DMA operations inside the guest must be performed on shared
-memory. Since the memory encryption bit is controlled by the guest OS when it
-is operating in 64-bit or 32-bit PAE mode, in all other modes the SEV hardware
-forces the memory encryption bit to 1.
-
-Support for SME and SEV can be determined through the CPUID instruction. The
-CPUID function 0x8000001f reports information related to SME:
-
-       0x8000001f[eax]:
-               Bit[0] indicates support for SME
-               Bit[1] indicates support for SEV
-       0x8000001f[ebx]:
-               Bits[5:0]  pagetable bit number used to activate memory
-                          encryption
-               Bits[11:6] reduction in physical address space, in bits, when
-                          memory encryption is enabled (this only affects
-                          system physical addresses, not guest physical
-                          addresses)
-
-If support for SME is present, MSR 0xc00100010 (MSR_K8_SYSCFG) can be used to
-determine if SME is enabled and/or to enable memory encryption:
-
-       0xc0010010:
-               Bit[23]   0 = memory encryption features are disabled
-                         1 = memory encryption features are enabled
-
-If SEV is supported, MSR 0xc0010131 (MSR_AMD64_SEV) can be used to determine if
-SEV is active:
-
-       0xc0010131:
-               Bit[0]    0 = memory encryption is not active
-                         1 = memory encryption is active
-
-Linux relies on BIOS to set this bit if BIOS has determined that the reduction
-in the physical address space as a result of enabling memory encryption (see
-CPUID information above) will not conflict with the address space resource
-requirements for the system.  If this bit is not set upon Linux startup then
-Linux itself will not set it and memory encryption will not be possible.
-
-The state of SME in the Linux kernel can be documented as follows:
-       - Supported:
-         The CPU supports SME (determined through CPUID instruction).
-
-       - Enabled:
-         Supported and bit 23 of MSR_K8_SYSCFG is set.
-
-       - Active:
-         Supported, Enabled and the Linux kernel is actively applying
-         the encryption bit to page table entries (the SME mask in the
-         kernel is non-zero).
-
-SME can also be enabled and activated in the BIOS. If SME is enabled and
-activated in the BIOS, then all memory accesses will be encrypted and it will
-not be necessary to activate the Linux memory encryption support.  If the BIOS
-merely enables SME (sets bit 23 of the MSR_K8_SYSCFG), then Linux can activate
-memory encryption by default (CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT=y) or
-by supplying mem_encrypt=on on the kernel command line.  However, if BIOS does
-not enable SME, then Linux will not be able to activate memory encryption, even
-if configured to do so by default or the mem_encrypt=on command line parameter
-is specified.
diff --git a/Documentation/x86/boot.rst b/Documentation/x86/boot.rst
new file mode 100644 (file)
index 0000000..08a2f10
--- /dev/null
@@ -0,0 +1,1256 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===========================
+The Linux/x86 Boot Protocol
+===========================
+
+On the x86 platform, the Linux kernel uses a rather complicated boot
+convention.  This has evolved partially due to historical aspects, as
+well as the desire in the early days to have the kernel itself be a
+bootable image, the complicated PC memory model and due to changed
+expectations in the PC industry caused by the effective demise of
+real-mode DOS as a mainstream operating system.
+
+Currently, the following versions of the Linux/x86 boot protocol exist.
+
+=============  ============================================================
+Old kernels    zImage/Image support only.  Some very early kernels
+               may not even support a command line.
+
+Protocol 2.00  (Kernel 1.3.73) Added bzImage and initrd support, as
+               well as a formalized way to communicate between the
+               boot loader and the kernel.  setup.S made relocatable,
+               although the traditional setup area still assumed
+               writable.
+
+Protocol 2.01  (Kernel 1.3.76) Added a heap overrun warning.
+
+Protocol 2.02  (Kernel 2.4.0-test3-pre3) New command line protocol.
+               Lower the conventional memory ceiling.  No overwrite
+               of the traditional setup area, thus making booting
+               safe for systems which use the EBDA from SMM or 32-bit
+               BIOS entry points.  zImage deprecated but still
+               supported.
+
+Protocol 2.03  (Kernel 2.4.18-pre1) Explicitly makes the highest possible
+               initrd address available to the bootloader.
+
+Protocol 2.04  (Kernel 2.6.14) Extend the syssize field to four bytes.
+
+Protocol 2.05  (Kernel 2.6.20) Make protected mode kernel relocatable.
+               Introduce relocatable_kernel and kernel_alignment fields.
+
+Protocol 2.06  (Kernel 2.6.22) Added a field that contains the size of
+               the boot command line.
+
+Protocol 2.07  (Kernel 2.6.24) Added paravirtualised boot protocol.
+               Introduced hardware_subarch and hardware_subarch_data
+               and KEEP_SEGMENTS flag in load_flags.
+
+Protocol 2.08  (Kernel 2.6.26) Added crc32 checksum and ELF format
+               payload. Introduced payload_offset and payload_length
+               fields to aid in locating the payload.
+
+Protocol 2.09  (Kernel 2.6.26) Added a field of 64-bit physical
+               pointer to single linked list of struct setup_data.
+
+Protocol 2.10  (Kernel 2.6.31) Added a protocol for relaxed alignment
+               beyond the kernel_alignment added, new init_size and
+               pref_address fields.  Added extended boot loader IDs.
+
+Protocol 2.11  (Kernel 3.6) Added a field for offset of EFI handover
+               protocol entry point.
+
+Protocol 2.12  (Kernel 3.8) Added the xloadflags field and extension fields
+               to struct boot_params for loading bzImage and ramdisk
+               above 4G in 64bit.
+
+Protocol 2.13  (Kernel 3.14) Support 32- and 64-bit flags being set in
+               xloadflags to support booting a 64-bit kernel from 32-bit
+               EFI
+=============  ============================================================
+
+
+Memory Layout
+=============
+
+The traditional memory map for the kernel loader, used for Image or
+zImage kernels, typically looks like::
+
+               |                        |
+       0A0000  +------------------------+
+               |  Reserved for BIOS     |      Do not use.  Reserved for BIOS EBDA.
+       09A000  +------------------------+
+               |  Command line          |
+               |  Stack/heap            |      For use by the kernel real-mode code.
+       098000  +------------------------+
+               |  Kernel setup          |      The kernel real-mode code.
+       090200  +------------------------+
+               |  Kernel boot sector    |      The kernel legacy boot sector.
+       090000  +------------------------+
+               |  Protected-mode kernel |      The bulk of the kernel image.
+       010000  +------------------------+
+               |  Boot loader           |      <- Boot sector entry point 0000:7C00
+       001000  +------------------------+
+               |  Reserved for MBR/BIOS |
+       000800  +------------------------+
+               |  Typically used by MBR |
+       000600  +------------------------+
+               |  BIOS use only         |
+       000000  +------------------------+
+
+When using bzImage, the protected-mode kernel was relocated to
+0x100000 ("high memory"), and the kernel real-mode block (boot sector,
+setup, and stack/heap) was made relocatable to any address between
+0x10000 and end of low memory. Unfortunately, in protocols 2.00 and
+2.01 the 0x90000+ memory range is still used internally by the kernel;
+the 2.02 protocol resolves that problem.
+
+It is desirable to keep the "memory ceiling" -- the highest point in
+low memory touched by the boot loader -- as low as possible, since
+some newer BIOSes have begun to allocate some rather large amounts of
+memory, called the Extended BIOS Data Area, near the top of low
+memory.         The boot loader should use the "INT 12h" BIOS call to verify
+how much low memory is available.
+
+Unfortunately, if INT 12h reports that the amount of memory is too
+low, there is usually nothing the boot loader can do but to report an
+error to the user.  The boot loader should therefore be designed to
+take up as little space in low memory as it reasonably can.  For
+zImage or old bzImage kernels, which need data written into the
+0x90000 segment, the boot loader should make sure not to use memory
+above the 0x9A000 point; too many BIOSes will break above that point.
+
+For a modern bzImage kernel with boot protocol version >= 2.02, a
+memory layout like the following is suggested::
+
+               ~                        ~
+               |  Protected-mode kernel |
+       100000  +------------------------+
+               |  I/O memory hole       |
+       0A0000  +------------------------+
+               |  Reserved for BIOS     |      Leave as much as possible unused
+               ~                        ~
+               |  Command line          |      (Can also be below the X+10000 mark)
+       X+10000 +------------------------+
+               |  Stack/heap            |      For use by the kernel real-mode code.
+       X+08000 +------------------------+
+               |  Kernel setup          |      The kernel real-mode code.
+               |  Kernel boot sector    |      The kernel legacy boot sector.
+       X       +------------------------+
+               |  Boot loader           |      <- Boot sector entry point 0000:7C00
+       001000  +------------------------+
+               |  Reserved for MBR/BIOS |
+       000800  +------------------------+
+               |  Typically used by MBR |
+       000600  +------------------------+
+               |  BIOS use only         |
+       000000  +------------------------+
+
+  ... where the address X is as low as the design of the boot loader permits.
+
+
+The Real-Mode Kernel Header
+===========================
+
+In the following text, and anywhere in the kernel boot sequence, "a
+sector" refers to 512 bytes.  It is independent of the actual sector
+size of the underlying medium.
+
+The first step in loading a Linux kernel should be to load the
+real-mode code (boot sector and setup code) and then examine the
+following header at offset 0x01f1.  The real-mode code can total up to
+32K, although the boot loader may choose to load only the first two
+sectors (1K) and then examine the bootup sector size.
+
+The header looks like:
+
+===========    ========        =====================   ============================================
+Offset/Size    Proto           Name                    Meaning
+===========    ========        =====================   ============================================
+01F1/1         ALL(1)          setup_sects             The size of the setup in sectors
+01F2/2         ALL             root_flags              If set, the root is mounted readonly
+01F4/4         2.04+(2)        syssize                 The size of the 32-bit code in 16-byte paras
+01F8/2         ALL             ram_size                DO NOT USE - for bootsect.S use only
+01FA/2         ALL             vid_mode                Video mode control
+01FC/2         ALL             root_dev                Default root device number
+01FE/2         ALL             boot_flag               0xAA55 magic number
+0200/2         2.00+           jump                    Jump instruction
+0202/4         2.00+           header                  Magic signature "HdrS"
+0206/2         2.00+           version                 Boot protocol version supported
+0208/4         2.00+           realmode_swtch          Boot loader hook (see below)
+020C/2         2.00+           start_sys_seg           The load-low segment (0x1000) (obsolete)
+020E/2         2.00+           kernel_version          Pointer to kernel version string
+0210/1         2.00+           type_of_loader          Boot loader identifier
+0211/1         2.00+           loadflags               Boot protocol option flags
+0212/2         2.00+           setup_move_size         Move to high memory size (used with hooks)
+0214/4         2.00+           code32_start            Boot loader hook (see below)
+0218/4         2.00+           ramdisk_image           initrd load address (set by boot loader)
+021C/4         2.00+           ramdisk_size            initrd size (set by boot loader)
+0220/4         2.00+           bootsect_kludge         DO NOT USE - for bootsect.S use only
+0224/2         2.01+           heap_end_ptr            Free memory after setup end
+0226/1         2.02+(3)        ext_loader_ver          Extended boot loader version
+0227/1         2.02+(3)        ext_loader_type         Extended boot loader ID
+0228/4         2.02+           cmd_line_ptr            32-bit pointer to the kernel command line
+022C/4         2.03+           initrd_addr_max         Highest legal initrd address
+0230/4         2.05+           kernel_alignment        Physical addr alignment required for kernel
+0234/1         2.05+           relocatable_kernel      Whether kernel is relocatable or not
+0235/1         2.10+           min_alignment           Minimum alignment, as a power of two
+0236/2         2.12+           xloadflags              Boot protocol option flags
+0238/4         2.06+           cmdline_size            Maximum size of the kernel command line
+023C/4         2.07+           hardware_subarch        Hardware subarchitecture
+0240/8         2.07+           hardware_subarch_data   Subarchitecture-specific data
+0248/4         2.08+           payload_offset          Offset of kernel payload
+024C/4         2.08+           payload_length          Length of kernel payload
+0250/8         2.09+           setup_data              64-bit physical pointer to linked list
+                                                       of struct setup_data
+0258/8         2.10+           pref_address            Preferred loading address
+0260/4         2.10+           init_size               Linear memory required during initialization
+0264/4         2.11+           handover_offset         Offset of handover entry point
+===========    ========        =====================   ============================================
+
+.. note::
+  (1) For backwards compatibility, if the setup_sects field contains 0, the
+      real value is 4.
+
+  (2) For boot protocol prior to 2.04, the upper two bytes of the syssize
+      field are unusable, which means the size of a bzImage kernel
+      cannot be determined.
+
+  (3) Ignored, but safe to set, for boot protocols 2.02-2.09.
+
+If the "HdrS" (0x53726448) magic number is not found at offset 0x202,
+the boot protocol version is "old".  Loading an old kernel, the
+following parameters should be assumed::
+
+       Image type = zImage
+       initrd not supported
+       Real-mode kernel must be located at 0x90000.
+
+Otherwise, the "version" field contains the protocol version,
+e.g. protocol version 2.01 will contain 0x0201 in this field.  When
+setting fields in the header, you must make sure only to set fields
+supported by the protocol version in use.
+
+
+Details of Harder Fileds
+========================
+
+For each field, some are information from the kernel to the bootloader
+("read"), some are expected to be filled out by the bootloader
+("write"), and some are expected to be read and modified by the
+bootloader ("modify").
+
+All general purpose boot loaders should write the fields marked
+(obligatory).  Boot loaders who want to load the kernel at a
+nonstandard address should fill in the fields marked (reloc); other
+boot loaders can ignore those fields.
+
+The byte order of all fields is littleendian (this is x86, after all.)
+
+============   ===========
+Field name:    setup_sects
+Type:          read
+Offset/size:   0x1f1/1
+Protocol:      ALL
+============   ===========
+
+  The size of the setup code in 512-byte sectors.  If this field is
+  0, the real value is 4.  The real-mode code consists of the boot
+  sector (always one 512-byte sector) plus the setup code.
+
+============   =================
+Field name:    root_flags
+Type:          modify (optional)
+Offset/size:   0x1f2/2
+Protocol:      ALL
+============   =================
+
+  If this field is nonzero, the root defaults to readonly.  The use of
+  this field is deprecated; use the "ro" or "rw" options on the
+  command line instead.
+
+============   ===============================================
+Field name:    syssize
+Type:          read
+Offset/size:   0x1f4/4 (protocol 2.04+) 0x1f4/2 (protocol ALL)
+Protocol:      2.04+
+============   ===============================================
+
+  The size of the protected-mode code in units of 16-byte paragraphs.
+  For protocol versions older than 2.04 this field is only two bytes
+  wide, and therefore cannot be trusted for the size of a kernel if
+  the LOAD_HIGH flag is set.
+
+============   ===============
+Field name:    ram_size
+Type:          kernel internal
+Offset/size:   0x1f8/2
+Protocol:      ALL
+============   ===============
+
+  This field is obsolete.
+
+============   ===================
+Field name:    vid_mode
+Type:          modify (obligatory)
+Offset/size:   0x1fa/2
+============   ===================
+
+  Please see the section on SPECIAL COMMAND LINE OPTIONS.
+
+============   =================
+Field name:    root_dev
+Type:          modify (optional)
+Offset/size:   0x1fc/2
+Protocol:      ALL
+============   =================
+
+  The default root device device number.  The use of this field is
+  deprecated, use the "root=" option on the command line instead.
+
+============   =========
+Field name:    boot_flag
+Type:          read
+Offset/size:   0x1fe/2
+Protocol:      ALL
+============   =========
+
+  Contains 0xAA55.  This is the closest thing old Linux kernels have
+  to a magic number.
+
+============   =======
+Field name:    jump
+Type:          read
+Offset/size:   0x200/2
+Protocol:      2.00+
+============   =======
+
+  Contains an x86 jump instruction, 0xEB followed by a signed offset
+  relative to byte 0x202.  This can be used to determine the size of
+  the header.
+
+============   =======
+Field name:    header
+Type:          read
+Offset/size:   0x202/4
+Protocol:      2.00+
+============   =======
+
+  Contains the magic number "HdrS" (0x53726448).
+
+============   =======
+Field name:    version
+Type:          read
+Offset/size:   0x206/2
+Protocol:      2.00+
+============   =======
+
+  Contains the boot protocol version, in (major << 8)+minor format,
+  e.g. 0x0204 for version 2.04, and 0x0a11 for a hypothetical version
+  10.17.
+
+============   =================
+Field name:    realmode_swtch
+Type:          modify (optional)
+Offset/size:   0x208/4
+Protocol:      2.00+
+============   =================
+
+  Boot loader hook (see ADVANCED BOOT LOADER HOOKS below.)
+
+============   =============
+Field name:    start_sys_seg
+Type:          read
+Offset/size:   0x20c/2
+Protocol:      2.00+
+============   =============
+
+  The load low segment (0x1000).  Obsolete.
+
+============   ==============
+Field name:    kernel_version
+Type:          read
+Offset/size:   0x20e/2
+Protocol:      2.00+
+============   ==============
+
+  If set to a nonzero value, contains a pointer to a NUL-terminated
+  human-readable kernel version number string, less 0x200.  This can
+  be used to display the kernel version to the user.  This value
+  should be less than (0x200*setup_sects).
+
+  For example, if this value is set to 0x1c00, the kernel version
+  number string can be found at offset 0x1e00 in the kernel file.
+  This is a valid value if and only if the "setup_sects" field
+  contains the value 15 or higher, as::
+
+       0x1c00  < 15*0x200 (= 0x1e00) but
+       0x1c00 >= 14*0x200 (= 0x1c00)
+
+       0x1c00 >> 9 = 14, So the minimum value for setup_secs is 15.
+
+============   ==================
+Field name:    type_of_loader
+Type:          write (obligatory)
+Offset/size:   0x210/1
+Protocol:      2.00+
+============   ==================
+
+  If your boot loader has an assigned id (see table below), enter
+  0xTV here, where T is an identifier for the boot loader and V is
+  a version number.  Otherwise, enter 0xFF here.
+
+  For boot loader IDs above T = 0xD, write T = 0xE to this field and
+  write the extended ID minus 0x10 to the ext_loader_type field.
+  Similarly, the ext_loader_ver field can be used to provide more than
+  four bits for the bootloader version.
+
+  For example, for T = 0x15, V = 0x234, write::
+
+       type_of_loader  <- 0xE4
+       ext_loader_type <- 0x05
+       ext_loader_ver  <- 0x23
+
+  Assigned boot loader ids (hexadecimal):
+
+       == =======================================
+       0  LILO
+          (0x00 reserved for pre-2.00 bootloader)
+       1  Loadlin
+       2  bootsect-loader
+          (0x20, all other values reserved)
+       3  Syslinux
+       4  Etherboot/gPXE/iPXE
+       5  ELILO
+       7  GRUB
+       8  U-Boot
+       9  Xen
+       A  Gujin
+       B  Qemu
+       C  Arcturus Networks uCbootloader
+       D  kexec-tools
+       E  Extended (see ext_loader_type)
+       F  Special (0xFF = undefined)
+       10 Reserved
+       11 Minimal Linux Bootloader
+          <http://sebastian-plotz.blogspot.de>
+       12 OVMF UEFI virtualization stack
+       == =======================================
+
+  Please contact <hpa@zytor.com> if you need a bootloader ID value assigned.
+
+============   ===================
+Field name:    loadflags
+Type:          modify (obligatory)
+Offset/size:   0x211/1
+Protocol:      2.00+
+============   ===================
+
+  This field is a bitmask.
+
+  Bit 0 (read):        LOADED_HIGH
+
+       - If 0, the protected-mode code is loaded at 0x10000.
+       - If 1, the protected-mode code is loaded at 0x100000.
+
+  Bit 1 (kernel internal): KASLR_FLAG
+
+       - Used internally by the compressed kernel to communicate
+         KASLR status to kernel proper.
+
+           - If 1, KASLR enabled.
+           - If 0, KASLR disabled.
+
+  Bit 5 (write): QUIET_FLAG
+
+       - If 0, print early messages.
+       - If 1, suppress early messages.
+
+               This requests to the kernel (decompressor and early
+               kernel) to not write early messages that require
+               accessing the display hardware directly.
+
+  Bit 6 (write): KEEP_SEGMENTS
+
+       Protocol: 2.07+
+
+       - If 0, reload the segment registers in the 32bit entry point.
+       - If 1, do not reload the segment registers in the 32bit entry point.
+
+               Assume that %cs %ds %ss %es are all set to flat segments with
+               a base of 0 (or the equivalent for their environment).
+
+  Bit 7 (write): CAN_USE_HEAP
+
+       Set this bit to 1 to indicate that the value entered in the
+       heap_end_ptr is valid.  If this field is clear, some setup code
+       functionality will be disabled.
+
+
+============   ===================
+Field name:    setup_move_size
+Type:          modify (obligatory)
+Offset/size:   0x212/2
+Protocol:      2.00-2.01
+============   ===================
+
+  When using protocol 2.00 or 2.01, if the real mode kernel is not
+  loaded at 0x90000, it gets moved there later in the loading
+  sequence.  Fill in this field if you want additional data (such as
+  the kernel command line) moved in addition to the real-mode kernel
+  itself.
+
+  The unit is bytes starting with the beginning of the boot sector.
+
+  This field is can be ignored when the protocol is 2.02 or higher, or
+  if the real-mode code is loaded at 0x90000.
+
+============   ========================
+Field name:    code32_start
+Type:          modify (optional, reloc)
+Offset/size:   0x214/4
+Protocol:      2.00+
+============   ========================
+
+  The address to jump to in protected mode.  This defaults to the load
+  address of the kernel, and can be used by the boot loader to
+  determine the proper load address.
+
+  This field can be modified for two purposes:
+
+    1. as a boot loader hook (see Advanced Boot Loader Hooks below.)
+
+    2. if a bootloader which does not install a hook loads a
+       relocatable kernel at a nonstandard address it will have to modify
+       this field to point to the load address.
+
+============   ==================
+Field name:    ramdisk_image
+Type:          write (obligatory)
+Offset/size:   0x218/4
+Protocol:      2.00+
+============   ==================
+
+  The 32-bit linear address of the initial ramdisk or ramfs.  Leave at
+  zero if there is no initial ramdisk/ramfs.
+
+============   ==================
+Field name:    ramdisk_size
+Type:          write (obligatory)
+Offset/size:   0x21c/4
+Protocol:      2.00+
+============   ==================
+
+  Size of the initial ramdisk or ramfs.  Leave at zero if there is no
+  initial ramdisk/ramfs.
+
+============   ===============
+Field name:    bootsect_kludge
+Type:          kernel internal
+Offset/size:   0x220/4
+Protocol:      2.00+
+============   ===============
+
+  This field is obsolete.
+
+============   ==================
+Field name:    heap_end_ptr
+Type:          write (obligatory)
+Offset/size:   0x224/2
+Protocol:      2.01+
+============   ==================
+
+  Set this field to the offset (from the beginning of the real-mode
+  code) of the end of the setup stack/heap, minus 0x0200.
+
+============   ================
+Field name:    ext_loader_ver
+Type:          write (optional)
+Offset/size:   0x226/1
+Protocol:      2.02+
+============   ================
+
+  This field is used as an extension of the version number in the
+  type_of_loader field.  The total version number is considered to be
+  (type_of_loader & 0x0f) + (ext_loader_ver << 4).
+
+  The use of this field is boot loader specific.  If not written, it
+  is zero.
+
+  Kernels prior to 2.6.31 did not recognize this field, but it is safe
+  to write for protocol version 2.02 or higher.
+
+============   =====================================================
+Field name:    ext_loader_type
+Type:          write (obligatory if (type_of_loader & 0xf0) == 0xe0)
+Offset/size:   0x227/1
+Protocol:      2.02+
+============   =====================================================
+
+  This field is used as an extension of the type number in
+  type_of_loader field.  If the type in type_of_loader is 0xE, then
+  the actual type is (ext_loader_type + 0x10).
+
+  This field is ignored if the type in type_of_loader is not 0xE.
+
+  Kernels prior to 2.6.31 did not recognize this field, but it is safe
+  to write for protocol version 2.02 or higher.
+
+============   ==================
+Field name:    cmd_line_ptr
+Type:          write (obligatory)
+Offset/size:   0x228/4
+Protocol:      2.02+
+============   ==================
+
+  Set this field to the linear address of the kernel command line.
+  The kernel command line can be located anywhere between the end of
+  the setup heap and 0xA0000; it does not have to be located in the
+  same 64K segment as the real-mode code itself.
+
+  Fill in this field even if your boot loader does not support a
+  command line, in which case you can point this to an empty string
+  (or better yet, to the string "auto".)  If this field is left at
+  zero, the kernel will assume that your boot loader does not support
+  the 2.02+ protocol.
+
+============   ===============
+Field name:    initrd_addr_max
+Type:          read
+Offset/size:   0x22c/4
+Protocol:      2.03+
+============   ===============
+
+  The maximum address that may be occupied by the initial
+  ramdisk/ramfs contents.  For boot protocols 2.02 or earlier, this
+  field is not present, and the maximum address is 0x37FFFFFF.  (This
+  address is defined as the address of the highest safe byte, so if
+  your ramdisk is exactly 131072 bytes long and this field is
+  0x37FFFFFF, you can start your ramdisk at 0x37FE0000.)
+
+============   ============================
+Field name:    kernel_alignment
+Type:          read/modify (reloc)
+Offset/size:   0x230/4
+Protocol:      2.05+ (read), 2.10+ (modify)
+============   ============================
+
+  Alignment unit required by the kernel (if relocatable_kernel is
+  true.)  A relocatable kernel that is loaded at an alignment
+  incompatible with the value in this field will be realigned during
+  kernel initialization.
+
+  Starting with protocol version 2.10, this reflects the kernel
+  alignment preferred for optimal performance; it is possible for the
+  loader to modify this field to permit a lesser alignment.  See the
+  min_alignment and pref_address field below.
+
+============   ==================
+Field name:    relocatable_kernel
+Type:          read (reloc)
+Offset/size:   0x234/1
+Protocol:      2.05+
+============   ==================
+
+  If this field is nonzero, the protected-mode part of the kernel can
+  be loaded at any address that satisfies the kernel_alignment field.
+  After loading, the boot loader must set the code32_start field to
+  point to the loaded code, or to a boot loader hook.
+
+============   =============
+Field name:    min_alignment
+Type:          read (reloc)
+Offset/size:   0x235/1
+Protocol:      2.10+
+============   =============
+
+  This field, if nonzero, indicates as a power of two the minimum
+  alignment required, as opposed to preferred, by the kernel to boot.
+  If a boot loader makes use of this field, it should update the
+  kernel_alignment field with the alignment unit desired; typically::
+
+       kernel_alignment = 1 << min_alignment
+
+  There may be a considerable performance cost with an excessively
+  misaligned kernel.  Therefore, a loader should typically try each
+  power-of-two alignment from kernel_alignment down to this alignment.
+
+============   ==========
+Field name:    xloadflags
+Type:          read
+Offset/size:   0x236/2
+Protocol:      2.12+
+============   ==========
+
+  This field is a bitmask.
+
+  Bit 0 (read):        XLF_KERNEL_64
+
+       - If 1, this kernel has the legacy 64-bit entry point at 0x200.
+
+  Bit 1 (read): XLF_CAN_BE_LOADED_ABOVE_4G
+
+        - If 1, kernel/boot_params/cmdline/ramdisk can be above 4G.
+
+  Bit 2 (read):        XLF_EFI_HANDOVER_32
+
+       - If 1, the kernel supports the 32-bit EFI handoff entry point
+          given at handover_offset.
+
+  Bit 3 (read): XLF_EFI_HANDOVER_64
+
+       - If 1, the kernel supports the 64-bit EFI handoff entry point
+          given at handover_offset + 0x200.
+
+  Bit 4 (read): XLF_EFI_KEXEC
+
+       - If 1, the kernel supports kexec EFI boot with EFI runtime support.
+
+
+============   ============
+Field name:    cmdline_size
+Type:          read
+Offset/size:   0x238/4
+Protocol:      2.06+
+============   ============
+
+  The maximum size of the command line without the terminating
+  zero. This means that the command line can contain at most
+  cmdline_size characters. With protocol version 2.05 and earlier, the
+  maximum size was 255.
+
+============   ====================================
+Field name:    hardware_subarch
+Type:          write (optional, defaults to x86/PC)
+Offset/size:   0x23c/4
+Protocol:      2.07+
+============   ====================================
+
+  In a paravirtualized environment the hardware low level architectural
+  pieces such as interrupt handling, page table handling, and
+  accessing process control registers needs to be done differently.
+
+  This field allows the bootloader to inform the kernel we are in one
+  one of those environments.
+
+  ==========   ==============================
+  0x00000000   The default x86/PC environment
+  0x00000001   lguest
+  0x00000002   Xen
+  0x00000003   Moorestown MID
+  0x00000004   CE4100 TV Platform
+  ==========   ==============================
+
+============   =========================
+Field name:    hardware_subarch_data
+Type:          write (subarch-dependent)
+Offset/size:   0x240/8
+Protocol:      2.07+
+============   =========================
+
+  A pointer to data that is specific to hardware subarch
+  This field is currently unused for the default x86/PC environment,
+  do not modify.
+
+============   ==============
+Field name:    payload_offset
+Type:          read
+Offset/size:   0x248/4
+Protocol:      2.08+
+============   ==============
+
+  If non-zero then this field contains the offset from the beginning
+  of the protected-mode code to the payload.
+
+  The payload may be compressed. The format of both the compressed and
+  uncompressed data should be determined using the standard magic
+  numbers.  The currently supported compression formats are gzip
+  (magic numbers 1F 8B or 1F 9E), bzip2 (magic number 42 5A), LZMA
+  (magic number 5D 00), XZ (magic number FD 37), and LZ4 (magic number
+  02 21).  The uncompressed payload is currently always ELF (magic
+  number 7F 45 4C 46).
+
+============   ==============
+Field name:    payload_length
+Type:          read
+Offset/size:   0x24c/4
+Protocol:      2.08+
+============   ==============
+
+  The length of the payload.
+
+============   ===============
+Field name:    setup_data
+Type:          write (special)
+Offset/size:   0x250/8
+Protocol:      2.09+
+============   ===============
+
+  The 64-bit physical pointer to NULL terminated single linked list of
+  struct setup_data. This is used to define a more extensible boot
+  parameters passing mechanism. The definition of struct setup_data is
+  as follow::
+
+       struct setup_data {
+               u64 next;
+               u32 type;
+               u32 len;
+               u8  data[0];
+       };
+
+  Where, the next is a 64-bit physical pointer to the next node of
+  linked list, the next field of the last node is 0; the type is used
+  to identify the contents of data; the len is the length of data
+  field; the data holds the real payload.
+
+  This list may be modified at a number of points during the bootup
+  process.  Therefore, when modifying this list one should always make
+  sure to consider the case where the linked list already contains
+  entries.
+
+============   ============
+Field name:    pref_address
+Type:          read (reloc)
+Offset/size:   0x258/8
+Protocol:      2.10+
+============   ============
+
+  This field, if nonzero, represents a preferred load address for the
+  kernel.  A relocating bootloader should attempt to load at this
+  address if possible.
+
+  A non-relocatable kernel will unconditionally move itself and to run
+  at this address.
+
+============   =======
+Field name:    init_size
+Type:          read
+Offset/size:   0x260/4
+============   =======
+
+  This field indicates the amount of linear contiguous memory starting
+  at the kernel runtime start address that the kernel needs before it
+  is capable of examining its memory map.  This is not the same thing
+  as the total amount of memory the kernel needs to boot, but it can
+  be used by a relocating boot loader to help select a safe load
+  address for the kernel.
+
+  The kernel runtime start address is determined by the following algorithm::
+
+       if (relocatable_kernel)
+       runtime_start = align_up(load_address, kernel_alignment)
+       else
+       runtime_start = pref_address
+
+============   ===============
+Field name:    handover_offset
+Type:          read
+Offset/size:   0x264/4
+============   ===============
+
+  This field is the offset from the beginning of the kernel image to
+  the EFI handover protocol entry point. Boot loaders using the EFI
+  handover protocol to boot the kernel should jump to this offset.
+
+  See EFI HANDOVER PROTOCOL below for more details.
+
+
+The Image Checksum
+==================
+
+From boot protocol version 2.08 onwards the CRC-32 is calculated over
+the entire file using the characteristic polynomial 0x04C11DB7 and an
+initial remainder of 0xffffffff.  The checksum is appended to the
+file; therefore the CRC of the file up to the limit specified in the
+syssize field of the header is always 0.
+
+
+The Kernel Command Line
+=======================
+
+The kernel command line has become an important way for the boot
+loader to communicate with the kernel.  Some of its options are also
+relevant to the boot loader itself, see "special command line options"
+below.
+
+The kernel command line is a null-terminated string. The maximum
+length can be retrieved from the field cmdline_size.  Before protocol
+version 2.06, the maximum was 255 characters.  A string that is too
+long will be automatically truncated by the kernel.
+
+If the boot protocol version is 2.02 or later, the address of the
+kernel command line is given by the header field cmd_line_ptr (see
+above.)  This address can be anywhere between the end of the setup
+heap and 0xA0000.
+
+If the protocol version is *not* 2.02 or higher, the kernel
+command line is entered using the following protocol:
+
+  - At offset 0x0020 (word), "cmd_line_magic", enter the magic
+    number 0xA33F.
+
+  - At offset 0x0022 (word), "cmd_line_offset", enter the offset
+    of the kernel command line (relative to the start of the
+    real-mode kernel).
+
+  - The kernel command line *must* be within the memory region
+    covered by setup_move_size, so you may need to adjust this
+    field.
+
+
+Memory Layout of The Real-Mode Code
+===================================
+
+The real-mode code requires a stack/heap to be set up, as well as
+memory allocated for the kernel command line.  This needs to be done
+in the real-mode accessible memory in bottom megabyte.
+
+It should be noted that modern machines often have a sizable Extended
+BIOS Data Area (EBDA).  As a result, it is advisable to use as little
+of the low megabyte as possible.
+
+Unfortunately, under the following circumstances the 0x90000 memory
+segment has to be used:
+
+       - When loading a zImage kernel ((loadflags & 0x01) == 0).
+       - When loading a 2.01 or earlier boot protocol kernel.
+
+.. note::
+     For the 2.00 and 2.01 boot protocols, the real-mode code
+     can be loaded at another address, but it is internally
+     relocated to 0x90000.  For the "old" protocol, the
+     real-mode code must be loaded at 0x90000.
+
+When loading at 0x90000, avoid using memory above 0x9a000.
+
+For boot protocol 2.02 or higher, the command line does not have to be
+located in the same 64K segment as the real-mode setup code; it is
+thus permitted to give the stack/heap the full 64K segment and locate
+the command line above it.
+
+The kernel command line should not be located below the real-mode
+code, nor should it be located in high memory.
+
+
+Sample Boot Configuartion
+=========================
+
+As a sample configuration, assume the following layout of the real
+mode segment.
+
+    When loading below 0x90000, use the entire segment:
+
+        =============  ===================
+       0x0000-0x7fff   Real mode kernel
+       0x8000-0xdfff   Stack and heap
+       0xe000-0xffff   Kernel command line
+       =============   ===================
+
+    When loading at 0x90000 OR the protocol version is 2.01 or earlier:
+
+       =============   ===================
+       0x0000-0x7fff   Real mode kernel
+       0x8000-0x97ff   Stack and heap
+       0x9800-0x9fff   Kernel command line
+       =============   ===================
+
+Such a boot loader should enter the following fields in the header::
+
+       unsigned long base_ptr; /* base address for real-mode segment */
+
+       if ( setup_sects == 0 ) {
+               setup_sects = 4;
+       }
+
+       if ( protocol >= 0x0200 ) {
+               type_of_loader = <type code>;
+               if ( loading_initrd ) {
+                       ramdisk_image = <initrd_address>;
+                       ramdisk_size = <initrd_size>;
+               }
+
+               if ( protocol >= 0x0202 && loadflags & 0x01 )
+                       heap_end = 0xe000;
+               else
+                       heap_end = 0x9800;
+
+               if ( protocol >= 0x0201 ) {
+                       heap_end_ptr = heap_end - 0x200;
+                       loadflags |= 0x80; /* CAN_USE_HEAP */
+               }
+
+               if ( protocol >= 0x0202 ) {
+                       cmd_line_ptr = base_ptr + heap_end;
+                       strcpy(cmd_line_ptr, cmdline);
+               } else {
+                       cmd_line_magic  = 0xA33F;
+                       cmd_line_offset = heap_end;
+                       setup_move_size = heap_end + strlen(cmdline)+1;
+                       strcpy(base_ptr+cmd_line_offset, cmdline);
+               }
+       } else {
+               /* Very old kernel */
+
+               heap_end = 0x9800;
+
+               cmd_line_magic  = 0xA33F;
+               cmd_line_offset = heap_end;
+
+               /* A very old kernel MUST have its real-mode code
+                  loaded at 0x90000 */
+
+               if ( base_ptr != 0x90000 ) {
+                       /* Copy the real-mode kernel */
+                       memcpy(0x90000, base_ptr, (setup_sects+1)*512);
+                       base_ptr = 0x90000;              /* Relocated */
+               }
+
+               strcpy(0x90000+cmd_line_offset, cmdline);
+
+               /* It is recommended to clear memory up to the 32K mark */
+               memset(0x90000 + (setup_sects+1)*512, 0,
+                      (64-(setup_sects+1))*512);
+       }
+
+
+Loading The Rest of The Kernel
+==============================
+
+The 32-bit (non-real-mode) kernel starts at offset (setup_sects+1)*512
+in the kernel file (again, if setup_sects == 0 the real value is 4.)
+It should be loaded at address 0x10000 for Image/zImage kernels and
+0x100000 for bzImage kernels.
+
+The kernel is a bzImage kernel if the protocol >= 2.00 and the 0x01
+bit (LOAD_HIGH) in the loadflags field is set::
+
+       is_bzImage = (protocol >= 0x0200) && (loadflags & 0x01);
+       load_address = is_bzImage ? 0x100000 : 0x10000;
+
+Note that Image/zImage kernels can be up to 512K in size, and thus use
+the entire 0x10000-0x90000 range of memory.  This means it is pretty
+much a requirement for these kernels to load the real-mode part at
+0x90000.  bzImage kernels allow much more flexibility.
+
+Special Command Line Options
+============================
+
+If the command line provided by the boot loader is entered by the
+user, the user may expect the following command line options to work.
+They should normally not be deleted from the kernel command line even
+though not all of them are actually meaningful to the kernel.  Boot
+loader authors who need additional command line options for the boot
+loader itself should get them registered in
+Documentation/admin-guide/kernel-parameters.rst to make sure they will not
+conflict with actual kernel options now or in the future.
+
+  vga=<mode>
+       <mode> here is either an integer (in C notation, either
+       decimal, octal, or hexadecimal) or one of the strings
+       "normal" (meaning 0xFFFF), "ext" (meaning 0xFFFE) or "ask"
+       (meaning 0xFFFD).  This value should be entered into the
+       vid_mode field, as it is used by the kernel before the command
+       line is parsed.
+
+  mem=<size>
+       <size> is an integer in C notation optionally followed by
+       (case insensitive) K, M, G, T, P or E (meaning << 10, << 20,
+       << 30, << 40, << 50 or << 60).  This specifies the end of
+       memory to the kernel. This affects the possible placement of
+       an initrd, since an initrd should be placed near end of
+       memory.  Note that this is an option to *both* the kernel and
+       the bootloader!
+
+  initrd=<file>
+       An initrd should be loaded.  The meaning of <file> is
+       obviously bootloader-dependent, and some boot loaders
+       (e.g. LILO) do not have such a command.
+
+In addition, some boot loaders add the following options to the
+user-specified command line:
+
+  BOOT_IMAGE=<file>
+       The boot image which was loaded.  Again, the meaning of <file>
+       is obviously bootloader-dependent.
+
+  auto
+       The kernel was booted without explicit user intervention.
+
+If these options are added by the boot loader, it is highly
+recommended that they are located *first*, before the user-specified
+or configuration-specified command line.  Otherwise, "init=/bin/sh"
+gets confused by the "auto" option.
+
+
+Running the Kernel
+==================
+
+The kernel is started by jumping to the kernel entry point, which is
+located at *segment* offset 0x20 from the start of the real mode
+kernel.  This means that if you loaded your real-mode kernel code at
+0x90000, the kernel entry point is 9020:0000.
+
+At entry, ds = es = ss should point to the start of the real-mode
+kernel code (0x9000 if the code is loaded at 0x90000), sp should be
+set up properly, normally pointing to the top of the heap, and
+interrupts should be disabled.  Furthermore, to guard against bugs in
+the kernel, it is recommended that the boot loader sets fs = gs = ds =
+es = ss.
+
+In our example from above, we would do::
+
+       /* Note: in the case of the "old" kernel protocol, base_ptr must
+          be == 0x90000 at this point; see the previous sample code */
+
+       seg = base_ptr >> 4;
+
+       cli();  /* Enter with interrupts disabled! */
+
+       /* Set up the real-mode kernel stack */
+       _SS = seg;
+       _SP = heap_end;
+
+       _DS = _ES = _FS = _GS = seg;
+       jmp_far(seg+0x20, 0);   /* Run the kernel */
+
+If your boot sector accesses a floppy drive, it is recommended to
+switch off the floppy motor before running the kernel, since the
+kernel boot leaves interrupts off and thus the motor will not be
+switched off, especially if the loaded kernel has the floppy driver as
+a demand-loaded module!
+
+
+Advanced Boot Loader Hooks
+==========================
+
+If the boot loader runs in a particularly hostile environment (such as
+LOADLIN, which runs under DOS) it may be impossible to follow the
+standard memory location requirements.  Such a boot loader may use the
+following hooks that, if set, are invoked by the kernel at the
+appropriate time.  The use of these hooks should probably be
+considered an absolutely last resort!
+
+IMPORTANT: All the hooks are required to preserve %esp, %ebp, %esi and
+%edi across invocation.
+
+  realmode_swtch:
+       A 16-bit real mode far subroutine invoked immediately before
+       entering protected mode.  The default routine disables NMI, so
+       your routine should probably do so, too.
+
+  code32_start:
+       A 32-bit flat-mode routine *jumped* to immediately after the
+       transition to protected mode, but before the kernel is
+       uncompressed.  No segments, except CS, are guaranteed to be
+       set up (current kernels do, but older ones do not); you should
+       set them up to BOOT_DS (0x18) yourself.
+
+       After completing your hook, you should jump to the address
+       that was in this field before your boot loader overwrote it
+       (relocated, if appropriate.)
+
+
+32-bit Boot Protocol
+====================
+
+For machine with some new BIOS other than legacy BIOS, such as EFI,
+LinuxBIOS, etc, and kexec, the 16-bit real mode setup code in kernel
+based on legacy BIOS can not be used, so a 32-bit boot protocol needs
+to be defined.
+
+In 32-bit boot protocol, the first step in loading a Linux kernel
+should be to setup the boot parameters (struct boot_params,
+traditionally known as "zero page"). The memory for struct boot_params
+should be allocated and initialized to all zero. Then the setup header
+from offset 0x01f1 of kernel image on should be loaded into struct
+boot_params and examined. The end of setup header can be calculated as
+follow::
+
+       0x0202 + byte value at offset 0x0201
+
+In addition to read/modify/write the setup header of the struct
+boot_params as that of 16-bit boot protocol, the boot loader should
+also fill the additional fields of the struct boot_params as that
+described in zero-page.txt.
+
+After setting up the struct boot_params, the boot loader can load the
+32/64-bit kernel in the same way as that of 16-bit boot protocol.
+
+In 32-bit boot protocol, the kernel is started by jumping to the
+32-bit kernel entry point, which is the start address of loaded
+32/64-bit kernel.
+
+At entry, the CPU must be in 32-bit protected mode with paging
+disabled; a GDT must be loaded with the descriptors for selectors
+__BOOT_CS(0x10) and __BOOT_DS(0x18); both descriptors must be 4G flat
+segment; __BOOT_CS must have execute/read permission, and __BOOT_DS
+must have read/write permission; CS must be __BOOT_CS and DS, ES, SS
+must be __BOOT_DS; interrupt must be disabled; %esi must hold the base
+address of the struct boot_params; %ebp, %edi and %ebx must be zero.
+
+64-bit Boot Protocol
+====================
+
+For machine with 64bit cpus and 64bit kernel, we could use 64bit bootloader
+and we need a 64-bit boot protocol.
+
+In 64-bit boot protocol, the first step in loading a Linux kernel
+should be to setup the boot parameters (struct boot_params,
+traditionally known as "zero page"). The memory for struct boot_params
+could be allocated anywhere (even above 4G) and initialized to all zero.
+Then, the setup header at offset 0x01f1 of kernel image on should be
+loaded into struct boot_params and examined. The end of setup header
+can be calculated as follows::
+
+       0x0202 + byte value at offset 0x0201
+
+In addition to read/modify/write the setup header of the struct
+boot_params as that of 16-bit boot protocol, the boot loader should
+also fill the additional fields of the struct boot_params as described
+in zero-page.txt.
+
+After setting up the struct boot_params, the boot loader can load
+64-bit kernel in the same way as that of 16-bit boot protocol, but
+kernel could be loaded above 4G.
+
+In 64-bit boot protocol, the kernel is started by jumping to the
+64-bit kernel entry point, which is the start address of loaded
+64-bit kernel plus 0x200.
+
+At entry, the CPU must be in 64-bit mode with paging enabled.
+The range with setup_header.init_size from start address of loaded
+kernel and zero page and command line buffer get ident mapping;
+a GDT must be loaded with the descriptors for selectors
+__BOOT_CS(0x10) and __BOOT_DS(0x18); both descriptors must be 4G flat
+segment; __BOOT_CS must have execute/read permission, and __BOOT_DS
+must have read/write permission; CS must be __BOOT_CS and DS, ES, SS
+must be __BOOT_DS; interrupt must be disabled; %rsi must hold the base
+address of the struct boot_params.
+
+EFI Handover Protocol
+=====================
+
+This protocol allows boot loaders to defer initialisation to the EFI
+boot stub. The boot loader is required to load the kernel/initrd(s)
+from the boot media and jump to the EFI handover protocol entry point
+which is hdr->handover_offset bytes from the beginning of
+startup_{32,64}.
+
+The function prototype for the handover entry point looks like this::
+
+    efi_main(void *handle, efi_system_table_t *table, struct boot_params *bp)
+
+'handle' is the EFI image handle passed to the boot loader by the EFI
+firmware, 'table' is the EFI system table - these are the first two
+arguments of the "handoff state" as described in section 2.3 of the
+UEFI specification. 'bp' is the boot loader-allocated boot params.
+
+The boot loader *must* fill out the following fields in bp::
+
+  - hdr.code32_start
+  - hdr.cmd_line_ptr
+  - hdr.ramdisk_image (if applicable)
+  - hdr.ramdisk_size  (if applicable)
+
+All other fields should be zero.
diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt
deleted file mode 100644 (file)
index 223e484..0000000
+++ /dev/null
@@ -1,1134 +0,0 @@
-                    THE LINUX/x86 BOOT PROTOCOL
-                    ---------------------------
-
-On the x86 platform, the Linux kernel uses a rather complicated boot
-convention.  This has evolved partially due to historical aspects, as
-well as the desire in the early days to have the kernel itself be a
-bootable image, the complicated PC memory model and due to changed
-expectations in the PC industry caused by the effective demise of
-real-mode DOS as a mainstream operating system.
-
-Currently, the following versions of the Linux/x86 boot protocol exist.
-
-Old kernels:   zImage/Image support only.  Some very early kernels
-               may not even support a command line.
-
-Protocol 2.00: (Kernel 1.3.73) Added bzImage and initrd support, as
-               well as a formalized way to communicate between the
-               boot loader and the kernel.  setup.S made relocatable,
-               although the traditional setup area still assumed
-               writable.
-
-Protocol 2.01: (Kernel 1.3.76) Added a heap overrun warning.
-
-Protocol 2.02: (Kernel 2.4.0-test3-pre3) New command line protocol.
-               Lower the conventional memory ceiling.  No overwrite
-               of the traditional setup area, thus making booting
-               safe for systems which use the EBDA from SMM or 32-bit
-               BIOS entry points.  zImage deprecated but still
-               supported.
-
-Protocol 2.03: (Kernel 2.4.18-pre1) Explicitly makes the highest possible
-               initrd address available to the bootloader.
-
-Protocol 2.04: (Kernel 2.6.14) Extend the syssize field to four bytes.
-
-Protocol 2.05: (Kernel 2.6.20) Make protected mode kernel relocatable.
-               Introduce relocatable_kernel and kernel_alignment fields.
-
-Protocol 2.06: (Kernel 2.6.22) Added a field that contains the size of
-               the boot command line.
-
-Protocol 2.07: (Kernel 2.6.24) Added paravirtualised boot protocol.
-               Introduced hardware_subarch and hardware_subarch_data
-               and KEEP_SEGMENTS flag in load_flags.
-
-Protocol 2.08: (Kernel 2.6.26) Added crc32 checksum and ELF format
-               payload. Introduced payload_offset and payload_length
-               fields to aid in locating the payload.
-
-Protocol 2.09: (Kernel 2.6.26) Added a field of 64-bit physical
-               pointer to single linked list of struct setup_data.
-
-Protocol 2.10: (Kernel 2.6.31) Added a protocol for relaxed alignment
-               beyond the kernel_alignment added, new init_size and
-               pref_address fields.  Added extended boot loader IDs.
-
-Protocol 2.11: (Kernel 3.6) Added a field for offset of EFI handover
-               protocol entry point.
-
-Protocol 2.12: (Kernel 3.8) Added the xloadflags field and extension fields
-               to struct boot_params for loading bzImage and ramdisk
-               above 4G in 64bit.
-
-Protocol 2.13: (Kernel 3.14) Support 32- and 64-bit flags being set in
-               xloadflags to support booting a 64-bit kernel from 32-bit
-               EFI
-
-**** MEMORY LAYOUT
-
-The traditional memory map for the kernel loader, used for Image or
-zImage kernels, typically looks like:
-
-       |                        |
-0A0000 +------------------------+
-       |  Reserved for BIOS     |      Do not use.  Reserved for BIOS EBDA.
-09A000 +------------------------+
-       |  Command line          |
-       |  Stack/heap            |      For use by the kernel real-mode code.
-098000 +------------------------+      
-       |  Kernel setup          |      The kernel real-mode code.
-090200 +------------------------+
-       |  Kernel boot sector    |      The kernel legacy boot sector.
-090000 +------------------------+
-       |  Protected-mode kernel |      The bulk of the kernel image.
-010000 +------------------------+
-       |  Boot loader           |      <- Boot sector entry point 0000:7C00
-001000 +------------------------+
-       |  Reserved for MBR/BIOS |
-000800 +------------------------+
-       |  Typically used by MBR |
-000600 +------------------------+ 
-       |  BIOS use only         |
-000000 +------------------------+
-
-
-When using bzImage, the protected-mode kernel was relocated to
-0x100000 ("high memory"), and the kernel real-mode block (boot sector,
-setup, and stack/heap) was made relocatable to any address between
-0x10000 and end of low memory. Unfortunately, in protocols 2.00 and
-2.01 the 0x90000+ memory range is still used internally by the kernel;
-the 2.02 protocol resolves that problem.
-
-It is desirable to keep the "memory ceiling" -- the highest point in
-low memory touched by the boot loader -- as low as possible, since
-some newer BIOSes have begun to allocate some rather large amounts of
-memory, called the Extended BIOS Data Area, near the top of low
-memory.         The boot loader should use the "INT 12h" BIOS call to verify
-how much low memory is available.
-
-Unfortunately, if INT 12h reports that the amount of memory is too
-low, there is usually nothing the boot loader can do but to report an
-error to the user.  The boot loader should therefore be designed to
-take up as little space in low memory as it reasonably can.  For
-zImage or old bzImage kernels, which need data written into the
-0x90000 segment, the boot loader should make sure not to use memory
-above the 0x9A000 point; too many BIOSes will break above that point.
-
-For a modern bzImage kernel with boot protocol version >= 2.02, a
-memory layout like the following is suggested:
-
-       ~                        ~
-        |  Protected-mode kernel |
-100000  +------------------------+
-       |  I/O memory hole       |
-0A0000 +------------------------+
-       |  Reserved for BIOS     |      Leave as much as possible unused
-       ~                        ~
-       |  Command line          |      (Can also be below the X+10000 mark)
-X+10000        +------------------------+
-       |  Stack/heap            |      For use by the kernel real-mode code.
-X+08000        +------------------------+      
-       |  Kernel setup          |      The kernel real-mode code.
-       |  Kernel boot sector    |      The kernel legacy boot sector.
-X       +------------------------+
-       |  Boot loader           |      <- Boot sector entry point 0000:7C00
-001000 +------------------------+
-       |  Reserved for MBR/BIOS |
-000800 +------------------------+
-       |  Typically used by MBR |
-000600 +------------------------+ 
-       |  BIOS use only         |
-000000 +------------------------+
-
-... where the address X is as low as the design of the boot loader
-permits.
-
-
-**** THE REAL-MODE KERNEL HEADER
-
-In the following text, and anywhere in the kernel boot sequence, "a
-sector" refers to 512 bytes.  It is independent of the actual sector
-size of the underlying medium.
-
-The first step in loading a Linux kernel should be to load the
-real-mode code (boot sector and setup code) and then examine the
-following header at offset 0x01f1.  The real-mode code can total up to
-32K, although the boot loader may choose to load only the first two
-sectors (1K) and then examine the bootup sector size.
-
-The header looks like:
-
-Offset Proto   Name            Meaning
-/Size
-
-01F1/1 ALL(1   setup_sects     The size of the setup in sectors
-01F2/2 ALL     root_flags      If set, the root is mounted readonly
-01F4/4 2.04+(2 syssize         The size of the 32-bit code in 16-byte paras
-01F8/2 ALL     ram_size        DO NOT USE - for bootsect.S use only
-01FA/2 ALL     vid_mode        Video mode control
-01FC/2 ALL     root_dev        Default root device number
-01FE/2 ALL     boot_flag       0xAA55 magic number
-0200/2 2.00+   jump            Jump instruction
-0202/4 2.00+   header          Magic signature "HdrS"
-0206/2 2.00+   version         Boot protocol version supported
-0208/4 2.00+   realmode_swtch  Boot loader hook (see below)
-020C/2 2.00+   start_sys_seg   The load-low segment (0x1000) (obsolete)
-020E/2 2.00+   kernel_version  Pointer to kernel version string
-0210/1 2.00+   type_of_loader  Boot loader identifier
-0211/1 2.00+   loadflags       Boot protocol option flags
-0212/2 2.00+   setup_move_size Move to high memory size (used with hooks)
-0214/4 2.00+   code32_start    Boot loader hook (see below)
-0218/4 2.00+   ramdisk_image   initrd load address (set by boot loader)
-021C/4 2.00+   ramdisk_size    initrd size (set by boot loader)
-0220/4 2.00+   bootsect_kludge DO NOT USE - for bootsect.S use only
-0224/2 2.01+   heap_end_ptr    Free memory after setup end
-0226/1 2.02+(3 ext_loader_ver  Extended boot loader version
-0227/1 2.02+(3 ext_loader_type Extended boot loader ID
-0228/4 2.02+   cmd_line_ptr    32-bit pointer to the kernel command line
-022C/4 2.03+   initrd_addr_max Highest legal initrd address
-0230/4 2.05+   kernel_alignment Physical addr alignment required for kernel
-0234/1 2.05+   relocatable_kernel Whether kernel is relocatable or not
-0235/1 2.10+   min_alignment   Minimum alignment, as a power of two
-0236/2 2.12+   xloadflags      Boot protocol option flags
-0238/4 2.06+   cmdline_size    Maximum size of the kernel command line
-023C/4 2.07+   hardware_subarch Hardware subarchitecture
-0240/8 2.07+   hardware_subarch_data Subarchitecture-specific data
-0248/4 2.08+   payload_offset  Offset of kernel payload
-024C/4 2.08+   payload_length  Length of kernel payload
-0250/8 2.09+   setup_data      64-bit physical pointer to linked list
-                               of struct setup_data
-0258/8 2.10+   pref_address    Preferred loading address
-0260/4 2.10+   init_size       Linear memory required during initialization
-0264/4 2.11+   handover_offset Offset of handover entry point
-
-(1) For backwards compatibility, if the setup_sects field contains 0, the
-    real value is 4.
-
-(2) For boot protocol prior to 2.04, the upper two bytes of the syssize
-    field are unusable, which means the size of a bzImage kernel
-    cannot be determined.
-
-(3) Ignored, but safe to set, for boot protocols 2.02-2.09.
-
-If the "HdrS" (0x53726448) magic number is not found at offset 0x202,
-the boot protocol version is "old".  Loading an old kernel, the
-following parameters should be assumed:
-
-       Image type = zImage
-       initrd not supported
-       Real-mode kernel must be located at 0x90000.
-
-Otherwise, the "version" field contains the protocol version,
-e.g. protocol version 2.01 will contain 0x0201 in this field.  When
-setting fields in the header, you must make sure only to set fields
-supported by the protocol version in use.
-
-
-**** DETAILS OF HEADER FIELDS
-
-For each field, some are information from the kernel to the bootloader
-("read"), some are expected to be filled out by the bootloader
-("write"), and some are expected to be read and modified by the
-bootloader ("modify").
-
-All general purpose boot loaders should write the fields marked
-(obligatory).  Boot loaders who want to load the kernel at a
-nonstandard address should fill in the fields marked (reloc); other
-boot loaders can ignore those fields.
-
-The byte order of all fields is littleendian (this is x86, after all.)
-
-Field name:    setup_sects
-Type:          read
-Offset/size:   0x1f1/1
-Protocol:      ALL
-
-  The size of the setup code in 512-byte sectors.  If this field is
-  0, the real value is 4.  The real-mode code consists of the boot
-  sector (always one 512-byte sector) plus the setup code.
-
-Field name:     root_flags
-Type:           modify (optional)
-Offset/size:    0x1f2/2
-Protocol:       ALL
-
-  If this field is nonzero, the root defaults to readonly.  The use of
-  this field is deprecated; use the "ro" or "rw" options on the
-  command line instead.
-
-Field name:    syssize
-Type:          read
-Offset/size:   0x1f4/4 (protocol 2.04+) 0x1f4/2 (protocol ALL)
-Protocol:      2.04+
-
-  The size of the protected-mode code in units of 16-byte paragraphs.
-  For protocol versions older than 2.04 this field is only two bytes
-  wide, and therefore cannot be trusted for the size of a kernel if
-  the LOAD_HIGH flag is set.
-
-Field name:    ram_size
-Type:          kernel internal
-Offset/size:   0x1f8/2
-Protocol:      ALL
-
-  This field is obsolete.
-
-Field name:    vid_mode
-Type:          modify (obligatory)
-Offset/size:   0x1fa/2
-
-  Please see the section on SPECIAL COMMAND LINE OPTIONS.
-
-Field name:    root_dev
-Type:          modify (optional)
-Offset/size:   0x1fc/2
-Protocol:      ALL
-
-  The default root device device number.  The use of this field is
-  deprecated, use the "root=" option on the command line instead.
-
-Field name:    boot_flag
-Type:          read
-Offset/size:   0x1fe/2
-Protocol:      ALL
-
-  Contains 0xAA55.  This is the closest thing old Linux kernels have
-  to a magic number.
-
-Field name:    jump
-Type:          read
-Offset/size:   0x200/2
-Protocol:      2.00+
-
-  Contains an x86 jump instruction, 0xEB followed by a signed offset
-  relative to byte 0x202.  This can be used to determine the size of
-  the header.
-
-Field name:    header
-Type:          read
-Offset/size:   0x202/4
-Protocol:      2.00+
-
-  Contains the magic number "HdrS" (0x53726448).
-
-Field name:    version
-Type:          read
-Offset/size:   0x206/2
-Protocol:      2.00+
-
-  Contains the boot protocol version, in (major << 8)+minor format,
-  e.g. 0x0204 for version 2.04, and 0x0a11 for a hypothetical version
-  10.17.
-
-Field name:    realmode_swtch
-Type:          modify (optional)
-Offset/size:   0x208/4
-Protocol:      2.00+
-
-  Boot loader hook (see ADVANCED BOOT LOADER HOOKS below.)
-
-Field name:    start_sys_seg
-Type:          read
-Offset/size:   0x20c/2
-Protocol:      2.00+
-
-  The load low segment (0x1000).  Obsolete.
-
-Field name:    kernel_version
-Type:          read
-Offset/size:   0x20e/2
-Protocol:      2.00+
-
-  If set to a nonzero value, contains a pointer to a NUL-terminated
-  human-readable kernel version number string, less 0x200.  This can
-  be used to display the kernel version to the user.  This value
-  should be less than (0x200*setup_sects).
-
-  For example, if this value is set to 0x1c00, the kernel version
-  number string can be found at offset 0x1e00 in the kernel file.
-  This is a valid value if and only if the "setup_sects" field
-  contains the value 15 or higher, as:
-
-       0x1c00  < 15*0x200 (= 0x1e00) but
-       0x1c00 >= 14*0x200 (= 0x1c00)
-
-       0x1c00 >> 9 = 14, so the minimum value for setup_secs is 15.
-
-Field name:    type_of_loader
-Type:          write (obligatory)
-Offset/size:   0x210/1
-Protocol:      2.00+
-
-  If your boot loader has an assigned id (see table below), enter
-  0xTV here, where T is an identifier for the boot loader and V is
-  a version number.  Otherwise, enter 0xFF here.
-
-  For boot loader IDs above T = 0xD, write T = 0xE to this field and
-  write the extended ID minus 0x10 to the ext_loader_type field.
-  Similarly, the ext_loader_ver field can be used to provide more than
-  four bits for the bootloader version.
-
-  For example, for T = 0x15, V = 0x234, write:
-
-  type_of_loader  <- 0xE4
-  ext_loader_type <- 0x05
-  ext_loader_ver  <- 0x23
-
-  Assigned boot loader ids (hexadecimal):
-
-       0  LILO                 (0x00 reserved for pre-2.00 bootloader)
-       1  Loadlin
-       2  bootsect-loader      (0x20, all other values reserved)
-       3  Syslinux
-       4  Etherboot/gPXE/iPXE
-       5  ELILO
-       7  GRUB
-       8  U-Boot
-       9  Xen
-       A  Gujin
-       B  Qemu
-       C  Arcturus Networks uCbootloader
-       D  kexec-tools
-       E  Extended             (see ext_loader_type)
-       F  Special              (0xFF = undefined)
-       10  Reserved
-       11  Minimal Linux Bootloader <http://sebastian-plotz.blogspot.de>
-       12  OVMF UEFI virtualization stack
-
-  Please contact <hpa@zytor.com> if you need a bootloader ID
-  value assigned.
-
-Field name:    loadflags
-Type:          modify (obligatory)
-Offset/size:   0x211/1
-Protocol:      2.00+
-
-  This field is a bitmask.
-
-  Bit 0 (read):        LOADED_HIGH
-       - If 0, the protected-mode code is loaded at 0x10000.
-       - If 1, the protected-mode code is loaded at 0x100000.
-
-  Bit 1 (kernel internal): KASLR_FLAG
-       - Used internally by the compressed kernel to communicate
-         KASLR status to kernel proper.
-         If 1, KASLR enabled.
-         If 0, KASLR disabled.
-
-  Bit 5 (write): QUIET_FLAG
-       - If 0, print early messages.
-       - If 1, suppress early messages.
-               This requests to the kernel (decompressor and early
-               kernel) to not write early messages that require
-               accessing the display hardware directly.
-
-  Bit 6 (write): KEEP_SEGMENTS
-       Protocol: 2.07+
-       - If 0, reload the segment registers in the 32bit entry point.
-       - If 1, do not reload the segment registers in the 32bit entry point.
-               Assume that %cs %ds %ss %es are all set to flat segments with
-               a base of 0 (or the equivalent for their environment).
-
-  Bit 7 (write): CAN_USE_HEAP
-       Set this bit to 1 to indicate that the value entered in the
-       heap_end_ptr is valid.  If this field is clear, some setup code
-       functionality will be disabled.
-
-Field name:    setup_move_size
-Type:          modify (obligatory)
-Offset/size:   0x212/2
-Protocol:      2.00-2.01
-
-  When using protocol 2.00 or 2.01, if the real mode kernel is not
-  loaded at 0x90000, it gets moved there later in the loading
-  sequence.  Fill in this field if you want additional data (such as
-  the kernel command line) moved in addition to the real-mode kernel
-  itself.
-
-  The unit is bytes starting with the beginning of the boot sector.
-  
-  This field is can be ignored when the protocol is 2.02 or higher, or
-  if the real-mode code is loaded at 0x90000.
-
-Field name:    code32_start
-Type:          modify (optional, reloc)
-Offset/size:   0x214/4
-Protocol:      2.00+
-
-  The address to jump to in protected mode.  This defaults to the load
-  address of the kernel, and can be used by the boot loader to
-  determine the proper load address.
-
-  This field can be modified for two purposes:
-
-  1. as a boot loader hook (see ADVANCED BOOT LOADER HOOKS below.)
-
-  2. if a bootloader which does not install a hook loads a
-     relocatable kernel at a nonstandard address it will have to modify
-     this field to point to the load address.
-
-Field name:    ramdisk_image
-Type:          write (obligatory)
-Offset/size:   0x218/4
-Protocol:      2.00+
-
-  The 32-bit linear address of the initial ramdisk or ramfs.  Leave at
-  zero if there is no initial ramdisk/ramfs.
-
-Field name:    ramdisk_size
-Type:          write (obligatory)
-Offset/size:   0x21c/4
-Protocol:      2.00+
-
-  Size of the initial ramdisk or ramfs.  Leave at zero if there is no
-  initial ramdisk/ramfs.
-
-Field name:    bootsect_kludge
-Type:          kernel internal
-Offset/size:   0x220/4
-Protocol:      2.00+
-
-  This field is obsolete.
-
-Field name:    heap_end_ptr
-Type:          write (obligatory)
-Offset/size:   0x224/2
-Protocol:      2.01+
-
-  Set this field to the offset (from the beginning of the real-mode
-  code) of the end of the setup stack/heap, minus 0x0200.
-
-Field name:    ext_loader_ver
-Type:          write (optional)
-Offset/size:   0x226/1
-Protocol:      2.02+
-
-  This field is used as an extension of the version number in the
-  type_of_loader field.  The total version number is considered to be
-  (type_of_loader & 0x0f) + (ext_loader_ver << 4).
-
-  The use of this field is boot loader specific.  If not written, it
-  is zero.
-
-  Kernels prior to 2.6.31 did not recognize this field, but it is safe
-  to write for protocol version 2.02 or higher.
-
-Field name:    ext_loader_type
-Type:          write (obligatory if (type_of_loader & 0xf0) == 0xe0)
-Offset/size:   0x227/1
-Protocol:      2.02+
-
-  This field is used as an extension of the type number in
-  type_of_loader field.  If the type in type_of_loader is 0xE, then
-  the actual type is (ext_loader_type + 0x10).
-
-  This field is ignored if the type in type_of_loader is not 0xE.
-
-  Kernels prior to 2.6.31 did not recognize this field, but it is safe
-  to write for protocol version 2.02 or higher.
-
-Field name:    cmd_line_ptr
-Type:          write (obligatory)
-Offset/size:   0x228/4
-Protocol:      2.02+
-
-  Set this field to the linear address of the kernel command line.
-  The kernel command line can be located anywhere between the end of
-  the setup heap and 0xA0000; it does not have to be located in the
-  same 64K segment as the real-mode code itself.
-
-  Fill in this field even if your boot loader does not support a
-  command line, in which case you can point this to an empty string
-  (or better yet, to the string "auto".)  If this field is left at
-  zero, the kernel will assume that your boot loader does not support
-  the 2.02+ protocol.
-
-Field name:    initrd_addr_max
-Type:          read
-Offset/size:   0x22c/4
-Protocol:      2.03+
-
-  The maximum address that may be occupied by the initial
-  ramdisk/ramfs contents.  For boot protocols 2.02 or earlier, this
-  field is not present, and the maximum address is 0x37FFFFFF.  (This
-  address is defined as the address of the highest safe byte, so if
-  your ramdisk is exactly 131072 bytes long and this field is
-  0x37FFFFFF, you can start your ramdisk at 0x37FE0000.)
-
-Field name:    kernel_alignment
-Type:          read/modify (reloc)
-Offset/size:   0x230/4
-Protocol:      2.05+ (read), 2.10+ (modify)
-
-  Alignment unit required by the kernel (if relocatable_kernel is
-  true.)  A relocatable kernel that is loaded at an alignment
-  incompatible with the value in this field will be realigned during
-  kernel initialization.
-
-  Starting with protocol version 2.10, this reflects the kernel
-  alignment preferred for optimal performance; it is possible for the
-  loader to modify this field to permit a lesser alignment.  See the
-  min_alignment and pref_address field below.
-
-Field name:    relocatable_kernel
-Type:          read (reloc)
-Offset/size:   0x234/1
-Protocol:      2.05+
-
-  If this field is nonzero, the protected-mode part of the kernel can
-  be loaded at any address that satisfies the kernel_alignment field.
-  After loading, the boot loader must set the code32_start field to
-  point to the loaded code, or to a boot loader hook.
-
-Field name:    min_alignment
-Type:          read (reloc)
-Offset/size:   0x235/1
-Protocol:      2.10+
-
-  This field, if nonzero, indicates as a power of two the minimum
-  alignment required, as opposed to preferred, by the kernel to boot.
-  If a boot loader makes use of this field, it should update the
-  kernel_alignment field with the alignment unit desired; typically:
-
-       kernel_alignment = 1 << min_alignment
-
-  There may be a considerable performance cost with an excessively
-  misaligned kernel.  Therefore, a loader should typically try each
-  power-of-two alignment from kernel_alignment down to this alignment.
-
-Field name:     xloadflags
-Type:           read
-Offset/size:    0x236/2
-Protocol:       2.12+
-
-  This field is a bitmask.
-
-  Bit 0 (read):        XLF_KERNEL_64
-       - If 1, this kernel has the legacy 64-bit entry point at 0x200.
-
-  Bit 1 (read): XLF_CAN_BE_LOADED_ABOVE_4G
-        - If 1, kernel/boot_params/cmdline/ramdisk can be above 4G.
-
-  Bit 2 (read):        XLF_EFI_HANDOVER_32
-       - If 1, the kernel supports the 32-bit EFI handoff entry point
-          given at handover_offset.
-
-  Bit 3 (read): XLF_EFI_HANDOVER_64
-       - If 1, the kernel supports the 64-bit EFI handoff entry point
-          given at handover_offset + 0x200.
-
-  Bit 4 (read): XLF_EFI_KEXEC
-       - If 1, the kernel supports kexec EFI boot with EFI runtime support.
-
-Field name:    cmdline_size
-Type:          read
-Offset/size:   0x238/4
-Protocol:      2.06+
-
-  The maximum size of the command line without the terminating
-  zero. This means that the command line can contain at most
-  cmdline_size characters. With protocol version 2.05 and earlier, the
-  maximum size was 255.
-
-Field name:    hardware_subarch
-Type:          write (optional, defaults to x86/PC)
-Offset/size:   0x23c/4
-Protocol:      2.07+
-
-  In a paravirtualized environment the hardware low level architectural
-  pieces such as interrupt handling, page table handling, and
-  accessing process control registers needs to be done differently.
-
-  This field allows the bootloader to inform the kernel we are in one
-  one of those environments.
-
-  0x00000000   The default x86/PC environment
-  0x00000001   lguest
-  0x00000002   Xen
-  0x00000003   Moorestown MID
-  0x00000004   CE4100 TV Platform
-
-Field name:    hardware_subarch_data
-Type:          write (subarch-dependent)
-Offset/size:   0x240/8
-Protocol:      2.07+
-
-  A pointer to data that is specific to hardware subarch
-  This field is currently unused for the default x86/PC environment,
-  do not modify.
-
-Field name:    payload_offset
-Type:          read
-Offset/size:   0x248/4
-Protocol:      2.08+
-
-  If non-zero then this field contains the offset from the beginning
-  of the protected-mode code to the payload.
-
-  The payload may be compressed. The format of both the compressed and
-  uncompressed data should be determined using the standard magic
-  numbers.  The currently supported compression formats are gzip
-  (magic numbers 1F 8B or 1F 9E), bzip2 (magic number 42 5A), LZMA
-  (magic number 5D 00), XZ (magic number FD 37), and LZ4 (magic number
-  02 21).  The uncompressed payload is currently always ELF (magic
-  number 7F 45 4C 46).
-
-Field name:    payload_length
-Type:          read
-Offset/size:   0x24c/4
-Protocol:      2.08+
-
-  The length of the payload.
-
-Field name:    setup_data
-Type:          write (special)
-Offset/size:   0x250/8
-Protocol:      2.09+
-
-  The 64-bit physical pointer to NULL terminated single linked list of
-  struct setup_data. This is used to define a more extensible boot
-  parameters passing mechanism. The definition of struct setup_data is
-  as follow:
-
-  struct setup_data {
-         u64 next;
-         u32 type;
-         u32 len;
-         u8  data[0];
-  };
-
-  Where, the next is a 64-bit physical pointer to the next node of
-  linked list, the next field of the last node is 0; the type is used
-  to identify the contents of data; the len is the length of data
-  field; the data holds the real payload.
-
-  This list may be modified at a number of points during the bootup
-  process.  Therefore, when modifying this list one should always make
-  sure to consider the case where the linked list already contains
-  entries.
-
-Field name:    pref_address
-Type:          read (reloc)
-Offset/size:   0x258/8
-Protocol:      2.10+
-
-  This field, if nonzero, represents a preferred load address for the
-  kernel.  A relocating bootloader should attempt to load at this
-  address if possible.
-
-  A non-relocatable kernel will unconditionally move itself and to run
-  at this address.
-
-Field name:    init_size
-Type:          read
-Offset/size:   0x260/4
-
-  This field indicates the amount of linear contiguous memory starting
-  at the kernel runtime start address that the kernel needs before it
-  is capable of examining its memory map.  This is not the same thing
-  as the total amount of memory the kernel needs to boot, but it can
-  be used by a relocating boot loader to help select a safe load
-  address for the kernel.
-
-  The kernel runtime start address is determined by the following algorithm:
-
-  if (relocatable_kernel)
-       runtime_start = align_up(load_address, kernel_alignment)
-  else
-       runtime_start = pref_address
-
-Field name:    handover_offset
-Type:          read
-Offset/size:   0x264/4
-
-  This field is the offset from the beginning of the kernel image to
-  the EFI handover protocol entry point. Boot loaders using the EFI
-  handover protocol to boot the kernel should jump to this offset.
-
-  See EFI HANDOVER PROTOCOL below for more details.
-
-
-**** THE IMAGE CHECKSUM
-
-From boot protocol version 2.08 onwards the CRC-32 is calculated over
-the entire file using the characteristic polynomial 0x04C11DB7 and an
-initial remainder of 0xffffffff.  The checksum is appended to the
-file; therefore the CRC of the file up to the limit specified in the
-syssize field of the header is always 0.
-
-
-**** THE KERNEL COMMAND LINE
-
-The kernel command line has become an important way for the boot
-loader to communicate with the kernel.  Some of its options are also
-relevant to the boot loader itself, see "special command line options"
-below.
-
-The kernel command line is a null-terminated string. The maximum
-length can be retrieved from the field cmdline_size.  Before protocol
-version 2.06, the maximum was 255 characters.  A string that is too
-long will be automatically truncated by the kernel.
-
-If the boot protocol version is 2.02 or later, the address of the
-kernel command line is given by the header field cmd_line_ptr (see
-above.)  This address can be anywhere between the end of the setup
-heap and 0xA0000.
-
-If the protocol version is *not* 2.02 or higher, the kernel
-command line is entered using the following protocol:
-
-       At offset 0x0020 (word), "cmd_line_magic", enter the magic
-       number 0xA33F.
-
-       At offset 0x0022 (word), "cmd_line_offset", enter the offset
-       of the kernel command line (relative to the start of the
-       real-mode kernel).
-       
-       The kernel command line *must* be within the memory region
-       covered by setup_move_size, so you may need to adjust this
-       field.
-
-
-**** MEMORY LAYOUT OF THE REAL-MODE CODE
-
-The real-mode code requires a stack/heap to be set up, as well as
-memory allocated for the kernel command line.  This needs to be done
-in the real-mode accessible memory in bottom megabyte.
-
-It should be noted that modern machines often have a sizable Extended
-BIOS Data Area (EBDA).  As a result, it is advisable to use as little
-of the low megabyte as possible.
-
-Unfortunately, under the following circumstances the 0x90000 memory
-segment has to be used:
-
-       - When loading a zImage kernel ((loadflags & 0x01) == 0).
-       - When loading a 2.01 or earlier boot protocol kernel.
-
-         -> For the 2.00 and 2.01 boot protocols, the real-mode code
-            can be loaded at another address, but it is internally
-            relocated to 0x90000.  For the "old" protocol, the
-            real-mode code must be loaded at 0x90000.
-
-When loading at 0x90000, avoid using memory above 0x9a000.
-
-For boot protocol 2.02 or higher, the command line does not have to be
-located in the same 64K segment as the real-mode setup code; it is
-thus permitted to give the stack/heap the full 64K segment and locate
-the command line above it.
-
-The kernel command line should not be located below the real-mode
-code, nor should it be located in high memory.
-
-
-**** SAMPLE BOOT CONFIGURATION
-
-As a sample configuration, assume the following layout of the real
-mode segment:
-
-    When loading below 0x90000, use the entire segment:
-
-       0x0000-0x7fff   Real mode kernel
-       0x8000-0xdfff   Stack and heap
-       0xe000-0xffff   Kernel command line
-
-    When loading at 0x90000 OR the protocol version is 2.01 or earlier:
-
-       0x0000-0x7fff   Real mode kernel
-       0x8000-0x97ff   Stack and heap
-       0x9800-0x9fff   Kernel command line
-
-Such a boot loader should enter the following fields in the header:
-
-       unsigned long base_ptr; /* base address for real-mode segment */
-
-       if ( setup_sects == 0 ) {
-               setup_sects = 4;
-       }
-
-       if ( protocol >= 0x0200 ) {
-               type_of_loader = <type code>;
-               if ( loading_initrd ) {
-                       ramdisk_image = <initrd_address>;
-                       ramdisk_size = <initrd_size>;
-               }
-
-               if ( protocol >= 0x0202 && loadflags & 0x01 )
-                       heap_end = 0xe000;
-               else
-                       heap_end = 0x9800;
-
-               if ( protocol >= 0x0201 ) {
-                       heap_end_ptr = heap_end - 0x200;
-                       loadflags |= 0x80; /* CAN_USE_HEAP */
-               }
-
-               if ( protocol >= 0x0202 ) {
-                       cmd_line_ptr = base_ptr + heap_end;
-                       strcpy(cmd_line_ptr, cmdline);
-               } else {
-                       cmd_line_magic  = 0xA33F;
-                       cmd_line_offset = heap_end;
-                       setup_move_size = heap_end + strlen(cmdline)+1;
-                       strcpy(base_ptr+cmd_line_offset, cmdline);
-               }
-       } else {
-               /* Very old kernel */
-
-               heap_end = 0x9800;
-
-               cmd_line_magic  = 0xA33F;
-               cmd_line_offset = heap_end;
-
-               /* A very old kernel MUST have its real-mode code
-                  loaded at 0x90000 */
-
-               if ( base_ptr != 0x90000 ) {
-                       /* Copy the real-mode kernel */
-                       memcpy(0x90000, base_ptr, (setup_sects+1)*512);
-                       base_ptr = 0x90000;              /* Relocated */
-               }
-
-               strcpy(0x90000+cmd_line_offset, cmdline);
-
-               /* It is recommended to clear memory up to the 32K mark */
-               memset(0x90000 + (setup_sects+1)*512, 0,
-                      (64-(setup_sects+1))*512);
-       }
-
-
-**** LOADING THE REST OF THE KERNEL
-
-The 32-bit (non-real-mode) kernel starts at offset (setup_sects+1)*512
-in the kernel file (again, if setup_sects == 0 the real value is 4.)
-It should be loaded at address 0x10000 for Image/zImage kernels and
-0x100000 for bzImage kernels.
-
-The kernel is a bzImage kernel if the protocol >= 2.00 and the 0x01
-bit (LOAD_HIGH) in the loadflags field is set:
-
-       is_bzImage = (protocol >= 0x0200) && (loadflags & 0x01);
-       load_address = is_bzImage ? 0x100000 : 0x10000;
-
-Note that Image/zImage kernels can be up to 512K in size, and thus use
-the entire 0x10000-0x90000 range of memory.  This means it is pretty
-much a requirement for these kernels to load the real-mode part at
-0x90000.  bzImage kernels allow much more flexibility.
-
-
-**** SPECIAL COMMAND LINE OPTIONS
-
-If the command line provided by the boot loader is entered by the
-user, the user may expect the following command line options to work.
-They should normally not be deleted from the kernel command line even
-though not all of them are actually meaningful to the kernel.  Boot
-loader authors who need additional command line options for the boot
-loader itself should get them registered in
-Documentation/admin-guide/kernel-parameters.rst to make sure they will not
-conflict with actual kernel options now or in the future.
-
-  vga=<mode>
-       <mode> here is either an integer (in C notation, either
-       decimal, octal, or hexadecimal) or one of the strings
-       "normal" (meaning 0xFFFF), "ext" (meaning 0xFFFE) or "ask"
-       (meaning 0xFFFD).  This value should be entered into the
-       vid_mode field, as it is used by the kernel before the command
-       line is parsed.
-
-  mem=<size>
-       <size> is an integer in C notation optionally followed by
-       (case insensitive) K, M, G, T, P or E (meaning << 10, << 20,
-       << 30, << 40, << 50 or << 60).  This specifies the end of
-       memory to the kernel. This affects the possible placement of
-       an initrd, since an initrd should be placed near end of
-       memory.  Note that this is an option to *both* the kernel and
-       the bootloader!
-
-  initrd=<file>
-       An initrd should be loaded.  The meaning of <file> is
-       obviously bootloader-dependent, and some boot loaders
-       (e.g. LILO) do not have such a command.
-
-In addition, some boot loaders add the following options to the
-user-specified command line:
-
-  BOOT_IMAGE=<file>
-       The boot image which was loaded.  Again, the meaning of <file>
-       is obviously bootloader-dependent.
-
-  auto
-       The kernel was booted without explicit user intervention.
-
-If these options are added by the boot loader, it is highly
-recommended that they are located *first*, before the user-specified
-or configuration-specified command line.  Otherwise, "init=/bin/sh"
-gets confused by the "auto" option.
-
-
-**** RUNNING THE KERNEL
-
-The kernel is started by jumping to the kernel entry point, which is
-located at *segment* offset 0x20 from the start of the real mode
-kernel.  This means that if you loaded your real-mode kernel code at
-0x90000, the kernel entry point is 9020:0000.
-
-At entry, ds = es = ss should point to the start of the real-mode
-kernel code (0x9000 if the code is loaded at 0x90000), sp should be
-set up properly, normally pointing to the top of the heap, and
-interrupts should be disabled.  Furthermore, to guard against bugs in
-the kernel, it is recommended that the boot loader sets fs = gs = ds =
-es = ss.
-
-In our example from above, we would do:
-
-       /* Note: in the case of the "old" kernel protocol, base_ptr must
-          be == 0x90000 at this point; see the previous sample code */
-
-       seg = base_ptr >> 4;
-
-       cli();  /* Enter with interrupts disabled! */
-
-       /* Set up the real-mode kernel stack */
-       _SS = seg;
-       _SP = heap_end;
-
-       _DS = _ES = _FS = _GS = seg;
-       jmp_far(seg+0x20, 0);   /* Run the kernel */
-
-If your boot sector accesses a floppy drive, it is recommended to
-switch off the floppy motor before running the kernel, since the
-kernel boot leaves interrupts off and thus the motor will not be
-switched off, especially if the loaded kernel has the floppy driver as
-a demand-loaded module!
-
-
-**** ADVANCED BOOT LOADER HOOKS
-
-If the boot loader runs in a particularly hostile environment (such as
-LOADLIN, which runs under DOS) it may be impossible to follow the
-standard memory location requirements.  Such a boot loader may use the
-following hooks that, if set, are invoked by the kernel at the
-appropriate time.  The use of these hooks should probably be
-considered an absolutely last resort!
-
-IMPORTANT: All the hooks are required to preserve %esp, %ebp, %esi and
-%edi across invocation.
-
-  realmode_swtch:
-       A 16-bit real mode far subroutine invoked immediately before
-       entering protected mode.  The default routine disables NMI, so
-       your routine should probably do so, too.
-
-  code32_start:
-       A 32-bit flat-mode routine *jumped* to immediately after the
-       transition to protected mode, but before the kernel is
-       uncompressed.  No segments, except CS, are guaranteed to be
-       set up (current kernels do, but older ones do not); you should
-       set them up to BOOT_DS (0x18) yourself.
-
-       After completing your hook, you should jump to the address
-       that was in this field before your boot loader overwrote it
-       (relocated, if appropriate.)
-
-
-**** 32-bit BOOT PROTOCOL
-
-For machine with some new BIOS other than legacy BIOS, such as EFI,
-LinuxBIOS, etc, and kexec, the 16-bit real mode setup code in kernel
-based on legacy BIOS can not be used, so a 32-bit boot protocol needs
-to be defined.
-
-In 32-bit boot protocol, the first step in loading a Linux kernel
-should be to setup the boot parameters (struct boot_params,
-traditionally known as "zero page"). The memory for struct boot_params
-should be allocated and initialized to all zero. Then the setup header
-from offset 0x01f1 of kernel image on should be loaded into struct
-boot_params and examined. The end of setup header can be calculated as
-follow:
-
-       0x0202 + byte value at offset 0x0201
-
-In addition to read/modify/write the setup header of the struct
-boot_params as that of 16-bit boot protocol, the boot loader should
-also fill the additional fields of the struct boot_params as that
-described in zero-page.txt.
-
-After setting up the struct boot_params, the boot loader can load the
-32/64-bit kernel in the same way as that of 16-bit boot protocol.
-
-In 32-bit boot protocol, the kernel is started by jumping to the
-32-bit kernel entry point, which is the start address of loaded
-32/64-bit kernel.
-
-At entry, the CPU must be in 32-bit protected mode with paging
-disabled; a GDT must be loaded with the descriptors for selectors
-__BOOT_CS(0x10) and __BOOT_DS(0x18); both descriptors must be 4G flat
-segment; __BOOT_CS must have execute/read permission, and __BOOT_DS
-must have read/write permission; CS must be __BOOT_CS and DS, ES, SS
-must be __BOOT_DS; interrupt must be disabled; %esi must hold the base
-address of the struct boot_params; %ebp, %edi and %ebx must be zero.
-
-**** 64-bit BOOT PROTOCOL
-
-For machine with 64bit cpus and 64bit kernel, we could use 64bit bootloader
-and we need a 64-bit boot protocol.
-
-In 64-bit boot protocol, the first step in loading a Linux kernel
-should be to setup the boot parameters (struct boot_params,
-traditionally known as "zero page"). The memory for struct boot_params
-could be allocated anywhere (even above 4G) and initialized to all zero.
-Then, the setup header at offset 0x01f1 of kernel image on should be
-loaded into struct boot_params and examined. The end of setup header
-can be calculated as follows:
-
-       0x0202 + byte value at offset 0x0201
-
-In addition to read/modify/write the setup header of the struct
-boot_params as that of 16-bit boot protocol, the boot loader should
-also fill the additional fields of the struct boot_params as described
-in zero-page.txt.
-
-After setting up the struct boot_params, the boot loader can load
-64-bit kernel in the same way as that of 16-bit boot protocol, but
-kernel could be loaded above 4G.
-
-In 64-bit boot protocol, the kernel is started by jumping to the
-64-bit kernel entry point, which is the start address of loaded
-64-bit kernel plus 0x200.
-
-At entry, the CPU must be in 64-bit mode with paging enabled.
-The range with setup_header.init_size from start address of loaded
-kernel and zero page and command line buffer get ident mapping;
-a GDT must be loaded with the descriptors for selectors
-__BOOT_CS(0x10) and __BOOT_DS(0x18); both descriptors must be 4G flat
-segment; __BOOT_CS must have execute/read permission, and __BOOT_DS
-must have read/write permission; CS must be __BOOT_CS and DS, ES, SS
-must be __BOOT_DS; interrupt must be disabled; %rsi must hold the base
-address of the struct boot_params.
-
-**** EFI HANDOVER PROTOCOL
-
-This protocol allows boot loaders to defer initialisation to the EFI
-boot stub. The boot loader is required to load the kernel/initrd(s)
-from the boot media and jump to the EFI handover protocol entry point
-which is hdr->handover_offset bytes from the beginning of
-startup_{32,64}.
-
-The function prototype for the handover entry point looks like this,
-
-    efi_main(void *handle, efi_system_table_t *table, struct boot_params *bp)
-
-'handle' is the EFI image handle passed to the boot loader by the EFI
-firmware, 'table' is the EFI system table - these are the first two
-arguments of the "handoff state" as described in section 2.3 of the
-UEFI specification. 'bp' is the boot loader-allocated boot params.
-
-The boot loader *must* fill out the following fields in bp,
-
-    o hdr.code32_start
-    o hdr.cmd_line_ptr
-    o hdr.ramdisk_image (if applicable)
-    o hdr.ramdisk_size  (if applicable)
-
-All other fields should be zero.
diff --git a/Documentation/x86/conf.py b/Documentation/x86/conf.py
new file mode 100644 (file)
index 0000000..33c5c31
--- /dev/null
@@ -0,0 +1,10 @@
+# -*- coding: utf-8; mode: python -*-
+
+project = "X86 architecture specific documentation"
+
+tags.add("subproject")
+
+latex_documents = [
+    ('index', 'x86.tex', project,
+     'The kernel development community', 'manual'),
+]
diff --git a/Documentation/x86/earlyprintk.rst b/Documentation/x86/earlyprintk.rst
new file mode 100644 (file)
index 0000000..1130737
--- /dev/null
@@ -0,0 +1,151 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============
+Early Printk
+============
+
+Mini-HOWTO for using the earlyprintk=dbgp boot option with a
+USB2 Debug port key and a debug cable, on x86 systems.
+
+You need two computers, the 'USB debug key' special gadget and
+and two USB cables, connected like this::
+
+  [host/target] <-------> [USB debug key] <-------> [client/console]
+
+Hardware requirements
+=====================
+
+  a) Host/target system needs to have USB debug port capability.
+
+     You can check this capability by looking at a 'Debug port' bit in
+     the lspci -vvv output::
+
+       # lspci -vvv
+       ...
+       00:1d.7 USB Controller: Intel Corporation 82801H (ICH8 Family) USB2 EHCI Controller #1 (rev 03) (prog-if 20 [EHCI])
+               Subsystem: Lenovo ThinkPad T61
+               Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
+               Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
+               Latency: 0
+               Interrupt: pin D routed to IRQ 19
+               Region 0: Memory at fe227000 (32-bit, non-prefetchable) [size=1K]
+               Capabilities: [50] Power Management version 2
+                       Flags: PMEClk- DSI- D1- D2- AuxCurrent=375mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
+                       Status: D0 PME-Enable- DSel=0 DScale=0 PME+
+               Capabilities: [58] Debug port: BAR=1 offset=00a0
+                            ^^^^^^^^^^^ <==================== [ HERE ]
+               Kernel driver in use: ehci_hcd
+               Kernel modules: ehci-hcd
+       ...
+
+     .. note::
+       If your system does not list a debug port capability then you probably
+       won't be able to use the USB debug key.
+
+  b) You also need a NetChip USB debug cable/key:
+
+        http://www.plxtech.com/products/NET2000/NET20DC/default.asp
+
+     This is a small blue plastic connector with two USB connections;
+     it draws power from its USB connections.
+
+  c) You need a second client/console system with a high speed USB 2.0 port.
+
+  d) The NetChip device must be plugged directly into the physical
+     debug port on the "host/target" system. You cannot use a USB hub in
+     between the physical debug port and the "host/target" system.
+
+     The EHCI debug controller is bound to a specific physical USB
+     port and the NetChip device will only work as an early printk
+     device in this port.  The EHCI host controllers are electrically
+     wired such that the EHCI debug controller is hooked up to the
+     first physical port and there is no way to change this via software.
+     You can find the physical port through experimentation by trying
+     each physical port on the system and rebooting.  Or you can try
+     and use lsusb or look at the kernel info messages emitted by the
+     usb stack when you plug a usb device into various ports on the
+     "host/target" system.
+
+     Some hardware vendors do not expose the usb debug port with a
+     physical connector and if you find such a device send a complaint
+     to the hardware vendor, because there is no reason not to wire
+     this port into one of the physically accessible ports.
+
+  e) It is also important to note, that many versions of the NetChip
+     device require the "client/console" system to be plugged into the
+     right hand side of the device (with the product logo facing up and
+     readable left to right).  The reason being is that the 5 volt
+     power supply is taken from only one side of the device and it
+     must be the side that does not get rebooted.
+
+Software requirements
+=====================
+
+  a) On the host/target system:
+
+    You need to enable the following kernel config option::
+
+      CONFIG_EARLY_PRINTK_DBGP=y
+
+    And you need to add the boot command line: "earlyprintk=dbgp".
+
+    .. note::
+      If you are using Grub, append it to the 'kernel' line in
+      /etc/grub.conf.  If you are using Grub2 on a BIOS firmware system,
+      append it to the 'linux' line in /boot/grub2/grub.cfg. If you are
+      using Grub2 on an EFI firmware system, append it to the 'linux'
+      or 'linuxefi' line in /boot/grub2/grub.cfg or
+      /boot/efi/EFI/<distro>/grub.cfg.
+
+    On systems with more than one EHCI debug controller you must
+    specify the correct EHCI debug controller number.  The ordering
+    comes from the PCI bus enumeration of the EHCI controllers.  The
+    default with no number argument is "0" or the first EHCI debug
+    controller.  To use the second EHCI debug controller, you would
+    use the command line: "earlyprintk=dbgp1"
+
+    .. note::
+      normally earlyprintk console gets turned off once the
+      regular console is alive - use "earlyprintk=dbgp,keep" to keep
+      this channel open beyond early bootup. This can be useful for
+      debugging crashes under Xorg, etc.
+
+  b) On the client/console system:
+
+    You should enable the following kernel config option::
+
+      CONFIG_USB_SERIAL_DEBUG=y
+
+    On the next bootup with the modified kernel you should
+    get a /dev/ttyUSBx device(s).
+
+    Now this channel of kernel messages is ready to be used: start
+    your favorite terminal emulator (minicom, etc.) and set
+    it up to use /dev/ttyUSB0 - or use a raw 'cat /dev/ttyUSBx' to
+    see the raw output.
+
+  c) On Nvidia Southbridge based systems: the kernel will try to probe
+     and find out which port has a debug device connected.
+
+Testing
+=======
+
+You can test the output by using earlyprintk=dbgp,keep and provoking
+kernel messages on the host/target system. You can provoke a harmless
+kernel message by for example doing::
+
+     echo h > /proc/sysrq-trigger
+
+On the host/target system you should see this help line in "dmesg" output::
+
+     SysRq : HELP : loglevel(0-9) reBoot Crashdump terminate-all-tasks(E) memory-full-oom-kill(F) kill-all-tasks(I) saK show-backtrace-all-active-cpus(L) show-memory-usage(M) nice-all-RT-tasks(N) powerOff show-registers(P) show-all-timers(Q) unRaw Sync show-task-states(T) Unmount show-blocked-tasks(W) dump-ftrace-buffer(Z)
+
+On the client/console system do::
+
+       cat /dev/ttyUSB0
+
+And you should see the help line above displayed shortly after you've
+provoked it on the host system.
+
+If it does not work then please ask about it on the linux-kernel@vger.kernel.org
+mailing list or contact the x86 maintainers.
diff --git a/Documentation/x86/earlyprintk.txt b/Documentation/x86/earlyprintk.txt
deleted file mode 100644 (file)
index 46933e0..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-
-Mini-HOWTO for using the earlyprintk=dbgp boot option with a
-USB2 Debug port key and a debug cable, on x86 systems.
-
-You need two computers, the 'USB debug key' special gadget and
-and two USB cables, connected like this:
-
-  [host/target] <-------> [USB debug key] <-------> [client/console]
-
-1. There are a number of specific hardware requirements:
-
- a.) Host/target system needs to have USB debug port capability.
-
- You can check this capability by looking at a 'Debug port' bit in
- the lspci -vvv output:
-
- # lspci -vvv
- ...
- 00:1d.7 USB Controller: Intel Corporation 82801H (ICH8 Family) USB2 EHCI Controller #1 (rev 03) (prog-if 20 [EHCI])
-         Subsystem: Lenovo ThinkPad T61
-         Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
-         Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
-         Latency: 0
-         Interrupt: pin D routed to IRQ 19
-         Region 0: Memory at fe227000 (32-bit, non-prefetchable) [size=1K]
-         Capabilities: [50] Power Management version 2
-                 Flags: PMEClk- DSI- D1- D2- AuxCurrent=375mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
-                 Status: D0 PME-Enable- DSel=0 DScale=0 PME+
-         Capabilities: [58] Debug port: BAR=1 offset=00a0
-                            ^^^^^^^^^^^ <==================== [ HERE ]
-        Kernel driver in use: ehci_hcd
-         Kernel modules: ehci-hcd
- ...
-
-( If your system does not list a debug port capability then you probably
-  won't be able to use the USB debug key. )
-
- b.) You also need a NetChip USB debug cable/key:
-
-        http://www.plxtech.com/products/NET2000/NET20DC/default.asp
-
-     This is a small blue plastic connector with two USB connections;
-     it draws power from its USB connections.
-
- c.) You need a second client/console system with a high speed USB 2.0
-     port.
-
- d.) The NetChip device must be plugged directly into the physical
-     debug port on the "host/target" system.  You cannot use a USB hub in
-     between the physical debug port and the "host/target" system.
-
-     The EHCI debug controller is bound to a specific physical USB
-     port and the NetChip device will only work as an early printk
-     device in this port.  The EHCI host controllers are electrically
-     wired such that the EHCI debug controller is hooked up to the
-     first physical port and there is no way to change this via software.
-     You can find the physical port through experimentation by trying
-     each physical port on the system and rebooting.  Or you can try
-     and use lsusb or look at the kernel info messages emitted by the
-     usb stack when you plug a usb device into various ports on the
-     "host/target" system.
-
-     Some hardware vendors do not expose the usb debug port with a
-     physical connector and if you find such a device send a complaint
-     to the hardware vendor, because there is no reason not to wire
-     this port into one of the physically accessible ports.
-
- e.) It is also important to note, that many versions of the NetChip
-     device require the "client/console" system to be plugged into the
-     right hand side of the device (with the product logo facing up and
-     readable left to right).  The reason being is that the 5 volt
-     power supply is taken from only one side of the device and it
-     must be the side that does not get rebooted.
-
-2. Software requirements:
-
- a.) On the host/target system:
-
-    You need to enable the following kernel config option:
-
-      CONFIG_EARLY_PRINTK_DBGP=y
-
-    And you need to add the boot command line: "earlyprintk=dbgp".
-
-    (If you are using Grub, append it to the 'kernel' line in
-     /etc/grub.conf.  If you are using Grub2 on a BIOS firmware system,
-     append it to the 'linux' line in /boot/grub2/grub.cfg. If you are
-     using Grub2 on an EFI firmware system, append it to the 'linux'
-     or 'linuxefi' line in /boot/grub2/grub.cfg or
-     /boot/efi/EFI/<distro>/grub.cfg.)
-
-    On systems with more than one EHCI debug controller you must
-    specify the correct EHCI debug controller number.  The ordering
-    comes from the PCI bus enumeration of the EHCI controllers.  The
-    default with no number argument is "0" or the first EHCI debug
-    controller.  To use the second EHCI debug controller, you would
-    use the command line: "earlyprintk=dbgp1"
-
-    NOTE: normally earlyprintk console gets turned off once the
-    regular console is alive - use "earlyprintk=dbgp,keep" to keep
-    this channel open beyond early bootup. This can be useful for
-    debugging crashes under Xorg, etc.
-
- b.) On the client/console system:
-
-    You should enable the following kernel config option:
-
-      CONFIG_USB_SERIAL_DEBUG=y
-
-    On the next bootup with the modified kernel you should
-    get a /dev/ttyUSBx device(s).
-
-    Now this channel of kernel messages is ready to be used: start
-    your favorite terminal emulator (minicom, etc.) and set
-    it up to use /dev/ttyUSB0 - or use a raw 'cat /dev/ttyUSBx' to
-    see the raw output.
-
- c.) On Nvidia Southbridge based systems: the kernel will try to probe
-     and find out which port has a debug device connected.
-
-3. Testing that it works fine:
-
-   You can test the output by using earlyprintk=dbgp,keep and provoking
-   kernel messages on the host/target system. You can provoke a harmless
-   kernel message by for example doing:
-
-     echo h > /proc/sysrq-trigger
-
-   On the host/target system you should see this help line in "dmesg" output:
-
-     SysRq : HELP : loglevel(0-9) reBoot Crashdump terminate-all-tasks(E) memory-full-oom-kill(F) kill-all-tasks(I) saK show-backtrace-all-active-cpus(L) show-memory-usage(M) nice-all-RT-tasks(N) powerOff show-registers(P) show-all-timers(Q) unRaw Sync show-task-states(T) Unmount show-blocked-tasks(W) dump-ftrace-buffer(Z)
-
-   On the client/console system do:
-
-       cat /dev/ttyUSB0
-
-   And you should see the help line above displayed shortly after you've
-   provoked it on the host system.
-
-If it does not work then please ask about it on the linux-kernel@vger.kernel.org
-mailing list or contact the x86 maintainers.
diff --git a/Documentation/x86/entry_64.rst b/Documentation/x86/entry_64.rst
new file mode 100644 (file)
index 0000000..a48b3f6
--- /dev/null
@@ -0,0 +1,110 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==============
+Kernel Entries
+==============
+
+This file documents some of the kernel entries in
+arch/x86/entry/entry_64.S.  A lot of this explanation is adapted from
+an email from Ingo Molnar:
+
+http://lkml.kernel.org/r/<20110529191055.GC9835%40elte.hu>
+
+The x86 architecture has quite a few different ways to jump into
+kernel code.  Most of these entry points are registered in
+arch/x86/kernel/traps.c and implemented in arch/x86/entry/entry_64.S
+for 64-bit, arch/x86/entry/entry_32.S for 32-bit and finally
+arch/x86/entry/entry_64_compat.S which implements the 32-bit compatibility
+syscall entry points and thus provides for 32-bit processes the
+ability to execute syscalls when running on 64-bit kernels.
+
+The IDT vector assignments are listed in arch/x86/include/asm/irq_vectors.h.
+
+Some of these entries are:
+
+ - system_call: syscall instruction from 64-bit code.
+
+ - entry_INT80_compat: int 0x80 from 32-bit or 64-bit code; compat syscall
+   either way.
+
+ - entry_INT80_compat, ia32_sysenter: syscall and sysenter from 32-bit
+   code
+
+ - interrupt: An array of entries.  Every IDT vector that doesn't
+   explicitly point somewhere else gets set to the corresponding
+   value in interrupts.  These point to a whole array of
+   magically-generated functions that make their way to do_IRQ with
+   the interrupt number as a parameter.
+
+ - APIC interrupts: Various special-purpose interrupts for things
+   like TLB shootdown.
+
+ - Architecturally-defined exceptions like divide_error.
+
+There are a few complexities here.  The different x86-64 entries
+have different calling conventions.  The syscall and sysenter
+instructions have their own peculiar calling conventions.  Some of
+the IDT entries push an error code onto the stack; others don't.
+IDT entries using the IST alternative stack mechanism need their own
+magic to get the stack frames right.  (You can find some
+documentation in the AMD APM, Volume 2, Chapter 8 and the Intel SDM,
+Volume 3, Chapter 6.)
+
+Dealing with the swapgs instruction is especially tricky.  Swapgs
+toggles whether gs is the kernel gs or the user gs.  The swapgs
+instruction is rather fragile: it must nest perfectly and only in
+single depth, it should only be used if entering from user mode to
+kernel mode and then when returning to user-space, and precisely
+so. If we mess that up even slightly, we crash.
+
+So when we have a secondary entry, already in kernel mode, we *must
+not* use SWAPGS blindly - nor must we forget doing a SWAPGS when it's
+not switched/swapped yet.
+
+Now, there's a secondary complication: there's a cheap way to test
+which mode the CPU is in and an expensive way.
+
+The cheap way is to pick this info off the entry frame on the kernel
+stack, from the CS of the ptregs area of the kernel stack::
+
+       xorl %ebx,%ebx
+       testl $3,CS+8(%rsp)
+       je error_kernelspace
+       SWAPGS
+
+The expensive (paranoid) way is to read back the MSR_GS_BASE value
+(which is what SWAPGS modifies)::
+
+       movl $1,%ebx
+       movl $MSR_GS_BASE,%ecx
+       rdmsr
+       testl %edx,%edx
+       js 1f   /* negative -> in kernel */
+       SWAPGS
+       xorl %ebx,%ebx
+  1:   ret
+
+If we are at an interrupt or user-trap/gate-alike boundary then we can
+use the faster check: the stack will be a reliable indicator of
+whether SWAPGS was already done: if we see that we are a secondary
+entry interrupting kernel mode execution, then we know that the GS
+base has already been switched. If it says that we interrupted
+user-space execution then we must do the SWAPGS.
+
+But if we are in an NMI/MCE/DEBUG/whatever super-atomic entry context,
+which might have triggered right after a normal entry wrote CS to the
+stack but before we executed SWAPGS, then the only safe way to check
+for GS is the slower method: the RDMSR.
+
+Therefore, super-atomic entries (except NMI, which is handled separately)
+must use idtentry with paranoid=1 to handle gsbase correctly.  This
+triggers three main behavior changes:
+
+ - Interrupt entry will use the slower gsbase check.
+ - Interrupt entry from user mode will switch off the IST stack.
+ - Interrupt exit to kernel mode will not attempt to reschedule.
+
+We try to only use IST entries and the paranoid entry code for vectors
+that absolutely need the more expensive check for the GS base - and we
+generate all 'normal' entry points with the regular (faster) paranoid=0
+variant.
diff --git a/Documentation/x86/entry_64.txt b/Documentation/x86/entry_64.txt
deleted file mode 100644 (file)
index c1df8eb..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-This file documents some of the kernel entries in
-arch/x86/entry/entry_64.S.  A lot of this explanation is adapted from
-an email from Ingo Molnar:
-
-http://lkml.kernel.org/r/<20110529191055.GC9835%40elte.hu>
-
-The x86 architecture has quite a few different ways to jump into
-kernel code.  Most of these entry points are registered in
-arch/x86/kernel/traps.c and implemented in arch/x86/entry/entry_64.S
-for 64-bit, arch/x86/entry/entry_32.S for 32-bit and finally
-arch/x86/entry/entry_64_compat.S which implements the 32-bit compatibility
-syscall entry points and thus provides for 32-bit processes the
-ability to execute syscalls when running on 64-bit kernels.
-
-The IDT vector assignments are listed in arch/x86/include/asm/irq_vectors.h.
-
-Some of these entries are:
-
- - system_call: syscall instruction from 64-bit code.
-
- - entry_INT80_compat: int 0x80 from 32-bit or 64-bit code; compat syscall
-   either way.
-
- - entry_INT80_compat, ia32_sysenter: syscall and sysenter from 32-bit
-   code
-
- - interrupt: An array of entries.  Every IDT vector that doesn't
-   explicitly point somewhere else gets set to the corresponding
-   value in interrupts.  These point to a whole array of
-   magically-generated functions that make their way to do_IRQ with
-   the interrupt number as a parameter.
-
- - APIC interrupts: Various special-purpose interrupts for things
-   like TLB shootdown.
-
- - Architecturally-defined exceptions like divide_error.
-
-There are a few complexities here.  The different x86-64 entries
-have different calling conventions.  The syscall and sysenter
-instructions have their own peculiar calling conventions.  Some of
-the IDT entries push an error code onto the stack; others don't.
-IDT entries using the IST alternative stack mechanism need their own
-magic to get the stack frames right.  (You can find some
-documentation in the AMD APM, Volume 2, Chapter 8 and the Intel SDM,
-Volume 3, Chapter 6.)
-
-Dealing with the swapgs instruction is especially tricky.  Swapgs
-toggles whether gs is the kernel gs or the user gs.  The swapgs
-instruction is rather fragile: it must nest perfectly and only in
-single depth, it should only be used if entering from user mode to
-kernel mode and then when returning to user-space, and precisely
-so. If we mess that up even slightly, we crash.
-
-So when we have a secondary entry, already in kernel mode, we *must
-not* use SWAPGS blindly - nor must we forget doing a SWAPGS when it's
-not switched/swapped yet.
-
-Now, there's a secondary complication: there's a cheap way to test
-which mode the CPU is in and an expensive way.
-
-The cheap way is to pick this info off the entry frame on the kernel
-stack, from the CS of the ptregs area of the kernel stack:
-
-       xorl %ebx,%ebx
-       testl $3,CS+8(%rsp)
-       je error_kernelspace
-       SWAPGS
-
-The expensive (paranoid) way is to read back the MSR_GS_BASE value
-(which is what SWAPGS modifies):
-
-       movl $1,%ebx
-       movl $MSR_GS_BASE,%ecx
-       rdmsr
-       testl %edx,%edx
-       js 1f   /* negative -> in kernel */
-       SWAPGS
-       xorl %ebx,%ebx
-1:     ret
-
-If we are at an interrupt or user-trap/gate-alike boundary then we can
-use the faster check: the stack will be a reliable indicator of
-whether SWAPGS was already done: if we see that we are a secondary
-entry interrupting kernel mode execution, then we know that the GS
-base has already been switched. If it says that we interrupted
-user-space execution then we must do the SWAPGS.
-
-But if we are in an NMI/MCE/DEBUG/whatever super-atomic entry context,
-which might have triggered right after a normal entry wrote CS to the
-stack but before we executed SWAPGS, then the only safe way to check
-for GS is the slower method: the RDMSR.
-
-Therefore, super-atomic entries (except NMI, which is handled separately)
-must use idtentry with paranoid=1 to handle gsbase correctly.  This
-triggers three main behavior changes:
-
- - Interrupt entry will use the slower gsbase check.
- - Interrupt entry from user mode will switch off the IST stack.
- - Interrupt exit to kernel mode will not attempt to reschedule.
-
-We try to only use IST entries and the paranoid entry code for vectors
-that absolutely need the more expensive check for the GS base - and we
-generate all 'normal' entry points with the regular (faster) paranoid=0
-variant.
diff --git a/Documentation/x86/exception-tables.rst b/Documentation/x86/exception-tables.rst
new file mode 100644 (file)
index 0000000..24596c8
--- /dev/null
@@ -0,0 +1,346 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===============================
+Kernel level exception handling
+===============================
+
+Commentary by Joerg Pommnitz <joerg@raleigh.ibm.com>
+
+When a process runs in kernel mode, it often has to access user
+mode memory whose address has been passed by an untrusted program.
+To protect itself the kernel has to verify this address.
+
+In older versions of Linux this was done with the
+int verify_area(int type, const void * addr, unsigned long size)
+function (which has since been replaced by access_ok()).
+
+This function verified that the memory area starting at address
+'addr' and of size 'size' was accessible for the operation specified
+in type (read or write). To do this, verify_read had to look up the
+virtual memory area (vma) that contained the address addr. In the
+normal case (correctly working program), this test was successful.
+It only failed for a few buggy programs. In some kernel profiling
+tests, this normally unneeded verification used up a considerable
+amount of time.
+
+To overcome this situation, Linus decided to let the virtual memory
+hardware present in every Linux-capable CPU handle this test.
+
+How does this work?
+
+Whenever the kernel tries to access an address that is currently not
+accessible, the CPU generates a page fault exception and calls the
+page fault handler::
+
+  void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+
+in arch/x86/mm/fault.c. The parameters on the stack are set up by
+the low level assembly glue in arch/x86/kernel/entry_32.S. The parameter
+regs is a pointer to the saved registers on the stack, error_code
+contains a reason code for the exception.
+
+do_page_fault first obtains the unaccessible address from the CPU
+control register CR2. If the address is within the virtual address
+space of the process, the fault probably occurred, because the page
+was not swapped in, write protected or something similar. However,
+we are interested in the other case: the address is not valid, there
+is no vma that contains this address. In this case, the kernel jumps
+to the bad_area label.
+
+There it uses the address of the instruction that caused the exception
+(i.e. regs->eip) to find an address where the execution can continue
+(fixup). If this search is successful, the fault handler modifies the
+return address (again regs->eip) and returns. The execution will
+continue at the address in fixup.
+
+Where does fixup point to?
+
+Since we jump to the contents of fixup, fixup obviously points
+to executable code. This code is hidden inside the user access macros.
+I have picked the get_user macro defined in arch/x86/include/asm/uaccess.h
+as an example. The definition is somewhat hard to follow, so let's peek at
+the code generated by the preprocessor and the compiler. I selected
+the get_user call in drivers/char/sysrq.c for a detailed examination.
+
+The original code in sysrq.c line 587::
+
+        get_user(c, buf);
+
+The preprocessor output (edited to become somewhat readable)::
+
+  (
+    {
+      long __gu_err = - 14 , __gu_val = 0;
+      const __typeof__(*( (  buf ) )) *__gu_addr = ((buf));
+      if (((((0 + current_set[0])->tss.segment) == 0x18 )  ||
+        (((sizeof(*(buf))) <= 0xC0000000UL) &&
+        ((unsigned long)(__gu_addr ) <= 0xC0000000UL - (sizeof(*(buf)))))))
+        do {
+          __gu_err  = 0;
+          switch ((sizeof(*(buf)))) {
+            case 1:
+              __asm__ __volatile__(
+                "1:      mov" "b" " %2,%" "b" "1\n"
+                "2:\n"
+                ".section .fixup,\"ax\"\n"
+                "3:      movl %3,%0\n"
+                "        xor" "b" " %" "b" "1,%" "b" "1\n"
+                "        jmp 2b\n"
+                ".section __ex_table,\"a\"\n"
+                "        .align 4\n"
+                "        .long 1b,3b\n"
+                ".text"        : "=r"(__gu_err), "=q" (__gu_val): "m"((*(struct __large_struct *)
+                              (   __gu_addr   )) ), "i"(- 14 ), "0"(  __gu_err  )) ;
+                break;
+            case 2:
+              __asm__ __volatile__(
+                "1:      mov" "w" " %2,%" "w" "1\n"
+                "2:\n"
+                ".section .fixup,\"ax\"\n"
+                "3:      movl %3,%0\n"
+                "        xor" "w" " %" "w" "1,%" "w" "1\n"
+                "        jmp 2b\n"
+                ".section __ex_table,\"a\"\n"
+                "        .align 4\n"
+                "        .long 1b,3b\n"
+                ".text"        : "=r"(__gu_err), "=r" (__gu_val) : "m"((*(struct __large_struct *)
+                              (   __gu_addr   )) ), "i"(- 14 ), "0"(  __gu_err  ));
+                break;
+            case 4:
+              __asm__ __volatile__(
+                "1:      mov" "l" " %2,%" "" "1\n"
+                "2:\n"
+                ".section .fixup,\"ax\"\n"
+                "3:      movl %3,%0\n"
+                "        xor" "l" " %" "" "1,%" "" "1\n"
+                "        jmp 2b\n"
+                ".section __ex_table,\"a\"\n"
+                "        .align 4\n"        "        .long 1b,3b\n"
+                ".text"        : "=r"(__gu_err), "=r" (__gu_val) : "m"((*(struct __large_struct *)
+                              (   __gu_addr   )) ), "i"(- 14 ), "0"(__gu_err));
+                break;
+            default:
+              (__gu_val) = __get_user_bad();
+          }
+        } while (0) ;
+      ((c)) = (__typeof__(*((buf))))__gu_val;
+      __gu_err;
+    }
+  );
+
+WOW! Black GCC/assembly magic. This is impossible to follow, so let's
+see what code gcc generates::
+
+ >         xorl %edx,%edx
+ >         movl current_set,%eax
+ >         cmpl $24,788(%eax)
+ >         je .L1424
+ >         cmpl $-1073741825,64(%esp)
+ >         ja .L1423
+ > .L1424:
+ >         movl %edx,%eax
+ >         movl 64(%esp),%ebx
+ > #APP
+ > 1:      movb (%ebx),%dl                /* this is the actual user access */
+ > 2:
+ > .section .fixup,"ax"
+ > 3:      movl $-14,%eax
+ >         xorb %dl,%dl
+ >         jmp 2b
+ > .section __ex_table,"a"
+ >         .align 4
+ >         .long 1b,3b
+ > .text
+ > #NO_APP
+ > .L1423:
+ >         movzbl %dl,%esi
+
+The optimizer does a good job and gives us something we can actually
+understand. Can we? The actual user access is quite obvious. Thanks
+to the unified address space we can just access the address in user
+memory. But what does the .section stuff do?????
+
+To understand this we have to look at the final kernel::
+
+ > objdump --section-headers vmlinux
+ >
+ > vmlinux:     file format elf32-i386
+ >
+ > Sections:
+ > Idx Name          Size      VMA       LMA       File off  Algn
+ >   0 .text         00098f40  c0100000  c0100000  00001000  2**4
+ >                   CONTENTS, ALLOC, LOAD, READONLY, CODE
+ >   1 .fixup        000016bc  c0198f40  c0198f40  00099f40  2**0
+ >                   CONTENTS, ALLOC, LOAD, READONLY, CODE
+ >   2 .rodata       0000f127  c019a5fc  c019a5fc  0009b5fc  2**2
+ >                   CONTENTS, ALLOC, LOAD, READONLY, DATA
+ >   3 __ex_table    000015c0  c01a9724  c01a9724  000aa724  2**2
+ >                   CONTENTS, ALLOC, LOAD, READONLY, DATA
+ >   4 .data         0000ea58  c01abcf0  c01abcf0  000abcf0  2**4
+ >                   CONTENTS, ALLOC, LOAD, DATA
+ >   5 .bss          00018e21  c01ba748  c01ba748  000ba748  2**2
+ >                   ALLOC
+ >   6 .comment      00000ec4  00000000  00000000  000ba748  2**0
+ >                   CONTENTS, READONLY
+ >   7 .note         00001068  00000ec4  00000ec4  000bb60c  2**0
+ >                   CONTENTS, READONLY
+
+There are obviously 2 non standard ELF sections in the generated object
+file. But first we want to find out what happened to our code in the
+final kernel executable::
+
+ > objdump --disassemble --section=.text vmlinux
+ >
+ > c017e785 <do_con_write+c1> xorl   %edx,%edx
+ > c017e787 <do_con_write+c3> movl   0xc01c7bec,%eax
+ > c017e78c <do_con_write+c8> cmpl   $0x18,0x314(%eax)
+ > c017e793 <do_con_write+cf> je     c017e79f <do_con_write+db>
+ > c017e795 <do_con_write+d1> cmpl   $0xbfffffff,0x40(%esp,1)
+ > c017e79d <do_con_write+d9> ja     c017e7a7 <do_con_write+e3>
+ > c017e79f <do_con_write+db> movl   %edx,%eax
+ > c017e7a1 <do_con_write+dd> movl   0x40(%esp,1),%ebx
+ > c017e7a5 <do_con_write+e1> movb   (%ebx),%dl
+ > c017e7a7 <do_con_write+e3> movzbl %dl,%esi
+
+The whole user memory access is reduced to 10 x86 machine instructions.
+The instructions bracketed in the .section directives are no longer
+in the normal execution path. They are located in a different section
+of the executable file::
+
+ > objdump --disassemble --section=.fixup vmlinux
+ >
+ > c0199ff5 <.fixup+10b5> movl   $0xfffffff2,%eax
+ > c0199ffa <.fixup+10ba> xorb   %dl,%dl
+ > c0199ffc <.fixup+10bc> jmp    c017e7a7 <do_con_write+e3>
+
+And finally::
+
+ > objdump --full-contents --section=__ex_table vmlinux
+ >
+ >  c01aa7c4 93c017c0 e09f19c0 97c017c0 99c017c0  ................
+ >  c01aa7d4 f6c217c0 e99f19c0 a5e717c0 f59f19c0  ................
+ >  c01aa7e4 080a18c0 01a019c0 0a0a18c0 04a019c0  ................
+
+or in human readable byte order::
+
+ >  c01aa7c4 c017c093 c0199fe0 c017c097 c017c099  ................
+ >  c01aa7d4 c017c2f6 c0199fe9 c017e7a5 c0199ff5  ................
+                               ^^^^^^^^^^^^^^^^^
+                               this is the interesting part!
+ >  c01aa7e4 c0180a08 c019a001 c0180a0a c019a004  ................
+
+What happened? The assembly directives::
+
+  .section .fixup,"ax"
+  .section __ex_table,"a"
+
+told the assembler to move the following code to the specified
+sections in the ELF object file. So the instructions::
+
+  3:      movl $-14,%eax
+          xorb %dl,%dl
+          jmp 2b
+
+ended up in the .fixup section of the object file and the addresses::
+
+        .long 1b,3b
+
+ended up in the __ex_table section of the object file. 1b and 3b
+are local labels. The local label 1b (1b stands for next label 1
+backward) is the address of the instruction that might fault, i.e.
+in our case the address of the label 1 is c017e7a5:
+the original assembly code: > 1:      movb (%ebx),%dl
+and linked in vmlinux     : > c017e7a5 <do_con_write+e1> movb   (%ebx),%dl
+
+The local label 3 (backwards again) is the address of the code to handle
+the fault, in our case the actual value is c0199ff5:
+the original assembly code: > 3:      movl $-14,%eax
+and linked in vmlinux     : > c0199ff5 <.fixup+10b5> movl   $0xfffffff2,%eax
+
+The assembly code::
+
+ > .section __ex_table,"a"
+ >         .align 4
+ >         .long 1b,3b
+
+becomes the value pair::
+
+ >  c01aa7d4 c017c2f6 c0199fe9 c017e7a5 c0199ff5  ................
+                               ^this is ^this is
+                               1b       3b
+
+c017e7a5,c0199ff5 in the exception table of the kernel.
+
+So, what actually happens if a fault from kernel mode with no suitable
+vma occurs?
+
+#. access to invalid address::
+
+    > c017e7a5 <do_con_write+e1> movb   (%ebx),%dl
+#. MMU generates exception
+#. CPU calls do_page_fault
+#. do page fault calls search_exception_table (regs->eip == c017e7a5);
+#. search_exception_table looks up the address c017e7a5 in the
+   exception table (i.e. the contents of the ELF section __ex_table)
+   and returns the address of the associated fault handle code c0199ff5.
+#. do_page_fault modifies its own return address to point to the fault
+   handle code and returns.
+#. execution continues in the fault handling code.
+#. a) EAX becomes -EFAULT (== -14)
+   b) DL  becomes zero (the value we "read" from user space)
+   c) execution continues at local label 2 (address of the
+      instruction immediately after the faulting user access).
+
+The steps 8a to 8c in a certain way emulate the faulting instruction.
+
+That's it, mostly. If you look at our example, you might ask why
+we set EAX to -EFAULT in the exception handler code. Well, the
+get_user macro actually returns a value: 0, if the user access was
+successful, -EFAULT on failure. Our original code did not test this
+return value, however the inline assembly code in get_user tries to
+return -EFAULT. GCC selected EAX to return this value.
+
+NOTE:
+Due to the way that the exception table is built and needs to be ordered,
+only use exceptions for code in the .text section.  Any other section
+will cause the exception table to not be sorted correctly, and the
+exceptions will fail.
+
+Things changed when 64-bit support was added to x86 Linux. Rather than
+double the size of the exception table by expanding the two entries
+from 32-bits to 64 bits, a clever trick was used to store addresses
+as relative offsets from the table itself. The assembly code changed
+from::
+
+    .long 1b,3b
+  to:
+          .long (from) - .
+          .long (to) - .
+
+and the C-code that uses these values converts back to absolute addresses
+like this::
+
+       ex_insn_addr(const struct exception_table_entry *x)
+       {
+               return (unsigned long)&x->insn + x->insn;
+       }
+
+In v4.6 the exception table entry was expanded with a new field "handler".
+This is also 32-bits wide and contains a third relative function
+pointer which points to one of:
+
+1) ``int ex_handler_default(const struct exception_table_entry *fixup)``
+     This is legacy case that just jumps to the fixup code
+
+2) ``int ex_handler_fault(const struct exception_table_entry *fixup)``
+     This case provides the fault number of the trap that occurred at
+     entry->insn. It is used to distinguish page faults from machine
+     check.
+
+3) ``int ex_handler_ext(const struct exception_table_entry *fixup)``
+     This case is used for uaccess_err ... we need to set a flag
+     in the task structure. Before the handler functions existed this
+     case was handled by adding a large offset to the fixup to tag
+     it as special.
+
+More functions can easily be added.
diff --git a/Documentation/x86/exception-tables.txt b/Documentation/x86/exception-tables.txt
deleted file mode 100644 (file)
index e396bcd..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-     Kernel level exception handling in Linux
-  Commentary by Joerg Pommnitz <joerg@raleigh.ibm.com>
-
-When a process runs in kernel mode, it often has to access user
-mode memory whose address has been passed by an untrusted program.
-To protect itself the kernel has to verify this address.
-
-In older versions of Linux this was done with the
-int verify_area(int type, const void * addr, unsigned long size)
-function (which has since been replaced by access_ok()).
-
-This function verified that the memory area starting at address
-'addr' and of size 'size' was accessible for the operation specified
-in type (read or write). To do this, verify_read had to look up the
-virtual memory area (vma) that contained the address addr. In the
-normal case (correctly working program), this test was successful.
-It only failed for a few buggy programs. In some kernel profiling
-tests, this normally unneeded verification used up a considerable
-amount of time.
-
-To overcome this situation, Linus decided to let the virtual memory
-hardware present in every Linux-capable CPU handle this test.
-
-How does this work?
-
-Whenever the kernel tries to access an address that is currently not
-accessible, the CPU generates a page fault exception and calls the
-page fault handler
-
-void do_page_fault(struct pt_regs *regs, unsigned long error_code)
-
-in arch/x86/mm/fault.c. The parameters on the stack are set up by
-the low level assembly glue in arch/x86/kernel/entry_32.S. The parameter
-regs is a pointer to the saved registers on the stack, error_code
-contains a reason code for the exception.
-
-do_page_fault first obtains the unaccessible address from the CPU
-control register CR2. If the address is within the virtual address
-space of the process, the fault probably occurred, because the page
-was not swapped in, write protected or something similar. However,
-we are interested in the other case: the address is not valid, there
-is no vma that contains this address. In this case, the kernel jumps
-to the bad_area label.
-
-There it uses the address of the instruction that caused the exception
-(i.e. regs->eip) to find an address where the execution can continue
-(fixup). If this search is successful, the fault handler modifies the
-return address (again regs->eip) and returns. The execution will
-continue at the address in fixup.
-
-Where does fixup point to?
-
-Since we jump to the contents of fixup, fixup obviously points
-to executable code. This code is hidden inside the user access macros.
-I have picked the get_user macro defined in arch/x86/include/asm/uaccess.h
-as an example. The definition is somewhat hard to follow, so let's peek at
-the code generated by the preprocessor and the compiler. I selected
-the get_user call in drivers/char/sysrq.c for a detailed examination.
-
-The original code in sysrq.c line 587:
-        get_user(c, buf);
-
-The preprocessor output (edited to become somewhat readable):
-
-(
-  {
-    long __gu_err = - 14 , __gu_val = 0;
-    const __typeof__(*( (  buf ) )) *__gu_addr = ((buf));
-    if (((((0 + current_set[0])->tss.segment) == 0x18 )  ||
-       (((sizeof(*(buf))) <= 0xC0000000UL) &&
-       ((unsigned long)(__gu_addr ) <= 0xC0000000UL - (sizeof(*(buf)))))))
-      do {
-        __gu_err  = 0;
-        switch ((sizeof(*(buf)))) {
-          case 1:
-            __asm__ __volatile__(
-              "1:      mov" "b" " %2,%" "b" "1\n"
-              "2:\n"
-              ".section .fixup,\"ax\"\n"
-              "3:      movl %3,%0\n"
-              "        xor" "b" " %" "b" "1,%" "b" "1\n"
-              "        jmp 2b\n"
-              ".section __ex_table,\"a\"\n"
-              "        .align 4\n"
-              "        .long 1b,3b\n"
-              ".text"        : "=r"(__gu_err), "=q" (__gu_val): "m"((*(struct __large_struct *)
-                            (   __gu_addr   )) ), "i"(- 14 ), "0"(  __gu_err  )) ;
-              break;
-          case 2:
-            __asm__ __volatile__(
-              "1:      mov" "w" " %2,%" "w" "1\n"
-              "2:\n"
-              ".section .fixup,\"ax\"\n"
-              "3:      movl %3,%0\n"
-              "        xor" "w" " %" "w" "1,%" "w" "1\n"
-              "        jmp 2b\n"
-              ".section __ex_table,\"a\"\n"
-              "        .align 4\n"
-              "        .long 1b,3b\n"
-              ".text"        : "=r"(__gu_err), "=r" (__gu_val) : "m"((*(struct __large_struct *)
-                            (   __gu_addr   )) ), "i"(- 14 ), "0"(  __gu_err  ));
-              break;
-          case 4:
-            __asm__ __volatile__(
-              "1:      mov" "l" " %2,%" "" "1\n"
-              "2:\n"
-              ".section .fixup,\"ax\"\n"
-              "3:      movl %3,%0\n"
-              "        xor" "l" " %" "" "1,%" "" "1\n"
-              "        jmp 2b\n"
-              ".section __ex_table,\"a\"\n"
-              "        .align 4\n"        "        .long 1b,3b\n"
-              ".text"        : "=r"(__gu_err), "=r" (__gu_val) : "m"((*(struct __large_struct *)
-                            (   __gu_addr   )) ), "i"(- 14 ), "0"(__gu_err));
-              break;
-          default:
-            (__gu_val) = __get_user_bad();
-        }
-      } while (0) ;
-    ((c)) = (__typeof__(*((buf))))__gu_val;
-    __gu_err;
-  }
-);
-
-WOW! Black GCC/assembly magic. This is impossible to follow, so let's
-see what code gcc generates:
-
- >         xorl %edx,%edx
- >         movl current_set,%eax
- >         cmpl $24,788(%eax)
- >         je .L1424
- >         cmpl $-1073741825,64(%esp)
- >         ja .L1423
- > .L1424:
- >         movl %edx,%eax
- >         movl 64(%esp),%ebx
- > #APP
- > 1:      movb (%ebx),%dl                /* this is the actual user access */
- > 2:
- > .section .fixup,"ax"
- > 3:      movl $-14,%eax
- >         xorb %dl,%dl
- >         jmp 2b
- > .section __ex_table,"a"
- >         .align 4
- >         .long 1b,3b
- > .text
- > #NO_APP
- > .L1423:
- >         movzbl %dl,%esi
-
-The optimizer does a good job and gives us something we can actually
-understand. Can we? The actual user access is quite obvious. Thanks
-to the unified address space we can just access the address in user
-memory. But what does the .section stuff do?????
-
-To understand this we have to look at the final kernel:
-
- > objdump --section-headers vmlinux
- >
- > vmlinux:     file format elf32-i386
- >
- > Sections:
- > Idx Name          Size      VMA       LMA       File off  Algn
- >   0 .text         00098f40  c0100000  c0100000  00001000  2**4
- >                   CONTENTS, ALLOC, LOAD, READONLY, CODE
- >   1 .fixup        000016bc  c0198f40  c0198f40  00099f40  2**0
- >                   CONTENTS, ALLOC, LOAD, READONLY, CODE
- >   2 .rodata       0000f127  c019a5fc  c019a5fc  0009b5fc  2**2
- >                   CONTENTS, ALLOC, LOAD, READONLY, DATA
- >   3 __ex_table    000015c0  c01a9724  c01a9724  000aa724  2**2
- >                   CONTENTS, ALLOC, LOAD, READONLY, DATA
- >   4 .data         0000ea58  c01abcf0  c01abcf0  000abcf0  2**4
- >                   CONTENTS, ALLOC, LOAD, DATA
- >   5 .bss          00018e21  c01ba748  c01ba748  000ba748  2**2
- >                   ALLOC
- >   6 .comment      00000ec4  00000000  00000000  000ba748  2**0
- >                   CONTENTS, READONLY
- >   7 .note         00001068  00000ec4  00000ec4  000bb60c  2**0
- >                   CONTENTS, READONLY
-
-There are obviously 2 non standard ELF sections in the generated object
-file. But first we want to find out what happened to our code in the
-final kernel executable:
-
- > objdump --disassemble --section=.text vmlinux
- >
- > c017e785 <do_con_write+c1> xorl   %edx,%edx
- > c017e787 <do_con_write+c3> movl   0xc01c7bec,%eax
- > c017e78c <do_con_write+c8> cmpl   $0x18,0x314(%eax)
- > c017e793 <do_con_write+cf> je     c017e79f <do_con_write+db>
- > c017e795 <do_con_write+d1> cmpl   $0xbfffffff,0x40(%esp,1)
- > c017e79d <do_con_write+d9> ja     c017e7a7 <do_con_write+e3>
- > c017e79f <do_con_write+db> movl   %edx,%eax
- > c017e7a1 <do_con_write+dd> movl   0x40(%esp,1),%ebx
- > c017e7a5 <do_con_write+e1> movb   (%ebx),%dl
- > c017e7a7 <do_con_write+e3> movzbl %dl,%esi
-
-The whole user memory access is reduced to 10 x86 machine instructions.
-The instructions bracketed in the .section directives are no longer
-in the normal execution path. They are located in a different section
-of the executable file:
-
- > objdump --disassemble --section=.fixup vmlinux
- >
- > c0199ff5 <.fixup+10b5> movl   $0xfffffff2,%eax
- > c0199ffa <.fixup+10ba> xorb   %dl,%dl
- > c0199ffc <.fixup+10bc> jmp    c017e7a7 <do_con_write+e3>
-
-And finally:
- > objdump --full-contents --section=__ex_table vmlinux
- >
- >  c01aa7c4 93c017c0 e09f19c0 97c017c0 99c017c0  ................
- >  c01aa7d4 f6c217c0 e99f19c0 a5e717c0 f59f19c0  ................
- >  c01aa7e4 080a18c0 01a019c0 0a0a18c0 04a019c0  ................
-
-or in human readable byte order:
-
- >  c01aa7c4 c017c093 c0199fe0 c017c097 c017c099  ................
- >  c01aa7d4 c017c2f6 c0199fe9 c017e7a5 c0199ff5  ................
-                               ^^^^^^^^^^^^^^^^^
-                               this is the interesting part!
- >  c01aa7e4 c0180a08 c019a001 c0180a0a c019a004  ................
-
-What happened? The assembly directives
-
-.section .fixup,"ax"
-.section __ex_table,"a"
-
-told the assembler to move the following code to the specified
-sections in the ELF object file. So the instructions
-3:      movl $-14,%eax
-        xorb %dl,%dl
-        jmp 2b
-ended up in the .fixup section of the object file and the addresses
-        .long 1b,3b
-ended up in the __ex_table section of the object file. 1b and 3b
-are local labels. The local label 1b (1b stands for next label 1
-backward) is the address of the instruction that might fault, i.e.
-in our case the address of the label 1 is c017e7a5:
-the original assembly code: > 1:      movb (%ebx),%dl
-and linked in vmlinux     : > c017e7a5 <do_con_write+e1> movb   (%ebx),%dl
-
-The local label 3 (backwards again) is the address of the code to handle
-the fault, in our case the actual value is c0199ff5:
-the original assembly code: > 3:      movl $-14,%eax
-and linked in vmlinux     : > c0199ff5 <.fixup+10b5> movl   $0xfffffff2,%eax
-
-The assembly code
- > .section __ex_table,"a"
- >         .align 4
- >         .long 1b,3b
-
-becomes the value pair
- >  c01aa7d4 c017c2f6 c0199fe9 c017e7a5 c0199ff5  ................
-                               ^this is ^this is
-                               1b       3b
-c017e7a5,c0199ff5 in the exception table of the kernel.
-
-So, what actually happens if a fault from kernel mode with no suitable
-vma occurs?
-
-1.) access to invalid address:
- > c017e7a5 <do_con_write+e1> movb   (%ebx),%dl
-2.) MMU generates exception
-3.) CPU calls do_page_fault
-4.) do page fault calls search_exception_table (regs->eip == c017e7a5);
-5.) search_exception_table looks up the address c017e7a5 in the
-    exception table (i.e. the contents of the ELF section __ex_table)
-    and returns the address of the associated fault handle code c0199ff5.
-6.) do_page_fault modifies its own return address to point to the fault
-    handle code and returns.
-7.) execution continues in the fault handling code.
-8.) 8a) EAX becomes -EFAULT (== -14)
-    8b) DL  becomes zero (the value we "read" from user space)
-    8c) execution continues at local label 2 (address of the
-        instruction immediately after the faulting user access).
-
-The steps 8a to 8c in a certain way emulate the faulting instruction.
-
-That's it, mostly. If you look at our example, you might ask why
-we set EAX to -EFAULT in the exception handler code. Well, the
-get_user macro actually returns a value: 0, if the user access was
-successful, -EFAULT on failure. Our original code did not test this
-return value, however the inline assembly code in get_user tries to
-return -EFAULT. GCC selected EAX to return this value.
-
-NOTE:
-Due to the way that the exception table is built and needs to be ordered,
-only use exceptions for code in the .text section.  Any other section
-will cause the exception table to not be sorted correctly, and the
-exceptions will fail.
-
-Things changed when 64-bit support was added to x86 Linux. Rather than
-double the size of the exception table by expanding the two entries
-from 32-bits to 64 bits, a clever trick was used to store addresses
-as relative offsets from the table itself. The assembly code changed
-from:
-       .long 1b,3b
-to:
-        .long (from) - .
-        .long (to) - .
-
-and the C-code that uses these values converts back to absolute addresses
-like this:
-
-       ex_insn_addr(const struct exception_table_entry *x)
-       {
-               return (unsigned long)&x->insn + x->insn;
-       }
-
-In v4.6 the exception table entry was expanded with a new field "handler".
-This is also 32-bits wide and contains a third relative function
-pointer which points to one of:
-
-1) int ex_handler_default(const struct exception_table_entry *fixup)
-   This is legacy case that just jumps to the fixup code
-2) int ex_handler_fault(const struct exception_table_entry *fixup)
-   This case provides the fault number of the trap that occurred at
-   entry->insn. It is used to distinguish page faults from machine
-   check.
-3) int ex_handler_ext(const struct exception_table_entry *fixup)
-   This case is used for uaccess_err ... we need to set a flag
-   in the task structure. Before the handler functions existed this
-   case was handled by adding a large offset to the fixup to tag
-   it as special.
-More functions can easily be added.
diff --git a/Documentation/x86/i386/IO-APIC.rst b/Documentation/x86/i386/IO-APIC.rst
new file mode 100644 (file)
index 0000000..ce4d8df
--- /dev/null
@@ -0,0 +1,123 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=======
+IO-APIC
+=======
+
+:Author: Ingo Molnar <mingo@kernel.org>
+
+Most (all) Intel-MP compliant SMP boards have the so-called 'IO-APIC',
+which is an enhanced interrupt controller. It enables us to route
+hardware interrupts to multiple CPUs, or to CPU groups. Without an
+IO-APIC, interrupts from hardware will be delivered only to the
+CPU which boots the operating system (usually CPU#0).
+
+Linux supports all variants of compliant SMP boards, including ones with
+multiple IO-APICs. Multiple IO-APICs are used in high-end servers to
+distribute IRQ load further.
+
+There are (a few) known breakages in certain older boards, such bugs are
+usually worked around by the kernel. If your MP-compliant SMP board does
+not boot Linux, then consult the linux-smp mailing list archives first.
+
+If your box boots fine with enabled IO-APIC IRQs, then your
+/proc/interrupts will look like this one::
+
+  hell:~> cat /proc/interrupts
+             CPU0
+    0:    1360293    IO-APIC-edge  timer
+    1:          4    IO-APIC-edge  keyboard
+    2:          0          XT-PIC  cascade
+   13:          1          XT-PIC  fpu
+   14:       1448    IO-APIC-edge  ide0
+   16:      28232   IO-APIC-level  Intel EtherExpress Pro 10/100 Ethernet
+   17:      51304   IO-APIC-level  eth0
+  NMI:          0
+  ERR:          0
+  hell:~>
+
+Some interrupts are still listed as 'XT PIC', but this is not a problem;
+none of those IRQ sources is performance-critical.
+
+
+In the unlikely case that your board does not create a working mp-table,
+you can use the pirq= boot parameter to 'hand-construct' IRQ entries. This
+is non-trivial though and cannot be automated. One sample /etc/lilo.conf
+entry::
+
+       append="pirq=15,11,10"
+
+The actual numbers depend on your system, on your PCI cards and on their
+PCI slot position. Usually PCI slots are 'daisy chained' before they are
+connected to the PCI chipset IRQ routing facility (the incoming PIRQ1-4
+lines)::
+
+               ,-.        ,-.        ,-.        ,-.        ,-.
+     PIRQ4 ----| |-.    ,-| |-.    ,-| |-.    ,-| |--------| |
+               |S|  \  /  |S|  \  /  |S|  \  /  |S|        |S|
+     PIRQ3 ----|l|-. `/---|l|-. `/---|l|-. `/---|l|--------|l|
+               |o|  \/    |o|  \/    |o|  \/    |o|        |o|
+     PIRQ2 ----|t|-./`----|t|-./`----|t|-./`----|t|--------|t|
+               |1| /\     |2| /\     |3| /\     |4|        |5|
+     PIRQ1 ----| |-  `----| |-  `----| |-  `----| |--------| |
+               `-'        `-'        `-'        `-'        `-'
+
+Every PCI card emits a PCI IRQ, which can be INTA, INTB, INTC or INTD::
+
+                               ,-.
+                         INTD--| |
+                               |S|
+                         INTC--|l|
+                               |o|
+                         INTB--|t|
+                               |x|
+                         INTA--| |
+                               `-'
+
+These INTA-D PCI IRQs are always 'local to the card', their real meaning
+depends on which slot they are in. If you look at the daisy chaining diagram,
+a card in slot4, issuing INTA IRQ, it will end up as a signal on PIRQ4 of
+the PCI chipset. Most cards issue INTA, this creates optimal distribution
+between the PIRQ lines. (distributing IRQ sources properly is not a
+necessity, PCI IRQs can be shared at will, but it's a good for performance
+to have non shared interrupts). Slot5 should be used for videocards, they
+do not use interrupts normally, thus they are not daisy chained either.
+
+so if you have your SCSI card (IRQ11) in Slot1, Tulip card (IRQ9) in
+Slot2, then you'll have to specify this pirq= line::
+
+       append="pirq=11,9"
+
+the following script tries to figure out such a default pirq= line from
+your PCI configuration::
+
+       echo -n pirq=; echo `scanpci | grep T_L | cut -c56-` | sed 's/ /,/g'
+
+note that this script won't work if you have skipped a few slots or if your
+board does not do default daisy-chaining. (or the IO-APIC has the PIRQ pins
+connected in some strange way). E.g. if in the above case you have your SCSI
+card (IRQ11) in Slot3, and have Slot1 empty::
+
+       append="pirq=0,9,11"
+
+[value '0' is a generic 'placeholder', reserved for empty (or non-IRQ emitting)
+slots.]
+
+Generally, it's always possible to find out the correct pirq= settings, just
+permute all IRQ numbers properly ... it will take some time though. An
+'incorrect' pirq line will cause the booting process to hang, or a device
+won't function properly (e.g. if it's inserted as a module).
+
+If you have 2 PCI buses, then you can use up to 8 pirq values, although such
+boards tend to have a good configuration.
+
+Be prepared that it might happen that you need some strange pirq line::
+
+       append="pirq=0,0,0,0,0,0,9,11"
+
+Use smart trial-and-error techniques to find out the correct pirq line ...
+
+Good luck and mail to linux-smp@vger.kernel.org or
+linux-kernel@vger.kernel.org if you have any problems that are not covered
+by this document.
+
diff --git a/Documentation/x86/i386/IO-APIC.txt b/Documentation/x86/i386/IO-APIC.txt
deleted file mode 100644 (file)
index 15f5baf..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-Most (all) Intel-MP compliant SMP boards have the so-called 'IO-APIC',
-which is an enhanced interrupt controller. It enables us to route
-hardware interrupts to multiple CPUs, or to CPU groups. Without an
-IO-APIC, interrupts from hardware will be delivered only to the
-CPU which boots the operating system (usually CPU#0).
-
-Linux supports all variants of compliant SMP boards, including ones with
-multiple IO-APICs. Multiple IO-APICs are used in high-end servers to
-distribute IRQ load further.
-
-There are (a few) known breakages in certain older boards, such bugs are
-usually worked around by the kernel. If your MP-compliant SMP board does
-not boot Linux, then consult the linux-smp mailing list archives first.
-
-If your box boots fine with enabled IO-APIC IRQs, then your
-/proc/interrupts will look like this one:
-
-   ---------------------------->
-  hell:~> cat /proc/interrupts
-             CPU0
-    0:    1360293    IO-APIC-edge  timer
-    1:          4    IO-APIC-edge  keyboard
-    2:          0          XT-PIC  cascade
-   13:          1          XT-PIC  fpu
-   14:       1448    IO-APIC-edge  ide0
-   16:      28232   IO-APIC-level  Intel EtherExpress Pro 10/100 Ethernet
-   17:      51304   IO-APIC-level  eth0
-  NMI:          0
-  ERR:          0
-  hell:~>
-  <----------------------------
-
-Some interrupts are still listed as 'XT PIC', but this is not a problem;
-none of those IRQ sources is performance-critical.
-
-
-In the unlikely case that your board does not create a working mp-table,
-you can use the pirq= boot parameter to 'hand-construct' IRQ entries. This
-is non-trivial though and cannot be automated. One sample /etc/lilo.conf
-entry:
-
-       append="pirq=15,11,10"
-
-The actual numbers depend on your system, on your PCI cards and on their
-PCI slot position. Usually PCI slots are 'daisy chained' before they are
-connected to the PCI chipset IRQ routing facility (the incoming PIRQ1-4
-lines):
-
-               ,-.        ,-.        ,-.        ,-.        ,-.
-     PIRQ4 ----| |-.    ,-| |-.    ,-| |-.    ,-| |--------| |
-               |S|  \  /  |S|  \  /  |S|  \  /  |S|        |S|
-     PIRQ3 ----|l|-. `/---|l|-. `/---|l|-. `/---|l|--------|l|
-               |o|  \/    |o|  \/    |o|  \/    |o|        |o|
-     PIRQ2 ----|t|-./`----|t|-./`----|t|-./`----|t|--------|t|
-               |1| /\     |2| /\     |3| /\     |4|        |5|
-     PIRQ1 ----| |-  `----| |-  `----| |-  `----| |--------| |
-               `-'        `-'        `-'        `-'        `-'
-
-Every PCI card emits a PCI IRQ, which can be INTA, INTB, INTC or INTD:
-
-                               ,-.
-                         INTD--| |
-                               |S|
-                         INTC--|l|
-                               |o|
-                         INTB--|t|
-                               |x|
-                         INTA--| |
-                               `-'
-
-These INTA-D PCI IRQs are always 'local to the card', their real meaning
-depends on which slot they are in. If you look at the daisy chaining diagram,
-a card in slot4, issuing INTA IRQ, it will end up as a signal on PIRQ4 of
-the PCI chipset. Most cards issue INTA, this creates optimal distribution
-between the PIRQ lines. (distributing IRQ sources properly is not a
-necessity, PCI IRQs can be shared at will, but it's a good for performance
-to have non shared interrupts). Slot5 should be used for videocards, they
-do not use interrupts normally, thus they are not daisy chained either.
-
-so if you have your SCSI card (IRQ11) in Slot1, Tulip card (IRQ9) in
-Slot2, then you'll have to specify this pirq= line:
-
-       append="pirq=11,9"
-
-the following script tries to figure out such a default pirq= line from
-your PCI configuration:
-
-       echo -n pirq=; echo `scanpci | grep T_L | cut -c56-` | sed 's/ /,/g'
-
-note that this script won't work if you have skipped a few slots or if your
-board does not do default daisy-chaining. (or the IO-APIC has the PIRQ pins
-connected in some strange way). E.g. if in the above case you have your SCSI
-card (IRQ11) in Slot3, and have Slot1 empty:
-
-       append="pirq=0,9,11"
-
-[value '0' is a generic 'placeholder', reserved for empty (or non-IRQ emitting)
-slots.]
-
-Generally, it's always possible to find out the correct pirq= settings, just
-permute all IRQ numbers properly ... it will take some time though. An
-'incorrect' pirq line will cause the booting process to hang, or a device
-won't function properly (e.g. if it's inserted as a module).
-
-If you have 2 PCI buses, then you can use up to 8 pirq values, although such
-boards tend to have a good configuration.
-
-Be prepared that it might happen that you need some strange pirq line:
-
-       append="pirq=0,0,0,0,0,0,9,11"
-
-Use smart trial-and-error techniques to find out the correct pirq line ...
-
-Good luck and mail to linux-smp@vger.kernel.org or
-linux-kernel@vger.kernel.org if you have any problems that are not covered
-by this document.
-
--- mingo
-
diff --git a/Documentation/x86/i386/index.rst b/Documentation/x86/i386/index.rst
new file mode 100644 (file)
index 0000000..8747cf5
--- /dev/null
@@ -0,0 +1,10 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============
+i386 Support
+============
+
+.. toctree::
+   :maxdepth: 2
+
+   IO-APIC
diff --git a/Documentation/x86/index.rst b/Documentation/x86/index.rst
new file mode 100644 (file)
index 0000000..ae36fc5
--- /dev/null
@@ -0,0 +1,31 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==========================
+x86-specific Documentation
+==========================
+
+.. toctree::
+   :maxdepth: 2
+   :numbered:
+
+   boot
+   topology
+   exception-tables
+   kernel-stacks
+   entry_64
+   earlyprintk
+   orc-unwinder
+   zero-page
+   tlb
+   mtrr
+   pat
+   protection-keys
+   intel_mpx
+   amd-memory-encryption
+   pti
+   mds
+   microcode
+   resctrl_ui
+   usb-legacy-support
+   i386/index
+   x86_64/index
diff --git a/Documentation/x86/intel_mpx.rst b/Documentation/x86/intel_mpx.rst
new file mode 100644 (file)
index 0000000..387a640
--- /dev/null
@@ -0,0 +1,252 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===========================================
+Intel(R) Memory Protection Extensions (MPX)
+===========================================
+
+Intel(R) MPX Overview
+=====================
+
+Intel(R) Memory Protection Extensions (Intel(R) MPX) is a new capability
+introduced into Intel Architecture. Intel MPX provides hardware features
+that can be used in conjunction with compiler changes to check memory
+references, for those references whose compile-time normal intentions are
+usurped at runtime due to buffer overflow or underflow.
+
+You can tell if your CPU supports MPX by looking in /proc/cpuinfo::
+
+       cat /proc/cpuinfo  | grep ' mpx '
+
+For more information, please refer to Intel(R) Architecture Instruction
+Set Extensions Programming Reference, Chapter 9: Intel(R) Memory Protection
+Extensions.
+
+Note: As of December 2014, no hardware with MPX is available but it is
+possible to use SDE (Intel(R) Software Development Emulator) instead, which
+can be downloaded from
+http://software.intel.com/en-us/articles/intel-software-development-emulator
+
+
+How to get the advantage of MPX
+===============================
+
+For MPX to work, changes are required in the kernel, binutils and compiler.
+No source changes are required for applications, just a recompile.
+
+There are a lot of moving parts of this to all work right. The following
+is how we expect the compiler, application and kernel to work together.
+
+1) Application developer compiles with -fmpx. The compiler will add the
+   instrumentation as well as some setup code called early after the app
+   starts. New instruction prefixes are noops for old CPUs.
+2) That setup code allocates (virtual) space for the "bounds directory",
+   points the "bndcfgu" register to the directory (must also set the valid
+   bit) and notifies the kernel (via the new prctl(PR_MPX_ENABLE_MANAGEMENT))
+   that the app will be using MPX.  The app must be careful not to access
+   the bounds tables between the time when it populates "bndcfgu" and
+   when it calls the prctl().  This might be hard to guarantee if the app
+   is compiled with MPX.  You can add "__attribute__((bnd_legacy))" to
+   the function to disable MPX instrumentation to help guarantee this.
+   Also be careful not to call out to any other code which might be
+   MPX-instrumented.
+3) The kernel detects that the CPU has MPX, allows the new prctl() to
+   succeed, and notes the location of the bounds directory. Userspace is
+   expected to keep the bounds directory at that location. We note it
+   instead of reading it each time because the 'xsave' operation needed
+   to access the bounds directory register is an expensive operation.
+4) If the application needs to spill bounds out of the 4 registers, it
+   issues a bndstx instruction. Since the bounds directory is empty at
+   this point, a bounds fault (#BR) is raised, the kernel allocates a
+   bounds table (in the user address space) and makes the relevant entry
+   in the bounds directory point to the new table.
+5) If the application violates the bounds specified in the bounds registers,
+   a separate kind of #BR is raised which will deliver a signal with
+   information about the violation in the 'struct siginfo'.
+6) Whenever memory is freed, we know that it can no longer contain valid
+   pointers, and we attempt to free the associated space in the bounds
+   tables. If an entire table becomes unused, we will attempt to free
+   the table and remove the entry in the directory.
+
+To summarize, there are essentially three things interacting here:
+
+GCC with -fmpx:
+ * enables annotation of code with MPX instructions and prefixes
+ * inserts code early in the application to call in to the "gcc runtime"
+GCC MPX Runtime:
+ * Checks for hardware MPX support in cpuid leaf
+ * allocates virtual space for the bounds directory (malloc() essentially)
+ * points the hardware BNDCFGU register at the directory
+ * calls a new prctl(PR_MPX_ENABLE_MANAGEMENT) to notify the kernel to
+   start managing the bounds directories
+Kernel MPX Code:
+ * Checks for hardware MPX support in cpuid leaf
+ * Handles #BR exceptions and sends SIGSEGV to the app when it violates
+   bounds, like during a buffer overflow.
+ * When bounds are spilled in to an unallocated bounds table, the kernel
+   notices in the #BR exception, allocates the virtual space, then
+   updates the bounds directory to point to the new table. It keeps
+   special track of the memory with a VM_MPX flag.
+ * Frees unused bounds tables at the time that the memory they described
+   is unmapped.
+
+
+How does MPX kernel code work
+=============================
+
+Handling #BR faults caused by MPX
+---------------------------------
+
+When MPX is enabled, there are 2 new situations that can generate
+#BR faults.
+
+  * new bounds tables (BT) need to be allocated to save bounds.
+  * bounds violation caused by MPX instructions.
+
+We hook #BR handler to handle these two new situations.
+
+On-demand kernel allocation of bounds tables
+--------------------------------------------
+
+MPX only has 4 hardware registers for storing bounds information. If
+MPX-enabled code needs more than these 4 registers, it needs to spill
+them somewhere. It has two special instructions for this which allow
+the bounds to be moved between the bounds registers and some new "bounds
+tables".
+
+#BR exceptions are a new class of exceptions just for MPX. They are
+similar conceptually to a page fault and will be raised by the MPX
+hardware during both bounds violations or when the tables are not
+present. The kernel handles those #BR exceptions for not-present tables
+by carving the space out of the normal processes address space and then
+pointing the bounds-directory over to it.
+
+The tables need to be accessed and controlled by userspace because
+the instructions for moving bounds in and out of them are extremely
+frequent. They potentially happen every time a register points to
+memory. Any direct kernel involvement (like a syscall) to access the
+tables would obviously destroy performance.
+
+Why not do this in userspace? MPX does not strictly require anything in
+the kernel. It can theoretically be done completely from userspace. Here
+are a few ways this could be done. We don't think any of them are practical
+in the real-world, but here they are.
+
+:Q: Can virtual space simply be reserved for the bounds tables so that we
+    never have to allocate them?
+:A: MPX-enabled application will possibly create a lot of bounds tables in
+    process address space to save bounds information. These tables can take
+    up huge swaths of memory (as much as 80% of the memory on the system)
+    even if we clean them up aggressively. In the worst-case scenario, the
+    tables can be 4x the size of the data structure being tracked. IOW, a
+    1-page structure can require 4 bounds-table pages. An X-GB virtual
+    area needs 4*X GB of virtual space, plus 2GB for the bounds directory.
+    If we were to preallocate them for the 128TB of user virtual address
+    space, we would need to reserve 512TB+2GB, which is larger than the
+    entire virtual address space today. This means they can not be reserved
+    ahead of time. Also, a single process's pre-populated bounds directory
+    consumes 2GB of virtual *AND* physical memory. IOW, it's completely
+    infeasible to prepopulate bounds directories.
+
+:Q: Can we preallocate bounds table space at the same time memory is
+    allocated which might contain pointers that might eventually need
+    bounds tables?
+:A: This would work if we could hook the site of each and every memory
+    allocation syscall. This can be done for small, constrained applications.
+    But, it isn't practical at a larger scale since a given app has no
+    way of controlling how all the parts of the app might allocate memory
+    (think libraries). The kernel is really the only place to intercept
+    these calls.
+
+:Q: Could a bounds fault be handed to userspace and the tables allocated
+    there in a signal handler instead of in the kernel?
+:A: mmap() is not on the list of safe async handler functions and even
+    if mmap() would work it still requires locking or nasty tricks to
+    keep track of the allocation state there.
+
+Having ruled out all of the userspace-only approaches for managing
+bounds tables that we could think of, we create them on demand in
+the kernel.
+
+Decoding MPX instructions
+-------------------------
+
+If a #BR is generated due to a bounds violation caused by MPX.
+We need to decode MPX instructions to get violation address and
+set this address into extended struct siginfo.
+
+The _sigfault field of struct siginfo is extended as follow::
+
+  87           /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+  88           struct {
+  89                   void __user *_addr; /* faulting insn/memory ref. */
+  90 #ifdef __ARCH_SI_TRAPNO
+  91                   int _trapno;    /* TRAP # which caused the signal */
+  92 #endif
+  93                   short _addr_lsb; /* LSB of the reported address */
+  94                   struct {
+  95                           void __user *_lower;
+  96                           void __user *_upper;
+  97                   } _addr_bnd;
+  98           } _sigfault;
+
+The '_addr' field refers to violation address, and new '_addr_and'
+field refers to the upper/lower bounds when a #BR is caused.
+
+Glibc will be also updated to support this new siginfo. So user
+can get violation address and bounds when bounds violations occur.
+
+Cleanup unused bounds tables
+----------------------------
+
+When a BNDSTX instruction attempts to save bounds to a bounds directory
+entry marked as invalid, a #BR is generated. This is an indication that
+no bounds table exists for this entry. In this case the fault handler
+will allocate a new bounds table on demand.
+
+Since the kernel allocated those tables on-demand without userspace
+knowledge, it is also responsible for freeing them when the associated
+mappings go away.
+
+Here, the solution for this issue is to hook do_munmap() to check
+whether one process is MPX enabled. If yes, those bounds tables covered
+in the virtual address region which is being unmapped will be freed also.
+
+Adding new prctl commands
+-------------------------
+
+Two new prctl commands are added to enable and disable MPX bounds tables
+management in kernel.
+::
+
+  155  #define PR_MPX_ENABLE_MANAGEMENT        43
+  156  #define PR_MPX_DISABLE_MANAGEMENT       44
+
+Runtime library in userspace is responsible for allocation of bounds
+directory. So kernel have to use XSAVE instruction to get the base
+of bounds directory from BNDCFG register.
+
+But XSAVE is expected to be very expensive. In order to do performance
+optimization, we have to get the base of bounds directory and save it
+into struct mm_struct to be used in future during PR_MPX_ENABLE_MANAGEMENT
+command execution.
+
+
+Special rules
+=============
+
+1) If userspace is requesting help from the kernel to do the management
+of bounds tables, it may not create or modify entries in the bounds directory.
+
+Certainly users can allocate bounds tables and forcibly point the bounds
+directory at them through XSAVE instruction, and then set valid bit
+of bounds entry to have this entry valid.  But, the kernel will decline
+to assist in managing these tables.
+
+2) Userspace may not take multiple bounds directory entries and point
+them at the same bounds table.
+
+This is allowed architecturally.  See more information "Intel(R) Architecture
+Instruction Set Extensions Programming Reference" (9.3.4).
+
+However, if users did this, the kernel might be fooled in to unmapping an
+in-use bounds table since it does not recognize sharing.
diff --git a/Documentation/x86/intel_mpx.txt b/Documentation/x86/intel_mpx.txt
deleted file mode 100644 (file)
index 85d0549..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-1. Intel(R) MPX Overview
-========================
-
-Intel(R) Memory Protection Extensions (Intel(R) MPX) is a new capability
-introduced into Intel Architecture. Intel MPX provides hardware features
-that can be used in conjunction with compiler changes to check memory
-references, for those references whose compile-time normal intentions are
-usurped at runtime due to buffer overflow or underflow.
-
-You can tell if your CPU supports MPX by looking in /proc/cpuinfo:
-
-       cat /proc/cpuinfo  | grep ' mpx '
-
-For more information, please refer to Intel(R) Architecture Instruction
-Set Extensions Programming Reference, Chapter 9: Intel(R) Memory Protection
-Extensions.
-
-Note: As of December 2014, no hardware with MPX is available but it is
-possible to use SDE (Intel(R) Software Development Emulator) instead, which
-can be downloaded from
-http://software.intel.com/en-us/articles/intel-software-development-emulator
-
-
-2. How to get the advantage of MPX
-==================================
-
-For MPX to work, changes are required in the kernel, binutils and compiler.
-No source changes are required for applications, just a recompile.
-
-There are a lot of moving parts of this to all work right. The following
-is how we expect the compiler, application and kernel to work together.
-
-1) Application developer compiles with -fmpx. The compiler will add the
-   instrumentation as well as some setup code called early after the app
-   starts. New instruction prefixes are noops for old CPUs.
-2) That setup code allocates (virtual) space for the "bounds directory",
-   points the "bndcfgu" register to the directory (must also set the valid
-   bit) and notifies the kernel (via the new prctl(PR_MPX_ENABLE_MANAGEMENT))
-   that the app will be using MPX.  The app must be careful not to access
-   the bounds tables between the time when it populates "bndcfgu" and
-   when it calls the prctl().  This might be hard to guarantee if the app
-   is compiled with MPX.  You can add "__attribute__((bnd_legacy))" to
-   the function to disable MPX instrumentation to help guarantee this.
-   Also be careful not to call out to any other code which might be
-   MPX-instrumented.
-3) The kernel detects that the CPU has MPX, allows the new prctl() to
-   succeed, and notes the location of the bounds directory. Userspace is
-   expected to keep the bounds directory at that location. We note it
-   instead of reading it each time because the 'xsave' operation needed
-   to access the bounds directory register is an expensive operation.
-4) If the application needs to spill bounds out of the 4 registers, it
-   issues a bndstx instruction. Since the bounds directory is empty at
-   this point, a bounds fault (#BR) is raised, the kernel allocates a
-   bounds table (in the user address space) and makes the relevant entry
-   in the bounds directory point to the new table.
-5) If the application violates the bounds specified in the bounds registers,
-   a separate kind of #BR is raised which will deliver a signal with
-   information about the violation in the 'struct siginfo'.
-6) Whenever memory is freed, we know that it can no longer contain valid
-   pointers, and we attempt to free the associated space in the bounds
-   tables. If an entire table becomes unused, we will attempt to free
-   the table and remove the entry in the directory.
-
-To summarize, there are essentially three things interacting here:
-
-GCC with -fmpx:
- * enables annotation of code with MPX instructions and prefixes
- * inserts code early in the application to call in to the "gcc runtime"
-GCC MPX Runtime:
- * Checks for hardware MPX support in cpuid leaf
- * allocates virtual space for the bounds directory (malloc() essentially)
- * points the hardware BNDCFGU register at the directory
- * calls a new prctl(PR_MPX_ENABLE_MANAGEMENT) to notify the kernel to
-   start managing the bounds directories
-Kernel MPX Code:
- * Checks for hardware MPX support in cpuid leaf
- * Handles #BR exceptions and sends SIGSEGV to the app when it violates
-   bounds, like during a buffer overflow.
- * When bounds are spilled in to an unallocated bounds table, the kernel
-   notices in the #BR exception, allocates the virtual space, then
-   updates the bounds directory to point to the new table. It keeps
-   special track of the memory with a VM_MPX flag.
- * Frees unused bounds tables at the time that the memory they described
-   is unmapped.
-
-
-3. How does MPX kernel code work
-================================
-
-Handling #BR faults caused by MPX
----------------------------------
-
-When MPX is enabled, there are 2 new situations that can generate
-#BR faults.
-  * new bounds tables (BT) need to be allocated to save bounds.
-  * bounds violation caused by MPX instructions.
-
-We hook #BR handler to handle these two new situations.
-
-On-demand kernel allocation of bounds tables
---------------------------------------------
-
-MPX only has 4 hardware registers for storing bounds information. If
-MPX-enabled code needs more than these 4 registers, it needs to spill
-them somewhere. It has two special instructions for this which allow
-the bounds to be moved between the bounds registers and some new "bounds
-tables".
-
-#BR exceptions are a new class of exceptions just for MPX. They are
-similar conceptually to a page fault and will be raised by the MPX
-hardware during both bounds violations or when the tables are not
-present. The kernel handles those #BR exceptions for not-present tables
-by carving the space out of the normal processes address space and then
-pointing the bounds-directory over to it.
-
-The tables need to be accessed and controlled by userspace because
-the instructions for moving bounds in and out of them are extremely
-frequent. They potentially happen every time a register points to
-memory. Any direct kernel involvement (like a syscall) to access the
-tables would obviously destroy performance.
-
-Why not do this in userspace? MPX does not strictly require anything in
-the kernel. It can theoretically be done completely from userspace. Here
-are a few ways this could be done. We don't think any of them are practical
-in the real-world, but here they are.
-
-Q: Can virtual space simply be reserved for the bounds tables so that we
-   never have to allocate them?
-A: MPX-enabled application will possibly create a lot of bounds tables in
-   process address space to save bounds information. These tables can take
-   up huge swaths of memory (as much as 80% of the memory on the system)
-   even if we clean them up aggressively. In the worst-case scenario, the
-   tables can be 4x the size of the data structure being tracked. IOW, a
-   1-page structure can require 4 bounds-table pages. An X-GB virtual
-   area needs 4*X GB of virtual space, plus 2GB for the bounds directory.
-   If we were to preallocate them for the 128TB of user virtual address
-   space, we would need to reserve 512TB+2GB, which is larger than the
-   entire virtual address space today. This means they can not be reserved
-   ahead of time. Also, a single process's pre-populated bounds directory
-   consumes 2GB of virtual *AND* physical memory. IOW, it's completely
-   infeasible to prepopulate bounds directories.
-
-Q: Can we preallocate bounds table space at the same time memory is
-   allocated which might contain pointers that might eventually need
-   bounds tables?
-A: This would work if we could hook the site of each and every memory
-   allocation syscall. This can be done for small, constrained applications.
-   But, it isn't practical at a larger scale since a given app has no
-   way of controlling how all the parts of the app might allocate memory
-   (think libraries). The kernel is really the only place to intercept
-   these calls.
-
-Q: Could a bounds fault be handed to userspace and the tables allocated
-   there in a signal handler instead of in the kernel?
-A: mmap() is not on the list of safe async handler functions and even
-   if mmap() would work it still requires locking or nasty tricks to
-   keep track of the allocation state there.
-
-Having ruled out all of the userspace-only approaches for managing
-bounds tables that we could think of, we create them on demand in
-the kernel.
-
-Decoding MPX instructions
--------------------------
-
-If a #BR is generated due to a bounds violation caused by MPX.
-We need to decode MPX instructions to get violation address and
-set this address into extended struct siginfo.
-
-The _sigfault field of struct siginfo is extended as follow:
-
-87             /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-88             struct {
-89                     void __user *_addr; /* faulting insn/memory ref. */
-90 #ifdef __ARCH_SI_TRAPNO
-91                     int _trapno;    /* TRAP # which caused the signal */
-92 #endif
-93                     short _addr_lsb; /* LSB of the reported address */
-94                     struct {
-95                             void __user *_lower;
-96                             void __user *_upper;
-97                     } _addr_bnd;
-98             } _sigfault;
-
-The '_addr' field refers to violation address, and new '_addr_and'
-field refers to the upper/lower bounds when a #BR is caused.
-
-Glibc will be also updated to support this new siginfo. So user
-can get violation address and bounds when bounds violations occur.
-
-Cleanup unused bounds tables
-----------------------------
-
-When a BNDSTX instruction attempts to save bounds to a bounds directory
-entry marked as invalid, a #BR is generated. This is an indication that
-no bounds table exists for this entry. In this case the fault handler
-will allocate a new bounds table on demand.
-
-Since the kernel allocated those tables on-demand without userspace
-knowledge, it is also responsible for freeing them when the associated
-mappings go away.
-
-Here, the solution for this issue is to hook do_munmap() to check
-whether one process is MPX enabled. If yes, those bounds tables covered
-in the virtual address region which is being unmapped will be freed also.
-
-Adding new prctl commands
--------------------------
-
-Two new prctl commands are added to enable and disable MPX bounds tables
-management in kernel.
-
-155    #define PR_MPX_ENABLE_MANAGEMENT        43
-156    #define PR_MPX_DISABLE_MANAGEMENT       44
-
-Runtime library in userspace is responsible for allocation of bounds
-directory. So kernel have to use XSAVE instruction to get the base
-of bounds directory from BNDCFG register.
-
-But XSAVE is expected to be very expensive. In order to do performance
-optimization, we have to get the base of bounds directory and save it
-into struct mm_struct to be used in future during PR_MPX_ENABLE_MANAGEMENT
-command execution.
-
-
-4. Special rules
-================
-
-1) If userspace is requesting help from the kernel to do the management
-of bounds tables, it may not create or modify entries in the bounds directory.
-
-Certainly users can allocate bounds tables and forcibly point the bounds
-directory at them through XSAVE instruction, and then set valid bit
-of bounds entry to have this entry valid.  But, the kernel will decline
-to assist in managing these tables.
-
-2) Userspace may not take multiple bounds directory entries and point
-them at the same bounds table.
-
-This is allowed architecturally.  See more information "Intel(R) Architecture
-Instruction Set Extensions Programming Reference" (9.3.4).
-
-However, if users did this, the kernel might be fooled in to unmapping an
-in-use bounds table since it does not recognize sharing.
diff --git a/Documentation/x86/kernel-stacks b/Documentation/x86/kernel-stacks
deleted file mode 100644 (file)
index d1bfb0b..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-Kernel stacks on x86-64 bit
----------------------------
-
-Most of the text from Keith Owens, hacked by AK
-
-x86_64 page size (PAGE_SIZE) is 4K.
-
-Like all other architectures, x86_64 has a kernel stack for every
-active thread.  These thread stacks are THREAD_SIZE (2*PAGE_SIZE) big.
-These stacks contain useful data as long as a thread is alive or a
-zombie. While the thread is in user space the kernel stack is empty
-except for the thread_info structure at the bottom.
-
-In addition to the per thread stacks, there are specialized stacks
-associated with each CPU.  These stacks are only used while the kernel
-is in control on that CPU; when a CPU returns to user space the
-specialized stacks contain no useful data.  The main CPU stacks are:
-
-* Interrupt stack.  IRQ_STACK_SIZE
-
-  Used for external hardware interrupts.  If this is the first external
-  hardware interrupt (i.e. not a nested hardware interrupt) then the
-  kernel switches from the current task to the interrupt stack.  Like
-  the split thread and interrupt stacks on i386, this gives more room
-  for kernel interrupt processing without having to increase the size
-  of every per thread stack.
-
-  The interrupt stack is also used when processing a softirq.
-
-Switching to the kernel interrupt stack is done by software based on a
-per CPU interrupt nest counter. This is needed because x86-64 "IST"
-hardware stacks cannot nest without races.
-
-x86_64 also has a feature which is not available on i386, the ability
-to automatically switch to a new stack for designated events such as
-double fault or NMI, which makes it easier to handle these unusual
-events on x86_64.  This feature is called the Interrupt Stack Table
-(IST).  There can be up to 7 IST entries per CPU. The IST code is an
-index into the Task State Segment (TSS). The IST entries in the TSS
-point to dedicated stacks; each stack can be a different size.
-
-An IST is selected by a non-zero value in the IST field of an
-interrupt-gate descriptor.  When an interrupt occurs and the hardware
-loads such a descriptor, the hardware automatically sets the new stack
-pointer based on the IST value, then invokes the interrupt handler.  If
-the interrupt came from user mode, then the interrupt handler prologue
-will switch back to the per-thread stack.  If software wants to allow
-nested IST interrupts then the handler must adjust the IST values on
-entry to and exit from the interrupt handler.  (This is occasionally
-done, e.g. for debug exceptions.)
-
-Events with different IST codes (i.e. with different stacks) can be
-nested.  For example, a debug interrupt can safely be interrupted by an
-NMI.  arch/x86_64/kernel/entry.S::paranoidentry adjusts the stack
-pointers on entry to and exit from all IST events, in theory allowing
-IST events with the same code to be nested.  However in most cases, the
-stack size allocated to an IST assumes no nesting for the same code.
-If that assumption is ever broken then the stacks will become corrupt.
-
-The currently assigned IST stacks are :-
-
-* ESTACK_DF.  EXCEPTION_STKSZ (PAGE_SIZE).
-
-  Used for interrupt 8 - Double Fault Exception (#DF).
-
-  Invoked when handling one exception causes another exception. Happens
-  when the kernel is very confused (e.g. kernel stack pointer corrupt).
-  Using a separate stack allows the kernel to recover from it well enough
-  in many cases to still output an oops.
-
-* ESTACK_NMI.  EXCEPTION_STKSZ (PAGE_SIZE).
-
-  Used for non-maskable interrupts (NMI).
-
-  NMI can be delivered at any time, including when the kernel is in the
-  middle of switching stacks.  Using IST for NMI events avoids making
-  assumptions about the previous state of the kernel stack.
-
-* ESTACK_DB.  EXCEPTION_STKSZ (PAGE_SIZE).
-
-  Used for hardware debug interrupts (interrupt 1) and for software
-  debug interrupts (INT3).
-
-  When debugging a kernel, debug interrupts (both hardware and
-  software) can occur at any time.  Using IST for these interrupts
-  avoids making assumptions about the previous state of the kernel
-  stack.
-
-  To handle nested #DB correctly there exist two instances of DB stacks. On
-  #DB entry the IST stackpointer for #DB is switched to the second instance
-  so a nested #DB starts from a clean stack. The nested #DB switches
-  the IST stackpointer to a guard hole to catch triple nesting.
-
-* ESTACK_MCE.  EXCEPTION_STKSZ (PAGE_SIZE).
-
-  Used for interrupt 18 - Machine Check Exception (#MC).
-
-  MCE can be delivered at any time, including when the kernel is in the
-  middle of switching stacks.  Using IST for MCE events avoids making
-  assumptions about the previous state of the kernel stack.
-
-For more details see the Intel IA32 or AMD AMD64 architecture manuals.
-
-
-Printing backtraces on x86
---------------------------
-
-The question about the '?' preceding function names in an x86 stacktrace
-keeps popping up, here's an indepth explanation. It helps if the reader
-stares at print_context_stack() and the whole machinery in and around
-arch/x86/kernel/dumpstack.c.
-
-Adapted from Ingo's mail, Message-ID: <20150521101614.GA10889@gmail.com>:
-
-We always scan the full kernel stack for return addresses stored on
-the kernel stack(s) [*], from stack top to stack bottom, and print out
-anything that 'looks like' a kernel text address.
-
-If it fits into the frame pointer chain, we print it without a question
-mark, knowing that it's part of the real backtrace.
-
-If the address does not fit into our expected frame pointer chain we
-still print it, but we print a '?'. It can mean two things:
-
- - either the address is not part of the call chain: it's just stale
-   values on the kernel stack, from earlier function calls. This is
-   the common case.
-
- - or it is part of the call chain, but the frame pointer was not set
-   up properly within the function, so we don't recognize it.
-
-This way we will always print out the real call chain (plus a few more
-entries), regardless of whether the frame pointer was set up correctly
-or not - but in most cases we'll get the call chain right as well. The
-entries printed are strictly in stack order, so you can deduce more
-information from that as well.
-
-The most important property of this method is that we _never_ lose
-information: we always strive to print _all_ addresses on the stack(s)
-that look like kernel text addresses, so if debug information is wrong,
-we still print out the real call chain as well - just with more question
-marks than ideal.
-
-[*] For things like IRQ and IST stacks, we also scan those stacks, in
-    the right order, and try to cross from one stack into another
-    reconstructing the call chain. This works most of the time.
diff --git a/Documentation/x86/kernel-stacks.rst b/Documentation/x86/kernel-stacks.rst
new file mode 100644 (file)
index 0000000..6b0bcf0
--- /dev/null
@@ -0,0 +1,152 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=============
+Kernel Stacks
+=============
+
+Kernel stacks on x86-64 bit
+===========================
+
+Most of the text from Keith Owens, hacked by AK
+
+x86_64 page size (PAGE_SIZE) is 4K.
+
+Like all other architectures, x86_64 has a kernel stack for every
+active thread.  These thread stacks are THREAD_SIZE (2*PAGE_SIZE) big.
+These stacks contain useful data as long as a thread is alive or a
+zombie. While the thread is in user space the kernel stack is empty
+except for the thread_info structure at the bottom.
+
+In addition to the per thread stacks, there are specialized stacks
+associated with each CPU.  These stacks are only used while the kernel
+is in control on that CPU; when a CPU returns to user space the
+specialized stacks contain no useful data.  The main CPU stacks are:
+
+* Interrupt stack.  IRQ_STACK_SIZE
+
+  Used for external hardware interrupts.  If this is the first external
+  hardware interrupt (i.e. not a nested hardware interrupt) then the
+  kernel switches from the current task to the interrupt stack.  Like
+  the split thread and interrupt stacks on i386, this gives more room
+  for kernel interrupt processing without having to increase the size
+  of every per thread stack.
+
+  The interrupt stack is also used when processing a softirq.
+
+Switching to the kernel interrupt stack is done by software based on a
+per CPU interrupt nest counter. This is needed because x86-64 "IST"
+hardware stacks cannot nest without races.
+
+x86_64 also has a feature which is not available on i386, the ability
+to automatically switch to a new stack for designated events such as
+double fault or NMI, which makes it easier to handle these unusual
+events on x86_64.  This feature is called the Interrupt Stack Table
+(IST).  There can be up to 7 IST entries per CPU. The IST code is an
+index into the Task State Segment (TSS). The IST entries in the TSS
+point to dedicated stacks; each stack can be a different size.
+
+An IST is selected by a non-zero value in the IST field of an
+interrupt-gate descriptor.  When an interrupt occurs and the hardware
+loads such a descriptor, the hardware automatically sets the new stack
+pointer based on the IST value, then invokes the interrupt handler.  If
+the interrupt came from user mode, then the interrupt handler prologue
+will switch back to the per-thread stack.  If software wants to allow
+nested IST interrupts then the handler must adjust the IST values on
+entry to and exit from the interrupt handler.  (This is occasionally
+done, e.g. for debug exceptions.)
+
+Events with different IST codes (i.e. with different stacks) can be
+nested.  For example, a debug interrupt can safely be interrupted by an
+NMI.  arch/x86_64/kernel/entry.S::paranoidentry adjusts the stack
+pointers on entry to and exit from all IST events, in theory allowing
+IST events with the same code to be nested.  However in most cases, the
+stack size allocated to an IST assumes no nesting for the same code.
+If that assumption is ever broken then the stacks will become corrupt.
+
+The currently assigned IST stacks are:
+
+* ESTACK_DF.  EXCEPTION_STKSZ (PAGE_SIZE).
+
+  Used for interrupt 8 - Double Fault Exception (#DF).
+
+  Invoked when handling one exception causes another exception. Happens
+  when the kernel is very confused (e.g. kernel stack pointer corrupt).
+  Using a separate stack allows the kernel to recover from it well enough
+  in many cases to still output an oops.
+
+* ESTACK_NMI.  EXCEPTION_STKSZ (PAGE_SIZE).
+
+  Used for non-maskable interrupts (NMI).
+
+  NMI can be delivered at any time, including when the kernel is in the
+  middle of switching stacks.  Using IST for NMI events avoids making
+  assumptions about the previous state of the kernel stack.
+
+* ESTACK_DB.  EXCEPTION_STKSZ (PAGE_SIZE).
+
+  Used for hardware debug interrupts (interrupt 1) and for software
+  debug interrupts (INT3).
+
+  When debugging a kernel, debug interrupts (both hardware and
+  software) can occur at any time.  Using IST for these interrupts
+  avoids making assumptions about the previous state of the kernel
+  stack.
+
+  To handle nested #DB correctly there exist two instances of DB stacks. On
+  #DB entry the IST stackpointer for #DB is switched to the second instance
+  so a nested #DB starts from a clean stack. The nested #DB switches
+  the IST stackpointer to a guard hole to catch triple nesting.
+
+* ESTACK_MCE.  EXCEPTION_STKSZ (PAGE_SIZE).
+
+  Used for interrupt 18 - Machine Check Exception (#MC).
+
+  MCE can be delivered at any time, including when the kernel is in the
+  middle of switching stacks.  Using IST for MCE events avoids making
+  assumptions about the previous state of the kernel stack.
+
+For more details see the Intel IA32 or AMD AMD64 architecture manuals.
+
+
+Printing backtraces on x86
+==========================
+
+The question about the '?' preceding function names in an x86 stacktrace
+keeps popping up, here's an indepth explanation. It helps if the reader
+stares at print_context_stack() and the whole machinery in and around
+arch/x86/kernel/dumpstack.c.
+
+Adapted from Ingo's mail, Message-ID: <20150521101614.GA10889@gmail.com>:
+
+We always scan the full kernel stack for return addresses stored on
+the kernel stack(s) [1]_, from stack top to stack bottom, and print out
+anything that 'looks like' a kernel text address.
+
+If it fits into the frame pointer chain, we print it without a question
+mark, knowing that it's part of the real backtrace.
+
+If the address does not fit into our expected frame pointer chain we
+still print it, but we print a '?'. It can mean two things:
+
+ - either the address is not part of the call chain: it's just stale
+   values on the kernel stack, from earlier function calls. This is
+   the common case.
+
+ - or it is part of the call chain, but the frame pointer was not set
+   up properly within the function, so we don't recognize it.
+
+This way we will always print out the real call chain (plus a few more
+entries), regardless of whether the frame pointer was set up correctly
+or not - but in most cases we'll get the call chain right as well. The
+entries printed are strictly in stack order, so you can deduce more
+information from that as well.
+
+The most important property of this method is that we _never_ lose
+information: we always strive to print _all_ addresses on the stack(s)
+that look like kernel text addresses, so if debug information is wrong,
+we still print out the real call chain as well - just with more question
+marks than ideal.
+
+.. [1] For things like IRQ and IST stacks, we also scan those stacks, in
+       the right order, and try to cross from one stack into another
+       reconstructing the call chain. This works most of the time.
diff --git a/Documentation/x86/mds.rst b/Documentation/x86/mds.rst
new file mode 100644 (file)
index 0000000..5d4330b
--- /dev/null
@@ -0,0 +1,193 @@
+Microarchitectural Data Sampling (MDS) mitigation
+=================================================
+
+.. _mds:
+
+Overview
+--------
+
+Microarchitectural Data Sampling (MDS) is a family of side channel attacks
+on internal buffers in Intel CPUs. The variants are:
+
+ - Microarchitectural Store Buffer Data Sampling (MSBDS) (CVE-2018-12126)
+ - Microarchitectural Fill Buffer Data Sampling (MFBDS) (CVE-2018-12130)
+ - Microarchitectural Load Port Data Sampling (MLPDS) (CVE-2018-12127)
+ - Microarchitectural Data Sampling Uncacheable Memory (MDSUM) (CVE-2019-11091)
+
+MSBDS leaks Store Buffer Entries which can be speculatively forwarded to a
+dependent load (store-to-load forwarding) as an optimization. The forward
+can also happen to a faulting or assisting load operation for a different
+memory address, which can be exploited under certain conditions. Store
+buffers are partitioned between Hyper-Threads so cross thread forwarding is
+not possible. But if a thread enters or exits a sleep state the store
+buffer is repartitioned which can expose data from one thread to the other.
+
+MFBDS leaks Fill Buffer Entries. Fill buffers are used internally to manage
+L1 miss situations and to hold data which is returned or sent in response
+to a memory or I/O operation. Fill buffers can forward data to a load
+operation and also write data to the cache. When the fill buffer is
+deallocated it can retain the stale data of the preceding operations which
+can then be forwarded to a faulting or assisting load operation, which can
+be exploited under certain conditions. Fill buffers are shared between
+Hyper-Threads so cross thread leakage is possible.
+
+MLPDS leaks Load Port Data. Load ports are used to perform load operations
+from memory or I/O. The received data is then forwarded to the register
+file or a subsequent operation. In some implementations the Load Port can
+contain stale data from a previous operation which can be forwarded to
+faulting or assisting loads under certain conditions, which again can be
+exploited eventually. Load ports are shared between Hyper-Threads so cross
+thread leakage is possible.
+
+MDSUM is a special case of MSBDS, MFBDS and MLPDS. An uncacheable load from
+memory that takes a fault or assist can leave data in a microarchitectural
+structure that may later be observed using one of the same methods used by
+MSBDS, MFBDS or MLPDS.
+
+Exposure assumptions
+--------------------
+
+It is assumed that attack code resides in user space or in a guest with one
+exception. The rationale behind this assumption is that the code construct
+needed for exploiting MDS requires:
+
+ - to control the load to trigger a fault or assist
+
+ - to have a disclosure gadget which exposes the speculatively accessed
+   data for consumption through a side channel.
+
+ - to control the pointer through which the disclosure gadget exposes the
+   data
+
+The existence of such a construct in the kernel cannot be excluded with
+100% certainty, but the complexity involved makes it extremly unlikely.
+
+There is one exception, which is untrusted BPF. The functionality of
+untrusted BPF is limited, but it needs to be thoroughly investigated
+whether it can be used to create such a construct.
+
+
+Mitigation strategy
+-------------------
+
+All variants have the same mitigation strategy at least for the single CPU
+thread case (SMT off): Force the CPU to clear the affected buffers.
+
+This is achieved by using the otherwise unused and obsolete VERW
+instruction in combination with a microcode update. The microcode clears
+the affected CPU buffers when the VERW instruction is executed.
+
+For virtualization there are two ways to achieve CPU buffer
+clearing. Either the modified VERW instruction or via the L1D Flush
+command. The latter is issued when L1TF mitigation is enabled so the extra
+VERW can be avoided. If the CPU is not affected by L1TF then VERW needs to
+be issued.
+
+If the VERW instruction with the supplied segment selector argument is
+executed on a CPU without the microcode update there is no side effect
+other than a small number of pointlessly wasted CPU cycles.
+
+This does not protect against cross Hyper-Thread attacks except for MSBDS
+which is only exploitable cross Hyper-thread when one of the Hyper-Threads
+enters a C-state.
+
+The kernel provides a function to invoke the buffer clearing:
+
+    mds_clear_cpu_buffers()
+
+The mitigation is invoked on kernel/userspace, hypervisor/guest and C-state
+(idle) transitions.
+
+As a special quirk to address virtualization scenarios where the host has
+the microcode updated, but the hypervisor does not (yet) expose the
+MD_CLEAR CPUID bit to guests, the kernel issues the VERW instruction in the
+hope that it might actually clear the buffers. The state is reflected
+accordingly.
+
+According to current knowledge additional mitigations inside the kernel
+itself are not required because the necessary gadgets to expose the leaked
+data cannot be controlled in a way which allows exploitation from malicious
+user space or VM guests.
+
+Kernel internal mitigation modes
+--------------------------------
+
+ ======= ============================================================
+ off      Mitigation is disabled. Either the CPU is not affected or
+          mds=off is supplied on the kernel command line
+
+ full     Mitigation is enabled. CPU is affected and MD_CLEAR is
+          advertised in CPUID.
+
+ vmwerv          Mitigation is enabled. CPU is affected and MD_CLEAR is not
+         advertised in CPUID. That is mainly for virtualization
+         scenarios where the host has the updated microcode but the
+         hypervisor does not expose MD_CLEAR in CPUID. It's a best
+         effort approach without guarantee.
+ ======= ============================================================
+
+If the CPU is affected and mds=off is not supplied on the kernel command
+line then the kernel selects the appropriate mitigation mode depending on
+the availability of the MD_CLEAR CPUID bit.
+
+Mitigation points
+-----------------
+
+1. Return to user space
+^^^^^^^^^^^^^^^^^^^^^^^
+
+   When transitioning from kernel to user space the CPU buffers are flushed
+   on affected CPUs when the mitigation is not disabled on the kernel
+   command line. The migitation is enabled through the static key
+   mds_user_clear.
+
+   The mitigation is invoked in prepare_exit_to_usermode() which covers
+   all but one of the kernel to user space transitions.  The exception
+   is when we return from a Non Maskable Interrupt (NMI), which is
+   handled directly in do_nmi().
+
+   (The reason that NMI is special is that prepare_exit_to_usermode() can
+    enable IRQs.  In NMI context, NMIs are blocked, and we don't want to
+    enable IRQs with NMIs blocked.)
+
+
+2. C-State transition
+^^^^^^^^^^^^^^^^^^^^^
+
+   When a CPU goes idle and enters a C-State the CPU buffers need to be
+   cleared on affected CPUs when SMT is active. This addresses the
+   repartitioning of the store buffer when one of the Hyper-Threads enters
+   a C-State.
+
+   When SMT is inactive, i.e. either the CPU does not support it or all
+   sibling threads are offline CPU buffer clearing is not required.
+
+   The idle clearing is enabled on CPUs which are only affected by MSBDS
+   and not by any other MDS variant. The other MDS variants cannot be
+   protected against cross Hyper-Thread attacks because the Fill Buffer and
+   the Load Ports are shared. So on CPUs affected by other variants, the
+   idle clearing would be a window dressing exercise and is therefore not
+   activated.
+
+   The invocation is controlled by the static key mds_idle_clear which is
+   switched depending on the chosen mitigation mode and the SMT state of
+   the system.
+
+   The buffer clear is only invoked before entering the C-State to prevent
+   that stale data from the idling CPU from spilling to the Hyper-Thread
+   sibling after the store buffer got repartitioned and all entries are
+   available to the non idle sibling.
+
+   When coming out of idle the store buffer is partitioned again so each
+   sibling has half of it available. The back from idle CPU could be then
+   speculatively exposed to contents of the sibling. The buffers are
+   flushed either on exit to user space or on VMENTER so malicious code
+   in user space or the guest cannot speculatively access them.
+
+   The mitigation is hooked into all variants of halt()/mwait(), but does
+   not cover the legacy ACPI IO-Port mechanism because the ACPI idle driver
+   has been superseded by the intel_idle driver around 2010 and is
+   preferred on all affected CPUs which are expected to gain the MD_CLEAR
+   functionality in microcode. Aside of that the IO-Port mechanism is a
+   legacy interface which is only used on older systems which are either
+   not affected or do not receive microcode updates anymore.
diff --git a/Documentation/x86/microcode.rst b/Documentation/x86/microcode.rst
new file mode 100644 (file)
index 0000000..a320d37
--- /dev/null
@@ -0,0 +1,142 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==========================
+The Linux Microcode Loader
+==========================
+
+:Authors: - Fenghua Yu <fenghua.yu@intel.com>
+          - Borislav Petkov <bp@suse.de>
+
+The kernel has a x86 microcode loading facility which is supposed to
+provide microcode loading methods in the OS. Potential use cases are
+updating the microcode on platforms beyond the OEM End-Of-Life support,
+and updating the microcode on long-running systems without rebooting.
+
+The loader supports three loading methods:
+
+Early load microcode
+====================
+
+The kernel can update microcode very early during boot. Loading
+microcode early can fix CPU issues before they are observed during
+kernel boot time.
+
+The microcode is stored in an initrd file. During boot, it is read from
+it and loaded into the CPU cores.
+
+The format of the combined initrd image is microcode in (uncompressed)
+cpio format followed by the (possibly compressed) initrd image. The
+loader parses the combined initrd image during boot.
+
+The microcode files in cpio name space are:
+
+on Intel:
+  kernel/x86/microcode/GenuineIntel.bin
+on AMD  :
+  kernel/x86/microcode/AuthenticAMD.bin
+
+During BSP (BootStrapping Processor) boot (pre-SMP), the kernel
+scans the microcode file in the initrd. If microcode matching the
+CPU is found, it will be applied in the BSP and later on in all APs
+(Application Processors).
+
+The loader also saves the matching microcode for the CPU in memory.
+Thus, the cached microcode patch is applied when CPUs resume from a
+sleep state.
+
+Here's a crude example how to prepare an initrd with microcode (this is
+normally done automatically by the distribution, when recreating the
+initrd, so you don't really have to do it yourself. It is documented
+here for future reference only).
+::
+
+  #!/bin/bash
+
+  if [ -z "$1" ]; then
+      echo "You need to supply an initrd file"
+      exit 1
+  fi
+
+  INITRD="$1"
+
+  DSTDIR=kernel/x86/microcode
+  TMPDIR=/tmp/initrd
+
+  rm -rf $TMPDIR
+
+  mkdir $TMPDIR
+  cd $TMPDIR
+  mkdir -p $DSTDIR
+
+  if [ -d /lib/firmware/amd-ucode ]; then
+          cat /lib/firmware/amd-ucode/microcode_amd*.bin > $DSTDIR/AuthenticAMD.bin
+  fi
+
+  if [ -d /lib/firmware/intel-ucode ]; then
+          cat /lib/firmware/intel-ucode/* > $DSTDIR/GenuineIntel.bin
+  fi
+
+  find . | cpio -o -H newc >../ucode.cpio
+  cd ..
+  mv $INITRD $INITRD.orig
+  cat ucode.cpio $INITRD.orig > $INITRD
+
+  rm -rf $TMPDIR
+
+
+The system needs to have the microcode packages installed into
+/lib/firmware or you need to fixup the paths above if yours are
+somewhere else and/or you've downloaded them directly from the processor
+vendor's site.
+
+Late loading
+============
+
+There are two legacy user space interfaces to load microcode, either through
+/dev/cpu/microcode or through /sys/devices/system/cpu/microcode/reload file
+in sysfs.
+
+The /dev/cpu/microcode method is deprecated because it needs a special
+userspace tool for that.
+
+The easier method is simply installing the microcode packages your distro
+supplies and running::
+
+  # echo 1 > /sys/devices/system/cpu/microcode/reload
+
+as root.
+
+The loading mechanism looks for microcode blobs in
+/lib/firmware/{intel-ucode,amd-ucode}. The default distro installation
+packages already put them there.
+
+Builtin microcode
+=================
+
+The loader supports also loading of a builtin microcode supplied through
+the regular builtin firmware method CONFIG_EXTRA_FIRMWARE. Only 64-bit is
+currently supported.
+
+Here's an example::
+
+  CONFIG_EXTRA_FIRMWARE="intel-ucode/06-3a-09 amd-ucode/microcode_amd_fam15h.bin"
+  CONFIG_EXTRA_FIRMWARE_DIR="/lib/firmware"
+
+This basically means, you have the following tree structure locally::
+
+  /lib/firmware/
+  |-- amd-ucode
+  ...
+  |   |-- microcode_amd_fam15h.bin
+  ...
+  |-- intel-ucode
+  ...
+  |   |-- 06-3a-09
+  ...
+
+so that the build system can find those files and integrate them into
+the final kernel image. The early loader finds them and applies them.
+
+Needless to say, this method is not the most flexible one because it
+requires rebuilding the kernel each time updated microcode from the CPU
+vendor is available.
diff --git a/Documentation/x86/microcode.txt b/Documentation/x86/microcode.txt
deleted file mode 100644 (file)
index 79fdb4a..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-       The Linux Microcode Loader
-
-Authors: Fenghua Yu <fenghua.yu@intel.com>
-        Borislav Petkov <bp@suse.de>
-
-The kernel has a x86 microcode loading facility which is supposed to
-provide microcode loading methods in the OS. Potential use cases are
-updating the microcode on platforms beyond the OEM End-Of-Life support,
-and updating the microcode on long-running systems without rebooting.
-
-The loader supports three loading methods:
-
-1. Early load microcode
-=======================
-
-The kernel can update microcode very early during boot. Loading
-microcode early can fix CPU issues before they are observed during
-kernel boot time.
-
-The microcode is stored in an initrd file. During boot, it is read from
-it and loaded into the CPU cores.
-
-The format of the combined initrd image is microcode in (uncompressed)
-cpio format followed by the (possibly compressed) initrd image. The
-loader parses the combined initrd image during boot.
-
-The microcode files in cpio name space are:
-
-on Intel: kernel/x86/microcode/GenuineIntel.bin
-on AMD  : kernel/x86/microcode/AuthenticAMD.bin
-
-During BSP (BootStrapping Processor) boot (pre-SMP), the kernel
-scans the microcode file in the initrd. If microcode matching the
-CPU is found, it will be applied in the BSP and later on in all APs
-(Application Processors).
-
-The loader also saves the matching microcode for the CPU in memory.
-Thus, the cached microcode patch is applied when CPUs resume from a
-sleep state.
-
-Here's a crude example how to prepare an initrd with microcode (this is
-normally done automatically by the distribution, when recreating the
-initrd, so you don't really have to do it yourself. It is documented
-here for future reference only).
-
----
-  #!/bin/bash
-
-  if [ -z "$1" ]; then
-      echo "You need to supply an initrd file"
-      exit 1
-  fi
-
-  INITRD="$1"
-
-  DSTDIR=kernel/x86/microcode
-  TMPDIR=/tmp/initrd
-
-  rm -rf $TMPDIR
-
-  mkdir $TMPDIR
-  cd $TMPDIR
-  mkdir -p $DSTDIR
-
-  if [ -d /lib/firmware/amd-ucode ]; then
-          cat /lib/firmware/amd-ucode/microcode_amd*.bin > $DSTDIR/AuthenticAMD.bin
-  fi
-
-  if [ -d /lib/firmware/intel-ucode ]; then
-          cat /lib/firmware/intel-ucode/* > $DSTDIR/GenuineIntel.bin
-  fi
-
-  find . | cpio -o -H newc >../ucode.cpio
-  cd ..
-  mv $INITRD $INITRD.orig
-  cat ucode.cpio $INITRD.orig > $INITRD
-
-  rm -rf $TMPDIR
----
-
-The system needs to have the microcode packages installed into
-/lib/firmware or you need to fixup the paths above if yours are
-somewhere else and/or you've downloaded them directly from the processor
-vendor's site.
-
-2. Late loading
-===============
-
-There are two legacy user space interfaces to load microcode, either through
-/dev/cpu/microcode or through /sys/devices/system/cpu/microcode/reload file
-in sysfs.
-
-The /dev/cpu/microcode method is deprecated because it needs a special
-userspace tool for that.
-
-The easier method is simply installing the microcode packages your distro
-supplies and running:
-
-# echo 1 > /sys/devices/system/cpu/microcode/reload
-
-as root.
-
-The loading mechanism looks for microcode blobs in
-/lib/firmware/{intel-ucode,amd-ucode}. The default distro installation
-packages already put them there.
-
-3. Builtin microcode
-====================
-
-The loader supports also loading of a builtin microcode supplied through
-the regular builtin firmware method CONFIG_EXTRA_FIRMWARE. Only 64-bit is
-currently supported.
-
-Here's an example:
-
-CONFIG_EXTRA_FIRMWARE="intel-ucode/06-3a-09 amd-ucode/microcode_amd_fam15h.bin"
-CONFIG_EXTRA_FIRMWARE_DIR="/lib/firmware"
-
-This basically means, you have the following tree structure locally:
-
-/lib/firmware/
-|-- amd-ucode
-...
-|   |-- microcode_amd_fam15h.bin
-...
-|-- intel-ucode
-...
-|   |-- 06-3a-09
-...
-
-so that the build system can find those files and integrate them into
-the final kernel image. The early loader finds them and applies them.
-
-Needless to say, this method is not the most flexible one because it
-requires rebuilding the kernel each time updated microcode from the CPU
-vendor is available.
diff --git a/Documentation/x86/mtrr.rst b/Documentation/x86/mtrr.rst
new file mode 100644 (file)
index 0000000..c5b695d
--- /dev/null
@@ -0,0 +1,354 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=========================================
+MTRR (Memory Type Range Register) control
+=========================================
+
+:Authors: - Richard Gooch <rgooch@atnf.csiro.au> - 3 Jun 1999
+          - Luis R. Rodriguez <mcgrof@do-not-panic.com> - April 9, 2015
+
+
+Phasing out MTRR use
+====================
+
+MTRR use is replaced on modern x86 hardware with PAT. Direct MTRR use by
+drivers on Linux is now completely phased out, device drivers should use
+arch_phys_wc_add() in combination with ioremap_wc() to make MTRR effective on
+non-PAT systems while a no-op but equally effective on PAT enabled systems.
+
+Even if Linux does not use MTRRs directly, some x86 platform firmware may still
+set up MTRRs early before booting the OS. They do this as some platform
+firmware may still have implemented access to MTRRs which would be controlled
+and handled by the platform firmware directly. An example of platform use of
+MTRRs is through the use of SMI handlers, one case could be for fan control,
+the platform code would need uncachable access to some of its fan control
+registers. Such platform access does not need any Operating System MTRR code in
+place other than mtrr_type_lookup() to ensure any OS specific mapping requests
+are aligned with platform MTRR setup. If MTRRs are only set up by the platform
+firmware code though and the OS does not make any specific MTRR mapping
+requests mtrr_type_lookup() should always return MTRR_TYPE_INVALID.
+
+For details refer to :doc:`pat`.
+
+.. tip::
+  On Intel P6 family processors (Pentium Pro, Pentium II and later)
+  the Memory Type Range Registers (MTRRs) may be used to control
+  processor access to memory ranges. This is most useful when you have
+  a video (VGA) card on a PCI or AGP bus. Enabling write-combining
+  allows bus write transfers to be combined into a larger transfer
+  before bursting over the PCI/AGP bus. This can increase performance
+  of image write operations 2.5 times or more.
+
+  The Cyrix 6x86, 6x86MX and M II processors have Address Range
+  Registers (ARRs) which provide a similar functionality to MTRRs. For
+  these, the ARRs are used to emulate the MTRRs.
+
+  The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
+  MTRRs. These are supported.  The AMD Athlon family provide 8 Intel
+  style MTRRs.
+
+  The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These
+  are supported.
+
+  The VIA Cyrix III and VIA C3 CPUs offer 8 Intel style MTRRs.
+
+  The CONFIG_MTRR option creates a /proc/mtrr file which may be used
+  to manipulate your MTRRs. Typically the X server should use
+  this. This should have a reasonably generic interface so that
+  similar control registers on other processors can be easily
+  supported.
+
+There are two interfaces to /proc/mtrr: one is an ASCII interface
+which allows you to read and write. The other is an ioctl()
+interface. The ASCII interface is meant for administration. The
+ioctl() interface is meant for C programs (i.e. the X server). The
+interfaces are described below, with sample commands and C code.
+
+
+Reading MTRRs from the shell
+============================
+::
+
+  % cat /proc/mtrr
+  reg00: base=0x00000000 (   0MB), size= 128MB: write-back, count=1
+  reg01: base=0x08000000 ( 128MB), size=  64MB: write-back, count=1
+
+Creating MTRRs from the C-shell::
+
+  # echo "base=0xf8000000 size=0x400000 type=write-combining" >! /proc/mtrr
+
+or if you use bash::
+
+  # echo "base=0xf8000000 size=0x400000 type=write-combining" >| /proc/mtrr
+
+And the result thereof::
+
+  % cat /proc/mtrr
+  reg00: base=0x00000000 (   0MB), size= 128MB: write-back, count=1
+  reg01: base=0x08000000 ( 128MB), size=  64MB: write-back, count=1
+  reg02: base=0xf8000000 (3968MB), size=   4MB: write-combining, count=1
+
+This is for video RAM at base address 0xf8000000 and size 4 megabytes. To
+find out your base address, you need to look at the output of your X
+server, which tells you where the linear framebuffer address is. A
+typical line that you may get is::
+
+  (--) S3: PCI: 968 rev 0, Linear FB @ 0xf8000000
+
+Note that you should only use the value from the X server, as it may
+move the framebuffer base address, so the only value you can trust is
+that reported by the X server.
+
+To find out the size of your framebuffer (what, you don't actually
+know?), the following line will tell you::
+
+  (--) S3: videoram:  4096k
+
+That's 4 megabytes, which is 0x400000 bytes (in hexadecimal).
+A patch is being written for XFree86 which will make this automatic:
+in other words the X server will manipulate /proc/mtrr using the
+ioctl() interface, so users won't have to do anything. If you use a
+commercial X server, lobby your vendor to add support for MTRRs.
+
+
+Creating overlapping MTRRs
+==========================
+::
+
+  %echo "base=0xfb000000 size=0x1000000 type=write-combining" >/proc/mtrr
+  %echo "base=0xfb000000 size=0x1000 type=uncachable" >/proc/mtrr
+
+And the results::
+
+  % cat /proc/mtrr
+  reg00: base=0x00000000 (   0MB), size=  64MB: write-back, count=1
+  reg01: base=0xfb000000 (4016MB), size=  16MB: write-combining, count=1
+  reg02: base=0xfb000000 (4016MB), size=   4kB: uncachable, count=1
+
+Some cards (especially Voodoo Graphics boards) need this 4 kB area
+excluded from the beginning of the region because it is used for
+registers.
+
+NOTE: You can only create type=uncachable region, if the first
+region that you created is type=write-combining.
+
+
+Removing MTRRs from the C-shel
+==============================
+::
+
+  % echo "disable=2" >! /proc/mtrr
+
+or using bash::
+
+  % echo "disable=2" >| /proc/mtrr
+
+
+Reading MTRRs from a C program using ioctl()'s
+==============================================
+::
+
+  /*  mtrr-show.c
+
+      Source file for mtrr-show (example program to show MTRRs using ioctl()'s)
+
+      Copyright (C) 1997-1998  Richard Gooch
+
+      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.
+
+      You should have received a copy of the GNU General Public License
+      along with this program; if not, write to the Free Software
+      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+      Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
+      The postal address is:
+        Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+  */
+
+  /*
+      This program will use an ioctl() on /proc/mtrr to show the current MTRR
+      settings. This is an alternative to reading /proc/mtrr.
+
+
+      Written by      Richard Gooch   17-DEC-1997
+
+      Last updated by Richard Gooch   2-MAY-1998
+
+
+  */
+  #include <stdio.h>
+  #include <stdlib.h>
+  #include <string.h>
+  #include <sys/types.h>
+  #include <sys/stat.h>
+  #include <fcntl.h>
+  #include <sys/ioctl.h>
+  #include <errno.h>
+  #include <asm/mtrr.h>
+
+  #define TRUE 1
+  #define FALSE 0
+  #define ERRSTRING strerror (errno)
+
+  static char *mtrr_strings[MTRR_NUM_TYPES] =
+  {
+      "uncachable",               /* 0 */
+      "write-combining",          /* 1 */
+      "?",                        /* 2 */
+      "?",                        /* 3 */
+      "write-through",            /* 4 */
+      "write-protect",            /* 5 */
+      "write-back",               /* 6 */
+  };
+
+  int main ()
+  {
+      int fd;
+      struct mtrr_gentry gentry;
+
+      if ( ( fd = open ("/proc/mtrr", O_RDONLY, 0) ) == -1 )
+      {
+    if (errno == ENOENT)
+    {
+        fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
+        stderr);
+        exit (1);
+    }
+    fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
+    exit (2);
+      }
+      for (gentry.regnum = 0; ioctl (fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
+    ++gentry.regnum)
+      {
+    if (gentry.size < 1)
+    {
+        fprintf (stderr, "Register: %u disabled\n", gentry.regnum);
+        continue;
+    }
+    fprintf (stderr, "Register: %u base: 0x%lx size: 0x%lx type: %s\n",
+      gentry.regnum, gentry.base, gentry.size,
+      mtrr_strings[gentry.type]);
+      }
+      if (errno == EINVAL) exit (0);
+      fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
+      exit (3);
+  }   /*  End Function main  */
+
+
+Creating MTRRs from a C programme using ioctl()'s
+=================================================
+::
+
+  /*  mtrr-add.c
+
+      Source file for mtrr-add (example programme to add an MTRRs using ioctl())
+
+      Copyright (C) 1997-1998  Richard Gooch
+
+      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.
+
+      You should have received a copy of the GNU General Public License
+      along with this program; if not, write to the Free Software
+      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+      Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
+      The postal address is:
+        Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+  */
+
+  /*
+      This programme will use an ioctl() on /proc/mtrr to add an entry. The first
+      available mtrr is used. This is an alternative to writing /proc/mtrr.
+
+
+      Written by      Richard Gooch   17-DEC-1997
+
+      Last updated by Richard Gooch   2-MAY-1998
+
+
+  */
+  #include <stdio.h>
+  #include <string.h>
+  #include <stdlib.h>
+  #include <unistd.h>
+  #include <sys/types.h>
+  #include <sys/stat.h>
+  #include <fcntl.h>
+  #include <sys/ioctl.h>
+  #include <errno.h>
+  #include <asm/mtrr.h>
+
+  #define TRUE 1
+  #define FALSE 0
+  #define ERRSTRING strerror (errno)
+
+  static char *mtrr_strings[MTRR_NUM_TYPES] =
+  {
+      "uncachable",               /* 0 */
+      "write-combining",          /* 1 */
+      "?",                        /* 2 */
+      "?",                        /* 3 */
+      "write-through",            /* 4 */
+      "write-protect",            /* 5 */
+      "write-back",               /* 6 */
+  };
+
+  int main (int argc, char **argv)
+  {
+      int fd;
+      struct mtrr_sentry sentry;
+
+      if (argc != 4)
+      {
+    fprintf (stderr, "Usage:\tmtrr-add base size type\n");
+    exit (1);
+      }
+      sentry.base = strtoul (argv[1], NULL, 0);
+      sentry.size = strtoul (argv[2], NULL, 0);
+      for (sentry.type = 0; sentry.type < MTRR_NUM_TYPES; ++sentry.type)
+      {
+    if (strcmp (argv[3], mtrr_strings[sentry.type]) == 0) break;
+      }
+      if (sentry.type >= MTRR_NUM_TYPES)
+      {
+    fprintf (stderr, "Illegal type: \"%s\"\n", argv[3]);
+    exit (2);
+      }
+      if ( ( fd = open ("/proc/mtrr", O_WRONLY, 0) ) == -1 )
+      {
+    if (errno == ENOENT)
+    {
+        fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
+        stderr);
+        exit (3);
+    }
+    fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
+    exit (4);
+      }
+      if (ioctl (fd, MTRRIOC_ADD_ENTRY, &sentry) == -1)
+      {
+    fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
+    exit (5);
+      }
+      fprintf (stderr, "Sleeping for 5 seconds so you can see the new entry\n");
+      sleep (5);
+      close (fd);
+      fputs ("I've just closed /proc/mtrr so now the new entry should be gone\n",
+      stderr);
+  }   /*  End Function main  */
diff --git a/Documentation/x86/mtrr.txt b/Documentation/x86/mtrr.txt
deleted file mode 100644 (file)
index dc3e703..0000000
+++ /dev/null
@@ -1,329 +0,0 @@
-MTRR (Memory Type Range Register) control
-
-Richard Gooch <rgooch@atnf.csiro.au> - 3 Jun 1999
-Luis R. Rodriguez <mcgrof@do-not-panic.com> - April 9, 2015
-
-===============================================================================
-Phasing out MTRR use
-
-MTRR use is replaced on modern x86 hardware with PAT. Direct MTRR use by
-drivers on Linux is now completely phased out, device drivers should use
-arch_phys_wc_add() in combination with ioremap_wc() to make MTRR effective on
-non-PAT systems while a no-op but equally effective on PAT enabled systems.
-
-Even if Linux does not use MTRRs directly, some x86 platform firmware may still
-set up MTRRs early before booting the OS. They do this as some platform
-firmware may still have implemented access to MTRRs which would be controlled
-and handled by the platform firmware directly. An example of platform use of
-MTRRs is through the use of SMI handlers, one case could be for fan control,
-the platform code would need uncachable access to some of its fan control
-registers. Such platform access does not need any Operating System MTRR code in
-place other than mtrr_type_lookup() to ensure any OS specific mapping requests
-are aligned with platform MTRR setup. If MTRRs are only set up by the platform
-firmware code though and the OS does not make any specific MTRR mapping
-requests mtrr_type_lookup() should always return MTRR_TYPE_INVALID.
-
-For details refer to Documentation/x86/pat.txt.
-
-===============================================================================
-
-  On Intel P6 family processors (Pentium Pro, Pentium II and later)
-  the Memory Type Range Registers (MTRRs) may be used to control
-  processor access to memory ranges. This is most useful when you have
-  a video (VGA) card on a PCI or AGP bus. Enabling write-combining
-  allows bus write transfers to be combined into a larger transfer
-  before bursting over the PCI/AGP bus. This can increase performance
-  of image write operations 2.5 times or more.
-
-  The Cyrix 6x86, 6x86MX and M II processors have Address Range
-  Registers (ARRs) which provide a similar functionality to MTRRs. For
-  these, the ARRs are used to emulate the MTRRs.
-
-  The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
-  MTRRs. These are supported.  The AMD Athlon family provide 8 Intel
-  style MTRRs.
-
-  The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These
-  are supported.
-
-  The VIA Cyrix III and VIA C3 CPUs offer 8 Intel style MTRRs.
-
-  The CONFIG_MTRR option creates a /proc/mtrr file which may be used
-  to manipulate your MTRRs. Typically the X server should use
-  this. This should have a reasonably generic interface so that
-  similar control registers on other processors can be easily
-  supported.
-
-
-There are two interfaces to /proc/mtrr: one is an ASCII interface
-which allows you to read and write. The other is an ioctl()
-interface. The ASCII interface is meant for administration. The
-ioctl() interface is meant for C programs (i.e. the X server). The
-interfaces are described below, with sample commands and C code.
-
-===============================================================================
-Reading MTRRs from the shell:
-
-% cat /proc/mtrr
-reg00: base=0x00000000 (   0MB), size= 128MB: write-back, count=1
-reg01: base=0x08000000 ( 128MB), size=  64MB: write-back, count=1
-===============================================================================
-Creating MTRRs from the C-shell:
-# echo "base=0xf8000000 size=0x400000 type=write-combining" >! /proc/mtrr
-or if you use bash:
-# echo "base=0xf8000000 size=0x400000 type=write-combining" >| /proc/mtrr
-
-And the result thereof:
-% cat /proc/mtrr
-reg00: base=0x00000000 (   0MB), size= 128MB: write-back, count=1
-reg01: base=0x08000000 ( 128MB), size=  64MB: write-back, count=1
-reg02: base=0xf8000000 (3968MB), size=   4MB: write-combining, count=1
-
-This is for video RAM at base address 0xf8000000 and size 4 megabytes. To
-find out your base address, you need to look at the output of your X
-server, which tells you where the linear framebuffer address is. A
-typical line that you may get is:
-
-(--) S3: PCI: 968 rev 0, Linear FB @ 0xf8000000
-
-Note that you should only use the value from the X server, as it may
-move the framebuffer base address, so the only value you can trust is
-that reported by the X server.
-
-To find out the size of your framebuffer (what, you don't actually
-know?), the following line will tell you:
-
-(--) S3: videoram:  4096k
-
-That's 4 megabytes, which is 0x400000 bytes (in hexadecimal).
-A patch is being written for XFree86 which will make this automatic:
-in other words the X server will manipulate /proc/mtrr using the
-ioctl() interface, so users won't have to do anything. If you use a
-commercial X server, lobby your vendor to add support for MTRRs.
-===============================================================================
-Creating overlapping MTRRs:
-
-%echo "base=0xfb000000 size=0x1000000 type=write-combining" >/proc/mtrr
-%echo "base=0xfb000000 size=0x1000 type=uncachable" >/proc/mtrr
-
-And the results: cat /proc/mtrr
-reg00: base=0x00000000 (   0MB), size=  64MB: write-back, count=1
-reg01: base=0xfb000000 (4016MB), size=  16MB: write-combining, count=1
-reg02: base=0xfb000000 (4016MB), size=   4kB: uncachable, count=1
-
-Some cards (especially Voodoo Graphics boards) need this 4 kB area
-excluded from the beginning of the region because it is used for
-registers.
-
-NOTE: You can only create type=uncachable region, if the first
-region that you created is type=write-combining.
-===============================================================================
-Removing MTRRs from the C-shell:
-% echo "disable=2" >! /proc/mtrr
-or using bash:
-% echo "disable=2" >| /proc/mtrr
-===============================================================================
-Reading MTRRs from a C program using ioctl()'s:
-
-/*  mtrr-show.c
-
-    Source file for mtrr-show (example program to show MTRRs using ioctl()'s)
-
-    Copyright (C) 1997-1998  Richard Gooch
-
-    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.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
-    The postal address is:
-      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
-*/
-
-/*
-    This program will use an ioctl() on /proc/mtrr to show the current MTRR
-    settings. This is an alternative to reading /proc/mtrr.
-
-
-    Written by      Richard Gooch   17-DEC-1997
-
-    Last updated by Richard Gooch   2-MAY-1998
-
-
-*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <asm/mtrr.h>
-
-#define TRUE 1
-#define FALSE 0
-#define ERRSTRING strerror (errno)
-
-static char *mtrr_strings[MTRR_NUM_TYPES] =
-{
-    "uncachable",               /* 0 */
-    "write-combining",          /* 1 */
-    "?",                        /* 2 */
-    "?",                        /* 3 */
-    "write-through",            /* 4 */
-    "write-protect",            /* 5 */
-    "write-back",               /* 6 */
-};
-
-int main ()
-{
-    int fd;
-    struct mtrr_gentry gentry;
-
-    if ( ( fd = open ("/proc/mtrr", O_RDONLY, 0) ) == -1 )
-    {
-       if (errno == ENOENT)
-       {
-           fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
-                  stderr);
-           exit (1);
-       }
-       fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
-       exit (2);
-    }
-    for (gentry.regnum = 0; ioctl (fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
-        ++gentry.regnum)
-    {
-       if (gentry.size < 1)
-       {
-           fprintf (stderr, "Register: %u disabled\n", gentry.regnum);
-           continue;
-       }
-       fprintf (stderr, "Register: %u base: 0x%lx size: 0x%lx type: %s\n",
-                gentry.regnum, gentry.base, gentry.size,
-                mtrr_strings[gentry.type]);
-    }
-    if (errno == EINVAL) exit (0);
-    fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
-    exit (3);
-}   /*  End Function main  */
-===============================================================================
-Creating MTRRs from a C programme using ioctl()'s:
-
-/*  mtrr-add.c
-
-    Source file for mtrr-add (example programme to add an MTRRs using ioctl())
-
-    Copyright (C) 1997-1998  Richard Gooch
-
-    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.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
-    The postal address is:
-      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
-*/
-
-/*
-    This programme will use an ioctl() on /proc/mtrr to add an entry. The first
-    available mtrr is used. This is an alternative to writing /proc/mtrr.
-
-
-    Written by      Richard Gooch   17-DEC-1997
-
-    Last updated by Richard Gooch   2-MAY-1998
-
-
-*/
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <asm/mtrr.h>
-
-#define TRUE 1
-#define FALSE 0
-#define ERRSTRING strerror (errno)
-
-static char *mtrr_strings[MTRR_NUM_TYPES] =
-{
-    "uncachable",               /* 0 */
-    "write-combining",          /* 1 */
-    "?",                        /* 2 */
-    "?",                        /* 3 */
-    "write-through",            /* 4 */
-    "write-protect",            /* 5 */
-    "write-back",               /* 6 */
-};
-
-int main (int argc, char **argv)
-{
-    int fd;
-    struct mtrr_sentry sentry;
-
-    if (argc != 4)
-    {
-       fprintf (stderr, "Usage:\tmtrr-add base size type\n");
-       exit (1);
-    }
-    sentry.base = strtoul (argv[1], NULL, 0);
-    sentry.size = strtoul (argv[2], NULL, 0);
-    for (sentry.type = 0; sentry.type < MTRR_NUM_TYPES; ++sentry.type)
-    {
-       if (strcmp (argv[3], mtrr_strings[sentry.type]) == 0) break;
-    }
-    if (sentry.type >= MTRR_NUM_TYPES)
-    {
-       fprintf (stderr, "Illegal type: \"%s\"\n", argv[3]);
-       exit (2);
-    }
-    if ( ( fd = open ("/proc/mtrr", O_WRONLY, 0) ) == -1 )
-    {
-       if (errno == ENOENT)
-       {
-           fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
-                  stderr);
-           exit (3);
-       }
-       fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
-       exit (4);
-    }
-    if (ioctl (fd, MTRRIOC_ADD_ENTRY, &sentry) == -1)
-    {
-       fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
-       exit (5);
-    }
-    fprintf (stderr, "Sleeping for 5 seconds so you can see the new entry\n");
-    sleep (5);
-    close (fd);
-    fputs ("I've just closed /proc/mtrr so now the new entry should be gone\n",
-          stderr);
-}   /*  End Function main  */
-===============================================================================
diff --git a/Documentation/x86/orc-unwinder.rst b/Documentation/x86/orc-unwinder.rst
new file mode 100644 (file)
index 0000000..d811576
--- /dev/null
@@ -0,0 +1,182 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============
+ORC unwinder
+============
+
+Overview
+========
+
+The kernel CONFIG_UNWINDER_ORC option enables the ORC unwinder, which is
+similar in concept to a DWARF unwinder.  The difference is that the
+format of the ORC data is much simpler than DWARF, which in turn allows
+the ORC unwinder to be much simpler and faster.
+
+The ORC data consists of unwind tables which are generated by objtool.
+They contain out-of-band data which is used by the in-kernel ORC
+unwinder.  Objtool generates the ORC data by first doing compile-time
+stack metadata validation (CONFIG_STACK_VALIDATION).  After analyzing
+all the code paths of a .o file, it determines information about the
+stack state at each instruction address in the file and outputs that
+information to the .orc_unwind and .orc_unwind_ip sections.
+
+The per-object ORC sections are combined at link time and are sorted and
+post-processed at boot time.  The unwinder uses the resulting data to
+correlate instruction addresses with their stack states at run time.
+
+
+ORC vs frame pointers
+=====================
+
+With frame pointers enabled, GCC adds instrumentation code to every
+function in the kernel.  The kernel's .text size increases by about
+3.2%, resulting in a broad kernel-wide slowdown.  Measurements by Mel
+Gorman [1]_ have shown a slowdown of 5-10% for some workloads.
+
+In contrast, the ORC unwinder has no effect on text size or runtime
+performance, because the debuginfo is out of band.  So if you disable
+frame pointers and enable the ORC unwinder, you get a nice performance
+improvement across the board, and still have reliable stack traces.
+
+Ingo Molnar says:
+
+  "Note that it's not just a performance improvement, but also an
+  instruction cache locality improvement: 3.2% .text savings almost
+  directly transform into a similarly sized reduction in cache
+  footprint. That can transform to even higher speedups for workloads
+  whose cache locality is borderline."
+
+Another benefit of ORC compared to frame pointers is that it can
+reliably unwind across interrupts and exceptions.  Frame pointer based
+unwinds can sometimes skip the caller of the interrupted function, if it
+was a leaf function or if the interrupt hit before the frame pointer was
+saved.
+
+The main disadvantage of the ORC unwinder compared to frame pointers is
+that it needs more memory to store the ORC unwind tables: roughly 2-4MB
+depending on the kernel config.
+
+
+ORC vs DWARF
+============
+
+ORC debuginfo's advantage over DWARF itself is that it's much simpler.
+It gets rid of the complex DWARF CFI state machine and also gets rid of
+the tracking of unnecessary registers.  This allows the unwinder to be
+much simpler, meaning fewer bugs, which is especially important for
+mission critical oops code.
+
+The simpler debuginfo format also enables the unwinder to be much faster
+than DWARF, which is important for perf and lockdep.  In a basic
+performance test by Jiri Slaby [2]_, the ORC unwinder was about 20x
+faster than an out-of-tree DWARF unwinder.  (Note: That measurement was
+taken before some performance tweaks were added, which doubled
+performance, so the speedup over DWARF may be closer to 40x.)
+
+The ORC data format does have a few downsides compared to DWARF.  ORC
+unwind tables take up ~50% more RAM (+1.3MB on an x86 defconfig kernel)
+than DWARF-based eh_frame tables.
+
+Another potential downside is that, as GCC evolves, it's conceivable
+that the ORC data may end up being *too* simple to describe the state of
+the stack for certain optimizations.  But IMO this is unlikely because
+GCC saves the frame pointer for any unusual stack adjustments it does,
+so I suspect we'll really only ever need to keep track of the stack
+pointer and the frame pointer between call frames.  But even if we do
+end up having to track all the registers DWARF tracks, at least we will
+still be able to control the format, e.g. no complex state machines.
+
+
+ORC unwind table generation
+===========================
+
+The ORC data is generated by objtool.  With the existing compile-time
+stack metadata validation feature, objtool already follows all code
+paths, and so it already has all the information it needs to be able to
+generate ORC data from scratch.  So it's an easy step to go from stack
+validation to ORC data generation.
+
+It should be possible to instead generate the ORC data with a simple
+tool which converts DWARF to ORC data.  However, such a solution would
+be incomplete due to the kernel's extensive use of asm, inline asm, and
+special sections like exception tables.
+
+That could be rectified by manually annotating those special code paths
+using GNU assembler .cfi annotations in .S files, and homegrown
+annotations for inline asm in .c files.  But asm annotations were tried
+in the past and were found to be unmaintainable.  They were often
+incorrect/incomplete and made the code harder to read and keep updated.
+And based on looking at glibc code, annotating inline asm in .c files
+might be even worse.
+
+Objtool still needs a few annotations, but only in code which does
+unusual things to the stack like entry code.  And even then, far fewer
+annotations are needed than what DWARF would need, so they're much more
+maintainable than DWARF CFI annotations.
+
+So the advantages of using objtool to generate ORC data are that it
+gives more accurate debuginfo, with very few annotations.  It also
+insulates the kernel from toolchain bugs which can be very painful to
+deal with in the kernel since we often have to workaround issues in
+older versions of the toolchain for years.
+
+The downside is that the unwinder now becomes dependent on objtool's
+ability to reverse engineer GCC code flow.  If GCC optimizations become
+too complicated for objtool to follow, the ORC data generation might
+stop working or become incomplete.  (It's worth noting that livepatch
+already has such a dependency on objtool's ability to follow GCC code
+flow.)
+
+If newer versions of GCC come up with some optimizations which break
+objtool, we may need to revisit the current implementation.  Some
+possible solutions would be asking GCC to make the optimizations more
+palatable, or having objtool use DWARF as an additional input, or
+creating a GCC plugin to assist objtool with its analysis.  But for now,
+objtool follows GCC code quite well.
+
+
+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
+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
+respectively.
+
+The ORC data is split into the two arrays for performance reasons, to
+make the searchable part of the data (.orc_unwind_ip) more compact.  The
+arrays are sorted in parallel at boot time.
+
+Performance is further improved by the use of a fast lookup table which
+is created at runtime.  The fast lookup table associates a given address
+with a range of indices for the .orc_unwind table, so that only a small
+subset of the table needs to be searched.
+
+
+Etymology
+=========
+
+Orcs, fearsome creatures of medieval folklore, are the Dwarves' natural
+enemies.  Similarly, the ORC unwinder was created in opposition to the
+complexity and slowness of DWARF.
+
+"Although Orcs rarely consider multiple solutions to a problem, they do
+excel at getting things done because they are creatures of action, not
+thought." [3]_  Similarly, unlike the esoteric DWARF unwinder, the
+veracious ORC unwinder wastes no time or siloconic effort decoding
+variable-length zero-extended unsigned-integer byte-coded
+state-machine-based debug information entries.
+
+Similar to how Orcs frequently unravel the well-intentioned plans of
+their adversaries, the ORC unwinder frequently unravels stacks with
+brutal, unyielding efficiency.
+
+ORC stands for Oops Rewind Capability.
+
+
+.. [1] https://lkml.kernel.org/r/20170602104048.jkkzssljsompjdwy@suse.de
+.. [2] https://lkml.kernel.org/r/d2ca5435-6386-29b8-db87-7f227c2b713a@suse.cz
+.. [3] http://dustin.wikidot.com/half-orcs-and-orcs
diff --git a/Documentation/x86/orc-unwinder.txt b/Documentation/x86/orc-unwinder.txt
deleted file mode 100644 (file)
index cd4b29b..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-ORC unwinder
-============
-
-Overview
---------
-
-The kernel CONFIG_UNWINDER_ORC option enables the ORC unwinder, which is
-similar in concept to a DWARF unwinder.  The difference is that the
-format of the ORC data is much simpler than DWARF, which in turn allows
-the ORC unwinder to be much simpler and faster.
-
-The ORC data consists of unwind tables which are generated by objtool.
-They contain out-of-band data which is used by the in-kernel ORC
-unwinder.  Objtool generates the ORC data by first doing compile-time
-stack metadata validation (CONFIG_STACK_VALIDATION).  After analyzing
-all the code paths of a .o file, it determines information about the
-stack state at each instruction address in the file and outputs that
-information to the .orc_unwind and .orc_unwind_ip sections.
-
-The per-object ORC sections are combined at link time and are sorted and
-post-processed at boot time.  The unwinder uses the resulting data to
-correlate instruction addresses with their stack states at run time.
-
-
-ORC vs frame pointers
----------------------
-
-With frame pointers enabled, GCC adds instrumentation code to every
-function in the kernel.  The kernel's .text size increases by about
-3.2%, resulting in a broad kernel-wide slowdown.  Measurements by Mel
-Gorman [1] have shown a slowdown of 5-10% for some workloads.
-
-In contrast, the ORC unwinder has no effect on text size or runtime
-performance, because the debuginfo is out of band.  So if you disable
-frame pointers and enable the ORC unwinder, you get a nice performance
-improvement across the board, and still have reliable stack traces.
-
-Ingo Molnar says:
-
-  "Note that it's not just a performance improvement, but also an
-  instruction cache locality improvement: 3.2% .text savings almost
-  directly transform into a similarly sized reduction in cache
-  footprint. That can transform to even higher speedups for workloads
-  whose cache locality is borderline."
-
-Another benefit of ORC compared to frame pointers is that it can
-reliably unwind across interrupts and exceptions.  Frame pointer based
-unwinds can sometimes skip the caller of the interrupted function, if it
-was a leaf function or if the interrupt hit before the frame pointer was
-saved.
-
-The main disadvantage of the ORC unwinder compared to frame pointers is
-that it needs more memory to store the ORC unwind tables: roughly 2-4MB
-depending on the kernel config.
-
-
-ORC vs DWARF
-------------
-
-ORC debuginfo's advantage over DWARF itself is that it's much simpler.
-It gets rid of the complex DWARF CFI state machine and also gets rid of
-the tracking of unnecessary registers.  This allows the unwinder to be
-much simpler, meaning fewer bugs, which is especially important for
-mission critical oops code.
-
-The simpler debuginfo format also enables the unwinder to be much faster
-than DWARF, which is important for perf and lockdep.  In a basic
-performance test by Jiri Slaby [2], the ORC unwinder was about 20x
-faster than an out-of-tree DWARF unwinder.  (Note: That measurement was
-taken before some performance tweaks were added, which doubled
-performance, so the speedup over DWARF may be closer to 40x.)
-
-The ORC data format does have a few downsides compared to DWARF.  ORC
-unwind tables take up ~50% more RAM (+1.3MB on an x86 defconfig kernel)
-than DWARF-based eh_frame tables.
-
-Another potential downside is that, as GCC evolves, it's conceivable
-that the ORC data may end up being *too* simple to describe the state of
-the stack for certain optimizations.  But IMO this is unlikely because
-GCC saves the frame pointer for any unusual stack adjustments it does,
-so I suspect we'll really only ever need to keep track of the stack
-pointer and the frame pointer between call frames.  But even if we do
-end up having to track all the registers DWARF tracks, at least we will
-still be able to control the format, e.g. no complex state machines.
-
-
-ORC unwind table generation
----------------------------
-
-The ORC data is generated by objtool.  With the existing compile-time
-stack metadata validation feature, objtool already follows all code
-paths, and so it already has all the information it needs to be able to
-generate ORC data from scratch.  So it's an easy step to go from stack
-validation to ORC data generation.
-
-It should be possible to instead generate the ORC data with a simple
-tool which converts DWARF to ORC data.  However, such a solution would
-be incomplete due to the kernel's extensive use of asm, inline asm, and
-special sections like exception tables.
-
-That could be rectified by manually annotating those special code paths
-using GNU assembler .cfi annotations in .S files, and homegrown
-annotations for inline asm in .c files.  But asm annotations were tried
-in the past and were found to be unmaintainable.  They were often
-incorrect/incomplete and made the code harder to read and keep updated.
-And based on looking at glibc code, annotating inline asm in .c files
-might be even worse.
-
-Objtool still needs a few annotations, but only in code which does
-unusual things to the stack like entry code.  And even then, far fewer
-annotations are needed than what DWARF would need, so they're much more
-maintainable than DWARF CFI annotations.
-
-So the advantages of using objtool to generate ORC data are that it
-gives more accurate debuginfo, with very few annotations.  It also
-insulates the kernel from toolchain bugs which can be very painful to
-deal with in the kernel since we often have to workaround issues in
-older versions of the toolchain for years.
-
-The downside is that the unwinder now becomes dependent on objtool's
-ability to reverse engineer GCC code flow.  If GCC optimizations become
-too complicated for objtool to follow, the ORC data generation might
-stop working or become incomplete.  (It's worth noting that livepatch
-already has such a dependency on objtool's ability to follow GCC code
-flow.)
-
-If newer versions of GCC come up with some optimizations which break
-objtool, we may need to revisit the current implementation.  Some
-possible solutions would be asking GCC to make the optimizations more
-palatable, or having objtool use DWARF as an additional input, or
-creating a GCC plugin to assist objtool with its analysis.  But for now,
-objtool follows GCC code quite well.
-
-
-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
-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
-respectively.
-
-The ORC data is split into the two arrays for performance reasons, to
-make the searchable part of the data (.orc_unwind_ip) more compact.  The
-arrays are sorted in parallel at boot time.
-
-Performance is further improved by the use of a fast lookup table which
-is created at runtime.  The fast lookup table associates a given address
-with a range of indices for the .orc_unwind table, so that only a small
-subset of the table needs to be searched.
-
-
-Etymology
----------
-
-Orcs, fearsome creatures of medieval folklore, are the Dwarves' natural
-enemies.  Similarly, the ORC unwinder was created in opposition to the
-complexity and slowness of DWARF.
-
-"Although Orcs rarely consider multiple solutions to a problem, they do
-excel at getting things done because they are creatures of action, not
-thought." [3]  Similarly, unlike the esoteric DWARF unwinder, the
-veracious ORC unwinder wastes no time or siloconic effort decoding
-variable-length zero-extended unsigned-integer byte-coded
-state-machine-based debug information entries.
-
-Similar to how Orcs frequently unravel the well-intentioned plans of
-their adversaries, the ORC unwinder frequently unravels stacks with
-brutal, unyielding efficiency.
-
-ORC stands for Oops Rewind Capability.
-
-
-[1] https://lkml.kernel.org/r/20170602104048.jkkzssljsompjdwy@suse.de
-[2] https://lkml.kernel.org/r/d2ca5435-6386-29b8-db87-7f227c2b713a@suse.cz
-[3] http://dustin.wikidot.com/half-orcs-and-orcs
diff --git a/Documentation/x86/pat.rst b/Documentation/x86/pat.rst
new file mode 100644 (file)
index 0000000..9a298fd
--- /dev/null
@@ -0,0 +1,242 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==========================
+PAT (Page Attribute Table)
+==========================
+
+x86 Page Attribute Table (PAT) allows for setting the memory attribute at the
+page level granularity. PAT is complementary to the MTRR settings which allows
+for setting of memory types over physical address ranges. However, PAT is
+more flexible than MTRR due to its capability to set attributes at page level
+and also due to the fact that there are no hardware limitations on number of
+such attribute settings allowed. Added flexibility comes with guidelines for
+not having memory type aliasing for the same physical memory with multiple
+virtual addresses.
+
+PAT allows for different types of memory attributes. The most commonly used
+ones that will be supported at this time are:
+
+===  ==============
+WB   Write-back
+UC   Uncached
+WC   Write-combined
+WT   Write-through
+UC-  Uncached Minus
+===  ==============
+
+
+PAT APIs
+========
+
+There are many different APIs in the kernel that allows setting of memory
+attributes at the page level. In order to avoid aliasing, these interfaces
+should be used thoughtfully. Below is a table of interfaces available,
+their intended usage and their memory attribute relationships. Internally,
+these APIs use a reserve_memtype()/free_memtype() interface on the physical
+address range to avoid any aliasing.
+
++------------------------+----------+--------------+------------------+
+| API                    |    RAM   |  ACPI,...    |  Reserved/Holes  |
++------------------------+----------+--------------+------------------+
+| ioremap                |    --    |    UC-       |       UC-        |
++------------------------+----------+--------------+------------------+
+| ioremap_cache          |    --    |    WB        |       WB         |
++------------------------+----------+--------------+------------------+
+| ioremap_uc             |    --    |    UC        |       UC         |
++------------------------+----------+--------------+------------------+
+| ioremap_nocache        |    --    |    UC-       |       UC-        |
++------------------------+----------+--------------+------------------+
+| ioremap_wc             |    --    |    --        |       WC         |
++------------------------+----------+--------------+------------------+
+| ioremap_wt             |    --    |    --        |       WT         |
++------------------------+----------+--------------+------------------+
+| set_memory_uc,         |    UC-   |    --        |       --         |
+| set_memory_wb          |          |              |                  |
++------------------------+----------+--------------+------------------+
+| set_memory_wc,         |    WC    |    --        |       --         |
+| set_memory_wb          |          |              |                  |
++------------------------+----------+--------------+------------------+
+| set_memory_wt,         |    WT    |    --        |       --         |
+| set_memory_wb          |          |              |                  |
++------------------------+----------+--------------+------------------+
+| pci sysfs resource     |    --    |    --        |       UC-        |
++------------------------+----------+--------------+------------------+
+| pci sysfs resource_wc  |    --    |    --        |       WC         |
+| is IORESOURCE_PREFETCH |          |              |                  |
++------------------------+----------+--------------+------------------+
+| pci proc               |    --    |    --        |       UC-        |
+| !PCIIOC_WRITE_COMBINE  |          |              |                  |
++------------------------+----------+--------------+------------------+
+| pci proc               |    --    |    --        |       WC         |
+| PCIIOC_WRITE_COMBINE   |          |              |                  |
++------------------------+----------+--------------+------------------+
+| /dev/mem               |    --    |   WB/WC/UC-  |    WB/WC/UC-     |
+| read-write             |          |              |                  |
++------------------------+----------+--------------+------------------+
+| /dev/mem               |    --    |    UC-       |       UC-        |
+| mmap SYNC flag         |          |              |                  |
++------------------------+----------+--------------+------------------+
+| /dev/mem               |    --    |   WB/WC/UC-  |  WB/WC/UC-       |
+| mmap !SYNC flag        |          |              |                  |
+| and                    |          |(from existing|  (from existing  |
+| any alias to this area |          |alias)        |  alias)          |
++------------------------+----------+--------------+------------------+
+| /dev/mem               |    --    |    WB        |       WB         |
+| mmap !SYNC flag        |          |              |                  |
+| no alias to this area  |          |              |                  |
+| and                    |          |              |                  |
+| MTRR says WB           |          |              |                  |
++------------------------+----------+--------------+------------------+
+| /dev/mem               |    --    |    --        |       UC-        |
+| mmap !SYNC flag        |          |              |                  |
+| no alias to this area  |          |              |                  |
+| and                    |          |              |                  |
+| MTRR says !WB          |          |              |                  |
++------------------------+----------+--------------+------------------+
+
+
+Advanced APIs for drivers
+=========================
+
+A. Exporting pages to users with remap_pfn_range, io_remap_pfn_range,
+vmf_insert_pfn.
+
+Drivers wanting to export some pages to userspace do it by using mmap
+interface and a combination of:
+
+  1) pgprot_noncached()
+  2) io_remap_pfn_range() or remap_pfn_range() or vmf_insert_pfn()
+
+With PAT support, a new API pgprot_writecombine is being added. So, drivers can
+continue to use the above sequence, with either pgprot_noncached() or
+pgprot_writecombine() in step 1, followed by step 2.
+
+In addition, step 2 internally tracks the region as UC or WC in memtype
+list in order to ensure no conflicting mapping.
+
+Note that this set of APIs only works with IO (non RAM) regions. If driver
+wants to export a RAM region, it has to do set_memory_uc() or set_memory_wc()
+as step 0 above and also track the usage of those pages and use set_memory_wb()
+before the page is freed to free pool.
+
+MTRR effects on PAT / non-PAT systems
+=====================================
+
+The following table provides the effects of using write-combining MTRRs when
+using ioremap*() calls on x86 for both non-PAT and PAT systems. Ideally
+mtrr_add() usage will be phased out in favor of arch_phys_wc_add() which will
+be a no-op on PAT enabled systems. The region over which a arch_phys_wc_add()
+is made, should already have been ioremapped with WC attributes or PAT entries,
+this can be done by using ioremap_wc() / set_memory_wc().  Devices which
+combine areas of IO memory desired to remain uncacheable with areas where
+write-combining is desirable should consider use of ioremap_uc() followed by
+set_memory_wc() to white-list effective write-combined areas.  Such use is
+nevertheless discouraged as the effective memory type is considered
+implementation defined, yet this strategy can be used as last resort on devices
+with size-constrained regions where otherwise MTRR write-combining would
+otherwise not be effective.
+::
+
+  ====  =======  ===  =========================  =====================
+  MTRR  Non-PAT  PAT  Linux ioremap value        Effective memory type
+  ====  =======  ===  =========================  =====================
+        PAT                                        Non-PAT |  PAT
+        |PCD                                               |
+        ||PWT                                              |
+        |||                                                |
+  WC    000      WB   _PAGE_CACHE_MODE_WB             WC   |   WC
+  WC    001      WC   _PAGE_CACHE_MODE_WC             WC*  |   WC
+  WC    010      UC-  _PAGE_CACHE_MODE_UC_MINUS       WC*  |   UC
+  WC    011      UC   _PAGE_CACHE_MODE_UC             UC   |   UC
+  ====  =======  ===  =========================  =====================
+
+  (*) denotes implementation defined and is discouraged
+
+.. note:: -- in the above table mean "Not suggested usage for the API". Some
+  of the --'s are strictly enforced by the kernel. Some others are not really
+  enforced today, but may be enforced in future.
+
+For ioremap and pci access through /sys or /proc - The actual type returned
+can be more restrictive, in case of any existing aliasing for that address.
+For example: If there is an existing uncached mapping, a new ioremap_wc can
+return uncached mapping in place of write-combine requested.
+
+set_memory_[uc|wc|wt] and set_memory_wb should be used in pairs, where driver
+will first make a region uc, wc or wt and switch it back to wb after use.
+
+Over time writes to /proc/mtrr will be deprecated in favor of using PAT based
+interfaces. Users writing to /proc/mtrr are suggested to use above interfaces.
+
+Drivers should use ioremap_[uc|wc] to access PCI BARs with [uc|wc] access
+types.
+
+Drivers should use set_memory_[uc|wc|wt] to set access type for RAM ranges.
+
+
+PAT debugging
+=============
+
+With CONFIG_DEBUG_FS enabled, PAT memtype list can be examined by::
+
+  # mount -t debugfs debugfs /sys/kernel/debug
+  # cat /sys/kernel/debug/x86/pat_memtype_list
+  PAT memtype list:
+  uncached-minus @ 0x7fadf000-0x7fae0000
+  uncached-minus @ 0x7fb19000-0x7fb1a000
+  uncached-minus @ 0x7fb1a000-0x7fb1b000
+  uncached-minus @ 0x7fb1b000-0x7fb1c000
+  uncached-minus @ 0x7fb1c000-0x7fb1d000
+  uncached-minus @ 0x7fb1d000-0x7fb1e000
+  uncached-minus @ 0x7fb1e000-0x7fb25000
+  uncached-minus @ 0x7fb25000-0x7fb26000
+  uncached-minus @ 0x7fb26000-0x7fb27000
+  uncached-minus @ 0x7fb27000-0x7fb28000
+  uncached-minus @ 0x7fb28000-0x7fb2e000
+  uncached-minus @ 0x7fb2e000-0x7fb2f000
+  uncached-minus @ 0x7fb2f000-0x7fb30000
+  uncached-minus @ 0x7fb31000-0x7fb32000
+  uncached-minus @ 0x80000000-0x90000000
+
+This list shows physical address ranges and various PAT settings used to
+access those physical address ranges.
+
+Another, more verbose way of getting PAT related debug messages is with
+"debugpat" boot parameter. With this parameter, various debug messages are
+printed to dmesg log.
+
+PAT Initialization
+==================
+
+The following table describes how PAT is initialized under various
+configurations. The PAT MSR must be updated by Linux in order to support WC
+and WT attributes. Otherwise, the PAT MSR has the value programmed in it
+by the firmware. Note, Xen enables WC attribute in the PAT MSR for guests.
+
+ ==== ===== ==========================  =========  =======
+ MTRR PAT   Call Sequence               PAT State  PAT MSR
+ ==== ===== ==========================  =========  =======
+ E    E     MTRR -> PAT init            Enabled    OS
+ E    D     MTRR -> PAT init            Disabled    -
+ D    E     MTRR -> PAT disable         Disabled   BIOS
+ D    D     MTRR -> PAT disable         Disabled    -
+ -    np/E  PAT  -> PAT disable         Disabled   BIOS
+ -    np/D  PAT  -> PAT disable         Disabled    -
+ E    !P/E  MTRR -> PAT init            Disabled   BIOS
+ D    !P/E  MTRR -> PAT disable         Disabled   BIOS
+ !M   !P/E  MTRR stub -> PAT disable    Disabled   BIOS
+ ==== ===== ==========================  =========  =======
+
+  Legend
+
+ ========= =======================================
+ E         Feature enabled in CPU
+ D        Feature disabled/unsupported in CPU
+ np       "nopat" boot option specified
+ !P       CONFIG_X86_PAT option unset
+ !M       CONFIG_MTRR option unset
+ Enabled   PAT state set to enabled
+ Disabled  PAT state set to disabled
+ OS        PAT initializes PAT MSR with OS setting
+ BIOS      PAT keeps PAT MSR with BIOS setting
+ ========= =======================================
+
diff --git a/Documentation/x86/pat.txt b/Documentation/x86/pat.txt
deleted file mode 100644 (file)
index 481d8d8..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-
-PAT (Page Attribute Table)
-
-x86 Page Attribute Table (PAT) allows for setting the memory attribute at the
-page level granularity. PAT is complementary to the MTRR settings which allows
-for setting of memory types over physical address ranges. However, PAT is
-more flexible than MTRR due to its capability to set attributes at page level
-and also due to the fact that there are no hardware limitations on number of
-such attribute settings allowed. Added flexibility comes with guidelines for
-not having memory type aliasing for the same physical memory with multiple
-virtual addresses.
-
-PAT allows for different types of memory attributes. The most commonly used
-ones that will be supported at this time are Write-back, Uncached,
-Write-combined, Write-through and Uncached Minus.
-
-
-PAT APIs
---------
-
-There are many different APIs in the kernel that allows setting of memory
-attributes at the page level. In order to avoid aliasing, these interfaces
-should be used thoughtfully. Below is a table of interfaces available,
-their intended usage and their memory attribute relationships. Internally,
-these APIs use a reserve_memtype()/free_memtype() interface on the physical
-address range to avoid any aliasing.
-
-
--------------------------------------------------------------------
-API                    |    RAM   |  ACPI,...  |  Reserved/Holes  |
------------------------|----------|------------|------------------|
-                       |          |            |                  |
-ioremap                |    --    |    UC-     |       UC-        |
-                       |          |            |                  |
-ioremap_cache          |    --    |    WB      |       WB         |
-                       |          |            |                  |
-ioremap_uc             |    --    |    UC      |       UC         |
-                       |          |            |                  |
-ioremap_nocache        |    --    |    UC-     |       UC-        |
-                       |          |            |                  |
-ioremap_wc             |    --    |    --      |       WC         |
-                       |          |            |                  |
-ioremap_wt             |    --    |    --      |       WT         |
-                       |          |            |                  |
-set_memory_uc          |    UC-   |    --      |       --         |
- set_memory_wb         |          |            |                  |
-                       |          |            |                  |
-set_memory_wc          |    WC    |    --      |       --         |
- set_memory_wb         |          |            |                  |
-                       |          |            |                  |
-set_memory_wt          |    WT    |    --      |       --         |
- set_memory_wb         |          |            |                  |
-                       |          |            |                  |
-pci sysfs resource     |    --    |    --      |       UC-        |
-                       |          |            |                  |
-pci sysfs resource_wc  |    --    |    --      |       WC         |
- is IORESOURCE_PREFETCH|          |            |                  |
-                       |          |            |                  |
-pci proc               |    --    |    --      |       UC-        |
- !PCIIOC_WRITE_COMBINE |          |            |                  |
-                       |          |            |                  |
-pci proc               |    --    |    --      |       WC         |
- PCIIOC_WRITE_COMBINE  |          |            |                  |
-                       |          |            |                  |
-/dev/mem               |    --    |  WB/WC/UC- |    WB/WC/UC-     |
- read-write            |          |            |                  |
-                       |          |            |                  |
-/dev/mem               |    --    |    UC-     |       UC-        |
- mmap SYNC flag        |          |            |                  |
-                       |          |            |                  |
-/dev/mem               |    --    |  WB/WC/UC- |    WB/WC/UC-     |
- mmap !SYNC flag       |          |(from exist-|  (from exist-    |
- and                   |          |  ing alias)|    ing alias)    |
- any alias to this area|          |            |                  |
-                       |          |            |                  |
-/dev/mem               |    --    |    WB      |       WB         |
- mmap !SYNC flag       |          |            |                  |
- no alias to this area |          |            |                  |
- and                   |          |            |                  |
- MTRR says WB          |          |            |                  |
-                       |          |            |                  |
-/dev/mem               |    --    |    --      |       UC-        |
- mmap !SYNC flag       |          |            |                  |
- no alias to this area |          |            |                  |
- and                   |          |            |                  |
- MTRR says !WB         |          |            |                  |
-                       |          |            |                  |
--------------------------------------------------------------------
-
-Advanced APIs for drivers
--------------------------
-A. Exporting pages to users with remap_pfn_range, io_remap_pfn_range,
-vmf_insert_pfn
-
-Drivers wanting to export some pages to userspace do it by using mmap
-interface and a combination of
-1) pgprot_noncached()
-2) io_remap_pfn_range() or remap_pfn_range() or vmf_insert_pfn()
-
-With PAT support, a new API pgprot_writecombine is being added. So, drivers can
-continue to use the above sequence, with either pgprot_noncached() or
-pgprot_writecombine() in step 1, followed by step 2.
-
-In addition, step 2 internally tracks the region as UC or WC in memtype
-list in order to ensure no conflicting mapping.
-
-Note that this set of APIs only works with IO (non RAM) regions. If driver
-wants to export a RAM region, it has to do set_memory_uc() or set_memory_wc()
-as step 0 above and also track the usage of those pages and use set_memory_wb()
-before the page is freed to free pool.
-
-MTRR effects on PAT / non-PAT systems
--------------------------------------
-
-The following table provides the effects of using write-combining MTRRs when
-using ioremap*() calls on x86 for both non-PAT and PAT systems. Ideally
-mtrr_add() usage will be phased out in favor of arch_phys_wc_add() which will
-be a no-op on PAT enabled systems. The region over which a arch_phys_wc_add()
-is made, should already have been ioremapped with WC attributes or PAT entries,
-this can be done by using ioremap_wc() / set_memory_wc().  Devices which
-combine areas of IO memory desired to remain uncacheable with areas where
-write-combining is desirable should consider use of ioremap_uc() followed by
-set_memory_wc() to white-list effective write-combined areas.  Such use is
-nevertheless discouraged as the effective memory type is considered
-implementation defined, yet this strategy can be used as last resort on devices
-with size-constrained regions where otherwise MTRR write-combining would
-otherwise not be effective.
-
-----------------------------------------------------------------------
-MTRR Non-PAT   PAT    Linux ioremap value        Effective memory type
-----------------------------------------------------------------------
-                                                  Non-PAT |  PAT
-     PAT
-     |PCD
-     ||PWT
-     |||
-WC   000      WB      _PAGE_CACHE_MODE_WB            WC   |   WC
-WC   001      WC      _PAGE_CACHE_MODE_WC            WC*  |   WC
-WC   010      UC-     _PAGE_CACHE_MODE_UC_MINUS      WC*  |   UC
-WC   011      UC      _PAGE_CACHE_MODE_UC            UC   |   UC
-----------------------------------------------------------------------
-
-(*) denotes implementation defined and is discouraged
-
-Notes:
-
--- in the above table mean "Not suggested usage for the API". Some of the --'s
-are strictly enforced by the kernel. Some others are not really enforced
-today, but may be enforced in future.
-
-For ioremap and pci access through /sys or /proc - The actual type returned
-can be more restrictive, in case of any existing aliasing for that address.
-For example: If there is an existing uncached mapping, a new ioremap_wc can
-return uncached mapping in place of write-combine requested.
-
-set_memory_[uc|wc|wt] and set_memory_wb should be used in pairs, where driver
-will first make a region uc, wc or wt and switch it back to wb after use.
-
-Over time writes to /proc/mtrr will be deprecated in favor of using PAT based
-interfaces. Users writing to /proc/mtrr are suggested to use above interfaces.
-
-Drivers should use ioremap_[uc|wc] to access PCI BARs with [uc|wc] access
-types.
-
-Drivers should use set_memory_[uc|wc|wt] to set access type for RAM ranges.
-
-
-PAT debugging
--------------
-
-With CONFIG_DEBUG_FS enabled, PAT memtype list can be examined by
-
-# mount -t debugfs debugfs /sys/kernel/debug
-# cat /sys/kernel/debug/x86/pat_memtype_list
-PAT memtype list:
-uncached-minus @ 0x7fadf000-0x7fae0000
-uncached-minus @ 0x7fb19000-0x7fb1a000
-uncached-minus @ 0x7fb1a000-0x7fb1b000
-uncached-minus @ 0x7fb1b000-0x7fb1c000
-uncached-minus @ 0x7fb1c000-0x7fb1d000
-uncached-minus @ 0x7fb1d000-0x7fb1e000
-uncached-minus @ 0x7fb1e000-0x7fb25000
-uncached-minus @ 0x7fb25000-0x7fb26000
-uncached-minus @ 0x7fb26000-0x7fb27000
-uncached-minus @ 0x7fb27000-0x7fb28000
-uncached-minus @ 0x7fb28000-0x7fb2e000
-uncached-minus @ 0x7fb2e000-0x7fb2f000
-uncached-minus @ 0x7fb2f000-0x7fb30000
-uncached-minus @ 0x7fb31000-0x7fb32000
-uncached-minus @ 0x80000000-0x90000000
-
-This list shows physical address ranges and various PAT settings used to
-access those physical address ranges.
-
-Another, more verbose way of getting PAT related debug messages is with
-"debugpat" boot parameter. With this parameter, various debug messages are
-printed to dmesg log.
-
-PAT Initialization
-------------------
-
-The following table describes how PAT is initialized under various
-configurations. The PAT MSR must be updated by Linux in order to support WC
-and WT attributes. Otherwise, the PAT MSR has the value programmed in it
-by the firmware. Note, Xen enables WC attribute in the PAT MSR for guests.
-
- MTRR PAT   Call Sequence               PAT State  PAT MSR
- =========================================================
- E    E     MTRR -> PAT init            Enabled    OS
- E    D     MTRR -> PAT init            Disabled    -
- D    E     MTRR -> PAT disable         Disabled   BIOS
- D    D     MTRR -> PAT disable         Disabled    -
- -    np/E  PAT  -> PAT disable         Disabled   BIOS
- -    np/D  PAT  -> PAT disable         Disabled    -
- E    !P/E  MTRR -> PAT init            Disabled   BIOS
- D    !P/E  MTRR -> PAT disable         Disabled   BIOS
- !M   !P/E  MTRR stub -> PAT disable    Disabled   BIOS
-
- Legend
- ------------------------------------------------
- E         Feature enabled in CPU
- D        Feature disabled/unsupported in CPU
- np       "nopat" boot option specified
- !P       CONFIG_X86_PAT option unset
- !M       CONFIG_MTRR option unset
- Enabled   PAT state set to enabled
- Disabled  PAT state set to disabled
- OS        PAT initializes PAT MSR with OS setting
- BIOS      PAT keeps PAT MSR with BIOS setting
-
diff --git a/Documentation/x86/protection-keys.rst b/Documentation/x86/protection-keys.rst
new file mode 100644 (file)
index 0000000..49d9833
--- /dev/null
@@ -0,0 +1,99 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================
+Memory Protection Keys
+======================
+
+Memory Protection Keys for Userspace (PKU aka PKEYs) is a feature
+which is found on Intel's Skylake "Scalable Processor" Server CPUs.
+It will be avalable in future non-server parts.
+
+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
+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.
+
+Syscalls
+========
+
+There are 3 system calls which directly interact with pkeys::
+
+       int pkey_alloc(unsigned long flags, unsigned long init_access_rights)
+       int pkey_free(int pkey);
+       int pkey_mprotect(unsigned long start, size_t len,
+                         unsigned long prot, int pkey);
+
+Before a pkey can be used, it must first be allocated with
+pkey_alloc().  An application calls the WRPKRU instruction
+directly in order to change access permissions to memory covered
+with a key.  In this example WRPKRU is wrapped by a C function
+called pkey_set().
+::
+
+       int real_prot = PROT_READ|PROT_WRITE;
+       pkey = pkey_alloc(0, PKEY_DISABLE_WRITE);
+       ptr = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+       ret = pkey_mprotect(ptr, PAGE_SIZE, real_prot, pkey);
+       ... application runs here
+
+Now, if the application needs to update the data at 'ptr', it can
+gain access, do the update, then remove its write access::
+
+       pkey_set(pkey, 0); // clear PKEY_DISABLE_WRITE
+       *ptr = foo; // assign something
+       pkey_set(pkey, PKEY_DISABLE_WRITE); // set PKEY_DISABLE_WRITE again
+
+Now when it frees the memory, it will also free the pkey since it
+is no longer in use::
+
+       munmap(ptr, PAGE_SIZE);
+       pkey_free(pkey);
+
+.. note:: pkey_set() is a wrapper for the RDPKRU and WRPKRU instructions.
+          An example implementation can be found in
+          tools/testing/selftests/x86/protection_keys.c.
+
+Behavior
+========
+
+The kernel attempts to make protection keys consistent with the
+behavior of a plain mprotect().  For instance if you do this::
+
+       mprotect(ptr, size, PROT_NONE);
+       something(ptr);
+
+you can expect the same effects with protection keys when doing this::
+
+       pkey = pkey_alloc(0, PKEY_DISABLE_WRITE | PKEY_DISABLE_READ);
+       pkey_mprotect(ptr, size, PROT_READ|PROT_WRITE, pkey);
+       something(ptr);
+
+That should be true whether something() is a direct access to 'ptr'
+like::
+
+       *ptr = foo;
+
+or when the kernel does the access on the application's behalf like
+with a read()::
+
+       read(fd, ptr, 1);
+
+The kernel will send a SIGSEGV in both cases, but si_code will be set
+to SEGV_PKERR when violating protection keys versus SEGV_ACCERR when
+the plain mprotect() permissions are violated.
diff --git a/Documentation/x86/protection-keys.txt b/Documentation/x86/protection-keys.txt
deleted file mode 100644 (file)
index ecb0d2d..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-Memory Protection Keys for Userspace (PKU aka PKEYs) is a feature
-which is found on Intel's Skylake "Scalable Processor" Server CPUs.
-It will be avalable in future non-server parts.
-
-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
-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.
-
-=========================== Syscalls ===========================
-
-There are 3 system calls which directly interact with pkeys:
-
-       int pkey_alloc(unsigned long flags, unsigned long init_access_rights)
-       int pkey_free(int pkey);
-       int pkey_mprotect(unsigned long start, size_t len,
-                         unsigned long prot, int pkey);
-
-Before a pkey can be used, it must first be allocated with
-pkey_alloc().  An application calls the WRPKRU instruction
-directly in order to change access permissions to memory covered
-with a key.  In this example WRPKRU is wrapped by a C function
-called pkey_set().
-
-       int real_prot = PROT_READ|PROT_WRITE;
-       pkey = pkey_alloc(0, PKEY_DISABLE_WRITE);
-       ptr = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-       ret = pkey_mprotect(ptr, PAGE_SIZE, real_prot, pkey);
-       ... application runs here
-
-Now, if the application needs to update the data at 'ptr', it can
-gain access, do the update, then remove its write access:
-
-       pkey_set(pkey, 0); // clear PKEY_DISABLE_WRITE
-       *ptr = foo; // assign something
-       pkey_set(pkey, PKEY_DISABLE_WRITE); // set PKEY_DISABLE_WRITE again
-
-Now when it frees the memory, it will also free the pkey since it
-is no longer in use:
-
-       munmap(ptr, PAGE_SIZE);
-       pkey_free(pkey);
-
-(Note: pkey_set() is a wrapper for the RDPKRU and WRPKRU instructions.
- An example implementation can be found in
- tools/testing/selftests/x86/protection_keys.c)
-
-=========================== Behavior ===========================
-
-The kernel attempts to make protection keys consistent with the
-behavior of a plain mprotect().  For instance if you do this:
-
-       mprotect(ptr, size, PROT_NONE);
-       something(ptr);
-
-you can expect the same effects with protection keys when doing this:
-
-       pkey = pkey_alloc(0, PKEY_DISABLE_WRITE | PKEY_DISABLE_READ);
-       pkey_mprotect(ptr, size, PROT_READ|PROT_WRITE, pkey);
-       something(ptr);
-
-That should be true whether something() is a direct access to 'ptr'
-like:
-
-       *ptr = foo;
-
-or when the kernel does the access on the application's behalf like
-with a read():
-
-       read(fd, ptr, 1);
-
-The kernel will send a SIGSEGV in both cases, but si_code will be set
-to SEGV_PKERR when violating protection keys versus SEGV_ACCERR when
-the plain mprotect() permissions are violated.
diff --git a/Documentation/x86/pti.rst b/Documentation/x86/pti.rst
new file mode 100644 (file)
index 0000000..4b858a9
--- /dev/null
@@ -0,0 +1,195 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==========================
+Page Table Isolation (PTI)
+==========================
+
+Overview
+========
+
+Page Table Isolation (pti, previously known as KAISER [1]_) is a
+countermeasure against attacks on the shared user/kernel address
+space such as the "Meltdown" approach [2]_.
+
+To mitigate this class of attacks, we create an independent set of
+page tables for use only when running userspace applications.  When
+the kernel is entered via syscalls, interrupts or exceptions, the
+page tables are switched to the full "kernel" copy.  When the system
+switches back to user mode, the user copy is used again.
+
+The userspace page tables contain only a minimal amount of kernel
+data: only what is needed to enter/exit the kernel such as the
+entry/exit functions themselves and the interrupt descriptor table
+(IDT).  There are a few strictly unnecessary things that get mapped
+such as the first C function when entering an interrupt (see
+comments in pti.c).
+
+This approach helps to ensure that side-channel attacks leveraging
+the paging structures do not function when PTI is enabled.  It can be
+enabled by setting CONFIG_PAGE_TABLE_ISOLATION=y at compile time.
+Once enabled at compile-time, it can be disabled at boot with the
+'nopti' or 'pti=' kernel parameters (see kernel-parameters.txt).
+
+Page Table Management
+=====================
+
+When PTI is enabled, the kernel manages two sets of page tables.
+The first set is very similar to the single set which is present in
+kernels without PTI.  This includes a complete mapping of userspace
+that the kernel can use for things like copy_to_user().
+
+Although _complete_, the user portion of the kernel page tables is
+crippled by setting the NX bit in the top level.  This ensures
+that any missed kernel->user CR3 switch will immediately crash
+userspace upon executing its first instruction.
+
+The userspace page tables map only the kernel data needed to enter
+and exit the kernel.  This data is entirely contained in the 'struct
+cpu_entry_area' structure which is placed in the fixmap which gives
+each CPU's copy of the area a compile-time-fixed virtual address.
+
+For new userspace mappings, the kernel makes the entries in its
+page tables like normal.  The only difference is when the kernel
+makes entries in the top (PGD) level.  In addition to setting the
+entry in the main kernel PGD, a copy of the entry is made in the
+userspace page tables' PGD.
+
+This sharing at the PGD level also inherently shares all the lower
+layers of the page tables.  This leaves a single, shared set of
+userspace page tables to manage.  One PTE to lock, one set of
+accessed bits, dirty bits, etc...
+
+Overhead
+========
+
+Protection against side-channel attacks is important.  But,
+this protection comes at a cost:
+
+1. Increased Memory Use
+
+  a. Each process now needs an order-1 PGD instead of order-0.
+     (Consumes an additional 4k per process).
+  b. The 'cpu_entry_area' structure must be 2MB in size and 2MB
+     aligned so that it can be mapped by setting a single PMD
+     entry.  This consumes nearly 2MB of RAM once the kernel
+     is decompressed, but no space in the kernel image itself.
+
+2. Runtime Cost
+
+  a. CR3 manipulation to switch between the page table copies
+     must be done at interrupt, syscall, and exception entry
+     and exit (it can be skipped when the kernel is interrupted,
+     though.)  Moves to CR3 are on the order of a hundred
+     cycles, and are required at every entry and exit.
+  b. A "trampoline" must be used for SYSCALL entry.  This
+     trampoline depends on a smaller set of resources than the
+     non-PTI SYSCALL entry code, so requires mapping fewer
+     things into the userspace page tables.  The downside is
+     that stacks must be switched at entry time.
+  c. Global pages are disabled for all kernel structures not
+     mapped into both kernel and userspace page tables.  This
+     feature of the MMU allows different processes to share TLB
+     entries mapping the kernel.  Losing the feature means more
+     TLB misses after a context switch.  The actual loss of
+     performance is very small, however, never exceeding 1%.
+  d. Process Context IDentifiers (PCID) is a CPU feature that
+     allows us to skip flushing the entire TLB when switching page
+     tables by setting a special bit in CR3 when the page tables
+     are changed.  This makes switching the page tables (at context
+     switch, or kernel entry/exit) cheaper.  But, on systems with
+     PCID support, the context switch code must flush both the user
+     and kernel entries out of the TLB.  The user PCID TLB flush is
+     deferred until the exit to userspace, minimizing the cost.
+     See intel.com/sdm for the gory PCID/INVPCID details.
+  e. The userspace page tables must be populated for each new
+     process.  Even without PTI, the shared kernel mappings
+     are created by copying top-level (PGD) entries into each
+     new process.  But, with PTI, there are now *two* kernel
+     mappings: one in the kernel page tables that maps everything
+     and one for the entry/exit structures.  At fork(), we need to
+     copy both.
+  f. In addition to the fork()-time copying, there must also
+     be an update to the userspace PGD any time a set_pgd() is done
+     on a PGD used to map userspace.  This ensures that the kernel
+     and userspace copies always map the same userspace
+     memory.
+  g. On systems without PCID support, each CR3 write flushes
+     the entire TLB.  That means that each syscall, interrupt
+     or exception flushes the TLB.
+  h. INVPCID is a TLB-flushing instruction which allows flushing
+     of TLB entries for non-current PCIDs.  Some systems support
+     PCIDs, but do not support INVPCID.  On these systems, addresses
+     can only be flushed from the TLB for the current PCID.  When
+     flushing a kernel address, we need to flush all PCIDs, so a
+     single kernel address flush will require a TLB-flushing CR3
+     write upon the next use of every PCID.
+
+Possible Future Work
+====================
+1. We can be more careful about not actually writing to CR3
+   unless its value is actually changed.
+2. Allow PTI to be enabled/disabled at runtime in addition to the
+   boot-time switching.
+
+Testing
+========
+
+To test stability of PTI, the following test procedure is recommended,
+ideally doing all of these in parallel:
+
+1. Set CONFIG_DEBUG_ENTRY=y
+2. Run several copies of all of the tools/testing/selftests/x86/ tests
+   (excluding MPX and protection_keys) in a loop on multiple CPUs for
+   several minutes.  These tests frequently uncover corner cases in the
+   kernel entry code.  In general, old kernels might cause these tests
+   themselves to crash, but they should never crash the kernel.
+3. Run the 'perf' tool in a mode (top or record) that generates many
+   frequent performance monitoring non-maskable interrupts (see "NMI"
+   in /proc/interrupts).  This exercises the NMI entry/exit code which
+   is known to trigger bugs in code paths that did not expect to be
+   interrupted, including nested NMIs.  Using "-c" boosts the rate of
+   NMIs, and using two -c with separate counters encourages nested NMIs
+   and less deterministic behavior.
+   ::
+
+       while true; do perf record -c 10000 -e instructions,cycles -a sleep 10; done
+
+4. Launch a KVM virtual machine.
+5. Run 32-bit binaries on systems supporting the SYSCALL instruction.
+   This has been a lightly-tested code path and needs extra scrutiny.
+
+Debugging
+=========
+
+Bugs in PTI cause a few different signatures of crashes
+that are worth noting here.
+
+ * Failures of the selftests/x86 code.  Usually a bug in one of the
+   more obscure corners of entry_64.S
+ * Crashes in early boot, especially around CPU bringup.  Bugs
+   in the trampoline code or mappings cause these.
+ * Crashes at the first interrupt.  Caused by bugs in entry_64.S,
+   like screwing up a page table switch.  Also caused by
+   incorrectly mapping the IRQ handler entry code.
+ * Crashes at the first NMI.  The NMI code is separate from main
+   interrupt handlers and can have bugs that do not affect
+   normal interrupts.  Also caused by incorrectly mapping NMI
+   code.  NMIs that interrupt the entry code must be very
+   careful and can be the cause of crashes that show up when
+   running perf.
+ * Kernel crashes at the first exit to userspace.  entry_64.S
+   bugs, or failing to map some of the exit code.
+ * Crashes at first interrupt that interrupts userspace. The paths
+   in entry_64.S that return to userspace are sometimes separate
+   from the ones that return to the kernel.
+ * Double faults: overflowing the kernel stack because of page
+   faults upon page faults.  Caused by touching non-pti-mapped
+   data in the entry code, or forgetting to switch to kernel
+   CR3 before calling into C functions which are not pti-mapped.
+ * Userspace segfaults early in boot, sometimes manifesting
+   as mount(8) failing to mount the rootfs.  These have
+   tended to be TLB invalidation issues.  Usually invalidating
+   the wrong PCID, or otherwise missing an invalidation.
+
+.. [1] https://gruss.cc/files/kaiser.pdf
+.. [2] https://meltdownattack.com/meltdown.pdf
diff --git a/Documentation/x86/pti.txt b/Documentation/x86/pti.txt
deleted file mode 100644 (file)
index 5cd5843..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-Overview
-========
-
-Page Table Isolation (pti, previously known as KAISER[1]) is a
-countermeasure against attacks on the shared user/kernel address
-space such as the "Meltdown" approach[2].
-
-To mitigate this class of attacks, we create an independent set of
-page tables for use only when running userspace applications.  When
-the kernel is entered via syscalls, interrupts or exceptions, the
-page tables are switched to the full "kernel" copy.  When the system
-switches back to user mode, the user copy is used again.
-
-The userspace page tables contain only a minimal amount of kernel
-data: only what is needed to enter/exit the kernel such as the
-entry/exit functions themselves and the interrupt descriptor table
-(IDT).  There are a few strictly unnecessary things that get mapped
-such as the first C function when entering an interrupt (see
-comments in pti.c).
-
-This approach helps to ensure that side-channel attacks leveraging
-the paging structures do not function when PTI is enabled.  It can be
-enabled by setting CONFIG_PAGE_TABLE_ISOLATION=y at compile time.
-Once enabled at compile-time, it can be disabled at boot with the
-'nopti' or 'pti=' kernel parameters (see kernel-parameters.txt).
-
-Page Table Management
-=====================
-
-When PTI is enabled, the kernel manages two sets of page tables.
-The first set is very similar to the single set which is present in
-kernels without PTI.  This includes a complete mapping of userspace
-that the kernel can use for things like copy_to_user().
-
-Although _complete_, the user portion of the kernel page tables is
-crippled by setting the NX bit in the top level.  This ensures
-that any missed kernel->user CR3 switch will immediately crash
-userspace upon executing its first instruction.
-
-The userspace page tables map only the kernel data needed to enter
-and exit the kernel.  This data is entirely contained in the 'struct
-cpu_entry_area' structure which is placed in the fixmap which gives
-each CPU's copy of the area a compile-time-fixed virtual address.
-
-For new userspace mappings, the kernel makes the entries in its
-page tables like normal.  The only difference is when the kernel
-makes entries in the top (PGD) level.  In addition to setting the
-entry in the main kernel PGD, a copy of the entry is made in the
-userspace page tables' PGD.
-
-This sharing at the PGD level also inherently shares all the lower
-layers of the page tables.  This leaves a single, shared set of
-userspace page tables to manage.  One PTE to lock, one set of
-accessed bits, dirty bits, etc...
-
-Overhead
-========
-
-Protection against side-channel attacks is important.  But,
-this protection comes at a cost:
-
-1. Increased Memory Use
-  a. Each process now needs an order-1 PGD instead of order-0.
-     (Consumes an additional 4k per process).
-  b. The 'cpu_entry_area' structure must be 2MB in size and 2MB
-     aligned so that it can be mapped by setting a single PMD
-     entry.  This consumes nearly 2MB of RAM once the kernel
-     is decompressed, but no space in the kernel image itself.
-
-2. Runtime Cost
-  a. CR3 manipulation to switch between the page table copies
-     must be done at interrupt, syscall, and exception entry
-     and exit (it can be skipped when the kernel is interrupted,
-     though.)  Moves to CR3 are on the order of a hundred
-     cycles, and are required at every entry and exit.
-  b. A "trampoline" must be used for SYSCALL entry.  This
-     trampoline depends on a smaller set of resources than the
-     non-PTI SYSCALL entry code, so requires mapping fewer
-     things into the userspace page tables.  The downside is
-     that stacks must be switched at entry time.
-  c. Global pages are disabled for all kernel structures not
-     mapped into both kernel and userspace page tables.  This
-     feature of the MMU allows different processes to share TLB
-     entries mapping the kernel.  Losing the feature means more
-     TLB misses after a context switch.  The actual loss of
-     performance is very small, however, never exceeding 1%.
-  d. Process Context IDentifiers (PCID) is a CPU feature that
-     allows us to skip flushing the entire TLB when switching page
-     tables by setting a special bit in CR3 when the page tables
-     are changed.  This makes switching the page tables (at context
-     switch, or kernel entry/exit) cheaper.  But, on systems with
-     PCID support, the context switch code must flush both the user
-     and kernel entries out of the TLB.  The user PCID TLB flush is
-     deferred until the exit to userspace, minimizing the cost.
-     See intel.com/sdm for the gory PCID/INVPCID details.
-  e. The userspace page tables must be populated for each new
-     process.  Even without PTI, the shared kernel mappings
-     are created by copying top-level (PGD) entries into each
-     new process.  But, with PTI, there are now *two* kernel
-     mappings: one in the kernel page tables that maps everything
-     and one for the entry/exit structures.  At fork(), we need to
-     copy both.
-  f. In addition to the fork()-time copying, there must also
-     be an update to the userspace PGD any time a set_pgd() is done
-     on a PGD used to map userspace.  This ensures that the kernel
-     and userspace copies always map the same userspace
-     memory.
-  g. On systems without PCID support, each CR3 write flushes
-     the entire TLB.  That means that each syscall, interrupt
-     or exception flushes the TLB.
-  h. INVPCID is a TLB-flushing instruction which allows flushing
-     of TLB entries for non-current PCIDs.  Some systems support
-     PCIDs, but do not support INVPCID.  On these systems, addresses
-     can only be flushed from the TLB for the current PCID.  When
-     flushing a kernel address, we need to flush all PCIDs, so a
-     single kernel address flush will require a TLB-flushing CR3
-     write upon the next use of every PCID.
-
-Possible Future Work
-====================
-1. We can be more careful about not actually writing to CR3
-   unless its value is actually changed.
-2. Allow PTI to be enabled/disabled at runtime in addition to the
-   boot-time switching.
-
-Testing
-========
-
-To test stability of PTI, the following test procedure is recommended,
-ideally doing all of these in parallel:
-
-1. Set CONFIG_DEBUG_ENTRY=y
-2. Run several copies of all of the tools/testing/selftests/x86/ tests
-   (excluding MPX and protection_keys) in a loop on multiple CPUs for
-   several minutes.  These tests frequently uncover corner cases in the
-   kernel entry code.  In general, old kernels might cause these tests
-   themselves to crash, but they should never crash the kernel.
-3. Run the 'perf' tool in a mode (top or record) that generates many
-   frequent performance monitoring non-maskable interrupts (see "NMI"
-   in /proc/interrupts).  This exercises the NMI entry/exit code which
-   is known to trigger bugs in code paths that did not expect to be
-   interrupted, including nested NMIs.  Using "-c" boosts the rate of
-   NMIs, and using two -c with separate counters encourages nested NMIs
-   and less deterministic behavior.
-
-       while true; do perf record -c 10000 -e instructions,cycles -a sleep 10; done
-
-4. Launch a KVM virtual machine.
-5. Run 32-bit binaries on systems supporting the SYSCALL instruction.
-   This has been a lightly-tested code path and needs extra scrutiny.
-
-Debugging
-=========
-
-Bugs in PTI cause a few different signatures of crashes
-that are worth noting here.
-
- * Failures of the selftests/x86 code.  Usually a bug in one of the
-   more obscure corners of entry_64.S
- * Crashes in early boot, especially around CPU bringup.  Bugs
-   in the trampoline code or mappings cause these.
- * Crashes at the first interrupt.  Caused by bugs in entry_64.S,
-   like screwing up a page table switch.  Also caused by
-   incorrectly mapping the IRQ handler entry code.
- * Crashes at the first NMI.  The NMI code is separate from main
-   interrupt handlers and can have bugs that do not affect
-   normal interrupts.  Also caused by incorrectly mapping NMI
-   code.  NMIs that interrupt the entry code must be very
-   careful and can be the cause of crashes that show up when
-   running perf.
- * Kernel crashes at the first exit to userspace.  entry_64.S
-   bugs, or failing to map some of the exit code.
- * Crashes at first interrupt that interrupts userspace. The paths
-   in entry_64.S that return to userspace are sometimes separate
-   from the ones that return to the kernel.
- * Double faults: overflowing the kernel stack because of page
-   faults upon page faults.  Caused by touching non-pti-mapped
-   data in the entry code, or forgetting to switch to kernel
-   CR3 before calling into C functions which are not pti-mapped.
- * Userspace segfaults early in boot, sometimes manifesting
-   as mount(8) failing to mount the rootfs.  These have
-   tended to be TLB invalidation issues.  Usually invalidating
-   the wrong PCID, or otherwise missing an invalidation.
-
-1. https://gruss.cc/files/kaiser.pdf
-2. https://meltdownattack.com/meltdown.pdf
diff --git a/Documentation/x86/resctrl_ui.rst b/Documentation/x86/resctrl_ui.rst
new file mode 100644 (file)
index 0000000..225cfd4
--- /dev/null
@@ -0,0 +1,1191 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: <isonum.txt>
+
+===========================================
+User Interface for Resource Control feature
+===========================================
+
+:Copyright: |copy| 2016 Intel Corporation
+:Authors: - Fenghua Yu <fenghua.yu@intel.com>
+          - Tony Luck <tony.luck@intel.com>
+          - Vikas Shivappa <vikas.shivappa@intel.com>
+
+
+Intel refers to this feature as Intel Resource Director Technology(Intel(R) RDT).
+AMD refers to this feature as AMD Platform Quality of Service(AMD QoS).
+
+This feature is enabled by the CONFIG_X86_CPU_RESCTRL and the x86 /proc/cpuinfo
+flag bits:
+
+=============================================  ================================
+RDT (Resource Director Technology) Allocation  "rdt_a"
+CAT (Cache Allocation Technology)              "cat_l3", "cat_l2"
+CDP (Code and Data Prioritization)             "cdp_l3", "cdp_l2"
+CQM (Cache QoS Monitoring)                     "cqm_llc", "cqm_occup_llc"
+MBM (Memory Bandwidth Monitoring)              "cqm_mbm_total", "cqm_mbm_local"
+MBA (Memory Bandwidth Allocation)              "mba"
+=============================================  ================================
+
+To use the feature mount the file system::
+
+ # mount -t resctrl resctrl [-o cdp[,cdpl2][,mba_MBps]] /sys/fs/resctrl
+
+mount options are:
+
+"cdp":
+       Enable code/data prioritization in L3 cache allocations.
+"cdpl2":
+       Enable code/data prioritization in L2 cache allocations.
+"mba_MBps":
+       Enable the MBA Software Controller(mba_sc) to specify MBA
+       bandwidth in MBps
+
+L2 and L3 CDP are controlled seperately.
+
+RDT features are orthogonal. A particular system may support only
+monitoring, only control, or both monitoring and control.  Cache
+pseudo-locking is a unique way of using cache control to "pin" or
+"lock" data in the cache. Details can be found in
+"Cache Pseudo-Locking".
+
+
+The mount succeeds if either of allocation or monitoring is present, but
+only those files and directories supported by the system will be created.
+For more details on the behavior of the interface during monitoring
+and allocation, see the "Resource alloc and monitor groups" section.
+
+Info directory
+==============
+
+The 'info' directory contains information about the enabled
+resources. Each resource has its own subdirectory. The subdirectory
+names reflect the resource names.
+
+Each subdirectory contains the following files with respect to
+allocation:
+
+Cache resource(L3/L2)  subdirectory contains the following files
+related to allocation:
+
+"num_closids":
+               The number of CLOSIDs which are valid for this
+               resource. The kernel uses the smallest number of
+               CLOSIDs of all enabled resources as limit.
+"cbm_mask":
+               The bitmask which is valid for this resource.
+               This mask is equivalent to 100%.
+"min_cbm_bits":
+               The minimum number of consecutive bits which
+               must be set when writing a mask.
+
+"shareable_bits":
+               Bitmask of shareable resource with other executing
+               entities (e.g. I/O). User can use this when
+               setting up exclusive cache partitions. Note that
+               some platforms support devices that have their
+               own settings for cache use which can over-ride
+               these bits.
+"bit_usage":
+               Annotated capacity bitmasks showing how all
+               instances of the resource are used. The legend is:
+
+                       "0":
+                             Corresponding region is unused. When the system's
+                             resources have been allocated and a "0" is found
+                             in "bit_usage" it is a sign that resources are
+                             wasted.
+
+                       "H":
+                             Corresponding region is used by hardware only
+                             but available for software use. If a resource
+                             has bits set in "shareable_bits" but not all
+                             of these bits appear in the resource groups'
+                             schematas then the bits appearing in
+                             "shareable_bits" but no resource group will
+                             be marked as "H".
+                       "X":
+                             Corresponding region is available for sharing and
+                             used by hardware and software. These are the
+                             bits that appear in "shareable_bits" as
+                             well as a resource group's allocation.
+                       "S":
+                             Corresponding region is used by software
+                             and available for sharing.
+                       "E":
+                             Corresponding region is used exclusively by
+                             one resource group. No sharing allowed.
+                       "P":
+                             Corresponding region is pseudo-locked. No
+                             sharing allowed.
+
+Memory bandwitdh(MB) subdirectory contains the following files
+with respect to allocation:
+
+"min_bandwidth":
+               The minimum memory bandwidth percentage which
+               user can request.
+
+"bandwidth_gran":
+               The granularity in which the memory bandwidth
+               percentage is allocated. The allocated
+               b/w percentage is rounded off to the next
+               control step available on the hardware. The
+               available bandwidth control steps are:
+               min_bandwidth + N * bandwidth_gran.
+
+"delay_linear":
+               Indicates if the delay scale is linear or
+               non-linear. This field is purely informational
+               only.
+
+If RDT monitoring is available there will be an "L3_MON" directory
+with the following files:
+
+"num_rmids":
+               The number of RMIDs available. This is the
+               upper bound for how many "CTRL_MON" + "MON"
+               groups can be created.
+
+"mon_features":
+               Lists the monitoring events if
+               monitoring is enabled for the resource.
+
+"max_threshold_occupancy":
+               Read/write file provides the largest value (in
+               bytes) at which a previously used LLC_occupancy
+               counter can be considered for re-use.
+
+Finally, in the top level of the "info" directory there is a file
+named "last_cmd_status". This is reset with every "command" issued
+via the file system (making new directories or writing to any of the
+control files). If the command was successful, it will read as "ok".
+If the command failed, it will provide more information that can be
+conveyed in the error returns from file operations. E.g.
+::
+
+       # echo L3:0=f7 > schemata
+       bash: echo: write error: Invalid argument
+       # cat info/last_cmd_status
+       mask f7 has non-consecutive 1-bits
+
+Resource alloc and monitor groups
+=================================
+
+Resource groups are represented as directories in the resctrl file
+system.  The default group is the root directory which, immediately
+after mounting, owns all the tasks and cpus in the system and can make
+full use of all resources.
+
+On a system with RDT control features additional directories can be
+created in the root directory that specify different amounts of each
+resource (see "schemata" below). The root and these additional top level
+directories are referred to as "CTRL_MON" groups below.
+
+On a system with RDT monitoring the root directory and other top level
+directories contain a directory named "mon_groups" in which additional
+directories can be created to monitor subsets of tasks in the CTRL_MON
+group that is their ancestor. These are called "MON" groups in the rest
+of this document.
+
+Removing a directory will move all tasks and cpus owned by the group it
+represents to the parent. Removing one of the created CTRL_MON groups
+will automatically remove all MON groups below it.
+
+All groups contain the following files:
+
+"tasks":
+       Reading this file shows the list of all tasks that belong to
+       this group. Writing a task id to the file will add a task to the
+       group. If the group is a CTRL_MON group the task is removed from
+       whichever previous CTRL_MON group owned the task and also from
+       any MON group that owned the task. If the group is a MON group,
+       then the task must already belong to the CTRL_MON parent of this
+       group. The task is removed from any previous MON group.
+
+
+"cpus":
+       Reading this file shows a bitmask of the logical CPUs owned by
+       this group. Writing a mask to this file will add and remove
+       CPUs to/from this group. As with the tasks file a hierarchy is
+       maintained where MON groups may only include CPUs owned by the
+       parent CTRL_MON group.
+       When the resouce group is in pseudo-locked mode this file will
+       only be readable, reflecting the CPUs associated with the
+       pseudo-locked region.
+
+
+"cpus_list":
+       Just like "cpus", only using ranges of CPUs instead of bitmasks.
+
+
+When control is enabled all CTRL_MON groups will also contain:
+
+"schemata":
+       A list of all the resources available to this group.
+       Each resource has its own line and format - see below for details.
+
+"size":
+       Mirrors the display of the "schemata" file to display the size in
+       bytes of each allocation instead of the bits representing the
+       allocation.
+
+"mode":
+       The "mode" of the resource group dictates the sharing of its
+       allocations. A "shareable" resource group allows sharing of its
+       allocations while an "exclusive" resource group does not. A
+       cache pseudo-locked region is created by first writing
+       "pseudo-locksetup" to the "mode" file before writing the cache
+       pseudo-locked region's schemata to the resource group's "schemata"
+       file. On successful pseudo-locked region creation the mode will
+       automatically change to "pseudo-locked".
+
+When monitoring is enabled all MON groups will also contain:
+
+"mon_data":
+       This contains a set of files organized by L3 domain and by
+       RDT event. E.g. on a system with two L3 domains there will
+       be subdirectories "mon_L3_00" and "mon_L3_01".  Each of these
+       directories have one file per event (e.g. "llc_occupancy",
+       "mbm_total_bytes", and "mbm_local_bytes"). In a MON group these
+       files provide a read out of the current value of the event for
+       all tasks in the group. In CTRL_MON groups these files provide
+       the sum for all tasks in the CTRL_MON group and all tasks in
+       MON groups. Please see example section for more details on usage.
+
+Resource allocation rules
+-------------------------
+
+When a task is running the following rules define which resources are
+available to it:
+
+1) If the task is a member of a non-default group, then the schemata
+   for that group is used.
+
+2) Else if the task belongs to the default group, but is running on a
+   CPU that is assigned to some specific group, then the schemata for the
+   CPU's group is used.
+
+3) Otherwise the schemata for the default group is used.
+
+Resource monitoring rules
+-------------------------
+1) If a task is a member of a MON group, or non-default CTRL_MON group
+   then RDT events for the task will be reported in that group.
+
+2) If a task is a member of the default CTRL_MON group, but is running
+   on a CPU that is assigned to some specific group, then the RDT events
+   for the task will be reported in that group.
+
+3) Otherwise RDT events for the task will be reported in the root level
+   "mon_data" group.
+
+
+Notes on cache occupancy monitoring and control
+===============================================
+When moving a task from one group to another you should remember that
+this only affects *new* cache allocations by the task. E.g. you may have
+a task in a monitor group showing 3 MB of cache occupancy. If you move
+to a new group and immediately check the occupancy of the old and new
+groups you will likely see that the old group is still showing 3 MB and
+the new group zero. When the task accesses locations still in cache from
+before the move, the h/w does not update any counters. On a busy system
+you will likely see the occupancy in the old group go down as cache lines
+are evicted and re-used while the occupancy in the new group rises as
+the task accesses memory and loads into the cache are counted based on
+membership in the new group.
+
+The same applies to cache allocation control. Moving a task to a group
+with a smaller cache partition will not evict any cache lines. The
+process may continue to use them from the old partition.
+
+Hardware uses CLOSid(Class of service ID) and an RMID(Resource monitoring ID)
+to identify a control group and a monitoring group respectively. Each of
+the resource groups are mapped to these IDs based on the kind of group. The
+number of CLOSid and RMID are limited by the hardware and hence the creation of
+a "CTRL_MON" directory may fail if we run out of either CLOSID or RMID
+and creation of "MON" group may fail if we run out of RMIDs.
+
+max_threshold_occupancy - generic concepts
+------------------------------------------
+
+Note that an RMID once freed may not be immediately available for use as
+the RMID is still tagged the cache lines of the previous user of RMID.
+Hence such RMIDs are placed on limbo list and checked back if the cache
+occupancy has gone down. If there is a time when system has a lot of
+limbo RMIDs but which are not ready to be used, user may see an -EBUSY
+during mkdir.
+
+max_threshold_occupancy is a user configurable value to determine the
+occupancy at which an RMID can be freed.
+
+Schemata files - general concepts
+---------------------------------
+Each line in the file describes one resource. The line starts with
+the name of the resource, followed by specific values to be applied
+in each of the instances of that resource on the system.
+
+Cache IDs
+---------
+On current generation systems there is one L3 cache per socket and L2
+caches are generally just shared by the hyperthreads on a core, but this
+isn't an architectural requirement. We could have multiple separate L3
+caches on a socket, multiple cores could share an L2 cache. So instead
+of using "socket" or "core" to define the set of logical cpus sharing
+a resource we use a "Cache ID". At a given cache level this will be a
+unique number across the whole system (but it isn't guaranteed to be a
+contiguous sequence, there may be gaps).  To find the ID for each logical
+CPU look in /sys/devices/system/cpu/cpu*/cache/index*/id
+
+Cache Bit Masks (CBM)
+---------------------
+For cache resources we describe the portion of the cache that is available
+for allocation using a bitmask. The maximum value of the mask is defined
+by each cpu model (and may be different for different cache levels). It
+is found using CPUID, but is also provided in the "info" directory of
+the resctrl file system in "info/{resource}/cbm_mask". X86 hardware
+requires that these masks have all the '1' bits in a contiguous block. So
+0x3, 0x6 and 0xC are legal 4-bit masks with two bits set, but 0x5, 0x9
+and 0xA are not.  On a system with a 20-bit mask each bit represents 5%
+of the capacity of the cache. You could partition the cache into four
+equal parts with masks: 0x1f, 0x3e0, 0x7c00, 0xf8000.
+
+Memory bandwidth Allocation and monitoring
+==========================================
+
+For Memory bandwidth resource, by default the user controls the resource
+by indicating the percentage of total memory bandwidth.
+
+The minimum bandwidth percentage value for each cpu model is predefined
+and can be looked up through "info/MB/min_bandwidth". The bandwidth
+granularity that is allocated is also dependent on the cpu model and can
+be looked up at "info/MB/bandwidth_gran". The available bandwidth
+control steps are: min_bw + N * bw_gran. Intermediate values are rounded
+to the next control step available on the hardware.
+
+The bandwidth throttling is a core specific mechanism on some of Intel
+SKUs. Using a high bandwidth and a low bandwidth setting on two threads
+sharing a core will result in both threads being throttled to use the
+low bandwidth. The fact that Memory bandwidth allocation(MBA) is a core
+specific mechanism where as memory bandwidth monitoring(MBM) is done at
+the package level may lead to confusion when users try to apply control
+via the MBA and then monitor the bandwidth to see if the controls are
+effective. Below are such scenarios:
+
+1. User may *not* see increase in actual bandwidth when percentage
+   values are increased:
+
+This can occur when aggregate L2 external bandwidth is more than L3
+external bandwidth. Consider an SKL SKU with 24 cores on a package and
+where L2 external  is 10GBps (hence aggregate L2 external bandwidth is
+240GBps) and L3 external bandwidth is 100GBps. Now a workload with '20
+threads, having 50% bandwidth, each consuming 5GBps' consumes the max L3
+bandwidth of 100GBps although the percentage value specified is only 50%
+<< 100%. Hence increasing the bandwidth percentage will not yeild any
+more bandwidth. This is because although the L2 external bandwidth still
+has capacity, the L3 external bandwidth is fully used. Also note that
+this would be dependent on number of cores the benchmark is run on.
+
+2. Same bandwidth percentage may mean different actual bandwidth
+   depending on # of threads:
+
+For the same SKU in #1, a 'single thread, with 10% bandwidth' and '4
+thread, with 10% bandwidth' can consume upto 10GBps and 40GBps although
+they have same percentage bandwidth of 10%. This is simply because as
+threads start using more cores in an rdtgroup, the actual bandwidth may
+increase or vary although user specified bandwidth percentage is same.
+
+In order to mitigate this and make the interface more user friendly,
+resctrl added support for specifying the bandwidth in MBps as well.  The
+kernel underneath would use a software feedback mechanism or a "Software
+Controller(mba_sc)" which reads the actual bandwidth using MBM counters
+and adjust the memowy bandwidth percentages to ensure::
+
+       "actual bandwidth < user specified bandwidth".
+
+By default, the schemata would take the bandwidth percentage values
+where as user can switch to the "MBA software controller" mode using
+a mount option 'mba_MBps'. The schemata format is specified in the below
+sections.
+
+L3 schemata file details (code and data prioritization disabled)
+----------------------------------------------------------------
+With CDP disabled the L3 schemata format is::
+
+       L3:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+
+L3 schemata file details (CDP enabled via mount option to resctrl)
+------------------------------------------------------------------
+When CDP is enabled L3 control is split into two separate resources
+so you can specify independent masks for code and data like this::
+
+       L3data:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+       L3code:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+
+L2 schemata file details
+------------------------
+L2 cache does not support code and data prioritization, so the
+schemata format is always::
+
+       L2:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+
+Memory bandwidth Allocation (default mode)
+------------------------------------------
+
+Memory b/w domain is L3 cache.
+::
+
+       MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;...
+
+Memory bandwidth Allocation specified in MBps
+---------------------------------------------
+
+Memory bandwidth domain is L3 cache.
+::
+
+       MB:<cache_id0>=bw_MBps0;<cache_id1>=bw_MBps1;...
+
+Reading/writing the schemata file
+---------------------------------
+Reading the schemata file will show the state of all resources
+on all domains. When writing you only need to specify those values
+which you wish to change.  E.g.
+::
+
+  # cat schemata
+  L3DATA:0=fffff;1=fffff;2=fffff;3=fffff
+  L3CODE:0=fffff;1=fffff;2=fffff;3=fffff
+  # echo "L3DATA:2=3c0;" > schemata
+  # cat schemata
+  L3DATA:0=fffff;1=fffff;2=3c0;3=fffff
+  L3CODE:0=fffff;1=fffff;2=fffff;3=fffff
+
+Cache Pseudo-Locking
+====================
+CAT enables a user to specify the amount of cache space that an
+application can fill. Cache pseudo-locking builds on the fact that a
+CPU can still read and write data pre-allocated outside its current
+allocated area on a cache hit. With cache pseudo-locking, data can be
+preloaded into a reserved portion of cache that no application can
+fill, and from that point on will only serve cache hits. The cache
+pseudo-locked memory is made accessible to user space where an
+application can map it into its virtual address space and thus have
+a region of memory with reduced average read latency.
+
+The creation of a cache pseudo-locked region is triggered by a request
+from the user to do so that is accompanied by a schemata of the region
+to be pseudo-locked. The cache pseudo-locked region is created as follows:
+
+- Create a CAT allocation CLOSNEW with a CBM matching the schemata
+  from the user of the cache region that will contain the pseudo-locked
+  memory. This region must not overlap with any current CAT allocation/CLOS
+  on the system and no future overlap with this cache region is allowed
+  while the pseudo-locked region exists.
+- Create a contiguous region of memory of the same size as the cache
+  region.
+- Flush the cache, disable hardware prefetchers, disable preemption.
+- Make CLOSNEW the active CLOS and touch the allocated memory to load
+  it into the cache.
+- Set the previous CLOS as active.
+- At this point the closid CLOSNEW can be released - the cache
+  pseudo-locked region is protected as long as its CBM does not appear in
+  any CAT allocation. Even though the cache pseudo-locked region will from
+  this point on not appear in any CBM of any CLOS an application running with
+  any CLOS will be able to access the memory in the pseudo-locked region since
+  the region continues to serve cache hits.
+- The contiguous region of memory loaded into the cache is exposed to
+  user-space as a character device.
+
+Cache pseudo-locking increases the probability that data will remain
+in the cache via carefully configuring the CAT feature and controlling
+application behavior. There is no guarantee that data is placed in
+cache. Instructions like INVD, WBINVD, CLFLUSH, etc. can still evict
+“locked” data from cache. Power management C-states may shrink or
+power off cache. Deeper C-states will automatically be restricted on
+pseudo-locked region creation.
+
+It is required that an application using a pseudo-locked region runs
+with affinity to the cores (or a subset of the cores) associated
+with the cache on which the pseudo-locked region resides. A sanity check
+within the code will not allow an application to map pseudo-locked memory
+unless it runs with affinity to cores associated with the cache on which the
+pseudo-locked region resides. The sanity check is only done during the
+initial mmap() handling, there is no enforcement afterwards and the
+application self needs to ensure it remains affine to the correct cores.
+
+Pseudo-locking is accomplished in two stages:
+
+1) During the first stage the system administrator allocates a portion
+   of cache that should be dedicated to pseudo-locking. At this time an
+   equivalent portion of memory is allocated, loaded into allocated
+   cache portion, and exposed as a character device.
+2) During the second stage a user-space application maps (mmap()) the
+   pseudo-locked memory into its address space.
+
+Cache Pseudo-Locking Interface
+------------------------------
+A pseudo-locked region is created using the resctrl interface as follows:
+
+1) Create a new resource group by creating a new directory in /sys/fs/resctrl.
+2) Change the new resource group's mode to "pseudo-locksetup" by writing
+   "pseudo-locksetup" to the "mode" file.
+3) Write the schemata of the pseudo-locked region to the "schemata" file. All
+   bits within the schemata should be "unused" according to the "bit_usage"
+   file.
+
+On successful pseudo-locked region creation the "mode" file will contain
+"pseudo-locked" and a new character device with the same name as the resource
+group will exist in /dev/pseudo_lock. This character device can be mmap()'ed
+by user space in order to obtain access to the pseudo-locked memory region.
+
+An example of cache pseudo-locked region creation and usage can be found below.
+
+Cache Pseudo-Locking Debugging Interface
+----------------------------------------
+The pseudo-locking debugging interface is enabled by default (if
+CONFIG_DEBUG_FS is enabled) and can be found in /sys/kernel/debug/resctrl.
+
+There is no explicit way for the kernel to test if a provided memory
+location is present in the cache. The pseudo-locking debugging interface uses
+the tracing infrastructure to provide two ways to measure cache residency of
+the pseudo-locked region:
+
+1) Memory access latency using the pseudo_lock_mem_latency tracepoint. Data
+   from these measurements are best visualized using a hist trigger (see
+   example below). In this test the pseudo-locked region is traversed at
+   a stride of 32 bytes while hardware prefetchers and preemption
+   are disabled. This also provides a substitute visualization of cache
+   hits and misses.
+2) Cache hit and miss measurements using model specific precision counters if
+   available. Depending on the levels of cache on the system the pseudo_lock_l2
+   and pseudo_lock_l3 tracepoints are available.
+
+When a pseudo-locked region is created a new debugfs directory is created for
+it in debugfs as /sys/kernel/debug/resctrl/<newdir>. A single
+write-only file, pseudo_lock_measure, is present in this directory. The
+measurement of the pseudo-locked region depends on the number written to this
+debugfs file:
+
+1:
+     writing "1" to the pseudo_lock_measure file will trigger the latency
+     measurement captured in the pseudo_lock_mem_latency tracepoint. See
+     example below.
+2:
+     writing "2" to the pseudo_lock_measure file will trigger the L2 cache
+     residency (cache hits and misses) measurement captured in the
+     pseudo_lock_l2 tracepoint. See example below.
+3:
+     writing "3" to the pseudo_lock_measure file will trigger the L3 cache
+     residency (cache hits and misses) measurement captured in the
+     pseudo_lock_l3 tracepoint.
+
+All measurements are recorded with the tracing infrastructure. This requires
+the relevant tracepoints to be enabled before the measurement is triggered.
+
+Example of latency debugging interface
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In this example a pseudo-locked region named "newlock" was created. Here is
+how we can measure the latency in cycles of reading from this region and
+visualize this data with a histogram that is available if CONFIG_HIST_TRIGGERS
+is set::
+
+  # :> /sys/kernel/debug/tracing/trace
+  # echo 'hist:keys=latency' > /sys/kernel/debug/tracing/events/resctrl/pseudo_lock_mem_latency/trigger
+  # echo 1 > /sys/kernel/debug/tracing/events/resctrl/pseudo_lock_mem_latency/enable
+  # echo 1 > /sys/kernel/debug/resctrl/newlock/pseudo_lock_measure
+  # echo 0 > /sys/kernel/debug/tracing/events/resctrl/pseudo_lock_mem_latency/enable
+  # cat /sys/kernel/debug/tracing/events/resctrl/pseudo_lock_mem_latency/hist
+
+  # event histogram
+  #
+  # trigger info: hist:keys=latency:vals=hitcount:sort=hitcount:size=2048 [active]
+  #
+
+  { latency:        456 } hitcount:          1
+  { latency:         50 } hitcount:         83
+  { latency:         36 } hitcount:         96
+  { latency:         44 } hitcount:        174
+  { latency:         48 } hitcount:        195
+  { latency:         46 } hitcount:        262
+  { latency:         42 } hitcount:        693
+  { latency:         40 } hitcount:       3204
+  { latency:         38 } hitcount:       3484
+
+  Totals:
+      Hits: 8192
+      Entries: 9
+    Dropped: 0
+
+Example of cache hits/misses debugging
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In this example a pseudo-locked region named "newlock" was created on the L2
+cache of a platform. Here is how we can obtain details of the cache hits
+and misses using the platform's precision counters.
+::
+
+  # :> /sys/kernel/debug/tracing/trace
+  # echo 1 > /sys/kernel/debug/tracing/events/resctrl/pseudo_lock_l2/enable
+  # echo 2 > /sys/kernel/debug/resctrl/newlock/pseudo_lock_measure
+  # echo 0 > /sys/kernel/debug/tracing/events/resctrl/pseudo_lock_l2/enable
+  # cat /sys/kernel/debug/tracing/trace
+
+  # tracer: nop
+  #
+  #                              _-----=> irqs-off
+  #                             / _----=> need-resched
+  #                            | / _---=> hardirq/softirq
+  #                            || / _--=> preempt-depth
+  #                            ||| /     delay
+  #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
+  #              | |       |   ||||       |         |
+  pseudo_lock_mea-1672  [002] ....  3132.860500: pseudo_lock_l2: hits=4097 miss=0
+
+
+Examples for RDT allocation usage
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1) Example 1
+
+On a two socket machine (one L3 cache per socket) with just four bits
+for cache bit masks, minimum b/w of 10% with a memory bandwidth
+granularity of 10%.
+::
+
+  # mount -t resctrl resctrl /sys/fs/resctrl
+  # cd /sys/fs/resctrl
+  # mkdir p0 p1
+  # echo "L3:0=3;1=c\nMB:0=50;1=50" > /sys/fs/resctrl/p0/schemata
+  # echo "L3:0=3;1=3\nMB:0=50;1=50" > /sys/fs/resctrl/p1/schemata
+
+The default resource group is unmodified, so we have access to all parts
+of all caches (its schemata file reads "L3:0=f;1=f").
+
+Tasks that are under the control of group "p0" may only allocate from the
+"lower" 50% on cache ID 0, and the "upper" 50% of cache ID 1.
+Tasks in group "p1" use the "lower" 50% of cache on both sockets.
+
+Similarly, tasks that are under the control of group "p0" may use a
+maximum memory b/w of 50% on socket0 and 50% on socket 1.
+Tasks in group "p1" may also use 50% memory b/w on both sockets.
+Note that unlike cache masks, memory b/w cannot specify whether these
+allocations can overlap or not. The allocations specifies the maximum
+b/w that the group may be able to use and the system admin can configure
+the b/w accordingly.
+
+If the MBA is specified in MB(megabytes) then user can enter the max b/w in MB
+rather than the percentage values.
+::
+
+  # echo "L3:0=3;1=c\nMB:0=1024;1=500" > /sys/fs/resctrl/p0/schemata
+  # echo "L3:0=3;1=3\nMB:0=1024;1=500" > /sys/fs/resctrl/p1/schemata
+
+In the above example the tasks in "p1" and "p0" on socket 0 would use a max b/w
+of 1024MB where as on socket 1 they would use 500MB.
+
+2) Example 2
+
+Again two sockets, but this time with a more realistic 20-bit mask.
+
+Two real time tasks pid=1234 running on processor 0 and pid=5678 running on
+processor 1 on socket 0 on a 2-socket and dual core machine. To avoid noisy
+neighbors, each of the two real-time tasks exclusively occupies one quarter
+of L3 cache on socket 0.
+::
+
+  # mount -t resctrl resctrl /sys/fs/resctrl
+  # cd /sys/fs/resctrl
+
+First we reset the schemata for the default group so that the "upper"
+50% of the L3 cache on socket 0 and 50% of memory b/w cannot be used by
+ordinary tasks::
+
+  # echo "L3:0=3ff;1=fffff\nMB:0=50;1=100" > schemata
+
+Next we make a resource group for our first real time task and give
+it access to the "top" 25% of the cache on socket 0.
+::
+
+  # mkdir p0
+  # echo "L3:0=f8000;1=fffff" > p0/schemata
+
+Finally we move our first real time task into this resource group. We
+also use taskset(1) to ensure the task always runs on a dedicated CPU
+on socket 0. Most uses of resource groups will also constrain which
+processors tasks run on.
+::
+
+  # echo 1234 > p0/tasks
+  # taskset -cp 1 1234
+
+Ditto for the second real time task (with the remaining 25% of cache)::
+
+  # mkdir p1
+  # echo "L3:0=7c00;1=fffff" > p1/schemata
+  # echo 5678 > p1/tasks
+  # taskset -cp 2 5678
+
+For the same 2 socket system with memory b/w resource and CAT L3 the
+schemata would look like(Assume min_bandwidth 10 and bandwidth_gran is
+10):
+
+For our first real time task this would request 20% memory b/w on socket 0.
+::
+
+  # echo -e "L3:0=f8000;1=fffff\nMB:0=20;1=100" > p0/schemata
+
+For our second real time task this would request an other 20% memory b/w
+on socket 0.
+::
+
+  # echo -e "L3:0=f8000;1=fffff\nMB:0=20;1=100" > p0/schemata
+
+3) Example 3
+
+A single socket system which has real-time tasks running on core 4-7 and
+non real-time workload assigned to core 0-3. The real-time tasks share text
+and data, so a per task association is not required and due to interaction
+with the kernel it's desired that the kernel on these cores shares L3 with
+the tasks.
+::
+
+  # mount -t resctrl resctrl /sys/fs/resctrl
+  # cd /sys/fs/resctrl
+
+First we reset the schemata for the default group so that the "upper"
+50% of the L3 cache on socket 0, and 50% of memory bandwidth on socket 0
+cannot be used by ordinary tasks::
+
+  # echo "L3:0=3ff\nMB:0=50" > schemata
+
+Next we make a resource group for our real time cores and give it access
+to the "top" 50% of the cache on socket 0 and 50% of memory bandwidth on
+socket 0.
+::
+
+  # mkdir p0
+  # echo "L3:0=ffc00\nMB:0=50" > p0/schemata
+
+Finally we move core 4-7 over to the new group and make sure that the
+kernel and the tasks running there get 50% of the cache. They should
+also get 50% of memory bandwidth assuming that the cores 4-7 are SMT
+siblings and only the real time threads are scheduled on the cores 4-7.
+::
+
+  # echo F0 > p0/cpus
+
+4) Example 4
+
+The resource groups in previous examples were all in the default "shareable"
+mode allowing sharing of their cache allocations. If one resource group
+configures a cache allocation then nothing prevents another resource group
+to overlap with that allocation.
+
+In this example a new exclusive resource group will be created on a L2 CAT
+system with two L2 cache instances that can be configured with an 8-bit
+capacity bitmask. The new exclusive resource group will be configured to use
+25% of each cache instance.
+::
+
+  # mount -t resctrl resctrl /sys/fs/resctrl/
+  # cd /sys/fs/resctrl
+
+First, we observe that the default group is configured to allocate to all L2
+cache::
+
+  # cat schemata
+  L2:0=ff;1=ff
+
+We could attempt to create the new resource group at this point, but it will
+fail because of the overlap with the schemata of the default group::
+
+  # mkdir p0
+  # echo 'L2:0=0x3;1=0x3' > p0/schemata
+  # cat p0/mode
+  shareable
+  # echo exclusive > p0/mode
+  -sh: echo: write error: Invalid argument
+  # cat info/last_cmd_status
+  schemata overlaps
+
+To ensure that there is no overlap with another resource group the default
+resource group's schemata has to change, making it possible for the new
+resource group to become exclusive.
+::
+
+  # echo 'L2:0=0xfc;1=0xfc' > schemata
+  # echo exclusive > p0/mode
+  # grep . p0/*
+  p0/cpus:0
+  p0/mode:exclusive
+  p0/schemata:L2:0=03;1=03
+  p0/size:L2:0=262144;1=262144
+
+A new resource group will on creation not overlap with an exclusive resource
+group::
+
+  # mkdir p1
+  # grep . p1/*
+  p1/cpus:0
+  p1/mode:shareable
+  p1/schemata:L2:0=fc;1=fc
+  p1/size:L2:0=786432;1=786432
+
+The bit_usage will reflect how the cache is used::
+
+  # cat info/L2/bit_usage
+  0=SSSSSSEE;1=SSSSSSEE
+
+A resource group cannot be forced to overlap with an exclusive resource group::
+
+  # echo 'L2:0=0x1;1=0x1' > p1/schemata
+  -sh: echo: write error: Invalid argument
+  # cat info/last_cmd_status
+  overlaps with exclusive group
+
+Example of Cache Pseudo-Locking
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Lock portion of L2 cache from cache id 1 using CBM 0x3. Pseudo-locked
+region is exposed at /dev/pseudo_lock/newlock that can be provided to
+application for argument to mmap().
+::
+
+  # mount -t resctrl resctrl /sys/fs/resctrl/
+  # cd /sys/fs/resctrl
+
+Ensure that there are bits available that can be pseudo-locked, since only
+unused bits can be pseudo-locked the bits to be pseudo-locked needs to be
+removed from the default resource group's schemata::
+
+  # cat info/L2/bit_usage
+  0=SSSSSSSS;1=SSSSSSSS
+  # echo 'L2:1=0xfc' > schemata
+  # cat info/L2/bit_usage
+  0=SSSSSSSS;1=SSSSSS00
+
+Create a new resource group that will be associated with the pseudo-locked
+region, indicate that it will be used for a pseudo-locked region, and
+configure the requested pseudo-locked region capacity bitmask::
+
+  # mkdir newlock
+  # echo pseudo-locksetup > newlock/mode
+  # echo 'L2:1=0x3' > newlock/schemata
+
+On success the resource group's mode will change to pseudo-locked, the
+bit_usage will reflect the pseudo-locked region, and the character device
+exposing the pseudo-locked region will exist::
+
+  # cat newlock/mode
+  pseudo-locked
+  # cat info/L2/bit_usage
+  0=SSSSSSSS;1=SSSSSSPP
+  # ls -l /dev/pseudo_lock/newlock
+  crw------- 1 root root 243, 0 Apr  3 05:01 /dev/pseudo_lock/newlock
+
+::
+
+  /*
+  * Example code to access one page of pseudo-locked cache region
+  * from user space.
+  */
+  #define _GNU_SOURCE
+  #include <fcntl.h>
+  #include <sched.h>
+  #include <stdio.h>
+  #include <stdlib.h>
+  #include <unistd.h>
+  #include <sys/mman.h>
+
+  /*
+  * It is required that the application runs with affinity to only
+  * cores associated with the pseudo-locked region. Here the cpu
+  * is hardcoded for convenience of example.
+  */
+  static int cpuid = 2;
+
+  int main(int argc, char *argv[])
+  {
+    cpu_set_t cpuset;
+    long page_size;
+    void *mapping;
+    int dev_fd;
+    int ret;
+
+    page_size = sysconf(_SC_PAGESIZE);
+
+    CPU_ZERO(&cpuset);
+    CPU_SET(cpuid, &cpuset);
+    ret = sched_setaffinity(0, sizeof(cpuset), &cpuset);
+    if (ret < 0) {
+      perror("sched_setaffinity");
+      exit(EXIT_FAILURE);
+    }
+
+    dev_fd = open("/dev/pseudo_lock/newlock", O_RDWR);
+    if (dev_fd < 0) {
+      perror("open");
+      exit(EXIT_FAILURE);
+    }
+
+    mapping = mmap(0, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+            dev_fd, 0);
+    if (mapping == MAP_FAILED) {
+      perror("mmap");
+      close(dev_fd);
+      exit(EXIT_FAILURE);
+    }
+
+    /* Application interacts with pseudo-locked memory @mapping */
+
+    ret = munmap(mapping, page_size);
+    if (ret < 0) {
+      perror("munmap");
+      close(dev_fd);
+      exit(EXIT_FAILURE);
+    }
+
+    close(dev_fd);
+    exit(EXIT_SUCCESS);
+  }
+
+Locking between applications
+----------------------------
+
+Certain operations on the resctrl filesystem, composed of read/writes
+to/from multiple files, must be atomic.
+
+As an example, the allocation of an exclusive reservation of L3 cache
+involves:
+
+  1. Read the cbmmasks from each directory or the per-resource "bit_usage"
+  2. Find a contiguous set of bits in the global CBM bitmask that is clear
+     in any of the directory cbmmasks
+  3. Create a new directory
+  4. Set the bits found in step 2 to the new directory "schemata" file
+
+If two applications attempt to allocate space concurrently then they can
+end up allocating the same bits so the reservations are shared instead of
+exclusive.
+
+To coordinate atomic operations on the resctrlfs and to avoid the problem
+above, the following locking procedure is recommended:
+
+Locking is based on flock, which is available in libc and also as a shell
+script command
+
+Write lock:
+
+ A) Take flock(LOCK_EX) on /sys/fs/resctrl
+ B) Read/write the directory structure.
+ C) funlock
+
+Read lock:
+
+ A) Take flock(LOCK_SH) on /sys/fs/resctrl
+ B) If success read the directory structure.
+ C) funlock
+
+Example with bash::
+
+  # Atomically read directory structure
+  $ flock -s /sys/fs/resctrl/ find /sys/fs/resctrl
+
+  # Read directory contents and create new subdirectory
+
+  $ cat create-dir.sh
+  find /sys/fs/resctrl/ > output.txt
+  mask = function-of(output.txt)
+  mkdir /sys/fs/resctrl/newres/
+  echo mask > /sys/fs/resctrl/newres/schemata
+
+  $ flock /sys/fs/resctrl/ ./create-dir.sh
+
+Example with C::
+
+  /*
+  * Example code do take advisory locks
+  * before accessing resctrl filesystem
+  */
+  #include <sys/file.h>
+  #include <stdlib.h>
+
+  void resctrl_take_shared_lock(int fd)
+  {
+    int ret;
+
+    /* take shared lock on resctrl filesystem */
+    ret = flock(fd, LOCK_SH);
+    if (ret) {
+      perror("flock");
+      exit(-1);
+    }
+  }
+
+  void resctrl_take_exclusive_lock(int fd)
+  {
+    int ret;
+
+    /* release lock on resctrl filesystem */
+    ret = flock(fd, LOCK_EX);
+    if (ret) {
+      perror("flock");
+      exit(-1);
+    }
+  }
+
+  void resctrl_release_lock(int fd)
+  {
+    int ret;
+
+    /* take shared lock on resctrl filesystem */
+    ret = flock(fd, LOCK_UN);
+    if (ret) {
+      perror("flock");
+      exit(-1);
+    }
+  }
+
+  void main(void)
+  {
+    int fd, ret;
+
+    fd = open("/sys/fs/resctrl", O_DIRECTORY);
+    if (fd == -1) {
+      perror("open");
+      exit(-1);
+    }
+    resctrl_take_shared_lock(fd);
+    /* code to read directory contents */
+    resctrl_release_lock(fd);
+
+    resctrl_take_exclusive_lock(fd);
+    /* code to read and write directory contents */
+    resctrl_release_lock(fd);
+  }
+
+Examples for RDT Monitoring along with allocation usage
+=======================================================
+Reading monitored data
+----------------------
+Reading an event file (for ex: mon_data/mon_L3_00/llc_occupancy) would
+show the current snapshot of LLC occupancy of the corresponding MON
+group or CTRL_MON group.
+
+
+Example 1 (Monitor CTRL_MON group and subset of tasks in CTRL_MON group)
+------------------------------------------------------------------------
+On a two socket machine (one L3 cache per socket) with just four bits
+for cache bit masks::
+
+  # mount -t resctrl resctrl /sys/fs/resctrl
+  # cd /sys/fs/resctrl
+  # mkdir p0 p1
+  # echo "L3:0=3;1=c" > /sys/fs/resctrl/p0/schemata
+  # echo "L3:0=3;1=3" > /sys/fs/resctrl/p1/schemata
+  # echo 5678 > p1/tasks
+  # echo 5679 > p1/tasks
+
+The default resource group is unmodified, so we have access to all parts
+of all caches (its schemata file reads "L3:0=f;1=f").
+
+Tasks that are under the control of group "p0" may only allocate from the
+"lower" 50% on cache ID 0, and the "upper" 50% of cache ID 1.
+Tasks in group "p1" use the "lower" 50% of cache on both sockets.
+
+Create monitor groups and assign a subset of tasks to each monitor group.
+::
+
+  # cd /sys/fs/resctrl/p1/mon_groups
+  # mkdir m11 m12
+  # echo 5678 > m11/tasks
+  # echo 5679 > m12/tasks
+
+fetch data (data shown in bytes)
+::
+
+  # cat m11/mon_data/mon_L3_00/llc_occupancy
+  16234000
+  # cat m11/mon_data/mon_L3_01/llc_occupancy
+  14789000
+  # cat m12/mon_data/mon_L3_00/llc_occupancy
+  16789000
+
+The parent ctrl_mon group shows the aggregated data.
+::
+
+  # cat /sys/fs/resctrl/p1/mon_data/mon_l3_00/llc_occupancy
+  31234000
+
+Example 2 (Monitor a task from its creation)
+--------------------------------------------
+On a two socket machine (one L3 cache per socket)::
+
+  # mount -t resctrl resctrl /sys/fs/resctrl
+  # cd /sys/fs/resctrl
+  # mkdir p0 p1
+
+An RMID is allocated to the group once its created and hence the <cmd>
+below is monitored from its creation.
+::
+
+  # echo $$ > /sys/fs/resctrl/p1/tasks
+  # <cmd>
+
+Fetch the data::
+
+  # cat /sys/fs/resctrl/p1/mon_data/mon_l3_00/llc_occupancy
+  31789000
+
+Example 3 (Monitor without CAT support or before creating CAT groups)
+---------------------------------------------------------------------
+
+Assume a system like HSW has only CQM and no CAT support. In this case
+the resctrl will still mount but cannot create CTRL_MON directories.
+But user can create different MON groups within the root group thereby
+able to monitor all tasks including kernel threads.
+
+This can also be used to profile jobs cache size footprint before being
+able to allocate them to different allocation groups.
+::
+
+  # mount -t resctrl resctrl /sys/fs/resctrl
+  # cd /sys/fs/resctrl
+  # mkdir mon_groups/m01
+  # mkdir mon_groups/m02
+
+  # echo 3478 > /sys/fs/resctrl/mon_groups/m01/tasks
+  # echo 2467 > /sys/fs/resctrl/mon_groups/m02/tasks
+
+Monitor the groups separately and also get per domain data. From the
+below its apparent that the tasks are mostly doing work on
+domain(socket) 0.
+::
+
+  # cat /sys/fs/resctrl/mon_groups/m01/mon_L3_00/llc_occupancy
+  31234000
+  # cat /sys/fs/resctrl/mon_groups/m01/mon_L3_01/llc_occupancy
+  34555
+  # cat /sys/fs/resctrl/mon_groups/m02/mon_L3_00/llc_occupancy
+  31234000
+  # cat /sys/fs/resctrl/mon_groups/m02/mon_L3_01/llc_occupancy
+  32789
+
+
+Example 4 (Monitor real time tasks)
+-----------------------------------
+
+A single socket system which has real time tasks running on cores 4-7
+and non real time tasks on other cpus. We want to monitor the cache
+occupancy of the real time threads on these cores.
+::
+
+  # mount -t resctrl resctrl /sys/fs/resctrl
+  # cd /sys/fs/resctrl
+  # mkdir p1
+
+Move the cpus 4-7 over to p1::
+
+  # echo f0 > p1/cpus
+
+View the llc occupancy snapshot::
+
+  # cat /sys/fs/resctrl/p1/mon_data/mon_L3_00/llc_occupancy
+  11234000
diff --git a/Documentation/x86/resctrl_ui.txt b/Documentation/x86/resctrl_ui.txt
deleted file mode 100644 (file)
index c1f95b5..0000000
+++ /dev/null
@@ -1,1121 +0,0 @@
-User Interface for Resource Control feature
-
-Intel refers to this feature as Intel Resource Director Technology(Intel(R) RDT).
-AMD refers to this feature as AMD Platform Quality of Service(AMD QoS).
-
-Copyright (C) 2016 Intel Corporation
-
-Fenghua Yu <fenghua.yu@intel.com>
-Tony Luck <tony.luck@intel.com>
-Vikas Shivappa <vikas.shivappa@intel.com>
-
-This feature is enabled by the CONFIG_X86_CPU_RESCTRL and the x86 /proc/cpuinfo
-flag bits:
-RDT (Resource Director Technology) Allocation - "rdt_a"
-CAT (Cache Allocation Technology) - "cat_l3", "cat_l2"
-CDP (Code and Data Prioritization ) - "cdp_l3", "cdp_l2"
-CQM (Cache QoS Monitoring) - "cqm_llc", "cqm_occup_llc"
-MBM (Memory Bandwidth Monitoring) - "cqm_mbm_total", "cqm_mbm_local"
-MBA (Memory Bandwidth Allocation) - "mba"
-
-To use the feature mount the file system:
-
- # mount -t resctrl resctrl [-o cdp[,cdpl2][,mba_MBps]] /sys/fs/resctrl
-
-mount options are:
-
-"cdp": Enable code/data prioritization in L3 cache allocations.
-"cdpl2": Enable code/data prioritization in L2 cache allocations.
-"mba_MBps": Enable the MBA Software Controller(mba_sc) to specify MBA
- bandwidth in MBps
-
-L2 and L3 CDP are controlled seperately.
-
-RDT features are orthogonal. A particular system may support only
-monitoring, only control, or both monitoring and control.  Cache
-pseudo-locking is a unique way of using cache control to "pin" or
-"lock" data in the cache. Details can be found in
-"Cache Pseudo-Locking".
-
-
-The mount succeeds if either of allocation or monitoring is present, but
-only those files and directories supported by the system will be created.
-For more details on the behavior of the interface during monitoring
-and allocation, see the "Resource alloc and monitor groups" section.
-
-Info directory
---------------
-
-The 'info' directory contains information about the enabled
-resources. Each resource has its own subdirectory. The subdirectory
-names reflect the resource names.
-
-Each subdirectory contains the following files with respect to
-allocation:
-
-Cache resource(L3/L2)  subdirectory contains the following files
-related to allocation:
-
-"num_closids":         The number of CLOSIDs which are valid for this
-                       resource. The kernel uses the smallest number of
-                       CLOSIDs of all enabled resources as limit.
-
-"cbm_mask":            The bitmask which is valid for this resource.
-                       This mask is equivalent to 100%.
-
-"min_cbm_bits":        The minimum number of consecutive bits which
-                       must be set when writing a mask.
-
-"shareable_bits":      Bitmask of shareable resource with other executing
-                       entities (e.g. I/O). User can use this when
-                       setting up exclusive cache partitions. Note that
-                       some platforms support devices that have their
-                       own settings for cache use which can over-ride
-                       these bits.
-"bit_usage":           Annotated capacity bitmasks showing how all
-                       instances of the resource are used. The legend is:
-                       "0" - Corresponding region is unused. When the system's
-                             resources have been allocated and a "0" is found
-                             in "bit_usage" it is a sign that resources are
-                             wasted.
-                       "H" - Corresponding region is used by hardware only
-                             but available for software use. If a resource
-                             has bits set in "shareable_bits" but not all
-                             of these bits appear in the resource groups'
-                             schematas then the bits appearing in
-                             "shareable_bits" but no resource group will
-                             be marked as "H".
-                       "X" - Corresponding region is available for sharing and
-                             used by hardware and software. These are the
-                             bits that appear in "shareable_bits" as
-                             well as a resource group's allocation.
-                       "S" - Corresponding region is used by software
-                             and available for sharing.
-                       "E" - Corresponding region is used exclusively by
-                             one resource group. No sharing allowed.
-                       "P" - Corresponding region is pseudo-locked. No
-                             sharing allowed.
-
-Memory bandwitdh(MB) subdirectory contains the following files
-with respect to allocation:
-
-"min_bandwidth":       The minimum memory bandwidth percentage which
-                       user can request.
-
-"bandwidth_gran":      The granularity in which the memory bandwidth
-                       percentage is allocated. The allocated
-                       b/w percentage is rounded off to the next
-                       control step available on the hardware. The
-                       available bandwidth control steps are:
-                       min_bandwidth + N * bandwidth_gran.
-
-"delay_linear":        Indicates if the delay scale is linear or
-                       non-linear. This field is purely informational
-                       only.
-
-If RDT monitoring is available there will be an "L3_MON" directory
-with the following files:
-
-"num_rmids":           The number of RMIDs available. This is the
-                       upper bound for how many "CTRL_MON" + "MON"
-                       groups can be created.
-
-"mon_features":        Lists the monitoring events if
-                       monitoring is enabled for the resource.
-
-"max_threshold_occupancy":
-                       Read/write file provides the largest value (in
-                       bytes) at which a previously used LLC_occupancy
-                       counter can be considered for re-use.
-
-Finally, in the top level of the "info" directory there is a file
-named "last_cmd_status". This is reset with every "command" issued
-via the file system (making new directories or writing to any of the
-control files). If the command was successful, it will read as "ok".
-If the command failed, it will provide more information that can be
-conveyed in the error returns from file operations. E.g.
-
-       # echo L3:0=f7 > schemata
-       bash: echo: write error: Invalid argument
-       # cat info/last_cmd_status
-       mask f7 has non-consecutive 1-bits
-
-Resource alloc and monitor groups
----------------------------------
-
-Resource groups are represented as directories in the resctrl file
-system.  The default group is the root directory which, immediately
-after mounting, owns all the tasks and cpus in the system and can make
-full use of all resources.
-
-On a system with RDT control features additional directories can be
-created in the root directory that specify different amounts of each
-resource (see "schemata" below). The root and these additional top level
-directories are referred to as "CTRL_MON" groups below.
-
-On a system with RDT monitoring the root directory and other top level
-directories contain a directory named "mon_groups" in which additional
-directories can be created to monitor subsets of tasks in the CTRL_MON
-group that is their ancestor. These are called "MON" groups in the rest
-of this document.
-
-Removing a directory will move all tasks and cpus owned by the group it
-represents to the parent. Removing one of the created CTRL_MON groups
-will automatically remove all MON groups below it.
-
-All groups contain the following files:
-
-"tasks":
-       Reading this file shows the list of all tasks that belong to
-       this group. Writing a task id to the file will add a task to the
-       group. If the group is a CTRL_MON group the task is removed from
-       whichever previous CTRL_MON group owned the task and also from
-       any MON group that owned the task. If the group is a MON group,
-       then the task must already belong to the CTRL_MON parent of this
-       group. The task is removed from any previous MON group.
-
-
-"cpus":
-       Reading this file shows a bitmask of the logical CPUs owned by
-       this group. Writing a mask to this file will add and remove
-       CPUs to/from this group. As with the tasks file a hierarchy is
-       maintained where MON groups may only include CPUs owned by the
-       parent CTRL_MON group.
-       When the resouce group is in pseudo-locked mode this file will
-       only be readable, reflecting the CPUs associated with the
-       pseudo-locked region.
-
-
-"cpus_list":
-       Just like "cpus", only using ranges of CPUs instead of bitmasks.
-
-
-When control is enabled all CTRL_MON groups will also contain:
-
-"schemata":
-       A list of all the resources available to this group.
-       Each resource has its own line and format - see below for details.
-
-"size":
-       Mirrors the display of the "schemata" file to display the size in
-       bytes of each allocation instead of the bits representing the
-       allocation.
-
-"mode":
-       The "mode" of the resource group dictates the sharing of its
-       allocations. A "shareable" resource group allows sharing of its
-       allocations while an "exclusive" resource group does not. A
-       cache pseudo-locked region is created by first writing
-       "pseudo-locksetup" to the "mode" file before writing the cache
-       pseudo-locked region's schemata to the resource group's "schemata"
-       file. On successful pseudo-locked region creation the mode will
-       automatically change to "pseudo-locked".
-
-When monitoring is enabled all MON groups will also contain:
-
-"mon_data":
-       This contains a set of files organized by L3 domain and by
-       RDT event. E.g. on a system with two L3 domains there will
-       be subdirectories "mon_L3_00" and "mon_L3_01".  Each of these
-       directories have one file per event (e.g. "llc_occupancy",
-       "mbm_total_bytes", and "mbm_local_bytes"). In a MON group these
-       files provide a read out of the current value of the event for
-       all tasks in the group. In CTRL_MON groups these files provide
-       the sum for all tasks in the CTRL_MON group and all tasks in
-       MON groups. Please see example section for more details on usage.
-
-Resource allocation rules
--------------------------
-When a task is running the following rules define which resources are
-available to it:
-
-1) If the task is a member of a non-default group, then the schemata
-   for that group is used.
-
-2) Else if the task belongs to the default group, but is running on a
-   CPU that is assigned to some specific group, then the schemata for the
-   CPU's group is used.
-
-3) Otherwise the schemata for the default group is used.
-
-Resource monitoring rules
--------------------------
-1) If a task is a member of a MON group, or non-default CTRL_MON group
-   then RDT events for the task will be reported in that group.
-
-2) If a task is a member of the default CTRL_MON group, but is running
-   on a CPU that is assigned to some specific group, then the RDT events
-   for the task will be reported in that group.
-
-3) Otherwise RDT events for the task will be reported in the root level
-   "mon_data" group.
-
-
-Notes on cache occupancy monitoring and control
------------------------------------------------
-When moving a task from one group to another you should remember that
-this only affects *new* cache allocations by the task. E.g. you may have
-a task in a monitor group showing 3 MB of cache occupancy. If you move
-to a new group and immediately check the occupancy of the old and new
-groups you will likely see that the old group is still showing 3 MB and
-the new group zero. When the task accesses locations still in cache from
-before the move, the h/w does not update any counters. On a busy system
-you will likely see the occupancy in the old group go down as cache lines
-are evicted and re-used while the occupancy in the new group rises as
-the task accesses memory and loads into the cache are counted based on
-membership in the new group.
-
-The same applies to cache allocation control. Moving a task to a group
-with a smaller cache partition will not evict any cache lines. The
-process may continue to use them from the old partition.
-
-Hardware uses CLOSid(Class of service ID) and an RMID(Resource monitoring ID)
-to identify a control group and a monitoring group respectively. Each of
-the resource groups are mapped to these IDs based on the kind of group. The
-number of CLOSid and RMID are limited by the hardware and hence the creation of
-a "CTRL_MON" directory may fail if we run out of either CLOSID or RMID
-and creation of "MON" group may fail if we run out of RMIDs.
-
-max_threshold_occupancy - generic concepts
-------------------------------------------
-
-Note that an RMID once freed may not be immediately available for use as
-the RMID is still tagged the cache lines of the previous user of RMID.
-Hence such RMIDs are placed on limbo list and checked back if the cache
-occupancy has gone down. If there is a time when system has a lot of
-limbo RMIDs but which are not ready to be used, user may see an -EBUSY
-during mkdir.
-
-max_threshold_occupancy is a user configurable value to determine the
-occupancy at which an RMID can be freed.
-
-Schemata files - general concepts
----------------------------------
-Each line in the file describes one resource. The line starts with
-the name of the resource, followed by specific values to be applied
-in each of the instances of that resource on the system.
-
-Cache IDs
----------
-On current generation systems there is one L3 cache per socket and L2
-caches are generally just shared by the hyperthreads on a core, but this
-isn't an architectural requirement. We could have multiple separate L3
-caches on a socket, multiple cores could share an L2 cache. So instead
-of using "socket" or "core" to define the set of logical cpus sharing
-a resource we use a "Cache ID". At a given cache level this will be a
-unique number across the whole system (but it isn't guaranteed to be a
-contiguous sequence, there may be gaps).  To find the ID for each logical
-CPU look in /sys/devices/system/cpu/cpu*/cache/index*/id
-
-Cache Bit Masks (CBM)
----------------------
-For cache resources we describe the portion of the cache that is available
-for allocation using a bitmask. The maximum value of the mask is defined
-by each cpu model (and may be different for different cache levels). It
-is found using CPUID, but is also provided in the "info" directory of
-the resctrl file system in "info/{resource}/cbm_mask". X86 hardware
-requires that these masks have all the '1' bits in a contiguous block. So
-0x3, 0x6 and 0xC are legal 4-bit masks with two bits set, but 0x5, 0x9
-and 0xA are not.  On a system with a 20-bit mask each bit represents 5%
-of the capacity of the cache. You could partition the cache into four
-equal parts with masks: 0x1f, 0x3e0, 0x7c00, 0xf8000.
-
-Memory bandwidth Allocation and monitoring
-------------------------------------------
-
-For Memory bandwidth resource, by default the user controls the resource
-by indicating the percentage of total memory bandwidth.
-
-The minimum bandwidth percentage value for each cpu model is predefined
-and can be looked up through "info/MB/min_bandwidth". The bandwidth
-granularity that is allocated is also dependent on the cpu model and can
-be looked up at "info/MB/bandwidth_gran". The available bandwidth
-control steps are: min_bw + N * bw_gran. Intermediate values are rounded
-to the next control step available on the hardware.
-
-The bandwidth throttling is a core specific mechanism on some of Intel
-SKUs. Using a high bandwidth and a low bandwidth setting on two threads
-sharing a core will result in both threads being throttled to use the
-low bandwidth. The fact that Memory bandwidth allocation(MBA) is a core
-specific mechanism where as memory bandwidth monitoring(MBM) is done at
-the package level may lead to confusion when users try to apply control
-via the MBA and then monitor the bandwidth to see if the controls are
-effective. Below are such scenarios:
-
-1. User may *not* see increase in actual bandwidth when percentage
-   values are increased:
-
-This can occur when aggregate L2 external bandwidth is more than L3
-external bandwidth. Consider an SKL SKU with 24 cores on a package and
-where L2 external  is 10GBps (hence aggregate L2 external bandwidth is
-240GBps) and L3 external bandwidth is 100GBps. Now a workload with '20
-threads, having 50% bandwidth, each consuming 5GBps' consumes the max L3
-bandwidth of 100GBps although the percentage value specified is only 50%
-<< 100%. Hence increasing the bandwidth percentage will not yeild any
-more bandwidth. This is because although the L2 external bandwidth still
-has capacity, the L3 external bandwidth is fully used. Also note that
-this would be dependent on number of cores the benchmark is run on.
-
-2. Same bandwidth percentage may mean different actual bandwidth
-   depending on # of threads:
-
-For the same SKU in #1, a 'single thread, with 10% bandwidth' and '4
-thread, with 10% bandwidth' can consume upto 10GBps and 40GBps although
-they have same percentage bandwidth of 10%. This is simply because as
-threads start using more cores in an rdtgroup, the actual bandwidth may
-increase or vary although user specified bandwidth percentage is same.
-
-In order to mitigate this and make the interface more user friendly,
-resctrl added support for specifying the bandwidth in MBps as well.  The
-kernel underneath would use a software feedback mechanism or a "Software
-Controller(mba_sc)" which reads the actual bandwidth using MBM counters
-and adjust the memowy bandwidth percentages to ensure
-
-       "actual bandwidth < user specified bandwidth".
-
-By default, the schemata would take the bandwidth percentage values
-where as user can switch to the "MBA software controller" mode using
-a mount option 'mba_MBps'. The schemata format is specified in the below
-sections.
-
-L3 schemata file details (code and data prioritization disabled)
-----------------------------------------------------------------
-With CDP disabled the L3 schemata format is:
-
-       L3:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
-
-L3 schemata file details (CDP enabled via mount option to resctrl)
-------------------------------------------------------------------
-When CDP is enabled L3 control is split into two separate resources
-so you can specify independent masks for code and data like this:
-
-       L3data:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
-       L3code:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
-
-L2 schemata file details
-------------------------
-L2 cache does not support code and data prioritization, so the
-schemata format is always:
-
-       L2:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
-
-Memory bandwidth Allocation (default mode)
-------------------------------------------
-
-Memory b/w domain is L3 cache.
-
-       MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;...
-
-Memory bandwidth Allocation specified in MBps
----------------------------------------------
-
-Memory bandwidth domain is L3 cache.
-
-       MB:<cache_id0>=bw_MBps0;<cache_id1>=bw_MBps1;...
-
-Reading/writing the schemata file
----------------------------------
-Reading the schemata file will show the state of all resources
-on all domains. When writing you only need to specify those values
-which you wish to change.  E.g.
-
-# cat schemata
-L3DATA:0=fffff;1=fffff;2=fffff;3=fffff
-L3CODE:0=fffff;1=fffff;2=fffff;3=fffff
-# echo "L3DATA:2=3c0;" > schemata
-# cat schemata
-L3DATA:0=fffff;1=fffff;2=3c0;3=fffff
-L3CODE:0=fffff;1=fffff;2=fffff;3=fffff
-
-Cache Pseudo-Locking
---------------------
-CAT enables a user to specify the amount of cache space that an
-application can fill. Cache pseudo-locking builds on the fact that a
-CPU can still read and write data pre-allocated outside its current
-allocated area on a cache hit. With cache pseudo-locking, data can be
-preloaded into a reserved portion of cache that no application can
-fill, and from that point on will only serve cache hits. The cache
-pseudo-locked memory is made accessible to user space where an
-application can map it into its virtual address space and thus have
-a region of memory with reduced average read latency.
-
-The creation of a cache pseudo-locked region is triggered by a request
-from the user to do so that is accompanied by a schemata of the region
-to be pseudo-locked. The cache pseudo-locked region is created as follows:
-- Create a CAT allocation CLOSNEW with a CBM matching the schemata
-  from the user of the cache region that will contain the pseudo-locked
-  memory. This region must not overlap with any current CAT allocation/CLOS
-  on the system and no future overlap with this cache region is allowed
-  while the pseudo-locked region exists.
-- Create a contiguous region of memory of the same size as the cache
-  region.
-- Flush the cache, disable hardware prefetchers, disable preemption.
-- Make CLOSNEW the active CLOS and touch the allocated memory to load
-  it into the cache.
-- Set the previous CLOS as active.
-- At this point the closid CLOSNEW can be released - the cache
-  pseudo-locked region is protected as long as its CBM does not appear in
-  any CAT allocation. Even though the cache pseudo-locked region will from
-  this point on not appear in any CBM of any CLOS an application running with
-  any CLOS will be able to access the memory in the pseudo-locked region since
-  the region continues to serve cache hits.
-- The contiguous region of memory loaded into the cache is exposed to
-  user-space as a character device.
-
-Cache pseudo-locking increases the probability that data will remain
-in the cache via carefully configuring the CAT feature and controlling
-application behavior. There is no guarantee that data is placed in
-cache. Instructions like INVD, WBINVD, CLFLUSH, etc. can still evict
-“locked” data from cache. Power management C-states may shrink or
-power off cache. Deeper C-states will automatically be restricted on
-pseudo-locked region creation.
-
-It is required that an application using a pseudo-locked region runs
-with affinity to the cores (or a subset of the cores) associated
-with the cache on which the pseudo-locked region resides. A sanity check
-within the code will not allow an application to map pseudo-locked memory
-unless it runs with affinity to cores associated with the cache on which the
-pseudo-locked region resides. The sanity check is only done during the
-initial mmap() handling, there is no enforcement afterwards and the
-application self needs to ensure it remains affine to the correct cores.
-
-Pseudo-locking is accomplished in two stages:
-1) During the first stage the system administrator allocates a portion
-   of cache that should be dedicated to pseudo-locking. At this time an
-   equivalent portion of memory is allocated, loaded into allocated
-   cache portion, and exposed as a character device.
-2) During the second stage a user-space application maps (mmap()) the
-   pseudo-locked memory into its address space.
-
-Cache Pseudo-Locking Interface
-------------------------------
-A pseudo-locked region is created using the resctrl interface as follows:
-
-1) Create a new resource group by creating a new directory in /sys/fs/resctrl.
-2) Change the new resource group's mode to "pseudo-locksetup" by writing
-   "pseudo-locksetup" to the "mode" file.
-3) Write the schemata of the pseudo-locked region to the "schemata" file. All
-   bits within the schemata should be "unused" according to the "bit_usage"
-   file.
-
-On successful pseudo-locked region creation the "mode" file will contain
-"pseudo-locked" and a new character device with the same name as the resource
-group will exist in /dev/pseudo_lock. This character device can be mmap()'ed
-by user space in order to obtain access to the pseudo-locked memory region.
-
-An example of cache pseudo-locked region creation and usage can be found below.
-
-Cache Pseudo-Locking Debugging Interface
----------------------------------------
-The pseudo-locking debugging interface is enabled by default (if
-CONFIG_DEBUG_FS is enabled) and can be found in /sys/kernel/debug/resctrl.
-
-There is no explicit way for the kernel to test if a provided memory
-location is present in the cache. The pseudo-locking debugging interface uses
-the tracing infrastructure to provide two ways to measure cache residency of
-the pseudo-locked region:
-1) Memory access latency using the pseudo_lock_mem_latency tracepoint. Data
-   from these measurements are best visualized using a hist trigger (see
-   example below). In this test the pseudo-locked region is traversed at
-   a stride of 32 bytes while hardware prefetchers and preemption
-   are disabled. This also provides a substitute visualization of cache
-   hits and misses.
-2) Cache hit and miss measurements using model specific precision counters if
-   available. Depending on the levels of cache on the system the pseudo_lock_l2
-   and pseudo_lock_l3 tracepoints are available.
-
-When a pseudo-locked region is created a new debugfs directory is created for
-it in debugfs as /sys/kernel/debug/resctrl/<newdir>. A single
-write-only file, pseudo_lock_measure, is present in this directory. The
-measurement of the pseudo-locked region depends on the number written to this
-debugfs file:
-1 -  writing "1" to the pseudo_lock_measure file will trigger the latency
-     measurement captured in the pseudo_lock_mem_latency tracepoint. See
-     example below.
-2 -  writing "2" to the pseudo_lock_measure file will trigger the L2 cache
-     residency (cache hits and misses) measurement captured in the
-     pseudo_lock_l2 tracepoint. See example below.
-3 -  writing "3" to the pseudo_lock_measure file will trigger the L3 cache
-     residency (cache hits and misses) measurement captured in the
-     pseudo_lock_l3 tracepoint.
-
-All measurements are recorded with the tracing infrastructure. This requires
-the relevant tracepoints to be enabled before the measurement is triggered.
-
-Example of latency debugging interface:
-In this example a pseudo-locked region named "newlock" was created. Here is
-how we can measure the latency in cycles of reading from this region and
-visualize this data with a histogram that is available if CONFIG_HIST_TRIGGERS
-is set:
-# :> /sys/kernel/debug/tracing/trace
-# echo 'hist:keys=latency' > /sys/kernel/debug/tracing/events/resctrl/pseudo_lock_mem_latency/trigger
-# echo 1 > /sys/kernel/debug/tracing/events/resctrl/pseudo_lock_mem_latency/enable
-# echo 1 > /sys/kernel/debug/resctrl/newlock/pseudo_lock_measure
-# echo 0 > /sys/kernel/debug/tracing/events/resctrl/pseudo_lock_mem_latency/enable
-# cat /sys/kernel/debug/tracing/events/resctrl/pseudo_lock_mem_latency/hist
-
-# event histogram
-#
-# trigger info: hist:keys=latency:vals=hitcount:sort=hitcount:size=2048 [active]
-#
-
-{ latency:        456 } hitcount:          1
-{ latency:         50 } hitcount:         83
-{ latency:         36 } hitcount:         96
-{ latency:         44 } hitcount:        174
-{ latency:         48 } hitcount:        195
-{ latency:         46 } hitcount:        262
-{ latency:         42 } hitcount:        693
-{ latency:         40 } hitcount:       3204
-{ latency:         38 } hitcount:       3484
-
-Totals:
-    Hits: 8192
-    Entries: 9
-   Dropped: 0
-
-Example of cache hits/misses debugging:
-In this example a pseudo-locked region named "newlock" was created on the L2
-cache of a platform. Here is how we can obtain details of the cache hits
-and misses using the platform's precision counters.
-
-# :> /sys/kernel/debug/tracing/trace
-# echo 1 > /sys/kernel/debug/tracing/events/resctrl/pseudo_lock_l2/enable
-# echo 2 > /sys/kernel/debug/resctrl/newlock/pseudo_lock_measure
-# echo 0 > /sys/kernel/debug/tracing/events/resctrl/pseudo_lock_l2/enable
-# cat /sys/kernel/debug/tracing/trace
-
-# tracer: nop
-#
-#                              _-----=> irqs-off
-#                             / _----=> need-resched
-#                            | / _---=> hardirq/softirq
-#                            || / _--=> preempt-depth
-#                            ||| /     delay
-#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
-#              | |       |   ||||       |         |
- pseudo_lock_mea-1672  [002] ....  3132.860500: pseudo_lock_l2: hits=4097 miss=0
-
-
-Examples for RDT allocation usage:
-
-Example 1
----------
-On a two socket machine (one L3 cache per socket) with just four bits
-for cache bit masks, minimum b/w of 10% with a memory bandwidth
-granularity of 10%
-
-# mount -t resctrl resctrl /sys/fs/resctrl
-# cd /sys/fs/resctrl
-# mkdir p0 p1
-# echo "L3:0=3;1=c\nMB:0=50;1=50" > /sys/fs/resctrl/p0/schemata
-# echo "L3:0=3;1=3\nMB:0=50;1=50" > /sys/fs/resctrl/p1/schemata
-
-The default resource group is unmodified, so we have access to all parts
-of all caches (its schemata file reads "L3:0=f;1=f").
-
-Tasks that are under the control of group "p0" may only allocate from the
-"lower" 50% on cache ID 0, and the "upper" 50% of cache ID 1.
-Tasks in group "p1" use the "lower" 50% of cache on both sockets.
-
-Similarly, tasks that are under the control of group "p0" may use a
-maximum memory b/w of 50% on socket0 and 50% on socket 1.
-Tasks in group "p1" may also use 50% memory b/w on both sockets.
-Note that unlike cache masks, memory b/w cannot specify whether these
-allocations can overlap or not. The allocations specifies the maximum
-b/w that the group may be able to use and the system admin can configure
-the b/w accordingly.
-
-If the MBA is specified in MB(megabytes) then user can enter the max b/w in MB
-rather than the percentage values.
-
-# echo "L3:0=3;1=c\nMB:0=1024;1=500" > /sys/fs/resctrl/p0/schemata
-# echo "L3:0=3;1=3\nMB:0=1024;1=500" > /sys/fs/resctrl/p1/schemata
-
-In the above example the tasks in "p1" and "p0" on socket 0 would use a max b/w
-of 1024MB where as on socket 1 they would use 500MB.
-
-Example 2
----------
-Again two sockets, but this time with a more realistic 20-bit mask.
-
-Two real time tasks pid=1234 running on processor 0 and pid=5678 running on
-processor 1 on socket 0 on a 2-socket and dual core machine. To avoid noisy
-neighbors, each of the two real-time tasks exclusively occupies one quarter
-of L3 cache on socket 0.
-
-# mount -t resctrl resctrl /sys/fs/resctrl
-# cd /sys/fs/resctrl
-
-First we reset the schemata for the default group so that the "upper"
-50% of the L3 cache on socket 0 and 50% of memory b/w cannot be used by
-ordinary tasks:
-
-# echo "L3:0=3ff;1=fffff\nMB:0=50;1=100" > schemata
-
-Next we make a resource group for our first real time task and give
-it access to the "top" 25% of the cache on socket 0.
-
-# mkdir p0
-# echo "L3:0=f8000;1=fffff" > p0/schemata
-
-Finally we move our first real time task into this resource group. We
-also use taskset(1) to ensure the task always runs on a dedicated CPU
-on socket 0. Most uses of resource groups will also constrain which
-processors tasks run on.
-
-# echo 1234 > p0/tasks
-# taskset -cp 1 1234
-
-Ditto for the second real time task (with the remaining 25% of cache):
-
-# mkdir p1
-# echo "L3:0=7c00;1=fffff" > p1/schemata
-# echo 5678 > p1/tasks
-# taskset -cp 2 5678
-
-For the same 2 socket system with memory b/w resource and CAT L3 the
-schemata would look like(Assume min_bandwidth 10 and bandwidth_gran is
-10):
-
-For our first real time task this would request 20% memory b/w on socket
-0.
-
-# echo -e "L3:0=f8000;1=fffff\nMB:0=20;1=100" > p0/schemata
-
-For our second real time task this would request an other 20% memory b/w
-on socket 0.
-
-# echo -e "L3:0=f8000;1=fffff\nMB:0=20;1=100" > p0/schemata
-
-Example 3
----------
-
-A single socket system which has real-time tasks running on core 4-7 and
-non real-time workload assigned to core 0-3. The real-time tasks share text
-and data, so a per task association is not required and due to interaction
-with the kernel it's desired that the kernel on these cores shares L3 with
-the tasks.
-
-# mount -t resctrl resctrl /sys/fs/resctrl
-# cd /sys/fs/resctrl
-
-First we reset the schemata for the default group so that the "upper"
-50% of the L3 cache on socket 0, and 50% of memory bandwidth on socket 0
-cannot be used by ordinary tasks:
-
-# echo "L3:0=3ff\nMB:0=50" > schemata
-
-Next we make a resource group for our real time cores and give it access
-to the "top" 50% of the cache on socket 0 and 50% of memory bandwidth on
-socket 0.
-
-# mkdir p0
-# echo "L3:0=ffc00\nMB:0=50" > p0/schemata
-
-Finally we move core 4-7 over to the new group and make sure that the
-kernel and the tasks running there get 50% of the cache. They should
-also get 50% of memory bandwidth assuming that the cores 4-7 are SMT
-siblings and only the real time threads are scheduled on the cores 4-7.
-
-# echo F0 > p0/cpus
-
-Example 4
----------
-
-The resource groups in previous examples were all in the default "shareable"
-mode allowing sharing of their cache allocations. If one resource group
-configures a cache allocation then nothing prevents another resource group
-to overlap with that allocation.
-
-In this example a new exclusive resource group will be created on a L2 CAT
-system with two L2 cache instances that can be configured with an 8-bit
-capacity bitmask. The new exclusive resource group will be configured to use
-25% of each cache instance.
-
-# mount -t resctrl resctrl /sys/fs/resctrl/
-# cd /sys/fs/resctrl
-
-First, we observe that the default group is configured to allocate to all L2
-cache:
-
-# cat schemata
-L2:0=ff;1=ff
-
-We could attempt to create the new resource group at this point, but it will
-fail because of the overlap with the schemata of the default group:
-# mkdir p0
-# echo 'L2:0=0x3;1=0x3' > p0/schemata
-# cat p0/mode
-shareable
-# echo exclusive > p0/mode
--sh: echo: write error: Invalid argument
-# cat info/last_cmd_status
-schemata overlaps
-
-To ensure that there is no overlap with another resource group the default
-resource group's schemata has to change, making it possible for the new
-resource group to become exclusive.
-# echo 'L2:0=0xfc;1=0xfc' > schemata
-# echo exclusive > p0/mode
-# grep . p0/*
-p0/cpus:0
-p0/mode:exclusive
-p0/schemata:L2:0=03;1=03
-p0/size:L2:0=262144;1=262144
-
-A new resource group will on creation not overlap with an exclusive resource
-group:
-# mkdir p1
-# grep . p1/*
-p1/cpus:0
-p1/mode:shareable
-p1/schemata:L2:0=fc;1=fc
-p1/size:L2:0=786432;1=786432
-
-The bit_usage will reflect how the cache is used:
-# cat info/L2/bit_usage
-0=SSSSSSEE;1=SSSSSSEE
-
-A resource group cannot be forced to overlap with an exclusive resource group:
-# echo 'L2:0=0x1;1=0x1' > p1/schemata
--sh: echo: write error: Invalid argument
-# cat info/last_cmd_status
-overlaps with exclusive group
-
-Example of Cache Pseudo-Locking
--------------------------------
-Lock portion of L2 cache from cache id 1 using CBM 0x3. Pseudo-locked
-region is exposed at /dev/pseudo_lock/newlock that can be provided to
-application for argument to mmap().
-
-# mount -t resctrl resctrl /sys/fs/resctrl/
-# cd /sys/fs/resctrl
-
-Ensure that there are bits available that can be pseudo-locked, since only
-unused bits can be pseudo-locked the bits to be pseudo-locked needs to be
-removed from the default resource group's schemata:
-# cat info/L2/bit_usage
-0=SSSSSSSS;1=SSSSSSSS
-# echo 'L2:1=0xfc' > schemata
-# cat info/L2/bit_usage
-0=SSSSSSSS;1=SSSSSS00
-
-Create a new resource group that will be associated with the pseudo-locked
-region, indicate that it will be used for a pseudo-locked region, and
-configure the requested pseudo-locked region capacity bitmask:
-
-# mkdir newlock
-# echo pseudo-locksetup > newlock/mode
-# echo 'L2:1=0x3' > newlock/schemata
-
-On success the resource group's mode will change to pseudo-locked, the
-bit_usage will reflect the pseudo-locked region, and the character device
-exposing the pseudo-locked region will exist:
-
-# cat newlock/mode
-pseudo-locked
-# cat info/L2/bit_usage
-0=SSSSSSSS;1=SSSSSSPP
-# ls -l /dev/pseudo_lock/newlock
-crw------- 1 root root 243, 0 Apr  3 05:01 /dev/pseudo_lock/newlock
-
-/*
- * Example code to access one page of pseudo-locked cache region
- * from user space.
- */
-#define _GNU_SOURCE
-#include <fcntl.h>
-#include <sched.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/mman.h>
-
-/*
- * It is required that the application runs with affinity to only
- * cores associated with the pseudo-locked region. Here the cpu
- * is hardcoded for convenience of example.
- */
-static int cpuid = 2;
-
-int main(int argc, char *argv[])
-{
-       cpu_set_t cpuset;
-       long page_size;
-       void *mapping;
-       int dev_fd;
-       int ret;
-
-       page_size = sysconf(_SC_PAGESIZE);
-
-       CPU_ZERO(&cpuset);
-       CPU_SET(cpuid, &cpuset);
-       ret = sched_setaffinity(0, sizeof(cpuset), &cpuset);
-       if (ret < 0) {
-               perror("sched_setaffinity");
-               exit(EXIT_FAILURE);
-       }
-
-       dev_fd = open("/dev/pseudo_lock/newlock", O_RDWR);
-       if (dev_fd < 0) {
-               perror("open");
-               exit(EXIT_FAILURE);
-       }
-
-       mapping = mmap(0, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
-                      dev_fd, 0);
-       if (mapping == MAP_FAILED) {
-               perror("mmap");
-               close(dev_fd);
-               exit(EXIT_FAILURE);
-       }
-
-       /* Application interacts with pseudo-locked memory @mapping */
-
-       ret = munmap(mapping, page_size);
-       if (ret < 0) {
-               perror("munmap");
-               close(dev_fd);
-               exit(EXIT_FAILURE);
-       }
-
-       close(dev_fd);
-       exit(EXIT_SUCCESS);
-}
-
-Locking between applications
-----------------------------
-
-Certain operations on the resctrl filesystem, composed of read/writes
-to/from multiple files, must be atomic.
-
-As an example, the allocation of an exclusive reservation of L3 cache
-involves:
-
-  1. Read the cbmmasks from each directory or the per-resource "bit_usage"
-  2. Find a contiguous set of bits in the global CBM bitmask that is clear
-     in any of the directory cbmmasks
-  3. Create a new directory
-  4. Set the bits found in step 2 to the new directory "schemata" file
-
-If two applications attempt to allocate space concurrently then they can
-end up allocating the same bits so the reservations are shared instead of
-exclusive.
-
-To coordinate atomic operations on the resctrlfs and to avoid the problem
-above, the following locking procedure is recommended:
-
-Locking is based on flock, which is available in libc and also as a shell
-script command
-
-Write lock:
-
- A) Take flock(LOCK_EX) on /sys/fs/resctrl
- B) Read/write the directory structure.
- C) funlock
-
-Read lock:
-
- A) Take flock(LOCK_SH) on /sys/fs/resctrl
- B) If success read the directory structure.
- C) funlock
-
-Example with bash:
-
-# Atomically read directory structure
-$ flock -s /sys/fs/resctrl/ find /sys/fs/resctrl
-
-# Read directory contents and create new subdirectory
-
-$ cat create-dir.sh
-find /sys/fs/resctrl/ > output.txt
-mask = function-of(output.txt)
-mkdir /sys/fs/resctrl/newres/
-echo mask > /sys/fs/resctrl/newres/schemata
-
-$ flock /sys/fs/resctrl/ ./create-dir.sh
-
-Example with C:
-
-/*
- * Example code do take advisory locks
- * before accessing resctrl filesystem
- */
-#include <sys/file.h>
-#include <stdlib.h>
-
-void resctrl_take_shared_lock(int fd)
-{
-       int ret;
-
-       /* take shared lock on resctrl filesystem */
-       ret = flock(fd, LOCK_SH);
-       if (ret) {
-               perror("flock");
-               exit(-1);
-       }
-}
-
-void resctrl_take_exclusive_lock(int fd)
-{
-       int ret;
-
-       /* release lock on resctrl filesystem */
-       ret = flock(fd, LOCK_EX);
-       if (ret) {
-               perror("flock");
-               exit(-1);
-       }
-}
-
-void resctrl_release_lock(int fd)
-{
-       int ret;
-
-       /* take shared lock on resctrl filesystem */
-       ret = flock(fd, LOCK_UN);
-       if (ret) {
-               perror("flock");
-               exit(-1);
-       }
-}
-
-void main(void)
-{
-       int fd, ret;
-
-       fd = open("/sys/fs/resctrl", O_DIRECTORY);
-       if (fd == -1) {
-               perror("open");
-               exit(-1);
-       }
-       resctrl_take_shared_lock(fd);
-       /* code to read directory contents */
-       resctrl_release_lock(fd);
-
-       resctrl_take_exclusive_lock(fd);
-       /* code to read and write directory contents */
-       resctrl_release_lock(fd);
-}
-
-Examples for RDT Monitoring along with allocation usage:
-
-Reading monitored data
-----------------------
-Reading an event file (for ex: mon_data/mon_L3_00/llc_occupancy) would
-show the current snapshot of LLC occupancy of the corresponding MON
-group or CTRL_MON group.
-
-
-Example 1 (Monitor CTRL_MON group and subset of tasks in CTRL_MON group)
----------
-On a two socket machine (one L3 cache per socket) with just four bits
-for cache bit masks
-
-# mount -t resctrl resctrl /sys/fs/resctrl
-# cd /sys/fs/resctrl
-# mkdir p0 p1
-# echo "L3:0=3;1=c" > /sys/fs/resctrl/p0/schemata
-# echo "L3:0=3;1=3" > /sys/fs/resctrl/p1/schemata
-# echo 5678 > p1/tasks
-# echo 5679 > p1/tasks
-
-The default resource group is unmodified, so we have access to all parts
-of all caches (its schemata file reads "L3:0=f;1=f").
-
-Tasks that are under the control of group "p0" may only allocate from the
-"lower" 50% on cache ID 0, and the "upper" 50% of cache ID 1.
-Tasks in group "p1" use the "lower" 50% of cache on both sockets.
-
-Create monitor groups and assign a subset of tasks to each monitor group.
-
-# cd /sys/fs/resctrl/p1/mon_groups
-# mkdir m11 m12
-# echo 5678 > m11/tasks
-# echo 5679 > m12/tasks
-
-fetch data (data shown in bytes)
-
-# cat m11/mon_data/mon_L3_00/llc_occupancy
-16234000
-# cat m11/mon_data/mon_L3_01/llc_occupancy
-14789000
-# cat m12/mon_data/mon_L3_00/llc_occupancy
-16789000
-
-The parent ctrl_mon group shows the aggregated data.
-
-# cat /sys/fs/resctrl/p1/mon_data/mon_l3_00/llc_occupancy
-31234000
-
-Example 2 (Monitor a task from its creation)
----------
-On a two socket machine (one L3 cache per socket)
-
-# mount -t resctrl resctrl /sys/fs/resctrl
-# cd /sys/fs/resctrl
-# mkdir p0 p1
-
-An RMID is allocated to the group once its created and hence the <cmd>
-below is monitored from its creation.
-
-# echo $$ > /sys/fs/resctrl/p1/tasks
-# <cmd>
-
-Fetch the data
-
-# cat /sys/fs/resctrl/p1/mon_data/mon_l3_00/llc_occupancy
-31789000
-
-Example 3 (Monitor without CAT support or before creating CAT groups)
----------
-
-Assume a system like HSW has only CQM and no CAT support. In this case
-the resctrl will still mount but cannot create CTRL_MON directories.
-But user can create different MON groups within the root group thereby
-able to monitor all tasks including kernel threads.
-
-This can also be used to profile jobs cache size footprint before being
-able to allocate them to different allocation groups.
-
-# mount -t resctrl resctrl /sys/fs/resctrl
-# cd /sys/fs/resctrl
-# mkdir mon_groups/m01
-# mkdir mon_groups/m02
-
-# echo 3478 > /sys/fs/resctrl/mon_groups/m01/tasks
-# echo 2467 > /sys/fs/resctrl/mon_groups/m02/tasks
-
-Monitor the groups separately and also get per domain data. From the
-below its apparent that the tasks are mostly doing work on
-domain(socket) 0.
-
-# cat /sys/fs/resctrl/mon_groups/m01/mon_L3_00/llc_occupancy
-31234000
-# cat /sys/fs/resctrl/mon_groups/m01/mon_L3_01/llc_occupancy
-34555
-# cat /sys/fs/resctrl/mon_groups/m02/mon_L3_00/llc_occupancy
-31234000
-# cat /sys/fs/resctrl/mon_groups/m02/mon_L3_01/llc_occupancy
-32789
-
-
-Example 4 (Monitor real time tasks)
------------------------------------
-
-A single socket system which has real time tasks running on cores 4-7
-and non real time tasks on other cpus. We want to monitor the cache
-occupancy of the real time threads on these cores.
-
-# mount -t resctrl resctrl /sys/fs/resctrl
-# cd /sys/fs/resctrl
-# mkdir p1
-
-Move the cpus 4-7 over to p1
-# echo f0 > p1/cpus
-
-View the llc occupancy snapshot
-
-# cat /sys/fs/resctrl/p1/mon_data/mon_L3_00/llc_occupancy
-11234000
diff --git a/Documentation/x86/tlb.rst b/Documentation/x86/tlb.rst
new file mode 100644 (file)
index 0000000..82ec58a
--- /dev/null
@@ -0,0 +1,83 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=======
+The TLB
+=======
+
+When the kernel unmaps or modified the attributes of a range of
+memory, it has two choices:
+
+ 1. Flush the entire TLB with a two-instruction sequence.  This is
+    a quick operation, but it causes collateral damage: TLB entries
+    from areas other than the one we are trying to flush will be
+    destroyed and must be refilled later, at some cost.
+ 2. Use the invlpg instruction to invalidate a single page at a
+    time.  This could potentially cost many more instructions, but
+    it is a much more precise operation, causing no collateral
+    damage to other TLB entries.
+
+Which method to do depends on a few things:
+
+ 1. The size of the flush being performed.  A flush of the entire
+    address space is obviously better performed by flushing the
+    entire TLB than doing 2^48/PAGE_SIZE individual flushes.
+ 2. The contents of the TLB.  If the TLB is empty, then there will
+    be no collateral damage caused by doing the global flush, and
+    all of the individual flush will have ended up being wasted
+    work.
+ 3. The size of the TLB.  The larger the TLB, the more collateral
+    damage we do with a full flush.  So, the larger the TLB, the
+    more attractive an individual flush looks.  Data and
+    instructions have separate TLBs, as do different page sizes.
+ 4. The microarchitecture.  The TLB has become a multi-level
+    cache on modern CPUs, and the global flushes have become more
+    expensive relative to single-page flushes.
+
+There is obviously no way the kernel can know all these things,
+especially the contents of the TLB during a given flush.  The
+sizes of the flush will vary greatly depending on the workload as
+well.  There is essentially no "right" point to choose.
+
+You may be doing too many individual invalidations if you see the
+invlpg instruction (or instructions _near_ it) show up high in
+profiles.  If you believe that individual invalidations being
+called too often, you can lower the tunable::
+
+       /sys/kernel/debug/x86/tlb_single_page_flush_ceiling
+
+This will cause us to do the global flush for more cases.
+Lowering it to 0 will disable the use of the individual flushes.
+Setting it to 1 is a very conservative setting and it should
+never need to be 0 under normal circumstances.
+
+Despite the fact that a single individual flush on x86 is
+guaranteed to flush a full 2MB [1]_, hugetlbfs always uses the full
+flushes.  THP is treated exactly the same as normal memory.
+
+You might see invlpg inside of flush_tlb_mm_range() show up in
+profiles, or you can use the trace_tlb_flush() tracepoints. to
+determine how long the flush operations are taking.
+
+Essentially, you are balancing the cycles you spend doing invlpg
+with the cycles that you spend refilling the TLB later.
+
+You can measure how expensive TLB refills are by using
+performance counters and 'perf stat', like this::
+
+  perf stat -e
+    cpu/event=0x8,umask=0x84,name=dtlb_load_misses_walk_duration/,
+    cpu/event=0x8,umask=0x82,name=dtlb_load_misses_walk_completed/,
+    cpu/event=0x49,umask=0x4,name=dtlb_store_misses_walk_duration/,
+    cpu/event=0x49,umask=0x2,name=dtlb_store_misses_walk_completed/,
+    cpu/event=0x85,umask=0x4,name=itlb_misses_walk_duration/,
+    cpu/event=0x85,umask=0x2,name=itlb_misses_walk_completed/
+
+That works on an IvyBridge-era CPU (i5-3320M).  Different CPUs
+may have differently-named counters, but they should at least
+be there in some form.  You can use pmu-tools 'ocperf list'
+(https://github.com/andikleen/pmu-tools) to find the right
+counters for a given CPU.
+
+.. [1] A footnote in Intel's SDM "4.10.4.2 Recommended Invalidation"
+   says: "One execution of INVLPG is sufficient even for a page
+   with size greater than 4 KBytes."
diff --git a/Documentation/x86/tlb.txt b/Documentation/x86/tlb.txt
deleted file mode 100644 (file)
index 6a0607b..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-When the kernel unmaps or modified the attributes of a range of
-memory, it has two choices:
- 1. Flush the entire TLB with a two-instruction sequence.  This is
-    a quick operation, but it causes collateral damage: TLB entries
-    from areas other than the one we are trying to flush will be
-    destroyed and must be refilled later, at some cost.
- 2. Use the invlpg instruction to invalidate a single page at a
-    time.  This could potentially cost many more instructions, but
-    it is a much more precise operation, causing no collateral
-    damage to other TLB entries.
-
-Which method to do depends on a few things:
- 1. The size of the flush being performed.  A flush of the entire
-    address space is obviously better performed by flushing the
-    entire TLB than doing 2^48/PAGE_SIZE individual flushes.
- 2. The contents of the TLB.  If the TLB is empty, then there will
-    be no collateral damage caused by doing the global flush, and
-    all of the individual flush will have ended up being wasted
-    work.
- 3. The size of the TLB.  The larger the TLB, the more collateral
-    damage we do with a full flush.  So, the larger the TLB, the
-    more attractive an individual flush looks.  Data and
-    instructions have separate TLBs, as do different page sizes.
- 4. The microarchitecture.  The TLB has become a multi-level
-    cache on modern CPUs, and the global flushes have become more
-    expensive relative to single-page flushes.
-
-There is obviously no way the kernel can know all these things,
-especially the contents of the TLB during a given flush.  The
-sizes of the flush will vary greatly depending on the workload as
-well.  There is essentially no "right" point to choose.
-
-You may be doing too many individual invalidations if you see the
-invlpg instruction (or instructions _near_ it) show up high in
-profiles.  If you believe that individual invalidations being
-called too often, you can lower the tunable:
-
-       /sys/kernel/debug/x86/tlb_single_page_flush_ceiling
-
-This will cause us to do the global flush for more cases.
-Lowering it to 0 will disable the use of the individual flushes.
-Setting it to 1 is a very conservative setting and it should
-never need to be 0 under normal circumstances.
-
-Despite the fact that a single individual flush on x86 is
-guaranteed to flush a full 2MB [1], hugetlbfs always uses the full
-flushes.  THP is treated exactly the same as normal memory.
-
-You might see invlpg inside of flush_tlb_mm_range() show up in
-profiles, or you can use the trace_tlb_flush() tracepoints. to
-determine how long the flush operations are taking.
-
-Essentially, you are balancing the cycles you spend doing invlpg
-with the cycles that you spend refilling the TLB later.
-
-You can measure how expensive TLB refills are by using
-performance counters and 'perf stat', like this:
-
-perf stat -e
-       cpu/event=0x8,umask=0x84,name=dtlb_load_misses_walk_duration/,
-       cpu/event=0x8,umask=0x82,name=dtlb_load_misses_walk_completed/,
-       cpu/event=0x49,umask=0x4,name=dtlb_store_misses_walk_duration/,
-       cpu/event=0x49,umask=0x2,name=dtlb_store_misses_walk_completed/,
-       cpu/event=0x85,umask=0x4,name=itlb_misses_walk_duration/,
-       cpu/event=0x85,umask=0x2,name=itlb_misses_walk_completed/
-
-That works on an IvyBridge-era CPU (i5-3320M).  Different CPUs
-may have differently-named counters, but they should at least
-be there in some form.  You can use pmu-tools 'ocperf list'
-(https://github.com/andikleen/pmu-tools) to find the right
-counters for a given CPU.
-
-1. A footnote in Intel's SDM "4.10.4.2 Recommended Invalidation"
-   says: "One execution of INVLPG is sufficient even for a page
-   with size greater than 4 KBytes."
diff --git a/Documentation/x86/topology.rst b/Documentation/x86/topology.rst
new file mode 100644 (file)
index 0000000..6e28dbe
--- /dev/null
@@ -0,0 +1,221 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============
+x86 Topology
+============
+
+This documents and clarifies the main aspects of x86 topology modelling and
+representation in the kernel. Update/change when doing changes to the
+respective code.
+
+The architecture-agnostic topology definitions are in
+Documentation/cputopology.txt. This file holds x86-specific
+differences/specialities which must not necessarily apply to the generic
+definitions. Thus, the way to read up on Linux topology on x86 is to start
+with the generic one and look at this one in parallel for the x86 specifics.
+
+Needless to say, code should use the generic functions - this file is *only*
+here to *document* the inner workings of x86 topology.
+
+Started by Thomas Gleixner <tglx@linutronix.de> and Borislav Petkov <bp@alien8.de>.
+
+The main aim of the topology facilities is to present adequate interfaces to
+code which needs to know/query/use the structure of the running system wrt
+threads, cores, packages, etc.
+
+The kernel does not care about the concept of physical sockets because a
+socket has no relevance to software. It's an electromechanical component. In
+the past a socket always contained a single package (see below), but with the
+advent of Multi Chip Modules (MCM) a socket can hold more than one package. So
+there might be still references to sockets in the code, but they are of
+historical nature and should be cleaned up.
+
+The topology of a system is described in the units of:
+
+    - packages
+    - cores
+    - threads
+
+Package
+=======
+Packages contain a number of cores plus shared resources, e.g. DRAM
+controller, shared caches etc.
+
+AMD nomenclature for package is 'Node'.
+
+Package-related topology information in the kernel:
+
+  - cpuinfo_x86.x86_max_cores:
+
+    The number of cores in a package. This information is retrieved via CPUID.
+
+  - cpuinfo_x86.phys_proc_id:
+
+    The physical ID of the package. This information is retrieved via CPUID
+    and deduced from the APIC IDs of the cores in the package.
+
+  - cpuinfo_x86.logical_proc_id:
+
+    The logical ID of the package. As we do not trust BIOSes to enumerate the
+    packages in a consistent way, we introduced the concept of logical package
+    ID so we can sanely calculate the number of maximum possible packages in
+    the system and have the packages enumerated linearly.
+
+  - topology_max_packages():
+
+    The maximum possible number of packages in the system. Helpful for per
+    package facilities to preallocate per package information.
+
+  - cpu_llc_id:
+
+    A per-CPU variable containing:
+
+      - On Intel, the first APIC ID of the list of CPUs sharing the Last Level
+        Cache
+
+      - On AMD, the Node ID or Core Complex ID containing the Last Level
+        Cache. In general, it is a number identifying an LLC uniquely on the
+        system.
+
+Cores
+=====
+A core consists of 1 or more threads. It does not matter whether the threads
+are SMT- or CMT-type threads.
+
+AMDs nomenclature for a CMT core is "Compute Unit". The kernel always uses
+"core".
+
+Core-related topology information in the kernel:
+
+  - smp_num_siblings:
+
+    The number of threads in a core. The number of threads in a package can be
+    calculated by::
+
+       threads_per_package = cpuinfo_x86.x86_max_cores * smp_num_siblings
+
+
+Threads
+=======
+A thread is a single scheduling unit. It's the equivalent to a logical Linux
+CPU.
+
+AMDs nomenclature for CMT threads is "Compute Unit Core". The kernel always
+uses "thread".
+
+Thread-related topology information in the kernel:
+
+  - topology_core_cpumask():
+
+    The cpumask contains all online threads in the package to which a thread
+    belongs.
+
+    The number of online threads is also printed in /proc/cpuinfo "siblings."
+
+  - topology_sibling_cpumask():
+
+    The cpumask contains all online threads in the core to which a thread
+    belongs.
+
+  - topology_logical_package_id():
+
+    The logical package ID to which a thread belongs.
+
+  - topology_physical_package_id():
+
+    The physical package ID to which a thread belongs.
+
+  - topology_core_id();
+
+    The ID of the core to which a thread belongs. It is also printed in /proc/cpuinfo
+    "core_id."
+
+
+
+System topology examples
+========================
+
+.. note::
+  The alternative Linux CPU enumeration depends on how the BIOS enumerates the
+  threads. Many BIOSes enumerate all threads 0 first and then all threads 1.
+  That has the "advantage" that the logical Linux CPU numbers of threads 0 stay
+  the same whether threads are enabled or not. That's merely an implementation
+  detail and has no practical impact.
+
+1) Single Package, Single Core::
+
+   [package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
+
+2) Single Package, Dual Core
+
+   a) One thread per core::
+
+       [package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
+                   -> [core 1] -> [thread 0] -> Linux CPU 1
+
+   b) Two threads per core::
+
+       [package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
+                               -> [thread 1] -> Linux CPU 1
+                   -> [core 1] -> [thread 0] -> Linux CPU 2
+                               -> [thread 1] -> Linux CPU 3
+
+      Alternative enumeration::
+
+       [package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
+                               -> [thread 1] -> Linux CPU 2
+                   -> [core 1] -> [thread 0] -> Linux CPU 1
+                               -> [thread 1] -> Linux CPU 3
+
+      AMD nomenclature for CMT systems::
+
+       [node 0] -> [Compute Unit 0] -> [Compute Unit Core 0] -> Linux CPU 0
+                                    -> [Compute Unit Core 1] -> Linux CPU 1
+                -> [Compute Unit 1] -> [Compute Unit Core 0] -> Linux CPU 2
+                                    -> [Compute Unit Core 1] -> Linux CPU 3
+
+4) Dual Package, Dual Core
+
+   a) One thread per core::
+
+       [package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
+                   -> [core 1] -> [thread 0] -> Linux CPU 1
+
+       [package 1] -> [core 0] -> [thread 0] -> Linux CPU 2
+                   -> [core 1] -> [thread 0] -> Linux CPU 3
+
+   b) Two threads per core::
+
+       [package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
+                               -> [thread 1] -> Linux CPU 1
+                   -> [core 1] -> [thread 0] -> Linux CPU 2
+                               -> [thread 1] -> Linux CPU 3
+
+       [package 1] -> [core 0] -> [thread 0] -> Linux CPU 4
+                               -> [thread 1] -> Linux CPU 5
+                   -> [core 1] -> [thread 0] -> Linux CPU 6
+                               -> [thread 1] -> Linux CPU 7
+
+      Alternative enumeration::
+
+       [package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
+                               -> [thread 1] -> Linux CPU 4
+                   -> [core 1] -> [thread 0] -> Linux CPU 1
+                               -> [thread 1] -> Linux CPU 5
+
+       [package 1] -> [core 0] -> [thread 0] -> Linux CPU 2
+                               -> [thread 1] -> Linux CPU 6
+                   -> [core 1] -> [thread 0] -> Linux CPU 3
+                               -> [thread 1] -> Linux CPU 7
+
+      AMD nomenclature for CMT systems::
+
+       [node 0] -> [Compute Unit 0] -> [Compute Unit Core 0] -> Linux CPU 0
+                                    -> [Compute Unit Core 1] -> Linux CPU 1
+                -> [Compute Unit 1] -> [Compute Unit Core 0] -> Linux CPU 2
+                                    -> [Compute Unit Core 1] -> Linux CPU 3
+
+       [node 1] -> [Compute Unit 0] -> [Compute Unit Core 0] -> Linux CPU 4
+                                    -> [Compute Unit Core 1] -> Linux CPU 5
+                -> [Compute Unit 1] -> [Compute Unit Core 0] -> Linux CPU 6
+                                    -> [Compute Unit Core 1] -> Linux CPU 7
diff --git a/Documentation/x86/topology.txt b/Documentation/x86/topology.txt
deleted file mode 100644 (file)
index 06b3cdb..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-x86 Topology
-============
-
-This documents and clarifies the main aspects of x86 topology modelling and
-representation in the kernel. Update/change when doing changes to the
-respective code.
-
-The architecture-agnostic topology definitions are in
-Documentation/cputopology.txt. This file holds x86-specific
-differences/specialities which must not necessarily apply to the generic
-definitions. Thus, the way to read up on Linux topology on x86 is to start
-with the generic one and look at this one in parallel for the x86 specifics.
-
-Needless to say, code should use the generic functions - this file is *only*
-here to *document* the inner workings of x86 topology.
-
-Started by Thomas Gleixner <tglx@linutronix.de> and Borislav Petkov <bp@alien8.de>.
-
-The main aim of the topology facilities is to present adequate interfaces to
-code which needs to know/query/use the structure of the running system wrt
-threads, cores, packages, etc.
-
-The kernel does not care about the concept of physical sockets because a
-socket has no relevance to software. It's an electromechanical component. In
-the past a socket always contained a single package (see below), but with the
-advent of Multi Chip Modules (MCM) a socket can hold more than one package. So
-there might be still references to sockets in the code, but they are of
-historical nature and should be cleaned up.
-
-The topology of a system is described in the units of:
-
-    - packages
-    - cores
-    - threads
-
-* Package:
-
-  Packages contain a number of cores plus shared resources, e.g. DRAM
-  controller, shared caches etc.
-
-  AMD nomenclature for package is 'Node'.
-
-  Package-related topology information in the kernel:
-
-  - cpuinfo_x86.x86_max_cores:
-
-    The number of cores in a package. This information is retrieved via CPUID.
-
-  - cpuinfo_x86.phys_proc_id:
-
-    The physical ID of the package. This information is retrieved via CPUID
-    and deduced from the APIC IDs of the cores in the package.
-
-  - cpuinfo_x86.logical_proc_id:
-
-    The logical ID of the package. As we do not trust BIOSes to enumerate the
-    packages in a consistent way, we introduced the concept of logical package
-    ID so we can sanely calculate the number of maximum possible packages in
-    the system and have the packages enumerated linearly.
-
-  - topology_max_packages():
-
-    The maximum possible number of packages in the system. Helpful for per
-    package facilities to preallocate per package information.
-
-  - cpu_llc_id:
-
-    A per-CPU variable containing:
-    - On Intel, the first APIC ID of the list of CPUs sharing the Last Level
-    Cache
-
-    - On AMD, the Node ID or Core Complex ID containing the Last Level
-    Cache. In general, it is a number identifying an LLC uniquely on the
-    system.
-
-* Cores:
-
-  A core consists of 1 or more threads. It does not matter whether the threads
-  are SMT- or CMT-type threads.
-
-  AMDs nomenclature for a CMT core is "Compute Unit". The kernel always uses
-  "core".
-
-  Core-related topology information in the kernel:
-
-  - smp_num_siblings:
-
-    The number of threads in a core. The number of threads in a package can be
-    calculated by:
-
-       threads_per_package = cpuinfo_x86.x86_max_cores * smp_num_siblings
-
-
-* Threads:
-
-  A thread is a single scheduling unit. It's the equivalent to a logical Linux
-  CPU.
-
-  AMDs nomenclature for CMT threads is "Compute Unit Core". The kernel always
-  uses "thread".
-
-  Thread-related topology information in the kernel:
-
-  - topology_core_cpumask():
-
-    The cpumask contains all online threads in the package to which a thread
-    belongs.
-
-    The number of online threads is also printed in /proc/cpuinfo "siblings."
-
-  - topology_sibling_cpumask():
-
-    The cpumask contains all online threads in the core to which a thread
-    belongs.
-
-   - topology_logical_package_id():
-
-    The logical package ID to which a thread belongs.
-
-   - topology_physical_package_id():
-
-    The physical package ID to which a thread belongs.
-
-   - topology_core_id();
-
-    The ID of the core to which a thread belongs. It is also printed in /proc/cpuinfo
-    "core_id."
-
-
-
-System topology examples
-
-Note:
-
-The alternative Linux CPU enumeration depends on how the BIOS enumerates the
-threads. Many BIOSes enumerate all threads 0 first and then all threads 1.
-That has the "advantage" that the logical Linux CPU numbers of threads 0 stay
-the same whether threads are enabled or not. That's merely an implementation
-detail and has no practical impact.
-
-1) Single Package, Single Core
-
-   [package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
-
-2) Single Package, Dual Core
-
-   a) One thread per core
-
-       [package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
-                   -> [core 1] -> [thread 0] -> Linux CPU 1
-
-   b) Two threads per core
-
-       [package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
-                               -> [thread 1] -> Linux CPU 1
-                   -> [core 1] -> [thread 0] -> Linux CPU 2
-                               -> [thread 1] -> Linux CPU 3
-
-      Alternative enumeration:
-
-       [package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
-                               -> [thread 1] -> Linux CPU 2
-                   -> [core 1] -> [thread 0] -> Linux CPU 1
-                               -> [thread 1] -> Linux CPU 3
-
-      AMD nomenclature for CMT systems:
-
-       [node 0] -> [Compute Unit 0] -> [Compute Unit Core 0] -> Linux CPU 0
-                                    -> [Compute Unit Core 1] -> Linux CPU 1
-                -> [Compute Unit 1] -> [Compute Unit Core 0] -> Linux CPU 2
-                                    -> [Compute Unit Core 1] -> Linux CPU 3
-
-4) Dual Package, Dual Core
-
-   a) One thread per core
-
-       [package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
-                   -> [core 1] -> [thread 0] -> Linux CPU 1
-
-       [package 1] -> [core 0] -> [thread 0] -> Linux CPU 2
-                   -> [core 1] -> [thread 0] -> Linux CPU 3
-
-   b) Two threads per core
-
-       [package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
-                               -> [thread 1] -> Linux CPU 1
-                   -> [core 1] -> [thread 0] -> Linux CPU 2
-                               -> [thread 1] -> Linux CPU 3
-
-       [package 1] -> [core 0] -> [thread 0] -> Linux CPU 4
-                               -> [thread 1] -> Linux CPU 5
-                   -> [core 1] -> [thread 0] -> Linux CPU 6
-                               -> [thread 1] -> Linux CPU 7
-
-      Alternative enumeration:
-
-       [package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
-                               -> [thread 1] -> Linux CPU 4
-                   -> [core 1] -> [thread 0] -> Linux CPU 1
-                               -> [thread 1] -> Linux CPU 5
-
-       [package 1] -> [core 0] -> [thread 0] -> Linux CPU 2
-                               -> [thread 1] -> Linux CPU 6
-                   -> [core 1] -> [thread 0] -> Linux CPU 3
-                               -> [thread 1] -> Linux CPU 7
-
-      AMD nomenclature for CMT systems:
-
-       [node 0] -> [Compute Unit 0] -> [Compute Unit Core 0] -> Linux CPU 0
-                                    -> [Compute Unit Core 1] -> Linux CPU 1
-                -> [Compute Unit 1] -> [Compute Unit Core 0] -> Linux CPU 2
-                                    -> [Compute Unit Core 1] -> Linux CPU 3
-
-       [node 1] -> [Compute Unit 0] -> [Compute Unit Core 0] -> Linux CPU 4
-                                    -> [Compute Unit Core 1] -> Linux CPU 5
-                -> [Compute Unit 1] -> [Compute Unit Core 0] -> Linux CPU 6
-                                    -> [Compute Unit Core 1] -> Linux CPU 7
diff --git a/Documentation/x86/usb-legacy-support.rst b/Documentation/x86/usb-legacy-support.rst
new file mode 100644 (file)
index 0000000..e01c08b
--- /dev/null
@@ -0,0 +1,50 @@
+
+.. SPDX-License-Identifier: GPL-2.0
+
+==================
+USB Legacy support
+==================
+
+:Author: Vojtech Pavlik <vojtech@suse.cz>, January 2004
+
+
+Also known as "USB Keyboard" or "USB Mouse support" in the BIOS Setup is a
+feature that allows one to use the USB mouse and keyboard as if they were
+their classic PS/2 counterparts.  This means one can use an USB keyboard to
+type in LILO for example.
+
+It has several drawbacks, though:
+
+1) On some machines, the emulated PS/2 mouse takes over even when no USB
+   mouse is present and a real PS/2 mouse is present.  In that case the extra
+   features (wheel, extra buttons, touchpad mode) of the real PS/2 mouse may
+   not be available.
+
+2) If CONFIG_HIGHMEM64G is enabled, the PS/2 mouse emulation can cause
+   system crashes, because the SMM BIOS is not expecting to be in PAE mode.
+   The Intel E7505 is a typical machine where this happens.
+
+3) If AMD64 64-bit mode is enabled, again system crashes often happen,
+   because the SMM BIOS isn't expecting the CPU to be in 64-bit mode.  The
+   BIOS manufacturers only test with Windows, and Windows doesn't do 64-bit
+   yet.
+
+Solutions:
+
+Problem 1)
+  can be solved by loading the USB drivers prior to loading the
+  PS/2 mouse driver. Since the PS/2 mouse driver is in 2.6 compiled into
+  the kernel unconditionally, this means the USB drivers need to be
+  compiled-in, too.
+
+Problem 2)
+  can currently only be solved by either disabling HIGHMEM64G
+  in the kernel config or USB Legacy support in the BIOS. A BIOS update
+  could help, but so far no such update exists.
+
+Problem 3)
+  is usually fixed by a BIOS update. Check the board
+  manufacturers web site. If an update is not available, disable USB
+  Legacy support in the BIOS. If this alone doesn't help, try also adding
+  idle=poll on the kernel command line. The BIOS may be entering the SMM
+  on the HLT instruction as well.
diff --git a/Documentation/x86/usb-legacy-support.txt b/Documentation/x86/usb-legacy-support.txt
deleted file mode 100644 (file)
index 1894cdf..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-USB Legacy support
-~~~~~~~~~~~~~~~~~~
-
-Vojtech Pavlik <vojtech@suse.cz>, January 2004
-
-
-Also known as "USB Keyboard" or "USB Mouse support" in the BIOS Setup is a
-feature that allows one to use the USB mouse and keyboard as if they were
-their classic PS/2 counterparts.  This means one can use an USB keyboard to
-type in LILO for example.
-
-It has several drawbacks, though:
-
-1) On some machines, the emulated PS/2 mouse takes over even when no USB
-   mouse is present and a real PS/2 mouse is present.  In that case the extra
-   features (wheel, extra buttons, touchpad mode) of the real PS/2 mouse may
-   not be available.
-
-2) If CONFIG_HIGHMEM64G is enabled, the PS/2 mouse emulation can cause
-   system crashes, because the SMM BIOS is not expecting to be in PAE mode.
-   The Intel E7505 is a typical machine where this happens.
-
-3) If AMD64 64-bit mode is enabled, again system crashes often happen,
-   because the SMM BIOS isn't expecting the CPU to be in 64-bit mode.  The
-   BIOS manufacturers only test with Windows, and Windows doesn't do 64-bit
-   yet.
-
-Solutions:
-
-Problem 1) can be solved by loading the USB drivers prior to loading the
-PS/2 mouse driver. Since the PS/2 mouse driver is in 2.6 compiled into
-the kernel unconditionally, this means the USB drivers need to be
-compiled-in, too.
-
-Problem 2) can currently only be solved by either disabling HIGHMEM64G
-in the kernel config or USB Legacy support in the BIOS. A BIOS update
-could help, but so far no such update exists.
-
-Problem 3) is usually fixed by a BIOS update. Check the board
-manufacturers web site. If an update is not available, disable USB
-Legacy support in the BIOS. If this alone doesn't help, try also adding
-idle=poll on the kernel command line. The BIOS may be entering the SMM
-on the HLT instruction as well.
-
diff --git a/Documentation/x86/x86_64/5level-paging.rst b/Documentation/x86/x86_64/5level-paging.rst
new file mode 100644 (file)
index 0000000..ab88a45
--- /dev/null
@@ -0,0 +1,67 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==============
+5-level paging
+==============
+
+Overview
+========
+Original x86-64 was limited by 4-level paing to 256 TiB of virtual address
+space and 64 TiB of physical address space. We are already bumping into
+this limit: some vendors offers servers with 64 TiB of memory today.
+
+To overcome the limitation upcoming hardware will introduce support for
+5-level paging. It is a straight-forward extension of the current page
+table structure adding one more layer of translation.
+
+It bumps the limits to 128 PiB of virtual address space and 4 PiB of
+physical address space. This "ought to be enough for anybody" ©.
+
+QEMU 2.9 and later support 5-level paging.
+
+Virtual memory layout for 5-level paging is described in
+Documentation/x86/x86_64/mm.txt
+
+
+Enabling 5-level paging
+=======================
+CONFIG_X86_5LEVEL=y enables the feature.
+
+Kernel with CONFIG_X86_5LEVEL=y still able to boot on 4-level hardware.
+In this case additional page table level -- p4d -- will be folded at
+runtime.
+
+User-space and large virtual address space
+==========================================
+On x86, 5-level paging enables 56-bit userspace virtual address space.
+Not all user space is ready to handle wide addresses. It's known that
+at least some JIT compilers use higher bits in pointers to encode their
+information. It collides with valid pointers with 5-level paging and
+leads to crashes.
+
+To mitigate this, we are not going to allocate virtual address space
+above 47-bit by default.
+
+But userspace can ask for allocation from full address space by
+specifying hint address (with or without MAP_FIXED) above 47-bits.
+
+If hint address set above 47-bit, but MAP_FIXED is not specified, we try
+to look for unmapped area by specified address. If it's already
+occupied, we look for unmapped area in *full* address space, rather than
+from 47-bit window.
+
+A high hint address would only affect the allocation in question, but not
+any future mmap()s.
+
+Specifying high hint address on older kernel or on machine without 5-level
+paging support is safe. The hint will be ignored and kernel will fall back
+to allocation from 47-bit address space.
+
+This approach helps to easily make application's memory allocator aware
+about large address space without manually tracking allocated virtual
+address space.
+
+One important case we need to handle here is interaction with MPX.
+MPX (without MAWA extension) cannot handle addresses above 47-bit, so we
+need to make sure that MPX cannot be enabled we already have VMA above
+the boundary and forbid creating such VMAs once MPX is enabled.
diff --git a/Documentation/x86/x86_64/5level-paging.txt b/Documentation/x86/x86_64/5level-paging.txt
deleted file mode 100644 (file)
index 2432a5e..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-== Overview ==
-
-Original x86-64 was limited by 4-level paing to 256 TiB of virtual address
-space and 64 TiB of physical address space. We are already bumping into
-this limit: some vendors offers servers with 64 TiB of memory today.
-
-To overcome the limitation upcoming hardware will introduce support for
-5-level paging. It is a straight-forward extension of the current page
-table structure adding one more layer of translation.
-
-It bumps the limits to 128 PiB of virtual address space and 4 PiB of
-physical address space. This "ought to be enough for anybody" ©.
-
-QEMU 2.9 and later support 5-level paging.
-
-Virtual memory layout for 5-level paging is described in
-Documentation/x86/x86_64/mm.txt
-
-== Enabling 5-level paging ==
-
-CONFIG_X86_5LEVEL=y enables the feature.
-
-Kernel with CONFIG_X86_5LEVEL=y still able to boot on 4-level hardware.
-In this case additional page table level -- p4d -- will be folded at
-runtime.
-
-== User-space and large virtual address space ==
-
-On x86, 5-level paging enables 56-bit userspace virtual address space.
-Not all user space is ready to handle wide addresses. It's known that
-at least some JIT compilers use higher bits in pointers to encode their
-information. It collides with valid pointers with 5-level paging and
-leads to crashes.
-
-To mitigate this, we are not going to allocate virtual address space
-above 47-bit by default.
-
-But userspace can ask for allocation from full address space by
-specifying hint address (with or without MAP_FIXED) above 47-bits.
-
-If hint address set above 47-bit, but MAP_FIXED is not specified, we try
-to look for unmapped area by specified address. If it's already
-occupied, we look for unmapped area in *full* address space, rather than
-from 47-bit window.
-
-A high hint address would only affect the allocation in question, but not
-any future mmap()s.
-
-Specifying high hint address on older kernel or on machine without 5-level
-paging support is safe. The hint will be ignored and kernel will fall back
-to allocation from 47-bit address space.
-
-This approach helps to easily make application's memory allocator aware
-about large address space without manually tracking allocated virtual
-address space.
-
-One important case we need to handle here is interaction with MPX.
-MPX (without MAWA extension) cannot handle addresses above 47-bit, so we
-need to make sure that MPX cannot be enabled we already have VMA above
-the boundary and forbid creating such VMAs once MPX is enabled.
-
diff --git a/Documentation/x86/x86_64/boot-options.rst b/Documentation/x86/x86_64/boot-options.rst
new file mode 100644 (file)
index 0000000..2f69836
--- /dev/null
@@ -0,0 +1,335 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===========================
+AMD64 Specific Boot Options
+===========================
+
+There are many others (usually documented in driver documentation), but
+only the AMD64 specific ones are listed here.
+
+Machine check
+=============
+Please see Documentation/x86/x86_64/machinecheck for sysfs runtime tunables.
+
+   mce=off
+               Disable machine check
+   mce=no_cmci
+               Disable CMCI(Corrected Machine Check Interrupt) that
+               Intel processor supports.  Usually this disablement is
+               not recommended, but it might be handy if your hardware
+               is misbehaving.
+               Note that you'll get more problems without CMCI than with
+               due to the shared banks, i.e. you might get duplicated
+               error logs.
+   mce=dont_log_ce
+               Don't make logs for corrected errors.  All events reported
+               as corrected are silently cleared by OS.
+               This option will be useful if you have no interest in any
+               of corrected errors.
+   mce=ignore_ce
+               Disable features for corrected errors, e.g. polling timer
+               and CMCI.  All events reported as corrected are not cleared
+               by OS and remained in its error banks.
+               Usually this disablement is not recommended, however if
+               there is an agent checking/clearing corrected errors
+               (e.g. BIOS or hardware monitoring applications), conflicting
+               with OS's error handling, and you cannot deactivate the agent,
+               then this option will be a help.
+   mce=no_lmce
+               Do not opt-in to Local MCE delivery. Use legacy method
+               to broadcast MCEs.
+   mce=bootlog
+               Enable logging of machine checks left over from booting.
+               Disabled by default on AMD Fam10h and older because some BIOS
+               leave bogus ones.
+               If your BIOS doesn't do that it's a good idea to enable though
+               to make sure you log even machine check events that result
+               in a reboot. On Intel systems it is enabled by default.
+   mce=nobootlog
+               Disable boot machine check logging.
+   mce=tolerancelevel[,monarchtimeout] (number,number)
+               tolerance levels:
+               0: always panic on uncorrected errors, log corrected errors
+               1: panic or SIGBUS on uncorrected errors, log corrected errors
+               2: SIGBUS or log uncorrected errors, log corrected errors
+               3: never panic or SIGBUS, log all errors (for testing only)
+               Default is 1
+               Can be also set using sysfs which is preferable.
+               monarchtimeout:
+               Sets the time in us to wait for other CPUs on machine checks. 0
+               to disable.
+   mce=bios_cmci_threshold
+               Don't overwrite the bios-set CMCI threshold. This boot option
+               prevents Linux from overwriting the CMCI threshold set by the
+               bios. Without this option, Linux always sets the CMCI
+               threshold to 1. Enabling this may make memory predictive failure
+               analysis less effective if the bios sets thresholds for memory
+               errors since we will not see details for all errors.
+   mce=recovery
+               Force-enable recoverable machine check code paths
+
+   nomce (for compatibility with i386)
+               same as mce=off
+
+   Everything else is in sysfs now.
+
+APICs
+=====
+
+   apic
+       Use IO-APIC. Default
+
+   noapic
+       Don't use the IO-APIC.
+
+   disableapic
+       Don't use the local APIC
+
+   nolapic
+     Don't use the local APIC (alias for i386 compatibility)
+
+   pirq=...
+       See Documentation/x86/i386/IO-APIC.txt
+
+   noapictimer
+       Don't set up the APIC timer
+
+   no_timer_check
+       Don't check the IO-APIC timer. This can work around
+       problems with incorrect timer initialization on some boards.
+
+   apicpmtimer
+       Do APIC timer calibration using the pmtimer. Implies
+       apicmaintimer. Useful when your PIT timer is totally broken.
+
+Timing
+======
+
+  notsc
+    Deprecated, use tsc=unstable instead.
+
+  nohpet
+    Don't use the HPET timer.
+
+Idle loop
+=========
+
+  idle=poll
+    Don't do power saving in the idle loop using HLT, but poll for rescheduling
+    event. This will make the CPUs eat a lot more power, but may be useful
+    to get slightly better performance in multiprocessor benchmarks. It also
+    makes some profiling using performance counters more accurate.
+    Please note that on systems with MONITOR/MWAIT support (like Intel EM64T
+    CPUs) this option has no performance advantage over the normal idle loop.
+    It may also interact badly with hyperthreading.
+
+Rebooting
+=========
+
+   reboot=b[ios] | t[riple] | k[bd] | a[cpi] | e[fi] [, [w]arm | [c]old]
+      bios
+        Use the CPU reboot vector for warm reset
+      warm
+        Don't set the cold reboot flag
+      cold
+        Set the cold reboot flag
+      triple
+        Force a triple fault (init)
+      kbd
+        Use the keyboard controller. cold reset (default)
+      acpi
+        Use the ACPI RESET_REG in the FADT. If ACPI is not configured or
+        the ACPI reset does not work, the reboot path attempts the reset
+        using the keyboard controller.
+      efi
+        Use efi reset_system runtime service. If EFI is not configured or
+        the EFI reset does not work, the reboot path attempts the reset using
+        the keyboard controller.
+
+   Using warm reset will be much faster especially on big memory
+   systems because the BIOS will not go through the memory check.
+   Disadvantage is that not all hardware will be completely reinitialized
+   on reboot so there may be boot problems on some systems.
+
+   reboot=force
+     Don't stop other CPUs on reboot. This can make reboot more reliable
+     in some cases.
+
+Non Executable Mappings
+=======================
+
+  noexec=on|off
+    on
+      Enable(default)
+    off
+      Disable
+
+NUMA
+====
+
+  numa=off
+    Only set up a single NUMA node spanning all memory.
+
+  numa=noacpi
+    Don't parse the SRAT table for NUMA setup
+
+  numa=fake=<size>[MG]
+    If given as a memory unit, fills all system RAM with nodes of
+    size interleaved over physical nodes.
+
+  numa=fake=<N>
+    If given as an integer, fills all system RAM with N fake nodes
+    interleaved over physical nodes.
+
+  numa=fake=<N>U
+    If given as an integer followed by 'U', it will divide each
+    physical node into N emulated nodes.
+
+ACPI
+====
+
+  acpi=off
+    Don't enable ACPI
+  acpi=ht
+    Use ACPI boot table parsing, but don't enable ACPI interpreter
+  acpi=force
+    Force ACPI on (currently not needed)
+  acpi=strict
+    Disable out of spec ACPI workarounds.
+  acpi_sci={edge,level,high,low}
+    Set up ACPI SCI interrupt.
+  acpi=noirq
+    Don't route interrupts
+  acpi=nocmcff
+    Disable firmware first mode for corrected errors. This
+    disables parsing the HEST CMC error source to check if
+    firmware has set the FF flag. This may result in
+    duplicate corrected error reports.
+
+PCI
+===
+
+  pci=off
+    Don't use PCI
+  pci=conf1
+    Use conf1 access.
+  pci=conf2
+    Use conf2 access.
+  pci=rom
+    Assign ROMs.
+  pci=assign-busses
+    Assign busses
+  pci=irqmask=MASK
+    Set PCI interrupt mask to MASK
+  pci=lastbus=NUMBER
+    Scan up to NUMBER busses, no matter what the mptable says.
+  pci=noacpi
+    Don't use ACPI to set up PCI interrupt routing.
+
+IOMMU (input/output memory management unit)
+===========================================
+Multiple x86-64 PCI-DMA mapping implementations exist, for example:
+
+   1. <lib/dma-direct.c>: use no hardware/software IOMMU at all
+      (e.g. because you have < 3 GB memory).
+      Kernel boot message: "PCI-DMA: Disabling IOMMU"
+
+   2. <arch/x86/kernel/amd_gart_64.c>: AMD GART based hardware IOMMU.
+      Kernel boot message: "PCI-DMA: using GART IOMMU"
+
+   3. <arch/x86_64/kernel/pci-swiotlb.c> : Software IOMMU implementation. Used
+      e.g. if there is no hardware IOMMU in the system and it is need because
+      you have >3GB memory or told the kernel to us it (iommu=soft))
+      Kernel boot message: "PCI-DMA: Using software bounce buffering
+      for IO (SWIOTLB)"
+
+   4. <arch/x86_64/pci-calgary.c> : IBM Calgary hardware IOMMU. Used in IBM
+      pSeries and xSeries servers. This hardware IOMMU supports DMA address
+      mapping with memory protection, etc.
+      Kernel boot message: "PCI-DMA: Using Calgary IOMMU"
+
+::
+
+  iommu=[<size>][,noagp][,off][,force][,noforce]
+  [,memaper[=<order>]][,merge][,fullflush][,nomerge]
+  [,noaperture][,calgary]
+
+General iommu options:
+
+    off
+      Don't initialize and use any kind of IOMMU.
+    noforce
+      Don't force hardware IOMMU usage when it is not needed. (default).
+    force
+      Force the use of the hardware IOMMU even when it is
+      not actually needed (e.g. because < 3 GB memory).
+    soft
+      Use software bounce buffering (SWIOTLB) (default for
+      Intel machines). This can be used to prevent the usage
+      of an available hardware IOMMU.
+
+iommu options only relevant to the AMD GART hardware IOMMU:
+
+    <size>
+      Set the size of the remapping area in bytes.
+    allowed
+      Overwrite iommu off workarounds for specific chipsets.
+    fullflush
+      Flush IOMMU on each allocation (default).
+    nofullflush
+      Don't use IOMMU fullflush.
+    memaper[=<order>]
+      Allocate an own aperture over RAM with size 32MB<<order.
+      (default: order=1, i.e. 64MB)
+    merge
+      Do scatter-gather (SG) merging. Implies "force" (experimental).
+    nomerge
+      Don't do scatter-gather (SG) merging.
+    noaperture
+      Ask the IOMMU not to touch the aperture for AGP.
+    noagp
+      Don't initialize the AGP driver and use full aperture.
+    panic
+      Always panic when IOMMU overflows.
+    calgary
+      Use the Calgary IOMMU if it is available
+
+iommu options only relevant to the software bounce buffering (SWIOTLB) IOMMU
+implementation:
+
+    swiotlb=<pages>[,force]
+      <pages>
+        Prereserve that many 128K pages for the software IO bounce buffering.
+      force
+        Force all IO through the software TLB.
+
+Settings for the IBM Calgary hardware IOMMU currently found in IBM
+pSeries and xSeries machines
+
+    calgary=[64k,128k,256k,512k,1M,2M,4M,8M]
+      Set the size of each PCI slot's translation table when using the
+      Calgary IOMMU. This is the size of the translation table itself
+      in main memory. The smallest table, 64k, covers an IO space of
+      32MB; the largest, 8MB table, can cover an IO space of 4GB.
+      Normally the kernel will make the right choice by itself.
+    calgary=[translate_empty_slots]
+      Enable translation even on slots that have no devices attached to
+      them, in case a device will be hotplugged in the future.
+    calgary=[disable=<PCI bus number>]
+      Disable translation on a given PHB. For
+      example, the built-in graphics adapter resides on the first bridge
+      (PCI bus number 0); if translation (isolation) is enabled on this
+      bridge, X servers that access the hardware directly from user
+      space might stop working. Use this option if you have devices that
+      are accessed from userspace directly on some PCI host bridge.
+    panic
+      Always panic when IOMMU overflows
+
+
+Miscellaneous
+=============
+
+  nogbpages
+    Do not use GB pages for kernel direct mappings.
+  gbpages
+    Use GB pages for kernel direct mappings.
diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt
deleted file mode 100644 (file)
index abc5388..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-AMD64 specific boot options
-
-There are many others (usually documented in driver documentation), but
-only the AMD64 specific ones are listed here.
-
-Machine check
-
-   Please see Documentation/x86/x86_64/machinecheck for sysfs runtime tunables.
-
-   mce=off
-               Disable machine check
-   mce=no_cmci
-               Disable CMCI(Corrected Machine Check Interrupt) that
-               Intel processor supports.  Usually this disablement is
-               not recommended, but it might be handy if your hardware
-               is misbehaving.
-               Note that you'll get more problems without CMCI than with
-               due to the shared banks, i.e. you might get duplicated
-               error logs.
-   mce=dont_log_ce
-               Don't make logs for corrected errors.  All events reported
-               as corrected are silently cleared by OS.
-               This option will be useful if you have no interest in any
-               of corrected errors.
-   mce=ignore_ce
-               Disable features for corrected errors, e.g. polling timer
-               and CMCI.  All events reported as corrected are not cleared
-               by OS and remained in its error banks.
-               Usually this disablement is not recommended, however if
-               there is an agent checking/clearing corrected errors
-               (e.g. BIOS or hardware monitoring applications), conflicting
-               with OS's error handling, and you cannot deactivate the agent,
-               then this option will be a help.
-   mce=no_lmce
-               Do not opt-in to Local MCE delivery. Use legacy method
-               to broadcast MCEs.
-   mce=bootlog
-               Enable logging of machine checks left over from booting.
-               Disabled by default on AMD Fam10h and older because some BIOS
-               leave bogus ones.
-               If your BIOS doesn't do that it's a good idea to enable though
-               to make sure you log even machine check events that result
-               in a reboot. On Intel systems it is enabled by default.
-   mce=nobootlog
-               Disable boot machine check logging.
-   mce=tolerancelevel[,monarchtimeout] (number,number)
-               tolerance levels:
-               0: always panic on uncorrected errors, log corrected errors
-               1: panic or SIGBUS on uncorrected errors, log corrected errors
-               2: SIGBUS or log uncorrected errors, log corrected errors
-               3: never panic or SIGBUS, log all errors (for testing only)
-               Default is 1
-               Can be also set using sysfs which is preferable.
-               monarchtimeout:
-               Sets the time in us to wait for other CPUs on machine checks. 0
-               to disable.
-   mce=bios_cmci_threshold
-               Don't overwrite the bios-set CMCI threshold. This boot option
-               prevents Linux from overwriting the CMCI threshold set by the
-               bios. Without this option, Linux always sets the CMCI
-               threshold to 1. Enabling this may make memory predictive failure
-               analysis less effective if the bios sets thresholds for memory
-               errors since we will not see details for all errors.
-   mce=recovery
-               Force-enable recoverable machine check code paths
-
-   nomce (for compatibility with i386): same as mce=off
-
-   Everything else is in sysfs now.
-
-APICs
-
-   apic                 Use IO-APIC. Default
-
-   noapic       Don't use the IO-APIC.
-
-   disableapic  Don't use the local APIC
-
-   nolapic      Don't use the local APIC (alias for i386 compatibility)
-
-   pirq=...     See Documentation/x86/i386/IO-APIC.txt
-
-   noapictimer  Don't set up the APIC timer
-
-   no_timer_check Don't check the IO-APIC timer. This can work around
-                problems with incorrect timer initialization on some boards.
-   apicpmtimer
-                Do APIC timer calibration using the pmtimer. Implies
-                apicmaintimer. Useful when your PIT timer is totally
-                broken.
-
-Timing
-
-  notsc
-  Deprecated, use tsc=unstable instead.
-
-  nohpet
-  Don't use the HPET timer.
-
-Idle loop
-
-  idle=poll
-  Don't do power saving in the idle loop using HLT, but poll for rescheduling
-  event. This will make the CPUs eat a lot more power, but may be useful
-  to get slightly better performance in multiprocessor benchmarks. It also
-  makes some profiling using performance counters more accurate.
-  Please note that on systems with MONITOR/MWAIT support (like Intel EM64T
-  CPUs) this option has no performance advantage over the normal idle loop.
-  It may also interact badly with hyperthreading.
-
-Rebooting
-
-   reboot=b[ios] | t[riple] | k[bd] | a[cpi] | e[fi] [, [w]arm | [c]old]
-   bios          Use the CPU reboot vector for warm reset
-   warm   Don't set the cold reboot flag
-   cold   Set the cold reboot flag
-   triple Force a triple fault (init)
-   kbd    Use the keyboard controller. cold reset (default)
-   acpi   Use the ACPI RESET_REG in the FADT. If ACPI is not configured or the
-          ACPI reset does not work, the reboot path attempts the reset using
-          the keyboard controller.
-   efi    Use efi reset_system runtime service. If EFI is not configured or the
-          EFI reset does not work, the reboot path attempts the reset using
-          the keyboard controller.
-
-   Using warm reset will be much faster especially on big memory
-   systems because the BIOS will not go through the memory check.
-   Disadvantage is that not all hardware will be completely reinitialized
-   on reboot so there may be boot problems on some systems.
-
-   reboot=force
-
-   Don't stop other CPUs on reboot. This can make reboot more reliable
-   in some cases.
-
-Non Executable Mappings
-
-  noexec=on|off
-
-  on      Enable(default)
-  off     Disable
-
-NUMA
-
-  numa=off     Only set up a single NUMA node spanning all memory.
-
-  numa=noacpi   Don't parse the SRAT table for NUMA setup
-
-  numa=fake=<size>[MG]
-               If given as a memory unit, fills all system RAM with nodes of
-               size interleaved over physical nodes.
-
-  numa=fake=<N>
-               If given as an integer, fills all system RAM with N fake nodes
-               interleaved over physical nodes.
-
-  numa=fake=<N>U
-               If given as an integer followed by 'U', it will divide each
-               physical node into N emulated nodes.
-
-ACPI
-
-  acpi=off     Don't enable ACPI
-  acpi=ht      Use ACPI boot table parsing, but don't enable ACPI
-               interpreter
-  acpi=force   Force ACPI on (currently not needed)
-
-  acpi=strict   Disable out of spec ACPI workarounds.
-
-  acpi_sci={edge,level,high,low}  Set up ACPI SCI interrupt.
-
-  acpi=noirq   Don't route interrupts
-
-  acpi=nocmcff Disable firmware first mode for corrected errors. This
-               disables parsing the HEST CMC error source to check if
-               firmware has set the FF flag. This may result in
-               duplicate corrected error reports.
-
-PCI
-
-  pci=off              Don't use PCI
-  pci=conf1            Use conf1 access.
-  pci=conf2            Use conf2 access.
-  pci=rom              Assign ROMs.
-  pci=assign-busses    Assign busses
-  pci=irqmask=MASK     Set PCI interrupt mask to MASK
-  pci=lastbus=NUMBER   Scan up to NUMBER busses, no matter what the mptable says.
-  pci=noacpi           Don't use ACPI to set up PCI interrupt routing.
-
-IOMMU (input/output memory management unit)
-
- Multiple x86-64 PCI-DMA mapping implementations exist, for example:
-
-   1. <lib/dma-direct.c>: use no hardware/software IOMMU at all
-      (e.g. because you have < 3 GB memory).
-      Kernel boot message: "PCI-DMA: Disabling IOMMU"
-
-   2. <arch/x86/kernel/amd_gart_64.c>: AMD GART based hardware IOMMU.
-      Kernel boot message: "PCI-DMA: using GART IOMMU"
-
-   3. <arch/x86_64/kernel/pci-swiotlb.c> : Software IOMMU implementation. Used
-      e.g. if there is no hardware IOMMU in the system and it is need because
-      you have >3GB memory or told the kernel to us it (iommu=soft))
-      Kernel boot message: "PCI-DMA: Using software bounce buffering
-      for IO (SWIOTLB)"
-
-   4. <arch/x86_64/pci-calgary.c> : IBM Calgary hardware IOMMU. Used in IBM
-      pSeries and xSeries servers. This hardware IOMMU supports DMA address
-      mapping with memory protection, etc.
-      Kernel boot message: "PCI-DMA: Using Calgary IOMMU"
-
- iommu=[<size>][,noagp][,off][,force][,noforce]
-       [,memaper[=<order>]][,merge][,fullflush][,nomerge]
-       [,noaperture][,calgary]
-
-  General iommu options:
-    off                Don't initialize and use any kind of IOMMU.
-    noforce            Don't force hardware IOMMU usage when it is not needed.
-                       (default).
-    force              Force the use of the hardware IOMMU even when it is
-                       not actually needed (e.g. because < 3 GB memory).
-    soft               Use software bounce buffering (SWIOTLB) (default for
-                       Intel machines). This can be used to prevent the usage
-                       of an available hardware IOMMU.
-
-  iommu options only relevant to the AMD GART hardware IOMMU:
-    <size>             Set the size of the remapping area in bytes.
-    allowed            Overwrite iommu off workarounds for specific chipsets.
-    fullflush          Flush IOMMU on each allocation (default).
-    nofullflush        Don't use IOMMU fullflush.
-    memaper[=<order>]  Allocate an own aperture over RAM with size 32MB<<order.
-                       (default: order=1, i.e. 64MB)
-    merge              Do scatter-gather (SG) merging. Implies "force"
-                       (experimental).
-    nomerge            Don't do scatter-gather (SG) merging.
-    noaperture         Ask the IOMMU not to touch the aperture for AGP.
-    noagp              Don't initialize the AGP driver and use full aperture.
-    panic              Always panic when IOMMU overflows.
-    calgary            Use the Calgary IOMMU if it is available
-
-  iommu options only relevant to the software bounce buffering (SWIOTLB) IOMMU
-  implementation:
-    swiotlb=<pages>[,force]
-    <pages>            Prereserve that many 128K pages for the software IO
-                       bounce buffering.
-    force              Force all IO through the software TLB.
-
-  Settings for the IBM Calgary hardware IOMMU currently found in IBM
-  pSeries and xSeries machines:
-
-    calgary=[64k,128k,256k,512k,1M,2M,4M,8M]
-    calgary=[translate_empty_slots]
-    calgary=[disable=<PCI bus number>]
-    panic              Always panic when IOMMU overflows
-
-    64k,...,8M - Set the size of each PCI slot's translation table
-    when using the Calgary IOMMU. This is the size of the translation
-    table itself in main memory. The smallest table, 64k, covers an IO
-    space of 32MB; the largest, 8MB table, can cover an IO space of
-    4GB. Normally the kernel will make the right choice by itself.
-
-    translate_empty_slots - Enable translation even on slots that have
-    no devices attached to them, in case a device will be hotplugged
-    in the future.
-
-    disable=<PCI bus number> - Disable translation on a given PHB. For
-    example, the built-in graphics adapter resides on the first bridge
-    (PCI bus number 0); if translation (isolation) is enabled on this
-    bridge, X servers that access the hardware directly from user
-    space might stop working. Use this option if you have devices that
-    are accessed from userspace directly on some PCI host bridge.
-
-Miscellaneous
-
-       nogbpages
-               Do not use GB pages for kernel direct mappings.
-       gbpages
-               Use GB pages for kernel direct mappings.
diff --git a/Documentation/x86/x86_64/cpu-hotplug-spec b/Documentation/x86/x86_64/cpu-hotplug-spec
deleted file mode 100644 (file)
index 3c23e05..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-Firmware support for CPU hotplug under Linux/x86-64
----------------------------------------------------
-
-Linux/x86-64 supports CPU hotplug now. For various reasons Linux wants to
-know in advance of boot time the maximum number of CPUs that could be plugged
-into the system. ACPI 3.0 currently has no official way to supply
-this information from the firmware to the operating system.
-
-In ACPI each CPU needs an LAPIC object in the MADT table (5.2.11.5 in the
-ACPI 3.0 specification).  ACPI already has the concept of disabled LAPIC
-objects by setting the Enabled bit in the LAPIC object to zero.
-
-For CPU hotplug Linux/x86-64 expects now that any possible future hotpluggable
-CPU is already available in the MADT. If the CPU is not available yet
-it should have its LAPIC Enabled bit set to 0. Linux will use the number
-of disabled LAPICs to compute the maximum number of future CPUs.
-
-In the worst case the user can overwrite this choice using a command line
-option (additional_cpus=...), but it is recommended to supply the correct
-number (or a reasonable approximation of it, with erring towards more not less)
-in the MADT to avoid manual configuration.
diff --git a/Documentation/x86/x86_64/cpu-hotplug-spec.rst b/Documentation/x86/x86_64/cpu-hotplug-spec.rst
new file mode 100644 (file)
index 0000000..8d1c91f
--- /dev/null
@@ -0,0 +1,24 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===================================================
+Firmware support for CPU hotplug under Linux/x86-64
+===================================================
+
+Linux/x86-64 supports CPU hotplug now. For various reasons Linux wants to
+know in advance of boot time the maximum number of CPUs that could be plugged
+into the system. ACPI 3.0 currently has no official way to supply
+this information from the firmware to the operating system.
+
+In ACPI each CPU needs an LAPIC object in the MADT table (5.2.11.5 in the
+ACPI 3.0 specification).  ACPI already has the concept of disabled LAPIC
+objects by setting the Enabled bit in the LAPIC object to zero.
+
+For CPU hotplug Linux/x86-64 expects now that any possible future hotpluggable
+CPU is already available in the MADT. If the CPU is not available yet
+it should have its LAPIC Enabled bit set to 0. Linux will use the number
+of disabled LAPICs to compute the maximum number of future CPUs.
+
+In the worst case the user can overwrite this choice using a command line
+option (additional_cpus=...), but it is recommended to supply the correct
+number (or a reasonable approximation of it, with erring towards more not less)
+in the MADT to avoid manual configuration.
diff --git a/Documentation/x86/x86_64/fake-numa-for-cpusets b/Documentation/x86/x86_64/fake-numa-for-cpusets
deleted file mode 100644 (file)
index 4b09f18..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-Using numa=fake and CPUSets for Resource Management
-Written by David Rientjes <rientjes@cs.washington.edu>
-
-This document describes how the numa=fake x86_64 command-line option can be used
-in conjunction with cpusets for coarse memory management.  Using this feature,
-you can create fake NUMA nodes that represent contiguous chunks of memory and
-assign them to cpusets and their attached tasks.  This is a way of limiting the
-amount of system memory that are available to a certain class of tasks.
-
-For more information on the features of cpusets, see
-Documentation/cgroup-v1/cpusets.txt.
-There are a number of different configurations you can use for your needs.  For
-more information on the numa=fake command line option and its various ways of
-configuring fake nodes, see Documentation/x86/x86_64/boot-options.txt.
-
-For the purposes of this introduction, we'll assume a very primitive NUMA
-emulation setup of "numa=fake=4*512,".  This will split our system memory into
-four equal chunks of 512M each that we can now use to assign to cpusets.  As
-you become more familiar with using this combination for resource control,
-you'll determine a better setup to minimize the number of nodes you have to deal
-with.
-
-A machine may be split as follows with "numa=fake=4*512," as reported by dmesg:
-
-       Faking node 0 at 0000000000000000-0000000020000000 (512MB)
-       Faking node 1 at 0000000020000000-0000000040000000 (512MB)
-       Faking node 2 at 0000000040000000-0000000060000000 (512MB)
-       Faking node 3 at 0000000060000000-0000000080000000 (512MB)
-       ...
-       On node 0 totalpages: 130975
-       On node 1 totalpages: 131072
-       On node 2 totalpages: 131072
-       On node 3 totalpages: 131072
-
-Now following the instructions for mounting the cpusets filesystem from
-Documentation/cgroup-v1/cpusets.txt, you can assign fake nodes (i.e. contiguous memory
-address spaces) to individual cpusets:
-
-       [root@xroads /]# mkdir exampleset
-       [root@xroads /]# mount -t cpuset none exampleset
-       [root@xroads /]# mkdir exampleset/ddset
-       [root@xroads /]# cd exampleset/ddset
-       [root@xroads /exampleset/ddset]# echo 0-1 > cpus
-       [root@xroads /exampleset/ddset]# echo 0-1 > mems
-
-Now this cpuset, 'ddset', will only allowed access to fake nodes 0 and 1 for
-memory allocations (1G).
-
-You can now assign tasks to these cpusets to limit the memory resources
-available to them according to the fake nodes assigned as mems:
-
-       [root@xroads /exampleset/ddset]# echo $$ > tasks
-       [root@xroads /exampleset/ddset]# dd if=/dev/zero of=tmp bs=1024 count=1G
-       [1] 13425
-
-Notice the difference between the system memory usage as reported by
-/proc/meminfo between the restricted cpuset case above and the unrestricted
-case (i.e. running the same 'dd' command without assigning it to a fake NUMA
-cpuset):
-                               Unrestricted    Restricted
-       MemTotal:               3091900 kB      3091900 kB
-       MemFree:                  42113 kB      1513236 kB
-
-This allows for coarse memory management for the tasks you assign to particular
-cpusets.  Since cpusets can form a hierarchy, you can create some pretty
-interesting combinations of use-cases for various classes of tasks for your
-memory management needs.
diff --git a/Documentation/x86/x86_64/fake-numa-for-cpusets.rst b/Documentation/x86/x86_64/fake-numa-for-cpusets.rst
new file mode 100644 (file)
index 0000000..74fbb78
--- /dev/null
@@ -0,0 +1,78 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====================
+Fake NUMA For CPUSets
+=====================
+
+:Author: David Rientjes <rientjes@cs.washington.edu>
+
+Using numa=fake and CPUSets for Resource Management
+
+This document describes how the numa=fake x86_64 command-line option can be used
+in conjunction with cpusets for coarse memory management.  Using this feature,
+you can create fake NUMA nodes that represent contiguous chunks of memory and
+assign them to cpusets and their attached tasks.  This is a way of limiting the
+amount of system memory that are available to a certain class of tasks.
+
+For more information on the features of cpusets, see
+Documentation/cgroup-v1/cpusets.txt.
+There are a number of different configurations you can use for your needs.  For
+more information on the numa=fake command line option and its various ways of
+configuring fake nodes, see Documentation/x86/x86_64/boot-options.txt.
+
+For the purposes of this introduction, we'll assume a very primitive NUMA
+emulation setup of "numa=fake=4*512,".  This will split our system memory into
+four equal chunks of 512M each that we can now use to assign to cpusets.  As
+you become more familiar with using this combination for resource control,
+you'll determine a better setup to minimize the number of nodes you have to deal
+with.
+
+A machine may be split as follows with "numa=fake=4*512," as reported by dmesg::
+
+       Faking node 0 at 0000000000000000-0000000020000000 (512MB)
+       Faking node 1 at 0000000020000000-0000000040000000 (512MB)
+       Faking node 2 at 0000000040000000-0000000060000000 (512MB)
+       Faking node 3 at 0000000060000000-0000000080000000 (512MB)
+       ...
+       On node 0 totalpages: 130975
+       On node 1 totalpages: 131072
+       On node 2 totalpages: 131072
+       On node 3 totalpages: 131072
+
+Now following the instructions for mounting the cpusets filesystem from
+Documentation/cgroup-v1/cpusets.txt, you can assign fake nodes (i.e. contiguous memory
+address spaces) to individual cpusets::
+
+       [root@xroads /]# mkdir exampleset
+       [root@xroads /]# mount -t cpuset none exampleset
+       [root@xroads /]# mkdir exampleset/ddset
+       [root@xroads /]# cd exampleset/ddset
+       [root@xroads /exampleset/ddset]# echo 0-1 > cpus
+       [root@xroads /exampleset/ddset]# echo 0-1 > mems
+
+Now this cpuset, 'ddset', will only allowed access to fake nodes 0 and 1 for
+memory allocations (1G).
+
+You can now assign tasks to these cpusets to limit the memory resources
+available to them according to the fake nodes assigned as mems::
+
+       [root@xroads /exampleset/ddset]# echo $$ > tasks
+       [root@xroads /exampleset/ddset]# dd if=/dev/zero of=tmp bs=1024 count=1G
+       [1] 13425
+
+Notice the difference between the system memory usage as reported by
+/proc/meminfo between the restricted cpuset case above and the unrestricted
+case (i.e. running the same 'dd' command without assigning it to a fake NUMA
+cpuset):
+
+       ========        ============    ==========
+       Name            Unrestricted    Restricted
+       ========        ============    ==========
+       MemTotal        3091900 kB      3091900 kB
+       MemFree         42113 kB        1513236 kB
+       ========        ============    ==========
+
+This allows for coarse memory management for the tasks you assign to particular
+cpusets.  Since cpusets can form a hierarchy, you can create some pretty
+interesting combinations of use-cases for various classes of tasks for your
+memory management needs.
diff --git a/Documentation/x86/x86_64/index.rst b/Documentation/x86/x86_64/index.rst
new file mode 100644 (file)
index 0000000..d6eaaa5
--- /dev/null
@@ -0,0 +1,16 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==============
+x86_64 Support
+==============
+
+.. toctree::
+   :maxdepth: 2
+
+   boot-options
+   uefi
+   mm
+   5level-paging
+   fake-numa-for-cpusets
+   cpu-hotplug-spec
+   machinecheck
diff --git a/Documentation/x86/x86_64/machinecheck b/Documentation/x86/x86_64/machinecheck
deleted file mode 100644 (file)
index d0648a7..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-
-Configurable sysfs parameters for the x86-64 machine check code.
-
-Machine checks report internal hardware error conditions detected
-by the CPU. Uncorrected errors typically cause a machine check
-(often with panic), corrected ones cause a machine check log entry.
-
-Machine checks are organized in banks (normally associated with
-a hardware subsystem) and subevents in a bank. The exact meaning
-of the banks and subevent is CPU specific.
-
-mcelog knows how to decode them.
-
-When you see the "Machine check errors logged" message in the system
-log then mcelog should run to collect and decode machine check entries
-from /dev/mcelog. Normally mcelog should be run regularly from a cronjob.
-
-Each CPU has a directory in /sys/devices/system/machinecheck/machinecheckN
-(N = CPU number)
-
-The directory contains some configurable entries:
-
-Entries:
-
-bankNctl
-(N bank number)
-       64bit Hex bitmask enabling/disabling specific subevents for bank N
-       When a bit in the bitmask is zero then the respective
-       subevent will not be reported.
-       By default all events are enabled.
-       Note that BIOS maintain another mask to disable specific events
-       per bank.  This is not visible here
-
-The following entries appear for each CPU, but they are truly shared
-between all CPUs.
-
-check_interval
-       How often to poll for corrected machine check errors, in seconds
-       (Note output is hexadecimal). Default 5 minutes.  When the poller
-       finds MCEs it triggers an exponential speedup (poll more often) on
-       the polling interval.  When the poller stops finding MCEs, it
-       triggers an exponential backoff (poll less often) on the polling
-       interval. The check_interval variable is both the initial and
-       maximum polling interval. 0 means no polling for corrected machine
-       check errors (but some corrected errors might be still reported
-       in other ways)
-
-tolerant
-       Tolerance level. When a machine check exception occurs for a non
-       corrected machine check the kernel can take different actions.
-       Since machine check exceptions can happen any time it is sometimes
-       risky for the kernel to kill a process because it defies
-       normal kernel locking rules. The tolerance level configures
-       how hard the kernel tries to recover even at some risk of
-       deadlock.  Higher tolerant values trade potentially better uptime
-       with the risk of a crash or even corruption (for tolerant >= 3).
-
-       0: always panic on uncorrected errors, log corrected errors
-       1: panic or SIGBUS on uncorrected errors, log corrected errors
-       2: SIGBUS or log uncorrected errors, log corrected errors
-       3: never panic or SIGBUS, log all errors (for testing only)
-
-       Default: 1
-
-       Note this only makes a difference if the CPU allows recovery
-       from a machine check exception. Current x86 CPUs generally do not.
-
-trigger
-       Program to run when a machine check event is detected.
-       This is an alternative to running mcelog regularly from cron
-       and allows to detect events faster.
-monarch_timeout
-       How long to wait for the other CPUs to machine check too on a
-       exception. 0 to disable waiting for other CPUs.
-       Unit: us
-
-TBD document entries for AMD threshold interrupt configuration
-
-For more details about the x86 machine check architecture
-see the Intel and AMD architecture manuals from their developer websites.
-
-For more details about the architecture see
-see http://one.firstfloor.org/~andi/mce.pdf
diff --git a/Documentation/x86/x86_64/machinecheck.rst b/Documentation/x86/x86_64/machinecheck.rst
new file mode 100644 (file)
index 0000000..e189168
--- /dev/null
@@ -0,0 +1,85 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===============================================================
+Configurable sysfs parameters for the x86-64 machine check code
+===============================================================
+
+Machine checks report internal hardware error conditions detected
+by the CPU. Uncorrected errors typically cause a machine check
+(often with panic), corrected ones cause a machine check log entry.
+
+Machine checks are organized in banks (normally associated with
+a hardware subsystem) and subevents in a bank. The exact meaning
+of the banks and subevent is CPU specific.
+
+mcelog knows how to decode them.
+
+When you see the "Machine check errors logged" message in the system
+log then mcelog should run to collect and decode machine check entries
+from /dev/mcelog. Normally mcelog should be run regularly from a cronjob.
+
+Each CPU has a directory in /sys/devices/system/machinecheck/machinecheckN
+(N = CPU number).
+
+The directory contains some configurable entries:
+
+bankNctl
+       (N bank number)
+
+       64bit Hex bitmask enabling/disabling specific subevents for bank N
+       When a bit in the bitmask is zero then the respective
+       subevent will not be reported.
+       By default all events are enabled.
+       Note that BIOS maintain another mask to disable specific events
+       per bank.  This is not visible here
+
+The following entries appear for each CPU, but they are truly shared
+between all CPUs.
+
+check_interval
+       How often to poll for corrected machine check errors, in seconds
+       (Note output is hexadecimal). Default 5 minutes.  When the poller
+       finds MCEs it triggers an exponential speedup (poll more often) on
+       the polling interval.  When the poller stops finding MCEs, it
+       triggers an exponential backoff (poll less often) on the polling
+       interval. The check_interval variable is both the initial and
+       maximum polling interval. 0 means no polling for corrected machine
+       check errors (but some corrected errors might be still reported
+       in other ways)
+
+tolerant
+       Tolerance level. When a machine check exception occurs for a non
+       corrected machine check the kernel can take different actions.
+       Since machine check exceptions can happen any time it is sometimes
+       risky for the kernel to kill a process because it defies
+       normal kernel locking rules. The tolerance level configures
+       how hard the kernel tries to recover even at some risk of
+       deadlock.  Higher tolerant values trade potentially better uptime
+       with the risk of a crash or even corruption (for tolerant >= 3).
+
+       0: always panic on uncorrected errors, log corrected errors
+       1: panic or SIGBUS on uncorrected errors, log corrected errors
+       2: SIGBUS or log uncorrected errors, log corrected errors
+       3: never panic or SIGBUS, log all errors (for testing only)
+
+       Default: 1
+
+       Note this only makes a difference if the CPU allows recovery
+       from a machine check exception. Current x86 CPUs generally do not.
+
+trigger
+       Program to run when a machine check event is detected.
+       This is an alternative to running mcelog regularly from cron
+       and allows to detect events faster.
+monarch_timeout
+       How long to wait for the other CPUs to machine check too on a
+       exception. 0 to disable waiting for other CPUs.
+       Unit: us
+
+TBD document entries for AMD threshold interrupt configuration
+
+For more details about the x86 machine check architecture
+see the Intel and AMD architecture manuals from their developer websites.
+
+For more details about the architecture see
+see http://one.firstfloor.org/~andi/mce.pdf
diff --git a/Documentation/x86/x86_64/mm.rst b/Documentation/x86/x86_64/mm.rst
new file mode 100644 (file)
index 0000000..267fc48
--- /dev/null
@@ -0,0 +1,161 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================
+Memory Managment
+================
+
+Complete virtual memory map with 4-level page tables
+====================================================
+
+.. note::
+
+ - Negative addresses such as "-23 TB" are absolute addresses in bytes, counted down
+   from the top of the 64-bit address space. It's easier to understand the layout
+   when seen both in absolute addresses and in distance-from-top notation.
+
+   For example 0xffffe90000000000 == -23 TB, it's 23 TB lower than the top of the
+   64-bit address space (ffffffffffffffff).
+
+   Note that as we get closer to the top of the address space, the notation changes
+   from TB to GB and then MB/KB.
+
+ - "16M TB" might look weird at first sight, but it's an easier to visualize size
+   notation than "16 EB", which few will recognize at first sight as 16 exabytes.
+   It also shows it nicely how incredibly large 64-bit address space is.
+
+::
+
+  ========================================================================================================================
+      Start addr    |   Offset   |     End addr     |  Size   | VM area description
+  ========================================================================================================================
+                    |            |                  |         |
+   0000000000000000 |    0       | 00007fffffffffff |  128 TB | user-space virtual memory, different per mm
+  __________________|____________|__________________|_________|___________________________________________________________
+                    |            |                  |         |
+   0000800000000000 | +128    TB | ffff7fffffffffff | ~16M TB | ... huge, almost 64 bits wide hole of non-canonical
+                    |            |                  |         |     virtual memory addresses up to the -128 TB
+                    |            |                  |         |     starting offset of kernel mappings.
+  __________________|____________|__________________|_________|___________________________________________________________
+                                                              |
+                                                              | Kernel-space virtual memory, shared between all processes:
+  ____________________________________________________________|___________________________________________________________
+                    |            |                  |         |
+   ffff800000000000 | -128    TB | ffff87ffffffffff |    8 TB | ... guard hole, also reserved for hypervisor
+   ffff880000000000 | -120    TB | ffff887fffffffff |  0.5 TB | LDT remap for PTI
+   ffff888000000000 | -119.5  TB | ffffc87fffffffff |   64 TB | direct mapping of all physical memory (page_offset_base)
+   ffffc88000000000 |  -55.5  TB | ffffc8ffffffffff |  0.5 TB | ... unused hole
+   ffffc90000000000 |  -55    TB | ffffe8ffffffffff |   32 TB | vmalloc/ioremap space (vmalloc_base)
+   ffffe90000000000 |  -23    TB | ffffe9ffffffffff |    1 TB | ... unused hole
+   ffffea0000000000 |  -22    TB | ffffeaffffffffff |    1 TB | virtual memory map (vmemmap_base)
+   ffffeb0000000000 |  -21    TB | ffffebffffffffff |    1 TB | ... unused hole
+   ffffec0000000000 |  -20    TB | fffffbffffffffff |   16 TB | KASAN shadow memory
+  __________________|____________|__________________|_________|____________________________________________________________
+                                                              |
+                                                              | Identical layout to the 56-bit one from here on:
+  ____________________________________________________________|____________________________________________________________
+                    |            |                  |         |
+   fffffc0000000000 |   -4    TB | fffffdffffffffff |    2 TB | ... unused hole
+                    |            |                  |         | vaddr_end for KASLR
+   fffffe0000000000 |   -2    TB | fffffe7fffffffff |  0.5 TB | cpu_entry_area mapping
+   fffffe8000000000 |   -1.5  TB | fffffeffffffffff |  0.5 TB | ... unused hole
+   ffffff0000000000 |   -1    TB | ffffff7fffffffff |  0.5 TB | %esp fixup stacks
+   ffffff8000000000 | -512    GB | ffffffeeffffffff |  444 GB | ... unused hole
+   ffffffef00000000 |  -68    GB | fffffffeffffffff |   64 GB | EFI region mapping space
+   ffffffff00000000 |   -4    GB | ffffffff7fffffff |    2 GB | ... unused hole
+   ffffffff80000000 |   -2    GB | ffffffff9fffffff |  512 MB | kernel text mapping, mapped to physical address 0
+   ffffffff80000000 |-2048    MB |                  |         |
+   ffffffffa0000000 |-1536    MB | fffffffffeffffff | 1520 MB | module mapping space
+   ffffffffff000000 |  -16    MB |                  |         |
+      FIXADDR_START | ~-11    MB | ffffffffff5fffff | ~0.5 MB | kernel-internal fixmap range, variable size and offset
+   ffffffffff600000 |  -10    MB | ffffffffff600fff |    4 kB | legacy vsyscall ABI
+   ffffffffffe00000 |   -2    MB | ffffffffffffffff |    2 MB | ... unused hole
+  __________________|____________|__________________|_________|___________________________________________________________
+
+
+Complete virtual memory map with 5-level page tables
+====================================================
+
+.. note::
+
+ - With 56-bit addresses, user-space memory gets expanded by a factor of 512x,
+   from 0.125 PB to 64 PB. All kernel mappings shift down to the -64 PB starting
+   offset and many of the regions expand to support the much larger physical
+   memory supported.
+
+::
+
+  ========================================================================================================================
+      Start addr    |   Offset   |     End addr     |  Size   | VM area description
+  ========================================================================================================================
+                    |            |                  |         |
+   0000000000000000 |    0       | 00ffffffffffffff |   64 PB | user-space virtual memory, different per mm
+  __________________|____________|__________________|_________|___________________________________________________________
+                    |            |                  |         |
+   0100000000000000 |  +64    PB | feffffffffffffff | ~16K PB | ... huge, still almost 64 bits wide hole of non-canonical
+                    |            |                  |         |     virtual memory addresses up to the -64 PB
+                    |            |                  |         |     starting offset of kernel mappings.
+  __________________|____________|__________________|_________|___________________________________________________________
+                                                              |
+                                                              | Kernel-space virtual memory, shared between all processes:
+  ____________________________________________________________|___________________________________________________________
+                    |            |                  |         |
+   ff00000000000000 |  -64    PB | ff0fffffffffffff |    4 PB | ... guard hole, also reserved for hypervisor
+   ff10000000000000 |  -60    PB | ff10ffffffffffff | 0.25 PB | LDT remap for PTI
+   ff11000000000000 |  -59.75 PB | ff90ffffffffffff |   32 PB | direct mapping of all physical memory (page_offset_base)
+   ff91000000000000 |  -27.75 PB | ff9fffffffffffff | 3.75 PB | ... unused hole
+   ffa0000000000000 |  -24    PB | ffd1ffffffffffff | 12.5 PB | vmalloc/ioremap space (vmalloc_base)
+   ffd2000000000000 |  -11.5  PB | ffd3ffffffffffff |  0.5 PB | ... unused hole
+   ffd4000000000000 |  -11    PB | ffd5ffffffffffff |  0.5 PB | virtual memory map (vmemmap_base)
+   ffd6000000000000 |  -10.5  PB | ffdeffffffffffff | 2.25 PB | ... unused hole
+   ffdf000000000000 |   -8.25 PB | fffffbffffffffff |   ~8 PB | KASAN shadow memory
+  __________________|____________|__________________|_________|____________________________________________________________
+                                                              |
+                                                              | Identical layout to the 47-bit one from here on:
+  ____________________________________________________________|____________________________________________________________
+                    |            |                  |         |
+   fffffc0000000000 |   -4    TB | fffffdffffffffff |    2 TB | ... unused hole
+                    |            |                  |         | vaddr_end for KASLR
+   fffffe0000000000 |   -2    TB | fffffe7fffffffff |  0.5 TB | cpu_entry_area mapping
+   fffffe8000000000 |   -1.5  TB | fffffeffffffffff |  0.5 TB | ... unused hole
+   ffffff0000000000 |   -1    TB | ffffff7fffffffff |  0.5 TB | %esp fixup stacks
+   ffffff8000000000 | -512    GB | ffffffeeffffffff |  444 GB | ... unused hole
+   ffffffef00000000 |  -68    GB | fffffffeffffffff |   64 GB | EFI region mapping space
+   ffffffff00000000 |   -4    GB | ffffffff7fffffff |    2 GB | ... unused hole
+   ffffffff80000000 |   -2    GB | ffffffff9fffffff |  512 MB | kernel text mapping, mapped to physical address 0
+   ffffffff80000000 |-2048    MB |                  |         |
+   ffffffffa0000000 |-1536    MB | fffffffffeffffff | 1520 MB | module mapping space
+   ffffffffff000000 |  -16    MB |                  |         |
+      FIXADDR_START | ~-11    MB | ffffffffff5fffff | ~0.5 MB | kernel-internal fixmap range, variable size and offset
+   ffffffffff600000 |  -10    MB | ffffffffff600fff |    4 kB | legacy vsyscall ABI
+   ffffffffffe00000 |   -2    MB | ffffffffffffffff |    2 MB | ... unused hole
+  __________________|____________|__________________|_________|___________________________________________________________
+
+Architecture defines a 64-bit virtual address. Implementations can support
+less. Currently supported are 48- and 57-bit virtual addresses. Bits 63
+through to the most-significant implemented bit are sign extended.
+This causes hole between user space and kernel addresses if you interpret them
+as unsigned.
+
+The direct mapping covers all memory in the system up to the highest
+memory address (this means in some cases it can also include PCI memory
+holes).
+
+vmalloc space is lazily synchronized into the different PML4/PML5 pages of
+the processes using the page fault handler, with init_top_pgt as
+reference.
+
+We map EFI runtime services in the 'efi_pgd' PGD in a 64Gb large virtual
+memory window (this size is arbitrary, it can be raised later if needed).
+The mappings are not part of any other kernel PGD and are only available
+during EFI runtime calls.
+
+Note that if CONFIG_RANDOMIZE_MEMORY is enabled, the direct mapping of all
+physical memory, vmalloc/ioremap space and virtual memory map are randomized.
+Their order is preserved but their base will be offset early at boot time.
+
+Be very careful vs. KASLR when changing anything here. The KASLR address
+range must not overlap with anything except the KASAN shadow area, which is
+correct as KASAN disables KASLR.
+
+For both 4- and 5-level layouts, the STACKLEAK_POISON value in the last 2MB
+hole: ffffffffffff4111
diff --git a/Documentation/x86/x86_64/mm.txt b/Documentation/x86/x86_64/mm.txt
deleted file mode 100644 (file)
index 6cbe652..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-====================================================
-Complete virtual memory map with 4-level page tables
-====================================================
-
-Notes:
-
- - Negative addresses such as "-23 TB" are absolute addresses in bytes, counted down
-   from the top of the 64-bit address space. It's easier to understand the layout
-   when seen both in absolute addresses and in distance-from-top notation.
-
-   For example 0xffffe90000000000 == -23 TB, it's 23 TB lower than the top of the
-   64-bit address space (ffffffffffffffff).
-
-   Note that as we get closer to the top of the address space, the notation changes
-   from TB to GB and then MB/KB.
-
- - "16M TB" might look weird at first sight, but it's an easier to visualize size
-   notation than "16 EB", which few will recognize at first sight as 16 exabytes.
-   It also shows it nicely how incredibly large 64-bit address space is.
-
-========================================================================================================================
-    Start addr    |   Offset   |     End addr     |  Size   | VM area description
-========================================================================================================================
-                  |            |                  |         |
- 0000000000000000 |    0       | 00007fffffffffff |  128 TB | user-space virtual memory, different per mm
-__________________|____________|__________________|_________|___________________________________________________________
-                  |            |                  |         |
- 0000800000000000 | +128    TB | ffff7fffffffffff | ~16M TB | ... huge, almost 64 bits wide hole of non-canonical
-                  |            |                  |         |     virtual memory addresses up to the -128 TB
-                  |            |                  |         |     starting offset of kernel mappings.
-__________________|____________|__________________|_________|___________________________________________________________
-                                                            |
-                                                            | Kernel-space virtual memory, shared between all processes:
-____________________________________________________________|___________________________________________________________
-                  |            |                  |         |
- ffff800000000000 | -128    TB | ffff87ffffffffff |    8 TB | ... guard hole, also reserved for hypervisor
- ffff880000000000 | -120    TB | ffff887fffffffff |  0.5 TB | LDT remap for PTI
- ffff888000000000 | -119.5  TB | ffffc87fffffffff |   64 TB | direct mapping of all physical memory (page_offset_base)
- ffffc88000000000 |  -55.5  TB | ffffc8ffffffffff |  0.5 TB | ... unused hole
- ffffc90000000000 |  -55    TB | ffffe8ffffffffff |   32 TB | vmalloc/ioremap space (vmalloc_base)
- ffffe90000000000 |  -23    TB | ffffe9ffffffffff |    1 TB | ... unused hole
- ffffea0000000000 |  -22    TB | ffffeaffffffffff |    1 TB | virtual memory map (vmemmap_base)
- ffffeb0000000000 |  -21    TB | ffffebffffffffff |    1 TB | ... unused hole
- ffffec0000000000 |  -20    TB | fffffbffffffffff |   16 TB | KASAN shadow memory
-__________________|____________|__________________|_________|____________________________________________________________
-                                                            |
-                                                            | Identical layout to the 56-bit one from here on:
-____________________________________________________________|____________________________________________________________
-                  |            |                  |         |
- fffffc0000000000 |   -4    TB | fffffdffffffffff |    2 TB | ... unused hole
-                  |            |                  |         | vaddr_end for KASLR
- fffffe0000000000 |   -2    TB | fffffe7fffffffff |  0.5 TB | cpu_entry_area mapping
- fffffe8000000000 |   -1.5  TB | fffffeffffffffff |  0.5 TB | ... unused hole
- ffffff0000000000 |   -1    TB | ffffff7fffffffff |  0.5 TB | %esp fixup stacks
- ffffff8000000000 | -512    GB | ffffffeeffffffff |  444 GB | ... unused hole
- ffffffef00000000 |  -68    GB | fffffffeffffffff |   64 GB | EFI region mapping space
- ffffffff00000000 |   -4    GB | ffffffff7fffffff |    2 GB | ... unused hole
- ffffffff80000000 |   -2    GB | ffffffff9fffffff |  512 MB | kernel text mapping, mapped to physical address 0
- ffffffff80000000 |-2048    MB |                  |         |
- ffffffffa0000000 |-1536    MB | fffffffffeffffff | 1520 MB | module mapping space
- ffffffffff000000 |  -16    MB |                  |         |
-    FIXADDR_START | ~-11    MB | ffffffffff5fffff | ~0.5 MB | kernel-internal fixmap range, variable size and offset
- ffffffffff600000 |  -10    MB | ffffffffff600fff |    4 kB | legacy vsyscall ABI
- ffffffffffe00000 |   -2    MB | ffffffffffffffff |    2 MB | ... unused hole
-__________________|____________|__________________|_________|___________________________________________________________
-
-
-====================================================
-Complete virtual memory map with 5-level page tables
-====================================================
-
-Notes:
-
- - With 56-bit addresses, user-space memory gets expanded by a factor of 512x,
-   from 0.125 PB to 64 PB. All kernel mappings shift down to the -64 PB starting
-   offset and many of the regions expand to support the much larger physical
-   memory supported.
-
-========================================================================================================================
-    Start addr    |   Offset   |     End addr     |  Size   | VM area description
-========================================================================================================================
-                  |            |                  |         |
- 0000000000000000 |    0       | 00ffffffffffffff |   64 PB | user-space virtual memory, different per mm
-__________________|____________|__________________|_________|___________________________________________________________
-                  |            |                  |         |
- 0100000000000000 |  +64    PB | feffffffffffffff | ~16K PB | ... huge, still almost 64 bits wide hole of non-canonical
-                  |            |                  |         |     virtual memory addresses up to the -64 PB
-                  |            |                  |         |     starting offset of kernel mappings.
-__________________|____________|__________________|_________|___________________________________________________________
-                                                            |
-                                                            | Kernel-space virtual memory, shared between all processes:
-____________________________________________________________|___________________________________________________________
-                  |            |                  |         |
- ff00000000000000 |  -64    PB | ff0fffffffffffff |    4 PB | ... guard hole, also reserved for hypervisor
- ff10000000000000 |  -60    PB | ff10ffffffffffff | 0.25 PB | LDT remap for PTI
- ff11000000000000 |  -59.75 PB | ff90ffffffffffff |   32 PB | direct mapping of all physical memory (page_offset_base)
- ff91000000000000 |  -27.75 PB | ff9fffffffffffff | 3.75 PB | ... unused hole
- ffa0000000000000 |  -24    PB | ffd1ffffffffffff | 12.5 PB | vmalloc/ioremap space (vmalloc_base)
- ffd2000000000000 |  -11.5  PB | ffd3ffffffffffff |  0.5 PB | ... unused hole
- ffd4000000000000 |  -11    PB | ffd5ffffffffffff |  0.5 PB | virtual memory map (vmemmap_base)
- ffd6000000000000 |  -10.5  PB | ffdeffffffffffff | 2.25 PB | ... unused hole
- ffdf000000000000 |   -8.25 PB | fffffbffffffffff |   ~8 PB | KASAN shadow memory
-__________________|____________|__________________|_________|____________________________________________________________
-                                                            |
-                                                            | Identical layout to the 47-bit one from here on:
-____________________________________________________________|____________________________________________________________
-                  |            |                  |         |
- fffffc0000000000 |   -4    TB | fffffdffffffffff |    2 TB | ... unused hole
-                  |            |                  |         | vaddr_end for KASLR
- fffffe0000000000 |   -2    TB | fffffe7fffffffff |  0.5 TB | cpu_entry_area mapping
- fffffe8000000000 |   -1.5  TB | fffffeffffffffff |  0.5 TB | ... unused hole
- ffffff0000000000 |   -1    TB | ffffff7fffffffff |  0.5 TB | %esp fixup stacks
- ffffff8000000000 | -512    GB | ffffffeeffffffff |  444 GB | ... unused hole
- ffffffef00000000 |  -68    GB | fffffffeffffffff |   64 GB | EFI region mapping space
- ffffffff00000000 |   -4    GB | ffffffff7fffffff |    2 GB | ... unused hole
- ffffffff80000000 |   -2    GB | ffffffff9fffffff |  512 MB | kernel text mapping, mapped to physical address 0
- ffffffff80000000 |-2048    MB |                  |         |
- ffffffffa0000000 |-1536    MB | fffffffffeffffff | 1520 MB | module mapping space
- ffffffffff000000 |  -16    MB |                  |         |
-    FIXADDR_START | ~-11    MB | ffffffffff5fffff | ~0.5 MB | kernel-internal fixmap range, variable size and offset
- ffffffffff600000 |  -10    MB | ffffffffff600fff |    4 kB | legacy vsyscall ABI
- ffffffffffe00000 |   -2    MB | ffffffffffffffff |    2 MB | ... unused hole
-__________________|____________|__________________|_________|___________________________________________________________
-
-Architecture defines a 64-bit virtual address. Implementations can support
-less. Currently supported are 48- and 57-bit virtual addresses. Bits 63
-through to the most-significant implemented bit are sign extended.
-This causes hole between user space and kernel addresses if you interpret them
-as unsigned.
-
-The direct mapping covers all memory in the system up to the highest
-memory address (this means in some cases it can also include PCI memory
-holes).
-
-vmalloc space is lazily synchronized into the different PML4/PML5 pages of
-the processes using the page fault handler, with init_top_pgt as
-reference.
-
-We map EFI runtime services in the 'efi_pgd' PGD in a 64Gb large virtual
-memory window (this size is arbitrary, it can be raised later if needed).
-The mappings are not part of any other kernel PGD and are only available
-during EFI runtime calls.
-
-Note that if CONFIG_RANDOMIZE_MEMORY is enabled, the direct mapping of all
-physical memory, vmalloc/ioremap space and virtual memory map are randomized.
-Their order is preserved but their base will be offset early at boot time.
-
-Be very careful vs. KASLR when changing anything here. The KASLR address
-range must not overlap with anything except the KASAN shadow area, which is
-correct as KASAN disables KASLR.
-
-For both 4- and 5-level layouts, the STACKLEAK_POISON value in the last 2MB
-hole: ffffffffffff4111
diff --git a/Documentation/x86/x86_64/uefi.rst b/Documentation/x86/x86_64/uefi.rst
new file mode 100644 (file)
index 0000000..88c3ba3
--- /dev/null
@@ -0,0 +1,58 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====================================
+General note on [U]EFI x86_64 support
+=====================================
+
+The nomenclature EFI and UEFI are used interchangeably in this document.
+
+Although the tools below are _not_ needed for building the kernel,
+the needed bootloader support and associated tools for x86_64 platforms
+with EFI firmware and specifications are listed below.
+
+1. UEFI specification:  http://www.uefi.org
+
+2. Booting Linux kernel on UEFI x86_64 platform requires bootloader
+   support. Elilo with x86_64 support can be used.
+
+3. x86_64 platform with EFI/UEFI firmware.
+
+Mechanics
+---------
+
+- Build the kernel with the following configuration::
+
+       CONFIG_FB_EFI=y
+       CONFIG_FRAMEBUFFER_CONSOLE=y
+
+  If EFI runtime services are expected, the following configuration should
+  be selected::
+
+       CONFIG_EFI=y
+       CONFIG_EFI_VARS=y or m          # optional
+
+- Create a VFAT partition on the disk
+- Copy the following to the VFAT partition:
+
+       elilo bootloader with x86_64 support, elilo configuration file,
+       kernel image built in first step and corresponding
+       initrd. Instructions on building elilo  and its dependencies
+       can be found in the elilo sourceforge project.
+
+- Boot to EFI shell and invoke elilo choosing the kernel image built
+  in first step.
+- If some or all EFI runtime services don't work, you can try following
+  kernel command line parameters to turn off some or all EFI runtime
+  services.
+
+       noefi
+               turn off all EFI runtime services
+       reboot_type=k
+               turn off EFI reboot runtime service
+
+- If the EFI memory map has additional entries not in the E820 map,
+  you can include those entries in the kernels memory map of available
+  physical RAM by using the following kernel command line parameter.
+
+       add_efi_memmap
+               include EFI memory map of available physical RAM
diff --git a/Documentation/x86/x86_64/uefi.txt b/Documentation/x86/x86_64/uefi.txt
deleted file mode 100644 (file)
index a5e2b4f..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-General note on [U]EFI x86_64 support
--------------------------------------
-
-The nomenclature EFI and UEFI are used interchangeably in this document.
-
-Although the tools below are _not_ needed for building the kernel,
-the needed bootloader support and associated tools for x86_64 platforms
-with EFI firmware and specifications are listed below.
-
-1. UEFI specification:  http://www.uefi.org
-
-2. Booting Linux kernel on UEFI x86_64 platform requires bootloader
-   support. Elilo with x86_64 support can be used.
-
-3. x86_64 platform with EFI/UEFI firmware.
-
-Mechanics:
----------
-- Build the kernel with the following configuration.
-       CONFIG_FB_EFI=y
-       CONFIG_FRAMEBUFFER_CONSOLE=y
-  If EFI runtime services are expected, the following configuration should
-  be selected.
-       CONFIG_EFI=y
-       CONFIG_EFI_VARS=y or m          # optional
-- Create a VFAT partition on the disk
-- Copy the following to the VFAT partition:
-       elilo bootloader with x86_64 support, elilo configuration file,
-       kernel image built in first step and corresponding
-       initrd. Instructions on building elilo  and its dependencies
-       can be found in the elilo sourceforge project.
-- Boot to EFI shell and invoke elilo choosing the kernel image built
-  in first step.
-- If some or all EFI runtime services don't work, you can try following
-  kernel command line parameters to turn off some or all EFI runtime
-  services.
-       noefi           turn off all EFI runtime services
-       reboot_type=k   turn off EFI reboot runtime service
-- If the EFI memory map has additional entries not in the E820 map,
-  you can include those entries in the kernels memory map of available
-  physical RAM by using the following kernel command line parameter.
-       add_efi_memmap  include EFI memory map of available physical RAM
diff --git a/Documentation/x86/zero-page.rst b/Documentation/x86/zero-page.rst
new file mode 100644 (file)
index 0000000..f088f58
--- /dev/null
@@ -0,0 +1,45 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=========
+Zero Page
+=========
+The additional fields in struct boot_params as a part of 32-bit boot
+protocol of kernel. These should be filled by bootloader or 16-bit
+real-mode setup code of the kernel. References/settings to it mainly
+are in::
+
+  arch/x86/include/uapi/asm/bootparam.h
+
+===========    =====   ======================= =================================================
+Offset/Size    Proto   Name                    Meaning
+
+000/040                ALL     screen_info             Text mode or frame buffer information
+                                               (struct screen_info)
+040/014                ALL     apm_bios_info           APM BIOS information (struct apm_bios_info)
+058/008                ALL     tboot_addr              Physical address of tboot shared page
+060/010                ALL     ist_info                Intel SpeedStep (IST) BIOS support information
+                                               (struct ist_info)
+080/010                ALL     hd0_info                hd0 disk parameter, OBSOLETE!!
+090/010                ALL     hd1_info                hd1 disk parameter, OBSOLETE!!
+0A0/010                ALL     sys_desc_table          System description table (struct sys_desc_table),
+                                               OBSOLETE!!
+0B0/010                ALL     olpc_ofw_header         OLPC's OpenFirmware CIF and friends
+0C0/004                ALL     ext_ramdisk_image       ramdisk_image high 32bits
+0C4/004                ALL     ext_ramdisk_size        ramdisk_size high 32bits
+0C8/004                ALL     ext_cmd_line_ptr        cmd_line_ptr high 32bits
+140/080                ALL     edid_info               Video mode setup (struct edid_info)
+1C0/020                ALL     efi_info                EFI 32 information (struct efi_info)
+1E0/004                ALL     alt_mem_k               Alternative mem check, in KB
+1E4/004                ALL     scratch                 Scratch field for the kernel setup code
+1E8/001                ALL     e820_entries            Number of entries in e820_table (below)
+1E9/001                ALL     eddbuf_entries          Number of entries in eddbuf (below)
+1EA/001                ALL     edd_mbr_sig_buf_entries Number of entries in edd_mbr_sig_buffer
+                                               (below)
+1EB/001                ALL     kbd_status              Numlock is enabled
+1EC/001                ALL     secure_boot             Secure boot is enabled in the firmware
+1EF/001                ALL     sentinel                Used to detect broken bootloaders
+290/040                ALL     edd_mbr_sig_buffer      EDD MBR signatures
+2D0/A00                ALL     e820_table              E820 memory map table
+                                               (array of struct e820_entry)
+D00/1EC                ALL     eddbuf                  EDD data (array of struct edd_info)
+===========    =====   ======================= =================================================
diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt
deleted file mode 100644 (file)
index 68aed07..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-The additional fields in struct boot_params as a part of 32-bit boot
-protocol of kernel. These should be filled by bootloader or 16-bit
-real-mode setup code of the kernel. References/settings to it mainly
-are in:
-
-  arch/x86/include/uapi/asm/bootparam.h
-
-
-Offset Proto   Name            Meaning
-/Size
-
-000/040        ALL     screen_info     Text mode or frame buffer information
-                               (struct screen_info)
-040/014        ALL     apm_bios_info   APM BIOS information (struct apm_bios_info)
-058/008        ALL     tboot_addr      Physical address of tboot shared page
-060/010        ALL     ist_info        Intel SpeedStep (IST) BIOS support information
-                               (struct ist_info)
-080/010        ALL     hd0_info        hd0 disk parameter, OBSOLETE!!
-090/010        ALL     hd1_info        hd1 disk parameter, OBSOLETE!!
-0A0/010        ALL     sys_desc_table  System description table (struct sys_desc_table),
-                               OBSOLETE!!
-0B0/010        ALL     olpc_ofw_header OLPC's OpenFirmware CIF and friends
-0C0/004        ALL     ext_ramdisk_image ramdisk_image high 32bits
-0C4/004        ALL     ext_ramdisk_size  ramdisk_size high 32bits
-0C8/004        ALL     ext_cmd_line_ptr  cmd_line_ptr high 32bits
-140/080        ALL     edid_info       Video mode setup (struct edid_info)
-1C0/020        ALL     efi_info        EFI 32 information (struct efi_info)
-1E0/004        ALL     alt_mem_k       Alternative mem check, in KB
-1E4/004        ALL     scratch         Scratch field for the kernel setup code
-1E8/001        ALL     e820_entries    Number of entries in e820_table (below)
-1E9/001        ALL     eddbuf_entries  Number of entries in eddbuf (below)
-1EA/001        ALL     edd_mbr_sig_buf_entries Number of entries in edd_mbr_sig_buffer
-                               (below)
-1EB/001        ALL     kbd_status      Numlock is enabled
-1EC/001        ALL     secure_boot     Secure boot is enabled in the firmware
-1EF/001        ALL     sentinel        Used to detect broken bootloaders
-290/040        ALL     edd_mbr_sig_buffer EDD MBR signatures
-2D0/A00        ALL     e820_table      E820 memory map table
-                               (array of struct e820_entry)
-D00/1EC        ALL     eddbuf          EDD data (array of struct edd_info)
index 0ab686c173be590e4f1136187cc3368dbad33f53..5f39b4ffdcd43f6a32268755e3e3810927224a5d 100644 (file)
@@ -41,8 +41,8 @@ Example of EEMI ops usage:
        int ret;
 
        eemi_ops = zynqmp_pm_get_eemi_ops();
-       if (!eemi_ops)
-               return -ENXIO;
+       if (IS_ERR(eemi_ops))
+               return PTR_ERR(eemi_ops);
 
        ret = eemi_ops->query_data(qdata, ret_payload);
 
index d85f8ecc64a2824fd5118e2b91d8aa0107d47a86..9cc6767e1b12eae0e55e9d105796a86bd0f16015 100644 (file)
@@ -710,6 +710,12 @@ L: linux-gpio@vger.kernel.org
 S:     Maintained
 F:     drivers/gpio/gpio-altera.c
 
+ALTERA SYSTEM MANAGER DRIVER
+M:     Thor Thayer <thor.thayer@linux.intel.com>
+S:     Maintained
+F:     drivers/mfd/altera-sysmgr.c
+F:     include/linux/mfd/altera-sysgmr.h
+
 ALTERA SYSTEM RESOURCE DRIVER FOR ARRIA10 DEVKIT
 M:     Thor Thayer <thor.thayer@linux.intel.com>
 S:     Maintained
@@ -736,6 +742,12 @@ F: drivers/tty/serial/altera_jtaguart.c
 F:     include/linux/altera_uart.h
 F:     include/linux/altera_jtaguart.h
 
+AMAZON ANNAPURNA LABS THERMAL MMIO DRIVER
+M:     Talel Shenhar <talel@amazon.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/thermal/amazon,al-thermal.txt
+F:     drivers/thermal/thermal_mmio.c
+
 AMAZON ETHERNET DRIVERS
 M:     Netanel Belgazal <netanel@amazon.com>
 R:     Saeed Bishara <saeedb@amazon.com>
@@ -988,7 +1000,7 @@ F: include/linux/clk/analogbits*
 ANDES ARCHITECTURE
 M:     Greentime Hu <green.hu@gmail.com>
 M:     Vincent Chen <deanbo422@gmail.com>
-T:     git https://github.com/andestech/linux.git
+T:     git https://git.kernel.org/pub/scm/linux/kernel/git/greentime/linux.git
 S:     Supported
 F:     arch/nds32/
 F:     Documentation/devicetree/bindings/interrupt-controller/andestech,ativic32.txt
@@ -1721,11 +1733,21 @@ L:      linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
 ARM/INTEL IXP4XX ARM ARCHITECTURE
+M:     Linus Walleij <linusw@kernel.org>
 M:     Imre Kaloz <kaloz@openwrt.org>
 M:     Krzysztof Halasa <khalasa@piap.pl>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
+F:     Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml
+F:     Documentation/devicetree/bindings/gpio/intel,ixp4xx-gpio.txt
+F:     Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml
+F:     Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml
 F:     arch/arm/mach-ixp4xx/
+F:     drivers/clocksource/timer-ixp4xx.c
+F:     drivers/gpio/gpio-ixp4xx.c
+F:     drivers/irqchip/irq-ixp4xx.c
+F:     include/linux/irqchip/irq-ixp4xx.h
+F:     include/linux/platform_data/timer-ixp4xx.h
 
 ARM/INTEL RESEARCH IMOTE/STARGATE 2 MACHINE SUPPORT
 M:     Jonathan Cameron <jic23@cam.ac.uk>
@@ -2021,7 +2043,7 @@ W:        http://www.armlinux.org.uk/
 S:     Maintained
 
 ARM/QUALCOMM SUPPORT
-M:     Andy Gross <andy.gross@linaro.org>
+M:     Andy Gross <agross@kernel.org>
 M:     David Brown <david.brown@linaro.org>
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
@@ -2226,6 +2248,7 @@ F:        arch/arm/mach-socfpga/
 F:     arch/arm/boot/dts/socfpga*
 F:     arch/arm/configs/socfpga_defconfig
 F:     arch/arm64/boot/dts/altera/
+F:     arch/arm64/boot/dts/intel/
 W:     http://www.rocketboards.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git
 
@@ -4127,7 +4150,9 @@ F:        Documentation/admin-guide/pm/intel_pstate.rst
 F:     Documentation/cpu-freq/
 F:     Documentation/devicetree/bindings/cpufreq/
 F:     drivers/cpufreq/
+F:     kernel/sched/cpufreq*.c
 F:     include/linux/cpufreq.h
+F:     include/linux/sched/cpufreq.h
 F:     tools/testing/selftests/cpufreq/
 
 CPU FREQUENCY DRIVERS - ARM BIG LITTLE
@@ -4310,7 +4335,7 @@ F:        drivers/infiniband/hw/cxgb3/
 F:     include/uapi/rdma/cxgb3-abi.h
 
 CXGB4 CRYPTO DRIVER (chcr)
-M:     Harsh Jain <harsh@chelsio.com>
+M:     Atul Gupta <atul.gupta@chelsio.com>
 L:     linux-crypto@vger.kernel.org
 W:     http://www.chelsio.com
 S:     Supported
@@ -7976,10 +8001,10 @@ F:      Documentation/media/v4l-drivers/ipu3.rst
 INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
 M:     Krzysztof Halasa <khalasa@piap.pl>
 S:     Maintained
-F:     arch/arm/mach-ixp4xx/include/mach/qmgr.h
-F:     arch/arm/mach-ixp4xx/include/mach/npe.h
-F:     arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
-F:     arch/arm/mach-ixp4xx/ixp4xx_npe.c
+F:     include/linux/soc/ixp4xx/qmgr.h
+F:     include/linux/soc/ixp4xx/npe.h
+F:     drivers/soc/ixp4xx/ixp4xx-qmgr.c
+F:     drivers/soc/ixp4xx/ixp4xx-npe.c
 F:     drivers/net/ethernet/xscale/ixp4xx_eth.c
 F:     drivers/net/wan/ixp4xx_hss.c
 
@@ -8418,9 +8443,11 @@ F:       drivers/net/ethernet/jme.*
 
 JOURNALLING FLASH FILE SYSTEM V2 (JFFS2)
 M:     David Woodhouse <dwmw2@infradead.org>
+M:     Richard Weinberger <richard@nod.at>
 L:     linux-mtd@lists.infradead.org
 W:     http://www.linux-mtd.infradead.org/doc/jffs2.html
-S:     Maintained
+T:     git git://git.infradead.org/ubifs-2.6.git
+S:     Odd Fixes
 F:     fs/jffs2/
 F:     include/uapi/linux/jffs2.h
 
@@ -9515,6 +9542,20 @@ S:       Maintained
 F:     Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.txt
 F:     drivers/iio/proximity/mb1232.c
 
+MAXIM MAX77650 PMIC MFD DRIVER
+M:     Bartosz Golaszewski <bgolaszewski@baylibre.com>
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/*/*max77650.txt
+F:     Documentation/devicetree/bindings/*/max77650*.txt
+F:     include/linux/mfd/max77650.h
+F:     drivers/mfd/max77650.c
+F:     drivers/regulator/max77650-regulator.c
+F:     drivers/power/supply/max77650-charger.c
+F:     drivers/input/misc/max77650-onkey.c
+F:     drivers/leds/leds-max77650.c
+F:     drivers/gpio/gpio-max77650.c
+
 MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER
 M:     Javier Martinez Canillas <javier@dowhile0.org>
 L:     linux-kernel@vger.kernel.org
@@ -10114,14 +10155,15 @@ F:    mm/
 MEMORY TECHNOLOGY DEVICES (MTD)
 M:     David Woodhouse <dwmw2@infradead.org>
 M:     Brian Norris <computersforpeace@gmail.com>
-M:     Boris Brezillon <bbrezillon@kernel.org>
 M:     Marek Vasut <marek.vasut@gmail.com>
+M:     Miquel Raynal <miquel.raynal@bootlin.com>
 M:     Richard Weinberger <richard@nod.at>
+M:     Vignesh Raghavendra <vigneshr@ti.com>
 L:     linux-mtd@lists.infradead.org
 W:     http://www.linux-mtd.infradead.org/
 Q:     http://patchwork.ozlabs.org/project/linux-mtd/list/
-T:     git git://git.infradead.org/linux-mtd.git master
-T:     git git://git.infradead.org/linux-mtd.git mtd/next
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git mtd/fixes
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git mtd/next
 S:     Maintained
 F:     Documentation/devicetree/bindings/mtd/
 F:     drivers/mtd/
@@ -10730,14 +10772,12 @@ S:    Supported
 F:     drivers/net/ethernet/myricom/myri10ge/
 
 NAND FLASH SUBSYSTEM
-M:     Boris Brezillon <bbrezillon@kernel.org>
 M:     Miquel Raynal <miquel.raynal@bootlin.com>
 R:     Richard Weinberger <richard@nod.at>
 L:     linux-mtd@lists.infradead.org
 W:     http://www.linux-mtd.infradead.org/
 Q:     http://patchwork.ozlabs.org/project/linux-mtd/list/
-T:     git git://git.infradead.org/linux-mtd.git nand/fixes
-T:     git git://git.infradead.org/linux-mtd.git nand/next
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next
 S:     Maintained
 F:     drivers/mtd/nand/
 F:     include/linux/mtd/*nand*.h
@@ -11745,6 +11785,7 @@ F:      include/linux/oprofile.h
 ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
 M:     Mark Fasheh <mark@fasheh.com>
 M:     Joel Becker <jlbec@evilplan.org>
+M:     Joseph Qi <joseph.qi@linux.alibaba.com>
 L:     ocfs2-devel@oss.oracle.com (moderated for non-subscribers)
 W:     http://ocfs2.wiki.kernel.org
 S:     Supported
@@ -12024,7 +12065,8 @@ F:      include/linux/switchtec.h
 F:     drivers/ntb/hw/mscc/
 
 PCI DRIVER FOR MOBIVEIL PCIE IP
-M:     Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
+M:     Karthikeyan Mitran <m.karthikeyan@mobiveil.co.in>
+M:     Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
 L:     linux-pci@vger.kernel.org
 S:     Supported
 F:     Documentation/devicetree/bindings/pci/mobiveil-pcie.txt
@@ -12158,6 +12200,12 @@ T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git/
 S:     Supported
 F:     drivers/pci/controller/
 
+PCIE DRIVER FOR ANNAPURNA LABS
+M:     Jonathan Chocron <jonnyc@amazon.com>
+L:     linux-pci@vger.kernel.org
+S:     Maintained
+F:     drivers/pci/controller/dwc/pcie-al.c
+
 PCIE DRIVER FOR AMLOGIC MESON
 M:     Yue Wang <yue.wang@Amlogic.com>
 L:     linux-pci@vger.kernel.org
@@ -14751,8 +14799,7 @@ M:      Tudor Ambarus <tudor.ambarus@microchip.com>
 L:     linux-mtd@lists.infradead.org
 W:     http://www.linux-mtd.infradead.org/
 Q:     http://patchwork.ozlabs.org/project/linux-mtd/list/
-T:     git git://git.infradead.org/linux-mtd.git spi-nor/fixes
-T:     git git://git.infradead.org/linux-mtd.git spi-nor/next
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git spi-nor/next
 S:     Maintained
 F:     drivers/mtd/spi-nor/
 F:     include/linux/mtd/spi-nor.h
@@ -15618,7 +15665,7 @@ F:      include/linux/clk/ti.h
 
 TI DAVINCI MACHINE SUPPORT
 M:     Sekhar Nori <nsekhar@ti.com>
-M:     Kevin Hilman <khilman@kernel.org>
+R:     Bartosz Golaszewski <bgolaszewski@baylibre.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nsekhar/linux-davinci.git
 S:     Supported
@@ -16557,6 +16604,7 @@ F:      fs/fat/
 
 VFIO DRIVER
 M:     Alex Williamson <alex.williamson@redhat.com>
+R:     Cornelia Huck <cohuck@redhat.com>
 L:     kvm@vger.kernel.org
 T:     git git://github.com/awilliam/linux-vfio.git
 S:     Maintained
index 5e43fcbad4ca551493345f4a052c73461a85ae78..c47b328eada033257e30c89a0f1678d030b5b95f 100644 (file)
@@ -245,6 +245,13 @@ config ARCH_HAS_FORTIFY_SOURCE
          An architecture should select this when it can successfully
          build and run with CONFIG_FORTIFY_SOURCE.
 
+#
+# Select if the arch provides a historic keepinit alias for the retain_initrd
+# command line option
+#
+config ARCH_HAS_KEEPINITRD
+       bool
+
 # Select if arch has all set_memory_ro/rw/x/nx() functions in asm/cacheflush.h
 config ARCH_HAS_SET_MEMORY
        bool
@@ -774,7 +781,7 @@ config COMPAT_OLD_SIGACTION
        bool
 
 config 64BIT_TIME
-       def_bool ARCH_HAS_64BIT_TIME
+       def_bool y
        help
          This should be selected by all architectures that need to support
          new system calls with a 64-bit time_t. This is relevant on all 32-bit
diff --git a/arch/alpha/include/asm/segment.h b/arch/alpha/include/asm/segment.h
deleted file mode 100644 (file)
index 0453d97..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ALPHA_SEGMENT_H
-#define __ALPHA_SEGMENT_H
-
-/* Only here because we have some old header files that expect it.. */
-
-#endif
index 4dbd4e41504159322ff13dbc335a7e1daea6efec..bbbd34586de01e1f11fe4ba1d6f21f1f8b0a2119 100644 (file)
@@ -10,7 +10,6 @@
 
 #include <asm/hwrpb.h>
 #include <asm/io.h>
-#include <asm/segment.h>
 
 #if 0
 # define DBG_DEVS(args)         printk args
index 733f08966fd217806593c03cbb91c994a3cc9425..71cd7aca38ce2464be5a0e2dad8a21a57a800ee7 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <asm/hwrpb.h>
 #include <asm/io.h>
-#include <asm/segment.h>
 
 #define SMC_DEBUG 0
 
index 165f268beafc471e14eac4c8d6d08e52c5c89864..9e7704e44f6ddd1ddcbe9e21afcd5ea5cfe9a097 100644 (file)
 535    common  io_uring_setup                  sys_io_uring_setup
 536    common  io_uring_enter                  sys_io_uring_enter
 537    common  io_uring_register               sys_io_uring_register
+538    common  open_tree                       sys_open_tree
+539    common  move_mount                      sys_move_mount
+540    common  fsopen                          sys_fsopen
+541    common  fsconfig                        sys_fsconfig
+542    common  fsmount                         sys_fsmount
+543    common  fspick                          sys_fspick
index a42fc5c4db893fdafa5825347600f1baff9890db..e2cbec3789e8c870ca159094f669daa30632c2a1 100644 (file)
@@ -285,17 +285,3 @@ mem_init(void)
        memblock_free_all();
        mem_init_print_info(NULL);
 }
-
-void
-free_initmem(void)
-{
-       free_initmem_default(-1);
-}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void
-free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-#endif
index eabc3efa6c6ddf9ba97a3f1ca7cd7379d144e2d9..526418543379b9272edba4eb757070fba5ff6996 100644 (file)
@@ -742,6 +742,7 @@ extern long arc_strnlen_user_noinline(const char __user *src, long n);
 
 #endif
 
+#include <asm/segment.h>
 #include <asm-generic/uaccess.h>
 
 #endif
index e1ab2d7f1d646510ab17a4be31b675e88027745b..02b7a3b20d7c847dd4b4803cd4b5418f2e79c629 100644 (file)
@@ -206,18 +206,3 @@ void __init mem_init(void)
        memblock_free_all();
        mem_init_print_info(NULL);
 }
-
-/*
- * free_initmem: Free all the __init memory.
- */
-void __ref free_initmem(void)
-{
-       free_initmem_default(-1);
-}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void __init free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-#endif
index dc9855c4a3b404cff6a4dd2ac81ba92d12bbe4fc..8869742a85df1a34c56b7da989eb1210bbd22e9e 100644 (file)
@@ -4,11 +4,11 @@ config ARM
        default y
        select ARCH_32BIT_OFF_T
        select ARCH_CLOCKSOURCE_DATA
-       select ARCH_DISCARD_MEMBLOCK if !HAVE_ARCH_PFN_VALID && !KEXEC
        select ARCH_HAS_DEBUG_VIRTUAL if MMU
        select ARCH_HAS_DEVMEM_IS_ALLOWED
        select ARCH_HAS_ELF_RANDOMIZE
        select ARCH_HAS_FORTIFY_SOURCE
+       select ARCH_HAS_KEEPINITRD
        select ARCH_HAS_KCOV
        select ARCH_HAS_MEMBARRIER_SYNC_CORE
        select ARCH_HAS_PTE_SPECIAL if ARM_LPAE
@@ -21,6 +21,7 @@ config ARM
        select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
        select ARCH_HAVE_CUSTOM_GPIO_H
        select ARCH_HAS_GCOV_PROFILE_ALL
+       select ARCH_KEEP_MEMBLOCK if HAVE_ARCH_PFN_VALID || KEXEC
        select ARCH_MIGHT_HAVE_PC_PARPORT
        select ARCH_NO_SG_CHAIN if !ARM_HAS_SG_CHAIN
        select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX
@@ -425,12 +426,15 @@ config ARCH_IXP4XX
        depends on MMU
        select ARCH_HAS_DMA_SET_COHERENT_MASK
        select ARCH_SUPPORTS_BIG_ENDIAN
-       select CLKSRC_MMIO
        select CPU_XSCALE
        select DMABOUNCE if PCI
        select GENERIC_CLOCKEVENTS
+       select GENERIC_IRQ_MULTI_HANDLER
+       select GPIO_IXP4XX
        select GPIOLIB
        select HAVE_PCI
+       select IXP4XX_IRQ
+       select IXP4XX_TIMER
        select NEED_MACH_IO_H
        select USB_EHCI_BIG_ENDIAN_DESC
        select USB_EHCI_BIG_ENDIAN_MMIO
@@ -896,8 +900,6 @@ config PLAT_PXA
 config PLAT_VERSATILE
        bool
 
-source "arch/arm/firmware/Kconfig"
-
 source "arch/arm/mm/Kconfig"
 
 config IWMMXT
index e388af4594a6e5e42a860469e10a53b89522e7bf..9a8862fee7381c1bc6fd31edba6d4f1941fd5e20 100644 (file)
@@ -1676,6 +1676,7 @@ config DEBUG_UART_PHYS
        default 0xe6e68000 if DEBUG_RCAR_GEN2_SCIF1
        default 0xe6ee0000 if DEBUG_RCAR_GEN2_SCIF4
        default 0xe8008000 if DEBUG_R7S72100_SCIF2
+       default 0xf0000000 if DEBUG_DIGICOLOR_UA0
        default 0xf0000be0 if ARCH_EBSA110
        default 0xf1012000 if DEBUG_MVEBU_UART0_ALTERNATE
        default 0xf1012100 if DEBUG_MVEBU_UART1_ALTERNATE
@@ -1727,6 +1728,7 @@ config DEBUG_UART_VIRT
        default 0xe0010fe0 if ARCH_RPC
        default 0xf0000be0 if ARCH_EBSA110
        default 0xf0010000 if DEBUG_ASM9260_UART
+       default 0xf0100000 if DEBUG_DIGICOLOR_UA0
        default 0xf01fb000 if DEBUG_NOMADIK_UART
        default 0xf0201000 if DEBUG_BCM2835 || DEBUG_BCM2836
        default 0xf1000300 if DEBUG_BCM_5301X
index 807a7d06c2a0825bed8f8ea8c1d9d8c7eb5f8be6..f863c6935d0e5008ce70da79245f96afe5fbeb6f 100644 (file)
@@ -116,8 +116,7 @@ endif
 AFLAGS_NOWARN  :=$(call as-option,-Wa$(comma)-mno-warn-deprecated,-Wa$(comma)-W)
 
 ifeq ($(CONFIG_THUMB2_KERNEL),y)
-AFLAGS_AUTOIT  :=$(call as-option,-Wa$(comma)-mimplicit-it=always,-Wa$(comma)-mauto-it)
-CFLAGS_ISA     :=-mthumb $(AFLAGS_AUTOIT) $(AFLAGS_NOWARN)
+CFLAGS_ISA     :=-mthumb -Wa,-mimplicit-it=always $(AFLAGS_NOWARN)
 AFLAGS_ISA     :=$(CFLAGS_ISA) -Wa$(comma)-mthumb
 # Work around buggy relocation from gas if requested:
 ifeq ($(CONFIG_THUMB2_AVOID_R_ARM_THM_JUMP11),y)
@@ -290,7 +289,6 @@ core-y                              += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
 core-y                         += arch/arm/probes/
 core-y                         += arch/arm/net/
 core-y                         += arch/arm/crypto/
-core-y                         += arch/arm/firmware/
 core-y                         += $(machdirs) $(platdirs)
 
 drivers-$(CONFIG_OPROFILE)      += arch/arm/oprofile/
index f4f5aeaf32985c3f5a5bebe88751e90a16311892..dab2914fa293cde2916a4fd0ceddf0e9929e411f 100644 (file)
@@ -229,6 +229,9 @@ dtb-$(CONFIG_ARCH_HIX5HD2) += \
 dtb-$(CONFIG_ARCH_INTEGRATOR) += \
        integratorap.dtb \
        integratorcp.dtb
+dtb-$(CONFIG_ARCH_IXP4XX) += \
+       intel-ixp42x-linksys-nslu2.dtb \
+       intel-ixp43x-gateworks-gw2358.dtb
 dtb-$(CONFIG_ARCH_KEYSTONE) += \
        keystone-k2hk-evm.dtb \
        keystone-k2l-evm.dtb \
@@ -363,7 +366,8 @@ dtb-$(CONFIG_SOC_IMX35) += \
        imx35-eukrea-mbimxsd35-baseboard.dtb \
        imx35-pdk.dtb
 dtb-$(CONFIG_SOC_IMX50) += \
-       imx50-evk.dtb
+       imx50-evk.dtb \
+       imx50-kobo-aura.dtb
 dtb-$(CONFIG_SOC_IMX51) += \
        imx51-apf51.dtb \
        imx51-apf51dev.dtb \
@@ -380,6 +384,7 @@ dtb-$(CONFIG_SOC_IMX53) += \
        imx53-kp-ddc.dtb \
        imx53-kp-hsc.dtb \
        imx53-m53evk.dtb \
+       imx53-m53menlo.dtb \
        imx53-mba53.dtb \
        imx53-ppd.dtb \
        imx53-qsb.dtb \
@@ -400,6 +405,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
        imx6dl-cubox-i-emmc-som-v15.dtb \
        imx6dl-cubox-i-som-v15.dtb \
        imx6dl-dfi-fs700-m60.dtb \
+       imx6dl-eckelmann-ci4x10.dtb \
        imx6dl-emcon-avari.dtb \
        imx6dl-gw51xx.dtb \
        imx6dl-gw52xx.dtb \
@@ -579,6 +585,7 @@ dtb-$(CONFIG_SOC_IMX7D) += \
        imx7d-cl-som-imx7.dtb \
        imx7d-colibri-emmc-eval-v3.dtb \
        imx7d-colibri-eval-v3.dtb \
+       imx7d-mba7.dtb \
        imx7d-nitrogen7.dtb \
        imx7d-pico-hobbit.dtb \
        imx7d-pico-pi.dtb \
@@ -586,7 +593,9 @@ dtb-$(CONFIG_SOC_IMX7D) += \
        imx7d-sdb.dtb \
        imx7d-sdb-reva.dtb \
        imx7d-sdb-sht11.dtb \
+       imx7d-zii-rpu2.dtb \
        imx7s-colibri-eval-v3.dtb \
+       imx7s-mba7.dtb \
        imx7s-warp.dtb
 dtb-$(CONFIG_SOC_IMX7ULP) += \
        imx7ulp-evk.dtb
@@ -606,6 +615,7 @@ dtb-$(CONFIG_SOC_VF610) += \
        vf610-zii-dev-rev-b.dtb \
        vf610-zii-dev-rev-c.dtb \
        vf610-zii-scu4-aib.dtb \
+       vf610-zii-spb4.dtb \
        vf610-zii-ssmb-dtu.dtb \
        vf610-zii-ssmb-spu3.dtb
 dtb-$(CONFIG_ARCH_MXS) += \
@@ -909,6 +919,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
        rk3288-veyron-jaq.dtb \
        rk3288-veyron-jerry.dtb \
        rk3288-veyron-mickey.dtb \
+       rk3288-veyron-mighty.dtb \
        rk3288-veyron-minnie.dtb \
        rk3288-veyron-pinky.dtb \
        rk3288-veyron-speedy.dtb \
@@ -964,6 +975,8 @@ dtb-$(CONFIG_ARCH_STM32) += \
        stm32746g-eval.dtb \
        stm32h743i-eval.dtb \
        stm32h743i-disco.dtb \
+       stm32mp157a-dk1.dtb \
+       stm32mp157c-dk2.dtb \
        stm32mp157c-ed1.dtb \
        stm32mp157c-ev1.dtb
 dtb-$(CONFIG_MACH_SUN4I) += \
@@ -1091,6 +1104,7 @@ dtb-$(CONFIG_MACH_SUN8I) += \
        sun8i-h3-orangepi-plus.dtb \
        sun8i-h3-orangepi-plus2e.dtb \
        sun8i-h3-orangepi-zero-plus2.dtb \
+       sun8i-h3-rervision-dvk.dtb \
        sun8i-r16-bananapi-m2m.dtb \
        sun8i-r16-nintendo-nes-classic.dtb \
        sun8i-r16-nintendo-super-nes-classic.dtb \
index 50dcf1290ac6e2a2cd1d38506fe1287d94f33d1c..2f650a736b44ebc5efa469856bac4b5d58efb26f 100644 (file)
 &am33xx_pinmux {
        uart1_pins: pinmux_uart1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x980, PIN_INPUT | MUX_MODE0)      /* uart1_rxd */
-                       AM33XX_IOPAD(0x984, PIN_INPUT | MUX_MODE0)      /* uart1_txd */
-                       AM33XX_IOPAD(0x978, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* uart1_ctsn */
-                       AM33XX_IOPAD(0x97c, PIN_OUTPUT_PULLDOWN | MUX_MODE0)      /* uart1_rtsn */
-                       AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE7)      /* lcd_vsync.gpio2[22] DTR */
-                       AM33XX_IOPAD(0x8e4, PIN_INPUT_PULLDOWN | MUX_MODE7)      /* lcd_hsync.gpio2[23] DSR */
-                       AM33XX_IOPAD(0x8e8, PIN_INPUT_PULLDOWN | MUX_MODE7)      /* lcd_pclk.gpio2[24] DCD */
-                       AM33XX_IOPAD(0x8ec, PIN_INPUT_PULLDOWN | MUX_MODE7)      /* lcd_ac_bias_en.gpio2[25] RI */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE7)      /* lcd_vsync.gpio2[22] DTR */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* lcd_hsync.gpio2[23] DSR */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* lcd_pclk.gpio2[24] DCD */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* lcd_ac_bias_en.gpio2[25] RI */
                >;
        };
 };
index f3f1abd26470c89900c5ae3fc8a0f97360e058c9..1ba66d5e21e87d833591b4c9ffb08efbb1079467 100644 (file)
 &am33xx_pinmux {
        tca6416_pins: pinmux_tca6416_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9b4, PIN_INPUT_PULLUP | MUX_MODE7)      /* xdma_event_intr1.gpio0[20] tca6416 stuff */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_INPUT_PULLUP, MUX_MODE7)      /* xdma_event_intr1.gpio0[20] tca6416 stuff */
                >;
        };
 
        uart1_pins: pinmux_uart1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x980, PIN_INPUT | MUX_MODE0)      /* uart1_rxd */
-                       AM33XX_IOPAD(0x984, PIN_INPUT | MUX_MODE0)      /* uart1_txd */
-                       AM33XX_IOPAD(0x978, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* uart1_ctsn */
-                       AM33XX_IOPAD(0x97c, PIN_OUTPUT_PULLDOWN | MUX_MODE0)      /* uart1_rtsn */
-                       AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE7)      /* lcd_vsync.gpio2[22] DTR */
-                       AM33XX_IOPAD(0x8e4, PIN_INPUT_PULLDOWN | MUX_MODE7)      /* lcd_hsync.gpio2[23] DSR */
-                       AM33XX_IOPAD(0x8e8, PIN_INPUT_PULLDOWN | MUX_MODE7)      /* lcd_pclk.gpio2[24] DCD */
-                       AM33XX_IOPAD(0x8ec, PIN_INPUT_PULLDOWN | MUX_MODE7)      /* lcd_ac_bias_en.gpio2[25] RI */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE7)      /* lcd_vsync.gpio2[22] DTR */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* lcd_hsync.gpio2[23] DSR */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* lcd_pclk.gpio2[24] DCD */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* lcd_ac_bias_en.gpio2[25] RI */
                >;
        };
 
        uart2_pins: pinmux_uart2_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x950, PIN_INPUT | MUX_MODE1)      /* spi0_sclk.uart2_rxd_mux3 */
-                       AM33XX_IOPAD(0x954, PIN_OUTPUT | MUX_MODE1)      /* spi0_d0.uart2_txd_mux3 */
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLDOWN | MUX_MODE2)      /* i2c0_sda.uart2_ctsn_mux0 */
-                       AM33XX_IOPAD(0x98c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)      /* i2c0_scl.uart2_rtsn_mux0 */
-                       AM33XX_IOPAD(0x830, PIN_OUTPUT_PULLDOWN | MUX_MODE7)      /* gpmc_ad12.gpio1[12] DTR */
-                       AM33XX_IOPAD(0x834, PIN_INPUT_PULLDOWN | MUX_MODE7)      /* gpmc_ad13.gpio1[13] DSR */
-                       AM33XX_IOPAD(0x838, PIN_INPUT_PULLDOWN | MUX_MODE7)      /* gpmc_ad14.gpio1[14] DCD */
-                       AM33XX_IOPAD(0x83c, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_ad15.gpio1[15] RI */
-
-                       AM33XX_IOPAD(0x9a0, PIN_INPUT_PULLUP | MUX_MODE7)      /* mcasp0_aclkr.gpio3[18], INPUT_PULLDOWN | MODE7 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT, MUX_MODE1)      /* spi0_sclk.uart2_rxd_mux3 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_OUTPUT, MUX_MODE1)      /* spi0_d0.uart2_txd_mux3 */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLDOWN, MUX_MODE2)      /* i2c0_sda.uart2_ctsn_mux0 */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* i2c0_scl.uart2_rtsn_mux0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_OUTPUT_PULLDOWN, MUX_MODE7)      /* gpmc_ad12.gpio1[12] DTR */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* gpmc_ad13.gpio1[13] DSR */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* gpmc_ad14.gpio1[14] DCD */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* gpmc_ad15.gpio1[15] RI */
+
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKR, PIN_INPUT_PULLUP, MUX_MODE7)      /* mcasp0_aclkr.gpio3[18], INPUT_PULLDOWN | MODE7 */
                >;
        };
 };
index 42f473f0ed77661e305684551bb09f03fba6b955..eed65fc0e8e65af59c2ec1c9aed25b4721745fa8 100644 (file)
 &am33xx_pinmux {
        tca6416_pins: pinmux_tca6416_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9b4, PIN_INPUT_PULLUP | MUX_MODE7)      /* xdma_event_intr1.gpio0[20] tca6416 stuff */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_INPUT_PULLUP, MUX_MODE7)      /* xdma_event_intr1.gpio0[20] tca6416 stuff */
                >;
        };
 
 
        dcan1_pins: pinmux_dcan1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x968, PIN_OUTPUT | MUX_MODE2)      /* uart0_ctsn.dcan1_tx_mux0 */
-                       AM33XX_IOPAD(0x96c, PIN_INPUT | MUX_MODE2)      /* uart0_rtsn.dcan1_rx_mux0 */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_CTSN, PIN_OUTPUT, MUX_MODE2)      /* uart0_ctsn.dcan1_tx_mux0 */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_INPUT, MUX_MODE2)      /* uart0_rtsn.dcan1_rx_mux0 */
                >;
        };
 
        uart1_pins: pinmux_uart1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x980, PIN_INPUT | MUX_MODE0)      /* uart1_rxd */
-                       AM33XX_IOPAD(0x984, PIN_INPUT | MUX_MODE0)      /* uart1_txd */
-                       AM33XX_IOPAD(0x978, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* uart1_ctsn */
-                       AM33XX_IOPAD(0x97c, PIN_OUTPUT_PULLDOWN | MUX_MODE0)      /* uart1_rtsn */
-                       AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE7)      /* lcd_vsync.gpio2[22] DTR */
-                       AM33XX_IOPAD(0x8e4, PIN_INPUT_PULLDOWN | MUX_MODE7)      /* lcd_hsync.gpio2[23] DSR */
-                       AM33XX_IOPAD(0x8e8, PIN_INPUT_PULLDOWN | MUX_MODE7)      /* lcd_pclk.gpio2[24] DCD */
-                       AM33XX_IOPAD(0x8ec, PIN_INPUT_PULLDOWN | MUX_MODE7)      /* lcd_ac_bias_en.gpio2[25] RI */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE7)      /* lcd_vsync.gpio2[22] DTR */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* lcd_hsync.gpio2[23] DSR */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* lcd_pclk.gpio2[24] DCD */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* lcd_ac_bias_en.gpio2[25] RI */
                >;
        };
 
        uart2_pins: pinmux_uart2_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x950, PIN_INPUT | MUX_MODE1)      /* spi0_sclk.uart2_rxd_mux3 */
-                       AM33XX_IOPAD(0x954, PIN_OUTPUT | MUX_MODE1)      /* spi0_d0.uart2_txd_mux3 */
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLDOWN | MUX_MODE2)      /* i2c0_sda.uart2_ctsn_mux0 */
-                       AM33XX_IOPAD(0x98c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)      /* i2c0_scl.uart2_rtsn_mux0 */
-                       AM33XX_IOPAD(0x830, PIN_OUTPUT_PULLDOWN | MUX_MODE7)      /* gpmc_ad12.gpio1[12] DTR */
-                       AM33XX_IOPAD(0x834, PIN_INPUT_PULLDOWN | MUX_MODE7)      /* gpmc_ad13.gpio1[13] DSR */
-                       AM33XX_IOPAD(0x838, PIN_INPUT_PULLDOWN | MUX_MODE7)      /* gpmc_ad14.gpio1[14] DCD */
-                       AM33XX_IOPAD(0x83c, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_ad15.gpio1[15] RI */
-
-                       AM33XX_IOPAD(0x9a0, PIN_INPUT_PULLUP | MUX_MODE7)      /* mcasp0_aclkr.gpio3[18], INPUT_PULLDOWN | MODE7 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT, MUX_MODE1)      /* spi0_sclk.uart2_rxd_mux3 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_OUTPUT, MUX_MODE1)      /* spi0_d0.uart2_txd_mux3 */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLDOWN, MUX_MODE2)      /* i2c0_sda.uart2_ctsn_mux0 */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* i2c0_scl.uart2_rtsn_mux0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_OUTPUT_PULLDOWN, MUX_MODE7)      /* gpmc_ad12.gpio1[12] DTR */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* gpmc_ad13.gpio1[13] DSR */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* gpmc_ad14.gpio1[14] DCD */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* gpmc_ad15.gpio1[15] RI */
+
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKR, PIN_INPUT_PULLUP, MUX_MODE7)      /* mcasp0_aclkr.gpio3[18], INPUT_PULLDOWN | MODE7 */
                >;
        };
 
index 3ab1767d5c135182c45e4f8e333eb8175df6ebba..fe75050c016f075e809eb055cff655840ac1c7c9 100644 (file)
@@ -42,9 +42,9 @@
 &am33xx_pinmux {
        user_leds: pinmux_user_leds {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x908, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* mii1_col.gpio3_0 PWR LED */
-                       AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* mii1_txd3.gpio0_16 WLAN LED */
-                       AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* mii1_txd2.gpio0_17 APP LED */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_OUTPUT_PULLDOWN, MUX_MODE7)     /* mii1_col.gpio3_0 PWR LED */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_OUTPUT_PULLDOWN, MUX_MODE7)    /* mii1_txd3.gpio0_16 WLAN LED */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE7)    /* mii1_txd2.gpio0_17 APP LED */
                >;
        };
 };
index 8c6fc4161ad701d09e99612559a6b04a94ea6a83..b572ad1f1377b03b473ca7a23c817bca077a5b0c 100644 (file)
 &am33xx_pinmux {
        mmc2_pins: pinmux_mmc2_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x820, PIN_INPUT_PULLUP | MUX_MODE2)      /* gpmc_ad8.mmc1_dat0_mux0 */
-                       AM33XX_IOPAD(0x824, PIN_INPUT_PULLUP | MUX_MODE2)      /* gpmc_ad9.mmc1_dat1_mux0 */
-                       AM33XX_IOPAD(0x828, PIN_INPUT_PULLUP | MUX_MODE2)      /* gpmc_ad10.mmc1_dat2_mux0 */
-                       AM33XX_IOPAD(0x82c, PIN_INPUT_PULLUP | MUX_MODE2)      /* gpmc_ad11.mmc1_dat3_mux0 */
-                       AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2)      /* gpmc_csn1.mmc1_clk_mux0 */
-                       AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2)      /* gpmc_csn2.mmc1_cmd_mux0 */
-                       AM33XX_IOPAD(0x9e4, PIN_INPUT_PULLUP | MUX_MODE7)      /* emu0.gpio3[7] */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD8, PIN_INPUT_PULLUP, MUX_MODE2)      /* gpmc_ad8.mmc1_dat0_mux0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD9, PIN_INPUT_PULLUP, MUX_MODE2)      /* gpmc_ad9.mmc1_dat1_mux0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_INPUT_PULLUP, MUX_MODE2)      /* gpmc_ad10.mmc1_dat2_mux0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_INPUT_PULLUP, MUX_MODE2)      /* gpmc_ad11.mmc1_dat3_mux0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_INPUT_PULLUP, MUX_MODE2)      /* gpmc_csn1.mmc1_clk_mux0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_INPUT_PULLUP, MUX_MODE2)      /* gpmc_csn2.mmc1_cmd_mux0 */
+                       AM33XX_PADCONF(AM335X_PIN_EMU0, PIN_INPUT_PULLUP, MUX_MODE7)      /* emu0.gpio3[7] */
                >;
        };
 
        wl12xx_gpio: pinmux_wl12xx_gpio {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9e8, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* emu1.gpio3[8] */
+                       AM33XX_PADCONF(AM335X_PIN_EMU1, PIN_OUTPUT_PULLUP, MUX_MODE7)      /* emu1.gpio3[8] */
                >;
        };
 
        tps65910_pins: pinmux_tps65910_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x878, PIN_INPUT_PULLUP | MUX_MODE7)      /* gpmc_ben1.gpio1[28] */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_INPUT_PULLUP, MUX_MODE7)      /* gpmc_ben1.gpio1[28] */
                >;
        };
 
        i2c1_pins: pinmux_i2c1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x958, PIN_INPUT | MUX_MODE2)      /* spi0_d1.i2c1_sda_mux3 */
-                       AM33XX_IOPAD(0x95c, PIN_INPUT | MUX_MODE2)      /* spi0_cs0.i2c1_scl_mux3 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D1, PIN_INPUT, MUX_MODE2)      /* spi0_d1.i2c1_sda_mux3 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_INPUT, MUX_MODE2)      /* spi0_cs0.i2c1_scl_mux3 */
                >;
        };
 
        uart0_pins: pinmux_uart0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)            /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        cpsw_default: cpsw_default {
                pinctrl-single,pins = <
                        /* Slave 1 */
-                       AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE1)       /* mii1_crs.rmii1_crs_dv */
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE1)      /* mii1_tx_en.rmii1_txen */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE1)      /* mii1_txd1.rmii1_txd1 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE1)      /* mii1_txd0.rmii1_txd0 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE1)      /* mii1_rxd1.rmii1_rxd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE1)      /* mii1_rxd0.rmii1_rxd0 */
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* rmii1_ref_clk.rmii1_refclk */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE1)       /* mii1_crs.rmii1_crs_dv */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE1)      /* mii1_tx_en.rmii1_txen */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLDOWN, MUX_MODE1)      /* mii1_txd1.rmii1_txd1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE1)      /* mii1_txd0.rmii1_txd0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE1)      /* mii1_rxd1.rmii1_rxd1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE1)      /* mii1_rxd0.rmii1_rxd0 */
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE0)      /* rmii1_ref_clk.rmii1_refclk */
 
 
                        /* Slave 2 */
-                       AM33XX_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a0.rgmii2_tctl */
-                       AM33XX_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a1.rgmii2_rctl */
-                       AM33XX_IOPAD(0x848, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a2.rgmii2_td3 */
-                       AM33XX_IOPAD(0x84c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a3.rgmii2_td2 */
-                       AM33XX_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a4.rgmii2_td1 */
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a5.rgmii2_td0 */
-                       AM33XX_IOPAD(0x858, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a6.rgmii2_tclk */
-                       AM33XX_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a7.rgmii2_rclk */
-                       AM33XX_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a8.rgmii2_rd3 */
-                       AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a9.rgmii2_rd2 */
-                       AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a10.rgmii2_rd1 */
-                       AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a11.rgmii2_rd0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a0.rgmii2_tctl */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A1, PIN_INPUT_PULLDOWN, MUX_MODE2)       /* gpmc_a1.rgmii2_rctl */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a2.rgmii2_td3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A3, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a3.rgmii2_td2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a4.rgmii2_td1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a5.rgmii2_td0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a6.rgmii2_tclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_INPUT_PULLDOWN, MUX_MODE2)       /* gpmc_a7.rgmii2_rclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_INPUT_PULLDOWN, MUX_MODE2)       /* gpmc_a8.rgmii2_rd3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A9, PIN_INPUT_PULLDOWN, MUX_MODE2)       /* gpmc_a9.rgmii2_rd2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a10.rgmii2_rd1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a11.rgmii2_rd0 */
                >;
        };
 
        cpsw_sleep: cpsw_sleep {
                pinctrl-single,pins = <
                        /* Slave 1 reset value */
-                       AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
 
                        /* Slave 2 reset value*/
-                       AM33XX_IOPAD(0x840, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x848, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x84c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x850, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x854, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x858, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A9, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        davinci_mdio_default: davinci_mdio_default {
                pinctrl-single,pins = <
                        /* MDIO */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)                      /* mdio_clk.mdio_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)    /* mdio_data.mdio_data */
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)                    /* mdio_clk.mdio_clk */
                >;
        };
 
        davinci_mdio_sleep: davinci_mdio_sleep {
                pinctrl-single,pins = <
                        /* MDIO reset value */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        nandflash_pins_s0: nandflash_pins_s0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad0.gpmc_ad0 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad1.gpmc_ad1 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad2.gpmc_ad2 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad3.gpmc_ad3 */
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad4.gpmc_ad4 */
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad5.gpmc_ad5 */
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad6.gpmc_ad6 */
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad7.gpmc_ad7 */
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_wait0.gpmc_wait0 */
-                       AM33XX_IOPAD(0x874, PIN_INPUT_PULLUP | MUX_MODE7)       /* gpmc_wpn.gpio0_30 */
-                       AM33XX_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE0)             /* gpmc_csn0.gpmc_csn0  */
-                       AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE0)             /* gpmc_advn_ale.gpmc_advn_ale */
-                       AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE0)             /* gpmc_oen_ren.gpmc_oen_ren */
-                       AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE0)             /* gpmc_wen.gpmc_wen */
-                       AM33XX_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE0)             /* gpmc_be0n_cle.gpmc_be0n_cle */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE0)        /* gpmc_ad0.gpmc_ad0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE0)        /* gpmc_ad1.gpmc_ad1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE0)        /* gpmc_ad2.gpmc_ad2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE0)        /* gpmc_ad3.gpmc_ad3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE0)        /* gpmc_ad4.gpmc_ad4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE0)        /* gpmc_ad5.gpmc_ad5 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE0)        /* gpmc_ad6.gpmc_ad6 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE0)        /* gpmc_ad7.gpmc_ad7 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLUP, MUX_MODE0)      /* gpmc_wait0.gpmc_wait0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_INPUT_PULLUP, MUX_MODE7)        /* gpmc_wpn.gpio0_30 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN0, PIN_OUTPUT, MUX_MODE0)             /* gpmc_csn0.gpmc_csn0  */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_ADVN_ALE, PIN_OUTPUT, MUX_MODE0)         /* gpmc_advn_ale.gpmc_advn_ale */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_OEN_REN, PIN_OUTPUT, MUX_MODE0)          /* gpmc_oen_ren.gpmc_oen_ren */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WEN, PIN_OUTPUT, MUX_MODE0)              /* gpmc_wen.gpmc_wen */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN0_CLE, PIN_OUTPUT, MUX_MODE0)         /* gpmc_be0n_cle.gpmc_be0n_cle */
                >;
        };
 };
index 29782be076057904bd636a557f5d5db94f019061..cbd5bd8c57de73ab21f466950dfdb8a32498cf48 100644 (file)
 &am33xx_pinmux {
        nxp_hdmi_pins: pinmux_nxp_hdmi_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9b0, PIN_OUTPUT | MUX_MODE3)     /* xdma_event_intr0.clkout1 */
-                       AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data0 */
-                       AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data1 */
-                       AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data2 */
-                       AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)     /* lcd_data3 */
-                       AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data4 */
-                       AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data5 */
-                       AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data6 */
-                       AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)     /* lcd_data7 */
-                       AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data8 */
-                       AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data9 */
-                       AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data10 */
-                       AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)     /* lcd_data11 */
-                       AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data12 */
-                       AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data13 */
-                       AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data14 */
-                       AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)     /* lcd_data15 */
-                       AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE0)     /* lcd_vsync */
-                       AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE0)     /* lcd_hsync */
-                       AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE0)     /* lcd_pclk */
-                       AM33XX_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE0)     /* lcd_ac_bias_en */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT, MUX_MODE3)      /* xdma_event_intr0.clkout1 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT, MUX_MODE0)
                >;
        };
        nxp_hdmi_off_pins: pinmux_nxp_hdmi_off_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9b0, PIN_OUTPUT | MUX_MODE3)     /* xdma_event_intr0.clkout1 */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT, MUX_MODE3)      /* xdma_event_intr0.clkout1 */
                >;
        };
 
        leds_base_pins: pinmux_leds_base_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_a5.gpio1_21 */
-                       AM33XX_IOPAD(0x888, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_csn3.gpio2_0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE7)      /* gpmc_a5.gpio1_21 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN3, PIN_OUTPUT_PULLDOWN, MUX_MODE7)    /* gpmc_csn3.gpio2_0 */
                >;
        };
 };
index 456eef57ef8971dae75d6e422032f57515a0dcc3..42cfc3b37c32a59c8431475d22e497557b9bc86c 100644 (file)
 
        user_leds_s0: user_leds_s0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_a5.gpio1_21 */
-                       AM33XX_IOPAD(0x858, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* gpmc_a6.gpio1_22 */
-                       AM33XX_IOPAD(0x85c, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_a7.gpio1_23 */
-                       AM33XX_IOPAD(0x860, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* gpmc_a8.gpio1_24 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE7)      /* gpmc_a5.gpio1_21 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_OUTPUT_PULLUP, MUX_MODE7)        /* gpmc_a6.gpio1_22 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_OUTPUT_PULLDOWN, MUX_MODE7)      /* gpmc_a7.gpio1_23 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_OUTPUT_PULLUP, MUX_MODE7)        /* gpmc_a8.gpio1_24 */
                >;
        };
 
        i2c0_pins: pinmux_i2c0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_sda.i2c0_sda */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_scl.i2c0_scl */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLUP, MUX_MODE0)        /* i2c0_sda.i2c0_sda */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLUP, MUX_MODE0)        /* i2c0_scl.i2c0_scl */
                >;
        };
 
        i2c2_pins: pinmux_i2c2_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x978, PIN_INPUT_PULLUP | MUX_MODE3)       /* uart1_ctsn.i2c2_sda */
-                       AM33XX_IOPAD(0x97c, PIN_INPUT_PULLUP | MUX_MODE3)       /* uart1_rtsn.i2c2_scl */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT_PULLUP, MUX_MODE3)      /* uart1_ctsn.i2c2_sda */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_INPUT_PULLUP, MUX_MODE3)      /* uart1_rtsn.i2c2_scl */
                >;
        };
 
        uart0_pins: pinmux_uart0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        clkout2_pin: pinmux_clkout2_pin {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9b4, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* xdma_event_intr1.clkout2 */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_OUTPUT_PULLDOWN, MUX_MODE3)     /* xdma_event_intr1.clkout2 */
                >;
        };
 
        cpsw_default: cpsw_default {
                pinctrl-single,pins = <
                        /* Slave 1 */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_rxerr.mii1_rxerr */
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* mii1_txen.mii1_txen */
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_rxdv.mii1_rxdv */
-                       AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* mii1_txd3.mii1_txd3 */
-                       AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* mii1_txd2.mii1_txd2 */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* mii1_txd1.mii1_txd1 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* mii1_txd0.mii1_txd0 */
-                       AM33XX_IOPAD(0x92c, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_txclk.mii1_txclk */
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_rxclk.mii1_rxclk */
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_rxd3.mii1_rxd3 */
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_rxd2.mii1_rxd2 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_rxd1.mii1_rxd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_rxd0.mii1_rxd0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        cpsw_sleep: cpsw_sleep {
                pinctrl-single,pins = <
                        /* Slave 1 reset value */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        davinci_mdio_default: davinci_mdio_default {
                pinctrl-single,pins = <
                        /* MDIO */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)                      /* mdio_clk.mdio_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        davinci_mdio_sleep: davinci_mdio_sleep {
                pinctrl-single,pins = <
                        /* MDIO reset value */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        mmc1_pins: pinmux_mmc1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7)              /* spio0_cs1.gpio0_6 */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat0.mmc0_dat0 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat1.mmc0_dat1 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat2.mmc0_dat2 */
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat3.mmc0_dat3 */
-                       AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_cmd.mmc0_cmd */
-                       AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_clk.mmc0_clk */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT, MUX_MODE7)               /* spio0_cs1.gpio0_6 */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        emmc_pins: pinmux_emmc_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
-                       AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_INPUT_PULLUP, MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_INPUT_PULLUP, MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
                >;
        };
 };
index e543c2bee8c2b714a58088d315b128c2c1fb034e..283e288b6e428d2e5e32390c7e0d7f266c77a9b5 100644 (file)
 &am33xx_pinmux {
        nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* xdma_event_intr0 */
-                       AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data0.lcd_data0 */
-                       AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data1.lcd_data1 */
-                       AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data2.lcd_data2 */
-                       AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)             /* lcd_data3.lcd_data3 */
-                       AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data4.lcd_data4 */
-                       AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data5.lcd_data5 */
-                       AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data6.lcd_data6 */
-                       AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)             /* lcd_data7.lcd_data7 */
-                       AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data8.lcd_data8 */
-                       AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data9.lcd_data9 */
-                       AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data10.lcd_data10 */
-                       AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)             /* lcd_data11.lcd_data11 */
-                       AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data12.lcd_data12 */
-                       AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data13.lcd_data13 */
-                       AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data14.lcd_data14 */
-                       AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)             /* lcd_data15.lcd_data15 */
-                       AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* lcd_vsync.lcd_vsync */
-                       AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* lcd_hsync.lcd_hsync */
-                       AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* lcd_pclk.lcd_pclk */
-                       AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* lcd_ac_bias_en.lcd_ac_bias_en */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLDOWN, MUX_MODE3)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        nxp_hdmi_bonelt_off_pins: nxp_hdmi_bonelt_off_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* xdma_event_intr0 */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLDOWN, MUX_MODE3)
                >;
        };
 
        mcasp0_pins: mcasp0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9ac, PIN_INPUT_PULLUP | MUX_MODE0) /* mcasp0_ahcklx.mcasp0_ahclkx */
-                       AM33XX_IOPAD(0x99c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2*/
-                       AM33XX_IOPAD(0x994, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mcasp0_fsx.mcasp0_fsx */
-                       AM33XX_IOPAD(0x990, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_aclkx.mcasp0_aclkx */
-                       AM33XX_IOPAD(0x86c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a11.GPIO1_27 */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKX, PIN_INPUT_PULLUP, MUX_MODE0) /* mcasp0_ahcklx.mcasp0_ahclkx */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKR, PIN_OUTPUT_PULLDOWN, MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2*/
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_OUTPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a11.GPIO1_27 */
                >;
        };
 };
index 83f49f616b19c021da9b65ad7db2ec9415f5da2b..5b275c96fccf5d955cfaf5f845f3fdaeb9e4b274 100644 (file)
 &am33xx_pinmux {
        bt_pins: pinmux_bt_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* gmii1_txd0.gpio0_28 - BT_EN */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLUP, MUX_MODE7)      /* gmii1_txd0.gpio0_28 - BT_EN */
                >;
        };
 
        mmc3_pins: pinmux_mmc3_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLUP | MUX_MODE6 ) /* (L15) gmii1_rxd1.mmc2_clk */
-                       AM33XX_IOPAD(0x914, PIN_INPUT_PULLUP | MUX_MODE6 ) /* (J16) gmii1_txen.mmc2_cmd */
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLUP | MUX_MODE5 ) /* (J17) gmii1_rxdv.mmc2_dat0 */
-                       AM33XX_IOPAD(0x91c, PIN_INPUT_PULLUP | MUX_MODE5 ) /* (J18) gmii1_txd3.mmc2_dat1 */
-                       AM33XX_IOPAD(0x920, PIN_INPUT_PULLUP | MUX_MODE5 ) /* (K15) gmii1_txd2.mmc2_dat2 */
-                       AM33XX_IOPAD(0x908, PIN_INPUT_PULLUP | MUX_MODE5 ) /* (H16) gmii1_col.mmc2_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLUP, MUX_MODE6 ) /* (L15) gmii1_rxd1.mmc2_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLUP, MUX_MODE6 ) /* (J16) gmii1_txen.mmc2_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (J17) gmii1_rxdv.mmc2_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (J18) gmii1_txd3.mmc2_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (K15) gmii1_txd2.mmc2_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLUP, MUX_MODE5 ) /* (H16) gmii1_col.mmc2_dat3 */
                >;
        };
 
        uart3_pins: pinmux_uart3_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLUP | MUX_MODE1)       /* gmii1_rxd3.uart3_rxd */
-                       AM33XX_IOPAD(0x938, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* gmii1_rxd2.uart3_txd */
-                       AM33XX_IOPAD(0x948, PIN_INPUT | MUX_MODE3)              /* mdio_data.uart3_ctsn */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* mdio_clk.uart3_rtsn */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLUP, MUX_MODE1)       /* gmii1_rxd3.uart3_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE1)    /* gmii1_rxd2.uart3_txd */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT, MUX_MODE3)           /* mdio_data.uart3_ctsn */
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLDOWN, MUX_MODE3)  /* mdio_clk.uart3_rtsn */
                >;
        };
 
        wl18xx_pins: pinmux_wl18xx_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x92c, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gmii1_txclk.gpio3_9 WL_EN */
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii1_refclk.gpio0_29 WL_IRQ */
-                       AM33XX_IOPAD(0x930, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* gmii1_rxclk.gpio3_10 LS_BUF_EN */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE7)  /* gmii1_txclk.gpio3_9 WL_EN */
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7) /* rmii1_refclk.gpio0_29 WL_IRQ */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_OUTPUT_PULLUP, MUX_MODE7)    /* gmii1_rxclk.gpio3_10 LS_BUF_EN */
                >;
        };
 };
index ccb147e70d179e144e7911cc85032e844a4b272e..8d241c856c8db578ba1279d2dd1432facee7a3a2 100644 (file)
 &am33xx_pinmux {
        user_leds_s0: user_leds_s0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT | MUX_MODE7) /* (V15) gpmc_a5.gpio1[21] - USR_LED_0 */
-                       AM33XX_IOPAD(0x858, PIN_OUTPUT | MUX_MODE7) /* (U15) gpmc_a6.gpio1[22] - USR_LED_1 */
-                       AM33XX_IOPAD(0x85c, PIN_OUTPUT | MUX_MODE7) /* (T15) gpmc_a7.gpio1[23] - USR_LED_2 */
-                       AM33XX_IOPAD(0x860, PIN_OUTPUT | MUX_MODE7) /* (V16) gpmc_a8.gpio1[24] - USR_LED_3 */
-                       AM33XX_IOPAD(0x9b0, PIN_OUTPUT | MUX_MODE7) /* (A15) xdma_event_intr0.gpio0[19] - WIFI_LED */
-                       AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE7) /* (R7) gpmc_advn_ale.gpio2[2] - P8.7, LED_RED, GP1_PIN_5 */
-                       AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE7) /* (T7) gpmc_oen_ren.gpio2[3] - P8.8, LED_GREEN, GP1_PIN_6 */
-                       AM33XX_IOPAD(0x82c, PIN_OUTPUT | MUX_MODE7) /* (U12) gpmc_ad11.gpio0[27] - P8.17, BATT_LED_1 */
-                       AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE7) /* (T5) lcd_data15.gpio0[11] - P8.32, BATT_LED_2 */
-                       AM33XX_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE7) /* (V6) gpmc_csn0.gpio1[29] - P8.26, BATT_LED_3 */
-                       AM33XX_IOPAD(0x828, PIN_OUTPUT | MUX_MODE7) /* (T11) gpmc_ad10.gpio0[26] - P8.14, BATT_LED_4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT, MUX_MODE7) /* (V15) gpmc_a5.gpio1[21] - USR_LED_0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_OUTPUT, MUX_MODE7) /* (U15) gpmc_a6.gpio1[22] - USR_LED_1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_OUTPUT, MUX_MODE7) /* (T15) gpmc_a7.gpio1[23] - USR_LED_2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_OUTPUT, MUX_MODE7) /* (V16) gpmc_a8.gpio1[24] - USR_LED_3 */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT, MUX_MODE7) /* (A15) xdma_event_intr0.gpio0[19] - WIFI_LED */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_ADVN_ALE, PIN_OUTPUT, MUX_MODE7) /* (R7) gpmc_advn_ale.gpio2[2] - P8.7, LED_RED, GP1_PIN_5 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_OEN_REN, PIN_OUTPUT, MUX_MODE7) /* (T7) gpmc_oen_ren.gpio2[3] - P8.8, LED_GREEN, GP1_PIN_6 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_OUTPUT, MUX_MODE7) /* (U12) gpmc_ad11.gpio0[27] - P8.17, BATT_LED_1 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE7) /* (T5) lcd_data15.gpio0[11] - P8.32, BATT_LED_2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN0, PIN_OUTPUT, MUX_MODE7) /* (V6) gpmc_csn0.gpio1[29] - P8.26, BATT_LED_3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_OUTPUT, MUX_MODE7) /* (T11) gpmc_ad10.gpio0[26] - P8.14, BATT_LED_4 */
 
                >;
        };
 
        i2c0_pins: pinmux_i2c0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)       /* (C17) I2C0_SDA.I2C0_SDA */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)       /* (C16) I2C0_SCL.I2C0_SCL */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLUP, MUX_MODE0)        /* (C17) I2C0_SDA.I2C0_SDA */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLUP, MUX_MODE0)        /* (C16) I2C0_SCL.I2C0_SCL */
                >;
        };
 
        i2c2_pins: pinmux_i2c2_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x978, PIN_INPUT_PULLUP | MUX_MODE3)       /* (D18) uart1_ctsn.I2C2_SDA */
-                       AM33XX_IOPAD(0x97c, PIN_INPUT_PULLUP | MUX_MODE3)       /* (D17) uart1_rtsn.I2C2_SCL */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT_PULLUP, MUX_MODE3)      /* (D18) uart1_ctsn.I2C2_SDA */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_INPUT_PULLUP, MUX_MODE3)      /* (D17) uart1_rtsn.I2C2_SCL */
                >;
        };
 
        /* UT0 */
        uart0_pins: pinmux_uart0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* (E15) uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* (E16) uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        /* UT1 */
        uart1_pins: pinmux_uart1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0)       /* (D16) uart1_rxd.uart1_rxd */
-                       AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* (D15) uart1_txd.uart1_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        /* GPS */
        uart2_pins: pinmux_uart2_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE1)       /* (A17) spi0_sclk.uart2_rxd */
-                       AM33XX_IOPAD(0x954, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* (B17) spi0_d0.uart2_txd */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT_PULLUP, MUX_MODE1)       /* (A17) spi0_sclk.uart2_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_OUTPUT_PULLDOWN, MUX_MODE1)      /* (B17) spi0_d0.uart2_txd */
                >;
        };
 
        /* DSM2 */
        uart4_pins: pinmux_uart4_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE6)       /* (T17) gpmc_wait0.uart4_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLUP, MUX_MODE6)      /* (T17) gpmc_wait0.uart4_rxd */
                >;
        };
 
        /* UT5 */
        uart5_pins: pinmux_uart5_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8C4, PIN_INPUT_PULLUP | MUX_MODE4)       /* (U2) lcd_data9.uart5_rxd */
-                       AM33XX_IOPAD(0x8C0, PIN_OUTPUT_PULLDOWN | MUX_MODE4)    /* (U1) lcd_data8.uart5_txd */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_INPUT_PULLUP, MUX_MODE4)       /* (U2) lcd_data9.uart5_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT_PULLDOWN, MUX_MODE4)    /* (U1) lcd_data8.uart5_txd */
                >;
        };
 
        mmc1_pins: pinmux_mmc1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7)              /* (C15) spi0_cs1.gpio0[6] */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT, MUX_MODE7)               /* (C15) spi0_cs1.gpio0[6] */
                >;
        };
 
        mmc2_pins: pinmux_mmc2_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2)       /* (U9) gpmc_csn1.mmc1_clk */
-                       AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2)       /* (V9) gpmc_csn2.mmc1_cmd */
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1)       /* (U7) gpmc_ad0.mmc1_dat0 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1)       /* (V7) gpmc_ad1.mmc1_dat1 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1)       /* (R8) gpmc_ad2.mmc1_dat2 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1)       /* (T8) gpmc_ad3.mmc1_dat3 */
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1)       /* (U8) gpmc_ad4.mmc1_dat4 */
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1)       /* (V8) gpmc_ad5.mmc1_dat5 */
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1)       /* (R9) gpmc_ad6.mmc1_dat6 */
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1)       /* (T9) gpmc_ad7.mmc1_dat7 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_INPUT_PULLUP, MUX_MODE2)       /* (U9) gpmc_csn1.mmc1_clk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_INPUT_PULLUP, MUX_MODE2)       /* (V9) gpmc_csn2.mmc1_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE1)        /* (U7) gpmc_ad0.mmc1_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE1)        /* (V7) gpmc_ad1.mmc1_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE1)        /* (R8) gpmc_ad2.mmc1_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE1)        /* (T8) gpmc_ad3.mmc1_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE1)        /* (U8) gpmc_ad4.mmc1_dat4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE1)        /* (V8) gpmc_ad5.mmc1_dat5 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE1)        /* (R9) gpmc_ad6.mmc1_dat6 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE1)        /* (T9) gpmc_ad7.mmc1_dat7 */
                >;
        };
 
        mmc3_pins: pinmux_mmc3_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLUP | MUX_MODE6)       /* (L15) gmii1_rxd1.mmc2_clk */
-                       AM33XX_IOPAD(0x914, PIN_INPUT_PULLUP | MUX_MODE6)       /* (J16) gmii1_txen.mmc2_cmd */
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLUP | MUX_MODE5)       /* (J17) gmii1_rxdv.mmc2_dat0 */
-                       AM33XX_IOPAD(0x91c, PIN_INPUT_PULLUP | MUX_MODE5)       /* (J18) gmii1_txd3.mmc2_dat1 */
-                       AM33XX_IOPAD(0x920, PIN_INPUT_PULLUP | MUX_MODE5)       /* (K15) gmii1_txd2.mmc2_dat2 */
-                       AM33XX_IOPAD(0x908, PIN_INPUT_PULLUP | MUX_MODE5)       /* (H16) gmii1_col.mmc2_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLUP, MUX_MODE6)       /* (L15) gmii1_rxd1.mmc2_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLUP, MUX_MODE6)      /* (J16) gmii1_txen.mmc2_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLUP, MUX_MODE5)      /* (J17) gmii1_rxdv.mmc2_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_INPUT_PULLUP, MUX_MODE5)       /* (J18) gmii1_txd3.mmc2_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_INPUT_PULLUP, MUX_MODE5)       /* (K15) gmii1_txd2.mmc2_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLUP, MUX_MODE5)        /* (H16) gmii1_col.mmc2_dat3 */
                >;
        };
 
        bt_pins: pinmux_bt_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* (K17) gmii1_txd0.gpio0[28] - BT_EN */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLUP, MUX_MODE7)      /* (K17) gmii1_txd0.gpio0[28] - BT_EN */
                >;
        };
 
        uart3_pins: pinmux_uart3_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLUP | MUX_MODE1)       /* (L17) gmii1_rxd3.uart3_rxd */
-                       AM33XX_IOPAD(0x938, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* (L16) gmii1_rxd2.uart3_txd */
-                       AM33XX_IOPAD(0x948, PIN_INPUT | MUX_MODE3)              /* (M17) mdio_data.uart3_ctsn */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* (M18) mdio_clk.uart3_rtsn */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLUP, MUX_MODE1)       /* (L17) gmii1_rxd3.uart3_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE1)    /* (L16) gmii1_rxd2.uart3_txd */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT, MUX_MODE3)           /* (M17) mdio_data.uart3_ctsn */
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLDOWN, MUX_MODE3)  /* (M18) mdio_clk.uart3_rtsn */
                >;
        };
 
        wl18xx_pins: pinmux_wl18xx_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x92c, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* (K18) gmii1_txclk.gpio3[9] - WL_EN */
-                       AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* (K16) gmii1_txd1.gpio0[21] - WL_IRQ */
-                       AM33XX_IOPAD(0x930, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* (L18) gmii1_rxclk.gpio3[10] - LS_BUF_EN */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE7)  /* (K18) gmii1_txclk.gpio3[9] - WL_EN */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* (K16) gmii1_txd1.gpio0[21] - WL_IRQ */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_OUTPUT_PULLUP, MUX_MODE7)    /* (L18) gmii1_rxclk.gpio3[10] - LS_BUF_EN */
                >;
        };
 
        /* DCAN */
        dcan1_pins: pinmux_dcan1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x96c, PIN_INPUT | MUX_MODE2)              /* (E17) uart0_rtsn.dcan1_rx */
-                       AM33XX_IOPAD(0x968, PIN_OUTPUT | MUX_MODE2)             /* (E18) uart0_ctsn.dcan1_tx */
-                       AM33XX_IOPAD(0x940, PIN_OUTPUT | MUX_MODE7)             /* (M16) gmii1_rxd0.gpio2[21] */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_INPUT, MUX_MODE2)             /* (E17) uart0_rtsn.dcan1_rx */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_CTSN, PIN_OUTPUT, MUX_MODE2)            /* (E18) uart0_ctsn.dcan1_tx */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_OUTPUT, MUX_MODE7)             /* (M16) gmii1_rxd0.gpio2[21] */
                >;
        };
 };
index 853e6d3a028dc4c4eb31c23712a808d35e49ee78..71317e372ec7f38143f4ad59a43a601ff9f6199e 100644 (file)
@@ -27,8 +27,8 @@
 &am33xx_pinmux {
        uart2_pins: uart2_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x950, PIN_INPUT | MUX_MODE1)      /* spi0_sclk.uart2_rxd */
-                       AM33XX_IOPAD(0x954, PIN_OUTPUT | MUX_MODE1)     /* spi0_d0.uart2_txd */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT, MUX_MODE1)      /* spi0_sclk.uart2_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_OUTPUT, MUX_MODE1)       /* spi0_d0.uart2_txd */
                >;
        };
 };
index 57731f0daf103ca872b4ac727c1ce491bc85979b..7db86a9c836a7714809de5fee551e88a68b3eca2 100644 (file)
 &am33xx_pinmux {
        bt_pins: pinmux_bt_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x878, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* gpmc_ad12.gpio1_28 BT_EN */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_OUTPUT_PULLUP, MUX_MODE7)      /* gpmc_ad12.gpio1_28 BT_EN */
                >;
        };
 
        mmc3_pins: pinmux_mmc3_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x830, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_ad12.mmc2_dat0 */
-                       AM33XX_IOPAD(0x834, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_ad13.mmc2_dat1 */
-                       AM33XX_IOPAD(0x838, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_ad14.mmc2_dat2 */
-                       AM33XX_IOPAD(0x83c, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_ad15.mmc2_dat3 */
-                       AM33XX_IOPAD(0x888, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_csn3.mmc2_cmd */
-                       AM33XX_IOPAD(0x88c, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_clk.mmc2_clk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_ad12.mmc2_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_ad13.mmc2_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_ad14.mmc2_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_ad15.mmc2_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN3, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_csn3.mmc2_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CLK, PIN_INPUT_PULLUP, MUX_MODE3)        /* gpmc_clk.mmc2_clk */
                >;
        };
 
        uart3_pins: pinmux_uart3_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLUP | MUX_MODE1)       /* gmii1_rxd3.uart3_rxd */
-                       AM33XX_IOPAD(0x938, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* gmii1_rxd2.uart3_txd */
-                       AM33XX_IOPAD(0x948, PIN_INPUT | MUX_MODE3)              /* mdio_data.uart3_ctsn */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* mdio_clk.uart3_rtsn */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLUP, MUX_MODE1)       /* gmii1_rxd3.uart3_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE1)    /* gmii1_rxd2.uart3_txd */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT, MUX_MODE3)           /* mdio_data.uart3_ctsn */
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLDOWN, MUX_MODE3)  /* mdio_clk.uart3_rtsn */
                >;
        };
 
        wl18xx_pins: pinmux_wl18xx_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x828, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_ad10.gpio0_26 WL_EN */
-                       AM33XX_IOPAD(0x82C, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_ad11.gpio0_27 WL_IRQ */
-                       AM33XX_IOPAD(0x87C, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* gpmc_csn0.gpio1_29 LS_BUF_EN */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_OUTPUT_PULLDOWN, MUX_MODE7)    /* gpmc_ad10.gpio0_26 WL_EN */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* gpmc_ad11.gpio0_27 WL_IRQ */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN0, PIN_OUTPUT_PULLUP, MUX_MODE7)      /* gpmc_csn0.gpio1_29 LS_BUF_EN */
                >;
        };
 };
index bffa5dce54ec9f1ff15f9848be30f1e98054368d..31da68355e57d44133c705ac90f3740f7296669c 100644 (file)
 &am33xx_pinmux {
        uart0_pins: pinmux_uart0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        cpsw_default: cpsw_default {
                pinctrl-single,pins = <
                        /* Slave 1 */
-                       AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE1)  /* mii1_crs.rmii1_crs */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLUP | MUX_MODE1)       /* mii1_rxerr.rmii1_rxerr */
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* mii1_txen.rmii1_txen */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* mii1_txd1.rmii1_txd1 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* mii1_txd0.rmii1_txd0 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLUP | MUX_MODE1)       /* mii1_rxd1.rmii1_rxd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLUP | MUX_MODE1)       /* mii1_rxd0.rmii1_rxd0 */
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* rmii1_ref_clk.rmii_ref_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLDOWN, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        cpsw_sleep: cpsw_sleep {
                pinctrl-single,pins = <
                        /* Slave 1 reset value */
-                       AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        davinci_mdio_default: davinci_mdio_default {
                pinctrl-single,pins = <
                        /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
                        /* mdio_clk.mdio_clk */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        davinci_mdio_sleep: davinci_mdio_sleep {
                pinctrl-single,pins = <
                        /* MDIO reset value */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        usb1_drvvbus: usb1_drvvbus {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0xa34, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* usb1_drvvbus.usb1_drvvbus */
+                       AM33XX_PADCONF(AM335X_PIN_USB1_DRVVBUS, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        sd_pins: pinmux_sd_card {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
-                       AM33XX_IOPAD(0x900, PIN_INPUT | MUX_MODE0) /* mmc0_clk.mmc0_clk */
-                       AM33XX_IOPAD(0x904, PIN_INPUT | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
-                       AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT, MUX_MODE7) /* spi0_cs1.gpio0_6 */
                >;
        };
 
        led_gpio_pins: led_gpio_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9e4, PIN_OUTPUT | MUX_MODE7) /* emu0.gpio3_7 */
-                       AM33XX_IOPAD(0x9e8, PIN_OUTPUT | MUX_MODE7) /* emu1.gpio3_8 */
+                       AM33XX_PADCONF(AM335X_PIN_EMU0, PIN_OUTPUT, MUX_MODE7) /* emu0.gpio3_7 */
+                       AM33XX_PADCONF(AM335X_PIN_EMU1, PIN_OUTPUT, MUX_MODE7) /* emu1.gpio3_8 */
                >;
        };
 };
index 1b43ebd08b38106a92ccc088998ef9f3cf51bab7..8b88bf6dafc45057afd38d7b79f19b41d27b59ad 100644 (file)
 
        i2c0_pins: pinmux_i2c0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_sda.i2c0_sda */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_scl.i2c0_scl */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        nandflash_pins: nandflash_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* gpmc_ad0.gpmc_ad0 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* gpmc_ad1.gpmc_ad1 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* gpmc_ad2.gpmc_ad2 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* gpmc_ad3.gpmc_ad3 */
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* gpmc_ad4.gpmc_ad4 */
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* gpmc_ad5.gpmc_ad5 */
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* gpmc_ad6.gpmc_ad6 */
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* gpmc_ad7.gpmc_ad7 */
-
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_wait0.gpmc_wait0 */
-                       AM33XX_IOPAD(0x87c, PIN_OUTPUT_PULLUP | MUX_MODE0)      /* gpmc_csn0.gpmc_csn0 */
-                       AM33XX_IOPAD(0x890, PIN_OUTPUT_PULLUP | MUX_MODE0)      /* gpmc_advn_ale.gpmc_advn_ale */
-                       AM33XX_IOPAD(0x894, PIN_OUTPUT_PULLUP | MUX_MODE0)      /* gpmc_oen_ren.gpmc_oen_ren */
-                       AM33XX_IOPAD(0x898, PIN_OUTPUT_PULLUP | MUX_MODE0)      /* gpmc_wen.gpmc_wen */
-                       AM33XX_IOPAD(0x89c, PIN_OUTPUT_PULLUP | MUX_MODE0)      /* gpmc_be0n_cle.gpmc_be0n_cle */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLDOWN, MUX_MODE0)
+
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN0, PIN_OUTPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_ADVN_ALE, PIN_OUTPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_OEN_REN, PIN_OUTPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WEN, PIN_OUTPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN0_CLE, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 };
index 2c724bb60417b9b67770a6d23d4b5d8d487a2332..3b0bb88dfc12cb016092ac3e9ec06b182d149022 100644 (file)
 
        i2c0_pins: pinmux_i2c0_pins {
                pinctrl-single,pins = <
-                       /* i2c0_sda.i2c0_sda */
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* i2c0_scl.i2c0_scl */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        i2c1_pins: pinmux_i2c1_pins {
                pinctrl-single,pins = <
                        /* uart0_ctsn.i2c1_sda */
-                       AM33XX_IOPAD(0x968, PIN_INPUT_PULLUP | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_CTSN, PIN_INPUT_PULLUP, MUX_MODE2)
                        /* uart0_rtsn.i2c1_scl */
-                       AM33XX_IOPAD(0x96c, PIN_INPUT_PULLUP | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_INPUT_PULLUP, MUX_MODE2)
                >;
        };
 
        gpio_led_pins: pinmux_gpio_led_pins {
                pinctrl-single,pins = <
                        /* gpmc_csn3.gpio2_0 */
-                       AM33XX_IOPAD(0x888, PIN_OUTPUT | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN3, PIN_OUTPUT, MUX_MODE7)
                >;
        };
 
        nandflash_pins: pinmux_nandflash_pins {
                pinctrl-single,pins = <
-                       /* gpmc_ad0.gpmc_ad0 */
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* gpmc_ad1.gpmc_ad1 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* gpmc_ad2.gpmc_ad2 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* gpmc_ad3.gpmc_ad3 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* gpmc_ad4.gpmc_ad4 */
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* gpmc_ad5.gpmc_ad5 */
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* gpmc_ad6.gpmc_ad6 */
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* gpmc_ad7.gpmc_ad7 */
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* gpmc_wait0.gpmc_wait0 */
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLUP, MUX_MODE0)
                        /* gpmc_wpn.gpio0_30 */
-                       AM33XX_IOPAD(0x874, PIN_INPUT_PULLUP | MUX_MODE7)
-                       /* gpmc_csn0.gpmc_csn0  */
-                       AM33XX_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE0)
-                       /* gpmc_advn_ale.gpmc_advn_ale */
-                       AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE0)
-                       /* gpmc_oen_ren.gpmc_oen_ren */
-                       AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE0)
-                       /* gpmc_wen.gpmc_wen */
-                       AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE0)
-                       /* gpmc_ben0_cle.gpmc_ben0_cle */
-                       AM33XX_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_INPUT_PULLUP, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_ADVN_ALE, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_OEN_REN, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WEN, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN0_CLE, PIN_OUTPUT, MUX_MODE0)
                >;
        };
 
        uart0_pins: pinmux_uart0_pins {
                pinctrl-single,pins = <
-                       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* uart0_txd.uart0_txd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        uart1_pins: pinmux_uart1_pins {
                pinctrl-single,pins = <
-                       /* uart1_ctsn.uart1_ctsn */
-                       AM33XX_IOPAD(0x978, PIN_INPUT | MUX_MODE0)
-                       /* uart1_rtsn.uart1_rtsn */
-                       AM33XX_IOPAD(0x97C, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
-                       /* uart1_rxd.uart1_rxd */
-                       AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* uart1_txd.uart1_txd */
-                       AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        dcan0_pins: pinmux_dcan0_pins {
                pinctrl-single,pins = <
                        /* uart1_ctsn.dcan0_tx */
-                       AM33XX_IOPAD(0x978, PIN_OUTPUT | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_OUTPUT, MUX_MODE2)
                        /* uart1_rtsn.dcan0_rx */
-                       AM33XX_IOPAD(0x97C, PIN_INPUT | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_INPUT, MUX_MODE2)
                >;
        };
 
        dcan1_pins: pinmux_dcan1_pins {
                pinctrl-single,pins = <
                        /* uart1_rxd.dcan1_tx */
-                       AM33XX_IOPAD(0x980, PIN_OUTPUT | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_OUTPUT, MUX_MODE2)
                        /* uart1_txd.dcan1_rx */
-                       AM33XX_IOPAD(0x984, PIN_INPUT | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_INPUT, MUX_MODE2)
                >;
        };
 
        ecap0_pins: pinmux_ecap0_pins {
                pinctrl-single,pins = <
-                       /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out MODE0 */
-                       AM33XX_IOPAD(0x964, 0x0)
+                       AM33XX_PADCONF(AM335X_PIN_ECAP0_IN_PWM0_OUT, 0x0, MUX_MODE0)
                >;
        };
 
                pinctrl-single,pins = <
                        /* Slave 1 */
                        /* mii1_tx_en.rgmii1_tctl */
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE2)
                        /* mii1_rxdv.rgmii1_rctl */
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE2)
                        /* mii1_txd3.rgmii1_td3 */
-                       AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_OUTPUT_PULLDOWN, MUX_MODE2)
                        /* mii1_txd2.rgmii1_td2 */
-                       AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE2)
                        /* mii1_txd1.rgmii1_td1 */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLDOWN, MUX_MODE2)
                        /* mii1_txd0.rgmii1_td0 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE2)
                        /* mii1_txclk.rgmii1_tclk */
-                       AM33XX_IOPAD(0x92c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE2)
                        /* mii1_rxclk.rgmii1_rclk */
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE2)
                        /* mii1_rxd3.rgmii1_rd3 */
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLDOWN, MUX_MODE2)
                        /* mii1_rxd2.rgmii1_rd2 */
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLDOWN, MUX_MODE2)
                        /* mii1_rxd1.rgmii1_rd1 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE2)
                        /* mii1_rxd0.rgmii1_rd0 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE2)
                >;
        };
 
        cpsw_sleep: cpsw_sleep {
                pinctrl-single,pins = <
                        /* Slave 1 reset value */
-                       AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        davinci_mdio_default: davinci_mdio_default {
                pinctrl-single,pins = <
-                       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)
-                       /* mdio_clk.mdio_clk */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        davinci_mdio_sleep: davinci_mdio_sleep {
                pinctrl-single,pins = <
                        /* MDIO reset value */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        mmc1_pins: pinmux_mmc1_pins {
                pinctrl-single,pins = <
-                       /* mmc0_dat3.mmc0_dat3 */
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* mmc0_dat2.mmc0_dat2 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* mmc0_dat1.mmc0_dat1 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* mmc0_dat0.mmc0_dat0 */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* mmc0_clk.mmc0_clk */
-                       AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)
-                       /* mmc0_cmd.mmc0_cmd */
-                       AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        spi0_pins: pinmux_spi0_pins {
                pinctrl-single,pins = <
-                       /* spi0_sclk.spi0_sclk */
-                       AM33XX_IOPAD(0x950, PIN_INPUT | MUX_MODE0)
-                       /* spi0_d0.spi0_d0 */
-                       AM33XX_IOPAD(0x954, PIN_OUTPUT_PULLUP | MUX_MODE0)
-                       /* spi0_d1.spi0_d1 */
-                       AM33XX_IOPAD(0x958, PIN_INPUT | MUX_MODE0)
-                       /* spi0_cs0.spi0_cs0 */
-                       AM33XX_IOPAD(0x95C, PIN_OUTPUT | MUX_MODE0)
-                       /* spi0_cs1.spi0_cs1 */
-                       AM33XX_IOPAD(0x960, PIN_OUTPUT | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_OUTPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D1, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_OUTPUT, MUX_MODE0)
                >;
        };
 
        bluetooth_pins: pinmux_bluetooth_pins {
                pinctrl-single,pins = <
                        /* XDMA_EVENT_INTR0.gpio0_19 - bluetooth enable */
-                       AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLUP | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLUP, MUX_MODE7)
                >;
        };
 
        mcasp1_pins: pinmux_mcasp1_pins {
                pinctrl-single,pins = <
                        /* MII1_CRS.mcasp1_aclkx */
-                       AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE4)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE4)
                        /* MII1_RX_ER.mcasp1_fsx */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE4)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE4)
                        /* MII1_COL.mcasp1_axr2 */
-                       AM33XX_IOPAD(0x908, PIN_INPUT_PULLDOWN | MUX_MODE4)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLDOWN, MUX_MODE4)
                        /* RMII1_REF_CLK.mcasp1_axr3 */
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE4)
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE4)
                >;
        };
 
        wifi_pins: pinmux_wifi_pins {
                pinctrl-single,pins = <
                        /* EMU1.gpio3_8 - WiFi IRQ */
-                       AM33XX_IOPAD(0x9e8, PIN_INPUT_PULLUP | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_EMU1, PIN_INPUT_PULLUP, MUX_MODE7)
                        /* XDMA_EVENT_INTR1.gpio0_20 - WiFi enable */
-                       AM33XX_IOPAD(0x9b4, PIN_OUTPUT | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_OUTPUT, MUX_MODE7)
                >;
        };
 };
index edcff79879e780e5aa307dfc0d18f393663a7f78..55d4392bb7a13ef714d2ee9dd5de5634e2773e41 100644 (file)
 
        matrix_keypad_s0: matrix_keypad_s0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_a5.gpio1_21 */
-                       AM33XX_IOPAD(0x858, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_a6.gpio1_22 */
-                       AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_a9.gpio1_25 */
-                       AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_a10.gpio1_26 */
-                       AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_a11.gpio1_27 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE7)      /* gpmc_a5.gpio1_21 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_OUTPUT_PULLDOWN, MUX_MODE7)      /* gpmc_a6.gpio1_22 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A9, PIN_INPUT_PULLDOWN, MUX_MODE7)       /* gpmc_a9.gpio1_25 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* gpmc_a10.gpio1_26 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* gpmc_a11.gpio1_27 */
                >;
        };
 
        volume_keys_s0: volume_keys_s0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x950, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* spi0_sclk.gpio0_2 */
-                       AM33XX_IOPAD(0x954, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* spi0_d0.gpio0_3 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* spi0_sclk.gpio0_2 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_INPUT_PULLDOWN, MUX_MODE7)       /* spi0_d0.gpio0_3 */
                >;
        };
 
        i2c0_pins: pinmux_i2c0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_sda.i2c0_sda */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_scl.i2c0_scl */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLUP, MUX_MODE0)        /* i2c0_sda.i2c0_sda */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLUP, MUX_MODE0)        /* i2c0_scl.i2c0_scl */
                >;
        };
 
        i2c1_pins: pinmux_i2c1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE2)       /* spi0_d1.i2c1_sda */
-                       AM33XX_IOPAD(0x95c, PIN_INPUT_PULLUP | MUX_MODE2)       /* spi0_cs0.i2c1_scl */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D1, PIN_INPUT_PULLUP, MUX_MODE2) /* spi0_d1.i2c1_sda */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_INPUT_PULLUP, MUX_MODE2)        /* spi0_cs0.i2c1_scl */
                >;
        };
 
        uart0_pins: pinmux_uart0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        uart1_pins: pinmux_uart1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x978, PIN_INPUT | MUX_MODE0)              /* uart1_ctsn.uart1_ctsn */
-                       AM33XX_IOPAD(0x97C, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart1_rtsn.uart1_rtsn */
-                       AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart1_rxd.uart1_rxd */
-                       AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart1_txd.uart1_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        clkout2_pin: pinmux_clkout2_pin {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9b4, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* xdma_event_intr1.clkout2 */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_OUTPUT_PULLDOWN, MUX_MODE3)     /* xdma_event_intr1.clkout2 */
                >;
        };
 
        nandflash_pins_s0: nandflash_pins_s0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad0.gpmc_ad0 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad1.gpmc_ad1 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad2.gpmc_ad2 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad3.gpmc_ad3 */
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad4.gpmc_ad4 */
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad5.gpmc_ad5 */
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad6.gpmc_ad6 */
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad7.gpmc_ad7 */
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_wait0.gpmc_wait0 */
-                       AM33XX_IOPAD(0x874, PIN_INPUT_PULLUP | MUX_MODE7)       /* gpmc_wpn.gpio0_30 */
-                       AM33XX_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE0)             /* gpmc_csn0.gpmc_csn0  */
-                       AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE0)             /* gpmc_advn_ale.gpmc_advn_ale */
-                       AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE0)             /* gpmc_oen_ren.gpmc_oen_ren */
-                       AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE0)             /* gpmc_wen.gpmc_wen */
-                       AM33XX_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE0)             /* gpmc_be0n_cle.gpmc_be0n_cle */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_INPUT_PULLUP, MUX_MODE7)        /* gpmc_wpn.gpio0_30 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_ADVN_ALE, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_OEN_REN, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WEN, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN0_CLE, PIN_OUTPUT, MUX_MODE0)
                >;
        };
 
        ecap0_pins: backlight_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x964, MUX_MODE0)  /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out */
+                       AM33XX_PADCONF(AM335X_PIN_ECAP0_IN_PWM0_OUT, 0x0, MUX_MODE0)
                >;
        };
 
        cpsw_default: cpsw_default {
                pinctrl-single,pins = <
                        /* Slave 1 */
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txen.rgmii1_tctl */
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxdv.rgmii1_rctl */
-                       AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd3.rgmii1_td3 */
-                       AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd2.rgmii1_td2 */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd1.rgmii1_td1 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd0.rgmii1_td0 */
-                       AM33XX_IOPAD(0x92c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txclk.rgmii1_tclk */
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxclk.rgmii1_rclk */
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxd3.rgmii1_rd3 */
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxd2.rgmii1_rd2 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxd1.rgmii1_rd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxd0.rgmii1_rd0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE2)   /* mii1_txen.rgmii1_tctl */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE2)    /* mii1_rxdv.rgmii1_rctl */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd3.rgmii1_td3 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd2.rgmii1_td2 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd1.rgmii1_td1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd0.rgmii1_td0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE2)  /* mii1_txclk.rgmii1_tclk */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE2)   /* mii1_rxclk.rgmii1_rclk */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLDOWN, MUX_MODE2)     /* mii1_rxd3.rgmii1_rd3 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLDOWN, MUX_MODE2)     /* mii1_rxd2.rgmii1_rd2 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE2)     /* mii1_rxd1.rgmii1_rd1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE2)     /* mii1_rxd0.rgmii1_rd0 */
                >;
        };
 
        cpsw_sleep: cpsw_sleep {
                pinctrl-single,pins = <
                        /* Slave 1 reset value */
-                       AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        davinci_mdio_default: davinci_mdio_default {
                pinctrl-single,pins = <
                        /* MDIO */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)                      /* mdio_clk.mdio_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        davinci_mdio_sleep: davinci_mdio_sleep {
                pinctrl-single,pins = <
                        /* MDIO reset value */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        mmc1_pins: pinmux_mmc1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7)              /* spi0_cs1.gpio0_6 */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat0.mmc0_dat0 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat1.mmc0_dat1 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat2.mmc0_dat2 */
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat3.mmc0_dat3 */
-                       AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_cmd.mmc0_cmd */
-                       AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_clk.mmc0_clk */
-                       AM33XX_IOPAD(0x9a0, PIN_INPUT | MUX_MODE4)              /* mcasp0_aclkr.mmc0_sdwp */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT, MUX_MODE7)               /* spi0_cs1.gpio0_6 */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKR, PIN_INPUT, MUX_MODE4)           /* mcasp0_aclkr.mmc0_sdwp */
                >;
        };
 
        mmc3_pins: pinmux_mmc3_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x844, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_a1.mmc2_dat0, INPUT_PULLUP | MODE3 */
-                       AM33XX_IOPAD(0x848, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_a2.mmc2_dat1, INPUT_PULLUP | MODE3 */
-                       AM33XX_IOPAD(0x84c, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_a3.mmc2_dat2, INPUT_PULLUP | MODE3 */
-                       AM33XX_IOPAD(0x878, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_ben1.mmc2_dat3, INPUT_PULLUP | MODE3 */
-                       AM33XX_IOPAD(0x888, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_csn3.mmc2_cmd, INPUT_PULLUP | MODE3 */
-                       AM33XX_IOPAD(0x88c, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_clk.mmc2_clk, INPUT_PULLUP | MODE3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A1, PIN_INPUT_PULLUP, MUX_MODE3) /* gpmc_a1.mmc2_dat0, INPUT_PULLUP | MODE3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_INPUT_PULLUP, MUX_MODE3) /* gpmc_a2.mmc2_dat1, INPUT_PULLUP | MODE3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A3, PIN_INPUT_PULLUP, MUX_MODE3) /* gpmc_a3.mmc2_dat2, INPUT_PULLUP | MODE3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_ben1.mmc2_dat3, INPUT_PULLUP | MODE3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN3, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_csn3.mmc2_cmd, INPUT_PULLUP | MODE3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CLK, PIN_INPUT_PULLUP, MUX_MODE3)        /* gpmc_clk.mmc2_clk, INPUT_PULLUP | MODE3 */
                >;
        };
 
        wlan_pins: pinmux_wlan_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_a0.gpio1_16 */
-                       AM33XX_IOPAD(0x99c, PIN_INPUT | MUX_MODE7)              /* mcasp0_ahclkr.gpio3_17 */
-                       AM33XX_IOPAD(0x9ac, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* mcasp0_ahclkx.gpio3_21 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_OUTPUT_PULLDOWN, MUX_MODE7)      /* gpmc_a0.gpio1_16 */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKR, PIN_INPUT, MUX_MODE7)          /* mcasp0_ahclkr.gpio3_17 */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKX, PIN_OUTPUT_PULLDOWN, MUX_MODE7)        /* mcasp0_ahclkx.gpio3_21 */
                >;
        };
 
        lcd_pins_s0: lcd_pins_s0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x820, PIN_OUTPUT | MUX_MODE1)             /* gpmc_ad8.lcd_data23 */
-                       AM33XX_IOPAD(0x824, PIN_OUTPUT | MUX_MODE1)             /* gpmc_ad9.lcd_data22 */
-                       AM33XX_IOPAD(0x828, PIN_OUTPUT | MUX_MODE1)             /* gpmc_ad10.lcd_data21 */
-                       AM33XX_IOPAD(0x82c, PIN_OUTPUT | MUX_MODE1)             /* gpmc_ad11.lcd_data20 */
-                       AM33XX_IOPAD(0x830, PIN_OUTPUT | MUX_MODE1)             /* gpmc_ad12.lcd_data19 */
-                       AM33XX_IOPAD(0x834, PIN_OUTPUT | MUX_MODE1)             /* gpmc_ad13.lcd_data18 */
-                       AM33XX_IOPAD(0x838, PIN_OUTPUT | MUX_MODE1)             /* gpmc_ad14.lcd_data17 */
-                       AM33XX_IOPAD(0x83c, PIN_OUTPUT | MUX_MODE1)             /* gpmc_ad15.lcd_data16 */
-                       AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data0.lcd_data0 */
-                       AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data1.lcd_data1 */
-                       AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data2.lcd_data2 */
-                       AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)             /* lcd_data3.lcd_data3 */
-                       AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data4.lcd_data4 */
-                       AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data5.lcd_data5 */
-                       AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data6.lcd_data6 */
-                       AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)             /* lcd_data7.lcd_data7 */
-                       AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data8.lcd_data8 */
-                       AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data9.lcd_data9 */
-                       AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data10.lcd_data10 */
-                       AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)             /* lcd_data11.lcd_data11 */
-                       AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data12.lcd_data12 */
-                       AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data13.lcd_data13 */
-                       AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data14.lcd_data14 */
-                       AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)             /* lcd_data15.lcd_data15 */
-                       AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE0)             /* lcd_vsync.lcd_vsync */
-                       AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE0)             /* lcd_hsync.lcd_hsync */
-                       AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE0)             /* lcd_pclk.lcd_pclk */
-                       AM33XX_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE0)             /* lcd_ac_bias_en.lcd_ac_bias_en */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD8, PIN_OUTPUT, MUX_MODE1)              /* gpmc_ad8.lcd_data23 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD9, PIN_OUTPUT, MUX_MODE1)              /* gpmc_ad9.lcd_data22 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_OUTPUT, MUX_MODE1)             /* gpmc_ad10.lcd_data21 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_OUTPUT, MUX_MODE1)             /* gpmc_ad11.lcd_data20 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_OUTPUT, MUX_MODE1)             /* gpmc_ad12.lcd_data19 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_OUTPUT, MUX_MODE1)             /* gpmc_ad13.lcd_data18 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_OUTPUT, MUX_MODE1)             /* gpmc_ad14.lcd_data17 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_OUTPUT, MUX_MODE1)             /* gpmc_ad15.lcd_data16 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT, MUX_MODE0)
                >;
        };
 
        mcasp1_pins: mcasp1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_rxerr.mcasp1_fsx */
-                       AM33XX_IOPAD(0x908, PIN_OUTPUT_PULLDOWN | MUX_MODE4) /* mii1_col.mcasp1_axr2 */
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE4) /* rmii1_ref_clk.mcasp1_axr3 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE4) /* mii1_rxerr.mcasp1_fsx */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_OUTPUT_PULLDOWN, MUX_MODE4) /* mii1_col.mcasp1_axr2 */
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE4) /* rmii1_ref_clk.mcasp1_axr3 */
                >;
        };
 
        mcasp1_pins_sleep: mcasp1_pins_sleep {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x908, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        dcan1_pins_default: dcan1_pins_default {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x968, PIN_OUTPUT | MUX_MODE2) /* uart0_ctsn.d_can1_tx */
-                       AM33XX_IOPAD(0x96c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* uart0_rtsn.d_can1_rx */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_CTSN, PIN_OUTPUT, MUX_MODE2) /* uart0_ctsn.d_can1_tx */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_INPUT_PULLDOWN, MUX_MODE2) /* uart0_rtsn.d_can1_rx */
                >;
        };
 };
index 2c2d8b5b8cf52bf55b28b20a47488363c895681c..8fc8056db94fcd0041d44bda415a7bed84007faa 100644 (file)
 
        lcd_pins_default: lcd_pins_default {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x820, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad8.lcd_data23 */
-                       AM33XX_IOPAD(0x824, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad9.lcd_data22 */
-                       AM33XX_IOPAD(0x828, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad10.lcd_data21 */
-                       AM33XX_IOPAD(0x82c, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad11.lcd_data20 */
-                       AM33XX_IOPAD(0x830, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad12.lcd_data19 */
-                       AM33XX_IOPAD(0x834, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad13.lcd_data18 */
-                       AM33XX_IOPAD(0x838, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad14.lcd_data17 */
-                       AM33XX_IOPAD(0x83c, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad15.lcd_data16 */
-                       AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data0.lcd_data0 */
-                       AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data1.lcd_data1 */
-                       AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data2.lcd_data2 */
-                       AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)     /* lcd_data3.lcd_data3 */
-                       AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data4.lcd_data4 */
-                       AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data5.lcd_data5 */
-                       AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data6.lcd_data6 */
-                       AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)     /* lcd_data7.lcd_data7 */
-                       AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data8.lcd_data8 */
-                       AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data9.lcd_data9 */
-                       AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data10.lcd_data10 */
-                       AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)     /* lcd_data11.lcd_data11 */
-                       AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data12.lcd_data12 */
-                       AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data13.lcd_data13 */
-                       AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data14.lcd_data14 */
-                       AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)     /* lcd_data15.lcd_data15 */
-                       AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE0)     /* lcd_vsync.lcd_vsync */
-                       AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE0)     /* lcd_hsync.lcd_hsync */
-                       AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE0)     /* lcd_pclk.lcd_pclk */
-                       AM33XX_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE0)     /* lcd_ac_bias_en.lcd_ac_bias_en */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD8, PIN_OUTPUT, MUX_MODE1)      /* gpmc_ad8.lcd_data23 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD9, PIN_OUTPUT, MUX_MODE1)      /* gpmc_ad9.lcd_data22 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_OUTPUT, MUX_MODE1)     /* gpmc_ad10.lcd_data21 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_OUTPUT, MUX_MODE1)     /* gpmc_ad11.lcd_data20 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_OUTPUT, MUX_MODE1)     /* gpmc_ad12.lcd_data19 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_OUTPUT, MUX_MODE1)     /* gpmc_ad13.lcd_data18 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_OUTPUT, MUX_MODE1)     /* gpmc_ad14.lcd_data17 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_OUTPUT, MUX_MODE1)     /* gpmc_ad15.lcd_data16 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT, MUX_MODE0)
                >;
        };
 
        lcd_pins_sleep: lcd_pins_sleep {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x820, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_ad8.lcd_data23 */
-                       AM33XX_IOPAD(0x824, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_ad9.lcd_data22 */
-                       AM33XX_IOPAD(0x828, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_ad10.lcd_data21 */
-                       AM33XX_IOPAD(0x82c, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_ad11.lcd_data20 */
-                       AM33XX_IOPAD(0x830, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_ad12.lcd_data19 */
-                       AM33XX_IOPAD(0x834, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_ad13.lcd_data18 */
-                       AM33XX_IOPAD(0x838, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_ad14.lcd_data17 */
-                       AM33XX_IOPAD(0x83c, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_ad15.lcd_data16 */
-                       AM33XX_IOPAD(0x8a0, PULL_DISABLE | MUX_MODE7)   /* lcd_data0.lcd_data0 */
-                       AM33XX_IOPAD(0x8a4, PULL_DISABLE | MUX_MODE7)   /* lcd_data1.lcd_data1 */
-                       AM33XX_IOPAD(0x8a8, PULL_DISABLE | MUX_MODE7)   /* lcd_data2.lcd_data2 */
-                       AM33XX_IOPAD(0x8ac, PULL_DISABLE | MUX_MODE7)   /* lcd_data3.lcd_data3 */
-                       AM33XX_IOPAD(0x8b0, PULL_DISABLE | MUX_MODE7)   /* lcd_data4.lcd_data4 */
-                       AM33XX_IOPAD(0x8b4, PULL_DISABLE | MUX_MODE7)   /* lcd_data5.lcd_data5 */
-                       AM33XX_IOPAD(0x8b8, PULL_DISABLE | MUX_MODE7)   /* lcd_data6.lcd_data6 */
-                       AM33XX_IOPAD(0x8bc, PULL_DISABLE | MUX_MODE7)   /* lcd_data7.lcd_data7 */
-                       AM33XX_IOPAD(0x8c0, PULL_DISABLE | MUX_MODE7)   /* lcd_data8.lcd_data8 */
-                       AM33XX_IOPAD(0x8c4, PULL_DISABLE | MUX_MODE7)   /* lcd_data9.lcd_data9 */
-                       AM33XX_IOPAD(0x8c8, PULL_DISABLE | MUX_MODE7)   /* lcd_data10.lcd_data10 */
-                       AM33XX_IOPAD(0x8cc, PULL_DISABLE | MUX_MODE7)   /* lcd_data11.lcd_data11 */
-                       AM33XX_IOPAD(0x8d0, PULL_DISABLE | MUX_MODE7)   /* lcd_data12.lcd_data12 */
-                       AM33XX_IOPAD(0x8d4, PULL_DISABLE | MUX_MODE7)   /* lcd_data13.lcd_data13 */
-                       AM33XX_IOPAD(0x8d8, PULL_DISABLE | MUX_MODE7)   /* lcd_data14.lcd_data14 */
-                       AM33XX_IOPAD(0x8dc, PULL_DISABLE | MUX_MODE7)   /* lcd_data15.lcd_data15 */
-                       AM33XX_IOPAD(0x8e0, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* lcd_vsync.lcd_vsync */
-                       AM33XX_IOPAD(0x8e4, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* lcd_hsync.lcd_hsync */
-                       AM33XX_IOPAD(0x8e8, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* lcd_pclk.lcd_pclk */
-                       AM33XX_IOPAD(0x8ec, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* lcd_ac_bias_en.lcd_ac_bias_en */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD8, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* gpmc_ad8.lcd_data23 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD9, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* gpmc_ad9.lcd_data22 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* gpmc_ad10.lcd_data21 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* gpmc_ad11.lcd_data20 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* gpmc_ad12.lcd_data19 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* gpmc_ad13.lcd_data18 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* gpmc_ad14.lcd_data17 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* gpmc_ad15.lcd_data16 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
 
        user_leds_s0: user_leds_s0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x810, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_ad4.gpio1_4 */
-                       AM33XX_IOPAD(0x814, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_ad5.gpio1_5 */
-                       AM33XX_IOPAD(0x818, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_ad6.gpio1_6 */
-                       AM33XX_IOPAD(0x81c, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_ad7.gpio1_7 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_OUTPUT_PULLDOWN, MUX_MODE7)     /* gpmc_ad4.gpio1_4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_OUTPUT_PULLDOWN, MUX_MODE7)     /* gpmc_ad5.gpio1_5 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_OUTPUT_PULLDOWN, MUX_MODE7)     /* gpmc_ad6.gpio1_6 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_OUTPUT_PULLDOWN, MUX_MODE7)     /* gpmc_ad7.gpio1_7 */
                >;
        };
 
        gpio_keys_s0: gpio_keys_s0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x894, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_oen_ren.gpio2_3 */
-                       AM33XX_IOPAD(0x890, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_advn_ale.gpio2_2 */
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_wait0.gpio0_30 */
-                       AM33XX_IOPAD(0x89c, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_ben0_cle.gpio2_5 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_OEN_REN, PIN_INPUT_PULLDOWN, MUX_MODE7)  /* gpmc_oen_ren.gpio2_3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_ADVN_ALE, PIN_INPUT_PULLDOWN, MUX_MODE7) /* gpmc_advn_ale.gpio2_2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLDOWN, MUX_MODE7)    /* gpmc_wait0.gpio0_30 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN0_CLE, PIN_INPUT_PULLDOWN, MUX_MODE7) /* gpmc_ben0_cle.gpio2_5 */
                >;
        };
 
        i2c0_pins: pinmux_i2c0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_sda.i2c0_sda */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_scl.i2c0_scl */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        uart0_pins: pinmux_uart0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        clkout2_pin: pinmux_clkout2_pin {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9b4, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* xdma_event_intr1.clkout2 */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_OUTPUT_PULLDOWN, MUX_MODE3)     /* xdma_event_intr1.clkout2 */
                >;
        };
 
        ecap2_pins: backlight_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x99c, MUX_MODE4)  /* mcasp0_ahclkr.ecap2_in_pwm2_out */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKR, 0x0, MUX_MODE4)        /* mcasp0_ahclkr.ecap2_in_pwm2_out */
                >;
        };
 
        cpsw_default: cpsw_default {
                pinctrl-single,pins = <
                        /* Slave 1 */
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txen.rgmii1_tctl */
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxdv.rgmii1_rctl */
-                       AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd3.rgmii1_td3 */
-                       AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd2.rgmii1_td2 */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd1.rgmii1_td1 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd0.rgmii1_td0 */
-                       AM33XX_IOPAD(0x92c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txclk.rgmii1_tclk */
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxclk.rgmii1_rclk */
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxd3.rgmii1_rd3 */
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxd2.rgmii1_rd2 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxd1.rgmii1_rd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxd0.rgmii1_rd0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE2)   /* mii1_txen.rgmii1_tctl */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE2)    /* mii1_rxdv.rgmii1_rctl */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd3.rgmii1_td3 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd2.rgmii1_td2 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd1.rgmii1_td1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd0.rgmii1_td0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE2)  /* mii1_txclk.rgmii1_tclk */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE2)   /* mii1_rxclk.rgmii1_rclk */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLDOWN, MUX_MODE2)     /* mii1_rxd3.rgmii1_rd3 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLDOWN, MUX_MODE2)     /* mii1_rxd2.rgmii1_rd2 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE2)     /* mii1_rxd1.rgmii1_rd1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE2)     /* mii1_rxd0.rgmii1_rd0 */
 
                        /* Slave 2 */
-                       AM33XX_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a0.rgmii2_tctl */
-                       AM33XX_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a1.rgmii2_rctl */
-                       AM33XX_IOPAD(0x848, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a2.rgmii2_td3 */
-                       AM33XX_IOPAD(0x84c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a3.rgmii2_td2 */
-                       AM33XX_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a4.rgmii2_td1 */
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a5.rgmii2_td0 */
-                       AM33XX_IOPAD(0x858, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a6.rgmii2_tclk */
-                       AM33XX_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a7.rgmii2_rclk */
-                       AM33XX_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a8.rgmii2_rd3 */
-                       AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a9.rgmii2_rd2 */
-                       AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a10.rgmii2_rd1 */
-                       AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a11.rgmii2_rd0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a0.rgmii2_tctl */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A1, PIN_INPUT_PULLDOWN, MUX_MODE2)       /* gpmc_a1.rgmii2_rctl */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a2.rgmii2_td3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A3, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a3.rgmii2_td2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a4.rgmii2_td1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a5.rgmii2_td0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a6.rgmii2_tclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_INPUT_PULLDOWN, MUX_MODE2)       /* gpmc_a7.rgmii2_rclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_INPUT_PULLDOWN, MUX_MODE2)       /* gpmc_a8.rgmii2_rd3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A9, PIN_INPUT_PULLDOWN, MUX_MODE2)       /* gpmc_a9.rgmii2_rd2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a10.rgmii2_rd1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a11.rgmii2_rd0 */
                >;
        };
 
        cpsw_sleep: cpsw_sleep {
                pinctrl-single,pins = <
                        /* Slave 1 reset value */
-                       AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
 
                        /* Slave 2 reset value*/
-                       AM33XX_IOPAD(0x840, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x848, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x84c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x850, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x854, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x858, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A9, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        davinci_mdio_default: davinci_mdio_default {
                pinctrl-single,pins = <
                        /* MDIO */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)                      /* mdio_clk.mdio_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        davinci_mdio_sleep: davinci_mdio_sleep {
                pinctrl-single,pins = <
                        /* MDIO reset value */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        mmc1_pins: pinmux_mmc1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7)              /* spi0_cs1.gpio0_6 */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat0.mmc0_dat0 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat1.mmc0_dat1 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat2.mmc0_dat2 */
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat3.mmc0_dat3 */
-                       AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_cmd.mmc0_cmd */
-                       AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_clk.mmc0_clk */
-                       AM33XX_IOPAD(0x9a0, PIN_INPUT | MUX_MODE4)              /* mcasp0_aclkr.mmc0_sdwp */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT, MUX_MODE7)               /* spi0_cs1.gpio0_6 */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKR, PIN_INPUT, MUX_MODE4)           /* mcasp0_aclkr.mmc0_sdwp */
                >;
        };
 
        mcasp1_pins: mcasp1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_rxerr.mcasp1_fsx */
-                       AM33XX_IOPAD(0x908, PIN_OUTPUT_PULLDOWN | MUX_MODE4) /* mii1_col.mcasp1_axr2 */
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE4) /* rmii1_ref_clk.mcasp1_axr3 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE4) /* mii1_rxerr.mcasp1_fsx */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_OUTPUT_PULLDOWN, MUX_MODE4) /* mii1_col.mcasp1_axr2 */
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE4) /* rmii1_ref_clk.mcasp1_axr3 */
                >;
        };
 
        mcasp1_pins_sleep: mcasp1_pins_sleep {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x908, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        mmc2_pins: pinmux_mmc2_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x874, PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpio0_31 */
-                       AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
-                       AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_INPUT_PULLUP, MUX_MODE7) /* gpmc_wpn.gpio0_31 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_INPUT_PULLUP, MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_INPUT_PULLUP, MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
                >;
        };
 
        wl12xx_gpio: pinmux_wl12xx_gpio {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x87c, PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_csn0.gpio1_29 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN0, PIN_OUTPUT_PULLUP, MUX_MODE7) /* gpmc_csn0.gpio1_29 */
                >;
        };
 };
index 9ac775c7107227517820b0ff302ea7c12d5c7af0..4365684fa66f652645991b833f6d4c3edce6b600 100644 (file)
 &am33xx_pinmux {
        user_leds: user_leds {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x91c, PIN_OUTPUT | MUX_MODE7) /* (J18) gmii1_txd3.gpio0[16] */
-                       AM33XX_IOPAD(0x920, PIN_OUTPUT | MUX_MODE7) /* (K15) gmii1_txd2.gpio0[17] */
-                       AM33XX_IOPAD(0x9b0, PIN_OUTPUT | MUX_MODE7) /* (A15) xdma_event_intr0.gpio0[19] */
-                       AM33XX_IOPAD(0x9b4, PIN_OUTPUT | MUX_MODE7) /* (D14) xdma_event_intr1.gpio0[20] */
-                       AM33XX_IOPAD(0x880, PIN_OUTPUT | MUX_MODE7) /* (U9) gpmc_csn1.gpio1[30] */
-                       AM33XX_IOPAD(0x92c, PIN_OUTPUT | MUX_MODE7) /* (K18) gmii1_txclk.gpio3[9] */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_OUTPUT, MUX_MODE7) /* (J18) gmii1_txd3.gpio0[16] */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_OUTPUT, MUX_MODE7) /* (K15) gmii1_txd2.gpio0[17] */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT, MUX_MODE7) /* (A15) xdma_event_intr0.gpio0[19] */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_OUTPUT, MUX_MODE7) /* (D14) xdma_event_intr1.gpio0[20] */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_OUTPUT, MUX_MODE7) /* (U9) gpmc_csn1.gpio1[30] */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_OUTPUT, MUX_MODE7) /* (K18) gmii1_txclk.gpio3[9] */
                >;
        };
 
        mmc0_pins_default: mmc0_pins_default {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0) /* (F17) mmc0_dat3.mmc0_dat3 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0) /* (F18) mmc0_dat2.mmc0_dat2 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0) /* (G15) mmc0_dat1.mmc0_dat1 */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0) /* (G16) mmc0_dat0.mmc0_dat0 */
-                       AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0) /* (G17) mmc0_clk.mmc0_clk */
-                       AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0) /* (G18) mmc0_cmd.mmc0_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        i2c0_pins_default: i2c0_pins_default {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT | MUX_MODE0) /* (C17) I2C0_SDA.I2C0_SDA */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT | MUX_MODE0) /* (C16) I2C0_SCL.I2C0_SCL */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT, MUX_MODE0)
                >;
        };
 
        spi0_pins_default: spi0_pins_default {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE0) /* (A17) spi0_sclk.spi0_sclk */
-                       AM33XX_IOPAD(0x954, PIN_INPUT_PULLUP | MUX_MODE0) /* (B17) spi0_d0.spi0_d0 */
-                       AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE0) /* (B16) spi0_d1.spi0_d1 */
-                       AM33XX_IOPAD(0x95c, PIN_INPUT_PULLUP | MUX_MODE0) /* (A16) spi0_cs0.spi0_cs0 */
-                       AM33XX_IOPAD(0x960, PIN_INPUT_PULLUP | MUX_MODE0) /* (C15) spi0_cs1.spi0_cs1 */
-                       AM33XX_IOPAD(0x9a0, PIN_INPUT_PULLUP | MUX_MODE7) /* (B12) mcasp0_aclkr.gpio3[18] */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKR, PIN_INPUT_PULLUP, MUX_MODE7) /* (B12) mcasp0_aclkr.gpio3[18] */
                >;
        };
 
        uart3_pins_default: uart3_pins_default {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLUP | MUX_MODE1) /* (L17) gmii1_rxd3.uart3_rxd */
-                       AM33XX_IOPAD(0x938, PIN_OUTPUT_PULLUP | MUX_MODE1) /* (L16) gmii1_rxd2.uart3_txd */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLUP, MUX_MODE1) /* (L17) gmii1_rxd3.uart3_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_OUTPUT_PULLUP, MUX_MODE1) /* (L16) gmii1_rxd2.uart3_txd */
                >;
        };
 
        cpsw_default: cpsw_default {
                pinctrl-single,pins = <
                        /* Slave 1, RMII mode */
-                       AM33XX_IOPAD(0x90c, (PIN_INPUT_PULLUP | MUX_MODE1))     /* mii1_crs.rmii1_crs_dv */
-                       AM33XX_IOPAD(0x944, (PIN_INPUT_PULLUP | MUX_MODE0))     /* rmii1_refclk.rmii1_refclk */
-                       AM33XX_IOPAD(0x940, (PIN_INPUT_PULLUP | MUX_MODE1))     /* mii1_rxd0.rmii1_rxd0 */
-                       AM33XX_IOPAD(0x93c, (PIN_INPUT_PULLUP | MUX_MODE1))     /* mii1_rxd1.rmii1_rxd1 */
-                       AM33XX_IOPAD(0x910, (PIN_INPUT_PULLUP | MUX_MODE1))     /* mii1_rxerr.rmii1_rxerr */
-                       AM33XX_IOPAD(0x928, (PIN_OUTPUT_PULLDOWN | MUX_MODE1))  /* mii1_txd0.rmii1_txd0 */
-                       AM33XX_IOPAD(0x924, (PIN_OUTPUT_PULLDOWN | MUX_MODE1))  /* mii1_txd1.rmii1_txd1 */
-                       AM33XX_IOPAD(0x914, (PIN_OUTPUT_PULLDOWN | MUX_MODE1))  /* mii1_txen.rmii1_txen */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLUP, MUX_MODE1)        /* mii1_crs.rmii1_crs_dv */
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLUP, MUX_MODE1)      /* mii1_rxerr.rmii1_rxerr */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE1)    /* mii1_txd0.rmii1_txd0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLDOWN, MUX_MODE1)    /* mii1_txd1.rmii1_txd1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE1)   /* mii1_txen.rmii1_txen */
                        /* Slave 2, RMII mode */
-                       AM33XX_IOPAD(0x870, (PIN_INPUT_PULLUP | MUX_MODE3))     /* gpmc_wait0.rmii2_crs_dv */
-                       AM33XX_IOPAD(0x908, (PIN_INPUT_PULLUP | MUX_MODE1))     /* mii1_col.rmii2_refclk */
-                       AM33XX_IOPAD(0x86c, (PIN_INPUT_PULLUP | MUX_MODE3))     /* gpmc_a11.rmii2_rxd0 */
-                       AM33XX_IOPAD(0x868, (PIN_INPUT_PULLUP | MUX_MODE3))     /* gpmc_a10.rmii2_rxd1 */
-                       AM33XX_IOPAD(0x874, (PIN_INPUT_PULLUP | MUX_MODE3))     /* gpmc_wpn.rmii2_rxerr */
-                       AM33XX_IOPAD(0x854, (PIN_OUTPUT_PULLDOWN | MUX_MODE3))  /* gpmc_a5.rmii2_txd0 */
-                       AM33XX_IOPAD(0x850, (PIN_OUTPUT_PULLDOWN | MUX_MODE3))  /* gpmc_a4.rmii2_txd1 */
-                       AM33XX_IOPAD(0x840, (PIN_OUTPUT_PULLDOWN | MUX_MODE3))  /* gpmc_a0.rmii2_txen */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLUP, MUX_MODE3)      /* gpmc_wait0.rmii2_crs_dv */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLUP, MUX_MODE1)        /* mii1_col.rmii2_refclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT_PULLUP, MUX_MODE3)        /* gpmc_a11.rmii2_rxd0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT_PULLUP, MUX_MODE3)        /* gpmc_a10.rmii2_rxd1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_INPUT_PULLUP, MUX_MODE3)        /* gpmc_wpn.rmii2_rxerr */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE3)      /* gpmc_a5.rmii2_txd0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_OUTPUT_PULLDOWN, MUX_MODE3)      /* gpmc_a4.rmii2_txd1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_OUTPUT_PULLDOWN, MUX_MODE3)      /* gpmc_a0.rmii2_txen */
                >;
        };
 
        cpsw_sleep: cpsw_sleep {
                pinctrl-single,pins = <
                        /* Slave 1 reset value */
-                       AM33XX_IOPAD(0x90c, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x944, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x940, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x93c, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x910, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x928, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x924, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x914, (PIN_INPUT_PULLDOWN | MUX_MODE7))
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)
 
                        /* Slave 2 reset value */
-                       AM33XX_IOPAD(0x870, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x908, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x86c, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x868, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x874, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x854, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x850, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x840, (PIN_INPUT_PULLDOWN | MUX_MODE7))
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        davinci_mdio_default: davinci_mdio_default {
                pinctrl-single,pins = <
                        /* MDIO */
-                       AM33XX_IOPAD(0x948, (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0))     /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x94c, (PIN_OUTPUT_PULLUP | MUX_MODE0))                    /* mdio_clk.mdio_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        davinci_mdio_sleep: davinci_mdio_sleep {
                pinctrl-single,pins = <
                        /* MDIO reset value */
-                       AM33XX_IOPAD(0x948, (PIN_INPUT_PULLDOWN | MUX_MODE7))
-                       AM33XX_IOPAD(0x94c, (PIN_INPUT_PULLDOWN | MUX_MODE7))
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 };
index cbd22f25de9570db37c84237305ed0fa67357d44..312deb6cf6a294982ec764628aa457b20b633551 100644 (file)
 &am33xx_pinmux {
        i2c0_pins: pinmux_i2c0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_sda.i2c0_sda */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_scl.i2c0_scl */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        nandflash_pins: pinmux_nandflash_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad0.gpmc_ad0 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad1.gpmc_ad1 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad2.gpmc_ad2 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad3.gpmc_ad3 */
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad4.gpmc_ad4 */
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad5.gpmc_ad5 */
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad6.gpmc_ad6 */
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad7.gpmc_ad7 */
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_wait0.gpmc_wait0 */
-                       AM33XX_IOPAD(0x874, PIN_INPUT_PULLUP | MUX_MODE7)       /* gpmc_wpn.gpio0_30 */
-                       AM33XX_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE0)             /* gpmc_csn0.gpmc_csn0 */
-                       AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE0)             /* gpmc_advn_ale.gpmc_advn_ale */
-                       AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE0)             /* gpmc_oen_ren.gpmc_oen_ren */
-                       AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE0)             /* gpmc_wen.gpmc_wen */
-                       AM33XX_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE0)             /* gpmc_be0n_cle.gpmc_be0n_cle */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_INPUT_PULLUP, MUX_MODE7)        /* gpmc_wpn.gpio0_30 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_ADVN_ALE, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_OEN_REN, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WEN, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN0_CLE, PIN_OUTPUT, MUX_MODE0)
                >;
        };
 
        uart0_pins: pinmux_uart0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        leds_pins: pinmux_leds_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x85c, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_a7.gpio1_23 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_OUTPUT_PULLDOWN, MUX_MODE7)      /* gpmc_a7.gpio1_23 */
                >;
        };
 };
index d0e8e720a4d6b5f5d0b9a0ec8970eaeea5ef27bd..aa4cd2b8d4b69251e75243f4c275e4a6aece0362 100644 (file)
 &am33xx_pinmux {
        mmc1_pins: pinmux_mmc1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat3 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat2 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat1 */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat0 */
-                       AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_clk */
-                       AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        i2c0_pins: pinmux_i2c0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT | MUX_MODE0)      /* i2c0_sda.i2c0_sda */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT | MUX_MODE0)      /* i2c0_scl.i2c0_scl */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT, MUX_MODE0)
                >;
        };
 
        cpsw_default: cpsw_default {
                pinctrl-single,pins = <
                        /* Slave 1 */
-                       AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii1_int */
-                       AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* rmii1_crs_dv */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* rmii1_rxer */
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* rmii1_txen */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* rmii1_td1 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* rmii1_td0 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* rmii1_rd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* rmii1_rd0 */
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* rmii1_refclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A9, PIN_INPUT_PULLDOWN, MUX_MODE7)       /* rmii1_int */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE1)      /* rmii1_crs_dv */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE1)    /* rmii1_rxer */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE1)   /* rmii1_txen */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLDOWN, MUX_MODE1)    /* rmii1_td1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE1)    /* rmii1_td0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE1)     /* rmii1_rd1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE1)     /* rmii1_rd0 */
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE0)
 
                        /* Slave 2 */
-                       AM33XX_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* rmii2_txen */
-                       AM33XX_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* rmii2_td1 */
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* rmii2_td0 */
-                       AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE3)     /* rmii2_rd1 */
-                       AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE3)     /* rmii2_rd0 */
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLDOWN | MUX_MODE3)     /* rmii2_crs_dv */
-                       AM33XX_IOPAD(0x874, PIN_INPUT_PULLDOWN | MUX_MODE3)     /* rmii2_rxer */
-                       AM33XX_IOPAD(0x878, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii2_int */
-                       AM33XX_IOPAD(0x908, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* rmii2_refclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_OUTPUT_PULLDOWN, MUX_MODE3)      /* rmii2_txen */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_OUTPUT_PULLDOWN, MUX_MODE3)      /* rmii2_td1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE3)      /* rmii2_td0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT_PULLDOWN, MUX_MODE3)      /* rmii2_rd1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT_PULLDOWN, MUX_MODE3)      /* rmii2_rd0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLDOWN, MUX_MODE3)    /* rmii2_crs_dv */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_INPUT_PULLDOWN, MUX_MODE3)      /* rmii2_rxer */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* rmii2_int */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLDOWN, MUX_MODE1)      /* rmii2_refclk */
                >;
        };
 
        cpsw_sleep: cpsw_sleep {
                pinctrl-single,pins = <
                        /* Slave 1 reset value */
-                       AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii1_int */
-                       AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii1_crs_dv */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii1_rxer */
-                       AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii1_txen */
-                       AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii1_td1 */
-                       AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii1_td0 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii1_rd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii1_rd0 */
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii1_refclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A9, PIN_INPUT_PULLDOWN, MUX_MODE7)       /* rmii1_int */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* rmii1_crs_dv */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE7)    /* rmii1_rxer */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)    /* rmii1_txen */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* rmii1_td1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* rmii1_td0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* rmii1_rd1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* rmii1_rd0 */
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7) /* rmii1_refclk */
 
                        /* Slave 2 reset value*/
-                       AM33XX_IOPAD(0x840, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii2_txen */
-                       AM33XX_IOPAD(0x850, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii2_td1 */
-                       AM33XX_IOPAD(0x854, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii2_td0 */
-                       AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii2_rd1 */
-                       AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii2_rd0 */
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii2_crs_dv */
-                       AM33XX_IOPAD(0x874, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii2_rxer */
-                       AM33XX_IOPAD(0x878, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii2_int */
-                       AM33XX_IOPAD(0x908, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* rmii2_refclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_INPUT_PULLDOWN, MUX_MODE7)       /* rmii2_txen */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_INPUT_PULLDOWN, MUX_MODE7)       /* rmii2_td1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_INPUT_PULLDOWN, MUX_MODE7)       /* rmii2_td0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* rmii2_rd1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* rmii2_rd0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLDOWN, MUX_MODE7)    /* rmii2_crs_dv */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* rmii2_rxer */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* rmii2_int */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* rmii2_refclk */
                >;
        };
 
        davinci_mdio_default: davinci_mdio_default {
                pinctrl-single,pins = <
                        /* MDIO */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)                      /* mdio_clk.mdio_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        davinci_mdio_sleep: davinci_mdio_sleep {
                pinctrl-single,pins = <
                        /* MDIO reset value */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        emmc_pins: pinmux_emmc_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
-                       AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_INPUT_PULLUP, MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_INPUT_PULLUP, MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
                >;
        };
 
        uart0_pins: pinmux_uart0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 };
index cb5913a6983787c2925c728f73178785421888be..671d4a5da9c43ad5ae0e92ea8099c0e2a30a66e5 100644 (file)
 
        i2c0_pins: pinmux_i2c0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_sda.i2c0_sda */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_scl.i2c0_scl */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        push_button_pins: pinmux_push_button {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8e4, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* lcd_hsync.gpio2_23 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* lcd_hsync.gpio2_23 */
                >;
        };
 
        uart0_pins: pinmux_uart0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        davinci_mdio_default: davinci_mdio_default {
                pinctrl-single,pins = <
                        /* MDIO */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)                      /* mdio_clk.mdio_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        mmc1_pins_default: pinmux_mmc1_pins {
                pinctrl-single,pins = <
                        /* eMMC */
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad12.mmc1_dat0 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad13.mmc1_dat1 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad14.mmc1_dat2 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad15.mmc1_dat3 */
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad8.mmc1_dat4 */
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad9.mmc1_dat5 */
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad10.mmc1_dat6 */
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad11.mmc1_dat7 */
-                       AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2)       /* gpmc_csn2.mmc1_cmd */
-                       AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2)       /* gpmc_csn1.mmc1_clk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad12.mmc1_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad13.mmc1_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad14.mmc1_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad15.mmc1_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad8.mmc1_dat4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad9.mmc1_dat5 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad10.mmc1_dat6 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad11.mmc1_dat7 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_INPUT_PULLUP, MUX_MODE2)       /* gpmc_csn2.mmc1_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_INPUT_PULLUP, MUX_MODE2)       /* gpmc_csn1.mmc1_clk */
                >;
        };
 
        spi0_pins: pinmux_spi0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE0)        /* spi0_sclk.spi0_sclk */
-                       AM33XX_IOPAD(0x95c, PIN_INPUT_PULLUP | MUX_MODE0)        /* spi0_cs0.spi0_cs0 */
-                       AM33XX_IOPAD(0x954, PIN_INPUT_PULLUP | MUX_MODE0)        /* spi0_d0.spi0_d0 */
-                       AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE0)        /* spi0_d1.spi0_d1 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D1, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 };
index 48aee6de4cdbfe5242f05f807246c21412c9ba20..5923b6e7e1cb8a2eb25f2e8a7131317afe386c1a 100644 (file)
        cpsw_default: cpsw_default {
                pinctrl-single,pins = <
                        /* Slave 1 */
-                       AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* mii1_crs.rmii1_crs_dv */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLUP | MUX_MODE1)       /* mii1_rxerr.rmii1_rxerr */
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* mii1_txen.rmii1_txen */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* mii1_txd1.rmii1_txd1 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* mii1_txd0.rmii1_txd0 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLUP | MUX_MODE1)       /* mii1_rxd1.rmii1_rxd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLUP | MUX_MODE1)       /* mii1_rxd0.rmii1_rxd0 */
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* mii1_refclk.rmii1_refclk */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE1)      /* mii1_crs.rmii1_crs_dv */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLUP, MUX_MODE1)      /* mii1_rxerr.rmii1_rxerr */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE1)   /* mii1_txen.rmii1_txen */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLDOWN, MUX_MODE1)    /* mii1_txd1.rmii1_txd1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE1)    /* mii1_txd0.rmii1_txd0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLUP, MUX_MODE1)       /* mii1_rxd1.rmii1_rxd1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLUP, MUX_MODE1)       /* mii1_rxd0.rmii1_rxd0 */
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        spi1_pins: pinmux_spi1 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x964, PIN_INPUT_PULLUP | MUX_MODE4)        /* ecap0_in_pwm0_out.spi1_sclk */
-                       AM33XX_IOPAD(0x978, PIN_INPUT_PULLUP | MUX_MODE4)        /* uart1_ctsn.spi1_cs0 */
-                       AM33XX_IOPAD(0x968, PIN_INPUT_PULLUP | MUX_MODE4)        /* uart0_ctsn.spi1_d0 */
-                       AM33XX_IOPAD(0x96c, PIN_INPUT_PULLUP | MUX_MODE4)        /* uart0_rtsn.spi1_d1 */
+                       AM33XX_PADCONF(AM335X_PIN_ECAP0_IN_PWM0_OUT, PIN_INPUT_PULLUP, MUX_MODE4)        /* ecap0_in_pwm0_out.spi1_sclk */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT_PULLUP, MUX_MODE4)       /* uart1_ctsn.spi1_cs0 */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_CTSN, PIN_INPUT_PULLUP, MUX_MODE4)       /* uart0_ctsn.spi1_d0 */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_INPUT_PULLUP, MUX_MODE4)       /* uart0_rtsn.spi1_d1 */
                >;
        };
 };
index e562ce40f290a71797ae3958d1111aa3699ddc32..5a2fb4bd4e026add036d73c9228b536108afc254 100644 (file)
 
        minipcie_pins: pinmux_minipcie {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8e8, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* lcd_pclk.gpio2_24 */
-                       AM33XX_IOPAD(0x8ec, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* lcd_ac_bias_en.gpio2_25 */
-                       AM33XX_IOPAD(0x8e0, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* lcd_vsync.gpio2_22  Power off PIN*/
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* lcd_pclk.gpio2_24 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)        /* lcd_ac_bias_en.gpio2_25 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_INPUT_PULLDOWN, MUX_MODE7)     /* lcd_vsync.gpio2_22  Power off PIN*/
                >;
        };
 
        push_button_pins: pinmux_push_button {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9ac, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* mcasp0_ahcklx.gpio3_21 */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKX, PIN_INPUT_PULLDOWN, MUX_MODE7) /* mcasp0_ahcklx.gpio3_21 */
                >;
        };
 
        i2c0_pins: pinmux_i2c0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)    /* i2c0_sda.i2c0_sda */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)    /* i2c0_scl.i2c0_scl */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
 
        i2c1_pins: pinmux_i2c1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x968, PIN_INPUT_PULLUP | MUX_MODE3)       /* uart0_ctsn.i2c1_sda */
-                       AM33XX_IOPAD(0x96c, PIN_INPUT_PULLUP | MUX_MODE3)       /* uart0_rtsn.i2c1_scl */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_CTSN, PIN_INPUT_PULLUP, MUX_MODE3)      /* uart0_ctsn.i2c1_sda */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_INPUT_PULLUP, MUX_MODE3)      /* uart0_rtsn.i2c1_scl */
                >;
        };
 
        uart0_pins: pinmux_uart0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        uart1_pins: pinmux_uart1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x978, PIN_INPUT | MUX_MODE0)              /* uart1_ctsn.uart1_ctsn */
-                       AM33XX_IOPAD(0x97C, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_rtsn.uart1_rtsn */
-                       AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0)    /* uart1_rxd.uart1_rxd */
-                       AM33XX_IOPAD(0x984, PIN_OUTPUT | MUX_MODE0)             /* uart1_txd.uart1_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_OUTPUT, MUX_MODE0)
                >;
        };
 
        uart2_pins: pinmux_uart2_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8d8, PIN_INPUT | MUX_MODE6)              /* lcd_data14.uart5_ctsn */
-                       AM33XX_IOPAD(0x8dc, PIN_OUTPUT_PULLDOWN | MUX_MODE6)  /* lcd_data15.uart5_rtsn */
-                       AM33XX_IOPAD(0x8c4, PIN_INPUT_PULLUP | MUX_MODE4)     /* lcd_data9.uart5_rxd */
-                       AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE4)             /* lcd_data8.uart5_txd */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_INPUT, MUX_MODE6)             /* lcd_data14.uart5_ctsn */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT_PULLDOWN, MUX_MODE6)  /* lcd_data15.uart5_rtsn */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_INPUT_PULLUP, MUX_MODE4)     /* lcd_data9.uart5_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE4)             /* lcd_data8.uart5_txd */
                >;
        };
 
        cpsw_default: cpsw_default {
                pinctrl-single,pins = <
                        /* Slave 1 */
-                       AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE1)  /* mii1_crs.rmii1_crs_dv */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLUP | MUX_MODE1)    /* mii1_rxerr.rmii1_rxerr */
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txen.rmii1_txen */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd1.rmii1_txd1 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd0.rmii1_txd0 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLUP | MUX_MODE1)    /* mii1_rxd1.rmii1_rxd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLUP | MUX_MODE1)    /* mii1_rxd0.rmii1_rxd0 */
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE0)  /* mii1_refclk.rmii1_refclk */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLDOWN, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE0)
 
                        /* Slave 2 */
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLDOWN | MUX_MODE3)   /* rmii2_crs_dv */
-                       AM33XX_IOPAD(0x874, PIN_INPUT_PULLDOWN | MUX_MODE3)   /* rmii2_rxer */
-                       AM33XX_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE3)  /* rmii2_txen */
-                       AM33XX_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE3)  /* rmii2_td1 */
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE3)  /* rmii2_td0 */
-                       AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE3)   /* rmii2_rd1 */
-                       AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE3)   /* rmii2_rd0 */
-                       AM33XX_IOPAD(0x908, PIN_INPUT_PULLDOWN | MUX_MODE1)  /* rmii2_refclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLDOWN, MUX_MODE3)   /* rmii2_crs_dv */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_INPUT_PULLDOWN, MUX_MODE3)   /* rmii2_rxer */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_OUTPUT_PULLDOWN, MUX_MODE3)  /* rmii2_txen */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_OUTPUT_PULLDOWN, MUX_MODE3)  /* rmii2_td1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE3)  /* rmii2_td0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT_PULLDOWN, MUX_MODE3)   /* rmii2_rd1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT_PULLDOWN, MUX_MODE3)   /* rmii2_rd0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLDOWN, MUX_MODE1)  /* rmii2_refclk */
 
                >;
        };
        davinci_mdio_default: davinci_mdio_default {
                pinctrl-single,pins = <
                        /* MDIO */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)                      /* mdio_clk.mdio_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        mmc0_pins_default: pinmux_mmc0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat3 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat2 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat1 */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat0 */
-                       AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_clk */
-                       AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_cmd */
-                       AM33XX_IOPAD(0x990, PIN_INPUT_PULLUP | MUX_MODE7)       /* mcasp0_aclkx.gpio3_14 */
-                       AM33XX_IOPAD(0x9a0, PIN_INPUT_PULLUP | MUX_MODE7)    /* mcasp0_aclkx.gpio3_18 */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_INPUT_PULLUP, MUX_MODE7)    /* mcasp0_aclkx.gpio3_14 */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKR, PIN_INPUT_PULLUP, MUX_MODE7)    /* mcasp0_aclkx.gpio3_18 */
                >;
        };
 
        mmc2_pins_default: pinmux_mmc2_pins {
                pinctrl-single,pins = <
                        /* eMMC */
-                       AM33XX_IOPAD(0x830, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_ad12.mmc2_dat0 */
-                       AM33XX_IOPAD(0x834, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_ad13.mmc2_dat1 */
-                       AM33XX_IOPAD(0x838, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_ad14.mmc2_dat2 */
-                       AM33XX_IOPAD(0x83c, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_ad15.mmc2_dat3 */
-                       AM33XX_IOPAD(0x820, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_ad8.mmc2_dat4 */
-                       AM33XX_IOPAD(0x824, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_ad9.mmc2_dat5 */
-                       AM33XX_IOPAD(0x828, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_ad10.mmc2_dat6 */
-                       AM33XX_IOPAD(0x82c, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_ad11.mmc2_dat7 */
-                       AM33XX_IOPAD(0x888, PIN_INPUT_PULLUP | MUX_MODE3)     /* gpmc_csn3.mmc2_cmd */
-                       AM33XX_IOPAD(0x88c, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_clk.mmc2_clk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_ad12.mmc2_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_ad13.mmc2_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_ad14.mmc2_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_ad15.mmc2_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD8, PIN_INPUT_PULLUP, MUX_MODE3)        /* gpmc_ad8.mmc2_dat4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD9, PIN_INPUT_PULLUP, MUX_MODE3)        /* gpmc_ad9.mmc2_dat5 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_ad10.mmc2_dat6 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_ad11.mmc2_dat7 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN3, PIN_INPUT_PULLUP, MUX_MODE3)     /* gpmc_csn3.mmc2_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CLK, PIN_INPUT_PULLUP, MUX_MODE3)        /* gpmc_clk.mmc2_clk */
                >;
        };
 
        spi0_pins: pinmux_spi0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_sclk.spi0_sclk */
-                       AM33XX_IOPAD(0x95C, PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_cs0.spi0_cs0 */
-                       AM33XX_IOPAD(0x954, PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_d0.spi0_d0 */
-                       AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_d1.spi0_d1 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D1, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
index 9c9143ed40037f04e63eec7c7e5e014083dd281d..0052657331eec7f4be3080545a6d2f5231ec9f64 100644 (file)
 
        misc_pins: misc_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x95c, PIN_OUTPUT | MUX_MODE7)     /* spi0_cs0.gpio0_5 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_OUTPUT, MUX_MODE7)      /* spi0_cs0.gpio0_5 */
                >;
        };
 
        gpmc_pins: gpmc_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad0.gpmc_ad0 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad1.gpmc_ad1 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad2.gpmc_ad2 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad3.gpmc_ad3 */
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad4.gpmc_ad4 */
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad5.gpmc_ad5 */
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad6.gpmc_ad6 */
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad7.gpmc_ad7 */
-                       AM33XX_IOPAD(0x820, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad8.gpmc_ad8 */
-                       AM33XX_IOPAD(0x824, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad9.gpmc_ad9 */
-                       AM33XX_IOPAD(0x828, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad10.gpmc_ad10 */
-                       AM33XX_IOPAD(0x82c, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad11.gpmc_ad11 */
-                       AM33XX_IOPAD(0x830, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad12.gpmc_ad12 */
-                       AM33XX_IOPAD(0x834, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad13.gpmc_ad13 */
-                       AM33XX_IOPAD(0x838, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad14.gpmc_ad14 */
-                       AM33XX_IOPAD(0x83c, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad15.gpmc_ad15 */
-
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_wait0.gpmc_wait0 */
-                       AM33XX_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE0)             /* gpmc_csn0.gpmc_csn0 */
-                       AM33XX_IOPAD(0x880, PIN_OUTPUT | MUX_MODE0)             /* gpmc_csn1.gpmc_csn1 */
-                       AM33XX_IOPAD(0x884, PIN_OUTPUT | MUX_MODE0)             /* gpmc_csn2.gpmc_csn2 */
-                       AM33XX_IOPAD(0x888, PIN_OUTPUT | MUX_MODE0)             /* gpmc_csn3.gpmc_csn3 */
-
-                       AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE0)             /* gpmc_advn_ale.gpmc_advn_ale */
-                       AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE0)             /* gpmc_oen_ren.gpmc_oen_ren */
-                       AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE0)             /* gpmc_wen.gpmc_wen */
-                       AM33XX_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE0)             /* gpmc_ben0_cle.gpmc_ben0_cle */
-
-                       AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE1)             /* lcd_data1.gpmc_a1 */
-                       AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE1)             /* lcd_data2.gpmc_a2 */
-                       AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE1)             /* lcd_data3.gpmc_a3 */
-                       AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE1)             /* lcd_data4.gpmc_a4 */
-                       AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE1)             /* lcd_data5.gpmc_a5 */
-                       AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE1)             /* lcd_data6.gpmc_a6 */
-                       AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE1)             /* lcd_data7.gpmc_a7 */
-
-                       AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE1)             /* lcd_vsync.gpmc_a8 */
-                       AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE1)             /* lcd_hsync.gpmc_a9 */
-                       AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE1)             /* lcd_pclk.gpmc_a10 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD8, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD9, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT_PULLUP, MUX_MODE0)
+
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN3, PIN_OUTPUT, MUX_MODE0)
+
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_ADVN_ALE, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_OEN_REN, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WEN, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN0_CLE, PIN_OUTPUT, MUX_MODE0)
+
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE1)             /* lcd_data1.gpmc_a1 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE1)             /* lcd_data2.gpmc_a2 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE1)             /* lcd_data3.gpmc_a3 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE1)             /* lcd_data4.gpmc_a4 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE1)             /* lcd_data5.gpmc_a5 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE1)             /* lcd_data6.gpmc_a6 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE1)             /* lcd_data7.gpmc_a7 */
+
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT, MUX_MODE1)             /* lcd_vsync.gpmc_a8 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT, MUX_MODE1)             /* lcd_hsync.gpmc_a9 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT, MUX_MODE1)              /* lcd_pclk.gpmc_a10 */
                >;
        };
 
        i2c0_pins: i2c0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* i2c0_sda.i2c0_sda */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* i2c0_scl.i2c0_scl */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        uart0_pins: uart0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT | MUX_MODE0)             /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT, MUX_MODE0)
                >;
        };
 
        uart1_pins: uart1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x978, PIN_OUTPUT | MUX_MODE7)             /* uart1_ctsn.uart1_ctsn */
-                       AM33XX_IOPAD(0x97c, PIN_OUTPUT | MUX_MODE7)             /* uart1_rtsn.uart1_rtsn */
-                       AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart1_rxd.uart1_rxd */
-                       AM33XX_IOPAD(0x984, PIN_OUTPUT | MUX_MODE0)             /* uart1_txd.uart1_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_OUTPUT, MUX_MODE0)
                >;
        };
 
        uart2_pins: uart2_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8c0, PIN_INPUT_PULLUP | MUX_MODE7)       /* lcd_data8.gpio2[14] */
-                       AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE7)             /* lcd_data9.gpio2[15] */
-                       AM33XX_IOPAD(0x950, PIN_INPUT | MUX_MODE1)              /* spi0_sclk.uart2_rxd */
-                       AM33XX_IOPAD(0x954, PIN_OUTPUT | MUX_MODE1)             /* spi0_d0.uart2_txd */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_INPUT_PULLUP, MUX_MODE7)       /* lcd_data8.gpio2[14] */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE7)             /* lcd_data9.gpio2[15] */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT, MUX_MODE1)              /* spi0_sclk.uart2_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_OUTPUT, MUX_MODE1)               /* spi0_d0.uart2_txd */
                >;
        };
 
        uart3_pins: uart3_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8c8, PIN_INPUT_PULLUP | MUX_MODE6)       /* lcd_data10.uart3_ctsn */
-                       AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE6)             /* lcd_data11.uart3_rtsn */
-                       AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE1)              /* spi0_cs1.uart3_rxd */
-                       AM33XX_IOPAD(0x964, PIN_OUTPUT | MUX_MODE1)             /* ecap0_in_pwm0_out.uart3_txd */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_INPUT_PULLUP, MUX_MODE6)      /* lcd_data10.uart3_ctsn */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE6)            /* lcd_data11.uart3_rtsn */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT, MUX_MODE1)               /* spi0_cs1.uart3_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_ECAP0_IN_PWM0_OUT, PIN_OUTPUT, MUX_MODE1)             /* ecap0_in_pwm0_out.uart3_txd */
                >;
        };
 
        uart4_pins: uart4_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8d0, PIN_INPUT_PULLUP | MUX_MODE6)       /* lcd_data12.uart4_ctsn */
-                       AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE6)             /* lcd_data13.uart4_rtsn */
-                       AM33XX_IOPAD(0x968, PIN_INPUT | MUX_MODE1)              /* uart0_ctsn.uart4_rxd */
-                       AM33XX_IOPAD(0x96c, PIN_OUTPUT | MUX_MODE1)             /* uart0_rtsn.uart4_txd */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_INPUT_PULLUP, MUX_MODE6)      /* lcd_data12.uart4_ctsn */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE6)            /* lcd_data13.uart4_rtsn */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_CTSN, PIN_INPUT, MUX_MODE1)             /* uart0_ctsn.uart4_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_OUTPUT, MUX_MODE1)            /* uart0_rtsn.uart4_txd */
                >;
        };
 
        uart5_pins: uart5_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8d8, PIN_INPUT | MUX_MODE4)              /* lcd_data14.uart5_rxd */
-                       AM33XX_IOPAD(0x944, PIN_OUTPUT | MUX_MODE3)             /* rmiii1_refclk.uart5_txd */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_INPUT, MUX_MODE4)             /* lcd_data14.uart5_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_OUTPUT, MUX_MODE3)         /* rmiii1_refclk.uart5_txd */
                >;
        };
 
        mmc1_pins: mmc1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat0.mmc0_dat0 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat1.mmc0_dat1 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat2.mmc0_dat2 */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat3.mmc0_dat3 */
-                       AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_clk.mmc0_clk */
-                       AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_cmd.mmc0_cmd */
-                       AM33XX_IOPAD(0x9e8, PIN_INPUT_PULLUP | MUX_MODE7)       /* emu1.gpio3[8] */
-                       AM33XX_IOPAD(0x9a0, PIN_INPUT_PULLUP | MUX_MODE7)       /* mcasp0_aclkr.gpio3[18] */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)        /* mmc0_clk.mmc0_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)        /* mmc0_cmd.mmc0_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_EMU1, PIN_INPUT_PULLUP, MUX_MODE7)    /* emu1.gpio3[8] */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKR, PIN_INPUT_PULLUP, MUX_MODE7)    /* mcasp0_aclkr.gpio3[18] */
                >;
        };
 };
index 95d54cf3849eb91e008f0179c042a3530f835244..f47cc9fea2538dd21c0f24bbc0cbc6c030b77dec 100644 (file)
 &am33xx_pinmux {
        nxp_hdmi_bonelt_pins: nxp-hdmi-bonelt-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* xdma_event_intr0 */
-                       AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data0.lcd_data0 */
-                       AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data1.lcd_data1 */
-                       AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data2.lcd_data2 */
-                       AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)             /* lcd_data3.lcd_data3 */
-                       AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data4.lcd_data4 */
-                       AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data5.lcd_data5 */
-                       AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data6.lcd_data6 */
-                       AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)             /* lcd_data7.lcd_data7 */
-                       AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data8.lcd_data8 */
-                       AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data9.lcd_data9 */
-                       AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data10.lcd_data10 */
-                       AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)             /* lcd_data11.lcd_data11 */
-                       AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data12.lcd_data12 */
-                       AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data13.lcd_data13 */
-                       AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data14.lcd_data14 */
-                       AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)             /* lcd_data15.lcd_data15 */
-                       AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* lcd_vsync.lcd_vsync */
-                       AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* lcd_hsync.lcd_hsync */
-                       AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* lcd_pclk.lcd_pclk */
-                       AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* lcd_ac_bias_en.lcd_ac_bias_en */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLDOWN, MUX_MODE3)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        nxp_hdmi_bonelt_off_pins: nxp-hdmi-bonelt-off-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* xdma_event_intr0 */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_OUTPUT_PULLDOWN, MUX_MODE3)
                >;
        };
 
        mcasp0_pins: mcasp0-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9ac, PIN_INPUT_PULLUP | MUX_MODE0) /* mcasp0_ahcklx.mcasp0_ahclkx */
-                       AM33XX_IOPAD(0x99c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2*/
-                       AM33XX_IOPAD(0x994, PIN_OUTPUT_PULLUP | MUX_MODE0) /* mcasp0_fsx.mcasp0_fsx */
-                       AM33XX_IOPAD(0x990, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_aclkx.mcasp0_aclkx */
-                       AM33XX_IOPAD(0x86c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a11.GPIO1_27 */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKX, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKR, PIN_OUTPUT_PULLDOWN, MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2*/
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_OUTPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_OUTPUT_PULLDOWN, MUX_MODE7) /* gpmc_a11.GPIO1_27 */
                >;
        };
 
        flash_enable: flash-enable {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x944, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* rmii1_ref_clk.gpio0_29 */
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE7)        /* rmii1_ref_clk.gpio0_29 */
                >;
        };
 
        imu_interrupt: imu-interrupt {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)             /* mii1_rx_er.gpio3_2 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE7)            /* mii1_rx_er.gpio3_2 */
                >;
        };
 
        ethernet_interrupt: ethernet-interrupt{
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x908, PIN_INPUT_PULLDOWN | MUX_MODE7)             /* mii1_col.gpio3_0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT_PULLDOWN, MUX_MODE7)              /* mii1_col.gpio3_0 */
                >;
        };
 };
 
        user_leds_s0: user-leds-s0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_a5.gpio1_21 */
-                       AM33XX_IOPAD(0x858, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* gpmc_a6.gpio1_22 */
-                       AM33XX_IOPAD(0x85c, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_a7.gpio1_23 */
-                       AM33XX_IOPAD(0x860, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* gpmc_a8.gpio1_24 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE7)      /* gpmc_a5.gpio1_21 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_OUTPUT_PULLUP, MUX_MODE7)        /* gpmc_a6.gpio1_22 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_OUTPUT_PULLDOWN, MUX_MODE7)      /* gpmc_a7.gpio1_23 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_OUTPUT_PULLUP, MUX_MODE7)        /* gpmc_a8.gpio1_24 */
                >;
        };
 
        i2c2_pins: pinmux-i2c2-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x978, PIN_INPUT_PULLUP | MUX_MODE3)       /* uart1_ctsn.i2c2_sda */
-                       AM33XX_IOPAD(0x97c, PIN_INPUT_PULLUP | MUX_MODE3)       /* uart1_rtsn.i2c2_scl */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT_PULLUP, MUX_MODE3)      /* uart1_ctsn.i2c2_sda */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_INPUT_PULLUP, MUX_MODE3)      /* uart1_rtsn.i2c2_scl */
                >;
        };
 
        uart0_pins: pinmux-uart0-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        clkout2_pin: pinmux-clkout2-pin {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9b4, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* xdma_event_intr1.clkout2 */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_OUTPUT_PULLDOWN, MUX_MODE3)     /* xdma_event_intr1.clkout2 */
                >;
        };
 
        cpsw_default: cpsw-default {
                pinctrl-single,pins = <
                        /* Slave 1 */
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txen.rgmii1_tctl */
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE2)             /* mii1_rxdv.rgmii1_rctl */
-                       AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd3.rgmii1_txd3 */
-                       AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd2.rgmii1_txd2 */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd1.rgmii1_txd1 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd0.rgmii1_txd0 */
-                       AM33XX_IOPAD(0x92c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txclk.rgmii1_txclk */
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE2)             /* mii1_rxclk.rgmii1_rxclk */
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE2)             /* mii1_rxd3.rgmii1_rxd3 */
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE2)             /* mii1_rxd2.rgmii1_rxd2 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE2)             /* mii1_rxd1.rgmii1_rxd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE2)             /* mii1_rxd0.rgmii1_rxd0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE2)   /* mii1_txen.rgmii1_tctl */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE2)            /* mii1_rxdv.rgmii1_rctl */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_OUTPUT_PULLDOWN, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLDOWN, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLDOWN, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLDOWN, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE2)
                >;
        };
 
        cpsw_sleep: cpsw-sleep {
                pinctrl-single,pins = <
                        /* Slave 1 reset value */
-                       AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        davinci_mdio_default: davinci-mdio-default {
                pinctrl-single,pins = <
                        /* MDIO */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)                      /* mdio_clk.mdio_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        davinci_mdio_sleep: davinci-mdio-sleep {
                pinctrl-single,pins = <
                        /* MDIO reset value */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        mmc1_pins: pinmux-mmc1-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* (C15) spi0_cs1.gpio0[6] */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0) /* (G16) mmc0_dat0.mmc0_dat0 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0) /* (G15) mmc0_dat1.mmc0_dat1 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0) /* (F18) mmc0_dat2.mmc0_dat2 */
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0) /* (F17) mmc0_dat3.mmc0_dat3 */
-                       AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0) /* (G18) mmc0_cmd.mmc0_cmd */
-                       AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0) /* (G17) mmc0_clk.mmc0_clk */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT, MUX_MODE7) /* (C15) spi0_cs1.gpio0[6] */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        emmc_pins: pinmux-emmc-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
-                       AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_INPUT_PULLUP, MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_INPUT_PULLUP, MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
                >;
        };
 };
index f8ff473f94f01086ecaabf10666b620c2a22e8fb..a8b6842489f745f838f50f9765e2c854c121b479 100644 (file)
@@ -36,8 +36,8 @@
 &am33xx_pinmux {
        i2c0_pins: pinmux-i2c0-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)       /* (C17) I2C0_SDA.I2C0_SDA */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)       /* (C16) I2C0_SCL.I2C0_SCL */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 };
index 1ec8e0d801912fbb080b7f3ff880d017f60bf320..baceaa7bb33b133731bdab2c55aea0fa30741678 100644 (file)
 &am33xx_pinmux {
        user_buttons_pins: pinmux_user_buttons {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9e4, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* emu0.gpio3_7 */
-                       AM33XX_IOPAD(0x9e8, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* emu1.gpio3_8 */
+                       AM33XX_PADCONF(AM335X_PIN_EMU0, PIN_INPUT_PULLDOWN, MUX_MODE7)  /* emu0.gpio3_7 */
+                       AM33XX_PADCONF(AM335X_PIN_EMU1, PIN_INPUT_PULLDOWN, MUX_MODE7)  /* emu1.gpio3_8 */
                >;
        };
 
        user_leds_pins: pinmux_user_leds {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x880, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_csn1.gpio1_30 */
-                       AM33XX_IOPAD(0x884, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_csn2.gpio1_31 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_OUTPUT_PULLDOWN, MUX_MODE7)    /* gpmc_csn1.gpio1_30 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_OUTPUT_PULLDOWN, MUX_MODE7)    /* gpmc_csn2.gpio1_31 */
                >;
        };
 };
@@ -96,8 +96,8 @@
 &am33xx_pinmux {
        dcan1_pins: pinmux_dcan1 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x980, PIN_OUTPUT_PULLUP | MUX_MODE2)      /* uart1_rxd.dcan1_tx_mux2 */
-                       AM33XX_IOPAD(0x984, PIN_INPUT_PULLUP | MUX_MODE2)       /* uart1_txd.dcan1_rx_mux2 */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_OUTPUT_PULLUP, MUX_MODE2)      /* uart1_rxd.dcan1_tx_mux2 */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_INPUT_PULLUP, MUX_MODE2)       /* uart1_txd.dcan1_rx_mux2 */
                >;
        };
 };
 &am33xx_pinmux {
        ethernet1_pins: pinmux_ethernet1 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a0.rgmii2_tctl */
-                       AM33XX_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a1.rgmii2_rctl */
-                       AM33XX_IOPAD(0x848, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a2.rgmii2_td3 */
-                       AM33XX_IOPAD(0x84c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a3.rgmii2_td2 */
-                       AM33XX_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a4.rgmii2_td1 */
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a5.rgmii2_td0 */
-                       AM33XX_IOPAD(0x858, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* gpmc_a6.rgmii2_tclk */
-                       AM33XX_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a7.rgmii2_rclk */
-                       AM33XX_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a8.rgmii2_rd3 */
-                       AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a9.rgmii2_rd2 */
-                       AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a10.rgmii2_rd1 */
-                       AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* gpmc_a11.rgmii2_rd0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a0.rgmii2_tctl */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A1, PIN_INPUT_PULLDOWN, MUX_MODE2)       /* gpmc_a1.rgmii2_rctl */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a2.rgmii2_td3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A3, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a3.rgmii2_td2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a4.rgmii2_td1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a5.rgmii2_td0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_OUTPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a6.rgmii2_tclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_INPUT_PULLDOWN, MUX_MODE2)       /* gpmc_a7.rgmii2_rclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_INPUT_PULLDOWN, MUX_MODE2)       /* gpmc_a8.rgmii2_rd3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A9, PIN_INPUT_PULLDOWN, MUX_MODE2)       /* gpmc_a9.rgmii2_rd2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a10.rgmii2_rd1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT_PULLDOWN, MUX_MODE2)      /* gpmc_a11.rgmii2_rd0 */
                >;
        };
 };
 
        cb_gpio_pins: pinmux_cb_gpio {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x968, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* uart0_ctsn.gpio1_8 */
-                       AM33XX_IOPAD(0x96c, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* uart0_rtsn.gpio1_9 */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_CTSN, PIN_OUTPUT_PULLDOWN, MUX_MODE7)   /* uart0_ctsn.gpio1_8 */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_OUTPUT_PULLDOWN, MUX_MODE7)   /* uart0_rtsn.gpio1_9 */
                >;
        };
 };
 &am33xx_pinmux {
        mmc1_pins: pinmux_mmc1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat3.mmc0_dat3 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat2.mmc0_dat2 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat1.mmc0_dat1 */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat0.mmc0_dat0 */
-                       AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_clk.mmc0_clk */
-                       AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_cmd.mmc0_cmd */
-                       AM33XX_IOPAD(0x960, PIN_INPUT_PULLUP | MUX_MODE7)       /* spi0_cs1.mmc0_sdcd */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT_PULLUP, MUX_MODE7)        /* spi0_cs1.mmc0_sdcd */
                >;
        };
 };
 &am33xx_pinmux {
        uart0_pins: pinmux_uart0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        uart1_pins: pinmux_uart1 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart1_rxd.uart1_rxd */
-                       AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart1_txd.uart1_txd */
-                       AM33XX_IOPAD(0x978, PIN_INPUT | MUX_MODE0)              /* uart1_ctsn.uart1_ctsn */
-                       AM33XX_IOPAD(0x97c, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart1_rtsn.uart1_rtsn */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        uart2_pins: pinmux_uart2 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x92c, PIN_INPUT_PULLUP | MUX_MODE1)       /* mii1_tx_clk.uart2_rxd */
-                       AM33XX_IOPAD(0x930, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* mii1_rx_clk.uart2_txd */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT_PULLUP, MUX_MODE1)     /* mii1_tx_clk.uart2_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE1)  /* mii1_rx_clk.uart2_txd */
                >;
        };
 
        uart3_pins: pinmux_uart3 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLUP | MUX_MODE1)       /* mii1_rxd3.uart3_rxd */
-                       AM33XX_IOPAD(0x938, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* mii1_rxd2.uart3_txd */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLUP, MUX_MODE1)       /* mii1_rxd3.uart3_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE1)    /* mii1_rxd2.uart3_txd */
                >;
        };
 };
index ae43d61f4e8b4333fa137bd315f05e079fd812b6..3141255f72c22a3e1efda1a9e78503952349074f 100644 (file)
 
        i2c0_pins: pinmux_i2c0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_sda.i2c0_sda */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_scl.i2c0_scl */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        i2c1_pins: pinmux_i2c1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE2)       /* spi0_d1.i2c1_sda */
-                       AM33XX_IOPAD(0x95c, PIN_INPUT_PULLUP | MUX_MODE2)       /* spi0_cs0.i2c1_scl */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D1, PIN_INPUT_PULLUP, MUX_MODE2) /* spi0_d1.i2c1_sda */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_INPUT_PULLUP, MUX_MODE2)        /* spi0_cs0.i2c1_scl */
                >;
        };
 
        i2c2_pins: pinmux_i2c2_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE2)       /* spi0_clk.i2c2_sda */
-                       AM33XX_IOPAD(0x954, PIN_INPUT_PULLUP | MUX_MODE2)       /* spi0_d0.i2c2_scl */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT_PULLUP, MUX_MODE2)       /* spi0_clk.i2c2_sda */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_INPUT_PULLUP, MUX_MODE2) /* spi0_d0.i2c2_scl */
                >;
        };
 
        spi1_pins: pinmux_spi1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x990, PIN_OUTPUT | MUX_MODE3)             /* mcasp0_aclkx.spi1_sclk */
-                       AM33XX_IOPAD(0x994, PIN_OUTPUT | MUX_MODE3)             /* mcasp0_fsx.spi1_d0 */
-                       AM33XX_IOPAD(0x998, PIN_INPUT_PULLDOWN | MUX_MODE3)     /* mcasp0_axr0.spi1_d1 */
-                       AM33XX_IOPAD(0x99C, PIN_OUTPUT | MUX_MODE3)             /* mcasp0_ahclkr.spi1_cs0 */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_OUTPUT, MUX_MODE3)          /* mcasp0_aclkx.spi1_sclk */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_OUTPUT, MUX_MODE3)            /* mcasp0_fsx.spi1_d0 */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AXR0, PIN_INPUT_PULLDOWN, MUX_MODE3)   /* mcasp0_axr0.spi1_d1 */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKR, PIN_OUTPUT, MUX_MODE3)         /* mcasp0_ahclkr.spi1_cs0 */
                >;
        };
 
        uart0_pins: pinmux_uart0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x96C, PIN_OUTPUT | MUX_MODE7)             /* uart0_rtsn.gpio1_9 */
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        uart1_pins: pinmux_uart1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart1_rxd.uart1_rxd */
-                       AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart1_txd.uart1_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        uart3_pins: pinmux_uart3_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x960, PIN_INPUT_PULLUP | MUX_MODE1)       /* spi0_cs1.uart3_rxd */
-                       AM33XX_IOPAD(0x964, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* ecap0_in_pwm0_out.uart3_txd */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT_PULLUP, MUX_MODE1)        /* spi0_cs1.uart3_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_ECAP0_IN_PWM0_OUT, PIN_OUTPUT_PULLDOWN, MUX_MODE1)    /* ecap0_in_pwm0_out.uart3_txd */
                >;
        };
 
        clkout2_pin: pinmux_clkout2_pin {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9b4, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* xdma_event_intr1.clkout2 */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_OUTPUT_PULLDOWN, MUX_MODE3)     /* xdma_event_intr1.clkout2 */
                >;
        };
 
        cpsw_default: cpsw_default {
                pinctrl-single,pins = <
                        /* Port 1 (emac0) */
-                       AM33XX_IOPAD(0x908, PIN_INPUT | MUX_MODE0)              /* mii1_col.mii1_col */
-                       AM33XX_IOPAD(0x90C, PIN_INPUT | MUX_MODE0)              /* mii1_crs.mii1_crs */
-                       AM33XX_IOPAD(0x910, PIN_INPUT | MUX_MODE0)              /* mii1_rxer.mii1_rxer */
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT | MUX_MODE0)             /* mii1_txen.mii1_txen */
-                       AM33XX_IOPAD(0x918, PIN_INPUT | MUX_MODE0)              /* mii1_rxdv.mii1_rxdv */
-                       AM33XX_IOPAD(0x91c, PIN_OUTPUT | MUX_MODE0)             /* mii1_txd3.mii1_txd3 */
-                       AM33XX_IOPAD(0x920, PIN_OUTPUT | MUX_MODE0)             /* mii1_txd2.mii1_txd2 */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT | MUX_MODE0)             /* mii1_txd1.mii1_txd1 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT | MUX_MODE0)             /* mii1_txd0.mii1_txd0 */
-                       AM33XX_IOPAD(0x92c, PIN_INPUT | MUX_MODE0)              /* mii1_txclk.mii1_txclk */
-                       AM33XX_IOPAD(0x930, PIN_INPUT | MUX_MODE0)              /* mii1_rxclk.mii1_rxclk */
-                       AM33XX_IOPAD(0x934, PIN_INPUT | MUX_MODE0)              /* mii1_rxd3.mii1_rxd3 */
-                       AM33XX_IOPAD(0x938, PIN_INPUT | MUX_MODE0)              /* mii1_rxd2.mii1_rxd2 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT | MUX_MODE0)              /* mii1_rxd1.mii1_rxd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT | MUX_MODE0)              /* mii1_rxd0.mii1_rxd0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT, MUX_MODE0)
 
                        /* Port 2 (emac1) */
-                       AM33XX_IOPAD(0x840, PIN_OUTPUT | MUX_MODE1)             /* mii2_txen.gpmc_a0 */
-                       AM33XX_IOPAD(0x844, PIN_INPUT | MUX_MODE1)              /* mii2_rxdv.gpmc_a1 */
-                       AM33XX_IOPAD(0x848, PIN_OUTPUT | MUX_MODE1)             /* mii2_txd3.gpmc_a2 */
-                       AM33XX_IOPAD(0x84c, PIN_OUTPUT | MUX_MODE1)             /* mii2_txd2.gpmc_a3 */
-                       AM33XX_IOPAD(0x850, PIN_OUTPUT | MUX_MODE1)             /* mii2_txd1.gpmc_a4 */
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT | MUX_MODE1)             /* mii2_txd0.gpmc_a5 */
-                       AM33XX_IOPAD(0x858, PIN_INPUT | MUX_MODE1)              /* mii2_txclk.gpmc_a6 */
-                       AM33XX_IOPAD(0x85c, PIN_INPUT | MUX_MODE1)              /* mii2_rxclk.gpmc_a7 */
-                       AM33XX_IOPAD(0x860, PIN_INPUT | MUX_MODE1)              /* mii2_rxd3.gpmc_a8 */
-                       AM33XX_IOPAD(0x864, PIN_INPUT | MUX_MODE1)              /* mii2_rxd2.gpmc_a9 */
-                       AM33XX_IOPAD(0x868, PIN_INPUT | MUX_MODE1)              /* mii2_rxd1.gpmc_a10 */
-                       AM33XX_IOPAD(0x86C, PIN_INPUT | MUX_MODE1)              /* mii2_rxd0.gpmc_a11 */
-                       AM33XX_IOPAD(0x870, PIN_INPUT | MUX_MODE1)              /* mii2_crs.gpmc_wait0 */
-                       AM33XX_IOPAD(0x874, PIN_INPUT | MUX_MODE1)              /* mii2_rxer.gpmc_wpn */
-                       AM33XX_IOPAD(0x878, PIN_INPUT | MUX_MODE1)              /* mii2_col.gpmc_ben1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_OUTPUT, MUX_MODE1)               /* mii2_txen.gpmc_a0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A1, PIN_INPUT, MUX_MODE1)                /* mii2_rxdv.gpmc_a1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_OUTPUT, MUX_MODE1)               /* mii2_txd3.gpmc_a2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A3, PIN_OUTPUT, MUX_MODE1)               /* mii2_txd2.gpmc_a3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_OUTPUT, MUX_MODE1)               /* mii2_txd1.gpmc_a4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT, MUX_MODE1)               /* mii2_txd0.gpmc_a5 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_INPUT, MUX_MODE1)                /* mii2_txclk.gpmc_a6 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_INPUT, MUX_MODE1)                /* mii2_rxclk.gpmc_a7 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_INPUT, MUX_MODE1)                /* mii2_rxd3.gpmc_a8 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A9, PIN_INPUT, MUX_MODE1)                /* mii2_rxd2.gpmc_a9 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT, MUX_MODE1)               /* mii2_rxd1.gpmc_a10 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT, MUX_MODE1)               /* mii2_rxd0.gpmc_a11 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT, MUX_MODE1)             /* mii2_crs.gpmc_wait0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_INPUT, MUX_MODE1)               /* mii2_rxer.gpmc_wpn */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_INPUT, MUX_MODE1)              /* mii2_col.gpmc_ben1 */
                >;
        };
 
        davinci_mdio_default: davinci_mdio_default {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)                      /* mdio_clk.mdio_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        mmc1_pins: pinmux_mmc1_pins {
                /* eMMC */
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat3 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat2 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat1 */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat0 */
-                       AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_clk */
-                       AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        mmc2_pins: pinmux_mmc2_pins {
                /* SD cardcage */
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad3.mmc1_dat3 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad2.mmc1_dat2 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad1.mmc1_dat1 */
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad0.mmc1_dat0 */
-                       AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2)       /* gpmc_csn1.mmc1_clk */
-                       AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2)       /* gpmc_csn2.mmc1_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad3.mmc1_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad2.mmc1_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad1.mmc1_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad0.mmc1_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_INPUT_PULLUP, MUX_MODE2)       /* gpmc_csn1.mmc1_clk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_INPUT_PULLUP, MUX_MODE2)       /* gpmc_csn2.mmc1_cmd */
                        /* card change signal for frontpanel SD cardcage */
-                       AM33XX_IOPAD(0x890, PIN_INPUT | MUX_MODE7)              /* gpmc_advn_ale.gpio2_2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_ADVN_ALE, PIN_INPUT, MUX_MODE7)          /* gpmc_advn_ale.gpio2_2 */
                >;
        };
 
        lcd_pins_s0: lcd_pins_s0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data0.lcd_data0 */
-                       AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data1.lcd_data1 */
-                       AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data2.lcd_data2 */
-                       AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)             /* lcd_data3.lcd_data3 */
-                       AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data4.lcd_data4 */
-                       AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data5.lcd_data5 */
-                       AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data6.lcd_data6 */
-                       AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)             /* lcd_data7.lcd_data7 */
-                       AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data8.lcd_data8 */
-                       AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data9.lcd_data9 */
-                       AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data10.lcd_data10 */
-                       AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)             /* lcd_data11.lcd_data11 */
-                       AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)             /* lcd_data12.lcd_data12 */
-                       AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)             /* lcd_data13.lcd_data13 */
-                       AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)             /* lcd_data14.lcd_data14 */
-                       AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)             /* lcd_data15.lcd_data15 */
-                       AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE0)             /* lcd_vsync.lcd_vsync */
-                       AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE0)             /* lcd_hsync.lcd_hsync */
-                       AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE0)             /* lcd_pclk.lcd_pclk */
-                       AM33XX_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE0)             /* lcd_ac_bias_en.lcd_ac_bias_en */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT, MUX_MODE0)
                >;
        };
 
        dcan0_pins: pinmux_dcan0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x978, PIN_OUTPUT | MUX_MODE2)             /* uart1_ctsn.d_can0_tx */
-                       AM33XX_IOPAD(0x97c, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* uart1_rtsn.d_can0_rx */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_OUTPUT, MUX_MODE2)            /* uart1_ctsn.d_can0_tx */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_INPUT_PULLDOWN, MUX_MODE2)    /* uart1_rtsn.d_can0_rx */
                >;
        };
 };
index 6be79b8349ac88547e415a796cdc6a5e769a766c..5c3e49f93ac42582cab745edc5c40d53b6f3bf5c 100644 (file)
 &am33xx_pinmux {
        i2c0_pins: pinmux_i2c0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_sda.i2c0_sda */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_scl.i2c0_scl */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
        i2c1_pins: pinmux_i2c1 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x90C, PIN_INPUT_PULLUP | MUX_MODE3)       /* mii1_crs,i2c1_sda */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLUP | MUX_MODE3)       /* mii1_rxerr,i2c1_scl */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLUP, MUX_MODE3)        /* mii1_crs,i2c1_sda */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLUP, MUX_MODE3)      /* mii1_rxerr,i2c1_scl */
                >;
        };
 };
 &am33xx_pinmux {
        accel_pins: pinmux_accel {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x898, PIN_INPUT | MUX_MODE7)   /* gpmc_wen.gpio2_4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WEN, PIN_INPUT, MUX_MODE7)   /* gpmc_wen.gpio2_4 */
                >;
        };
 };
 &am33xx_pinmux {
        audio_pins: pinmux_audio {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9ac, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* mcasp0_ahcklx.mcasp0_ahclkx */
-                       AM33XX_IOPAD(0x994, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* mcasp0_fsx.mcasp0_fsx */
-                       AM33XX_IOPAD(0x990, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* mcasp0_aclkx.mcasp0_aclkx */
-                       AM33XX_IOPAD(0x998, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* mcasp0_axr0.mcasp0_axr0 */
-                       AM33XX_IOPAD(0x9a8, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* mcasp0_axr1.mcasp0_axr1 */
-                       AM33XX_IOPAD(0x840, PIN_OUTPUT | MUX_MODE7)     /* gpmc_a0.gpio1_16 */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKX, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AXR0, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AXR1, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_OUTPUT, MUX_MODE7)       /* gpmc_a0.gpio1_16 */
                >;
        };
 };
 &am33xx_pinmux {
        lcd_pins: pinmux_lcd {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data0.lcd_data0 */
-                       AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data1.lcd_data1 */
-                       AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data2.lcd_data2 */
-                       AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)     /* lcd_data3.lcd_data3 */
-                       AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data4.lcd_data4 */
-                       AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data5.lcd_data5 */
-                       AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data6.lcd_data6 */
-                       AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)     /* lcd_data7.lcd_data7 */
-                       AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data8.lcd_data8 */
-                       AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data9.lcd_data9 */
-                       AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data10.lcd_data10 */
-                       AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)     /* lcd_data11.lcd_data11 */
-                       AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data12.lcd_data12 */
-                       AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data13.lcd_data13 */
-                       AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data14.lcd_data14 */
-                       AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)     /* lcd_data15.lcd_data15 */
-                       AM33XX_IOPAD(0x820, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad8.lcd_data16 */
-                       AM33XX_IOPAD(0x824, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad9.lcd_data17 */
-                       AM33XX_IOPAD(0x828, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad10.lcd_data18 */
-                       AM33XX_IOPAD(0x82c, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad11.lcd_data19 */
-                       AM33XX_IOPAD(0x830, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad12.lcd_data20 */
-                       AM33XX_IOPAD(0x834, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad13.lcd_data21 */
-                       AM33XX_IOPAD(0x838, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad14.lcd_data22 */
-                       AM33XX_IOPAD(0x83c, PIN_OUTPUT | MUX_MODE1)     /* gpmc_ad15.lcd_data23 */
-                       AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE0)     /* lcd_vsync.lcd_vsync */
-                       AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE0)     /* lcd_hsync.lcd_hsync */
-                       AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE0)     /* lcd_pclk.lcd_pclk */
-                       AM33XX_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE0)     /* lcd_ac_bias_en.lcd_ac_bias_en */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD8, PIN_OUTPUT, MUX_MODE1)      /* gpmc_ad8.lcd_data16 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD9, PIN_OUTPUT, MUX_MODE1)      /* gpmc_ad9.lcd_data17 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_OUTPUT, MUX_MODE1)     /* gpmc_ad10.lcd_data18 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_OUTPUT, MUX_MODE1)     /* gpmc_ad11.lcd_data19 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_OUTPUT, MUX_MODE1)     /* gpmc_ad12.lcd_data20 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_OUTPUT, MUX_MODE1)     /* gpmc_ad13.lcd_data21 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_OUTPUT, MUX_MODE1)     /* gpmc_ad14.lcd_data22 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_OUTPUT, MUX_MODE1)     /* gpmc_ad15.lcd_data23 */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT, MUX_MODE0)
                        /* Display Enable */
-                       AM33XX_IOPAD(0x86c, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* gpmc_a11.gpio1_27 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_OUTPUT_PULLUP, MUX_MODE7)       /* gpmc_a11.gpio1_27 */
                >;
        };
 };
 &am33xx_pinmux {
        ethernet_pins: pinmux_ethernet {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txen.rgmii1_tctl */
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLUP | MUX_MODE2)       /* mii1_rxdv.rgmii1_rctl */
-                       AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd3.rgmii1_td3 */
-                       AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd2.rgmii1_td2 */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd1.rgmii1_td1 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd0.rgmii1_td0 */
-                       AM33XX_IOPAD(0x92c, PIN_INPUT_PULLUP | MUX_MODE2)       /* mii1_txclk.rgmii1_tclk */
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLUP | MUX_MODE2)       /* mii1_rxclk.rgmii1_rclk */
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLUP | MUX_MODE2)       /* mii1_rxd3.rgmii1_rxd3 */
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLUP | MUX_MODE2)       /* mii1_rxd2.rgmii1_rxd2 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLUP | MUX_MODE2)       /* mii1_rxd1.rgmii1_rxd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLUP | MUX_MODE2)       /* mii1_rxd0.rgmii1_rxd0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE2)   /* mii1_txen.rgmii1_tctl */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLUP, MUX_MODE2)      /* mii1_rxdv.rgmii1_rctl */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd3.rgmii1_td3 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd2.rgmii1_td2 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd1.rgmii1_td1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd0.rgmii1_td0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT_PULLUP, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLUP, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLUP, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLUP, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLUP, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLUP, MUX_MODE2)
                        /* ethernet interrupt */
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLUP | MUX_MODE7)       /* rmii2_refclk.gpio0_29 */
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLUP, MUX_MODE7)   /* rmii2_refclk.gpio0_29 */
                        /* ethernet PHY nReset */
-                       AM33XX_IOPAD(0x908, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* mii1_col.gpio3_0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_COL, PIN_OUTPUT_PULLUP, MUX_MODE7)       /* mii1_col.gpio3_0 */
                >;
        };
 
        mdio_pins: pinmux_mdio {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)                      /* mdio_clk.mdio_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 };
 &am33xx_pinmux {
        sd_pins: pinmux_sd_card {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat0.mmc0_dat0 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat1.mmc0_dat1 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat2.mmc0_dat2 */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat3.mmc0_dat3 */
-                       AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_clk.mmc0_clk */
-                       AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_cmd.mmc0_cmd */
-                       AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7)              /* spi0_cs1.gpio0_6 */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT, MUX_MODE7)               /* spi0_cs1.gpio0_6 */
                >;
        };
        emmc_pins: pinmux_emmc {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2)       /* gpmc_csn1.mmc1_clk */
-                       AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2)       /* gpmc_csn2.mmc1_cmd */
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad0.mmc1_dat0 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad1.mmc1_dat1 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad2.mmc1_dat2 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad3.mmc1_dat3 */
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad4.mmc1_dat4 */
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad5.mmc1_dat5 */
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad6.mmc1_dat6 */
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad7.mmc1_dat7 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_INPUT_PULLUP, MUX_MODE2)       /* gpmc_csn1.mmc1_clk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_INPUT_PULLUP, MUX_MODE2)       /* gpmc_csn2.mmc1_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad0.mmc1_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad1.mmc1_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad2.mmc1_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad3.mmc1_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad4.mmc1_dat4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad5.mmc1_dat5 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad6.mmc1_dat6 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad7.mmc1_dat7 */
                        /* EMMC nReset */
-                       AM33XX_IOPAD(0x874, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* gpmc_wpn.gpio0_31 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_OUTPUT_PULLUP, MUX_MODE7)       /* gpmc_wpn.gpio0_31 */
                >;
        };
        wireless_pins: pinmux_wireless {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x844, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_a1.mmc2_dat0 */
-                       AM33XX_IOPAD(0x848, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_a2.mmc2_dat1 */
-                       AM33XX_IOPAD(0x84c, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_a3.mmc2_dat2 */
-                       AM33XX_IOPAD(0x878, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_ben1.mmc2_dat3 */
-                       AM33XX_IOPAD(0x888, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_csn3.mmc2_cmd */
-                       AM33XX_IOPAD(0x88c, PIN_INPUT_PULLUP | MUX_MODE3)       /* gpmc_clk.mmc1_clk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A1, PIN_INPUT_PULLUP, MUX_MODE3) /* gpmc_a1.mmc2_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_INPUT_PULLUP, MUX_MODE3) /* gpmc_a2.mmc2_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A3, PIN_INPUT_PULLUP, MUX_MODE3) /* gpmc_a3.mmc2_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_ben1.mmc2_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN3, PIN_INPUT_PULLUP, MUX_MODE3)       /* gpmc_csn3.mmc2_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CLK, PIN_INPUT_PULLUP, MUX_MODE3)        /* gpmc_clk.mmc1_clk */
                        /* WLAN nReset */
-                       AM33XX_IOPAD(0x860, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* gpmc_a8.gpio1_24 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_OUTPUT_PULLUP, MUX_MODE7)        /* gpmc_a8.gpio1_24 */
                        /* WLAN nPower down */
-                       AM33XX_IOPAD(0x870, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* gpmc_wait0.gpio0_30 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_OUTPUT_PULLUP, MUX_MODE7)     /* gpmc_wait0.gpio0_30 */
                        /* 32kHz Clock */
-                       AM33XX_IOPAD(0x9b4, PIN_OUTPUT_PULLDOWN | MUX_MODE3)    /* xdma_event_intr1.clkout2 */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_OUTPUT_PULLDOWN, MUX_MODE3)     /* xdma_event_intr1.clkout2 */
                >;
        };
 };
 &am33xx_pinmux {
        spi0_pins: pinmux_spi0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_sclk.spi0_sclk */
-                       AM33XX_IOPAD(0x95C, PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_cs0.spi0_cs0 */
-                       AM33XX_IOPAD(0x954, PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_d0.spi0_d0 */
-                       AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE0) /* spi0_d1.spi0_d1 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D1, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 };
 &am33xx_pinmux {
        uart0_pins: pinmux_uart0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
        uart1_pins: pinmux_uart1 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x978, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart1_ctsn.uart1_ctsn */
-                       AM33XX_IOPAD(0x97C, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart1_rtsn.uart1_rtsn */
-                       AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart1_rxd.uart1_rxd */
-                       AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart1_txd.uart1_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 };
        usb_pins: pinmux_usb {
                pinctrl-single,pins = <
                        /* USB0 Over-Current (active low) */
-                       AM33XX_IOPAD(0x864, PIN_INPUT | MUX_MODE7)      /* gpmc_a9.gpio1_25 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A9, PIN_INPUT, MUX_MODE7)        /* gpmc_a9.gpio1_25 */
                        /* USB1 Over-Current (active low) */
-                       AM33XX_IOPAD(0x868, PIN_INPUT | MUX_MODE7)      /* gpmc_a10.gpio1_26 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT, MUX_MODE7)       /* gpmc_a10.gpio1_26 */
                >;
        };
 };
 &am33xx_pinmux {
        user_leds_pins: pinmux_user_leds {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x850, PIN_OUTPUT | MUX_MODE7)     /* gpmc_a4.gpio1_20 */
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT | MUX_MODE7)     /* gpmc_a5.gpio1_21 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_OUTPUT, MUX_MODE7)       /* gpmc_a4.gpio1_20 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT, MUX_MODE7)       /* gpmc_a5.gpio1_21 */
                >;
        };
 
        user_buttons_pins: pinmux_user_buttons {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x858, PIN_INPUT_PULLUP | MUX_MODE7)       /* gpmc_a6.gpio1_22 */
-                       AM33XX_IOPAD(0x85C, PIN_INPUT_PULLUP | MUX_MODE7)       /* gpmc_a7.gpio1_21 */
-                       AM33XX_IOPAD(0x964, PIN_INPUT_PULLUP | MUX_MODE7)       /* gpmc_a8.gpio0_7 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_INPUT_PULLUP, MUX_MODE7) /* gpmc_a6.gpio1_22 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_INPUT_PULLUP, MUX_MODE7) /* gpmc_a7.gpio1_21 */
+                       AM33XX_PADCONF(AM335X_PIN_ECAP0_IN_PWM0_OUT, PIN_INPUT_PULLUP, MUX_MODE7)       /* gpmc_a8.gpio0_7 */
                >;
        };
 };
index 015adb626b0369715d1a7b30548bbdf373ee1cd9..23c3039c567efdc3cecfb37b6c82a22619ce2350 100644 (file)
 &am33xx_pinmux {
        ethernet0_pins: pinmux_ethernet0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* mii1_crs.rmii1_crs_dv */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* mii1_rxerr.rmii1_rxerr */
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT | MUX_MODE1)             /* mii1_txen.rmii1_txen */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT | MUX_MODE1)             /* mii1_txd1.rmii1_txd1 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT | MUX_MODE1)             /* mii1_txd0.rmii1_txd0 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* mii1_rxd1.rmii1_rxd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* mii1_rxd0.rmii1_rxd0 */
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* rmii1_refclk.rmii1_refclk */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_CRS, PIN_INPUT_PULLDOWN, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        mdio_pins: pinmux_mdio {
                pinctrl-single,pins = <
                        /* MDIO */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)                      /* mdio_clk.mdio_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 };
 &am33xx_pinmux {
        i2c0_pins: pinmux_i2c0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT | MUX_MODE0)      /* i2c0_sda.i2c0_sda */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT | MUX_MODE0)      /* i2c0_scl.i2c0_scl */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT, MUX_MODE0)
                >;
        };
 };
 &am33xx_pinmux {
                nandflash_pins: pinmux_nandflash {
                        pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad0.gpmc_ad0 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad1.gpmc_ad1 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad2.gpmc_ad2 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad3.gpmc_ad3 */
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad4.gpmc_ad4 */
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad5.gpmc_ad5 */
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad6.gpmc_ad6 */
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_ad7.gpmc_ad7 */
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0)       /* gpmc_wait0.gpmc_wait0 */
-                       AM33XX_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE0)             /* gpmc_csn0.gpmc_csn0 */
-                       AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE0)             /* gpmc_advn_ale.gpmc_advn_ale */
-                       AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE0)             /* gpmc_oen_ren.gpmc_oen_ren */
-                       AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE0)             /* gpmc_wen.gpmc_wen */
-                       AM33XX_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE0)             /* gpmc_be0n_cle.gpmc_be0n_cle */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_ADVN_ALE, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_OEN_REN, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WEN, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN0_CLE, PIN_OUTPUT, MUX_MODE0)
                >;
        };
 };
 &am33xx_pinmux {
        spi0_pins: pinmux_spi0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x950, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* spi0_clk.spi0_clk */
-                       AM33XX_IOPAD(0x954, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* spi0_d0.spi0_d0 */
-                       AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE0)       /* spi0_d1.spi0_d1 */
-                       AM33XX_IOPAD(0x95c, PIN_INPUT_PULLUP | MUX_MODE0)       /* spi0_cs0.spi0_cs0 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 };
index 62fe5cab9fae564c36788245b89643e6dc17a2ec..ff4f919d22f627e305a4201b173622bda835418d 100644 (file)
 &am33xx_pinmux {
        i2c2_pins: pinmux-i2c2-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x97c, PIN_INPUT_PULLUP | MUX_MODE3)       /* (D17) uart1_rtsn.I2C2_SCL */
-                       AM33XX_IOPAD(0x978, PIN_INPUT_PULLUP | MUX_MODE3)       /* (D18) uart1_ctsn.I2C2_SDA */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_INPUT_PULLUP, MUX_MODE3)      /* (D17) uart1_rtsn.I2C2_SCL */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT_PULLUP, MUX_MODE3)      /* (D18) uart1_ctsn.I2C2_SDA */
                >;
        };
 
        ehrpwm0_pins: pinmux-ehrpwm0-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x990, PIN_OUTPUT_PULLDOWN | MUX_MODE1)    /* (A13) mcasp0_aclkx.ehrpwm0A */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_OUTPUT_PULLDOWN, MUX_MODE1) /* (A13) mcasp0_aclkx.ehrpwm0A */
                >;
        };
 
        ehrpwm1_pins: pinmux-ehrpwm1-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x848, PIN_OUTPUT_PULLDOWN | MUX_MODE6)    /* (U14) gpmc_a2.ehrpwm1A */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_OUTPUT_PULLDOWN, MUX_MODE6)      /* (U14) gpmc_a2.ehrpwm1A */
                >;
        };
 
        mmc0_pins: pinmux-mmc0-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7)              /* (C15) spi0_cs1.gpio0[6] */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)       /* (G16) mmc0_dat0.mmc0_dat0 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)       /* (G15) mmc0_dat1.mmc0_dat1 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)       /* (F18) mmc0_dat2.mmc0_dat2 */
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)       /* (F17) mmc0_dat3.mmc0_dat3 */
-                       AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)       /* (G18) mmc0_cmd.mmc0_cmd */
-                       AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)       /* (G17) mmc0_clk.mmc0_clk */
-                       AM33XX_IOPAD(0x9a0, PIN_INPUT | MUX_MODE4)              /* (B12) mcasp0_aclkr.mmc0_sdwp */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT, MUX_MODE7)               /* (C15) spi0_cs1.gpio0[6] */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKR, PIN_INPUT, MUX_MODE4)           /* (B12) mcasp0_aclkr.mmc0_sdwp */
                >;
        };
 
        spi0_pins: pinmux-spi0-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE0)       /* (A17) spi0_sclk.spi0_sclk */
-                       AM33XX_IOPAD(0x954, PIN_INPUT_PULLUP | MUX_MODE0)       /* (B17) spi0_d0.spi0_d0 */
-                       AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE0)       /* (B16) spi0_d1.spi0_d1 */
-                       AM33XX_IOPAD(0x95c, PIN_INPUT_PULLUP | MUX_MODE0)       /* (A16) spi0_cs0.spi0_cs0 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        spi1_pins: pinmux-spi1-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x964, PIN_INPUT_PULLUP | MUX_MODE4)       /* (C18) eCAP0_in_PWM0_out.spi1_sclk */
-                       AM33XX_IOPAD(0x968, PIN_INPUT_PULLUP | MUX_MODE4)       /* (E18) uart0_ctsn.spi1_d0 */
-                       AM33XX_IOPAD(0x96c, PIN_INPUT_PULLUP | MUX_MODE4)       /* (E17) uart0_rtsn.spi1_d1 */
-                       AM33XX_IOPAD(0x9b0, PIN_INPUT_PULLUP | MUX_MODE4)       /* (A15) xdma_event_intr0.spi1_cs1 */
+                       AM33XX_PADCONF(AM335X_PIN_ECAP0_IN_PWM0_OUT, PIN_INPUT_PULLUP, MUX_MODE4)       /* (C18) eCAP0_in_PWM0_out.spi1_sclk */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_CTSN, PIN_INPUT_PULLUP, MUX_MODE4)      /* (E18) uart0_ctsn.spi1_d0 */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_INPUT_PULLUP, MUX_MODE4)      /* (E17) uart0_rtsn.spi1_d1 */
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR0, PIN_INPUT_PULLUP, MUX_MODE4)        /* (A15) xdma_event_intr0.spi1_cs1 */
                >;
        };
 
        usr_leds_pins: pinmux-usr-leds-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT | MUX_MODE7)             /* (V15) gpmc_a5.gpio1[21] - USR_LED_0 */
-                       AM33XX_IOPAD(0x858, PIN_OUTPUT | MUX_MODE7)             /* (U15) gpmc_a6.gpio1[22] - USR_LED_1 */
-                       AM33XX_IOPAD(0x85c, PIN_OUTPUT | MUX_MODE7)             /* (T15) gpmc_a7.gpio1[23] - USR_LED_2 */
-                       AM33XX_IOPAD(0x860, PIN_OUTPUT | MUX_MODE7)             /* (V16) gpmc_a8.gpio1[24] - USR_LED_3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT, MUX_MODE7)               /* (V15) gpmc_a5.gpio1[21] - USR_LED_0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_OUTPUT, MUX_MODE7)               /* (U15) gpmc_a6.gpio1[22] - USR_LED_1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_OUTPUT, MUX_MODE7)               /* (T15) gpmc_a7.gpio1[23] - USR_LED_2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_OUTPUT, MUX_MODE7)               /* (V16) gpmc_a8.gpio1[24] - USR_LED_3 */
                >;
        };
 
        uart0_pins: pinmux-uart0-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* (E15) uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* (E16) uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        uart4_pins: pinmux-uart4-pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE6)       /* (T17) gpmc_wait0.uart4_rxd */
-                       AM33XX_IOPAD(0x874, PIN_OUTPUT_PULLDOWN | MUX_MODE6)    /* (U17) gpmc_wpn.uart4_txd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLUP, MUX_MODE6)      /* (T17) gpmc_wait0.uart4_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_OUTPUT_PULLDOWN, MUX_MODE6)     /* (U17) gpmc_wpn.uart4_txd */
                >;
        };
 };
index 35527fdf56cc8896178b055ebee6f63e6cad6845..7ed27b5c4756505994e4ae107a3d05fedd810337 100644 (file)
        cpsw_default: cpsw_default {
                pinctrl-single,pins = <
                        /* Slave 1 */
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txen.rgmii1_tctl */
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxdv.rgmii1_rctl */
-                       AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd3.rgmii1_td3 */
-                       AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd2.rgmii1_td2 */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd1.rgmii1_td1 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txd0.rgmii1_td0 */
-                       AM33XX_IOPAD(0x92c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mii1_txclk.rgmii1_tclk */
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxclk.rgmii1_rclk */
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxd3.rgmii1_rd3 */
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxd2.rgmii1_rd2 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxd1.rgmii1_rd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE2)     /* mii1_rxd0.rgmii1_rd0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE2)   /* mii1_txen.rgmii1_tctl */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE2)    /* mii1_rxdv.rgmii1_rctl */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd3.rgmii1_td3 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd2.rgmii1_td2 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd1.rgmii1_td1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE2)    /* mii1_txd0.rgmii1_td0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_OUTPUT_PULLDOWN, MUX_MODE2)  /* mii1_txclk.rgmii1_tclk */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE2)   /* mii1_rxclk.rgmii1_rclk */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLDOWN, MUX_MODE2)     /* mii1_rxd3.rgmii1_rd3 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLDOWN, MUX_MODE2)     /* mii1_rxd2.rgmii1_rd2 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE2)     /* mii1_rxd1.rgmii1_rd1 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE2)     /* mii1_rxd0.rgmii1_rd0 */
                >;
        };
 
        cpsw_sleep: cpsw_sleep {
                pinctrl-single,pins = <
                        /* Slave 1 reset value */
-                       AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        davinci_mdio_default: davinci_mdio_default {
                pinctrl-single,pins = <
                        /* MDIO */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)                      /* mdio_clk.mdio_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        davinci_mdio_sleep: davinci_mdio_sleep {
                pinctrl-single,pins = <
                        /* MDIO reset value */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        usb_hub_ctrl: usb_hub_ctrl {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x944, PIN_OUTPUT_PULLUP | MUX_MODE7)     /* rmii1_refclk.gpio0_29 */
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_OUTPUT_PULLUP, MUX_MODE7)     /* rmii1_refclk.gpio0_29 */
                >;
        };
 
        mpu6050_pins: pinmux_mpu6050_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x968, PIN_INPUT | MUX_MODE7)    /* uart0_ctsn.gpio1_8 */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_CTSN, PIN_INPUT, MUX_MODE7)    /* uart0_ctsn.gpio1_8 */
                >;
        };
 
        lps3331ap_pins: pinmux_lps3331ap_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x868, PIN_INPUT | MUX_MODE7)     /* gpmc_a10.gpio1_26 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT, MUX_MODE7)     /* gpmc_a10.gpio1_26 */
                >;
        };
 };
index 917d7ccc9109e2038fc137ae9856d4e51a0291fa..07c46a59f1d2d6e88552e2dcfe50351eb39bca80 100644 (file)
        lcd_pins_default: lcd_pins_default {
                pinctrl-single,pins = <
                        /* gpmc_ad8.lcd_data23 */
-                       AM33XX_IOPAD(0x820, PIN_OUTPUT | MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD8, PIN_OUTPUT, MUX_MODE1)
                        /* gpmc_ad9.lcd_data22 */
-                       AM33XX_IOPAD(0x824, PIN_OUTPUT | MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD9, PIN_OUTPUT, MUX_MODE1)
                        /* gpmc_ad10.lcd_data21 */
-                       AM33XX_IOPAD(0x828, PIN_OUTPUT | MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_OUTPUT, MUX_MODE1)
                        /* gpmc_ad11.lcd_data20 */
-                       AM33XX_IOPAD(0x82c, PIN_OUTPUT | MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_OUTPUT, MUX_MODE1)
                        /* gpmc_ad12.lcd_data19 */
-                       AM33XX_IOPAD(0x830, PIN_OUTPUT | MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_OUTPUT, MUX_MODE1)
                        /* gpmc_ad13.lcd_data18 */
-                       AM33XX_IOPAD(0x834, PIN_OUTPUT | MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_OUTPUT, MUX_MODE1)
                        /* gpmc_ad14.lcd_data17 */
-                       AM33XX_IOPAD(0x838, PIN_OUTPUT | MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_OUTPUT, MUX_MODE1)
                        /* gpmc_ad15.lcd_data16 */
-                       AM33XX_IOPAD(0x83c, PIN_OUTPUT | MUX_MODE1)
-                       /* lcd_data0.lcd_data0 */
-                       AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data1.lcd_data1 */
-                       AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data2.lcd_data2 */
-                       AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data3.lcd_data3 */
-                       AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data4.lcd_data4 */
-                       AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data5.lcd_data5 */
-                       AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data6.lcd_data6 */
-                       AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data7.lcd_data7 */
-                       AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data8.lcd_data8 */
-                       AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data9.lcd_data9 */
-                       AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data10.lcd_data10 */
-                       AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data11.lcd_data11 */
-                       AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data12.lcd_data12 */
-                       AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data13.lcd_data13 */
-                       AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data14.lcd_data14 */
-                       AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_data15.lcd_data15 */
-                       AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_vsync.lcd_vsync */
-                       AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_hsync.lcd_hsync */
-                       AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_pclk.lcd_pclk */
-                       AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE0)
-                       /* lcd_ac_bias_en.lcd_ac_bias_en */
-                       AM33XX_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_OUTPUT, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT, MUX_MODE0)
                >;
        };
 
        lcd_pins_sleep: lcd_pins_sleep {
                pinctrl-single,pins = <
                        /* gpmc_ad8.lcd_data23 */
-                       AM33XX_IOPAD(0x820, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD8, PIN_INPUT_PULLDOWN, MUX_MODE7)
                        /* gpmc_ad9.lcd_data22 */
-                       AM33XX_IOPAD(0x824, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD9, PIN_INPUT_PULLDOWN, MUX_MODE7)
                        /* gpmc_ad10.lcd_data21 */
-                       AM33XX_IOPAD(0x828, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_INPUT_PULLDOWN, MUX_MODE7)
                        /* gpmc_ad11.lcd_data20 */
-                       AM33XX_IOPAD(0x82c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_INPUT_PULLDOWN, MUX_MODE7)
                        /* gpmc_ad12.lcd_data19 */
-                       AM33XX_IOPAD(0x830, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_INPUT_PULLDOWN, MUX_MODE7)
                        /* gpmc_ad13.lcd_data18 */
-                       AM33XX_IOPAD(0x834, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_INPUT_PULLDOWN, MUX_MODE7)
                        /* gpmc_ad14.lcd_data17 */
-                       AM33XX_IOPAD(0x838, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_INPUT_PULLDOWN, MUX_MODE7)
                        /* gpmc_ad15.lcd_data16 */
-                       AM33XX_IOPAD(0x83c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       /* lcd_data0.lcd_data0 */
-                       AM33XX_IOPAD(0x8a0, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data1.lcd_data1 */
-                       AM33XX_IOPAD(0x8a4, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data2.lcd_data2 */
-                       AM33XX_IOPAD(0x8a8, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data3.lcd_data3 */
-                       AM33XX_IOPAD(0x8ac, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data4.lcd_data4 */
-                       AM33XX_IOPAD(0x8b0, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data5.lcd_data5 */
-                       AM33XX_IOPAD(0x8b4, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data6.lcd_data6 */
-                       AM33XX_IOPAD(0x8b8, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data7.lcd_data7 */
-                       AM33XX_IOPAD(0x8bc, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data8.lcd_data8 */
-                       AM33XX_IOPAD(0x8c0, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data9.lcd_data9 */
-                       AM33XX_IOPAD(0x8c4, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data10.lcd_data10 */
-                       AM33XX_IOPAD(0x8c8, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data11.lcd_data11 */
-                       AM33XX_IOPAD(0x8cc, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data12.lcd_data12 */
-                       AM33XX_IOPAD(0x8d0, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data13.lcd_data13 */
-                       AM33XX_IOPAD(0x8d4, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data14.lcd_data14 */
-                       AM33XX_IOPAD(0x8d8, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_data15.lcd_data15 */
-                       AM33XX_IOPAD(0x8dc, PULL_DISABLE | MUX_MODE7)
-                       /* lcd_vsync.lcd_vsync */
-                       AM33XX_IOPAD(0x8e0, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       /* lcd_hsync.lcd_hsync */
-                       AM33XX_IOPAD(0x8e4, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       /* lcd_pclk.lcd_pclk */
-                       AM33XX_IOPAD(0x8e8, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       /* lcd_ac_bias_en.lcd_ac_bias_en */
-                       AM33XX_IOPAD(0x8ec, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PULL_DISABLE, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 };
index bfbe27a80006e6e4fa0b023b73a94eb3b02d5651..5b036850401571dbcddfcabab4a7ab58858554ab 100644 (file)
        clkout2_pin: pinmux_clkout2_pin {
                pinctrl-single,pins = <
                        /* xdma_event_intr1.clkout2 */
-                       AM33XX_IOPAD(0x9b4, PIN_INPUT | MUX_MODE6)
+                       AM33XX_PADCONF(AM335X_PIN_XDMA_EVENT_INTR1, PIN_INPUT, MUX_MODE6)
                >;
        };
 
        cpsw_default: cpsw_default {
                pinctrl-single,pins = <
                        /* Slave 1 */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE0)
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE0)
-                       AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
-                       AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE0)
-                       AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE0)
-                       AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE0)
-                       AM33XX_IOPAD(0x92c, PIN_INPUT_PULLUP | MUX_MODE0)
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE0)
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE0)
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE0)
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE0)
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        cpsw_sleep: cpsw_sleep {
                pinctrl-single,pins = <
                        /* Slave 1 reset value */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        davinci_mdio_default: davinci_mdio_default {
                pinctrl-single,pins = <
-                       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)
-                       /* mdio_clk.mdio_clk */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        davinci_mdio_sleep: davinci_mdio_sleep {
                pinctrl-single,pins = <
                        /* MDIO reset value */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        ehrpwm1_pins: pinmux_ehrpwm1 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x84c, PIN_OUTPUT | MUX_MODE6) /* gpmc_a3.gpio1_19 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A3, PIN_OUTPUT, MUX_MODE6) /* gpmc_a3.gpio1_19 */
                >;
        };
 
        emmc_pins: pinmux_emmc_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x880, PIN_INPUT | MUX_MODE2)
-                       AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2)
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1)
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1)
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1)
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1)
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1)
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1)
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1)
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_INPUT, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_INPUT_PULLUP, MUX_MODE2)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE1)
                >;
        };
 
        i2c0_pins: pinmux_i2c0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT | MUX_MODE0)
-                       AM33XX_IOPAD(0x98c, PIN_INPUT | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT, MUX_MODE0)
                >;
        };
 
        mmc1_pins: pinmux_mmc1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE5)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT, MUX_MODE5)
                >;
        };
 
        mmc3_pins: pinmux_mmc3_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x830, PIN_INPUT | MUX_MODE3)
-                       AM33XX_IOPAD(0x834, PIN_INPUT | MUX_MODE3)
-                       AM33XX_IOPAD(0x838, PIN_INPUT | MUX_MODE3)
-                       AM33XX_IOPAD(0x83c, PIN_INPUT | MUX_MODE3)
-                       AM33XX_IOPAD(0x888, PIN_INPUT | MUX_MODE3)
-                       AM33XX_IOPAD(0x88c, PIN_INPUT | MUX_MODE3)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_INPUT, MUX_MODE3)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_INPUT, MUX_MODE3)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_INPUT, MUX_MODE3)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT, MUX_MODE3)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN3, PIN_INPUT, MUX_MODE3)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CLK, PIN_INPUT, MUX_MODE3)
                >;
        };
 
        uart0_pins: pinmux_uart0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x968, PIN_INPUT_PULLDOWN | MUX_MODE0)
-                       AM33XX_IOPAD(0x96c, PIN_OUTPUT | MUX_MODE0)
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLDOWN | MUX_MODE0)
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_CTSN, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT, MUX_MODE0)
                >;
        };
 
        uart1_pins: pinmux_uart1 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x978, PIN_INPUT_PULLDOWN | MUX_MODE0)
-                       AM33XX_IOPAD(0x97C, PIN_OUTPUT | MUX_MODE0)
-                       AM33XX_IOPAD(0x980, PIN_INPUT | MUX_MODE0)
-                       AM33XX_IOPAD(0x984, PIN_OUTPUT | MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_OUTPUT, MUX_MODE0)
                >;
        };
 
        uart2_pins: pinmux_uart2_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x950, PIN_INPUT | MUX_MODE1)
-                       AM33XX_IOPAD(0x954, PIN_OUTPUT | MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT, MUX_MODE1)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_OUTPUT, MUX_MODE1)
                >;
        };
 
        uart4_pins: pinmux_uart4_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE6)
-                       AM33XX_IOPAD(0x874, PIN_OUTPUT_PULLUP | MUX_MODE6)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLUP, MUX_MODE6)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_OUTPUT_PULLUP, MUX_MODE6)
                >;
        };
 
        user_leds_s0: user_leds_s0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x820, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x824, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x828, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x82c, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x840, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x844, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x848, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x858, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x85c, PIN_OUTPUT_PULLUP | MUX_MODE7)
-                       AM33XX_IOPAD(0x860, PIN_INPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x864, PIN_INPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x868, PIN_INPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x86c, PIN_INPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x878, PIN_OUTPUT_PULLUP | MUX_MODE7)
-                       AM33XX_IOPAD(0x87c, PIN_INPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x894, PIN_INPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x958, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x95c, PIN_OUTPUT | MUX_MODE7)
-                       AM33XX_IOPAD(0x964, PIN_OUTPUT_PULLUP | MUX_MODE7)
-                       AM33XX_IOPAD(0x9a0, PIN_OUTPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x9a4, PIN_OUTPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x9a8, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x9ac, PIN_INPUT_PULLUP | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD8, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD9, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD11, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A1, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_OUTPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_OUTPUT_PULLUP, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_INPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A9, PIN_INPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_OUTPUT_PULLUP, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN0, PIN_INPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_ADVN_ALE, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_OEN_REN, PIN_INPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WEN, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN0_CLE, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_RMII1_REF_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D1, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_OUTPUT, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_ECAP0_IN_PWM0_OUT, PIN_OUTPUT_PULLUP, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKR, PIN_OUTPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_FSR, PIN_OUTPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AXR1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKX, PIN_INPUT_PULLUP, MUX_MODE7)
                >;
        };
 };
index 38d57b89f7d39a504644714735b46080ef990daf..1ac0c8aa98c5ce8176f91e123685cff7c2773c5c 100644 (file)
 
        audio_pins: pinmux_audio_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9ac, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* mcasp0_ahcklx.mcasp0_ahclkx */
-                       AM33XX_IOPAD(0x994, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* mcasp0_fsx.mcasp0_fsx */
-                       AM33XX_IOPAD(0x990, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* mcasp0_aclkx.mcasp0_aclkx */
-                       AM33XX_IOPAD(0x998, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* mcasp0_axr0.mcasp0_axr0 */
-                       AM33XX_IOPAD(0x99c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)    /* mcasp0_ahclkr.mcasp0_axr2 */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKX, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AXR0, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKR, PIN_OUTPUT_PULLDOWN, MUX_MODE2)
                >;
        };
 
        audio_pa_pins: pinmux_audio_pa_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9a0, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* SoundPA_en - mcasp0_aclkr.gpio3_18 */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKR, PIN_INPUT_PULLDOWN, MUX_MODE7)  /* SoundPA_en - mcasp0_aclkr.gpio3_18 */
                >;
        };
 
        audio_mclk_pins: pinmux_audio_mclk_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* gpmc_a11.gpio1_27 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* gpmc_a11.gpio1_27 */
                >;
        };
 
        backlight0_pins: pinmux_backlight0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE7)     /* gpmc_wen.gpio2_4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WEN, PIN_OUTPUT, MUX_MODE7)      /* gpmc_wen.gpio2_4 */
                >;
        };
 
        backlight1_pins: pinmux_backlight1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x828, PIN_OUTPUT | MUX_MODE7)     /* gpmc_ad10.gpio0_26 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD10, PIN_OUTPUT, MUX_MODE7)     /* gpmc_ad10.gpio0_26 */
                >;
        };
 
        lcd_pins: pinmux_lcd_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data0.lcd_data0 */
-                       AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data1.lcd_data1 */
-                       AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data2.lcd_data2 */
-                       AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)     /* lcd_data3.lcd_data3 */
-                       AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data4.lcd_data4 */
-                       AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data5.lcd_data5 */
-                       AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data6.lcd_data6 */
-                       AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)     /* lcd_data7.lcd_data7 */
-                       AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data8.lcd_data8 */
-                       AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data9.lcd_data9 */
-                       AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data10.lcd_data10 */
-                       AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)     /* lcd_data11.lcd_data11 */
-                       AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)     /* lcd_data12.lcd_data12 */
-                       AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)     /* lcd_data13.lcd_data13 */
-                       AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)     /* lcd_data14.lcd_data14 */
-                       AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)     /* lcd_data15.lcd_data15 */
-                       AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* lcd_vsync.lcd_vsync */
-                       AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* lcd_hsync.lcd_hsync */
-                       AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* lcd_pclk.lcd_pclk */
-                       AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* lcd_ac_bias_en.lcd_ac_bias_en */
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA0, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA1, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA2, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA3, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA4, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA5, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA6, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA7, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA8, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA9, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA10, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA11, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA12, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA13, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA14, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_DATA15, PIN_OUTPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_VSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_HSYNC, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_PCLK, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_LCD_AC_BIAS_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        led_pins: pinmux_led_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT | MUX_MODE7)     /* gpmc_a5.gpio1_21 */
-                       AM33XX_IOPAD(0x858, PIN_OUTPUT | MUX_MODE7)     /* gpmc_a6.gpio1_22 */
-                       AM33XX_IOPAD(0x85c, PIN_OUTPUT | MUX_MODE7)     /* gpmc_a7.gpio1_23 */
-                       AM33XX_IOPAD(0x860, PIN_OUTPUT | MUX_MODE7)     /* gpmc_a8.gpio1_24 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT, MUX_MODE7)       /* gpmc_a5.gpio1_21 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_OUTPUT, MUX_MODE7)       /* gpmc_a6.gpio1_22 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_OUTPUT, MUX_MODE7)       /* gpmc_a7.gpio1_23 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_OUTPUT, MUX_MODE7)       /* gpmc_a8.gpio1_24 */
                >;
        };
 
        uart0_pins: pinmux_uart0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        uart1_pins: pinmux_uart1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart1_rxd.uart1_rxd */
-                       AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart1_txd.uart1_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        uart4_pins: pinmux_uart4_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE6)       /* gpmc_wait0.uart4_rxd */
-                       AM33XX_IOPAD(0x874, PIN_OUTPUT_PULLDOWN | MUX_MODE6)    /* gpmc_wpn.uart4_txd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WAIT0, PIN_INPUT_PULLUP, MUX_MODE6)      /* gpmc_wait0.uart4_rxd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_OUTPUT_PULLDOWN, MUX_MODE6)     /* gpmc_wpn.uart4_txd */
                >;
        };
 
        i2c0_pins: pinmux_i2c0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_sda.i2c0_sda */
-                       AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)       /* i2c0_scl.i2c0_scl */
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SDA, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_I2C0_SCL, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        i2c2_pins: pinmux_i2c2_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x978, PIN_INPUT_PULLUP | MUX_MODE3)       /* uart1_ctsn.i2c2_sda */
-                       AM33XX_IOPAD(0x97c, PIN_INPUT_PULLUP | MUX_MODE3)       /* uart1_rtsn.i2c2_scl */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT_PULLUP, MUX_MODE3)      /* uart1_ctsn.i2c2_sda */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_INPUT_PULLUP, MUX_MODE3)      /* uart1_rtsn.i2c2_scl */
                >;
        };
 
        cpsw_default: cpsw_default {
                pinctrl-single,pins = <
                        /* Slave 1 */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_rxerr.mii1_rxerr */
-                       AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* mii1_txen.mii1_txen */
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_rxdv.mii1_rxdv */
-                       AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* mii1_txd3.mii1_txd3 */
-                       AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* mii1_txd2.mii1_txd2 */
-                       AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* mii1_txd1.mii1_txd1 */
-                       AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* mii1_txd0.mii1_txd0 */
-                       AM33XX_IOPAD(0x92c, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_txclk.mii1_txclk */
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_rxclk.mii1_rxclk */
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_rxd3.mii1_rxd3 */
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_rxd2.mii1_rxd2 */
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_rxd1.mii1_rxd1 */
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLUP | MUX_MODE0)       /* mii1_rxd0.mii1_rxd0 */
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLUP, MUX_MODE0)
                >;
        };
 
        cpsw_sleep: cpsw_sleep {
                pinctrl-single,pins = <
                        /* Slave 1 reset value */
-                       AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_ER, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_EN, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_DV, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_TX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RX_CLK, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD3, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD2, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD1, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        davinci_mdio_default: davinci_mdio_default {
                pinctrl-single,pins = <
                        /* MDIO */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)       /* mdio_data.mdio_data */
-                       AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)                      /* mdio_clk.mdio_clk */
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLUP | SLEWCTRL_FAST, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_OUTPUT_PULLUP, MUX_MODE0)
                        /* Ethernet */
-                       AM33XX_IOPAD(0x838, PIN_INPUT_PULLUP | MUX_MODE7)       /* Ethernet_nRST - gpmc_ad14.gpio1_14 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD14, PIN_INPUT_PULLUP, MUX_MODE7)       /* Ethernet_nRST - gpmc_ad14.gpio1_14 */
                >;
        };
 
        davinci_mdio_sleep: davinci_mdio_sleep {
                pinctrl-single,pins = <
                        /* MDIO reset value */
-                       AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
-                       AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDIO, PIN_INPUT_PULLDOWN, MUX_MODE7)
+                       AM33XX_PADCONF(AM335X_PIN_MDC, PIN_INPUT_PULLDOWN, MUX_MODE7)
                >;
        };
 
        mmc1_pins: pinmux_mmc1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x96c, PIN_INPUT | MUX_MODE7)              /* uart0_rtsn.gpio1_9 */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_INPUT, MUX_MODE7)             /* uart0_rtsn.gpio1_9 */
                >;
        };
 
        emmc_pwrseq_pins: pinmux_emmc_pwrseq_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x850, PIN_OUTPUT_PULLUP | MUX_MODE7)      /* gpmc_a4.gpio1_20 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_OUTPUT_PULLUP, MUX_MODE7)        /* gpmc_a4.gpio1_20 */
                >;
        };
 
        emmc_pins: pinmux_emmc_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2)       /* gpmc_csn1.mmc1_clk */
-                       AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2)       /* gpmc_csn2.mmc1_cmd */
-                       AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad0.mmc1_dat0 */
-                       AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad1.mmc1_dat1 */
-                       AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad2.mmc1_dat2 */
-                       AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad3.mmc1_dat3 */
-                       AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad4.mmc1_dat4 */
-                       AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad5.mmc1_dat5 */
-                       AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad6.mmc1_dat6 */
-                       AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1)       /* gpmc_ad7.mmc1_dat7 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN1, PIN_INPUT_PULLUP, MUX_MODE2)       /* gpmc_csn1.mmc1_clk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_CSN2, PIN_INPUT_PULLUP, MUX_MODE2)       /* gpmc_csn2.mmc1_cmd */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD0, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad0.mmc1_dat0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD1, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad1.mmc1_dat1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD2, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad2.mmc1_dat2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD3, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad3.mmc1_dat3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD4, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad4.mmc1_dat4 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD5, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad5.mmc1_dat5 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD6, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad6.mmc1_dat6 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD7, PIN_INPUT_PULLUP, MUX_MODE1)        /* gpmc_ad7.mmc1_dat7 */
                >;
        };
 
        ehrpwm1_pins: pinmux_ehrpwm1a_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x848, PIN_OUTPUT | MUX_MODE6)     /* gpmc_a2.ehrpwm1a */
-                       AM33XX_IOPAD(0x84c, PIN_OUTPUT | MUX_MODE6)     /* gpmc_a3.ehrpwm1b */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_OUTPUT, MUX_MODE6)       /* gpmc_a2.ehrpwm1a */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A3, PIN_OUTPUT, MUX_MODE6)       /* gpmc_a3.ehrpwm1b */
                >;
        };
 
        rtc0_irq_pins: pinmux_rtc0_irq_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x824, PIN_INPUT_PULLUP | MUX_MODE7)     /* gpmc_ad9.gpio0_23 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD9, PIN_INPUT_PULLUP, MUX_MODE7)     /* gpmc_ad9.gpio0_23 */
                >;
        };
 
        spi0_pins: pinmux_spi0_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x954, PIN_INPUT_PULLUP | MUX_MODE0)       /* SPI0_MOSI - spi0_d0.spi0_d0 */
-                       AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE0)       /* SPI0_MISO - spi0_d1.spi0_d1 */
-                       AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE0)       /* SPI0_CLK  - spi0_clk.spi0_clk */
-                       AM33XX_IOPAD(0x95c, PIN_INPUT_PULLUP | MUX_MODE0)       /* SPI0_CS0 (NBATTSS) - spi0_cs0.spi0_cs0 */
-                       AM33XX_IOPAD(0x960, PIN_INPUT_PULLUP | MUX_MODE0)       /* SPI0_CS1 (FPGA_FLASH_NCS) - spi0_cs1.spi0_cs1 */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_INPUT_PULLUP, MUX_MODE0) /* SPI0_MOSI */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_D1, PIN_INPUT_PULLUP, MUX_MODE0) /* SPI0_MISO */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_SCLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_INPUT_PULLUP, MUX_MODE0)        /* SPI0_CS0 (NBATTSS) */
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT_PULLUP, MUX_MODE0)        /* SPI0_CS1 (FPGA_FLASH_NCS) */
                >;
        };
 
        lwb_pins: pinmux_lwb_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x830, PIN_INPUT_PULLUP | MUX_MODE7)       /* nKbdInt - gpmc_ad12.gpio1_12 */
-                       AM33XX_IOPAD(0x834, PIN_INPUT_PULLUP | MUX_MODE7)       /* nKbdReset - gpmc_ad13.gpio1_13 */
-                       AM33XX_IOPAD(0x844, PIN_INPUT_PULLUP | MUX_MODE7)       /* USB1_enPower - gpmc_a1.gpio1_17 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD12, PIN_INPUT_PULLUP, MUX_MODE7)       /* nKbdInt - gpmc_ad12.gpio1_12 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD13, PIN_INPUT_PULLUP, MUX_MODE7)       /* nKbdReset - gpmc_ad13.gpio1_13 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A1, PIN_INPUT_PULLUP, MUX_MODE7) /* USB1_enPower - gpmc_a1.gpio1_17 */
                        /* PDI Bus - Battery system */
-                       AM33XX_IOPAD(0x840, PIN_INPUT_PULLUP | MUX_MODE7)       /* nBattReset  gpmc_a0.gpio1_16 */
-                       AM33XX_IOPAD(0x83c, PIN_INPUT_PULLUP | MUX_MODE7)       /* BattPDIData gpmc_ad15.gpio1_15 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_INPUT_PULLUP, MUX_MODE7) /* nBattReset  gpmc_a0.gpio1_16 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD15, PIN_INPUT_PULLUP, MUX_MODE7)       /* BattPDIData gpmc_ad15.gpio1_15 */
                        /* FPGA */
-                       AM33XX_IOPAD(0x820, PIN_INPUT_PULLUP | MUX_MODE7)       /* FPGA_DONE - gpmc_ad8.gpio0_22 */
-                       AM33XX_IOPAD(0x840, PIN_INPUT_PULLUP | MUX_MODE7)       /* FPGA_NRST - gpmc_a0.gpio1_16 */
-                       AM33XX_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* FPGA_RUN - gpmc_a1.gpio1_17 */
-                       AM33XX_IOPAD(0x864, PIN_INPUT_PULLUP | MUX_MODE7)       /* ENFPGA - gpmc_a9.gpio1_25 */
-                       AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* FPGA_PROGRAM - gpmc_a10.gpio1_26 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_AD8, PIN_INPUT_PULLUP, MUX_MODE7)        /* FPGA_DONE - gpmc_ad8.gpio0_22 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_INPUT_PULLUP, MUX_MODE7) /* FPGA_NRST - gpmc_a0.gpio1_16 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A1, PIN_INPUT_PULLDOWN, MUX_MODE7)       /* FPGA_RUN - gpmc_a1.gpio1_17 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A9, PIN_INPUT_PULLUP, MUX_MODE7) /* ENFPGA - gpmc_a9.gpio1_25 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT_PULLDOWN, MUX_MODE7)      /* FPGA_PROGRAM - gpmc_a10.gpio1_26 */
                >;
        };
 };
index 8ce541739b24f08bb4a4a0677caee390ba4f899e..b7d28a20341fb5d0494d55cd5a261f2c20d87a2f 100644 (file)
 &am33xx_pinmux {
        mcasp0_pins: pinmux_mcasp0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x9AC, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_ahclkx.mcasp0_ahclkx */
-                       AM33XX_IOPAD(0x990, PIN_INPUT_PULLDOWN | MUX_MODE0)  /* mcasp0_aclkx.mcasp0_aclkx */
-                       AM33XX_IOPAD(0x994, PIN_INPUT_PULLDOWN | MUX_MODE0)  /* mcasp0_fsx.mcasp0_fsx */
-                       AM33XX_IOPAD(0x998, PIN_INPUT_PULLDOWN | MUX_MODE0)  /* mcasp0_axr0.mcasp0_axr0 */
-                       AM33XX_IOPAD(0x9A8, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_axr1.mcasp0_axr1 */
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AHCLKX, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_ACLKX, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_FSX, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AXR0, PIN_INPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MCASP0_AXR1, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 };
@@ -84,8 +84,8 @@
 &am33xx_pinmux {
        dcan1_pins: pinmux_dcan1 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x968, PIN_OUTPUT_PULLUP | MUX_MODE2) /* uart0_ctsn.d_can1_tx */
-                       AM33XX_IOPAD(0x96c, PIN_INPUT_PULLUP | MUX_MODE2) /* uart0_rtsn.d_can1_rx */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_CTSN, PIN_OUTPUT_PULLUP, MUX_MODE2) /* uart0_ctsn.d_can1_tx */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RTSN, PIN_INPUT_PULLUP, MUX_MODE2) /* uart0_rtsn.d_can1_rx */
                >;
        };
 };
 &am33xx_pinmux {
        ethernet1_pins: pinmux_ethernet1 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x840, PIN_OUTPUT | MUX_MODE1)             /* gpmc_a0.mii2_txen */
-                       AM33XX_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* gpmc_a1.mii2_rxdv */
-                       AM33XX_IOPAD(0x848, PIN_OUTPUT | MUX_MODE1)             /* gpmc_a2.mii2_txd3 */
-                       AM33XX_IOPAD(0x84c, PIN_OUTPUT | MUX_MODE1)             /* gpmc_a3.mii2_txd2 */
-                       AM33XX_IOPAD(0x850, PIN_OUTPUT | MUX_MODE1)             /* gpmc_a4.mii2_txd1 */
-                       AM33XX_IOPAD(0x854, PIN_OUTPUT | MUX_MODE1)             /* gpmc_a5.mii2_txd0 */
-                       AM33XX_IOPAD(0x858, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* gpmc_a6.mii2_txclk */
-                       AM33XX_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* gpmc_a7.mii2_rxclk */
-                       AM33XX_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* gpmc_a8.mii2_rxd3 */
-                       AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* gpmc_a9.mii2_rxd2 */
-                       AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* gpmc_a10.mii2_rxd1 */
-                       AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* gpmc_a11.mii2_rxd0 */
-                       AM33XX_IOPAD(0x874, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* gpmc_wpn.mii2_rxerr */
-                       AM33XX_IOPAD(0x878, PIN_INPUT_PULLDOWN | MUX_MODE1)     /* gpmc_ben1.mii2_col */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A0, PIN_OUTPUT, MUX_MODE1)               /* gpmc_a0.mii2_txen */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A1, PIN_INPUT_PULLDOWN, MUX_MODE1)       /* gpmc_a1.mii2_rxdv */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A2, PIN_OUTPUT, MUX_MODE1)               /* gpmc_a2.mii2_txd3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A3, PIN_OUTPUT, MUX_MODE1)               /* gpmc_a3.mii2_txd2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A4, PIN_OUTPUT, MUX_MODE1)               /* gpmc_a4.mii2_txd1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT, MUX_MODE1)               /* gpmc_a5.mii2_txd0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A6, PIN_INPUT_PULLDOWN, MUX_MODE1)       /* gpmc_a6.mii2_txclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A7, PIN_INPUT_PULLDOWN, MUX_MODE1)       /* gpmc_a7.mii2_rxclk */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A8, PIN_INPUT_PULLDOWN, MUX_MODE1)       /* gpmc_a8.mii2_rxd3 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A9, PIN_INPUT_PULLDOWN, MUX_MODE1)       /* gpmc_a9.mii2_rxd2 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A10, PIN_INPUT_PULLDOWN, MUX_MODE1)      /* gpmc_a10.mii2_rxd1 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_A11, PIN_INPUT_PULLDOWN, MUX_MODE1)      /* gpmc_a11.mii2_rxd0 */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_WPN, PIN_INPUT_PULLDOWN, MUX_MODE1)      /* gpmc_wpn.mii2_rxerr */
+                       AM33XX_PADCONF(AM335X_PIN_GPMC_BEN1, PIN_INPUT_PULLDOWN, MUX_MODE1)     /* gpmc_ben1.mii2_col */
                >;
        };
 };
 &am33xx_pinmux {
        mmc1_pins: pinmux_mmc1 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat3.mmc0_dat3 */
-                       AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat2.mmc0_dat2 */
-                       AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat1.mmc0_dat1 */
-                       AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_dat0.mmc0_dat0 */
-                       AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_clk.mmc0_clk */
-                       AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)       /* mmc0_cmd.mmc0_cmd */
-                       AM33XX_IOPAD(0x960, PIN_INPUT_PULLUP | MUX_MODE7)       /* spi0_cs1.mmc0_sdcd */
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT3, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT2, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT1, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_DAT0, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CLK, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_MMC0_CMD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_SPI0_CS1, PIN_INPUT_PULLUP, MUX_MODE7)        /* spi0_cs1.mmc0_sdcd */
                >;
        };
 };
 &am33xx_pinmux {
        uart0_pins: pinmux_uart0 {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)    /* uart0_rxd.uart0_rxd */
-                       AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+                       AM33XX_PADCONF(AM335X_PIN_UART0_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART0_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 
        uart1_pins: pinmux_uart1_pins {
                pinctrl-single,pins = <
-                       AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0)       /* uart1_rxd.uart1_rxd */
-                       AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart1_txd.uart1_txd */
-                       AM33XX_IOPAD(0x978, PIN_INPUT | MUX_MODE0)              /* uart1_ctsn.uart1_ctsn */
-                       AM33XX_IOPAD(0x97c, PIN_OUTPUT_PULLDOWN | MUX_MODE0)    /* uart1_rtsn.uart1_rtsn */
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RXD, PIN_INPUT_PULLUP, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_TXD, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_CTSN, PIN_INPUT, MUX_MODE0)
+                       AM33XX_PADCONF(AM335X_PIN_UART1_RTSN, PIN_OUTPUT_PULLDOWN, MUX_MODE0)
                >;
        };
 };
index 9dfd80e3b76ecb8ac73ef18e7a164f4881ab1e82..9b8b132b04e11c2dfd06aec831d2aed1373eb048 100644 (file)
@@ -80,6 +80,7 @@
                pinctrl-names = "default", "sleep";
                pinctrl-0 = <&matrix_keypad_default>;
                pinctrl-1 = <&matrix_keypad_sleep>;
+               wakeup-source;
 
                row-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH         /* Bank0, pin12 */
                             &gpio0 13 GPIO_ACTIVE_HIGH         /* Bank0, pin13 */
                        regulator-name = "vdcdc3";
                        regulator-boot-on;
                        regulator-always-on;
+                       regulator-state-mem {
+                               regulator-on-in-suspend;
+                       };
+                       regulator-state-disk {
+                               regulator-off-in-suspend;
+                       };
                };
 
                dcdc4: regulator-dcdc4 {
                        regulator-name = "v1_0bat";
                        regulator-min-microvolt = <1000000>;
                        regulator-max-microvolt = <1000000>;
+                       regulator-boot-on;
+                       regulator-always-on;
                };
 
                dcdc6: regulator-dcdc6 {
                        regulator-name = "v1_8bat";
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
+                       regulator-boot-on;
+                       regulator-always-on;
                };
 
                ldo1: regulator-ldo1 {
diff --git a/arch/arm/boot/dts/am5718.dtsi b/arch/arm/boot/dts/am5718.dtsi
new file mode 100644 (file)
index 0000000..d51007c
--- /dev/null
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+#include "dra72x.dtsi"
+
+/ {
+       compatible = "ti,am5718", "ti,dra7";
+};
+
+/*
+ * These modules are not present on AM5718
+ *
+ * ATL
+ * VCP1, VCP2
+ * MLB
+ * ISS
+ * USB3, USB4
+ */
+
+&usb3_tm {
+       status = "disabled";
+};
+
+&usb4_tm {
+       status = "disabled";
+};
+
+&atl_tm {
+       status = "disabled";
+};
index 6432309b39e3854eb225a64d5766e9164d88ff2c..66116ad3f9f4cf14e2d113983af63e3d91b8b58a 100644 (file)
@@ -7,7 +7,7 @@
  */
 /dts-v1/;
 
-#include "dra72x.dtsi"
+#include "am5718.dtsi"
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include "dra7-mmc-iodelay.dtsi"
diff --git a/arch/arm/boot/dts/am5728.dtsi b/arch/arm/boot/dts/am5728.dtsi
new file mode 100644 (file)
index 0000000..82e5427
--- /dev/null
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+#include "dra74x.dtsi"
+
+/ {
+       compatible = "ti,am5728", "ti,dra7";
+};
+
+/*
+ * These modules are not present on AM5728
+ *
+ * EVE1, EVE2
+ * ATL
+ * VCP1, VCP2
+ * MLB
+ * ISS
+ * USB3, USB4
+ */
+
+&usb3_tm {
+       status = "disabled";
+};
+
+&usb4_tm {
+       status = "disabled";
+};
+
+&atl_tm {
+       status = "disabled";
+};
index b2fb6e097be7607ddd1613a75c8290b26f9fe121..4f835222c266bf907475d710d765e946101221e1 100644 (file)
@@ -8,15 +8,14 @@
 
 /dts-v1/;
 
-#include "dra74x.dtsi"
+#include "am5728.dtsi"
 #include "dra7-mmc-iodelay.dtsi"
 #include "dra74x-mmc-iodelay.dtsi"
 #include "am572x-idk-common.dtsi"
 
 / {
        model = "TI AM5728 IDK";
-       compatible = "ti,am5728-idk", "ti,am5728", "ti,dra742", "ti,dra74",
-                    "ti,dra7";
+       compatible = "ti,am5728-idk", "ti,am5728", "ti,dra7";
 };
 
 &mmc1 {
diff --git a/arch/arm/boot/dts/am5748.dtsi b/arch/arm/boot/dts/am5748.dtsi
new file mode 100644 (file)
index 0000000..5e12975
--- /dev/null
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+#include "dra76x.dtsi"
+
+/ {
+       compatible = "ti,am5748", "ti,dra762", "ti,dra7";
+};
+
+/*
+ * These modules are not present on AM5748
+ *
+ * EVE1, EVE2
+ * ATL
+ * VCP1, VCP2
+ * MLB
+ * ISS
+ * USB3, USB4
+ */
+
+&usb3_tm {
+       status = "disabled";
+};
+
+&usb4_tm {
+       status = "disabled";
+};
+
+&atl_tm {
+       status = "disabled";
+};
index 378dfa780ac17a69a1c9420dd69c7c58690cb0d3..dc5141c35610e9596ee5e6fb3272bedc95e426c3 100644 (file)
@@ -6,14 +6,14 @@
 
 /dts-v1/;
 
-#include "dra76x.dtsi"
+#include "am5748.dtsi"
 #include "dra7-mmc-iodelay.dtsi"
 #include "dra76x-mmc-iodelay.dtsi"
 #include "am572x-idk-common.dtsi"
 
 / {
        model = "TI AM5748 IDK";
-       compatible = "ti,am5728-idk", "ti,dra762", "ti,dra7";
+       compatible = "ti,am5748-idk", "ti,am5748", "ti,dra762", "ti,dra7";
 };
 
 &qspi {
index 1e6620f139dd32f5325e343909695c5c98086506..2341a56ebab928efe5fd3f23cdbecbe46e1082af 100644 (file)
@@ -7,7 +7,7 @@
  */
 /dts-v1/;
 
-#include "dra74x.dtsi"
+#include "am5728.dtsi"
 #include "am57xx-commercial-grade.dtsi"
 #include "dra74x-mmc-iodelay.dtsi"
 #include <dt-bindings/gpio/gpio.h>
index 4748ce8747ad865074debf76adaac141247af017..0460de0da2bf7e1c2d88f315b774af8b98c9dd67 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/irq.h>
-#include "dra74x.dtsi"
+#include "am5728.dtsi"
 
 / {
        model = "CompuLab CL-SOM-AM57x";
index 96c18703e4717d513810dcc6f7ff3ad561ae7d63..3f4bb44d85f00a53ee60993bf2bd3b30e5b500bb 100644 (file)
                                reg = <0x20300 0x34>, <0x20704 0x4>, <0x18260 0x4>;
                                clocks = <&coreclk 2>, <&refclk>;
                                clock-names = "nbclk", "fixed";
+                               interrupts-extended = <&gic GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+                                                     <&gic GIC_SPI  9 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        cpurst: cpurst@20800 {
index 2375449c02d054ae6e17a3aae2a8d00e6f984ecb..556ed469830cdb015dd7d3b3f7f3ad9d2883608b 100644 (file)
 
        chosen {
                stdout-path = &uart5;
-               bootargs = "console=ttyS4,115200 earlyprintk";
+               bootargs = "console=tty0 console=ttyS4,115200 earlyprintk";
        };
 
        memory@80000000 {
                reg = <0x80000000 0x20000000>;
        };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               gfx_memory: framebuffer {
+                       size = <0x01000000>;
+                       alignment = <0x01000000>;
+                       compatible = "shared-dma-pool";
+                       reusable;
+               };
+       };
 };
 
 &fmc {
@@ -27,6 +40,7 @@
                status = "okay";
                m25p,fast-read;
                label = "bmc";
+#include "openbmc-flash-layout.dtsi"
        };
 };
 
 &uhci {
        status = "okay";
 };
+
+&gfx {
+     status = "okay";
+     memory-region = <&gfx_memory>;
+};
index 9f194b5eeba442135fc732eb8e04da973dcd2de1..43aba4071a5c2c610ebd00f219fec074cb3133f1 100644 (file)
        memory@80000000 {
                reg = <0x80000000 0x20000000>;
        };
+
+       ast-adc-hwmon {
+               compatible = "iio-hwmon";
+               io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
+                             <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>;
+       };
 };
 
 &pinctrl {
index 4c2dcac738e8cf0ba226a560d0b5afcad40cfcd2..c4521eda787cd5d1a3914fd11c9e9a80dd66e89c 100644 (file)
        status = "okay";
 };
 
+&vuart {
+       // VUART Host Console
+       status = "okay";
+};
+
 &uart1 {
        // Host Console
        status = "okay";
index b854ac0bae9a9a865915db202860735358963d7c..b249da80fb83e56fe4182f188059c140611d3b62 100644 (file)
@@ -32,9 +32,9 @@
                        no-map;
                };
 
-               flash_memory: region@98000000 {
+               flash_memory: region@5c000000 {
                        no-map;
-                       reg = <0x98000000 0x01000000>; /* 16MB */
+                       reg = <0x5C000000 0x02000000>; /* 32MB */
                };
        };
 
index 76fe994f2ba4075b70972df15d5fd3eed364b9b7..418a1988b262a43466e4fd227c6b20b28b271750 100644 (file)
                        reg = <0x9ef00000 0x00100000>;
                        no-map;
                };
+
+               gfx_memory: framebuffer {
+                       size = <0x01000000>;
+                       alignment = <0x01000000>;
+                       compatible = "shared-dma-pool";
+                       reusable;
+               };
        };
 
        leds {
 
 &gfx {
        status = "okay";
+       memory-region = <&gfx_memory>;
 };
 
 &pinctrl {
index ad54117c075e994e00f17fcbcbe05e0785e359cd..f1356ca794d8b866cfa41e1d362095c42df2c8ce 100644 (file)
                        no-map;
                        reg = <0x98000000 0x04000000>; /* 64M */
                };
+
+               gfx_memory: framebuffer {
+                       size = <0x01000000>;
+                       alignment = <0x01000000>;
+                       compatible = "shared-dma-pool";
+                       reusable;
+               };
        };
 
        gpio-keys {
                status = "okay";
                label = "bmc";
                m25p,fast-read;
-#include "openbmc-flash-layout.dtsi"
+
+               partitions {
+                       #address-cells = < 1 >;
+                       #size-cells = < 1 >;
+                       compatible = "fixed-partitions";
+                       u-boot@0 {
+                               reg = < 0 0x60000 >;
+                               label = "u-boot";
+                       };
+                       u-boot-env@60000 {
+                               reg = < 0x60000 0x20000 >;
+                               label = "u-boot-env";
+                       };
+                       obmc-ubi@80000 {
+                               reg = < 0x80000 0x1F80000 >;
+                               label = "obmc-ubi";
+                       };
+               };
        };
 
        flash@1 {
                status = "okay";
-               label = "alt";
+               label = "alt-bmc";
                m25p,fast-read;
+
+               partitions {
+                       #address-cells = < 1 >;
+                       #size-cells = < 1 >;
+                       compatible = "fixed-partitions";
+                       u-boot@0 {
+                               reg = < 0 0x60000 >;
+                               label = "alt-u-boot";
+                       };
+                       u-boot-env@60000 {
+                               reg = < 0x60000 0x20000 >;
+                               label = "alt-u-boot-env";
+                       };
+                       obmc-ubi@80000 {
+                               reg = < 0x80000 0x1F80000 >;
+                               label = "alt-obmc-ubi";
+                       };
+               };
+
        };
 };
 
 
 &gfx {
        status = "okay";
+       memory-region = <&gfx_memory>;
 };
 
 &pinctrl {
 &adc {
        status = "okay";
 };
+
+&vhub {
+       status = "okay";
+};
index 9549f867aa1efd4356acc46609487e6216f560f9..5d7050d00874299b5b264b2732eaf333342b2874 100644 (file)
                                clock-names = "PCLK";
                        };
 
+                       rtc: rtc@1e781000 {
+                               compatible = "aspeed,ast2400-rtc";
+                               reg = <0x1e781000 0x18>;
+                               status = "disabled";
+                       };
+
                        uart1: serial@1e783000 {
                                compatible = "ns16550a";
                                reg = <0x1e783000 0x20>;
index 85ed9dbec19629582770515a8323b5f60e7bd66d..4345c3153ca74cf73b2703b9aa0a87fc3f0005f3 100644 (file)
                                compatible = "aspeed,ast2500-gfx", "syscon";
                                reg = <0x1e6e6000 0x1000>;
                                reg-io-width = <4>;
+                               clocks = <&syscon ASPEED_CLK_GATE_D1CLK>;
+                               resets = <&syscon ASPEED_RESET_CRT1>;
+                               status = "disabled";
+                               interrupts = <0x19>;
                        };
 
                        adc: adc@1e6e9000 {
                                status = "disabled";
                        };
 
+                       video: video@1e700000 {
+                               compatible = "aspeed,ast2500-video-engine";
+                               reg = <0x1e700000 0x1000>;
+                               clocks = <&syscon ASPEED_CLK_GATE_VCLK>,
+                                        <&syscon ASPEED_CLK_GATE_ECLK>;
+                               clock-names = "vclk", "eclk";
+                               interrupts = <7>;
+                               status = "disabled";
+                       };
+
                        sram: sram@1e720000 {
                                compatible = "mmio-sram";
                                reg = <0x1e720000 0x9000>;      // 36K
                                #interrupt-cells = <2>;
                        };
 
+                       rtc: rtc@1e781000 {
+                               compatible = "aspeed,ast2500-rtc";
+                               reg = <0x1e781000 0x18>;
+                               status = "disabled";
+                       };
+
                        timer: timer@1e782000 {
                                /* This timer is a Faraday FTTMR010 derivative */
                                compatible = "aspeed,ast2400-timer";
index 33a159c0163fd39f067d838e5a4ae7104d428e88..7788d5db65c25fa3150b8ead1c0519654efebbca 100644 (file)
@@ -1,47 +1,10 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * at91-sama5d27_som1.dtsi - Device Tree file for SAMA5D27 SoM1 board
  *
  *  Copyright (c) 2017, Microchip Technology Inc.
  *                2017 Cristian Birsan <cristian.birsan@microchip.com>
  *                2017 Claudiu Beznea <claudiu.beznea@microchip.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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 file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 #include "sama5d2.dtsi"
 #include "sama5d2-pinfunc.h"
index a48180555ef55ad419dca062453a3c99c044ee42..89f0c9979b89c98bb927f86e4b26e65c7fcdbbf0 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * at91-sama5d27_som1_ek.dts - Device Tree file for SAMA5D27-SOM1-EK board
  *
@@ -5,44 +6,6 @@
  *                2016 Nicolas Ferre <nicolas.ferre@atmel.com>
  *                2017 Cristian Birsan <cristian.birsan@microchip.com>
  *                2017 Claudiu Beznea <claudiu.beznea@microchip.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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 file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 /dts-v1/;
 #include "at91-sama5d27_som1.dtsi"
index fa54e8866f1ecb9909d5c917b308bff292a5730a..808e399fd39a3bb42c5bd86e98e63766050756e8 100644 (file)
@@ -1,52 +1,16 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * at91-sama5d2_xplained.dts - Device Tree file for SAMA5D2 Xplained board
  *
  *  Copyright (C) 2015 Atmel,
  *                2015 Nicolas Ferre <nicolas.ferre@atmel.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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 file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 /dts-v1/;
 #include "sama5d2.dtsi"
 #include "sama5d2-pinfunc.h"
 #include <dt-bindings/mfd/atmel-flexcom.h>
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/regulator/active-semi,8945a-regulator.h>
 
 / {
        model = "Atmel SAMA5D2 Xplained";
                                                        regulator-name = "VDD_1V35";
                                                        regulator-min-microvolt = <1350000>;
                                                        regulator-max-microvolt = <1350000>;
+                                                       regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_FIXED>,
+                                                                                 <ACT8945A_REGULATOR_MODE_LOWPOWER>;
+                                                       regulator-initial-mode = <ACT8945A_REGULATOR_MODE_FIXED>;
                                                        regulator-always-on;
+
+                                                       regulator-state-mem {
+                                                               regulator-on-in-suspend;
+                                                               regulator-suspend-min-microvolt=<1400000>;
+                                                               regulator-suspend-max-microvolt=<1400000>;
+                                                               regulator-changeable-in-suspend;
+                                                               regulator-mode=<ACT8945A_REGULATOR_MODE_LOWPOWER>;
+                                                       };
                                                };
 
                                                vdd_1v2_reg: REG_DCDC2 {
                                                        regulator-name = "VDD_1V2";
                                                        regulator-min-microvolt = <1100000>;
                                                        regulator-max-microvolt = <1300000>;
+                                                       regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_FIXED>,
+                                                                                 <ACT8945A_REGULATOR_MODE_LOWPOWER>;
+                                                       regulator-initial-mode = <ACT8945A_REGULATOR_MODE_FIXED>;
                                                        regulator-always-on;
+
+                                                       regulator-state-mem {
+                                                               regulator-off-in-suspend;
+                                                       };
                                                };
 
                                                vdd_3v3_reg: REG_DCDC3 {
                                                        regulator-name = "VDD_3V3";
                                                        regulator-min-microvolt = <3300000>;
                                                        regulator-max-microvolt = <3300000>;
+                                                       regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_FIXED>,
+                                                                                 <ACT8945A_REGULATOR_MODE_LOWPOWER>;
+                                                       regulator-initial-mode = <ACT8945A_REGULATOR_MODE_FIXED>;
                                                        regulator-always-on;
+
+                                                       regulator-state-mem {
+                                                               regulator-off-in-suspend;
+                                                       };
                                                };
 
                                                vdd_fuse_reg: REG_LDO1 {
                                                        regulator-name = "VDD_FUSE";
                                                        regulator-min-microvolt = <2500000>;
                                                        regulator-max-microvolt = <2500000>;
+                                                       regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_NORMAL>,
+                                                                                 <ACT8945A_REGULATOR_MODE_LOWPOWER>;
+                                                       regulator-initial-mode = <ACT8945A_REGULATOR_MODE_NORMAL>;
                                                        regulator-always-on;
+
+                                                       regulator-state-mem {
+                                                               regulator-off-in-suspend;
+                                                       };
                                                };
 
                                                vdd_3v3_lp_reg: REG_LDO2 {
                                                        regulator-name = "VDD_3V3_LP";
                                                        regulator-min-microvolt = <3300000>;
                                                        regulator-max-microvolt = <3300000>;
+                                                       regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_NORMAL>,
+                                                                                 <ACT8945A_REGULATOR_MODE_LOWPOWER>;
+                                                       regulator-initial-mode = <ACT8945A_REGULATOR_MODE_NORMAL>;
                                                        regulator-always-on;
+
+                                                       regulator-state-mem {
+                                                               regulator-off-in-suspend;
+                                                       };
                                                };
 
                                                vdd_led_reg: REG_LDO3 {
                                                        regulator-name = "VDD_LED";
                                                        regulator-min-microvolt = <3300000>;
                                                        regulator-max-microvolt = <3300000>;
+                                                       regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_NORMAL>,
+                                                                                 <ACT8945A_REGULATOR_MODE_LOWPOWER>;
+                                                       regulator-initial-mode = <ACT8945A_REGULATOR_MODE_NORMAL>;
                                                        regulator-always-on;
+
+                                                       regulator-state-mem {
+                                                               regulator-off-in-suspend;
+                                                       };
                                                };
 
                                                vdd_sdhc_1v8_reg: REG_LDO4 {
                                                        regulator-name = "VDD_SDHC_1V8";
                                                        regulator-min-microvolt = <1800000>;
                                                        regulator-max-microvolt = <1800000>;
+                                                       regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_NORMAL>,
+                                                                                 <ACT8945A_REGULATOR_MODE_LOWPOWER>;
+                                                       regulator-initial-mode = <ACT8945A_REGULATOR_MODE_NORMAL>;
                                                        regulator-always-on;
+
+                                                       regulator-state-mem {
+                                                               regulator-off-in-suspend;
+                                                       };
                                                };
                                        };
 
index 43aef56ac74a3e5aeb34a5bf0376fb82f29fc3c2..fdfc37d716e01b172405a6ff92354f1ca73c5672 100644 (file)
@@ -1,46 +1,9 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * at91-sama5d4_xplained.dts - Device Tree file for SAMA5D4 Xplained board
  *
  *  Copyright (C) 2015 Atmel,
  *                2015 Josh Wu <josh.wu@atmel.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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 file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 /dts-v1/;
 #include "sama5d4.dtsi"
index 12d5af938aa3429163f84fe178059df24c73b534..0cc1cff13e46e1e372a4967dc389f48897889e67 100644 (file)
@@ -1,46 +1,9 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * at91-sama5d4ek.dts - Device Tree file for SAMA5D4 Evaluation Kit
  *
  *  Copyright (C) 2014 Atmel,
  *                2014 Nicolas Ferre <nicolas.ferre@atmel.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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 file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 /dts-v1/;
 #include "sama5d4.dtsi"
index 430277291e025fb17c31cebf49173ffaadab55ea..15050fdd479d6a29601b648bef3eef32668439e6 100644 (file)
@@ -1,47 +1,10 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Device Tree file for VInCo platform
  *
  *  Copyright (C) 2014 Atmel,
  *                2014 Nicolas Ferre <nicolas.ferre@atmel.com>
  *   2015 Gregory CLEMENT <gregory.clement@free-electrons.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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 file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 /dts-v1/;
 #include "sama5d4.dtsi"
index 07d1b571e6017b27a29b7acb7d5e72499baba1c4..81f808a10931c71271405e47a1a74b21a29f92a6 100644 (file)
@@ -1,46 +1,9 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Device Tree file for Atmel at91sam9260 Evaluation Kit
  *
  *  Copyright (C) 2016 Atmel,
  *               2016 Nicolas Ferre <nicolas.ferre@atmel.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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 file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 /dts-v1/;
 #include "at91sam9260.dtsi"
index 1304452f0fae0eb8887591357263c1a61a3f6979..3f9d8caf8b0a6ec0a6ecafe30384a693fcd8222c 100644 (file)
@@ -1,46 +1,9 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * at91sam9xe.dtsi - Device Tree Include file for AT91SAM9XE family SoC
  *
  *  Copyright (C) 2015 Atmel,
  *                2015 Alexandre Belloni <alexandre.Belloni@free-electrons.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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 file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 
 #include "at91sam9260.dtsi"
index bd83962d3627fa1bd0423da3c31c3f96343050d1..1dfeeceabf4c39f8a7f7d49e51d13c7ff520dfd9 100644 (file)
                        status = "disabled";
                };
        };
+
+       usb_power_supply: usb-power-supply {
+               compatible = "x-powers,axp813-usb-power-supply";
+       };
 };
index 414f1cd6873331fd91fef8e69edf997e03f4dfaf..fe9f0bc29fec20df23b0bd0a6567d610f92f90dc 100644 (file)
                        ranges = <0x0 0x3a000 0x1000>;
                };
 
-               target-module@3c000 {                   /* 0x4843c000, ap 23 08.0 */
+               atl_tm: target-module@3c000 {           /* 0x4843c000, ap 23 08.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
                        reg = <0x3c000 0x4>;
                        reg-names = "rev";
                        };
                };
 
-               target-module@100000 {                  /* 0x48900000, ap 85 04.0 */
+               usb3_tm: target-module@100000 {         /* 0x48900000, ap 85 04.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
                        ti,hwmods = "usb_otg_ss3";
                        reg = <0x100000 0x4>,
                        };
                };
 
-               target-module@140000 {                  /* 0x48940000, ap 75 3c.0 */
+               usb4_tm: target-module@140000 {         /* 0x48940000, ap 75 3c.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
                        ti,hwmods = "usb_otg_ss4";
                        reg = <0x140000 0x4>,
index 2bc9add8b7a5038c76ca48bd9ae7faf59584a559..d87e932f45bde0a16a42e6360b220f38a1cdc156 100644 (file)
                                ti,hwmods = "pcie1";
                                phys = <&pcie1_phy>;
                                phy-names = "pcie-phy0";
+                               ti,syscon-lane-sel = <&scm_conf_pcie 0x18>;
                                interrupt-map-mask = <0 0 0 7>;
                                interrupt-map = <0 0 0 1 &pcie1_intc 1>,
                                                <0 0 0 2 &pcie1_intc 2>,
                                phys = <&pcie1_phy>;
                                phy-names = "pcie-phy0";
                                ti,syscon-unaligned-access = <&scm_conf1 0x14 1>;
+                               ti,syscon-lane-sel = <&scm_conf_pcie 0x18>;
                                status = "disabled";
                        };
                };
index 1bb8e5c9d029009b93f49c3adb4aec1b41fab03d..abfff54d6de5e040729a5252c9939cc07f008920 100644 (file)
@@ -25,7 +25,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel root=/dev/nfs ip=dhcp";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
                stdout-path = "serial1:115200n8";
        };
 
index 5892a9f7622faba0b7f4b27a372d6be64af0f3e1..8ce3a7786b19808c74ab7996b24cf27ab6d1d4c2 100644 (file)
                };
        };
 
-       soc: soc {
-               compatible = "simple-bus";
+       fixed-rate-clocks {
                #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               fixed-rate-clocks {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
+               #size-cells = <0>;
 
-                       xusbxti: clock@0 {
-                               compatible = "fixed-clock";
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-                               reg = <0>;
-                               clock-frequency = <0>;
-                               #clock-cells = <0>;
-                               clock-output-names = "xusbxti";
-                       };
+               xusbxti: clock@0 {
+                       compatible = "fixed-clock";
+                       reg = <0>;
+                       clock-frequency = <0>;
+                       #clock-cells = <0>;
+                       clock-output-names = "xusbxti";
+               };
 
-                       xxti: clock@1 {
-                               compatible = "fixed-clock";
-                               reg = <1>;
-                               clock-frequency = <0>;
-                               #clock-cells = <0>;
-                               clock-output-names = "xxti";
-                       };
+               xxti: clock@1 {
+                       compatible = "fixed-clock";
+                       reg = <1>;
+                       clock-frequency = <0>;
+                       #clock-cells = <0>;
+                       clock-output-names = "xxti";
+               };
 
-                       xtcxo: clock@2 {
-                               compatible = "fixed-clock";
-                               reg = <2>;
-                               clock-frequency = <0>;
-                               #clock-cells = <0>;
-                               clock-output-names = "xtcxo";
-                       };
+               xtcxo: clock@2 {
+                       compatible = "fixed-clock";
+                       reg = <2>;
+                       clock-frequency = <0>;
+                       #clock-cells = <0>;
+                       clock-output-names = "xtcxo";
                };
+       };
+
+       pmu {
+               compatible = "arm,cortex-a7-pmu";
+               interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+       };
+
+       soc: soc {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
 
                sysram@2020000 {
                        compatible = "mmio-sram";
                        status = "disabled";
                };
 
-               pmu {
-                       compatible = "arm,cortex-a7-pmu";
-                       interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-               };
-
                ppmu_dmc0: ppmu_dmc0@106a0000 {
                        compatible = "samsung,exynos-ppmu";
                        reg = <0x106a0000 0x2000>;
index 6085e92ac2d73925796e5d28e9a2b5832afd8729..36ccf227434da6b8e37fc7e392910ce690a8ebdf 100644 (file)
                serial3 = &serial_3;
        };
 
+       pmu: pmu {
+               compatible = "arm,cortex-a9-pmu";
+               interrupt-parent = <&combiner>;
+               interrupts = <2 2>, <3 2>;
+       };
+
        soc: soc {
                compatible = "simple-bus";
                #address-cells = <1>;
                        reg = <0x10440000 0x1000>;
                };
 
-               pmu: pmu {
-                       compatible = "arm,cortex-a9-pmu";
-                       interrupt-parent = <&combiner>;
-                       interrupts = <2 2>, <3 2>;
-               };
-
                sys_reg: syscon@10010000 {
                        compatible = "samsung,exynos4-sysreg", "syscon";
                        reg = <0x10010000 0x400>;
                        status = "disabled";
                };
 
-               amba {
+               amba: amba {
                        #address-cells = <1>;
                        #size-cells = <1>;
                        compatible = "simple-bus";
index dd9ec05eb0f795437999b505253f82d1d375b479..36b1edea254a80e411531fde19d3305b1eb252e4 100644 (file)
@@ -30,8 +30,8 @@
        };
 
        chosen {
-               bootargs ="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc";
-               stdout-path = &serial_2;
+               bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M init=/linuxrc";
+               stdout-path = "serial2:115200n8";
        };
 
        mmc_reg: voltage-regulator {
index 7a3e621ededecb8c70100792f36a8f2fa673f767..77fc11e593ad3c6201aa98e9a7bff25a7ea3d326 100644 (file)
@@ -26,8 +26,8 @@
        };
 
        chosen {
-               bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc";
-               stdout-path = &serial_1;
+               bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M init=/linuxrc";
+               stdout-path = "serial1:115200n8";
        };
 
        fixed-rate-clocks {
index 8dbc47d627a574d553348c20460d2a105f881855..6882480dbaf7a50ea08cc9e67db6bef5072ae2bf 100644 (file)
@@ -26,8 +26,8 @@
        };
 
        chosen {
-               bootargs = "console=ttySAC2,115200N8 root=/dev/mmcblk0p5 rootwait earlyprintk panic=5";
-               stdout-path = &serial_2;
+               bootargs = "root=/dev/mmcblk0p5 rootwait earlyprintk panic=5";
+               stdout-path = "serial2:115200n8";
        };
 
        regulators {
index 5c3d98654f137bf793cf51c135b2bc41c34a9ae4..bf092e97e14f043f7fce322a17150087d6b39e16 100644 (file)
@@ -24,8 +24,8 @@
        };
 
        chosen {
-               bootargs = "console=ttySAC2,115200N8 root=/dev/mmcblk0p5 rw rootwait earlyprintk panic=5 maxcpus=1";
-               stdout-path = &serial_2;
+               bootargs = "root=/dev/mmcblk0p5 rw rootwait earlyprintk panic=5 maxcpus=1";
+               stdout-path = "serial2:115200n8";
        };
 
 
        };
 };
 
+&amba {
+       mdma0: mdma@12840000 {
+               compatible = "arm,pl330", "arm,primecell";
+               reg = <0x12840000 0x1000>;
+               interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clock CLK_MDMA>;
+               clock-names = "apb_pclk";
+               #dma-cells = <1>;
+               #dma-channels = <8>;
+               #dma-requests = <1>;
+               power-domains = <&pd_lcd0>;
+       };
+};
+
 &camera {
        status = "okay";
 
 };
 
 &mdma1 {
-       reg = <0x12840000 0x1000>;
+       /* Use the secure mdma0 */
+       status = "disabled";
 };
 
 &mixer {
index 2bdf899df436612a68346c32873d37b21ac4a4c4..96d99887bceb555d6787e833bd443585e048be43 100644 (file)
@@ -34,8 +34,6 @@
        fan0: pwm-fan {
                compatible = "pwm-fan";
                pwms = <&pwm 0 10000 0>;
-               cooling-min-state = <0>;
-               cooling-max-state = <3>;
                #cooling-cells = <2>;
                cooling-levels = <0 102 170 230>;
        };
        };
 };
 
+&adc {
+       vdd-supply = <&ldo10_reg>;
+       /* Nothing connected to ADC inputs, keep it disabled */
+};
+
 /* Supply for LAN9730/SMSC95xx */
 &buck8_reg {
        regulator-name = "BUCK8_P3V3";
index 346f7193245715095f713b517987a248d579d10f..698de4345d16e672b28fb5386d1c0fec9b4763fa 100644 (file)
@@ -25,8 +25,7 @@
        };
 
        chosen {
-               bootargs ="console=ttySAC2,115200";
-               stdout-path = &serial_2;
+               stdout-path = "serial2:115200n8";
        };
 
        firmware@203f000 {
index 5c5c2887c14fb2e508ffa01f1a63fb9e51e32919..e70fb6e601f0efca883fc92b76b92613b0fd39c3 100644 (file)
@@ -23,8 +23,8 @@
        };
 
        chosen {
-               bootargs ="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc";
-               stdout-path = &serial_1;
+               bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M init=/linuxrc";
+               stdout-path = "serial1:115200n8";
        };
 
        fixed-rate-clocks {
index 327ee980d3a577ccd1316b1ba93447a9805f43dc..aac533933c617e2c3c0cde2cb19d82922f6456de 100644 (file)
@@ -22,6 +22,7 @@
        };
 
        chosen {
-               bootargs = "console=ttySAC2,115200N8 root=/dev/mmcblk0p5 rootwait earlyprintk panic=5";
+               bootargs = "root=/dev/mmcblk0p5 rootwait earlyprintk panic=5";
+               stdout-path = "serial2:115200n8";
        };
 };
index 26ad6ab3c6af5ae3cdeb247e7f86017960077ab3..e5c041ec07569312b9afa36cdda24da627693589 100644 (file)
                };
 
                adc: adc@126c0000 {
-                       compatible = "samsung,exynos-adc-v1";
+                       compatible = "samsung,exynos4212-adc";
                        reg = <0x126C0000 0x100>;
                        interrupt-parent = <&combiner>;
                        interrupts = <10 3>;
index d5e66189ed2a006d5838342c0fb38deb93b714e9..6dc96948a9ccc7fc87ceac0544ff7a2e68a86356 100644 (file)
@@ -24,7 +24,8 @@
        };
 
        chosen {
-               bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc";
+               bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M init=/linuxrc";
+               stdout-path = "serial2:115200n8";
        };
 
        vdd: fixed-regulator-vdd {
index 80986b97dfe5e18ee3ad3aae7c3fb619328fe681..d5e0392b409ecada566fbd2f43c74b0aa57c8608 100644 (file)
                };
        };
 
+       pmu {
+               compatible = "arm,cortex-a15-pmu";
+               interrupt-parent = <&combiner>;
+               interrupts = <1 2>, <22 4>;
+       };
+
        soc: soc {
                sysram@2020000 {
                        compatible = "mmio-sram";
                        power-domains = <&pd_mau>;
                };
 
-               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)>;
-                       /*
-                        * Unfortunately we need this since some versions
-                        * of U-Boot on Exynos don't set the CNTFRQ register,
-                        * so we need the value from DT.
-                        */
-                       clock-frequency = <24000000>;
-               };
-
                mct@101c0000 {
                        compatible = "samsung,exynos4210-mct";
                        reg = <0x101C0000 0x800>;
                        };
                };
 
-               pmu {
-                       compatible = "arm,cortex-a15-pmu";
-                       interrupt-parent = <&combiner>;
-                       interrupts = <1 2>, <22 4>;
-               };
-
                pinctrl_0: pinctrl@11400000 {
                        compatible = "samsung,exynos5250-pinctrl";
                        reg = <0x11400000 0x1000>;
                       };
                };
        };
+
+       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)>;
+               /*
+                * Unfortunately we need this since some versions
+                * of U-Boot on Exynos don't set the CNTFRQ register,
+                * so we need the value from DT.
+                */
+               clock-frequency = <24000000>;
+       };
 };
 
 &dp {
index b1edb20b789eb47b1f18c9162e8b570832915271..17e2f3e0d71e67c5c2d03ed5adee93831bfd6e00 100644 (file)
                #gpio-cells = <2>;
 
                interrupt-controller;
+               interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
                #interrupt-cells = <2>;
        };
 
                #gpio-cells = <2>;
 
                interrupt-controller;
+               interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
                #interrupt-cells = <2>;
        };
 
index fa19c59b2fb6f045577803927fdcd046f6edfc45..36a2b77eeb9d480f1489331c963f845df95e8f30 100644 (file)
@@ -19,7 +19,7 @@
        };
 
        chosen {
-               bootargs = "console=ttySAC2,115200";
+               stdout-path = "serial2:115200n8";
        };
 
        fin_pll: xxti {
index 55167850619cb0738cfac1a99f7696219aed2b45..3581b57fbbf7a4535d71fc4a723fd250a0215878 100644 (file)
        #size-cells = <1>;
 
        aliases {
+               i2c0 = &hsi2c_0;
+               i2c1 = &hsi2c_1;
+               i2c2 = &hsi2c_2;
+               i2c3 = &hsi2c_3;
                pinctrl0 = &pinctrl_0;
                pinctrl1 = &pinctrl_1;
                pinctrl2 = &pinctrl_2;
                        wakeup-interrupt-controller {
                                compatible = "samsung,exynos4210-wakeup-eint";
                                interrupt-parent = <&gic>;
-                               interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
                        };
                };
 
                        #size-cells = <0>;
                        clocks = <&clock_fsys FSYS_CLK_MMC0>, <&clock_top TOP_SCLK_MMC0>;
                        clock-names = "biu", "ciu";
+                       assigned-clocks =
+                               <&clock_top TOP_MOUT_SCLK_FSYS_MMC0_SDCLKIN_A>,
+                               <&clock_top TOP_MOUT_SCLK_FSYS_MMC0_SDCLKIN_B>,
+                               <&clock_top TOP_SCLK_MMC0>;
+                       assigned-clock-parents =
+                               <&clock_top TOP_MOUT_BUSTOP_PLL_USER>,
+                               <&clock_top TOP_MOUT_SCLK_FSYS_MMC0_SDCLKIN_A>;
+                       assigned-clock-rates = <0>, <0>, <800000000>;
                        fifo-depth = <64>;
                        status = "disabled";
                };
                        #size-cells = <0>;
                        clocks = <&clock_fsys FSYS_CLK_MMC1>, <&clock_top TOP_SCLK_MMC1>;
                        clock-names = "biu", "ciu";
+                       assigned-clocks =
+                               <&clock_top TOP_MOUT_SCLK_FSYS_MMC1_SDCLKIN_A>,
+                               <&clock_top TOP_MOUT_SCLK_FSYS_MMC1_SDCLKIN_B>,
+                               <&clock_top TOP_SCLK_MMC1>;
+                       assigned-clock-parents =
+                               <&clock_top TOP_MOUT_BUSTOP_PLL_USER>,
+                               <&clock_top TOP_MOUT_SCLK_FSYS_MMC1_SDCLKIN_A>;
+                       assigned-clock-rates = <0>, <0>, <800000000>;
                        fifo-depth = <64>;
                        status = "disabled";
                };
                        #size-cells = <0>;
                        clocks = <&clock_fsys FSYS_CLK_MMC2>, <&clock_top TOP_SCLK_MMC2>;
                        clock-names = "biu", "ciu";
+                       assigned-clocks =
+                               <&clock_top TOP_MOUT_SCLK_FSYS_MMC2_SDCLKIN_A>,
+                               <&clock_top TOP_MOUT_SCLK_FSYS_MMC2_SDCLKIN_B>,
+                               <&clock_top TOP_SCLK_MMC2>;
+                       assigned-clock-parents =
+                               <&clock_top TOP_MOUT_BUSTOP_PLL_USER>,
+                               <&clock_top TOP_MOUT_SCLK_FSYS_MMC2_SDCLKIN_A>;
+                       assigned-clock-rates = <0>, <0>, <800000000>;
                        fifo-depth = <64>;
                        status = "disabled";
                };
+
+               hsi2c_0: hsi2c@12da0000 {
+                       compatible = "samsung,exynos5260-hsi2c";
+                       reg = <0x12DA0000 0x1000>;
+                       interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&i2c0_hs_bus>;
+                       clocks = <&clock_peri PERI_CLK_HSIC0>;
+                       clock-names = "hsi2c";
+                       status = "disabled";
+               };
+
+               hsi2c_1: hsi2c@12db0000 {
+                       compatible = "samsung,exynos5260-hsi2c";
+                       reg = <0x12DB0000 0x1000>;
+                       interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&i2c1_hs_bus>;
+                       clocks = <&clock_peri PERI_CLK_HSIC1>;
+                       clock-names = "hsi2c";
+                       status = "disabled";
+               };
+
+               hsi2c_2: hsi2c@12dc0000 {
+                       compatible = "samsung,exynos5260-hsi2c";
+                       reg = <0x12DC0000 0x1000>;
+                       interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&i2c2_hs_bus>;
+                       clocks = <&clock_peri PERI_CLK_HSIC2>;
+                       clock-names = "hsi2c";
+                       status = "disabled";
+               };
+
+               hsi2c_3: hsi2c@12dd0000 {
+                       compatible = "samsung,exynos5260-hsi2c";
+                       reg = <0x12DD0000 0x1000>;
+                       interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&i2c3_hs_bus>;
+                       clocks = <&clock_peri PERI_CLK_HSIC3>;
+                       clock-names = "hsi2c";
+                       status = "disabled";
+               };
        };
 };
 
index 434a7591ff6397e5f1e397690ecd46f6277e7786..8f9e08f940ab4d454f97239d51cd987c2a797953 100644 (file)
@@ -38,8 +38,6 @@
        fan0: pwm-fan {
                compatible = "pwm-fan";
                pwms = <&pwm 0 20972 0>;
-               cooling-min-state = <0>;
-               cooling-max-state = <3>;
                #cooling-cells = <2>;
                cooling-levels = <0 130 170 230>;
        };
index 8fc8c841d34b9958c8778692e81b259e80887de3..dffa5e3ed90c4b4aacbcbd62eacb3ef6081d91c7 100644 (file)
@@ -19,7 +19,7 @@
        };
 
        chosen {
-               bootargs = "console=ttySAC2,115200";
+               stdout-path = "serial2:115200n8";
        };
 
        fin_pll: xxti {
index 3447160e1fbf0195c58646d54352d3c9abffbd2b..dbf0306896f65e23fdcb684e3b0327644375089d 100644 (file)
@@ -24,7 +24,7 @@
        };
 
        chosen {
-               bootargs = "console=ttySAC3,115200";
+               stdout-path = "serial3:115200n8";
        };
 
        firmware@2073000 {
        };
 };
 
+&adc {
+       vdd-supply = <&ldo4_reg>;
+       status = "okay";
+};
+
+&cci {
+       status = "disabled";
+};
+
 &cpu0 {
        cpu-supply = <&buck2_reg>;
 };
        cpu-supply = <&buck6_reg>;
 };
 
-&usbdrd_dwc3_1 {
-       dr_mode = "host";
+&cpu0_thermal {
+       trips {
+               cpu0_alert0: cpu-alert-0 {
+                       temperature = <60000>; /* millicelsius */
+                       hysteresis = <5000>; /* millicelsius */
+                       type = "passive";
+               };
+               cpu0_alert1: cpu-alert-1 {
+                       temperature = <80000>; /* millicelsius */
+                       hysteresis = <10000>; /* millicelsius */
+                       type = "passive";
+               };
+               cpu0_alert2: cpu-alert-2 {
+                       temperature = <110000>; /* millicelsius */
+                       hysteresis = <10000>; /* millicelsius */
+                       type = "passive";
+               };
+               cpu0_crit0: cpu-crit-0 {
+                       temperature = <120000>; /* millicelsius */
+                       hysteresis = <0>; /* millicelsius */
+                       type = "critical";
+               };
+       };
+
+       cooling-maps {
+               /*
+                * Reduce the CPU speed by 2 steps, down to: 1600 MHz
+                * and 1100 MHz.
+                */
+               map0 {
+                       trip = <&cpu0_alert0>;
+                       cooling-device = <&cpu0 0 2>,
+                                        <&cpu1 0 2>,
+                                        <&cpu2 0 2>,
+                                        <&cpu3 0 2>,
+                                        <&cpu4 0 2>,
+                                        <&cpu5 0 2>,
+                                        <&cpu6 0 2>,
+                                        <&cpu7 0 2>;
+               };
+
+               /*
+                * Reduce the CPU speed down to 1200 MHz big (6 steps)
+                * and 800 MHz LITTLE (5 steps).
+                */
+               map1 {
+                       trip = <&cpu0_alert1>;
+                       cooling-device = <&cpu0 3 6>,
+                                        <&cpu1 3 6>,
+                                        <&cpu2 3 6>,
+                                        <&cpu3 3 6>,
+                                        <&cpu4 3 5>,
+                                        <&cpu5 3 5>,
+                                        <&cpu6 3 5>,
+                                        <&cpu7 3 5>;
+               };
+
+               /*
+                * Reduce the CPU speed as much as possible, down to 700 MHz
+                * big (11 steps) and 600 MHz LITTLE (7 steps).
+                */
+               map2 {
+                       trip = <&cpu0_alert2>;
+                       cooling-device = <&cpu0 6 11>,
+                                        <&cpu1 6 11>,
+                                        <&cpu2 6 11>,
+                                        <&cpu3 6 11>,
+                                        <&cpu4 5 7>,
+                                        <&cpu5 5 7>,
+                                        <&cpu6 5 7>,
+                                        <&cpu7 5 7>;
+               };
+       };
 };
 
-&cci {
-       status = "disabled";
+&cpu1_thermal {
+       trips {
+               cpu1_alert0: cpu-alert-0 {
+                       temperature = <60000>; /* millicelsius */
+                       hysteresis = <5000>; /* millicelsius */
+                       type = "passive";
+               };
+               cpu1_alert1: cpu-alert-1 {
+                       temperature = <80000>; /* millicelsius */
+                       hysteresis = <10000>; /* millicelsius */
+                       type = "passive";
+               };
+               cpu1_alert2: cpu-alert-2 {
+                       temperature = <110000>; /* millicelsius */
+                       hysteresis = <10000>; /* millicelsius */
+                       type = "passive";
+               };
+               cpu1_crit0: cpu-crit-0 {
+                       temperature = <120000>; /* millicelsius */
+                       hysteresis = <0>; /* millicelsius */
+                       type = "critical";
+               };
+       };
+
+       cooling-maps {
+               map0 {
+                       trip = <&cpu1_alert0>;
+                       cooling-device = <&cpu0 0 2>,
+                                        <&cpu1 0 2>,
+                                        <&cpu2 0 2>,
+                                        <&cpu3 0 2>,
+                                        <&cpu4 0 2>,
+                                        <&cpu5 0 2>,
+                                        <&cpu6 0 2>,
+                                        <&cpu7 0 2>;
+               };
+
+               map1 {
+                       trip = <&cpu1_alert1>;
+                       cooling-device = <&cpu0 3 6>,
+                                        <&cpu1 3 6>,
+                                        <&cpu2 3 6>,
+                                        <&cpu3 3 6>,
+                                        <&cpu4 3 5>,
+                                        <&cpu5 3 5>,
+                                        <&cpu6 3 5>,
+                                        <&cpu7 3 5>;
+               };
+
+               map2 {
+                       trip = <&cpu1_alert2>;
+                       cooling-device = <&cpu0 6 11>,
+                                        <&cpu1 6 11>,
+                                        <&cpu2 6 11>,
+                                        <&cpu3 6 11>,
+                                        <&cpu4 5 7>,
+                                        <&cpu5 5 7>,
+                                        <&cpu6 5 7>,
+                                        <&cpu7 5 7>;
+               };
+       };
+};
+
+&cpu2_thermal {
+       trips {
+               cpu2_alert0: cpu-alert-0 {
+                       temperature = <60000>; /* millicelsius */
+                       hysteresis = <5000>; /* millicelsius */
+                       type = "passive";
+               };
+               cpu2_alert1: cpu-alert-1 {
+                       temperature = <80000>; /* millicelsius */
+                       hysteresis = <10000>; /* millicelsius */
+                       type = "passive";
+               };
+               cpu2_alert2: cpu-alert-2 {
+                       temperature = <110000>; /* millicelsius */
+                       hysteresis = <10000>; /* millicelsius */
+                       type = "passive";
+               };
+               cpu2_crit0: cpu-crit-0 {
+                       temperature = <120000>; /* millicelsius */
+                       hysteresis = <0>; /* millicelsius */
+                       type = "critical";
+               };
+       };
+
+       cooling-maps {
+               map0 {
+                       trip = <&cpu2_alert0>;
+                       cooling-device = <&cpu0 0 2>,
+                                        <&cpu1 0 2>,
+                                        <&cpu2 0 2>,
+                                        <&cpu3 0 2>,
+                                        <&cpu4 0 2>,
+                                        <&cpu5 0 2>,
+                                        <&cpu6 0 2>,
+                                        <&cpu7 0 2>;
+               };
+
+               map1 {
+                       trip = <&cpu2_alert1>;
+                       cooling-device = <&cpu0 3 6>,
+                                        <&cpu1 3 6>,
+                                        <&cpu2 3 6>,
+                                        <&cpu3 3 6>,
+                                        <&cpu4 3 5>,
+                                        <&cpu5 3 5>,
+                                        <&cpu6 3 5>,
+                                        <&cpu7 3 5>;
+               };
+
+               map2 {
+                       trip = <&cpu2_alert2>;
+                       cooling-device = <&cpu0 6 11>,
+                                        <&cpu1 6 11>,
+                                        <&cpu2 6 11>,
+                                        <&cpu3 6 11>,
+                                        <&cpu4 6 7>,
+                                        <&cpu5 6 7>,
+                                        <&cpu6 6 7>,
+                                        <&cpu7 6 7>;
+               };
+       };
+};
+
+&cpu3_thermal {
+       trips {
+               cpu3_alert0: cpu-alert-0 {
+                       temperature = <60000>; /* millicelsius */
+                       hysteresis = <5000>; /* millicelsius */
+                       type = "passive";
+               };
+               cpu3_alert1: cpu-alert-1 {
+                       temperature = <80000>; /* millicelsius */
+                       hysteresis = <10000>; /* millicelsius */
+                       type = "passive";
+               };
+               cpu3_alert2: cpu-alert-2 {
+                       temperature = <110000>; /* millicelsius */
+                       hysteresis = <10000>; /* millicelsius */
+                       type = "passive";
+               };
+               cpu3_crit0: cpu-crit-0 {
+                       temperature = <120000>; /* millicelsius */
+                       hysteresis = <0>; /* millicelsius */
+                       type = "critical";
+               };
+       };
+
+       cooling-maps {
+               map0 {
+                       trip = <&cpu3_alert0>;
+                       cooling-device = <&cpu0 0 2>,
+                                        <&cpu1 0 2>,
+                                        <&cpu2 0 2>,
+                                        <&cpu3 0 2>,
+                                        <&cpu4 0 2>,
+                                        <&cpu5 0 2>,
+                                        <&cpu6 0 2>,
+                                        <&cpu7 0 2>;
+               };
+
+               map1 {
+                       trip = <&cpu3_alert1>;
+                       cooling-device = <&cpu0 3 6>,
+                                        <&cpu1 3 6>,
+                                        <&cpu2 3 6>,
+                                        <&cpu3 3 6>,
+                                        <&cpu4 3 5>,
+                                        <&cpu5 3 5>,
+                                        <&cpu6 3 5>,
+                                        <&cpu7 3 5>;
+               };
+
+               map2 {
+                       trip = <&cpu3_alert2>;
+                       cooling-device = <&cpu0 6 11>,
+                                        <&cpu1 6 11>,
+                                        <&cpu2 6 11>,
+                                        <&cpu3 6 11>,
+                                        <&cpu4 5 7>,
+                                        <&cpu5 5 7>,
+                                        <&cpu6 5 7>,
+                                        <&cpu7 5 7>;
+               };
+       };
 };
 
 &hdmi {
                                regulator-name = "PVDD_APIO_1V8";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
                        };
 
                        ldo3_reg: LDO3 {
                                regulator-name = "PVDD_APIO_MMCON_1V8";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
+                               /*
+                                * Must be always on, even though there is
+                                * a consumer (mmc_0).  Otherwise the board
+                                * does not reboot with vendor U-Boot
+                                * (Linaro for Arndale Octa, v2012.07).
+                                */
                                regulator-always-on;
                        };
 
                                regulator-name = "PVDD_ABB_1V8";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
                        };
 
                        ldo9_reg: LDO9 {
 
                        ldo13_reg: LDO13 {
                                regulator-name = "PVDD_APIO_MMCOFF_2V8";
-                               regulator-min-microvolt = <2800000>;
+                               regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <2800000>;
                        };
 
+                       ldo14_reg: LDO14 {
+                               /* Unused */
+                               regulator-name = "PVDD_LDO14";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <3950000>;
+                       };
+
                        ldo15_reg: LDO15 {
                                regulator-name = "PVDD_PERI_2V8";
                                regulator-min-microvolt = <3300000>;
                                regulator-max-microvolt = <2200000>;
                        };
 
+                       ldo17_reg: LDO17 {
+                               /* Unused */
+                               regulator-name = "PVDD_LDO17";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <3950000>;
+                       };
+
                        ldo18_reg: LDO18 {
                                regulator-name = "PVDD_EMMC_1V8";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
                        };
 
+                       ldo22_reg: LDO22 {
+                               /* Unused */
+                               regulator-name = "PVDD_LDO22";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <2375000>;
+                       };
+
                        ldo23_reg: LDO23 {
                                regulator-name = "PVDD_MIFS_1V1";
-                               regulator-min-microvolt = <1200000>;
-                               regulator-max-microvolt = <1200000>;
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1100000>;
                                regulator-always-on;
                        };
 
                                regulator-max-microvolt = <2800000>;
                        };
 
+                       ldo25_reg: LDO25 {
+                               /* Unused */
+                               regulator-name = "PVDD_LDO25";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <3950000>;
+                       };
+
                        ldo26_reg: LDO26 {
                                regulator-name = "PVDD_CAM0_AF_2V8";
                                regulator-min-microvolt = <3000000>;
 
                        ldo27_reg: LDO27 {
                                regulator-name = "PVDD_G3DS_1V0";
-                               regulator-min-microvolt = <1200000>;
-                               regulator-max-microvolt = <1200000>;
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1100000>;
                        };
 
                        ldo28_reg: LDO28 {
                                regulator-max-microvolt = <1800000>;
                        };
 
+                       ldo30_reg: LDO30 {
+                               /* Unused */
+                               regulator-name = "PVDD_LDO30";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <3950000>;
+                       };
+
                        ldo31_reg: LDO31 {
                                regulator-name = "PVDD_PERI_1V8";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
                        };
 
+                       ldo34_reg: LDO34 {
+                               /* Unused */
+                               regulator-name = "PVDD_LDO34";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <3950000>;
+                       };
+
                        ldo35_reg: LDO35 {
                                regulator-name = "PVDD_CAM0_DVDD_1V2";
                                regulator-min-microvolt = <1200000>;
                                regulator-max-microvolt = <1200000>;
                        };
 
+                       ldo36_reg: LDO36 {
+                               /* Unused */
+                               regulator-name = "PVDD_LDO36";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <3950000>;
+                       };
+
+                       ldo37_reg: LDO37 {
+                               /* Unused */
+                               regulator-name = "PVDD_LDO37";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <3950000>;
+                       };
+
                        ldo38_reg: LDO38 {
                                regulator-name = "PVDD_CAM0_AVDD_2V8";
                                regulator-min-microvolt = <2800000>;
 
 &mmc_0 {
        status = "okay";
-       broken-cd;
+       non-removable;
        card-detect-delay = <200>;
        samsung,dw-mshc-ciu-div = <3>;
        samsung,dw-mshc-sdr-timing = <0 4>;
        pinctrl-names = "default";
        pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>;
        vmmc-supply = <&ldo10_reg>;
+       vqmmc-supply = <&ldo3_reg>;
        bus-width = <8>;
        cap-mmc-highspeed;
+       mmc-hs200-1_8v;
 };
 
 &mmc_2 {
        status = "okay";
        card-detect-delay = <200>;
        samsung,dw-mshc-ciu-div = <3>;
-       samsung,dw-mshc-sdr-timing = <2 3>;
-       samsung,dw-mshc-ddr-timing = <1 2>;
+       samsung,dw-mshc-sdr-timing = <0 4>;
+       samsung,dw-mshc-ddr-timing = <0 2>;
        pinctrl-names = "default";
        pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus1 &sd2_bus4>;
        vmmc-supply = <&ldo19_reg>;
        vqmmc-supply = <&ldo13_reg>;
        bus-width = <4>;
        cap-sd-highspeed;
+       sd-uhs-sdr50;
+       sd-uhs-sdr104;
+       sd-uhs-ddr50;
 };
 
 &pinctrl_0 {
        clocks = <&clock CLK_RTC>, <&s2mps11_osc S2MPS11_CLK_AP>;
        clock-names = "rtc", "rtc_src";
 };
+
+&usbdrd_dwc3_1 {
+       dr_mode = "host";
+};
index 3cf9050478937a364708039661e43506589dc704..8240e51869729b1cd9343241dd4a0d54771eb37c 100644 (file)
@@ -21,7 +21,8 @@
        };
 
        chosen {
-               bootargs = "console=ttySAC2,115200 init=/linuxrc";
+               bootargs = "init=/linuxrc";
+               stdout-path = "serial2:115200n8";
        };
 
        fixed-rate-clocks {
index aaff1588076136728926c96c6c07e749b6d7064c..5fb2326875dcb72576a9930ad63dcaaa69e57689 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com
  *
- * SAMSUNG EXYNOS54200 SoC device nodes are listed in this file.
+ * SAMSUNG EXYNOS5420 SoC device nodes are listed in this file.
  * EXYNOS5420 based board files can include this file and provide
  * values for board specfic bindings.
  */
index 51a843bd65ed135cbe92db28e84034bd93dfb4d9..c3c2d85267da693434323816d8f0920fbd3fb36c 100644 (file)
                        "Headphone Jack", "HPL",
                        "Headphone Jack", "HPR",
                        "Headphone Jack", "MICBIAS",
-                       "IN1", "Headphone Jack",
+                       "IN12", "Headphone Jack",
                        "Speakers", "SPKL",
                        "Speakers", "SPKR",
                        "I2S Playback", "Mixer DAI TX",
-                       "HiFi Playback", "Mixer DAI TX";
+                       "HiFi Playback", "Mixer DAI TX",
+                       "Mixer DAI RX", "HiFi Capture";
 
                assigned-clocks = <&clock CLK_MOUT_EPLL>,
                                <&clock CLK_MOUT_MAU_EPLL>,
index 5f195ad7e4676205fef8aa00827031cc19121ebb..93a48f2dda49c5e3faf33f1b7b8f6652393be638 100644 (file)
@@ -44,8 +44,6 @@
        fan0: pwm-fan {
                compatible = "pwm-fan";
                pwms = <&pwm 0 20972 0>;
-               cooling-min-state = <0>;
-               cooling-max-state = <3>;
                #cooling-cells = <2>;
                cooling-levels = <0 130 170 230>;
        };
index de26e5ee0d2de390d935090ea9950eda9c571876..ae866bcc30c4e3c029b96e7d41e79fe4ce9c6729 100644 (file)
                usbdrdphy1 = &usbdrd_phy1;
        };
 
-       soc: soc {
-               arm_a7_pmu: arm-a7-pmu {
-                       compatible = "arm,cortex-a7-pmu";
-                       interrupt-parent = <&gic>;
-                       interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
-                       status = "disabled";
-               };
+       arm_a7_pmu: arm-a7-pmu {
+               compatible = "arm,cortex-a7-pmu";
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+               status = "disabled";
+       };
 
-               arm_a15_pmu: arm-a15-pmu {
-                       compatible = "arm,cortex-a15-pmu";
-                       interrupt-parent = <&combiner>;
-                       interrupts = <1 2>,
-                                    <7 0>,
-                                    <16 6>,
-                                    <19 2>;
-                       status = "disabled";
-               };
+       arm_a15_pmu: arm-a15-pmu {
+               compatible = "arm,cortex-a15-pmu";
+               interrupt-parent = <&combiner>;
+               interrupts = <1 2>,
+                            <7 0>,
+                            <16 6>,
+                            <19 2>;
+               status = "disabled";
+       };
 
+       soc: soc {
                sysram@2020000 {
                        compatible = "mmio-sram";
                        reg = <0x02020000 0x54000>;
index 592111c8d6fdfcd299a316b2bf02d757c6f40cef..cfbfbc91a1e1a23ebd9c91f2153ee8f17bea4fdf 100644 (file)
                        /* 32MB of flash */
                        reg = <0x30000000 0x02000000>;
 
-                       /*
-                        * This "RedBoot" is the Storlink derivative.
-                        */
-                       partition@0 {
-                               label = "RedBoot";
-                               reg = <0x00000000 0x00040000>;
-                               read-only;
-                       };
-                       /*
-                        * This firmware image contains the kernel catenated
-                        * with the squashfs root filesystem. For some reason
-                        * this is called "upgrade" on the vendor system.
-                        */
-                       partition@40000 {
-                               label = "upgrade";
-                               reg = <0x00040000 0x01f40000>;
-                               read-only;
-                       };
-                       /* RGDB, Residental Gateway Database? */
-                       partition@1f80000 {
-                               label = "rgdb";
-                               reg = <0x01f80000 0x00040000>;
-                               read-only;
-                       };
-                       /*
-                        * This partition contains MAC addresses for WAN,
-                        * WLAN and LAN, and the country code (for wireless
-                        * I guess).
-                        */
-                       partition@1fc0000 {
-                               label = "nvram";
-                               reg = <0x01fc0000 0x00020000>;
-                               read-only;
-                       };
-                       partition@1fe0000 {
-                               label = "LangPack";
-                               reg = <0x01fe0000 0x00020000>;
-                               read-only;
+                       partitions {
+                               compatible = "fixed-partitions";
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+
+                               /*
+                                * This "RedBoot" is the Storlink derivative.
+                                */
+                               partition@0 {
+                                       label = "RedBoot";
+                                       reg = <0x00000000 0x00040000>;
+                                       read-only;
+                               };
+                               /*
+                                * This firmware image contains the kernel catenated
+                                * with the squashfs root filesystem. For some reason
+                                * this is called "upgrade" on the vendor system.
+                                */
+                               partition@40000 {
+                                       label = "upgrade";
+                                       reg = <0x00040000 0x01f40000>;
+                                       read-only;
+                               };
+                               /* RGDB, Residental Gateway Database? */
+                               partition@1f80000 {
+                                       label = "rgdb";
+                                       reg = <0x01f80000 0x00040000>;
+                                       read-only;
+                               };
+                               /*
+                                * This partition contains MAC addresses for WAN,
+                                * WLAN and LAN, and the country code (for wireless
+                                * I guess).
+                                */
+                               partition@1fc0000 {
+                                       label = "nvram";
+                                       reg = <0x01fc0000 0x00020000>;
+                                       read-only;
+                               };
+                               partition@1fe0000 {
+                                       label = "LangPack";
+                                       reg = <0x01fe0000 0x00020000>;
+                                       read-only;
+                               };
                        };
                };
 
index 59cadeee23eddcfe1271654539b9375326d652d0..9cbdc1a15cda21aca4d277c86fea1496a1acaced 100644 (file)
                gpio0 = &gpio1;
                gpio1 = &gpio2;
                gpio2 = &gpio3;
+               i2c0 = &i2c1;
+               i2c1 = &i2c2;
+               i2c2 = &i2c3;
+               mmc0 = &esdhc1;
+               mmc1 = &esdhc2;
+               mmc2 = &esdhc3;
                serial0 = &uart1;
                serial1 = &uart2;
                serial2 = &uart3;
diff --git a/arch/arm/boot/dts/imx50-kobo-aura.dts b/arch/arm/boot/dts/imx50-kobo-aura.dts
new file mode 100644 (file)
index 0000000..a0eaf86
--- /dev/null
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2019 Jonathan Neuschäfer
+//
+// The Kobo Aura e-book reader, model N514. The mainboard is marked as E606F0B.
+
+/dts-v1/;
+#include "imx50.dtsi"
+#include <dt-bindings/input/input.h>
+
+/ {
+       model = "Kobo Aura (N514)";
+       compatible = "kobo,aura", "fsl,imx50";
+
+       chosen {
+               stdout-path = "serial1:115200n8";
+       };
+
+       memory@70000000 {
+               device_type = "memory";
+               reg = <0x70000000 0x10000000>;
+       };
+
+       gpio-leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_leds>;
+
+               on {
+                       label = "kobo_aura:orange:on";
+                       gpios = <&gpio6 24 GPIO_ACTIVE_LOW>;
+                       panic-indicator;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpiokeys>;
+
+               power {
+                       label = "Power Button";
+                       gpios = <&gpio4 10 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_POWER>;
+               };
+
+               hallsensor {
+                       label = "Hallsensor";
+                       gpios = <&gpio5 15 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESERVED>;
+                       linux,input-type = <EV_SW>;
+               };
+
+               frontlight {
+                       label = "Frontlight";
+                       gpios = <&gpio4 1 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_DISPLAYTOGGLE>;
+               };
+       };
+
+       sd2_pwrseq: pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_sd2_reset>;
+               reset-gpios = <&gpio4 17 GPIO_ACTIVE_LOW>;
+       };
+
+       sd2_vmmc: gpio-regulator {
+               compatible = "regulator-gpio";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_sd2_vmmc>;
+               regulator-name = "vmmc";
+               states = <3300000 0>;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               enable-gpio = <&gpio4 12 GPIO_ACTIVE_LOW>;
+               startup-delay-us = <100000>;
+       };
+};
+
+&esdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sd1>;
+       max-frequency = <50000000>;
+       bus-width = <4>;
+       cd-gpios = <&gpio5 17 GPIO_ACTIVE_LOW>;
+       disable-wp;
+       status = "okay";
+
+       /* External µSD card */
+};
+
+&esdhc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sd2>;
+       bus-width = <4>;
+       max-frequency = <50000000>;
+       disable-wp;
+       mmc-pwrseq = <&sd2_pwrseq>;
+       vmmc-supply = <&sd2_vmmc>;
+       status = "okay";
+
+       /* CyberTan WC121 SDIO WiFi (BCM43362) */
+};
+
+&esdhc3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sd3>;
+       bus-width = <8>;
+       non-removable;
+       max-frequency = <50000000>;
+       disable-wp;
+       status = "okay";
+
+       /* Internal eMMC */
+};
+
+&i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+
+       /* TODO: ektf2132 touch controller at 0x15 */
+};
+
+&i2c2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       status = "okay";
+
+       /* TODO: TPS65185 PMIC for E Ink at 0x68 */
+};
+
+&i2c3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       status = "okay";
+
+       /* TODO: embedded controller at 0x43 */
+};
+
+&iomuxc {
+       pinctrl_gpiokeys: gpiokeys {
+               fsl,pins = <
+                       MX50_PAD_CSPI_MISO__GPIO4_10            0x0
+                       MX50_PAD_SD2_D7__GPIO5_15               0x0
+                       MX50_PAD_KEY_ROW0__GPIO4_1              0x0
+               >;
+       };
+
+       pinctrl_i2c1: i2c1 {
+               fsl,pins = <
+                       MX50_PAD_I2C1_SCL__I2C1_SCL             0x400001fd
+                       MX50_PAD_I2C1_SDA__I2C1_SDA             0x400001fd
+               >;
+       };
+
+       pinctrl_i2c2: i2c2 {
+               fsl,pins = <
+                       MX50_PAD_I2C2_SCL__I2C2_SCL             0x400001fd
+                       MX50_PAD_I2C2_SDA__I2C2_SDA             0x400001fd
+               >;
+       };
+
+       pinctrl_i2c3: i2c3 {
+               fsl,pins = <
+                       MX50_PAD_I2C3_SCL__I2C3_SCL             0x400001fd
+                       MX50_PAD_I2C3_SDA__I2C3_SDA             0x400001fd
+               >;
+       };
+
+       pinctrl_leds: leds {
+               fsl,pins = <
+                       MX50_PAD_PWM1__GPIO6_24                 0x0
+               >;
+       };
+
+       pinctrl_sd1: sd1 {
+               fsl,pins = <
+                       MX50_PAD_SD1_CMD__ESDHC1_CMD            0x1e4
+                       MX50_PAD_SD1_CLK__ESDHC1_CLK            0xd4
+                       MX50_PAD_SD1_D0__ESDHC1_DAT0            0x1d4
+                       MX50_PAD_SD1_D1__ESDHC1_DAT1            0x1d4
+                       MX50_PAD_SD1_D2__ESDHC1_DAT2            0x1d4
+                       MX50_PAD_SD1_D3__ESDHC1_DAT3            0x1d4
+
+                       MX50_PAD_SD2_CD__GPIO5_17               0x0
+               >;
+       };
+
+       pinctrl_sd2: sd2 {
+               fsl,pins = <
+                       MX50_PAD_SD2_CMD__ESDHC2_CMD            0x1e4
+                       MX50_PAD_SD2_CLK__ESDHC2_CLK            0xd4
+                       MX50_PAD_SD2_D0__ESDHC2_DAT0            0x1d4
+                       MX50_PAD_SD2_D1__ESDHC2_DAT1            0x1d4
+                       MX50_PAD_SD2_D2__ESDHC2_DAT2            0x1d4
+                       MX50_PAD_SD2_D3__ESDHC2_DAT3            0x1d4
+               >;
+       };
+
+       pinctrl_sd2_reset: sd2-reset {
+               fsl,pins = <
+                       MX50_PAD_ECSPI2_MOSI__GPIO4_17          0x0
+               >;
+       };
+
+       pinctrl_sd2_vmmc: sd2-vmmc {
+               fsl,pins = <
+                       MX50_PAD_ECSPI1_SCLK__GPIO4_12          0x0
+               >;
+       };
+
+       pinctrl_sd3: sd3 {
+               fsl,pins = <
+                       MX50_PAD_SD3_CMD__ESDHC3_CMD            0x1e4
+                       MX50_PAD_SD3_CLK__ESDHC3_CLK            0xd4
+                       MX50_PAD_SD3_D0__ESDHC3_DAT0            0x1d4
+                       MX50_PAD_SD3_D1__ESDHC3_DAT1            0x1d4
+                       MX50_PAD_SD3_D2__ESDHC3_DAT2            0x1d4
+                       MX50_PAD_SD3_D3__ESDHC3_DAT3            0x1d4
+                       MX50_PAD_SD3_D4__ESDHC3_DAT4            0x1d4
+                       MX50_PAD_SD3_D5__ESDHC3_DAT5            0x1d4
+                       MX50_PAD_SD3_D6__ESDHC3_DAT6            0x1d4
+                       MX50_PAD_SD3_D7__ESDHC3_DAT7            0x1d4
+               >;
+       };
+
+       pinctrl_uart2: uart2 {
+               fsl,pins = <
+                       MX50_PAD_UART2_TXD__UART2_TXD_MUX       0x1e4
+                       MX50_PAD_UART2_RXD__UART2_RXD_MUX       0x1e4
+               >;
+       };
+
+       pinctrl_usbphy: usbphy {
+               fsl,pins = <
+                       MX50_PAD_ECSPI2_SS0__GPIO4_19           0x0
+               >;
+       };
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       status = "okay";
+};
+
+&usbotg {
+       phy_type = "utmi_wide";
+       dr_mode = "peripheral";
+       status = "okay";
+};
+
+&usbphy0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbphy>;
+       vbus-detect-gpio = <&gpio4 19 GPIO_ACTIVE_LOW>;
+};
index ee1e3e8bf4ecbc77325717c694c075890ac23c48..0bfe7c91d0eb291a395f355ba461048c13c9fd6e 100644 (file)
                gpio3 = &gpio4;
                gpio4 = &gpio5;
                gpio5 = &gpio6;
+               i2c0 = &i2c1;
+               i2c1 = &i2c2;
+               i2c2 = &i2c3;
+               mmc0 = &esdhc1;
+               mmc1 = &esdhc2;
+               mmc2 = &esdhc3;
+               mmc3 = &esdhc4;
                serial0 = &uart1;
                serial1 = &uart2;
                serial2 = &uart3;
                serial3 = &uart4;
                serial4 = &uart5;
+               spi0 = &ecspi1;
+               spi1 = &ecspi2;
+               spi2 = &cspi;
        };
 
        cpus {
                };
        };
 
+       usbphy0: usbphy-0 {
+               compatible = "usb-nop-xceiv";
+               clocks = <&clks IMX5_CLK_USB_PHY1_GATE>;
+               clock-names = "main_clk";
+               #phy-cells = <0>;
+               status = "okay";
+       };
+
        soc {
                #address-cells = <1>;
                #size-cells = <1>;
                                compatible = "fsl,imx50-usb", "fsl,imx27-usb";
                                reg = <0x53f80000 0x0200>;
                                interrupts = <18>;
-                               clocks = <&clks IMX5_CLK_USB_PHY1_GATE>;
+                               clocks = <&clks IMX5_CLK_USBOH3_GATE>;
+                               fsl,usbphy = <&usbphy0>;
                                status = "disabled";
                        };
 
                                reg = <0x63fb0000 0x4000>;
                                interrupts = <6>;
                                clocks = <&clks IMX5_CLK_SDMA_GATE>,
-                                        <&clks IMX5_CLK_SDMA_GATE>;
+                                        <&clks IMX5_CLK_AHB>;
                                clock-names = "ipg", "ahb";
                                #dma-cells = <3>;
                                fsl,sdma-ram-script-name = "imx/sdma/sdma-imx50.bin";
index a8220f08dcbfb9dd9e0583c319cb64867ee4ec76..3596060f52e78e52f0c3197888e98f943f629d38 100644 (file)
@@ -1,42 +1,6 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
 /*
  * Copyright (C) 2017 Zodiac Inflight Innovations
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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.
- *
- *     This file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 , 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 
 /dts-v1/;
index a5ee25cedc10e37939c5c5e20875403c88d418f4..0a4b9a5d9a9c9698fd71c5e4b6378a6fc77659c5 100644 (file)
                                reg = <0x83fb0000 0x4000>;
                                interrupts = <6>;
                                clocks = <&clks IMX5_CLK_SDMA_GATE>,
-                                        <&clks IMX5_CLK_SDMA_GATE>;
+                                        <&clks IMX5_CLK_AHB>;
                                clock-names = "ipg", "ahb";
                                #dma-cells = <3>;
                                fsl,sdma-ram-script-name = "imx/sdma/sdma-imx51.bin";
index db2e5bce9b6a1dad7eb3b58520868ddf1099fcc0..d1770e1d5e50300015cd3955752a4884b29ec9d1 100644 (file)
@@ -52,7 +52,7 @@
        clock-frequency = <400000>;
        status = "okay";
 
-       stmpe610@41 {
+       touchscreen@41 {
                compatible = "st,stmpe610";
                reg = <0x41>;
                id = <0>;
diff --git a/arch/arm/boot/dts/imx53-m53menlo.dts b/arch/arm/boot/dts/imx53-m53menlo.dts
new file mode 100644 (file)
index 0000000..f0a3fde
--- /dev/null
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2019 Marek Vasut <marex@denx.de>
+ */
+
+/dts-v1/;
+#include "imx53-m53.dtsi"
+
+/ {
+       model = "MENLO M53 EMBEDDED DEVICE";
+       compatible = "menlo,m53menlo", "fsl,imx53";
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_led>;
+
+               user1 {
+                       label = "TestLed601";
+                       gpios = <&gpio6 1 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "mmc0";
+               };
+
+               user2 {
+                       label = "TestLed602";
+                       gpios = <&gpio6 2 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+               };
+
+               eth {
+                       label = "EthLedYe";
+                       gpios = <&gpio2 11 GPIO_ACTIVE_LOW>;
+                       linux,default-trigger = "none";
+               };
+       };
+
+       panel {
+               compatible = "edt,etm070080dh6";
+               enable-gpios = <&gpio6 0 GPIO_ACTIVE_HIGH>;
+
+               port {
+                       panel_in: endpoint {
+                               remote-endpoint = <&lvds0_out>;
+                       };
+               };
+       };
+
+       reg_usbh1_vbus: regulator-usbh1-vbus {
+               compatible = "regulator-fixed";
+               regulator-name = "vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpio1 2 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&can1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_can1>;
+       status = "okay";
+};
+
+&can2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_can2>;
+       status = "okay";
+};
+
+&clks {
+       assigned-clocks = <&clks IMX5_CLK_CKO1_SEL>,
+                         <&clks IMX5_CLK_CKO1_PODF>,
+                         <&clks IMX5_CLK_CKO1>;
+       assigned-clock-parents = <&clks IMX5_CLK_AHB>;
+       assigned-clock-rates = <133333334>, <33333334>, <33333334>;
+};
+
+&esdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_esdhc1>;
+       cd-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+};
+
+&fec {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec>;
+       phy-mode = "rmii";
+       status = "okay";
+};
+
+&i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+
+       touchscreen@38 {
+               compatible = "edt,edt-ft5x06";
+               reg = <0x38>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_edt_ft5x06>;
+               interrupt-parent = <&gpio6>;
+               interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
+               reset-gpios = <&gpio2 9 GPIO_ACTIVE_LOW>;
+               wake-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+               pagesize = <32>;
+       };
+
+       dac@60 {
+               compatible = "microchip,mcp4725";
+               reg = <0x60>;
+       };
+};
+
+&i2c2 {
+       touchscreen@41 {
+               status = "disabled";
+       };
+};
+
+&i2c3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hog>;
+
+       imx53-m53evk {
+               hoggrp {
+                       fsl,pins = <
+                               MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK       0x1c4
+                               MX53_PAD_EIM_EB3__GPIO2_31              0x1d5
+                               MX53_PAD_PATA_DA_0__GPIO7_6             0x1d5
+                               MX53_PAD_GPIO_19__CCM_CLKO              0x1d5
+                               MX53_PAD_CSI0_MCLK__CCM_CSI0_MCLK       0x1d5
+                               MX53_PAD_CSI0_DAT4__GPIO5_22            0x1d5
+                               MX53_PAD_CSI0_DAT5__GPIO5_23            0x1d5
+                               MX53_PAD_CSI0_DAT6__GPIO5_24            0x1d5
+                               MX53_PAD_CSI0_DAT7__GPIO5_25            0x1d5
+                               MX53_PAD_CSI0_DAT8__GPIO5_26            0x1d5
+                               MX53_PAD_CSI0_DAT9__GPIO5_27            0x1d5
+                               MX53_PAD_CSI0_DAT10__GPIO5_28           0x1d5
+                               MX53_PAD_CSI0_DAT11__GPIO5_29           0x1d5
+                               MX53_PAD_CSI0_DAT14__GPIO6_0            0x1d5
+                       >;
+               };
+
+               pinctrl_led: ledgrp {
+                       fsl,pins = <
+                               MX53_PAD_CSI0_DAT15__GPIO6_1            0x1d5
+                               MX53_PAD_CSI0_DAT16__GPIO6_2            0x1d5
+                       >;
+               };
+
+               pinctrl_can1: can1grp {
+                       fsl,pins = <
+                               MX53_PAD_GPIO_7__CAN1_TXCAN             0x1c4
+                               MX53_PAD_GPIO_8__CAN1_RXCAN             0x1c4
+                       >;
+               };
+
+               pinctrl_can2: can2grp {
+                       fsl,pins = <
+                               MX53_PAD_KEY_COL4__CAN2_TXCAN           0x1c4
+                               MX53_PAD_KEY_ROW4__CAN2_RXCAN           0x1c4
+                       >;
+               };
+
+               pinctrl_display_gpio: display-gpiogrp {
+                       fsl,pins = <
+                               MX53_PAD_CSI0_DAT12__GPIO5_30           0x1d5 /* Reset */
+                               MX53_PAD_CSI0_DAT13__GPIO5_31           0x1d5 /* Interrupt */
+                       >;
+               };
+
+               pinctrl_edt_ft5x06: edt-ft5x06grp {
+                       fsl,pins = <
+                               MX53_PAD_PATA_DATA9__GPIO2_9            0x1d5 /* Reset */
+                               MX53_PAD_CSI0_DAT19__GPIO6_5            0x1d5 /* Interrupt */
+                               MX53_PAD_PATA_DATA10__GPIO2_10          0x1d5 /* Wake */
+                       >;
+               };
+
+               pinctrl_esdhc1: esdhc1grp {
+                       fsl,pins = <
+                               MX53_PAD_SD1_DATA0__ESDHC1_DAT0         0x1d5
+                               MX53_PAD_SD1_DATA1__ESDHC1_DAT1         0x1d5
+                               MX53_PAD_SD1_DATA2__ESDHC1_DAT2         0x1d5
+                               MX53_PAD_SD1_DATA3__ESDHC1_DAT3         0x1d5
+                               MX53_PAD_SD1_CMD__ESDHC1_CMD            0x1d5
+                               MX53_PAD_SD1_CLK__ESDHC1_CLK            0x1d5
+                       >;
+               };
+
+               pinctrl_fec: fecgrp {
+                       fsl,pins = <
+                               MX53_PAD_FEC_MDC__FEC_MDC               0x4
+                               MX53_PAD_FEC_MDIO__FEC_MDIO             0x1fc
+                               MX53_PAD_FEC_REF_CLK__FEC_TX_CLK        0x180
+                               MX53_PAD_FEC_RX_ER__FEC_RX_ER           0x180
+                               MX53_PAD_FEC_CRS_DV__FEC_RX_DV          0x180
+                               MX53_PAD_FEC_RXD1__FEC_RDATA_1          0x180
+                               MX53_PAD_FEC_RXD0__FEC_RDATA_0          0x180
+                               MX53_PAD_FEC_TX_EN__FEC_TX_EN           0x4
+                               MX53_PAD_FEC_TXD1__FEC_TDATA_1          0x4
+                               MX53_PAD_FEC_TXD0__FEC_TDATA_0          0x4
+                       >;
+               };
+
+               pinctrl_i2c1: i2c1grp {
+                       fsl,pins = <
+                               MX53_PAD_EIM_D21__I2C1_SCL              0x400001e4
+                               MX53_PAD_EIM_D28__I2C1_SDA              0x400001e4
+                       >;
+               };
+
+               pinctrl_i2c3: i2c3grp {
+                       fsl,pins = <
+                               MX53_PAD_GPIO_6__I2C3_SDA               0x400001e4
+                               MX53_PAD_GPIO_5__I2C3_SCL               0x400001e4
+                       >;
+               };
+
+               pinctrl_lvds0: lvds0grp {
+                       /* LVDS pins only have pin mux configuration */
+                       fsl,pins = <
+                               MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK     0x80000000
+                               MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0     0x80000000
+                               MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1     0x80000000
+                               MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2     0x80000000
+                               MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3     0x80000000
+                       >;
+               };
+
+               pinctrl_uart1: uart1grp {
+                       fsl,pins = <
+                               MX53_PAD_PATA_DIOW__UART1_TXD_MUX       0x1e4
+                               MX53_PAD_PATA_DMACK__UART1_RXD_MUX      0x1e4
+                       >;
+               };
+
+               pinctrl_uart2: uart2grp {
+                       fsl,pins = <
+                               MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX  0x1e4
+                               MX53_PAD_PATA_DMARQ__UART2_TXD_MUX      0x1e4
+                       >;
+               };
+
+               pinctrl_usb: usbgrp {
+                       fsl,pins = <
+                               MX53_PAD_GPIO_2__GPIO1_2                0x1d5
+                               MX53_PAD_GPIO_3__USBOH3_USBH1_OC        0x1d5
+                       >;
+               };
+       };
+};
+
+&ldb {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_lvds0>;
+       status = "okay";
+
+       lvds0: lvds-channel@0 {
+               reg = <0>;
+               fsl,data-mapping = "spwg";
+               fsl,data-width = <18>;
+               status = "okay";
+
+               port@2 {
+                       reg = <2>;
+
+                       lvds0_out: endpoint {
+                               remote-endpoint = <&panel_in>;
+                       };
+               };
+       };
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       status = "okay";
+};
+
+&usbh1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usb>;
+       vbus-supply = <&reg_usbh1_vbus>;
+       phy_type = "utmi";
+       dr_mode = "peripheral";
+       status = "okay";
+};
+
+&usbotg {
+       dr_mode = "peripheral";
+       status = "okay";
+};
index b3300300aabef142f081b9261a87f8861c28a993..9b672ed2486d12b87872d4b355a109c54c5320ef 100644 (file)
                                reg = <0x63fb0000 0x4000>;
                                interrupts = <6>;
                                clocks = <&clks IMX5_CLK_SDMA_GATE>,
-                                        <&clks IMX5_CLK_SDMA_GATE>;
+                                        <&clks IMX5_CLK_AHB>;
                                clock-names = "ipg", "ahb";
                                #dma-cells = <3>;
                                fsl,sdma-ram-script-name = "imx/sdma/sdma-imx53.bin";
index fb01fa6e422442e00bf087dcd73843ca4d22cba5..2a6ce87071f9eec7709de4f39b3d571dc6201edf 100644 (file)
@@ -88,6 +88,7 @@
                regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
                gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>;
+               startup-delay-us = <70000>;
                enable-active-high;
        };
 
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
                gpio = <&gpio1 26 GPIO_ACTIVE_HIGH>;
+               startup-delay-us = <70000>;
                enable-active-high;
                regulator-always-on;
        };
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-reset-duration = <10>;
        phy-reset-gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
        phy-supply = <&reg_enet>;
                gpio-cfg = <
                        0x0000 /* 0:Default */
                        0x0000 /* 1:Default */
-                       0x0013 /* 2:FN_DMICCLK */
+                       0x0000 /* 2:FN_DMICCLK */
                        0x0000 /* 3:Default */
-                       0x8014 /* 4:FN_DMICCDAT */
+                       0x0000 /* 4:FN_DMICCDAT */
                        0x0000 /* 5:Default */
                >;
        };
diff --git a/arch/arm/boot/dts/imx6dl-eckelmann-ci4x10.dts b/arch/arm/boot/dts/imx6dl-eckelmann-ci4x10.dts
new file mode 100644 (file)
index 0000000..9eb2b73
--- /dev/null
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016 Eckelmann AG.
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+#include "imx6dl.dtsi"
+
+/ {
+       model = "Eckelmann CI 4X10 Board";
+       compatible = "eckelmann,imx6dl-ci4x10", "fsl,imx6dl";
+
+       chosen {
+               stdout-path = &uart3;
+       };
+
+       memory@10000000 {
+               device_type = "memory";
+               reg = <0x10000000 0x40000000>;
+       };
+
+       rmii_clk: clock-rmii {
+               /* This clock is provided by the phy (KSZ8091RNB) */
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <50000000>;
+       };
+
+       reg_usb_h1_vbus: regulator-usb-h1-vbus {
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_usb_h1_vbus>;
+               compatible = "regulator-fixed";
+               regulator-name = "usb_h1_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpio3 31 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       siox {
+               compatible = "eckelmann,siox-gpio";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_siox>;
+               din-gpios = <&gpio6 11 GPIO_ACTIVE_HIGH>;
+               dout-gpios = <&gpio6 8 GPIO_ACTIVE_HIGH>;
+               dclk-gpios = <&gpio6 9 GPIO_ACTIVE_HIGH>;
+               dld-gpios = <&gpio6 10 GPIO_ACTIVE_HIGH>;
+       };
+};
+
+&can1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan1>;
+       status = "okay";
+};
+
+&can2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan2>;
+       status = "okay";
+};
+
+&ecspi2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi2>;
+       cs-gpios = <&gpio5 12 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+
+       flash@0 {
+               compatible = "everspin,mr25h256";
+               reg = <0>;
+               spi-max-frequency = <15000000>;
+       };
+};
+
+&ecspi1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi1>;
+       cs-gpios = <&gpio5 25 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+
+       tpm@0 {
+               compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
+               reg = <0>;
+               spi-max-frequency = <10000000>;
+       };
+};
+
+&gpio2 {
+       gpio-line-names = "buzzer", "", "", "", "", "", "", "",
+                         "", "", "", "", "", "", "", "",
+                         "", "", "", "", "", "", "", "",
+                         "", "", "", "", "", "", "", "";
+};
+
+&gpio4 {
+       gpio-line-names = "", "", "", "", "", "", "", "in2",
+                         "prio2", "prio1", "aux", "", "", "", "", "",
+                         "", "", "", "", "", "", "", "",
+                         "", "", "", "", "", "", "", "";
+};
+
+&gpio6 {
+       gpio-line-names = "", "", "", "", "", "", "", "",
+                         "", "", "", "", "", "", "", "in1",
+                         "", "", "", "", "", "", "", "",
+                         "", "", "", "", "", "", "", "";
+};
+
+&i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+
+       temperature-sensor@49 {
+               compatible = "ad,ad7414";
+               reg = <0x49>;
+       };
+
+       rtc@51 {
+               compatible = "nxp,pcf2127";
+               reg = <0x51>;
+       };
+};
+
+&iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hog>;
+
+       pinctrl_hog: hog {
+               fsl,pins = <
+                       MX6QDL_PAD_NANDF_D0__GPIO2_IO00         0x00000018 /* buzzer */
+                       MX6QDL_PAD_KEY_COL1__GPIO4_IO08         0x00000018 /* OUT_1 */
+                       MX6QDL_PAD_KEY_ROW1__GPIO4_IO09         0x00000018 /* OUT_2 */
+                       MX6QDL_PAD_KEY_COL2__GPIO4_IO10         0x00000018 /* OUT_3 */
+                       MX6QDL_PAD_NANDF_CS2__GPIO6_IO15        0x00000000 /* In1 */
+                       MX6QDL_PAD_KEY_ROW0__GPIO4_IO07         0x00000000 /* In2 */
+                       MX6QDL_PAD_GPIO_9__GPIO1_IO09           0x00000018 /* unused watchdog pin */
+                       MX6QDL_PAD_SD1_DAT2__GPIO1_IO19         0x00000018 /* unused watchdog pin */
+
+               >;
+       };
+
+       pinctrl_ecspi1: ecspi1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT4__ECSPI1_SCLK       0x000100a0
+                       MX6QDL_PAD_CSI0_DAT5__ECSPI1_MOSI       0x000100a0
+                       MX6QDL_PAD_CSI0_DAT6__ECSPI1_MISO       0x000100a0
+                       MX6QDL_PAD_CSI0_DAT7__GPIO5_IO25        0x000100a0
+               >;
+       };
+
+       pinctrl_ecspi2: ecspi2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_DISP0_DAT19__ECSPI2_SCLK     0x000100b1
+                       MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI         0x000100b1
+                       MX6QDL_PAD_EIM_OE__ECSPI2_MISO          0x000100b1
+                       MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12      0x000100b1
+               >;
+       };
+
+       pinctrl_enet: enetgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_16__ENET_REF_CLK        0x4001b0a8
+                       MX6QDL_PAD_ENET_MDIO__ENET_MDIO         0x0001b098
+                       MX6QDL_PAD_ENET_MDC__ENET_MDC           0x0001b098
+                       MX6QDL_PAD_ENET_TXD0__ENET_TX_DATA0     0x0001b098
+                       MX6QDL_PAD_ENET_TXD1__ENET_TX_DATA1     0x0001b098
+                       MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN       0x0001b098
+                       MX6QDL_PAD_ENET_RX_ER__ENET_RX_ER       0x0001b0b0
+                       MX6QDL_PAD_ENET_RXD0__ENET_RX_DATA0     0x0001b0b0
+                       MX6QDL_PAD_ENET_RXD1__ENET_RX_DATA1     0x0001b0b0
+                       MX6QDL_PAD_ENET_CRS_DV__ENET_RX_EN      0x0001b0b0
+                       MX6QDL_PAD_SD1_CMD__GPIO1_IO18          0x00000018
+               >;
+       };
+
+       pinctrl_flexcan1: flexcan1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_7__FLEXCAN1_TX          0x0001b020
+                       MX6QDL_PAD_GPIO_8__FLEXCAN1_RX          0x0001b0b0
+               >;
+       };
+
+       pinctrl_flexcan2: flexcan2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX        0x0001b020
+                       MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX        0x0001b0b0
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       /* without SION i2c doesn't detect bus busy */
+                       MX6QDL_PAD_CSI0_DAT9__I2C1_SCL          0x4001b820
+                       MX6QDL_PAD_CSI0_DAT8__I2C1_SDA          0x4001b820
+               >;
+       };
+
+       pinctrl_pcie: pciegrp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD1_CLK__GPIO1_IO20          0x00000018
+               >;
+       };
+
+       pinctrl_reg_usb_h1_vbus: reg_usb_h1_vbusgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D31__GPIO3_IO31          0x0001b0b0
+               >;
+       };
+
+       pinctrl_siox: sioxgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_NANDF_CS0__GPIO6_IO11        0x0001b010      /* DIN */
+                       MX6QDL_PAD_NANDF_ALE__GPIO6_IO08        0x0001b010      /* DOUT */
+                       MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09       0x0001b010      /* DCLK */
+                       MX6QDL_PAD_NANDF_RB0__GPIO6_IO10        0x0001b010      /* DLD */
+               >;
+       };
+
+       pinctrl_uart1_dte: uart1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT11__UART1_TX_DATA    0x0001b010
+                       MX6QDL_PAD_CSI0_DAT10__UART1_RX_DATA    0x0001b010
+                       MX6QDL_PAD_EIM_D19__UART1_RTS_B         0x0001b010
+                       MX6QDL_PAD_EIM_D20__UART1_CTS_B         0x0001b010
+                       MX6QDL_PAD_EIM_D23__GPIO3_IO23          0x0001b010      /* DCD */
+                       MX6QDL_PAD_EIM_D24__GPIO3_IO24          0x0001b010      /* DTR */
+                       MX6QDL_PAD_EIM_D25__GPIO3_IO25          0x0001b010      /* DSR */
+               >;
+       };
+
+       pinctrl_uart2_dte: uart2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D27__UART2_TX_DATA       0x0001b010
+                       MX6QDL_PAD_EIM_D26__UART2_RX_DATA       0x0001b010
+                       MX6QDL_PAD_EIM_D28__UART2_RTS_B         0x0001b010
+                       MX6QDL_PAD_EIM_D29__UART2_CTS_B         0x0001b010
+                       MX6QDL_PAD_NANDF_D1__GPIO2_IO01         0x0001b010      /* DCD */
+                       MX6QDL_PAD_GPIO_18__GPIO7_IO13          0x0001b010      /* DTR */
+                       MX6QDL_PAD_NANDF_CS3__GPIO6_IO16        0x0001b010      /* DSR */
+               >;
+       };
+
+       pinctrl_uart3_dce: uart3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_CLK__UART3_RX_DATA       0x0001b010
+                       MX6QDL_PAD_SD4_CMD__UART3_TX_DATA       0x0001b010
+               >;
+       };
+
+       pinctrl_uart4_dce: uart4grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA    0x0001b010
+                       MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA    0x0001b010
+                       MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03       0x0001b010
+               >;
+       };
+
+       pinctrl_uart5_dce: uart5grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT15__UART5_RX_DATA    0x0001b010
+                       MX6QDL_PAD_CSI0_DAT14__UART5_TX_DATA    0x0001b010
+                       MX6QDL_PAD_CSI0_DAT19__GPIO6_IO05       0x0001b010      /* RTS */
+               >;
+       };
+
+       pinctrl_usbh1: usbh1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D30__USB_H1_OC           0x0001b0b0
+               >;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_CMD__SD3_CMD             0x00017059
+                       MX6QDL_PAD_SD3_CLK__SD3_CLK             0x00010059
+                       MX6QDL_PAD_SD3_DAT0__SD3_DATA0          0x00017059
+                       MX6QDL_PAD_SD3_DAT1__SD3_DATA1          0x00017059
+                       MX6QDL_PAD_SD3_DAT2__SD3_DATA2          0x00017059
+                       MX6QDL_PAD_SD3_DAT3__SD3_DATA3          0x00017059
+                       MX6QDL_PAD_SD3_DAT4__SD3_DATA4          0x00017059
+                       MX6QDL_PAD_SD3_DAT5__SD3_DATA5          0x00017059
+                       MX6QDL_PAD_SD3_DAT6__SD3_DATA6          0x00017059
+                       MX6QDL_PAD_SD3_DAT7__SD3_DATA7          0x00017059
+               >;
+       };
+};
+
+&fec {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet>;
+       phy-mode = "rmii";
+       phy-reset-gpios = <&gpio1 18 GPIO_ACTIVE_LOW>;
+       phy-handle = <&phy>;
+       clocks = <&clks IMX6QDL_CLK_ENET>, <&clks IMX6QDL_CLK_ENET>, <&rmii_clk>;
+       status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               phy: ethernet-phy@1 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <1>;
+               };
+       };
+};
+
+&pcie {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie>;
+       reset-gpio = <&gpio1 20 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1_dte>;
+       uart-has-rtscts;
+       fsl,dte-mode;
+       dcd-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>;
+       dtr-gpios = <&gpio3 24 GPIO_ACTIVE_LOW>;
+       dsr-gpios = <&gpio3 25 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2_dte>;
+       uart-has-rtscts;
+       fsl,dte-mode;
+       dcd-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
+       dtr-gpios = <&gpio7 13 GPIO_ACTIVE_LOW>;
+       dsr-gpios = <&gpio6 16 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3_dce>;
+       status = "okay";
+};
+
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart4_dce>;
+       rts-gpios = <&gpio6 3 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+};
+
+&uart5 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart5_dce>;
+       rts-gpios = <&gpio6 5 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+};
+
+&usbh1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbh1>;
+       vbus-supply = <&reg_usb_h1_vbus>;
+       status = "okay";
+};
+
+&usbotg {
+       dr_mode = "peripheral";
+       status = "okay";
+};
+
+&usdhc3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc3>;
+       bus-width = <8>;
+       non-removable;
+       status = "okay";
+};
index 65c184bb8fb05b275d143d207ca4176b8dda3617..d9de49efa802d6705fddabb9a308eff710e1d553 100644 (file)
@@ -92,7 +92,7 @@
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-reset-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>;
        interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>,
                              <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>;
index 660d52a245babe5a3fd0f0aafe693a77e2339db5..ff3283c83a39443864baa99b932c7bbae44fe984 100644 (file)
        model = "Freescale i.MX6 DualLite/Solo SABRE Automotive Board";
        compatible = "fsl,imx6dl-sabreauto", "fsl,imx6dl";
 };
+
+&cpu0 {
+       operating-points = <
+               /* kHz    uV */
+               996000  1275000
+               792000  1175000
+               396000  1150000
+       >;
+       fsl,soc-operating-points = <
+               /* ARM kHz  SOC-PU uV */
+               996000  1200000
+               792000  1175000
+               396000  1175000
+       >;
+};
index adc9455e42c743f9c0ac835f30bbdfdd0765e188..37c63402157bf923e868a796e98c45becfa74aab 100644 (file)
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        status = "okay";
 };
 
index 56e5b5050fcfcc2e5f093593c95c5f7c944e1ad1..cb0a5f7d5a19caf45197d046d31712ad6ca42e42 100644 (file)
 /dts-v1/;
 #include "imx6q.dtsi"
 #include "imx6qdl-gw54xx.dtsi"
+#include <dt-bindings/media/tda1997x.h>
 
 / {
        model = "Gateworks Ventana i.MX6 Dual/Quad GW54XX";
        compatible = "gw,imx6q-gw54xx", "gw,ventana", "fsl,imx6q";
+
+       sound-digital {
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "tda1997x-audio";
+
+               simple-audio-card,dai-link@0 {
+                       format = "i2s";
+
+                       cpu {
+                               sound-dai = <&ssi2>;
+                       };
+
+                       codec {
+                               bitclock-master;
+                               frame-master;
+                               sound-dai = <&hdmi_receiver>;
+                       };
+               };
+       };
 };
 
 &i2c3 {
                        };
                };
        };
+
+       hdmi_receiver: hdmi-receiver@48 {
+               compatible = "nxp,tda19971";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_tda1997x>;
+               reg = <0x48>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+               DOVDD-supply = <&reg_3p3v>;
+               AVDD-supply = <&sw4_reg>;
+               DVDD-supply = <&sw4_reg>;
+               #sound-dai-cells = <0>;
+               nxp,audout-format = "i2s";
+               nxp,audout-layout = <0>;
+               nxp,audout-width = <16>;
+               nxp,audout-mclk-fs = <128>;
+               /*
+                * The 8bpp YUV422 semi-planar mode outputs CbCr[11:4]
+                * and Y[11:4] across 16bits in the same cycle
+                * which we map to VP[15:08]<->CSI_DATA[19:12]
+                */
+               nxp,vidout-portcfg =
+                       /*G_Y_11_8<->VP[15:12]<->CSI_DATA[19:16]*/
+                       < TDA1997X_VP24_V15_12 TDA1997X_G_Y_11_8 >,
+                       /*G_Y_7_4<->VP[11:08]<->CSI_DATA[15:12]*/
+                       < TDA1997X_VP24_V11_08 TDA1997X_G_Y_7_4 >,
+                       /*R_CR_CBCR_11_8<->VP[07:04]<->CSI_DATA[11:08]*/
+                       < TDA1997X_VP24_V07_04 TDA1997X_R_CR_CBCR_11_8 >,
+                       /*R_CR_CBCR_7_4<->VP[03:00]<->CSI_DATA[07:04]*/
+                       < TDA1997X_VP24_V03_00 TDA1997X_R_CR_CBCR_7_4 >;
+
+               port {
+                       tda1997x_to_ipu1_csi0_mux: endpoint {
+                               remote-endpoint = <&ipu1_csi0_mux_from_parallel_sensor>;
+                               bus-width = <16>;
+                               hsync-active = <1>;
+                               vsync-active = <1>;
+                               data-active = <1>;
+                       };
+               };
+       };
+};
+
+&ipu1_csi0_from_ipu1_csi0_mux {
+       bus-width = <16>;
+};
+
+&ipu1_csi0_mux_from_parallel_sensor {
+       remote-endpoint = <&tda1997x_to_ipu1_csi0_mux>;
+       bus-width = <16>;
+};
+
+&ipu1_csi0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ipu1_csi0>;
 };
 
 &ipu2_csi1_from_ipu2_csi1_mux {
                >;
        };
 
+       pinctrl_ipu1_csi0: ipu1_csi0grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT4__IPU1_CSI0_DATA04          0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT5__IPU1_CSI0_DATA05          0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT6__IPU1_CSI0_DATA06          0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT7__IPU1_CSI0_DATA07          0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT8__IPU1_CSI0_DATA08          0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT9__IPU1_CSI0_DATA09          0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT10__IPU1_CSI0_DATA10         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT11__IPU1_CSI0_DATA11         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19         0x1b0b0
+                       MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC           0x1b0b0
+                       MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK        0x1b0b0
+                       MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC          0x1b0b0
+               >;
+       };
+
        pinctrl_ipu2_csi1: ipu2_csi1grp {
                fsl,pins = <
                        MX6QDL_PAD_EIM_EB2__IPU2_CSI1_DATA19    0x1b0b0
                        MX6QDL_PAD_EIM_A16__IPU2_CSI1_PIXCLK    0x1b0b0
                >;
        };
+
+       pinctrl_tda1997x: tda1997xgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_7__GPIO1_IO07   0x1b0b0
+               >;
+       };
 };
index 45eb0b7f75f83c88339a7e04ebc42cdf77e037fb..d96ae54be3381399f9fe2285a6a0f45e7278b54f 100644 (file)
@@ -21,6 +21,8 @@
 
        panel-lvds0 {
                compatible = "okaya,rs800480t-7x0gp";
+               power-supply = <&reg_lcd_reset>;
+               backlight = <&backlight>;
 
                port {
                        panel_in_lvds0: endpoint {
@@ -38,7 +40,6 @@
                regulator-max-microvolt = <3300000>;
                gpio = <&gpio4 17 GPIO_ACTIVE_HIGH>;
                enable-active-high;
-               regulator-always-on;
                vin-supply = <&reg_3v3>;
                startup-delay-us = <500000>;
        };
@@ -52,7 +53,6 @@
                regulator-max-microvolt = <3300000>;
                gpio = <&gpio5 2 GPIO_ACTIVE_HIGH>;
                enable-active-high;
-               regulator-always-on;
                vin-supply = <&reg_lcd>;
        };
 };
index d8ccb533b6b7acee381e6b9f9297865626043d1d..84b30bd6908fd88b101ec31815a4e9cd5cd4080f 100644 (file)
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-reset-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index 2ce8399a10ba6e24ec7c17ab04071fb88a01bba6..bfff87ce2e1f631006d471a6333da1b0a8bc47d0 100644 (file)
@@ -98,7 +98,7 @@
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index 0f0743db27798c35153ea7646d17131c5a7553e0..a1c5e69d81ba5ab95fb6b03818ed5a5e27021d7a 100644 (file)
@@ -1,42 +1,6 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
 /*
  * Copyright (C) 2016-2017 Zodiac Inflight Innovations
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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.
- *
- *     This file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 , 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 
 /dts-v1/;
index 1ebf29f43a245deaffd46040b6c71b8cd2e572b7..4738c3c1ab502df7d802f51d0bf9de83299f7a4a 100644 (file)
@@ -51,7 +51,7 @@
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-reset-duration = <10>;
        phy-reset-gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
        status = "okay";
index 397e205551c4e3ded319ee73f710613518ef0802..70d26616d77164855125e3b5813d6e47bc7651f9 100644 (file)
@@ -77,8 +77,6 @@
 
        pwm_fan: pwm-fan {
                compatible = "pwm-fan";
-               cooling-min-state = <0>;
-               cooling-max-state = <4>;
                #cooling-cells = <2>;
                pwms = <&pwm4 0 50000>;
                cooling-levels = <0 64 127 191 255>;
index 81b2fcf6eedfb23c79499ca78160d5092625e989..e4d1c5250d1edfd9be5d06b83fa6c58846c0783a 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/sound/fsl-imx-audmux.h>
 
 / {
        /* these are used by bootloader for disabling nodes */
                };
        };
 
-       sound {
+       sound-analog {
                compatible = "fsl,imx6q-ventana-sgtl5000",
                             "fsl,imx-audio-sgtl5000";
                model = "sgtl5000-audio";
                ssi-controller = <&ssi1>;
-               audio-codec = <&codec>;
+               audio-codec = <&sgtl5000>;
                audio-routing =
                        "MIC_IN", "Mic Jack",
                        "Mic Jack", "Mic Bias",
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_audmux>; /* AUD4<->sgtl5000 */
        status = "okay";
+
+       ssi2 {
+               fsl,audmux-port = <1>;
+               fsl,port-config = <
+                       (IMX_AUDMUX_V2_PTCR_TFSDIR |
+                       IMX_AUDMUX_V2_PTCR_TFSEL(4+8) | /* RXFS */
+                       IMX_AUDMUX_V2_PTCR_TCLKDIR |
+                       IMX_AUDMUX_V2_PTCR_TCSEL(4+8) | /* RXC */
+                       IMX_AUDMUX_V2_PTCR_SYN)
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(4)
+               >;
+       };
+
+       aud5 {
+               fsl,audmux-port = <4>;
+               fsl,port-config = <
+                       IMX_AUDMUX_V2_PTCR_SYN
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(1)>;
+       };
 };
 
 &can1 {
        pinctrl-0 = <&pinctrl_i2c3>;
        status = "okay";
 
-       codec: sgtl5000@a {
+       sgtl5000: audio-codec@a {
                compatible = "fsl,sgtl5000";
                reg = <0x0a>;
                clocks = <&clks IMX6QDL_CLK_CKO>;
                        MX6QDL_PAD_SD2_DAT2__AUD4_TXD           0x110b0
                        MX6QDL_PAD_SD2_DAT1__AUD4_TXFS          0x130b0
                        MX6QDL_PAD_GPIO_0__CCM_CLKO1            0x130b0 /* AUD4_MCK */
+                       MX6QDL_PAD_EIM_D25__AUD5_RXC            0x130b0
+                       MX6QDL_PAD_DISP0_DAT19__AUD5_RXD        0x130b0
+                       MX6QDL_PAD_EIM_D24__AUD5_RXFS           0x130b0
                >;
        };
 
index 8e46a80f57a46f6e9fa295d28b035c0e22d49dd4..c23ba229fd057dc03cdfe99136a88135358f12e8 100644 (file)
@@ -46,6 +46,8 @@
  */
 
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/media/tda1997x.h>
+#include <dt-bindings/sound/fsl-imx-audmux.h>
 
 / {
        /* these are used by bootloader for disabling nodes */
                regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
        };
+
+       sound-digital {
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "tda1997x-audio";
+
+               simple-audio-card,dai-link@0 {
+                       format = "i2s";
+
+                       cpu {
+                               sound-dai = <&ssi2>;
+                       };
+
+                       codec {
+                               bitclock-master;
+                               frame-master;
+                               sound-dai = <&hdmi_receiver>;
+                       };
+               };
+       };
+};
+
+&audmux {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_audmux>; /* AUD5<->tda1997x */
+       status = "okay";
+
+       ssi1 {
+               fsl,audmux-port = <0>;
+               fsl,port-config = <
+                       (IMX_AUDMUX_V2_PTCR_TFSDIR |
+                       IMX_AUDMUX_V2_PTCR_TFSEL(4+8) | /* RXFS */
+                       IMX_AUDMUX_V2_PTCR_TCLKDIR |
+                       IMX_AUDMUX_V2_PTCR_TCSEL(4+8) | /* RXC */
+                       IMX_AUDMUX_V2_PTCR_SYN)
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(4)
+               >;
+       };
+
+       aud5 {
+               fsl,audmux-port = <4>;
+               fsl,port-config = <
+                       IMX_AUDMUX_V2_PTCR_SYN
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(0)>;
+       };
 };
 
 &can1 {
                #gpio-cells = <2>;
        };
 
+       hdmi_receiver: hdmi-receiver@48 {
+               compatible = "nxp,tda19971";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_tda1997x>;
+               reg = <0x48>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+               DOVDD-supply = <&reg_3p3>;
+               AVDD-supply = <&reg_1p8b>;
+               DVDD-supply = <&reg_1p8a>;
+               #sound-dai-cells = <0>;
+               nxp,audout-format = "i2s";
+               nxp,audout-layout = <0>;
+               nxp,audout-width = <16>;
+               nxp,audout-mclk-fs = <128>;
+               /*
+                * The 8bpp YUV422 semi-planar mode outputs CbCr[11:4]
+                * and Y[11:4] across 16bits in the same cycle
+                * which we map to VP[15:08]<->CSI_DATA[19:12]
+                */
+               nxp,vidout-portcfg =
+                       /*G_Y_11_8<->VP[15:12]<->CSI_DATA[19:16]*/
+                       < TDA1997X_VP24_V15_12 TDA1997X_G_Y_11_8 >,
+                       /*G_Y_7_4<->VP[11:08]<->CSI_DATA[15:12]*/
+                       < TDA1997X_VP24_V11_08 TDA1997X_G_Y_7_4 >,
+                       /*R_CR_CBCR_11_8<->VP[07:04]<->CSI_DATA[11:08]*/
+                       < TDA1997X_VP24_V07_04 TDA1997X_R_CR_CBCR_11_8 >,
+                       /*R_CR_CBCR_7_4<->VP[03:00]<->CSI_DATA[07:04]*/
+                       < TDA1997X_VP24_V03_00 TDA1997X_R_CR_CBCR_7_4 >;
+
+               port {
+                       tda1997x_to_ipu1_csi0_mux: endpoint {
+                               remote-endpoint = <&ipu1_csi0_mux_from_parallel_sensor>;
+                               bus-width = <16>;
+                               hsync-active = <1>;
+                               vsync-active = <1>;
+                               data-active = <1>;
+                       };
+               };
+       };
+};
+
+&ipu1_csi0_from_ipu1_csi0_mux {
+       bus-width = <16>;
+};
+
+&ipu1_csi0_mux_from_parallel_sensor {
+       remote-endpoint = <&tda1997x_to_ipu1_csi0_mux>;
+       bus-width = <16>;
+};
+
+&ipu1_csi0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ipu1_csi0>;
 };
 
 &pcie {
 };
 
 &iomuxc {
+       pinctrl_audmux: audmuxgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_DISP0_DAT19__AUD5_RXD        0x130b0
+                       MX6QDL_PAD_DISP0_DAT14__AUD5_RXC        0x130b0
+                       MX6QDL_PAD_DISP0_DAT13__AUD5_RXFS       0x130b0
+               >;
+       };
+
        pinctrl_flexcan1: flexcan1grp {
                fsl,pins = <
                        MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX        0x1b0b1
                >;
        };
 
+       pinctrl_ipu1_csi0: ipu1_csi0grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT4__IPU1_CSI0_DATA04          0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT5__IPU1_CSI0_DATA05          0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT6__IPU1_CSI0_DATA06          0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT7__IPU1_CSI0_DATA07          0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT8__IPU1_CSI0_DATA08          0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT9__IPU1_CSI0_DATA09          0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT10__IPU1_CSI0_DATA10         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT11__IPU1_CSI0_DATA11         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18         0x1b0b0
+                       MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19         0x1b0b0
+                       MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC           0x1b0b0
+                       MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK        0x1b0b0
+                       MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC          0x1b0b0
+               >;
+       };
+
        pinctrl_pcie: pciegrp {
                fsl,pins = <
                        MX6QDL_PAD_GPIO_0__GPIO1_IO00           0x1b0b0 /* PCIE RST */
                >;
        };
 
+       pinctrl_tda1997x: tda1997xgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_7__GPIO1_IO07           0x1b0b0
+               >;
+       };
+
        pinctrl_uart2: uart2grp {
                fsl,pins = <
                        MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA      0x1b0b1
index 9cb9a743912187d52ddfdc3cebc4a1f7f3741307..aee9221f0f29f9f29043ece0611f254f20f806b6 100644 (file)
        tlv320aic3105: codec@18 {
                compatible = "ti,tlv320aic3x";
                reg = <0x18>;
-               gpio-reset = <&gpio5 17 GPIO_ACTIVE_LOW>;
+               reset-gpios = <&gpio5 17 GPIO_ACTIVE_LOW>;
                clocks = <&clks IMX6QDL_CLK_CKO>;
                ai3x-micbias-vg = <2>; /* MICBIAS_2_5V */
                /* Regulators */
index 027df06c5dc7d60c9711ebef8b9333e2fe0c9a58..7e53ac6cfa8aa8c56cd8e800401fc33cacd66724 100644 (file)
@@ -79,7 +79,7 @@
        status = "okay";
        cs-gpios = <&gpio4 24 0>;
 
-       flash@0 {
+       som_flash: flash@0 {
                compatible = "m25p80", "jedec,spi-nor";
                spi-max-frequency = <20000000>;
                reg = <0>;
        pinctrl-0 = <&pinctrl_i2c1>;
        status = "okay";
 
-       eeprom@50 {
+       som_eeprom: eeprom@50 {
                compatible = "atmel,24c32";
                reg = <0x50>;
        };
index 1280de50a984575b891c5d95d8709c732f32ab03..f3404dd1053779c131486166619ee788f1c2e1e0 100644 (file)
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>,
                              <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>;
        fsl,err006687-workaround-present;
index a0705066ccba42f9bffb2cd22b4e06e68bcc7442..185fb17a35001e8165dc5cf77b79cd0c344868d6 100644 (file)
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index 4ccb7afc4b35ddb3ff465b0880ff8f7bc54c6e22..6d7f6b9035bc173eae0ba1369a07c07e94162049 100644 (file)
@@ -53,7 +53,7 @@
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_microsom_enet_ar8035>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-reset-duration = <2>;
        phy-reset-gpios = <&gpio4 15 GPIO_ACTIVE_LOW>;
        status = "okay";
index 8752a4961c477c7bb91a3bfc83998892fb158a7e..c41cac502bacc30ced5a402de990944a8e404a21 100644 (file)
                IOVDD-supply = <&reg_3p3v>;
                DVDD-supply = <&reg_3p3v>;
                ai3x-ocmv = <0>;
-               gpio-reset = <&gpio5 5 GPIO_ACTIVE_LOW>;
+               reset-gpios = <&gpio5 5 GPIO_ACTIVE_LOW>;
        };
 };
 
index b7d5fb4214046b387965bc16d2b39f42319b4c81..50d9a989e06a9072595f2e64d19c6e19171b9862 100644 (file)
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-reset-gpios = <&gpio3 29 GPIO_ACTIVE_LOW>;
        interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>,
                              <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>;
index 69942c7ff89db6ef3c503843a39004357bf856e2..93be00a60c887208ab04953d6f5b248e8903eeb9 100644 (file)
@@ -1,42 +1,6 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
 /*
  * Copyright (C) 2016-2017 Zodiac Inflight Innovations
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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.
- *
- *     This file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 , 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 
 #include <dt-bindings/gpio/gpio.h>
 
        panel {
                power-supply = <&reg_3p3v_display>;
+               backlight = <&sp_backlight>;
                status = "disabled";
 
                port {
                        compatible = "zii,rave-sp-watchdog";
                };
 
-               backlight {
+               sp_backlight: backlight {
                        compatible = "zii,rave-sp-backlight";
                };
 
                AVDD-supply = <&reg_3p3v>;
                IOVDD-supply = <&reg_3p3v>;
                DVDD-supply = <&vgen4_reg>;
-               gpio-reset = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+               reset-gpios = <&gpio1 2 GPIO_ACTIVE_LOW>;
        };
 
        accel@1c {
                };
        };
 
+       watchdog@38 {
+               compatible = "zii,rave-wdt";
+               reg = <0x38>;
+       };
+
        temp-sense@48 {
                compatible = "national,lm75";
                reg = <0x48>;
                AVDD-supply = <&reg_3p3v>;
                IOVDD-supply = <&reg_3p3v>;
                DVDD-supply = <&vgen4_reg>;
-               gpio-reset = <&gpio1 0 GPIO_ACTIVE_HIGH>;
+               reset-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
        };
 
        touchscreen@20 {
index fe17a3405edc5dd8d095d2b1b67d0f580a847997..b3a77bcf00d51c9572cd4af1d5317bbfae6cc6ae 100644 (file)
@@ -4,6 +4,7 @@
 // Copyright 2011 Linaro Ltd.
 
 #include <dt-bindings/clock/imx6qdl-clock.h>
+#include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 / {
                        ranges = <0x81000000 0 0          0x01f80000 0 0x00010000 /* downstream I/O */
                                  0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; /* non-prefetchable memory */
                        num-lanes = <1>;
+                       num-viewport = <4>;
                        interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "msi";
                        #interrupt-cells = <1>;
                                        status = "disabled";
                                };
 
+                               snvs_pwrkey: snvs-powerkey {
+                                       compatible = "fsl,sec-v4.0-pwrkey";
+                                       regmap = <&snvs>;
+                                       interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+                                       linux,keycode = <KEY_POWER>;
+                                       wakeup-source;
+                               };
+
                                snvs_lpgpr: snvs-lpgpr {
                                        compatible = "fsl,imx6q-snvs-lpgpr";
                                };
                                compatible = "fsl,imx6q-sdma", "fsl,imx35-sdma";
                                reg = <0x020ec000 0x4000>;
                                interrupts = <0 2 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6QDL_CLK_SDMA>,
+                               clocks = <&clks IMX6QDL_CLK_IPG>,
                                         <&clks IMX6QDL_CLK_SDMA>;
                                clock-names = "ipg", "ahb";
                                #dma-cells = <3>;
                                reg = <0x021ac000 0x4000>;
                        };
 
-                       mmdc0: mmdc@21b0000 { /* MMDC0 */
+                       mmdc0: memory-controller@21b0000 { /* MMDC0 */
                                compatible = "fsl,imx6q-mmdc";
                                reg = <0x021b0000 0x4000>;
                                clocks = <&clks IMX6QDL_CLK_MMDC_P0_IPG>;
                        };
 
-                       mmdc1: mmdc@21b4000 { /* MMDC1 */
+                       mmdc1: memory-controller@21b4000 { /* MMDC1 */
+                               compatible = "fsl,imx6q-mmdc";
                                reg = <0x021b4000 0x4000>;
+                               status = "disabled";
                        };
 
                        weim: weim@21b8000 {
index 98bf7a6b2850b189b276e10b9c8c6bc5507cfd83..57de447c4609d39add9453b1997c618361280021 100644 (file)
@@ -1,42 +1,6 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
 /*
  * Copyright (C) 2016-2017 Zodiac Inflight Innovations
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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.
- *
- *     This file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 , 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 
 /dts-v1/;
index 4b4813f176cdaacefedaffb41a559c4245c5042e..9ddbeea64b724947a2682d4039a6d053887324cd 100644 (file)
                gpio2 = &gpio3;
                gpio3 = &gpio4;
                gpio4 = &gpio5;
+               i2c0 = &i2c1;
+               i2c1 = &i2c2;
+               i2c2 = &i2c3;
+               mmc0 = &usdhc1;
+               mmc1 = &usdhc2;
+               mmc2 = &usdhc3;
+               mmc3 = &usdhc4;
                serial0 = &uart1;
                serial1 = &uart2;
                serial2 = &uart3;
                                reg = <0x020ec000 0x4000>;
                                interrupts = <0 2 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks IMX6SL_CLK_SDMA>,
-                                        <&clks IMX6SL_CLK_SDMA>;
+                                        <&clks IMX6SL_CLK_AHB>;
                                clock-names = "ipg", "ahb";
                                #dma-cells = <3>;
                                /* imx6sl reuses imx6q sdma firmware */
                                status = "disabled";
                        };
 
-                       mmdc: mmdc@21b0000 {
+                       memory-controller@21b0000 {
                                compatible = "fsl,imx6sl-mmdc", "fsl,imx6q-mmdc";
                                reg = <0x021b0000 0x4000>;
                                clocks = <&clks IMX6SL_CLK_MMDC_P0_IPG>;
index 62847c68330bb835c64f6769daba5668ca8cd71f..1b4899f0fcded0607cd62b5b37aa0f4238e06ba1 100644 (file)
@@ -64,6 +64,7 @@
                                198000          1175000
                        >;
                        clock-latency = <61036>; /* two CLK32 periods */
+                       #cooling-cells = <2>;
                        clocks = <&clks IMX6SLL_CLK_ARM>,
                                 <&clks IMX6SLL_CLK_PLL2_PFD2>,
                                 <&clks IMX6SLL_CLK_STEP>,
                                compatible = "fsl,imx6sll-sdma", "fsl,imx35-sdma";
                                reg = <0x020ec000 0x4000>;
                                interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6SLL_CLK_SDMA>,
+                               clocks = <&clks IMX6SLL_CLK_IPG>,
                                         <&clks IMX6SLL_CLK_SDMA>;
                                clock-names = "ipg", "ahb";
                                #dma-cells = <3>;
index b0ee324afe581f79364faf89925093677460094c..315044ccd65fc6da86f1313c3d6715bb0aee8d56 100644 (file)
@@ -75,7 +75,7 @@
 &fec1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet1>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-handle = <&ethphy1>;
        fsl,magic-packet;
        status = "okay";
index 08ede56c3f10be58da8f81ca2e6d83f7378db297..f6972deb5e39ce17d6360ead6a1d4b7cae697050 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet1>;
        phy-supply = <&reg_enet_3v3>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-handle = <&ethphy1>;
        phy-reset-gpios = <&gpio2 7 GPIO_ACTIVE_LOW>;
        status = "okay";
index 5b16e65f7696bcba7b6f837c90ff035697edbb36..b16a123990a266b62d7c8b49fdef6caa01d47e59 100644 (file)
                                compatible = "fsl,imx6sx-sdma", "fsl,imx6q-sdma";
                                reg = <0x020ec000 0x4000>;
                                interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6SX_CLK_SDMA>,
+                               clocks = <&clks IMX6SX_CLK_IPG>,
                                         <&clks IMX6SX_CLK_SDMA>;
                                clock-names = "ipg", "ahb";
                                #dma-cells = <3>;
                                status = "disabled";
                        };
 
-                       mmdc: mmdc@21b0000 {
+                       memory-controller@21b0000 {
                                compatible = "fsl,imx6sx-mmdc", "fsl,imx6q-mmdc";
                                reg = <0x021b0000 0x4000>;
                                clocks = <&clks IMX6SX_CLK_MMDC_P0_IPG>;
index 62ed30c781ed8692bf392157c41198d1bdb21e37..bbf010c7333696cd9f6bc5e23dd01cd39268f47b 100644 (file)
                                             "fsl,imx35-sdma";
                                reg = <0x020ec000 0x4000>;
                                interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX6UL_CLK_SDMA>,
+                               clocks = <&clks IMX6UL_CLK_IPG>,
                                         <&clks IMX6UL_CLK_SDMA>;
                                clock-names = "ipg", "ahb";
                                #dma-cells = <3>;
                                status = "disabled";
                        };
 
-                       mmdc: mmdc@21b0000 {
+                       memory-controller@21b0000 {
                                compatible = "fsl,imx6ul-mmdc", "fsl,imx6q-mmdc";
                                reg = <0x021b0000 0x4000>;
                                clocks = <&clks IMX6UL_CLK_MMDC_P0_IPG>;
diff --git a/arch/arm/boot/dts/imx7-mba7.dtsi b/arch/arm/boot/dts/imx7-mba7.dtsi
new file mode 100644 (file)
index 0000000..50abf18
--- /dev/null
@@ -0,0 +1,550 @@
+// SPDX-License-Identifier: GPL-2.0 OR X11
+/*
+ * Device Tree Include file for TQ Systems MBa7 carrier board.
+ *
+ * Copyright (C) 2016 TQ Systems GmbH
+ * Author: Markus Niebel <Markus.Niebel@tq-group.com>
+ * Copyright (C) 2019 Bruno Thomsen <bruno.thomsen@gmail.com>
+ *
+ * Note: This file does not include nodes for all peripheral devices.
+ * As device driver coverage increases additional nodes can be added.
+ */
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/net/ti-dp83867.h>
+
+/ {
+       beeper {
+               compatible = "gpio-beeper";
+               gpios = <&pca9555 0 GPIO_ACTIVE_HIGH>;
+       };
+
+       chosen {
+               stdout-path = &uart6;
+       };
+
+       gpio_buttons: gpio-keys {
+               compatible = "gpio-keys";
+
+               button-0 {
+                       /* #SWITCH_A */
+                       label = "S11";
+                       linux,code = <KEY_1>;
+                       gpios = <&pca9555 13 GPIO_ACTIVE_LOW>;
+               };
+
+               button-1 {
+                       /* #SWITCH_B */
+                       label = "S12";
+                       linux,code = <KEY_2>;
+                       gpios = <&pca9555 14 GPIO_ACTIVE_LOW>;
+               };
+
+               button-2 {
+                       /* #SWITCH_C */
+                       label = "S13";
+                       linux,code = <KEY_3>;
+                       gpios = <&pca9555 15 GPIO_ACTIVE_LOW>;
+               };
+       };
+
+       gpio-leds {
+               compatible = "gpio-leds";
+
+               led1 {
+                       label = "led1";
+                       gpios = <&pca9555 8 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "default-on";
+               };
+
+               led2 {
+                       label = "led2";
+                       gpios = <&pca9555 9 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       reg_sd1_vmmc: regulator-sd1-vmmc {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC3V3_SD1";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+
+       reg_fec1_pwdn: regulator-fec1-pwdn {
+               compatible = "regulator-fixed";
+               regulator-name = "PWDN_FEC1";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_fec2_pwdn: regulator-fec2-pwdn {
+               compatible = "regulator-fixed";
+               regulator-name = "PWDN_FEC2";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               gpio = <&gpio2 31 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_usb_otg1_vbus: regulator-usb-otg1-vbus {
+               compatible = "regulator-fixed";
+               regulator-name = "VBUS_USBOTG1";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_usb_otg2_vbus: regulator-usb-otg2-vbus {
+               compatible = "regulator-fixed";
+               regulator-name = "VBUS_USBOTG2";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpio1 7 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_mpcie_1v5: regulator-mpcie-1v5 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC1V5_MPCIE";
+               regulator-min-microvolt = <1500000>;
+               regulator-max-microvolt = <1500000>;
+               gpio = <&pca9555 12 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               regulator-always-on;
+       };
+
+       reg_mpcie_3v3: regulator-mpcie-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC3V3_MPCIE";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&pca9555 10 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               regulator-always-on;
+       };
+
+       reg_mba_12v0: regulator-mba-12v0 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC12V0_MBA7";
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+               gpio = <&pca9555 11 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_lvds_transmitter: regulator-lvds-transmitter {
+               compatible = "regulator-fixed";
+               regulator-name = "#SHTDN_LVDS";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&pca9555 1 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_vref_1v8: regulator-vref-1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC1V8_REF";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+               vin-supply = <&sw2_reg>;
+       };
+
+       reg_audio_3v3: regulator-audio-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC3V3_AUDIO";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+};
+
+&adc1 {
+       vref-supply = <&reg_vref_1v8>;
+       status = "okay";
+};
+
+&adc2 {
+       vref-supply = <&reg_vref_1v8>;
+       status = "okay";
+};
+
+&ecspi1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi1>;
+       num-chipselects = <3>;
+       cs-gpios = <&gpio4 0 GPIO_ACTIVE_LOW>, <&gpio4 1 GPIO_ACTIVE_LOW>,
+                  <&gpio4 2 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&ecspi2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi2>;
+       num-chipselects = <1>;
+       status = "okay";
+};
+
+&fec1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet1>;
+       phy-mode = "rgmii-id";
+       phy-reset-gpios = <&gpio7 15 GPIO_ACTIVE_LOW>;
+       phy-reset-duration = <1>;
+       phy-reset-delay = <1>;
+       phy-supply = <&reg_fec1_pwdn>;
+       phy-handle = <&ethphy1_0>;
+       fsl,magic-packet;
+       status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy1_0: ethernet-phy@0 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <0>;
+                       ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_50_NS>;
+                       ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_50_NS>;
+                       ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+                       /* LED1: Link/Activity, LED2: Error */
+                       ti,led-function = <0x0db0>;
+                       /* Active low, LED1 and LED2 driven by phy */
+                       ti,led-ctrl = <0x1001>;
+               };
+       };
+};
+
+&flexcan1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan1>;
+       status = "okay";
+};
+
+&flexcan2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan2>;
+       status = "okay";
+};
+
+&i2c1 {
+       lm75: temperature-sensor@49 {
+               compatible = "national,lm75";
+               reg = <0x49>;
+       };
+};
+
+&i2c2 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       status = "okay";
+
+       tlv320aic32x4: audio-codec@18 {
+               compatible = "ti,tlv320aic32x4";
+               reg = <0x18>;
+               clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+               clock-names = "mclk";
+               ldoin-supply = <&reg_audio_3v3>;
+               iov-supply = <&reg_audio_3v3>;
+       };
+
+       pca9555: gpio-expander@20 {
+               compatible = "nxp,pca9555";
+               reg = <0x20>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pca9555>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               interrupt-parent = <&gpio7>;
+               interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+       };
+};
+
+&i2c3 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hog_mba7_1>;
+
+       pinctrl_ecspi1: ecspi1grp {
+               fsl,pins = <
+                       MX7D_PAD_ECSPI1_MISO__ECSPI1_MISO               0x7c
+                       MX7D_PAD_ECSPI1_MOSI__ECSPI1_MOSI               0x74
+                       MX7D_PAD_ECSPI1_SCLK__ECSPI1_SCLK               0x74
+                       MX7D_PAD_UART1_RX_DATA__GPIO4_IO0               0x74
+                       MX7D_PAD_UART1_TX_DATA__GPIO4_IO1               0x74
+                       MX7D_PAD_UART2_RX_DATA__GPIO4_IO2               0x74
+               >;
+       };
+
+       pinctrl_ecspi2: ecspi2grp {
+               fsl,pins = <
+                       MX7D_PAD_ECSPI2_MISO__ECSPI2_MISO               0x7c
+                       MX7D_PAD_ECSPI2_MOSI__ECSPI2_MOSI               0x74
+                       MX7D_PAD_ECSPI2_SCLK__ECSPI2_SCLK               0x74
+                       MX7D_PAD_ECSPI2_SS0__ECSPI2_SS0                 0x74
+               >;
+       };
+
+       pinctrl_enet1: enet1grp {
+               fsl,pins = <
+                       MX7D_PAD_GPIO1_IO10__ENET1_MDIO                 0x02
+                       MX7D_PAD_GPIO1_IO11__ENET1_MDC                  0x00
+                       MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC       0x71
+                       MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0       0x71
+                       MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1       0x71
+                       MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2       0x71
+                       MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3       0x71
+                       MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x71
+                       MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC       0x79
+                       MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0       0x79
+                       MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1       0x79
+                       MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2       0x79
+                       MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3       0x79
+                       MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x79
+                       /* Reset: SION, 100kPU, SRE_FAST, DSE_X1 */
+                       MX7D_PAD_ENET1_COL__GPIO7_IO15          0x40000070
+                       /* INT/PWDN: SION, 100kPU, HYS, SRE_FAST, DSE_X1 */
+                       MX7D_PAD_GPIO1_IO09__GPIO1_IO9          0x40000078
+               >;
+       };
+
+       pinctrl_flexcan1: flexcan1grp {
+               fsl,pins = <
+                       MX7D_PAD_GPIO1_IO12__FLEXCAN1_RX        0x5a
+                       MX7D_PAD_GPIO1_IO13__FLEXCAN1_TX        0x52
+               >;
+       };
+
+       pinctrl_flexcan2: flexcan2grp {
+               fsl,pins = <
+                       MX7D_PAD_GPIO1_IO14__FLEXCAN2_RX        0x5a
+                       MX7D_PAD_GPIO1_IO15__FLEXCAN2_TX        0x52
+               >;
+       };
+
+       pinctrl_hog_mba7_1: hogmba71grp {
+               fsl,pins = <
+                       /* Limitation: WDOG2_B / WDOG2_RESET not usable */
+                       MX7D_PAD_ENET1_RX_CLK__GPIO7_IO13       0x4000007c
+                       MX7D_PAD_ENET1_CRS__GPIO7_IO14          0x40000074
+                       /* #BOOT_EN */
+                       MX7D_PAD_UART2_TX_DATA__GPIO4_IO3       0x40000010
+               >;
+       };
+
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX7D_PAD_I2C2_SCL__I2C2_SCL             0x40000078
+                       MX7D_PAD_I2C2_SDA__I2C2_SDA             0x40000078
+               >;
+       };
+
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX7D_PAD_I2C3_SCL__I2C3_SCL             0x40000078
+                       MX7D_PAD_I2C3_SDA__I2C3_SDA             0x40000078
+               >;
+       };
+
+
+       pinctrl_pca9555: pca95550grp {
+               fsl,pins = <
+                       MX7D_PAD_ENET1_TX_CLK__GPIO7_IO12       0x78
+               >;
+       };
+
+       pinctrl_uart3: uart3grp {
+               fsl,pins = <
+                       MX7D_PAD_UART3_RX_DATA__UART3_DCE_RX    0x7e
+                       MX7D_PAD_UART3_TX_DATA__UART3_DCE_TX    0x76
+                       MX7D_PAD_UART3_CTS_B__UART3_DCE_CTS     0x76
+                       MX7D_PAD_UART3_RTS_B__UART3_DCE_RTS     0x7e
+               >;
+       };
+
+       pinctrl_uart4: uart4grp {
+               fsl,pins = <
+                       MX7D_PAD_SAI2_TX_SYNC__UART4_DCE_RX     0x7e
+                       MX7D_PAD_SAI2_TX_BCLK__UART4_DCE_TX     0x76
+                       MX7D_PAD_SAI2_RX_DATA__UART4_DCE_CTS    0x76
+                       MX7D_PAD_SAI2_TX_DATA__UART4_DCE_RTS    0x7e
+               >;
+       };
+
+       pinctrl_uart5: uart5grp {
+               fsl,pins = <
+                       MX7D_PAD_I2C4_SCL__UART5_DCE_RX         0x7e
+                       MX7D_PAD_I2C4_SDA__UART5_DCE_TX         0x76
+               >;
+       };
+
+       pinctrl_uart6: uart6grp {
+               fsl,pins = <
+                       MX7D_PAD_EPDC_DATA08__UART6_DCE_RX      0x7d
+                       MX7D_PAD_EPDC_DATA09__UART6_DCE_TX      0x75
+                       MX7D_PAD_EPDC_DATA11__UART6_DCE_CTS     0x75
+                       MX7D_PAD_EPDC_DATA10__UART6_DCE_RTS     0x7d
+               >;
+       };
+
+       pinctrl_uart7: uart7grp {
+               fsl,pins = <
+                       MX7D_PAD_EPDC_DATA12__UART7_DCE_RX      0x7e
+                       MX7D_PAD_EPDC_DATA13__UART7_DCE_TX      0x76
+                       MX7D_PAD_EPDC_DATA15__UART7_DCE_CTS     0x76
+                       /* Limitation: RTS is not connected */
+                       MX7D_PAD_EPDC_DATA14__UART7_DCE_RTS     0x7e
+               >;
+       };
+
+       pinctrl_usdhc1_gpio: usdhc1grp_gpio {
+               fsl,pins = <
+                       /* WP */
+                       MX7D_PAD_SD1_WP__GPIO5_IO1              0x7c
+                       /* CD */
+                       MX7D_PAD_SD1_CD_B__GPIO5_IO0            0x7c
+                       /* VSELECT */
+                       MX7D_PAD_GPIO1_IO08__SD1_VSELECT        0x59
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       MX7D_PAD_SD1_CMD__SD1_CMD               0x5e
+                       MX7D_PAD_SD1_CLK__SD1_CLK               0x57
+                       MX7D_PAD_SD1_DATA0__SD1_DATA0           0x5e
+                       MX7D_PAD_SD1_DATA1__SD1_DATA1           0x5e
+                       MX7D_PAD_SD1_DATA2__SD1_DATA2           0x5e
+                       MX7D_PAD_SD1_DATA3__SD1_DATA3           0x5e
+               >;
+       };
+
+       pinctrl_usdhc1_100mhz: usdhc1grp_100mhz {
+               fsl,pins = <
+                       MX7D_PAD_SD1_CMD__SD1_CMD               0x5a
+                       MX7D_PAD_SD1_CLK__SD1_CLK               0x57
+                       MX7D_PAD_SD1_DATA0__SD1_DATA0           0x5a
+                       MX7D_PAD_SD1_DATA1__SD1_DATA1           0x5a
+                       MX7D_PAD_SD1_DATA2__SD1_DATA2           0x5a
+                       MX7D_PAD_SD1_DATA3__SD1_DATA3           0x5a
+               >;
+       };
+
+       pinctrl_usdhc1_200mhz: usdhc1grp_200mhz {
+               fsl,pins = <
+                       MX7D_PAD_SD1_CMD__SD1_CMD               0x5b
+                       MX7D_PAD_SD1_CLK__SD1_CLK               0x57
+                       MX7D_PAD_SD1_DATA0__SD1_DATA0           0x5b
+                       MX7D_PAD_SD1_DATA1__SD1_DATA1           0x5b
+                       MX7D_PAD_SD1_DATA2__SD1_DATA2           0x5b
+                       MX7D_PAD_SD1_DATA3__SD1_DATA3           0x5b
+               >;
+       };
+};
+
+&iomuxc_lpsr {
+       pinctrl_pwm1: pwm1grp {
+               fsl,pins = <
+                       /* LCD_CONTRAST */
+                       MX7D_PAD_LPSR_GPIO1_IO01__PWM1_OUT      0x50
+               >;
+       };
+
+       pinctrl_usbotg1: usbotg1grp {
+               fsl,pins = <
+                       MX7D_PAD_LPSR_GPIO1_IO04__USB_OTG1_OC   0x5c
+                       MX7D_PAD_LPSR_GPIO1_IO05__GPIO1_IO5     0x59
+               >;
+       };
+};
+
+&pwm1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm1>;
+       status = "okay";
+};
+
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
+       assigned-clocks = <&clks IMX7D_UART3_ROOT_SRC>;
+       assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>;
+       status = "okay";
+};
+
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart4>;
+       assigned-clocks = <&clks IMX7D_UART4_ROOT_SRC>;
+       assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>;
+       status = "okay";
+};
+
+&uart5 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart5>;
+       assigned-clocks = <&clks IMX7D_UART5_ROOT_SRC>;
+       assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>;
+       status = "okay";
+};
+
+&uart6 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart6>;
+       assigned-clocks = <&clks IMX7D_UART6_ROOT_SRC>;
+       assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>;
+       status = "okay";
+};
+
+&uart7 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart7>;
+       assigned-clocks = <&clks IMX7D_UART7_ROOT_SRC>;
+       assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>;
+       uart-has-rtscts;
+       status = "okay";
+};
+
+&usbh {
+       status = "okay";
+};
+
+&usbotg1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg1>;
+       vbus-supply = <&reg_usb_otg1_vbus>;
+       srp-disable;
+       hnp-disable;
+       adp-disable;
+       dr_mode = "host";
+       status = "okay";
+};
+
+&usdhc1 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_usdhc1_gpio>;
+       pinctrl-1 = <&pinctrl_usdhc1_100mhz>, <&pinctrl_usdhc1_gpio>;
+       pinctrl-2 = <&pinctrl_usdhc1_200mhz>, <&pinctrl_usdhc1_gpio>;
+       cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
+       vmmc-supply = <&reg_sd1_vmmc>;
+       bus-width = <4>;
+       no-1-8-v;
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx7-tqma7.dtsi b/arch/arm/boot/dts/imx7-tqma7.dtsi
new file mode 100644 (file)
index 0000000..9aaed85
--- /dev/null
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0 OR X11
+/*
+ * Device Tree Include file for TQ Systems TQMa7x boards with full mounted PCB.
+ *
+ * Copyright (C) 2016 TQ Systems GmbH
+ * Author: Markus Niebel <Markus.Niebel@tq-group.com>
+ * Copyright (C) 2019 Bruno Thomsen <bruno.thomsen@gmail.com>
+ */
+
+/ {
+       memory@80000000 {
+               device_type = "memory";
+               /* 512 MB - default configuration */
+               reg = <0x80000000 0x20000000>;
+       };
+};
+
+&cpu0 {
+       arm-supply = <&sw1a_reg>;
+};
+
+&i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       clock-frequency = <100000>;
+       status = "okay";
+
+       pfuze3000: pmic@8 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pmic1>;
+               compatible = "fsl,pfuze3000";
+               reg = <0x08>;
+
+               regulators {
+                       sw1a_reg: sw1a {
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-ramp-delay = <6250>;
+                       };
+
+                       /* use sw1c_reg to align with pfuze100/pfuze200 */
+                       sw1c_reg: sw1b {
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1475000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-ramp-delay = <6250>;
+                       };
+
+                       sw2_reg: sw2 {
+                               regulator-min-microvolt = <1500000>;
+                               regulator-max-microvolt = <1850000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sw3a_reg: sw3 {
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <1650000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       swbst_reg: swbst {
+                               regulator-min-microvolt = <5000000>;
+                               regulator-max-microvolt = <5150000>;
+                       };
+
+                       snvs_reg: vsnvs {
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vref_reg: vrefddr {
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vgen1_reg: vldo1 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen2_reg: vldo2 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1550000>;
+                               regulator-always-on;
+                       };
+
+                       vgen3_reg: vccsd {
+                               regulator-min-microvolt = <2850000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen4_reg: v33 {
+                               regulator-min-microvolt = <2850000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen5_reg: vldo3 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen6_reg: vldo4 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+               };
+       };
+
+       /* NXP SE97BTP with temperature sensor + eeprom */
+       se97b: temperature-sensor-eeprom@1e {
+               compatible = "nxp,se97b", "jedec,jc-42.4-temp";
+               reg = <0x1e>;
+               status = "okay";
+       };
+
+       /* ST M24C64 */
+       m24c64: eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+               pagesize = <32>;
+               status = "okay";
+       };
+
+       at24c02: eeprom@56 {
+               compatible = "atmel,24c02";
+               reg = <0x56>;
+               pagesize = <16>;
+               status = "okay";
+       };
+
+       ds1339: rtc@68 {
+               compatible = "dallas,ds1339";
+               reg = <0x68>;
+       };
+};
+
+&iomuxc {
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX7D_PAD_I2C1_SDA__I2C1_SDA     0x40000078
+                       MX7D_PAD_I2C1_SCL__I2C1_SCL     0x40000078
+               >;
+       };
+
+       pinctrl_pmic1: pmic1grp {
+               fsl,pins = <
+                       MX7D_PAD_SD2_RESET_B__GPIO5_IO11        0x4000005C
+               >;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX7D_PAD_SD3_CMD__SD3_CMD               0x59
+                       MX7D_PAD_SD3_CLK__SD3_CLK               0x56
+                       MX7D_PAD_SD3_DATA0__SD3_DATA0           0x59
+                       MX7D_PAD_SD3_DATA1__SD3_DATA1           0x59
+                       MX7D_PAD_SD3_DATA2__SD3_DATA2           0x59
+                       MX7D_PAD_SD3_DATA3__SD3_DATA3           0x59
+                       MX7D_PAD_SD3_DATA4__SD3_DATA4           0x59
+                       MX7D_PAD_SD3_DATA5__SD3_DATA5           0x59
+                       MX7D_PAD_SD3_DATA6__SD3_DATA6           0x59
+                       MX7D_PAD_SD3_DATA7__SD3_DATA7           0x59
+                       MX7D_PAD_SD3_STROBE__SD3_STROBE         0x19
+               >;
+       };
+
+       pinctrl_usdhc3_100mhz: usdhc3grp_100mhz {
+               fsl,pins = <
+                       MX7D_PAD_SD3_CMD__SD3_CMD               0x5a
+                       MX7D_PAD_SD3_CLK__SD3_CLK               0x51
+                       MX7D_PAD_SD3_DATA0__SD3_DATA0           0x5a
+                       MX7D_PAD_SD3_DATA1__SD3_DATA1           0x5a
+                       MX7D_PAD_SD3_DATA2__SD3_DATA2           0x5a
+                       MX7D_PAD_SD3_DATA3__SD3_DATA3           0x5a
+                       MX7D_PAD_SD3_DATA4__SD3_DATA4           0x5a
+                       MX7D_PAD_SD3_DATA5__SD3_DATA5           0x5a
+                       MX7D_PAD_SD3_DATA6__SD3_DATA6           0x5a
+                       MX7D_PAD_SD3_DATA7__SD3_DATA7           0x5a
+                       MX7D_PAD_SD3_STROBE__SD3_STROBE         0x1a
+               >;
+       };
+
+       pinctrl_usdhc3_200mhz: usdhc3grp_200mhz {
+               fsl,pins = <
+                       MX7D_PAD_SD3_CMD__SD3_CMD               0x5b
+                       MX7D_PAD_SD3_CLK__SD3_CLK               0x51
+                       MX7D_PAD_SD3_DATA0__SD3_DATA0           0x5b
+                       MX7D_PAD_SD3_DATA1__SD3_DATA1           0x5b
+                       MX7D_PAD_SD3_DATA2__SD3_DATA2           0x5b
+                       MX7D_PAD_SD3_DATA3__SD3_DATA3           0x5b
+                       MX7D_PAD_SD3_DATA4__SD3_DATA4           0x5b
+                       MX7D_PAD_SD3_DATA5__SD3_DATA5           0x5b
+                       MX7D_PAD_SD3_DATA6__SD3_DATA6           0x5b
+                       MX7D_PAD_SD3_DATA7__SD3_DATA7           0x5b
+                       MX7D_PAD_SD3_STROBE__SD3_STROBE         0x1b
+               >;
+       };
+};
+
+&iomuxc_lpsr {
+       pinctrl_wdog1: wdog1grp {
+               fsl,pins = <
+                       MX7D_PAD_LPSR_GPIO1_IO00__WDOG1_WDOG_B  0x30
+               >;
+       };
+};
+
+&sdma {
+       status = "okay";
+};
+
+&usdhc3 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc3>;
+       pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+       assigned-clocks = <&clks IMX7D_USDHC3_ROOT_CLK>;
+       assigned-clock-rates = <400000000>;
+       bus-width = <8>;
+       non-removable;
+       vmmc-supply = <&vgen4_reg>;
+       vqmmc-supply = <&sw2_reg>;
+       status = "okay";
+};
+
+&wdog1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wdog1>;
+       /*
+        * Errata e10574:
+        * WDOG reset needs to run with WDOG_RESET_B signal enabled.
+        * X1-51 (WDOG1#) signal needs carrier board handling to reset
+        * TQMa7 on X1-22 (RESET_IN#).
+        */
+       fsl,ext-reset-output;
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx7d-mba7.dts b/arch/arm/boot/dts/imx7d-mba7.dts
new file mode 100644 (file)
index 0000000..221274c
--- /dev/null
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0 OR X11
+/*
+ * Device Tree Source for TQ Systems TQMa7D board on MBa7 carrier board.
+ *
+ * Copyright (C) 2016 TQ Systems GmbH
+ * Author: Markus Niebel <Markus.Niebel@tq-group.com>
+ * Copyright (C) 2019 Bruno Thomsen <bruno.thomsen@gmail.com>
+ */
+
+/dts-v1/;
+
+#include "imx7d-tqma7.dtsi"
+#include "imx7-mba7.dtsi"
+
+/ {
+       model = "TQ Systems TQMa7D board on MBa7 carrier board";
+       compatible = "tq,imx7d-mba7", "fsl,imx7d";
+};
+
+&fec2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet2>;
+       phy-mode = "rgmii-id";
+       phy-reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>;
+       phy-reset-duration = <1>;
+       phy-reset-delay = <1>;
+       phy-supply = <&reg_fec2_pwdn>;
+       phy-handle = <&ethphy2_0>;
+       fsl,magic-packet;
+       status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy2_0: ethernet-phy@0 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <0>;
+                       ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_50_NS>;
+                       ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_50_NS>;
+                       ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+                       /* LED1: Link/Activity, LED2: error */
+                       ti,led-function = <0x0db0>;
+                       /* active low, LED1/2 driven by phy */
+                       ti,led-ctrl = <0x1001>;
+               };
+       };
+};
+
+&iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hog_mba7_1>;
+
+       pinctrl_enet2: enet2grp {
+               fsl,pins = <
+                       MX7D_PAD_SD2_CD_B__ENET2_MDIO                   0x02
+                       MX7D_PAD_SD2_WP__ENET2_MDC                      0x00
+                       MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC             0x71
+                       MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0            0x71
+                       MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1            0x71
+                       MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2            0x71
+                       MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3             0x71
+                       MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL          0x71
+                       MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC            0x79
+                       MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0            0x79
+                       MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1             0x79
+                       MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2             0x79
+                       MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3            0x79
+                       MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL         0x79
+                       /* Reset: SION, 100kPU, SRE_FAST, DSE_X1 */
+                       MX7D_PAD_EPDC_BDR0__GPIO2_IO28          0x40000070
+                       /* INT/PWDN: SION, 100kPU, HYS, SRE_FAST, DSE_X1 */
+                       MX7D_PAD_EPDC_PWR_STAT__GPIO2_IO31      0x40000078
+               >;
+       };
+
+       pinctrl_pcie: pciegrp {
+               fsl,pins = <
+                       /* #pcie_wake */
+                       MX7D_PAD_EPDC_PWR_COM__GPIO2_IO30               0x70
+                       /* #pcie_rst */
+                       MX7D_PAD_SD2_CLK__GPIO5_IO12                    0x70
+                       /* #pcie_dis */
+                       MX7D_PAD_EPDC_BDR1__GPIO2_IO29                  0x70
+               >;
+       };
+};
+
+&iomuxc_lpsr {
+       pinctrl_usbotg2: usbotg2grp {
+               fsl,pins = <
+                       MX7D_PAD_LPSR_GPIO1_IO06__USB_OTG2_OC   0x5c
+                       MX7D_PAD_LPSR_GPIO1_IO07__GPIO1_IO7     0x59
+               >;
+       };
+};
+
+&pcie {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie>;
+       /* 1.5V logically from 3.3V */
+       /* probe deferral not supported */
+       /* pcie-bus-supply = <&reg_mpcie_1v5>; */
+       reset-gpio = <&gpio5 12 GPIO_ACTIVE_LOW>;
+       disable-gpio = <&gpio2 29 GPIO_ACTIVE_LOW>;
+       power-on-gpio = <&gpio2 30 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&usbotg2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg2>;
+       vbus-supply = <&reg_usb_otg2_vbus>;
+       srp-disable;
+       hnp-disable;
+       adp-disable;
+       dr_mode = "host";
+       status = "okay";
+};
index 3fd595a7120245366cfa2aac183a2ba68cda18b1..6f50ebf31a0ab5dcc3d74713ee58011d6ab5663e 100644 (file)
@@ -92,7 +92,7 @@
                          <&clks IMX7D_ENET1_TIME_ROOT_CLK>;
        assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>;
        assigned-clock-rates = <0>, <100000000>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-handle = <&ethphy0>;
        fsl,magic-packet;
        phy-reset-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
diff --git a/arch/arm/boot/dts/imx7d-tqma7.dtsi b/arch/arm/boot/dts/imx7d-tqma7.dtsi
new file mode 100644 (file)
index 0000000..8ad3048
--- /dev/null
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0 OR X11
+/*
+ * Device Tree Include file for TQ Systems TQMa7D board with NXP i.MX7Dual SoC.
+ *
+ * Copyright (C) 2016 TQ Systems GmbH
+ * Author: Markus Niebel <Markus.Niebel@tq-group.com>
+ * Copyright (C) 2019 Bruno Thomsen <bruno.thomsen@gmail.com>
+ */
+
+#include "imx7d.dtsi"
+#include "imx7-tqma7.dtsi"
diff --git a/arch/arm/boot/dts/imx7d-zii-rpu2.dts b/arch/arm/boot/dts/imx7d-zii-rpu2.dts
new file mode 100644 (file)
index 0000000..3e467a9
--- /dev/null
@@ -0,0 +1,941 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Device tree file for ZII's RPU2 board
+ *
+ * RPU - Remote Peripheral Unit
+ *
+ * Copyright (C) 2019 Zodiac Inflight Innovations
+ */
+
+/dts-v1/;
+#include <dt-bindings/thermal/thermal.h>
+#include "imx7d.dtsi"
+
+/ {
+       model = "ZII RPU2 Board";
+       compatible = "zii,imx7d-rpu2", "fsl,imx7d";
+
+       chosen {
+               stdout-path = &uart1;
+       };
+
+       cs2000_ref: oscillator {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <24576000>;
+       };
+
+       cs2000_in_dummy: dummy-oscillator {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       gpio-leds {
+               compatible = "gpio-leds";
+               pinctrl-0 = <&pinctrl_leds_debug>;
+               pinctrl-names = "default";
+
+               debug {
+                       label = "zii:green:debug1";
+                       gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       iio-hwmon {
+               compatible = "iio-hwmon";
+               io-channels = <&adc1 0>, <&adc1 1>, <&adc1 2>, <&adc1 3>,
+                             <&adc2 1>;
+       };
+
+       reg_can1_stby: regulator-can1-stby {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_flexcan1_stby>;
+               regulator-name = "can1-3v3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_can2_stby: regulator-can2-stby {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_flexcan2_stby>;
+               regulator-name = "can2-3v3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&gpio1 8 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_vref_1v8: regulator-vref-1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "vref-1v8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+       };
+
+       reg_3p3v: regulator-3p3v {
+               compatible = "regulator-fixed";
+               regulator-name = "GEN_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+
+       reg_5p0v_main: regulator-5p0v-main {
+               compatible = "regulator-fixed";
+               regulator-name = "5V_MAIN";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+       };
+
+       sound1 {
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "Audio Output 1";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,bitclock-master = <&sound1_codec>;
+               simple-audio-card,frame-master = <&sound1_codec>;
+               simple-audio-card,widgets =
+                       "Headphone", "Headphone Jack";
+               simple-audio-card,routing =
+                       "Headphone Jack", "HPLEFT",
+                       "Headphone Jack", "HPRIGHT",
+                       "LEFTIN", "HPL",
+                       "RIGHTIN", "HPR";
+               simple-audio-card,aux-devs = <&hpa1>;
+
+               simple-audio-card,cpu {
+                       sound-dai = <&sai1>;
+               };
+
+               sound1_codec: simple-audio-card,codec {
+                       sound-dai = <&codec1>;
+                       clocks = <&cs2000>;
+               };
+       };
+
+       sound2 {
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "Audio Output 2";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,bitclock-master = <&sound2_codec>;
+               simple-audio-card,frame-master = <&sound2_codec>;
+               simple-audio-card,widgets =
+                       "Headphone", "Headphone Jack";
+               simple-audio-card,routing =
+                       "Headphone Jack", "HPLEFT",
+                       "Headphone Jack", "HPRIGHT",
+                       "LEFTIN", "HPL",
+                       "RIGHTIN", "HPR";
+               simple-audio-card,aux-devs = <&hpa2>;
+
+               simple-audio-card,cpu {
+                       sound-dai = <&sai2>;
+               };
+
+               sound2_codec: simple-audio-card,codec {
+                       sound-dai = <&codec2>;
+                       clocks = <&cs2000>;
+               };
+       };
+
+       sound3 {
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "Audio Output 3";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,bitclock-master = <&sound3_codec>;
+               simple-audio-card,frame-master = <&sound3_codec>;
+               simple-audio-card,widgets =
+                       "Headphone", "Headphone Jack";
+               simple-audio-card,routing =
+                       "Headphone Jack", "HPLEFT",
+                       "Headphone Jack", "HPRIGHT",
+                       "LEFTIN", "HPL",
+                       "RIGHTIN", "HPR";
+               simple-audio-card,aux-devs = <&hpa3>;
+
+               simple-audio-card,cpu {
+                       sound-dai = <&sai3>;
+               };
+
+               sound3_codec: simple-audio-card,codec {
+                       sound-dai = <&codec3>;
+                       clocks = <&cs2000>;
+               };
+       };
+};
+
+&adc1 {
+       vref-supply = <&reg_vref_1v8>;
+       status = "okay";
+};
+
+&adc2 {
+       vref-supply = <&reg_vref_1v8>;
+       status = "okay";
+};
+
+&cpu0 {
+       arm-supply = <&sw1a_reg>;
+};
+
+&clks {
+       assigned-clocks = <&clks IMX7D_PLL_AUDIO_POST_DIV>;
+       assigned-clock-rates = <884736000>;
+};
+
+&ecspi1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi1>;
+       cs-gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               spi-max-frequency = <20000000>;
+               reg = <0>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+       };
+};
+
+&fec1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet1>;
+       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 = "rgmii";
+       status = "okay";
+
+       fixed-link {
+               speed = <1000>;
+               full-duplex;
+       };
+
+       mdio1: mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "okay";
+
+               switch: switch@0 {
+                       compatible = "marvell,mv88e6085";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_switch>;
+                       reg = <0>;
+                       eeprom-length = <512>;
+                       interrupt-parent = <&gpio1>;
+                       interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       label = "eth_cu_1000_1";
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                                       label = "eth_cu_1000_2";
+                               };
+
+                               port@2 {
+                                       reg = <2>;
+                                       label = "pic";
+
+                                       fixed-link {
+                                               speed = <100>;
+                                               full-duplex;
+                                       };
+                               };
+
+                               port@5 {
+                                       reg = <5>;
+                                       label = "cpu";
+                                       ethernet = <&fec1>;
+                                       phy-mode = "rgmii-id";
+
+                                       fixed-link {
+                                               speed = <1000>;
+                                               full-duplex;
+                                       };
+                               };
+
+                               port@6 {
+                                       reg = <6>;
+                                       label = "gigabit_proc";
+                                       ethernet = <&fec2>;
+                                       phy-mode = "rgmii-id";
+
+                                       fixed-link {
+                                               speed = <1000>;
+                                               full-duplex;
+                                       };
+                               };
+                       };
+               };
+       };
+};
+
+&fec2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet2>;
+       assigned-clocks = <&clks IMX7D_ENET2_TIME_ROOT_SRC>,
+                         <&clks IMX7D_ENET2_TIME_ROOT_CLK>;
+       assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>;
+       assigned-clock-rates = <0>, <100000000>;
+       phy-mode = "rgmii";
+       fsl,magic-packet;
+       status = "okay";
+
+       fixed-link {
+               speed = <1000>;
+               full-duplex;
+       };
+};
+
+&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 = "okay";
+};
+
+&gpio1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpio1>;
+
+       gpio-line-names = "", "", "", "", "", "", "", "",
+                         "", "",
+                         "usb_1_en_b",
+                         "usb_2_en_b",
+                         "", "", "", "", "", "", "", "",
+                         "", "", "", "", "", "", "", "",
+                         "", "", "", "";
+};
+
+&gpio2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpio2>;
+
+       gpio-line-names = "12v_out_en_1",
+                         "12v_out_en_2",
+                         "12v_out_en_3",
+                         "28v_out_en_5",
+                         "28v_out_en_1",
+                         "28v_out_en_2",
+                         "28v_out_en_3",
+                         "28v_out_en_4",
+                         "", "",
+                         "usb_3_en_b",
+                         "usb_4_en_b",
+                         "", "", "", "", "", "", "", "",
+                         "", "", "", "", "", "", "", "",
+                         "", "", "", "";
+};
+
+&i2c1 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+
+       pmic: pmic@8 {
+               compatible = "fsl,pfuze3000";
+               reg = <0x08>;
+
+               regulators {
+                       sw1a_reg: sw1a {
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-ramp-delay = <6250>;
+                       };
+
+                       sw1c_reg: sw1b {
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1475000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-ramp-delay = <6250>;
+                       };
+
+                       sw2_reg: sw2 {
+                               regulator-min-microvolt = <1500000>;
+                               regulator-max-microvolt = <1850000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sw3a_reg: sw3 {
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <1650000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       swbst_reg: swbst {
+                               regulator-min-microvolt = <5000000>;
+                               regulator-max-microvolt = <5150000>;
+                       };
+
+                       snvs_reg: vsnvs {
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vref_reg: vrefddr {
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vgen1_reg: vldo1 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen2_reg: vldo2 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1550000>;
+                               regulator-always-on;
+                       };
+
+                       vgen3_reg: vccsd {
+                               regulator-min-microvolt = <2850000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen4_reg: v33 {
+                               regulator-min-microvolt = <2850000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen5_reg: vldo3 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen6_reg: vldo4 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+               };
+       };
+
+       cs2000: clkgen@4e {
+               compatible = "cirrus,cs2000-cp";
+               reg = <0x4e>;
+               #clock-cells = <0>;
+               clock-names = "clk_in", "ref_clk";
+               clocks = <&cs2000_in_dummy>, <&cs2000_ref>;
+               assigned-clocks = <&cs2000>;
+               assigned-clock-rates = <24000000>;
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c04";
+               reg = <0x50>;
+       };
+
+       eeprom@52 {
+               compatible = "atmel,24c04";
+               reg = <0x52>;
+       };
+};
+
+&i2c2 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       status = "okay";
+
+       codec2: codec@18 {
+               compatible = "ti,tlv320dac3100";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_codec2>;
+               reg = <0x18>;
+               #sound-dai-cells = <0>;
+               HPVDD-supply = <&reg_3p3v>;
+               SPRVDD-supply = <&reg_3p3v>;
+               SPLVDD-supply = <&reg_3p3v>;
+               AVDD-supply = <&reg_3p3v>;
+               IOVDD-supply = <&reg_3p3v>;
+               DVDD-supply = <&vgen4_reg>;
+               gpio-reset = <&gpio1 6 GPIO_ACTIVE_LOW>;
+       };
+
+       hpa2: amp@60 {
+               compatible = "ti,tpa6130a2";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_tpa2>;
+               reg = <0x60>;
+               power-gpio = <&gpio3 27 GPIO_ACTIVE_HIGH>;
+               Vdd-supply = <&reg_5p0v_main>;
+       };
+};
+
+&i2c3 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       status = "okay";
+
+       codec3: codec@18 {
+               compatible = "ti,tlv320dac3100";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_codec3>;
+               reg = <0x18>;
+               #sound-dai-cells = <0>;
+               HPVDD-supply = <&reg_3p3v>;
+               SPRVDD-supply = <&reg_3p3v>;
+               SPLVDD-supply = <&reg_3p3v>;
+               AVDD-supply = <&reg_3p3v>;
+               IOVDD-supply = <&reg_3p3v>;
+               DVDD-supply = <&vgen4_reg>;
+               gpio-reset = <&gpio1 7 GPIO_ACTIVE_LOW>;
+       };
+
+       hpa3: amp@60 {
+               compatible = "ti,tpa6130a2";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_tpa3>;
+               reg = <0x60>;
+               power-gpio = <&gpio3 28 GPIO_ACTIVE_HIGH>;
+               Vdd-supply = <&reg_5p0v_main>;
+       };
+};
+
+&i2c4 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c4>;
+       status = "okay";
+
+       codec1: codec@18 {
+               compatible = "ti,tlv320dac3100";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_codec1>;
+               reg = <0x18>;
+               #sound-dai-cells = <0>;
+               HPVDD-supply = <&reg_3p3v>;
+               SPRVDD-supply = <&reg_3p3v>;
+               SPLVDD-supply = <&reg_3p3v>;
+               AVDD-supply = <&reg_3p3v>;
+               IOVDD-supply = <&reg_3p3v>;
+               DVDD-supply = <&vgen4_reg>;
+               gpio-reset = <&gpio1 5 GPIO_ACTIVE_LOW>;
+       };
+
+       hpa1: amp@60 {
+               compatible = "ti,tpa6130a2";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_tpa1>;
+               reg = <0x60>;
+               power-gpio = <&gpio3 26 GPIO_ACTIVE_HIGH>;
+               Vdd-supply = <&reg_5p0v_main>;
+       };
+};
+
+&sai1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sai1>;
+       assigned-clocks = <&clks IMX7D_SAI1_ROOT_SRC>,
+                         <&clks IMX7D_SAI1_ROOT_CLK>;
+       assigned-clock-parents = <&clks IMX7D_PLL_AUDIO_POST_DIV>;
+       assigned-clock-rates = <0>, <36864000>;
+       status = "okay";
+};
+
+&sai2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sai2>;
+       assigned-clocks = <&clks IMX7D_SAI2_ROOT_SRC>,
+                         <&clks IMX7D_SAI2_ROOT_CLK>;
+       assigned-clock-parents = <&clks IMX7D_PLL_AUDIO_POST_DIV>;
+       assigned-clock-rates = <0>, <36864000>;
+       status = "okay";
+};
+
+&sai3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sai3>;
+       assigned-clocks = <&clks IMX7D_SAI3_ROOT_SRC>,
+                         <&clks IMX7D_SAI3_ROOT_CLK>;
+       assigned-clock-parents = <&clks IMX7D_PLL_AUDIO_POST_DIV>;
+       assigned-clock-rates = <0>, <36864000>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       assigned-clocks = <&clks IMX7D_UART2_ROOT_SRC>;
+       assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>;
+       status = "okay";
+};
+
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart4>;
+       assigned-clocks = <&clks IMX7D_UART4_ROOT_SRC>;
+       assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>;
+       status = "okay";
+
+       rave-sp {
+               compatible = "zii,rave-sp-rdu2";
+               current-speed = <1000000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               watchdog {
+                       compatible = "zii,rave-sp-watchdog";
+               };
+
+               eeprom@a3 {
+                       compatible = "zii,rave-sp-eeprom";
+                       reg = <0xa3 0x4000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       zii,eeprom-name = "main-eeprom";
+               };
+       };
+};
+
+&usbotg1 {
+       dr_mode = "host";
+       disable-over-current;
+       status = "okay";
+};
+
+&usbotg2 {
+       dr_mode = "host";
+       disable-over-current;
+       status = "okay";
+};
+
+&usdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc1>;
+       bus-width = <4>;
+       no-1-8-v;
+       no-sdio;
+       keep-power-in-suspend;
+       status = "okay";
+};
+
+&usdhc3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc3>;
+       bus-width = <8>;
+       no-1-8-v;
+       non-removable;
+       no-sdio;
+       no-sd;
+       keep-power-in-suspend;
+       status = "okay";
+};
+
+&wdog1 {
+       status = "disabled";
+};
+
+&snvs_rtc {
+       status = "disabled";
+};
+
+&snvs_pwrkey {
+       status = "disabled";
+};
+
+&iomuxc {
+       pinctrl_ecspi1: ecspi1grp {
+               fsl,pins = <
+                       MX7D_PAD_ECSPI1_SCLK__ECSPI1_SCLK       0x2
+                       MX7D_PAD_ECSPI1_MOSI__ECSPI1_MOSI       0x2
+                       MX7D_PAD_ECSPI1_MISO__ECSPI1_MISO       0x2
+                       MX7D_PAD_ECSPI1_SS0__GPIO4_IO19         0x59
+               >;
+       };
+
+       pinctrl_enet1: enet1grp {
+               fsl,pins = <
+                       MX7D_PAD_SD2_CD_B__ENET1_MDIO                           0x3
+                       MX7D_PAD_SD2_WP__ENET1_MDC                              0x3
+                       MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC               0x1
+                       MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0               0x1
+                       MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1               0x1
+                       MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2               0x1
+                       MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3               0x1
+                       MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL         0x1
+                       MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC               0x1
+                       MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0               0x1
+                       MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1               0x1
+                       MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2               0x1
+                       MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3               0x1
+                       MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL         0x1
+               >;
+       };
+
+       pinctrl_enet2: enet2grp {
+               fsl,pins = <
+                       MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC                     0x1
+                       MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0                    0x1
+                       MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1                    0x1
+                       MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2                    0x1
+                       MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3                     0x1
+                       MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL                  0x1
+                       MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC                    0x1
+                       MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0                    0x1
+                       MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1                     0x1
+                       MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2                     0x1
+                       MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3                    0x1
+                       MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL                 0x1
+                       MX7D_PAD_UART1_TX_DATA__ENET2_1588_EVENT0_OUT           0x1
+               >;
+       };
+
+       pinctrl_flexcan1: flexcan1grp {
+               fsl,pins = <
+                       MX7D_PAD_GPIO1_IO12__FLEXCAN1_RX        0x59
+                       MX7D_PAD_GPIO1_IO13__FLEXCAN1_TX        0x59
+               >;
+       };
+
+       pinctrl_flexcan1_stby: flexcan1stbygrp {
+               fsl,pins = <
+                       MX7D_PAD_GPIO1_IO08__GPIO1_IO8          0x59
+               >;
+       };
+
+       pinctrl_flexcan2: flexcan2grp {
+               fsl,pins = <
+                       MX7D_PAD_GPIO1_IO14__FLEXCAN2_RX        0x59
+                       MX7D_PAD_GPIO1_IO15__FLEXCAN2_TX        0x59
+               >;
+       };
+
+       pinctrl_flexcan2_stby: flexcan2stbygrp {
+               fsl,pins = <
+                       MX7D_PAD_GPIO1_IO09__GPIO1_IO9          0x59
+               >;
+       };
+
+       pinctrl_gpio1: gpio1grp {
+               fsl,pins = <
+                       MX7D_PAD_GPIO1_IO10__GPIO1_IO10         0x00
+                       MX7D_PAD_GPIO1_IO11__GPIO1_IO11         0x00
+               >;
+       };
+
+       pinctrl_gpio2: gpio2grp {
+               fsl,pins = <
+                       MX7D_PAD_EPDC_DATA00__GPIO2_IO0         0x00
+                       MX7D_PAD_EPDC_DATA01__GPIO2_IO1         0x00
+                       MX7D_PAD_EPDC_DATA02__GPIO2_IO2         0x00
+                       MX7D_PAD_EPDC_DATA03__GPIO2_IO3         0x03
+                       MX7D_PAD_EPDC_DATA04__GPIO2_IO4         0x03
+                       MX7D_PAD_EPDC_DATA05__GPIO2_IO5         0x03
+                       MX7D_PAD_EPDC_DATA06__GPIO2_IO6         0x03
+                       MX7D_PAD_EPDC_DATA07__GPIO2_IO7         0x03
+                       MX7D_PAD_EPDC_DATA10__GPIO2_IO10        0x00
+                       MX7D_PAD_EPDC_DATA11__GPIO2_IO11        0x00
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX7D_PAD_I2C1_SDA__I2C1_SDA             0x4000007f
+                       MX7D_PAD_I2C1_SCL__I2C1_SCL             0x4000007f
+               >;
+       };
+
+       pinctrl_i2c1_gpio: i2c1gpiogrp {
+               fsl,pins = <
+                       MX7D_PAD_I2C1_SDA__GPIO4_IO9            0x4000007f
+                       MX7D_PAD_I2C1_SCL__GPIO4_IO8            0x4000007f
+               >;
+       };
+
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX7D_PAD_I2C2_SDA__I2C2_SDA             0x4000007f
+                       MX7D_PAD_I2C2_SCL__I2C2_SCL             0x4000007f
+               >;
+       };
+
+       pinctrl_i2c2_gpio: i2c2gpiogrp {
+               fsl,pins = <
+                       MX7D_PAD_I2C2_SDA__GPIO4_IO11           0x4000007f
+                       MX7D_PAD_I2C2_SCL__GPIO4_IO10           0x4000007f
+               >;
+       };
+
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX7D_PAD_I2C3_SDA__I2C3_SDA             0x4000007f
+                       MX7D_PAD_I2C3_SCL__I2C3_SCL             0x4000007f
+               >;
+       };
+
+       pinctrl_i2c3_gpio: i2c3gpiogrp {
+               fsl,pins = <
+                       MX7D_PAD_I2C3_SDA__GPIO4_IO13           0x4000007f
+                       MX7D_PAD_I2C3_SCL__GPIO4_IO12           0x4000007f
+               >;
+       };
+
+       pinctrl_i2c4: i2c4grp {
+               fsl,pins = <
+                       MX7D_PAD_I2C4_SDA__I2C4_SDA             0x4000007f
+                       MX7D_PAD_I2C4_SCL__I2C4_SCL             0x4000007f
+               >;
+       };
+
+       pinctrl_i2c4_gpio: i2c4gpiogrp {
+               fsl,pins = <
+                       MX7D_PAD_SAI1_RX_BCLK__GPIO6_IO17       0x4000007f
+                       MX7D_PAD_SAI1_RX_SYNC__GPIO6_IO16       0x4000007f
+               >;
+       };
+
+       pinctrl_leds_debug: debuggrp {
+               fsl,pins = <
+                       MX7D_PAD_EPDC_DATA08__GPIO2_IO8         0x59
+               >;
+       };
+
+       pinctrl_sai1: sai1grp {
+               fsl,pins = <
+                       MX7D_PAD_SAI1_TX_BCLK__SAI1_TX_BCLK     0x1f
+                       MX7D_PAD_SAI1_TX_SYNC__SAI1_TX_SYNC     0x1f
+                       MX7D_PAD_SAI1_TX_DATA__SAI1_TX_DATA0    0x30
+               >;
+       };
+
+       pinctrl_sai2: sai2grp {
+               fsl,pins = <
+                       MX7D_PAD_SAI2_TX_BCLK__SAI2_TX_BCLK     0x1f
+                       MX7D_PAD_SAI2_TX_SYNC__SAI2_TX_SYNC     0x1f
+                       MX7D_PAD_SAI2_TX_DATA__SAI2_TX_DATA0    0x30
+               >;
+       };
+
+       pinctrl_sai3: sai3grp {
+               fsl,pins = <
+                       MX7D_PAD_UART3_TX_DATA__SAI3_TX_BCLK    0x1f
+                       MX7D_PAD_UART3_CTS_B__SAI3_TX_SYNC      0x1f
+                       MX7D_PAD_UART3_RTS_B__SAI3_TX_DATA0     0x30
+               >;
+       };
+
+       pinctrl_tpa1: tpa6130-1grp {
+               fsl,pins = <
+                       MX7D_PAD_LCD_DATA21__GPIO3_IO26         0x40000038
+               >;
+       };
+
+       pinctrl_tpa2: tpa6130-2grp {
+               fsl,pins = <
+                       MX7D_PAD_LCD_DATA22__GPIO3_IO27         0x40000038
+               >;
+       };
+
+       pinctrl_tpa3: tpa6130-3grp {
+               fsl,pins = <
+                       MX7D_PAD_LCD_DATA23__GPIO3_IO28         0x40000038
+               >;
+       };
+
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX7D_PAD_UART2_RX_DATA__UART2_DCE_RX    0x79
+                       MX7D_PAD_UART2_TX_DATA__UART2_DCE_TX    0x79
+               >;
+       };
+
+       pinctrl_uart4: uart4grp {
+               fsl,pins = <
+                       MX7D_PAD_SD2_DATA0__UART4_DCE_RX        0x79
+                       MX7D_PAD_SD2_DATA1__UART4_DCE_TX        0x79
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               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
+               >;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX7D_PAD_SD3_CMD__SD3_CMD               0x59
+                       MX7D_PAD_SD3_CLK__SD3_CLK               0x19
+                       MX7D_PAD_SD3_DATA0__SD3_DATA0           0x59
+                       MX7D_PAD_SD3_DATA1__SD3_DATA1           0x59
+                       MX7D_PAD_SD3_DATA2__SD3_DATA2           0x59
+                       MX7D_PAD_SD3_DATA3__SD3_DATA3           0x59
+                       MX7D_PAD_SD3_DATA4__SD3_DATA4           0x59
+                       MX7D_PAD_SD3_DATA5__SD3_DATA5           0x59
+                       MX7D_PAD_SD3_DATA6__SD3_DATA6           0x59
+                       MX7D_PAD_SD3_DATA7__SD3_DATA7           0x59
+                       MX7D_PAD_SD3_RESET_B__SD3_RESET_B       0x59
+               >;
+       };
+};
+
+&iomuxc_lpsr {
+       pinctrl_codec1: dac1grp {
+               fsl,pins = <
+                       MX7D_PAD_LPSR_GPIO1_IO05__GPIO1_IO5     0x40000038
+               >;
+       };
+
+       pinctrl_codec2: dac2grp {
+               fsl,pins = <
+                       MX7D_PAD_LPSR_GPIO1_IO06__GPIO1_IO6     0x40000038
+               >;
+       };
+
+       pinctrl_codec3: dac3grp {
+               fsl,pins = <
+                       MX7D_PAD_LPSR_GPIO1_IO07__GPIO1_IO7     0x40000038
+               >;
+       };
+
+       pinctrl_switch: switchgrp {
+               fsl,pins = <
+                       MX7D_PAD_LPSR_GPIO1_IO02__GPIO1_IO2     0x08
+               >;
+       };
+};
index 6eb98e7c568d4f9f350ffd37d291fbeaf6fed9fe..f33b560821b8a7d1de70228394022f33ff830f37 100644 (file)
                ranges = <0x81000000 0 0          0x4ff80000 0 0x00010000   /* downstream I/O */
                          0x82000000 0 0x40000000 0x40000000 0 0x0ff00000>; /* non-prefetchable memory */
                num-lanes = <1>;
+               num-viewport = <4>;
                interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
                interrupt-names = "msi";
                #interrupt-cells = <1>;
diff --git a/arch/arm/boot/dts/imx7s-mba7.dts b/arch/arm/boot/dts/imx7s-mba7.dts
new file mode 100644 (file)
index 0000000..a143d56
--- /dev/null
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0 OR X11
+/*
+ * Device Tree Source for TQ Systems TQMa7S board on MBa7 carrier board.
+ *
+ * Copyright (C) 2016 TQ Systems GmbH
+ * Author: Markus Niebel <Markus.Niebel@tq-group.com>
+ * Copyright (C) 2019 Bruno Thomsen <bruno.thomsen@gmail.com>
+ */
+
+/dts-v1/;
+
+#include "imx7s-tqma7.dtsi"
+#include "imx7-mba7.dtsi"
+
+/ {
+       model = "TQ Systems TQMa7S board on MBa7 carrier board";
+       compatible = "tq,imx7s-mba7", "fsl,imx7s";
+};
diff --git a/arch/arm/boot/dts/imx7s-tqma7.dtsi b/arch/arm/boot/dts/imx7s-tqma7.dtsi
new file mode 100644 (file)
index 0000000..5f5433e
--- /dev/null
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0 OR X11
+/*
+ * Device Tree Include file for TQ Systems TQMa7S board with NXP i.MX7Solo SoC.
+ *
+ * Copyright (C) 2016 TQ Systems GmbH
+ * Author: Markus Niebel <Markus.Niebel@tq-group.com>
+ * Copyright (C) 2019 Bruno Thomsen <bruno.thomsen@gmail.com>
+ */
+
+#include "imx7s.dtsi"
+#include "imx7-tqma7.dtsi"
index 23431faecaf4aeca263b0fb55bd82b66cf81fe80..d6b4888fa686bcc8b33699c4078429da53fb762f 100644 (file)
                regulator-always-on;
        };
 
+       reg_peri_3p15v: regulator-peri-3p15v {
+               compatible = "regulator-fixed";
+               regulator-name = "peri_3p15v_reg";
+               regulator-min-microvolt = <3150000>;
+               regulator-max-microvolt = <3150000>;
+               regulator-always-on;
+       };
+
        sound {
                compatible = "simple-audio-card";
                simple-audio-card,name = "imx7-sgtl5000";
        assigned-clock-rates = <884736000>;
 };
 
+&csi {
+       status = "okay";
+};
+
 &i2c1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_i2c1>;
                        swbst_reg: swbst {
                                regulator-min-microvolt = <5000000>;
                                regulator-max-microvolt = <5150000>;
+                               regulator-boot-on;
+                               regulator-always-on;
                        };
 
                        snvs_reg: vsnvs {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_i2c2>;
        status = "okay";
+
+       ov2680: camera@36 {
+               compatible = "ovti,ov2680";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_ov2680>;
+               reg = <0x36>;
+               clocks = <&osc>;
+               clock-names = "xvclk";
+               reset-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
+               DOVDD-supply = <&sw2_reg>;
+               DVDD-supply = <&sw2_reg>;
+               AVDD-supply = <&reg_peri_3p15v>;
+
+               port {
+                       ov2680_to_mipi: endpoint {
+                               remote-endpoint = <&mipi_from_sensor>;
+                               clock-lanes = <0>;
+                               data-lanes = <1>;
+                       };
+               };
+       };
 };
 
 &i2c3 {
        };
 };
 
+&mipi_csi {
+       clock-frequency = <166000000>;
+       fsl,csis-hs-settle = <3>;
+       status = "okay";
+
+       port@0 {
+               reg = <0>;
+
+               mipi_from_sensor: endpoint {
+                       remote-endpoint = <&ov2680_to_mipi>;
+                       data-lanes = <1>;
+               };
+
+       };
+};
+
 &sai1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_sai1>;
        status = "okay";
 };
 
+&video_mux {
+       status = "okay";
+};
+
 &wdog1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_wdog>;
                >;
        };
 
+       pinctrl_ov2680: ov2660grp {
+               fsl,pins = <
+                       MX7D_PAD_LPSR_GPIO1_IO03__GPIO1_IO3     0x14
+               >;
+       };
+
        pinctrl_sai1: sai1grp {
                fsl,pins = <
                        MX7D_PAD_SAI1_RX_DATA__SAI1_RX_DATA0    0x1f
index e88f53a4c7f46cc4763b05ea450c1e397de8d272..106711d2c01b05e33ee20335eee2368c0565b9d4 100644 (file)
@@ -8,6 +8,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/reset/imx7-reset.h>
 #include "imx7d-pinfunc.h"
 
 / {
 
                        gpr: iomuxc-gpr@30340000 {
                                compatible = "fsl,imx7d-iomuxc-gpr",
-                                       "fsl,imx6q-iomuxc-gpr", "syscon";
+                                       "fsl,imx6q-iomuxc-gpr", "syscon",
+                                       "simple-mfd";
                                reg = <0x30340000 0x10000>;
+
+                               mux: mux-controller {
+                                       compatible = "mmio-mux";
+                                       #mux-control-cells = <0>;
+                                       mux-reg-masks = <0x14 0x00000010>;
+                               };
+
+                               video_mux: csi-mux {
+                                       compatible = "video-mux";
+                                       mux-controls = <&mux 0>;
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+                                       status = "disabled";
+
+                                       port@0 {
+                                               reg = <0>;
+                                       };
+
+                                       port@1 {
+                                               reg = <1>;
+
+                                               csi_mux_from_mipi_vc0: endpoint {
+                                                       remote-endpoint = <&mipi_vc0_to_csi_mux>;
+                                               };
+                                       };
+
+                                       port@2 {
+                                               reg = <2>;
+
+                                               csi_mux_to_csi: endpoint {
+                                                       remote-endpoint = <&csi_from_csi_mux>;
+                                               };
+                                       };
+                               };
                        };
 
                        ocotp: ocotp-ctrl@30350000 {
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       pgc_pcie_phy: pgc-power-domain@1 {
+                                       pgc_mipi_phy: power-domain@0 {
+                                               #power-domain-cells = <0>;
+                                               reg = <0>;
+                                               power-supply = <&reg_1p0d>;
+                                       };
+
+                                       pgc_pcie_phy: power-domain@1 {
                                                #power-domain-cells = <0>;
                                                reg = <1>;
                                                power-supply = <&reg_1p0d>;
                                interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks IMX7D_ADC_ROOT_CLK>;
                                clock-names = "adc";
+                               #io-channel-cells = <1>;
                                status = "disabled";
                        };
 
                                interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks IMX7D_ADC_ROOT_CLK>;
                                clock-names = "adc";
+                               #io-channel-cells = <1>;
                                status = "disabled";
                        };
 
                                status = "disabled";
                        };
 
+                       csi: csi@30710000 {
+                               compatible = "fsl,imx7-csi";
+                               reg = <0x30710000 0x10000>;
+                               interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks IMX7D_CLK_DUMMY>,
+                                        <&clks IMX7D_CSI_MCLK_ROOT_CLK>,
+                                        <&clks IMX7D_CLK_DUMMY>;
+                               clock-names = "axi", "mclk", "dcic";
+                               status = "disabled";
+
+                               port {
+                                       csi_from_csi_mux: endpoint {
+                                               remote-endpoint = <&csi_mux_to_csi>;
+                                       };
+                               };
+                       };
+
                        lcdif: lcdif@30730000 {
                                compatible = "fsl,imx7d-lcdif", "fsl,imx28-lcdif";
                                reg = <0x30730000 0x10000>;
                                clock-names = "pix", "axi";
                                status = "disabled";
                        };
+
+                       mipi_csi: mipi-csi@30750000 {
+                               compatible = "fsl,imx7-mipi-csi2";
+                               reg = <0x30750000 0x10000>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks IMX7D_IPG_ROOT_CLK>,
+                                        <&clks IMX7D_MIPI_CSI_ROOT_CLK>,
+                                        <&clks IMX7D_MIPI_DPHY_ROOT_CLK>;
+                               clock-names = "pclk", "wrap", "phy";
+                               power-domains = <&pgc_mipi_phy>;
+                               phy-supply = <&reg_1p0d>;
+                               resets = <&src IMX7_RESET_MIPI_PHY_MRST>;
+                               reset-names = "mrst";
+                               status = "disabled";
+
+                               port@0 {
+                                       reg = <0>;
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+
+                                       mipi_vc0_to_csi_mux: endpoint {
+                                               remote-endpoint = <&csi_mux_from_mipi_vc0>;
+                                       };
+                               };
+                       };
                };
 
                aips3: aips-bus@30800000 {
                                compatible = "fsl,imx7d-sdma", "fsl,imx35-sdma";
                                reg = <0x30bd0000 0x10000>;
                                interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&clks IMX7D_SDMA_CORE_CLK>,
-                                        <&clks IMX7D_AHB_CHANNEL_ROOT_CLK>;
+                               clocks = <&clks IMX7D_IPG_ROOT_CLK>,
+                                        <&clks IMX7D_SDMA_CORE_CLK>;
                                clock-names = "ipg", "ahb";
                                #dma-cells = <3>;
                                fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin";
index fca6e50f37c895bd6bea7846e42b6aeb82d5c58c..d6b711011cba831348c6f4c2cb68f94ef788c1c9 100644 (file)
                        status = "disabled";
                };
 
+               memory-controller@40ab0000 {
+                       compatible = "fsl,imx7ulp-mmdc", "fsl,imx6q-mmdc";
+                       reg = <0x40ab0000 0x1000>;
+                       clocks = <&pcc3 IMX7ULP_CLK_MMDC>;
+               };
+
                iomuxc1: pinctrl@40ac0000 {
                        compatible = "fsl,imx7ulp-iomuxc1";
                        reg = <0x40ac0000 0x1000>;
                        compatible = "fsl,imx7ulp-sim", "syscon";
                        reg = <0x410a3000 0x1000>;
                };
+
+               ocotp: ocotp-ctrl@410a6000 {
+                       compatible = "fsl,imx7ulp-ocotp", "syscon";
+                       reg = <0x410a6000 0x4000>;
+                       clocks = <&scg1 IMX7ULP_CLK_DUMMY>;
+               };
        };
 };
diff --git a/arch/arm/boot/dts/intel-ixp42x-linksys-nslu2.dts b/arch/arm/boot/dts/intel-ixp42x-linksys-nslu2.dts
new file mode 100644 (file)
index 0000000..8fcd958
--- /dev/null
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Device Tree file for Linksys NSLU2
+ */
+
+/dts-v1/;
+
+#include "intel-ixp42x.dtsi"
+#include <dt-bindings/input/input.h>
+
+/ {
+       model = "Linksys NSLU2 (Network Storage Link for USB 2.0 Disk Drives)";
+       compatible = "linksys,nslu2", "intel,ixp42x";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       memory@0 {
+               /* 32 MB SDRAM */
+               device_type = "memory";
+               reg = <0x00000000 0x2000000>;
+       };
+
+       chosen {
+               bootargs = "console=ttyS0,115200n8 root=/dev/mtdblock2 rw rootfstype=squashfs,jffs2 rootwait";
+               stdout-path = "uart0:115200n8";
+       };
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               led-status {
+                       label = "nslu2:red:status";
+                       gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
+                       default-state = "on";
+                       linux,default-trigger = "heartbeat";
+               };
+               led-ready {
+                       label = "nslu2:green:ready";
+                       gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
+                       default-state = "on";
+               };
+               led-disk-1 {
+                       label = "nslu2:green:disk-1";
+                       gpios = <&gpio0 3 GPIO_ACTIVE_LOW>;
+                       default-state = "off";
+               };
+               led-disk-2 {
+                       label = "nslu2:green:disk-2";
+                       gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
+                       default-state = "off";
+               };
+       };
+
+       gpio_keys {
+               compatible = "gpio-keys";
+
+               button-power {
+                       wakeup-source;
+                       linux,code = <KEY_POWER>;
+                       label = "power";
+                       gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>;
+               };
+               button-reset {
+                       wakeup-source;
+                       linux,code = <KEY_ESC>;
+                       label = "reset";
+                       gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
+               };
+       };
+
+       i2c {
+               compatible = "i2c-gpio";
+               sda-gpios = <&gpio0 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
+               scl-gpios = <&gpio0 6 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               rtc@6f {
+                       compatible = "xicor,x1205";
+                       reg = <0x6f>;
+               };
+       };
+
+       gpio-poweroff {
+               compatible = "gpio-poweroff";
+               gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
+               timeout-ms = <5000>;
+       };
+
+       /* The first 16MB region on the expansion bus */
+       flash@50000000 {
+               compatible = "intel,ixp4xx-flash", "cfi-flash";
+               bank-width = <2>;
+               /*
+                * 8 MB of Flash in 0x20000 byte blocks
+                * mapped in at 0x50000000
+                */
+               reg = <0x50000000 0x800000>;
+
+               partitions {
+                       compatible = "redboot-fis";
+                       /* Eraseblock at 0x7e0000 */
+                       fis-index-block = <0x3f>;
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/intel-ixp42x.dtsi b/arch/arm/boot/dts/intel-ixp42x.dtsi
new file mode 100644 (file)
index 0000000..a9622ca
--- /dev/null
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Device Tree file for Intel XScale Network Processors
+ * in the IXP 42x series. This series has 32 interrupts.
+ */
+#include "intel-ixp4xx.dtsi"
+
+/ {
+       soc {
+               interrupt-controller@c8003000 {
+                       compatible = "intel,ixp42x-interrupt";
+               };
+
+               /*
+                * This is the USB Device Mode (UDC) controller, which is used
+                * to present the IXP4xx as a device on a USB bus.
+                */
+               usb@c800b000 {
+                       compatible = "intel,ixp4xx-udc";
+                       reg = <0xc800b000 0x1000>;
+                       interrupts = <12 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/intel-ixp43x-gateworks-gw2358.dts b/arch/arm/boot/dts/intel-ixp43x-gateworks-gw2358.dts
new file mode 100644 (file)
index 0000000..ba1163a
--- /dev/null
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Device Tree file for Gateworks IXP43x-based Cambria GW2358
+ */
+
+/dts-v1/;
+
+#include "intel-ixp43x.dtsi"
+
+/ {
+       model = "Gateworks Cambria GW2358";
+       compatible = "gateworks,gw2358", "intel,ixp43x";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       memory@0 {
+               /* 128 MB SDRAM */
+               device_type = "memory";
+               reg = <0x00000000 0x8000000>;
+       };
+
+       chosen {
+               bootargs = "console=ttyS0,115200n8 root=/dev/mtdblock2 rw rootfstype=squashfs,jffs2 rootwait";
+               stdout-path = "uart0:115200n8";
+       };
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               led-user {
+                       label = "gw2358:green:LED";
+                       gpios = <&pld1 0 GPIO_ACTIVE_LOW>;
+                       default-state = "on";
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+
+       i2c {
+               compatible = "i2c-gpio";
+               sda-gpios = <&gpio0 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
+               scl-gpios = <&gpio0 6 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               hwmon@28 {
+                       compatible = "adi,ad7418";
+                       reg = <0x28>;
+               };
+               rtc: ds1672@68 {
+                       compatible = "dallas,ds1672";
+                       reg = <0x68>;
+               };
+               eeprom@51 {
+                       compatible = "atmel,24c08";
+                       reg = <0x51>;
+                       pagesize = <16>;
+                       size = <1024>;
+                       read-only;
+               };
+               pld0: pld@56 {
+                       compatible = "gateworks,pld-gpio";
+                       reg = <0x56>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+               /* This PLD just handles the LED and user button */
+               pld1: pld@57 {
+                       compatible = "gateworks,pld-gpio";
+                       reg = <0x57>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+       };
+
+       flash@50000000 {
+               compatible = "intel,ixp4xx-flash", "cfi-flash";
+               bank-width = <2>;
+               /*
+                * 32 MB of Flash in 0x20000 byte blocks
+                * mapped in at 0x50000000
+                */
+               reg = <0x50000000 0x2000000>;
+
+               partitions {
+                       compatible = "redboot-fis";
+                       /* Eraseblock at 0x1fe0000 */
+                       fis-index-block = <0xff>;
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/intel-ixp43x.dtsi b/arch/arm/boot/dts/intel-ixp43x.dtsi
new file mode 100644 (file)
index 0000000..494fb2f
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Device Tree file for Intel XScale Network Processors
+ * in the IXP 43x series. This series has 64 interrupts and adds a few more
+ * peripherals over the 42x series.
+ */
+#include "intel-ixp4xx.dtsi"
+
+/ {
+       soc {
+               interrupt-controller@c8003000 {
+                       compatible = "intel,ixp43x-interrupt";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/intel-ixp45x-ixp46x.dtsi b/arch/arm/boot/dts/intel-ixp45x-ixp46x.dtsi
new file mode 100644 (file)
index 0000000..f8cd506
--- /dev/null
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Device Tree file for Intel XScale Network Processors
+ * in the IXP45x and IXP46x series. This series has 64 interrupts and adds a
+ * few more peripherals over the 42x and 43x series so this extends the
+ * basic IXP4xx DTSI.
+ */
+#include "intel-ixp4xx.dtsi"
+
+/ {
+       soc {
+               interrupt-controller@c8003000 {
+                       compatible = "intel,ixp43x-interrupt";
+               };
+
+               /*
+                * This is the USB Device Mode (UDC) controller, which is used
+                * to present the IXP4xx as a device on a USB bus.
+                */
+               usb@c800b000 {
+                       compatible = "intel,ixp4xx-udc";
+                       reg = <0xc800b000 0x1000>;
+                       interrupts = <12 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "disabled";
+               };
+
+               i2c@c8011000 {
+                       compatible = "intel,ixp4xx-i2c";
+                       reg = <0xc8011000 0x18>;
+                       interrupts = <33 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/intel-ixp4xx.dtsi b/arch/arm/boot/dts/intel-ixp4xx.dtsi
new file mode 100644 (file)
index 0000000..d4a0958
--- /dev/null
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Device Tree file for Intel XScale Network Processors
+ * in the IXP 4xx series.
+ */
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       soc {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+               compatible = "simple-bus";
+               interrupt-parent = <&intcon>;
+
+               qmgr: queue-manager@60000000 {
+                       compatible = "intel,ixp4xx-ahb-queue-manager";
+                       reg = <0x60000000 0x4000>;
+                       interrupts = <3 IRQ_TYPE_LEVEL_HIGH>, <4 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               uart0: serial@c8000000 {
+                       compatible = "intel,xscale-uart";
+                       reg = <0xc8000000 0x1000>;
+                       /*
+                        * The reg-offset and reg-shift is a side effect
+                        * of running the platform in big endian mode.
+                        */
+                       reg-offset = <3>;
+                       reg-shift = <2>;
+                       interrupts = <15 IRQ_TYPE_LEVEL_HIGH>;
+                       clock-frequency = <14745600>;
+                       no-loopback-test;
+               };
+
+               gpio0: gpio@c8004000 {
+                       compatible = "intel,ixp4xx-gpio";
+                       reg = <0xc8004000 0x1000>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               intcon: interrupt-controller@c8003000 {
+                       /*
+                        * Note: no compatible string. The subvariant of the
+                        * chip needs to define what version it is. The
+                        * location of the interrupt controller is fixed in
+                        * memory across all variants.
+                        */
+                       reg = <0xc8003000 0x100>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               timer@c8005000 {
+                       compatible = "intel,ixp4xx-timer";
+                       reg = <0xc8005000 0x100>;
+                       interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               npe@c8006000 {
+                       compatible = "intel,ixp4xx-network-processing-engine";
+                       reg = <0xc8006000 0x1000>, <0xc8007000 0x1000>, <0xc8008000 0x1000>;
+               };
+       };
+};
index f46a11827ef6cd1c270c115855e2ad72005898ba..4adf4c96f79815cfd98ff30e6ab6ba41faace934 100644 (file)
 &mac {
        phy-mode = "rmii";
        use-iram;
+       status = "okay";
 };
 
 /* Here, choose exactly one from: ohci, usbd */
index ebd19258e22b57a0654993e7534598d3da57a124..1b15f798794b69ce00f02d696d892622335c757e 100644 (file)
 &mac {
        phy-mode = "rmii";
        use-iram;
+       status = "okay";
 };
 
 /* Here, choose exactly one from: ohci, usbd */
 };
 
 &ssp0 {
-       #address-cells = <1>;
-       #size-cells = <0>;
        num-cs = <1>;
        cs-gpios = <&gpio 3 5 0>;
        status = "okay";
index 20b38f4ade375defa9c856cc0add75ade4158d09..7b7ec7b1217b89515b6c4455e1bc10538274d305 100644 (file)
@@ -1,14 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * NXP LPC32xx SoC
  *
+ * Copyright (C) 2015-2019 Vladimir Zapolskiy <vz@mleia.com>
  * Copyright 2012 Roland Stigge <stigge@antcom.de>
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
  */
 
 #include <dt-bindings/clock/lpc32xx-clock.h>
                        reg = <0x31060000 0x1000>;
                        interrupts = <29 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&clk LPC32XX_CLK_MAC>;
+                       status = "disabled";
                };
 
                emc: memory-controller@31080000 {
                                interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clk LPC32XX_CLK_SSP0>;
                                clock-names = "apb_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
                                status = "disabled";
                        };
 
                                compatible = "nxp,lpc3220-spi";
                                reg = <0x20088000 0x1000>;
                                clocks = <&clk LPC32XX_CLK_SPI1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
                                status = "disabled";
                        };
 
                                interrupts = <21 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clk LPC32XX_CLK_SSP1>;
                                clock-names = "apb_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
                                status = "disabled";
                        };
 
                                compatible = "nxp,lpc3220-spi";
                                reg = <0x20090000 0x1000>;
                                clocks = <&clk LPC32XX_CLK_SPI2>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
                                status = "disabled";
                        };
 
                        i2s0: i2s@20094000 {
                                compatible = "nxp,lpc3220-i2s";
                                reg = <0x20094000 0x1000>;
+                               status = "disabled";
                        };
 
                        sd: sd@20098000 {
 
                        i2s1: i2s@2009c000 {
                                compatible = "nxp,lpc3220-i2s";
-                               reg = <0x2009C000 0x1000>;
+                               reg = <0x2009c000 0x1000>;
+                               status = "disabled";
                        };
 
                        /* UART5 first since it is the default console, ttyS0 */
 
                        i2c1: i2c@400a0000 {
                                compatible = "nxp,pnx-i2c";
-                               reg = <0x400A0000 0x100>;
+                               reg = <0x400a0000 0x100>;
                                interrupt-parent = <&sic1>;
                                interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
                                #address-cells = <1>;
 
                        i2c2: i2c@400a8000 {
                                compatible = "nxp,pnx-i2c";
-                               reg = <0x400A8000 0x100>;
+                               reg = <0x400a8000 0x100>;
                                interrupt-parent = <&sic1>;
                                interrupts = <18 IRQ_TYPE_LEVEL_LOW>;
                                #address-cells = <1>;
 
                        mpwm: mpwm@400e8000 {
                                compatible = "nxp,lpc3220-motor-pwm";
-                               reg = <0x400E8000 0x78>;
+                               reg = <0x400e8000 0x78>;
                                status = "disabled";
                                #pwm-cells = <2>;
                        };
 
                        timer4: timer@4002c000 {
                                compatible = "nxp,lpc3220-timer";
-                               reg = <0x4002C000 0x1000>;
+                               reg = <0x4002c000 0x1000>;
                                interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
                                clocks = <&clk LPC32XX_CLK_TIMER4>;
                                clock-names = "timerclk";
 
                        watchdog: watchdog@4003c000 {
                                compatible = "nxp,pnx4008-wdt";
-                               reg = <0x4003C000 0x1000>;
+                               reg = <0x4003c000 0x1000>;
                                clocks = <&clk LPC32XX_CLK_WDOG>;
                        };
 
 
                        timer1: timer@4004c000 {
                                compatible = "nxp,lpc3220-timer";
-                               reg = <0x4004C000 0x1000>;
+                               reg = <0x4004c000 0x1000>;
                                interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
                                clocks = <&clk LPC32XX_CLK_TIMER1>;
                                clock-names = "timerclk";
 
                        pwm1: pwm@4005c000 {
                                compatible = "nxp,lpc3220-pwm";
-                               reg = <0x4005C000 0x4>;
+                               reg = <0x4005c000 0x4>;
                                clocks = <&clk LPC32XX_CLK_PWM1>;
                                assigned-clocks = <&clk LPC32XX_CLK_PWM1>;
                                assigned-clock-parents = <&clk LPC32XX_CLK_PERIPH>;
 
                        pwm2: pwm@4005c004 {
                                compatible = "nxp,lpc3220-pwm";
-                               reg = <0x4005C004 0x4>;
+                               reg = <0x4005c004 0x4>;
                                clocks = <&clk LPC32XX_CLK_PWM2>;
                                assigned-clocks = <&clk LPC32XX_CLK_PWM2>;
                                assigned-clock-parents = <&clk LPC32XX_CLK_PERIPH>;
index ba1ddd93b8f8704d71a06893cc2d289a5ba1dca6..dcb1d9bd0922e1adf749d3b1f1f1522020a7c0c0 100644 (file)
 };
 
 &qspi {
-       fsl,qspi-has-second-chip;
        status = "okay";
 
        flash: flash@0 {
index ca60730dda40bd2d0f48273b99dd6654ba0a3abd..74a67604876c83818d34f97a02474a87a34270e5 100644 (file)
        status = "okay";
 };
 
+&esdhc {
+       status = "okay";
+};
+
 &i2c0 {
        status = "okay";
 
index 97e1fb7ea932430bc127475d18f288086d3f8e10..9b1fe99d55b1e677a393665aafbefe2d91f8d601 100644 (file)
 };
 
 &enet0 {
-       tbi-handle = <&tbi1>;
+       tbi-handle = <&tbi0>;
        phy-handle = <&sgmii_phy2>;
        phy-connection-type = "sgmii";
        status = "okay";
        sgmii_phy2: ethernet-phy@2 {
                reg = <0x2>;
        };
+       tbi0: tbi-phy@1f {
+               reg = <0x1f>;
+               device_type = "tbi-phy";
+       };
+};
+
+&mdio1 {
        tbi1: tbi-phy@1f {
                reg = <0x1f>;
                device_type = "tbi-phy";
index b10ff5877b4ca8e4ae8047ccbb4a0a84e3f5b534..464df4290ffcb5c43e717f2f47b0a4c4abeac40d 100644 (file)
                        interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
                        clock-names = "qspi_en", "qspi";
                        clocks = <&clockgen 4 1>, <&clockgen 4 1>;
-                       big-endian;
                        status = "disabled";
                };
 
                };
 
                mdio0: mdio@2d24000 {
-                       compatible = "gianfar";
+                       compatible = "fsl,etsec2-mdio";
                        device_type = "mdio";
                        #address-cells = <1>;
                        #size-cells = <0>;
                              <0x0 0x2d10030 0x0 0x4>;
                };
 
+               mdio1: mdio@2d64000 {
+                       compatible = "fsl,etsec2-mdio";
+                       device_type = "mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0 0x2d64000 0x0 0x4000>,
+                             <0x0 0x2d50030 0x0 0x4>;
+               };
+
                ptp_clock@2d10e00 {
                        compatible = "fsl,etsec-ptp";
                        reg = <0x0 0x2d10e00 0x0 0xb0>;
index 6f54a8897574da85b663d7b1631502e1c4351781..8841783aceec93e4158d0539fd89269243524529 100644 (file)
                                #size-cells = <0>;
                                status = "disabled";
                        };
+
+                       rtc: rtc@740 {
+                               compatible = "amlogic,meson6-rtc";
+                               reg = <0x740 0x14>;
+                               interrupts = <GIC_SPI 72 IRQ_TYPE_EDGE_RISING>;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               status = "disabled";
+                       };
                };
 
                usb0: usb@c9040000 {
index a9781243453ecb5a81a118465801efafb3e2e2cd..7ef442462ea474460796b03ebe63462f28e5b65e 100644 (file)
                status = "disabled";
        };
 
+       clock-measure@8758 {
+               compatible = "amlogic,meson8-clk-measure";
+               reg = <0x8758 0x1c>;
+       };
+
        pinctrl_cbus: pinctrl@9880 {
                compatible = "amlogic,meson8-cbus-pinctrl";
                reg = <0x9880 0x10>;
        compatible = "amlogic,meson8-pwm", "amlogic,meson8b-pwm";
 };
 
+&rtc {
+       compatible = "amlogic,meson8-rtc";
+       resets = <&reset RESET_RTC>;
+};
+
 &saradc {
        compatible = "amlogic,meson8-saradc", "amlogic,meson-saradc";
        clocks = <&clkc CLKID_XTAL>,
index 3ca9638fad09def6dbd6ed943b0b25e8b8ab3411..9bf4249cb60d00effefe87dd6016885293e1caab 100644 (file)
                };
        };
 
+       rtc32k_xtal: rtc32k-xtal-clk {
+               /* X2 in the schematics */
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+               clock-output-names = "RTC32K";
+               #clock-cells = <0>;
+       };
+
        usb_vbus: regulator-usb-vbus {
                /*
                 * Silergy SY6288CCAC-GP 2A Power Distribution Switch.
        clock-names = "clkin0";
 };
 
+&rtc {
+       status = "okay";
+       clocks = <&rtc32k_xtal>;
+       vdd-supply = <&vcc_rtc>;
+};
+
 /* exposed through the pin headers labeled "URDUG1" on the top of the PCB */
 &uart_AO {
        status = "okay";
index 3b0e0f8fbc237326e93c9bcdf544cc845ba0864a..f3ad9397f670931c064f3511ea7ae86ca6f6e66c 100644 (file)
                io-channels = <&saradc 8>;
        };
 
+       rtc32k_xtal: rtc32k-xtal-clk {
+               /* X3 in the schematics */
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+               clock-output-names = "RTC32K";
+               #clock-cells = <0>;
+       };
+
        vcc_1v8: regulator-vcc-1v8 {
                /*
                 * RICHTEK RT9179 configured for a fixed output voltage of
        };
 };
 
+&gpio {
+       gpio-line-names = /* Bank GPIOX */
+                         "J2 Header Pin 35", "J2 Header Pin 36",
+                         "J2 Header Pin 32", "J2 Header Pin 31",
+                         "J2 Header Pin 29", "J2 Header Pin 18",
+                         "J2 Header Pin 22", "J2 Header Pin 16",
+                         "J2 Header Pin 23", "J2 Header Pin 21",
+                         "J2 Header Pin 19", "J2 Header Pin 33",
+                         "J2 Header Pin 8", "J2 Header Pin 10",
+                         "J2 Header Pin 15", "J2 Header Pin 13",
+                         "J2 Header Pin 24", "J2 Header Pin 26",
+                         /* Bank GPIOY */
+                         "Revision (upper)", "Revision (lower)",
+                         "J2 Header Pin 7", "", "J2 Header Pin 12",
+                         "J2 Header Pin 11", "", "", "",
+                         "TFLASH_VDD_EN", "", "",
+                         /* Bank GPIODV */
+                         "VCCK_PWM (PWM_C)", "I2CA_SDA", "I2CA_SCL",
+                         "I2CB_SDA", "I2CB_SCL", "VDDEE_PWM (PWM_D)",
+                         "",
+                         /* Bank GPIOH */
+                         "HDMI_HPD", "HDMI_I2C_SDA", "HDMI_I2C_SCL",
+                         "ETH_PHY_INTR", "ETH_PHY_NRST", "ETH_TXD1",
+                         "ETH_TXD0", "ETH_TXD3", "ETH_TXD2",
+                         "ETH_RGMII_TX_CLK",
+                         /* Bank CARD */
+                         "SD_DATA1 (SDB_D1)", "SD_DATA0 (SDB_D0)",
+                         "SD_CLK",  "SD_CMD", "SD_DATA3 (SDB_D3)",
+                         "SD_DATA2 (SDB_D2)", "SD_CDN (SD_DET_N)",
+                         /* Bank BOOT */
+                         "SDC_D0 (EMMC)", "SDC_D1 (EMMC)",
+                         "SDC_D2 (EMMC)", "SDC_D3 (EMMC)",
+                         "SDC_D4 (EMMC)", "SDC_D5 (EMMC)",
+                         "SDC_D6 (EMMC)", "SDC_D7 (EMMC)",
+                         "SDC_CLK (EMMC)", "SDC_RSTn (EMMC)",
+                         "SDC_CMD (EMMC)", "BOOT_SEL", "", "", "",
+                         "", "", "", "",
+                         /* Bank DIF */
+                         "ETH_RXD1", "ETH_RXD0", "ETH_RX_DV",
+                         "RGMII_RX_CLK", "ETH_RXD3", "ETH_RXD2",
+                         "ETH_TXEN", "ETH_PHY_REF_CLK_25MOUT",
+                         "ETH_MDC", "ETH_MDIO";
+};
+
 &gpio_ao {
+       gpio-line-names = "UART TX", "UART RX", "",
+                         "TF_3V3N_1V8_EN", "USB_HUB_RST_N",
+                         "USB_OTG_PWREN", "J7 Header Pin 2",
+                         "IR_IN", "J7 Header Pin 4",
+                         "J7 Header Pin 6", "J7 Header Pin 5",
+                         "J7 Header Pin 7", "HDMI_CEC",
+                         "SYS_LED", "", "";
+
        /*
         * WARNING: The USB Hub on the Odroid-C1/C1+ needs a reset signal
         * to be turned high in order to be detected by the USB Controller.
        clock-names = "clkin0";
 };
 
+&rtc {
+       /* needs to be enabled manually when a battery is connected */
+       clocks = <&rtc32k_xtal>;
+       vdd-supply = <&vdd_rtc>;
+};
+
 &uart_AO {
        status = "okay";
        pinctrl-0 = <&uart_ao_a_pins>;
index fe84a8c3ce81a05659954e60e50bb12fbb093ab0..800cd65fc50a4f0e59c2278eee74d49f117aea63 100644 (file)
                status = "disabled";
        };
 
+       clock-measure@8758 {
+               compatible = "amlogic,meson8b-clk-measure";
+               reg = <0x8758 0x1c>;
+       };
+
        pinctrl_cbus: pinctrl@9880 {
                compatible = "amlogic,meson8b-cbus-pinctrl";
                reg = <0x9880 0x10>;
        compatible = "amlogic,meson8b-pwm";
 };
 
+&rtc {
+       compatible = "amlogic,meson8b-rtc";
+       resets = <&reset RESET_RTC>;
+};
+
 &saradc {
        compatible = "amlogic,meson8b-saradc", "amlogic,meson-saradc";
        clocks = <&clkc CLKID_XTAL>,
index 96b9913ecc1f9a281c01473118de715a4e67a076..09c1dbc0bb6904c82b0a94d95c97ff0a1f16446f 100644 (file)
@@ -48,7 +48,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&aic33_pins>;
 
-               gpio-reset = <&gpio4 22 GPIO_ACTIVE_LOW>; /* gpio118 */
+               reset-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>; /* gpio118 */
 
                ai3x-gpio-func = <
                        10 /* AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK */
index 5e81691534147f256b72cc807109ef064db8cb80..a1dacb8a6987bfffc174c24a348226123127c574 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include "omap443x.dtsi"
+#include "omap4-mcpdm.dtsi"
 
 / {
        model = "Gumstix Duovero";
                >;
        };
 
-       mcpdm_pins: pinmux_mcpdm_pins {
-               pinctrl-single,pins = <
-                       OMAP4_IOPAD(0x106, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_pdm_ul_data.abe_pdm_ul_data */
-                       OMAP4_IOPAD(0x108, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_pdm_dl_data.abe_pdm_dl_data */
-                       OMAP4_IOPAD(0x10a, PIN_INPUT_PULLUP   | MUX_MODE0)      /* abe_pdm_frame.abe_pdm_frame */
-                       OMAP4_IOPAD(0x10c, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_pdm_lb_clk.abe_pdm_lb_clk */
-                       OMAP4_IOPAD(0x10e, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_clks.abe_clks */
-               >;
-       };
-
        mcbsp1_pins: pinmux_mcbsp1_pins {
                pinctrl-single,pins = <
                        OMAP4_IOPAD(0x0fe, PIN_INPUT | MUX_MODE0)               /* abe_mcbsp1_clkx.abe_mcbsp1_clkx */
        status = "okay";
 };
 
-&mcpdm {
-       pinctrl-names = "default";
-       pinctrl-0 = <&mcpdm_pins>;
-
-       clocks = <&twl6040>;
-       clock-names = "pdmclk";
-
-       status = "okay";
-};
-
 &mmc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&mmc1_pins>;
diff --git a/arch/arm/boot/dts/omap4-l4-abe.dtsi b/arch/arm/boot/dts/omap4-l4-abe.dtsi
new file mode 100644 (file)
index 0000000..67072df
--- /dev/null
@@ -0,0 +1,501 @@
+&l4_abe {                                              /* 0x40100000 */
+       compatible = "ti,omap4-l4-abe", "simple-bus";
+       reg = <0x40100000 0x400>,
+             <0x40100400 0x400>;
+       reg-names = "la", "ap";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       ranges = <0x00000000 0x40100000 0x100000>,      /* segment 0 */
+                <0x49000000 0x49000000 0x100000>;
+       segment@0 {                                     /* 0x40100000 */
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges =
+                        /* CPU to L4 ABE mapping */
+                        <0x00000000 0x00000000 0x000400>,      /* ap 0 */
+                        <0x00000400 0x00000400 0x000400>,      /* ap 1 */
+                        <0x00022000 0x00022000 0x001000>,      /* ap 2 */
+                        <0x00023000 0x00023000 0x001000>,      /* ap 3 */
+                        <0x00024000 0x00024000 0x001000>,      /* ap 4 */
+                        <0x00025000 0x00025000 0x001000>,      /* ap 5 */
+                        <0x00026000 0x00026000 0x001000>,      /* ap 6 */
+                        <0x00027000 0x00027000 0x001000>,      /* ap 7 */
+                        <0x00028000 0x00028000 0x001000>,      /* ap 8 */
+                        <0x00029000 0x00029000 0x001000>,      /* ap 9 */
+                        <0x0002a000 0x0002a000 0x001000>,      /* ap 10 */
+                        <0x0002b000 0x0002b000 0x001000>,      /* ap 11 */
+                        <0x0002e000 0x0002e000 0x001000>,      /* ap 12 */
+                        <0x0002f000 0x0002f000 0x001000>,      /* ap 13 */
+                        <0x00030000 0x00030000 0x001000>,      /* ap 14 */
+                        <0x00031000 0x00031000 0x001000>,      /* ap 15 */
+                        <0x00032000 0x00032000 0x001000>,      /* ap 16 */
+                        <0x00033000 0x00033000 0x001000>,      /* ap 17 */
+                        <0x00038000 0x00038000 0x001000>,      /* ap 18 */
+                        <0x00039000 0x00039000 0x001000>,      /* ap 19 */
+                        <0x0003a000 0x0003a000 0x001000>,      /* ap 20 */
+                        <0x0003b000 0x0003b000 0x001000>,      /* ap 21 */
+                        <0x0003c000 0x0003c000 0x001000>,      /* ap 22 */
+                        <0x0003d000 0x0003d000 0x001000>,      /* ap 23 */
+                        <0x0003e000 0x0003e000 0x001000>,      /* ap 24 */
+                        <0x0003f000 0x0003f000 0x001000>,      /* ap 25 */
+                        <0x00080000 0x00080000 0x010000>,      /* ap 26 */
+                        <0x00080000 0x00080000 0x001000>,      /* ap 27 */
+                        <0x000a0000 0x000a0000 0x010000>,      /* ap 28 */
+                        <0x000a0000 0x000a0000 0x001000>,      /* ap 29 */
+                        <0x000c0000 0x000c0000 0x010000>,      /* ap 30 */
+                        <0x000c0000 0x000c0000 0x001000>,      /* ap 31 */
+                        <0x000f1000 0x000f1000 0x001000>,      /* ap 32 */
+                        <0x000f2000 0x000f2000 0x001000>,      /* ap 33 */
+
+                        /* L3 to L4 ABE mapping */
+                        <0x49000000 0x49000000 0x000400>,      /* ap 0 */
+                        <0x49000400 0x49000400 0x000400>,      /* ap 1 */
+                        <0x49022000 0x49022000 0x001000>,      /* ap 2 */
+                        <0x49023000 0x49023000 0x001000>,      /* ap 3 */
+                        <0x49024000 0x49024000 0x001000>,      /* ap 4 */
+                        <0x49025000 0x49025000 0x001000>,      /* ap 5 */
+                        <0x49026000 0x49026000 0x001000>,      /* ap 6 */
+                        <0x49027000 0x49027000 0x001000>,      /* ap 7 */
+                        <0x49028000 0x49028000 0x001000>,      /* ap 8 */
+                        <0x49029000 0x49029000 0x001000>,      /* ap 9 */
+                        <0x4902a000 0x4902a000 0x001000>,      /* ap 10 */
+                        <0x4902b000 0x4902b000 0x001000>,      /* ap 11 */
+                        <0x4902e000 0x4902e000 0x001000>,      /* ap 12 */
+                        <0x4902f000 0x4902f000 0x001000>,      /* ap 13 */
+                        <0x49030000 0x49030000 0x001000>,      /* ap 14 */
+                        <0x49031000 0x49031000 0x001000>,      /* ap 15 */
+                        <0x49032000 0x49032000 0x001000>,      /* ap 16 */
+                        <0x49033000 0x49033000 0x001000>,      /* ap 17 */
+                        <0x49038000 0x49038000 0x001000>,      /* ap 18 */
+                        <0x49039000 0x49039000 0x001000>,      /* ap 19 */
+                        <0x4903a000 0x4903a000 0x001000>,      /* ap 20 */
+                        <0x4903b000 0x4903b000 0x001000>,      /* ap 21 */
+                        <0x4903c000 0x4903c000 0x001000>,      /* ap 22 */
+                        <0x4903d000 0x4903d000 0x001000>,      /* ap 23 */
+                        <0x4903e000 0x4903e000 0x001000>,      /* ap 24 */
+                        <0x4903f000 0x4903f000 0x001000>,      /* ap 25 */
+                        <0x49080000 0x49080000 0x010000>,      /* ap 26 */
+                        <0x49080000 0x49080000 0x001000>,      /* ap 27 */
+                        <0x490a0000 0x490a0000 0x010000>,      /* ap 28 */
+                        <0x490a0000 0x490a0000 0x001000>,      /* ap 29 */
+                        <0x490c0000 0x490c0000 0x010000>,      /* ap 30 */
+                        <0x490c0000 0x490c0000 0x001000>,      /* ap 31 */
+                        <0x490f1000 0x490f1000 0x001000>,      /* ap 32 */
+                        <0x490f2000 0x490f2000 0x001000>;      /* ap 33 */
+
+               target-module@22000 {                   /* 0x40122000, ap 2 02.0 */
+                       compatible = "ti,sysc-omap2", "ti,sysc";
+                       ti,hwmods = "mcbsp1";
+                       reg = <0x2208c 0x4>;
+                       reg-names = "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP2_CLOCKACTIVITY |
+                                        SYSC_OMAP2_ENAWAKEUP |
+                                        SYSC_OMAP2_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>;
+                       /* Domains (V, P, C): iva, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP4_MCBSP1_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x22000 0x1000>,
+                                <0x49022000 0x49022000 0x1000>;
+
+                       mcbsp1: mcbsp@0 {
+                               compatible = "ti,omap4-mcbsp";
+                               reg = <0x0 0xff>, /* MPU private access */
+                                     <0x49022000 0xff>; /* L3 Interconnect */
+                               reg-names = "mpu", "dma";
+                               interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "common";
+                               ti,buffer-size = <128>;
+                               dmas = <&sdma 33>,
+                                      <&sdma 34>;
+                               dma-names = "tx", "rx";
+                               status = "disabled";
+                       };
+               };
+
+               target-module@24000 {                   /* 0x40124000, ap 4 04.0 */
+                       compatible = "ti,sysc-omap2", "ti,sysc";
+                       ti,hwmods = "mcbsp2";
+                       reg = <0x2408c 0x4>;
+                       reg-names = "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP2_CLOCKACTIVITY |
+                                        SYSC_OMAP2_ENAWAKEUP |
+                                        SYSC_OMAP2_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>;
+                       /* Domains (V, P, C): iva, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP4_MCBSP2_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x24000 0x1000>,
+                                <0x49024000 0x49024000 0x1000>;
+
+                       mcbsp2: mcbsp@0 {
+                               compatible = "ti,omap4-mcbsp";
+                               reg = <0x0 0xff>, /* MPU private access */
+                                     <0x49024000 0xff>; /* L3 Interconnect */
+                               reg-names = "mpu", "dma";
+                               interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "common";
+                               ti,buffer-size = <128>;
+                               dmas = <&sdma 17>,
+                                      <&sdma 18>;
+                               dma-names = "tx", "rx";
+                               status = "disabled";
+                       };
+               };
+
+               target-module@26000 {                   /* 0x40126000, ap 6 06.0 */
+                       compatible = "ti,sysc-omap2", "ti,sysc";
+                       ti,hwmods = "mcbsp3";
+                       reg = <0x2608c 0x4>;
+                       reg-names = "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP2_CLOCKACTIVITY |
+                                        SYSC_OMAP2_ENAWAKEUP |
+                                        SYSC_OMAP2_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>;
+                       /* Domains (V, P, C): iva, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP4_MCBSP3_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x26000 0x1000>,
+                                <0x49026000 0x49026000 0x1000>;
+
+                       mcbsp3: mcbsp@0 {
+                               compatible = "ti,omap4-mcbsp";
+                               reg = <0x0 0xff>, /* MPU private access */
+                                     <0x49026000 0xff>; /* L3 Interconnect */
+                               reg-names = "mpu", "dma";
+                               interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "common";
+                               ti,buffer-size = <128>;
+                               dmas = <&sdma 19>,
+                                      <&sdma 20>;
+                               dma-names = "tx", "rx";
+                               status = "disabled";
+                       };
+               };
+
+               target-module@28000 {                   /* 0x40128000, ap 8 08.0 */
+                       compatible = "ti,sysc-mcasp", "ti,sysc";
+                       ti,hwmods = "mcasp";
+                       reg = <0x28000 0x4>,
+                             <0x28004 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       /* Domains (V, P, C): iva, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP4_MCASP_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x28000 0x1000>,
+                                <0x49028000 0x49028000 0x1000>;
+
+                       /*
+                        * Child device unsupported by davinci-mcasp. At least
+                        * RX path is disabled for omap4, and only DIT mode
+                        * works with no I2S. See also old Android kernel
+                        * omap-mcasp driver for more information.
+                        */
+               };
+
+               target-module@2a000 {                   /* 0x4012a000, ap 10 0a.0 */
+                       compatible = "ti,sysc";
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x2a000 0x1000>,
+                                <0x4902a000 0x4902a000 0x1000>;
+               };
+
+               target-module@2e000 {                   /* 0x4012e000, ap 12 0c.0 */
+                       compatible = "ti,sysc-omap4", "ti,sysc";
+                       ti,hwmods = "dmic";
+                       reg = <0x2e000 0x4>,
+                             <0x2e010 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP4_FREEEMU |
+                                        SYSC_OMAP4_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       /* Domains (V, P, C): iva, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP4_DMIC_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x2e000 0x1000>,
+                                <0x4902e000 0x4902e000 0x1000>;
+
+                       dmic: dmic@0 {
+                               compatible = "ti,omap4-dmic";
+                               reg = <0x0 0x7f>, /* MPU private access */
+                                     <0x4902e000 0x7f>; /* L3 Interconnect */
+                               reg-names = "mpu", "dma";
+                               interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+                               dmas = <&sdma 67>;
+                               dma-names = "up_link";
+                               status = "disabled";
+                       };
+               };
+
+               target-module@30000 {                   /* 0x40130000, ap 14 0e.0 */
+                       compatible = "ti,sysc-omap2", "ti,sysc";
+                       ti,hwmods = "wd_timer3";
+                       reg = <0x30000 0x4>,
+                             <0x30010 0x4>,
+                             <0x30014 0x4>;
+                       reg-names = "rev", "sysc", "syss";
+                       ti,sysc-mask = <(SYSC_OMAP2_EMUFREE |
+                                        SYSC_OMAP2_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       ti,syss-mask = <1>;
+                       /* Domains (V, P, C): iva, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP4_WD_TIMER3_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x30000 0x1000>,
+                                <0x49030000 0x49030000 0x1000>;
+
+                       wdt3: wdt@0 {
+                               compatible = "ti,omap4-wdt", "ti,omap3-wdt";
+                               reg = <0x0 0x80>;
+                               interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+               };
+
+               mcpdm_module: target-module@32000 {     /* 0x40132000, ap 16 10.0 */
+                       compatible = "ti,sysc-omap4", "ti,sysc";
+                       ti,hwmods = "mcpdm";
+                       reg = <0x32000 0x4>,
+                             <0x32010 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP4_FREEEMU |
+                                        SYSC_OMAP4_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       /* Domains (V, P, C): iva, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP4_MCPDM_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x32000 0x1000>,
+                                <0x49032000 0x49032000 0x1000>;
+
+                       /* Must be only enabled for boards with pdmclk wired */
+                       status = "disabled";
+
+                       mcpdm: mcpdm@0 {
+                               compatible = "ti,omap4-mcpdm";
+                               reg = <0x0 0x7f>, /* MPU private access */
+                                     <0x49032000 0x7f>; /* L3 Interconnect */
+                               reg-names = "mpu", "dma";
+                               interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+                               dmas = <&sdma 65>,
+                                      <&sdma 66>;
+                               dma-names = "up_link", "dn_link";
+                       };
+               };
+
+               target-module@38000 {                   /* 0x40138000, ap 18 12.0 */
+                       compatible = "ti,sysc-omap4-timer", "ti,sysc";
+                       ti,hwmods = "timer5";
+                       reg = <0x38000 0x4>,
+                             <0x38010 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP4_FREEEMU |
+                                        SYSC_OMAP4_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       /* Domains (V, P, C): iva, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP4_TIMER5_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x38000 0x1000>,
+                                <0x49038000 0x49038000 0x1000>;
+
+                       timer5: timer@0 {
+                               compatible = "ti,omap4430-timer";
+                               reg = <0x00000000 0x80>,
+                                     <0x49038000 0x80>;
+                               clocks = <&abe_clkctrl OMAP4_TIMER5_CLKCTRL 24>;
+                               clock-names = "fck";
+                               interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+                               ti,timer-dsp;
+                       };
+               };
+
+               target-module@3a000 {                   /* 0x4013a000, ap 20 14.0 */
+                       compatible = "ti,sysc-omap4-timer", "ti,sysc";
+                       ti,hwmods = "timer6";
+                       reg = <0x3a000 0x4>,
+                             <0x3a010 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP4_FREEEMU |
+                                        SYSC_OMAP4_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       /* Domains (V, P, C): iva, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP4_TIMER6_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x3a000 0x1000>,
+                                <0x4903a000 0x4903a000 0x1000>;
+
+                       timer6: timer@0 {
+                               compatible = "ti,omap4430-timer";
+                               reg = <0x00000000 0x80>,
+                                     <0x4903a000 0x80>;
+                               clocks = <&abe_clkctrl OMAP4_TIMER6_CLKCTRL 24>;
+                               clock-names = "fck";
+                               interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+                               ti,timer-dsp;
+                       };
+               };
+
+               target-module@3c000 {                   /* 0x4013c000, ap 22 16.0 */
+                       compatible = "ti,sysc-omap4-timer", "ti,sysc";
+                       ti,hwmods = "timer7";
+                       reg = <0x3c000 0x4>,
+                             <0x3c010 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP4_FREEEMU |
+                                        SYSC_OMAP4_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       /* Domains (V, P, C): iva, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP4_TIMER7_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x3c000 0x1000>,
+                                <0x4903c000 0x4903c000 0x1000>;
+
+                       timer7: timer@0 {
+                               compatible = "ti,omap4430-timer";
+                               reg = <0x00000000 0x80>,
+                                     <0x4903c000 0x80>;
+                               clocks = <&abe_clkctrl OMAP4_TIMER7_CLKCTRL 24>;
+                               clock-names = "fck";
+                               interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+                               ti,timer-dsp;
+                       };
+               };
+
+               target-module@3e000 {                   /* 0x4013e000, ap 24 18.0 */
+                       compatible = "ti,sysc-omap4-timer", "ti,sysc";
+                       ti,hwmods = "timer8";
+                       reg = <0x3e000 0x4>,
+                             <0x3e010 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP4_FREEEMU |
+                                        SYSC_OMAP4_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       /* Domains (V, P, C): iva, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP4_TIMER8_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x3e000 0x1000>,
+                                <0x4903e000 0x4903e000 0x1000>;
+
+                       timer8: timer@0 {
+                               compatible = "ti,omap4430-timer";
+                               reg = <0x00000000 0x80>,
+                                     <0x4903e000 0x80>;
+                               clocks = <&abe_clkctrl OMAP4_TIMER8_CLKCTRL 24>;
+                               clock-names = "fck";
+                               interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+                               ti,timer-pwm;
+                               ti,timer-dsp;
+                       };
+               };
+
+               target-module@80000 {                   /* 0x40180000, ap 26 1a.0 */
+                       compatible = "ti,sysc";
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x80000 0x10000>,
+                                <0x49080000 0x49080000 0x10000>;
+               };
+
+               target-module@a0000 {                   /* 0x401a0000, ap 28 1c.0 */
+                       compatible = "ti,sysc";
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0xa0000 0x10000>,
+                                <0x490a0000 0x490a0000 0x10000>;
+               };
+
+               target-module@c0000 {                   /* 0x401c0000, ap 30 1e.0 */
+                       compatible = "ti,sysc";
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0xc0000 0x10000>,
+                                <0x490c0000 0x490c0000 0x10000>;
+               };
+
+               target-module@f1000 {                   /* 0x401f1000, ap 32 20.0 */
+                       compatible = "ti,sysc-omap4", "ti,sysc";
+                       ti,hwmods = "aess";
+                       reg = <0xf1000 0x4>,
+                             <0xf1010 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-midle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>;
+                       /* Domains (V, P, C): iva, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP4_AESS_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0xf1000 0x1000>,
+                                <0x490f1000 0x490f1000 0x1000>;
+
+                       /*
+                        * No child device binding or driver in mainline.
+                        * See Android tree and related upstreaming efforts
+                        * for the old driver.
+                        */
+               };
+       };
+};
+
diff --git a/arch/arm/boot/dts/omap4-mcpdm.dtsi b/arch/arm/boot/dts/omap4-mcpdm.dtsi
new file mode 100644 (file)
index 0000000..915a9b3
--- /dev/null
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Common omap4 mcpdm configuration
+ *
+ * Only include this file if your board has pdmclk wired from the
+ * pmic to ABE as mcpdm uses an external clock for the module.
+ */
+
+&omap4_pmx_core {
+       mcpdm_pins: pinmux_mcpdm_pins {
+               pinctrl-single,pins = <
+               /* 0x4a100106 abe_pdm_ul_data.abe_pdm_ul_data ag25 */
+               OMAP4_IOPAD(0x106, PIN_INPUT_PULLDOWN | MUX_MODE0)
+
+               /* 0x4a100108 abe_pdm_dl_data.abe_pdm_dl_data af25 */
+               OMAP4_IOPAD(0x108, PIN_INPUT_PULLDOWN | MUX_MODE0)
+
+               /* 0x4a10010a abe_pdm_frame.abe_pdm_frame ae25 */
+               OMAP4_IOPAD(0x10a, PIN_INPUT_PULLUP   | MUX_MODE0)
+
+               /* 0x4a10010c abe_pdm_lb_clk.abe_pdm_lb_clk af26 */
+               OMAP4_IOPAD(0x10c, PIN_INPUT_PULLDOWN | MUX_MODE0)
+
+               /* 0x4a10010e abe_clks.abe_clks ah26 */
+               OMAP4_IOPAD(0x10e, PIN_INPUT_PULLDOWN | MUX_MODE0)
+               >;
+       };
+};
+
+&mcpdm_module {
+       /*
+        * McPDM pads must be muxed at the interconnect target module
+        * level as the module on the SoC needs external clock from
+        * the PMIC
+        */
+       pinctrl-names = "default";
+       pinctrl-0 = <&mcpdm_pins>;
+       status = "okay";
+};
+
+&mcpdm {
+       clocks = <&twl6040>;
+       clock-names = "pdmclk";
+};
index 926f018823a47a756e45e1267f722a5dd506e232..68e1894df71343f97c14ed3010625e21485f2e67 100644 (file)
@@ -7,6 +7,7 @@
  */
 #include <dt-bindings/input/input.h>
 #include "elpida_ecb240abacn.dtsi"
+#include "omap4-mcpdm.dtsi"
 
 / {
        memory@80000000 {
                >;
        };
 
-       mcpdm_pins: pinmux_mcpdm_pins {
-               pinctrl-single,pins = <
-                       OMAP4_IOPAD(0x106, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_pdm_ul_data.abe_pdm_ul_data */
-                       OMAP4_IOPAD(0x108, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_pdm_dl_data.abe_pdm_dl_data */
-                       OMAP4_IOPAD(0x10a, PIN_INPUT_PULLUP   | MUX_MODE0)      /* abe_pdm_frame.abe_pdm_frame */
-                       OMAP4_IOPAD(0x10c, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_pdm_lb_clk.abe_pdm_lb_clk */
-                       OMAP4_IOPAD(0x10e, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_clks.abe_clks */
-               >;
-       };
-
        mcbsp1_pins: pinmux_mcbsp1_pins {
                pinctrl-single,pins = <
                        OMAP4_IOPAD(0x0fe, PIN_INPUT | MUX_MODE0)               /* abe_mcbsp1_clkx.abe_mcbsp1_clkx */
        status = "okay";
 };
 
-&mcpdm {
-       pinctrl-names = "default";
-       pinctrl-0 = <&mcpdm_pins>;
-
-       clocks = <&twl6040>;
-       clock-names = "pdmclk";
-
-       status = "okay";
-};
-
 &twl_usb_comparator {
        usb-supply = <&vusb>;
 };
index c88817bdcc560d231c274fd88f536f8f70ba6bee..fb51a4bffd35392e8b9807b56e7cfe678953d089 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "omap443x.dtsi"
 #include "elpida_ecb240abacn.dtsi"
+#include "omap4-mcpdm.dtsi"
 
 / {
        model = "TI OMAP4 SDP board";
                >;
        };
 
-       mcpdm_pins: pinmux_mcpdm_pins {
-               pinctrl-single,pins = <
-                       OMAP4_IOPAD(0x106, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_pdm_ul_data.abe_pdm_ul_data */
-                       OMAP4_IOPAD(0x108, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_pdm_dl_data.abe_pdm_dl_data */
-                       OMAP4_IOPAD(0x10a, PIN_INPUT_PULLUP | MUX_MODE0)        /* abe_pdm_frame.abe_pdm_frame */
-                       OMAP4_IOPAD(0x10c, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_pdm_lb_clk.abe_pdm_lb_clk */
-                       OMAP4_IOPAD(0x10e, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_clks.abe_clks */
-               >;
-       };
-
        dmic_pins: pinmux_dmic_pins {
                pinctrl-single,pins = <
                        OMAP4_IOPAD(0x110, PIN_OUTPUT | MUX_MODE0)              /* abe_dmic_clk1.abe_dmic_clk1 */
        status = "okay";
 };
 
-&mcpdm {
-       pinctrl-names = "default";
-       pinctrl-0 = <&mcpdm_pins>;
-
-       clocks = <&twl6040>;
-       clock-names = "pdmclk";
-
-       status = "okay";
-};
-
 &twl_usb_comparator {
        usb-supply = <&vusb>;
 };
index 10fce28ceb5b7dc38477e60f0d87a86b6a384638..9562d372077c4fa3500d7a274a5d4348a2eaf8bd 100644 (file)
@@ -7,6 +7,7 @@
  * published by the Free Software Foundation.
  */
 #include "omap4460.dtsi"
+#include "omap4-mcpdm.dtsi"
 
 / {
        model = "Variscite VAR-SOM-OM44";
                >;
        };
 
-       mcpdm_pins: pinmux_mcpdm_pins {
-               pinctrl-single,pins = <
-                       OMAP4_IOPAD(0x106, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_pdm_ul_data.abe_pdm_ul_data */
-                       OMAP4_IOPAD(0x108, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_pdm_dl_data.abe_pdm_dl_data */
-                       OMAP4_IOPAD(0x10a, PIN_INPUT_PULLUP | MUX_MODE0)        /* abe_pdm_frame.abe_pdm_frame */
-                       OMAP4_IOPAD(0x10c, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_pdm_lb_clk.abe_pdm_lb_clk */
-                       OMAP4_IOPAD(0x10e, PIN_INPUT_PULLDOWN | MUX_MODE0)      /* abe_clks.abe_clks */
-               >;
-       };
-
        tsc2004_pins: pinmux_tsc2004_pins {
                pinctrl-single,pins = <
                        OMAP4_IOPAD(0x090, PIN_INPUT | MUX_MODE3)               /* gpmc_ncs4.gpio_101 (irq) */
        status = "disabled";
 };
 
-&mcpdm {
-       pinctrl-names = "default";
-       pinctrl-0 = <&mcpdm_pins>;
-
-       clocks = <&twl6040>;
-       clock-names = "pdmclk";
-
-       status = "okay";
-};
-
 &gpmc {
        status = "disabled";
 };
index 1a96d4317c9757e7dc6d991d1a25405b9090e952..442a737f35fec850d3c8d730489dd9ac3b75656b 100644 (file)
                l4_per: interconnect@48000000 {
                };
 
+               l4_abe: interconnect@40100000 {
+               };
+
                ocmcram: ocmcram@40304000 {
                        compatible = "mmio-sram";
                        reg = <0x40304000 0xa000>; /* 40k */
                        #iommu-cells = <0>;
                        ti,iommu-bus-err-back;
                };
-               target-module@40130000 {
-                       compatible = "ti,sysc-omap2", "ti,sysc";
-                       ti,hwmods = "wd_timer3";
-                       reg = <0x40130000 0x4>,
-                             <0x40130010 0x4>,
-                             <0x40130014 0x4>;
-                       reg-names = "rev", "sysc", "syss";
-                       ti,sysc-mask = <(SYSC_OMAP2_EMUFREE |
-                                        SYSC_OMAP2_SOFTRESET)>;
-                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
-                                       <SYSC_IDLE_NO>,
-                                       <SYSC_IDLE_SMART>,
-                                       <SYSC_IDLE_SMART_WKUP>;
-                       ti,syss-mask = <1>;
-                       /* Domains (V, P, C): abe, abe_pwrdm, abe_clkdm */
-                       clocks = <&abe_clkctrl OMAP4_WD_TIMER3_CLKCTRL 0>;
-                       clock-names = "fck";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       ranges = <0x00000000 0x40130000 0x1000>, /* MPU private access */
-                                <0x49030000 0x49030000 0x0080>; /* L3 Interconnect */
-
-                       wdt3: wdt@0 {
-                               compatible = "ti,omap4-wdt", "ti,omap3-wdt";
-                               reg = <0x0 0x80>;
-                               interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
-                       };
-               };
-
-               mcpdm: mcpdm@40132000 {
-                       compatible = "ti,omap4-mcpdm";
-                       reg = <0x40132000 0x7f>, /* MPU private access */
-                             <0x49032000 0x7f>; /* L3 Interconnect */
-                       reg-names = "mpu", "dma";
-                       interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
-                       ti,hwmods = "mcpdm";
-                       dmas = <&sdma 65>,
-                              <&sdma 66>;
-                       dma-names = "up_link", "dn_link";
-                       status = "disabled";
-               };
-
-               dmic: dmic@4012e000 {
-                       compatible = "ti,omap4-dmic";
-                       reg = <0x4012e000 0x7f>, /* MPU private access */
-                             <0x4902e000 0x7f>; /* L3 Interconnect */
-                       reg-names = "mpu", "dma";
-                       interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
-                       ti,hwmods = "dmic";
-                       dmas = <&sdma 67>;
-                       dma-names = "up_link";
-                       status = "disabled";
-               };
-
-               mcbsp1: mcbsp@40122000 {
-                       compatible = "ti,omap4-mcbsp";
-                       reg = <0x40122000 0xff>, /* MPU private access */
-                             <0x49022000 0xff>; /* L3 Interconnect */
-                       reg-names = "mpu", "dma";
-                       interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "common";
-                       ti,buffer-size = <128>;
-                       ti,hwmods = "mcbsp1";
-                       dmas = <&sdma 33>,
-                              <&sdma 34>;
-                       dma-names = "tx", "rx";
-                       status = "disabled";
-               };
-
-               mcbsp2: mcbsp@40124000 {
-                       compatible = "ti,omap4-mcbsp";
-                       reg = <0x40124000 0xff>, /* MPU private access */
-                             <0x49024000 0xff>; /* L3 Interconnect */
-                       reg-names = "mpu", "dma";
-                       interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "common";
-                       ti,buffer-size = <128>;
-                       ti,hwmods = "mcbsp2";
-                       dmas = <&sdma 17>,
-                              <&sdma 18>;
-                       dma-names = "tx", "rx";
-                       status = "disabled";
-               };
-
-               mcbsp3: mcbsp@40126000 {
-                       compatible = "ti,omap4-mcbsp";
-                       reg = <0x40126000 0xff>, /* MPU private access */
-                             <0x49026000 0xff>; /* L3 Interconnect */
-                       reg-names = "mpu", "dma";
-                       interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "common";
-                       ti,buffer-size = <128>;
-                       ti,hwmods = "mcbsp3";
-                       dmas = <&sdma 19>,
-                              <&sdma 20>;
-                       dma-names = "tx", "rx";
-                       status = "disabled";
-               };
-
-               target-module@40128000 {
-                       compatible = "ti,sysc-mcasp", "ti,sysc";
-                       ti,hwmods = "mcasp";
-                       reg = <0x40128000 0x4>,
-                             <0x40128004 0x4>;
-                       reg-names = "rev", "sysc";
-                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
-                                       <SYSC_IDLE_NO>,
-                                       <SYSC_IDLE_SMART>,
-                                       <SYSC_IDLE_SMART_WKUP>;
-                       clocks = <&abe_clkctrl OMAP4_MCASP_CLKCTRL 0>;
-                       clock-names = "fck";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       ranges = <0x00000000 0x40128000 0x1000>, /* MPU */
-                                <0x49028000 0x49028000 0x1000>; /* L3 */
-
-                       /*
-                        * Child device unsupported by davinci-mcasp. At least
-                        * RX path is disabled for omap4, and only DIT mode
-                        * works with no I2S. See also old Android kernel
-                        * omap-mcasp driver for more information.
-                        */
-               };
-
                target-module@4012c000 {
                        compatible = "ti,sysc-omap4", "ti,sysc";
                        ti,hwmods = "slimbus1";
                        /* No child device binding or driver in mainline */
                };
 
-               target-module@401f1000 {
-                       compatible = "ti,sysc-omap4", "ti,sysc";
-                       ti,hwmods = "aess";
-                       reg = <0x401f1000 0x4>,
-                             <0x401f1010 0x4>;
-                       reg-names = "rev", "sysc";
-                       ti,sysc-midle = <SYSC_IDLE_FORCE>,
-                                       <SYSC_IDLE_NO>,
-                                       <SYSC_IDLE_SMART>,
-                                       <SYSC_IDLE_SMART_WKUP>;
-                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
-                                       <SYSC_IDLE_NO>,
-                                       <SYSC_IDLE_SMART>;
-                       clocks = <&abe_clkctrl OMAP4_AESS_CLKCTRL 0>;
-                       clock-names = "fck";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       ranges = <0x00000000 0x401f1000 0x1000>, /* MPU */
-                                <0x490f1000 0x490f1000 0x1000>; /* L3 */
-
-                       /*
-                        * No child device binding or driver in mainline.
-                        * See Android tree and related upstreaming efforts
-                        * for the old driver.
-                        */
-               };
-
                dmm@4e000000 {
                        compatible = "ti,omap4-dmm";
                        reg = <0x4e000000 0x800>;
                        hw-caps-temp-alert;
                };
 
-               timer5: timer@40138000 {
-                       compatible = "ti,omap4430-timer";
-                       reg = <0x40138000 0x80>,
-                             <0x49038000 0x80>;
-                       interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
-                       ti,hwmods = "timer5";
-                       ti,timer-dsp;
-               };
-
-               timer6: timer@4013a000 {
-                       compatible = "ti,omap4430-timer";
-                       reg = <0x4013a000 0x80>,
-                             <0x4903a000 0x80>;
-                       interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
-                       ti,hwmods = "timer6";
-                       ti,timer-dsp;
-               };
-
-               timer7: timer@4013c000 {
-                       compatible = "ti,omap4430-timer";
-                       reg = <0x4013c000 0x80>,
-                             <0x4903c000 0x80>;
-                       interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
-                       ti,hwmods = "timer7";
-                       ti,timer-dsp;
-               };
-
-               timer8: timer@4013e000 {
-                       compatible = "ti,omap4430-timer";
-                       reg = <0x4013e000 0x80>,
-                             <0x4903e000 0x80>;
-                       interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
-                       ti,hwmods = "timer8";
-                       ti,timer-pwm;
-                       ti,timer-dsp;
-               };
-
                aes1: aes@4b501000 {
                        compatible = "ti,omap4-aes";
                        ti,hwmods = "aes1";
 };
 
 #include "omap4-l4.dtsi"
+#include "omap4-l4-abe.dtsi"
 #include "omap44xx-clocks.dtsi"
index 61a06f6add3ca52a9d7c4851080c53d0a5d18ac9..2dc3e1950c9600218a61fdb3b78069a384188877 100644 (file)
        };
 };
 
-&mcpdm {
+&mcpdm_module {
+       /* Module on the SoC needs external clock from the PMIC */
        pinctrl-names = "default";
        pinctrl-0 = <&mcpdm_pins>;
+       status = "okay";
+};
 
+&mcpdm {
        clocks = <&twl6040>;
        clock-names = "pdmclk";
-
-       status = "okay";
 };
 
 &mcbsp1 {
diff --git a/arch/arm/boot/dts/omap5-l4-abe.dtsi b/arch/arm/boot/dts/omap5-l4-abe.dtsi
new file mode 100644 (file)
index 0000000..dc9d053
--- /dev/null
@@ -0,0 +1,447 @@
+&l4_abe {                                              /* 0x40100000 */
+       compatible = "ti,omap5-l4-abe", "simple-bus";
+       reg = <0x40100000 0x400>,
+             <0x40100400 0x400>;
+       reg-names = "la", "ap";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       ranges = <0x00000000 0x40100000 0x100000>,      /* segment 0 */
+                <0x49000000 0x49000000 0x100000>;
+       segment@0 {                                     /* 0x40100000 */
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges =
+                        /* CPU to L4 ABE mapping */
+                        <0x00000000 0x00000000 0x000400>,      /* ap 0 */
+                        <0x00000400 0x00000400 0x000400>,      /* ap 1 */
+                        <0x00022000 0x00022000 0x001000>,      /* ap 2 */
+                        <0x00023000 0x00023000 0x001000>,      /* ap 3 */
+                        <0x00024000 0x00024000 0x001000>,      /* ap 4 */
+                        <0x00025000 0x00025000 0x001000>,      /* ap 5 */
+                        <0x00026000 0x00026000 0x001000>,      /* ap 6 */
+                        <0x00027000 0x00027000 0x001000>,      /* ap 7 */
+                        <0x00028000 0x00028000 0x001000>,      /* ap 8 */
+                        <0x00029000 0x00029000 0x001000>,      /* ap 9 */
+                        <0x0002a000 0x0002a000 0x001000>,      /* ap 10 */
+                        <0x0002b000 0x0002b000 0x001000>,      /* ap 11 */
+                        <0x0002e000 0x0002e000 0x001000>,      /* ap 12 */
+                        <0x0002f000 0x0002f000 0x001000>,      /* ap 13 */
+                        <0x00030000 0x00030000 0x001000>,      /* ap 14 */
+                        <0x00031000 0x00031000 0x001000>,      /* ap 15 */
+                        <0x00032000 0x00032000 0x001000>,      /* ap 16 */
+                        <0x00033000 0x00033000 0x001000>,      /* ap 17 */
+                        <0x00038000 0x00038000 0x001000>,      /* ap 18 */
+                        <0x00039000 0x00039000 0x001000>,      /* ap 19 */
+                        <0x0003a000 0x0003a000 0x001000>,      /* ap 20 */
+                        <0x0003b000 0x0003b000 0x001000>,      /* ap 21 */
+                        <0x0003c000 0x0003c000 0x001000>,      /* ap 22 */
+                        <0x0003d000 0x0003d000 0x001000>,      /* ap 23 */
+                        <0x0003e000 0x0003e000 0x001000>,      /* ap 24 */
+                        <0x0003f000 0x0003f000 0x001000>,      /* ap 25 */
+                        <0x00080000 0x00080000 0x010000>,      /* ap 26 */
+                        <0x00080000 0x00080000 0x001000>,      /* ap 27 */
+                        <0x000a0000 0x000a0000 0x010000>,      /* ap 28 */
+                        <0x000a0000 0x000a0000 0x001000>,      /* ap 29 */
+                        <0x000c0000 0x000c0000 0x010000>,      /* ap 30 */
+                        <0x000c0000 0x000c0000 0x001000>,      /* ap 31 */
+                        <0x000f1000 0x000f1000 0x001000>,      /* ap 32 */
+                        <0x000f2000 0x000f2000 0x001000>,      /* ap 33 */
+
+                        /* L3 to L4 ABE mapping */
+                        <0x49000000 0x49000000 0x000400>,      /* ap 0 */
+                        <0x49000400 0x49000400 0x000400>,      /* ap 1 */
+                        <0x49022000 0x49022000 0x001000>,      /* ap 2 */
+                        <0x49023000 0x49023000 0x001000>,      /* ap 3 */
+                        <0x49024000 0x49024000 0x001000>,      /* ap 4 */
+                        <0x49025000 0x49025000 0x001000>,      /* ap 5 */
+                        <0x49026000 0x49026000 0x001000>,      /* ap 6 */
+                        <0x49027000 0x49027000 0x001000>,      /* ap 7 */
+                        <0x49028000 0x49028000 0x001000>,      /* ap 8 */
+                        <0x49029000 0x49029000 0x001000>,      /* ap 9 */
+                        <0x4902a000 0x4902a000 0x001000>,      /* ap 10 */
+                        <0x4902b000 0x4902b000 0x001000>,      /* ap 11 */
+                        <0x4902e000 0x4902e000 0x001000>,      /* ap 12 */
+                        <0x4902f000 0x4902f000 0x001000>,      /* ap 13 */
+                        <0x49030000 0x49030000 0x001000>,      /* ap 14 */
+                        <0x49031000 0x49031000 0x001000>,      /* ap 15 */
+                        <0x49032000 0x49032000 0x001000>,      /* ap 16 */
+                        <0x49033000 0x49033000 0x001000>,      /* ap 17 */
+                        <0x49038000 0x49038000 0x001000>,      /* ap 18 */
+                        <0x49039000 0x49039000 0x001000>,      /* ap 19 */
+                        <0x4903a000 0x4903a000 0x001000>,      /* ap 20 */
+                        <0x4903b000 0x4903b000 0x001000>,      /* ap 21 */
+                        <0x4903c000 0x4903c000 0x001000>,      /* ap 22 */
+                        <0x4903d000 0x4903d000 0x001000>,      /* ap 23 */
+                        <0x4903e000 0x4903e000 0x001000>,      /* ap 24 */
+                        <0x4903f000 0x4903f000 0x001000>,      /* ap 25 */
+                        <0x49080000 0x49080000 0x010000>,      /* ap 26 */
+                        <0x49080000 0x49080000 0x001000>,      /* ap 27 */
+                        <0x490a0000 0x490a0000 0x010000>,      /* ap 28 */
+                        <0x490a0000 0x490a0000 0x001000>,      /* ap 29 */
+                        <0x490c0000 0x490c0000 0x010000>,      /* ap 30 */
+                        <0x490c0000 0x490c0000 0x001000>,      /* ap 31 */
+                        <0x490f1000 0x490f1000 0x001000>,      /* ap 32 */
+                        <0x490f2000 0x490f2000 0x001000>;      /* ap 33 */
+
+               target-module@22000 {                   /* 0x40122000, ap 2 02.0 */
+                       compatible = "ti,sysc-omap2", "ti,sysc";
+                       ti,hwmods = "mcbsp1";
+                       reg = <0x2208c 0x4>;
+                       reg-names = "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP2_CLOCKACTIVITY |
+                                        SYSC_OMAP2_ENAWAKEUP |
+                                        SYSC_OMAP2_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>;
+                       /* Domains (V, P, C): core, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP5_MCBSP1_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x22000 0x1000>,
+                                <0x49022000 0x49022000 0x1000>;
+
+                       mcbsp1: mcbsp@0 {
+                               compatible = "ti,omap4-mcbsp";
+                               reg = <0x0 0xff>, /* MPU private access */
+                                     <0x49022000 0xff>; /* L3 Interconnect */
+                               reg-names = "mpu", "dma";
+                               interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "common";
+                               ti,buffer-size = <128>;
+                               dmas = <&sdma 33>,
+                                      <&sdma 34>;
+                               dma-names = "tx", "rx";
+                               status = "disabled";
+                       };
+               };
+
+               target-module@24000 {                   /* 0x40124000, ap 4 04.0 */
+                       compatible = "ti,sysc-omap2", "ti,sysc";
+                       ti,hwmods = "mcbsp2";
+                       reg = <0x2408c 0x4>;
+                       reg-names = "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP2_CLOCKACTIVITY |
+                                        SYSC_OMAP2_ENAWAKEUP |
+                                        SYSC_OMAP2_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>;
+                       /* Domains (V, P, C): core, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP5_MCBSP2_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x24000 0x1000>,
+                                <0x49024000 0x49024000 0x1000>;
+
+                       mcbsp2: mcbsp@0 {
+                               compatible = "ti,omap4-mcbsp";
+                               reg = <0x0 0xff>, /* MPU private access */
+                                     <0x49024000 0xff>; /* L3 Interconnect */
+                               reg-names = "mpu", "dma";
+                               interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "common";
+                               ti,buffer-size = <128>;
+                               dmas = <&sdma 17>,
+                                      <&sdma 18>;
+                               dma-names = "tx", "rx";
+                               status = "disabled";
+                       };
+               };
+
+               target-module@26000 {                   /* 0x40126000, ap 6 06.0 */
+                       compatible = "ti,sysc-omap2", "ti,sysc";
+                       ti,hwmods = "mcbsp3";
+                       reg = <0x2608c 0x4>;
+                       reg-names = "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP2_CLOCKACTIVITY |
+                                        SYSC_OMAP2_ENAWAKEUP |
+                                        SYSC_OMAP2_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>;
+                       /* Domains (V, P, C): core, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP5_MCBSP3_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x26000 0x1000>,
+                                <0x49026000 0x49026000 0x1000>;
+
+                       mcbsp3: mcbsp@0 {
+                               compatible = "ti,omap4-mcbsp";
+                               reg = <0x0 0xff>, /* MPU private access */
+                                     <0x49026000 0xff>; /* L3 Interconnect */
+                               reg-names = "mpu", "dma";
+                               interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "common";
+                               ti,buffer-size = <128>;
+                               dmas = <&sdma 19>,
+                                      <&sdma 20>;
+                               dma-names = "tx", "rx";
+                               status = "disabled";
+                       };
+               };
+
+               target-module@28000 {                   /* 0x40128000, ap 8 08.0 */
+                       compatible = "ti,sysc";
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x28000 0x1000>,
+                                <0x49028000 0x49028000 0x1000>;
+               };
+
+               target-module@2a000 {                   /* 0x4012a000, ap 10 0a.0 */
+                       compatible = "ti,sysc";
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x2a000 0x1000>,
+                                <0x4902a000 0x4902a000 0x1000>;
+               };
+
+               target-module@2e000 {                   /* 0x4012e000, ap 12 0c.0 */
+                       compatible = "ti,sysc-omap4", "ti,sysc";
+                       ti,hwmods = "dmic";
+                       reg = <0x2e000 0x4>,
+                             <0x2e010 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP4_FREEEMU |
+                                        SYSC_OMAP4_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       /* Domains (V, P, C): core, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP5_DMIC_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x2e000 0x1000>,
+                                <0x4902e000 0x4902e000 0x1000>;
+
+                       dmic: dmic@0 {
+                               compatible = "ti,omap4-dmic";
+                               reg = <0x0 0x7f>, /* MPU private access */
+                                     <0x4902e000 0x7f>; /* L3 Interconnect */
+                               reg-names = "mpu", "dma";
+                               interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+                               dmas = <&sdma 67>;
+                               dma-names = "up_link";
+                               status = "disabled";
+                       };
+               };
+
+               target-module@30000 {                   /* 0x40130000, ap 14 0e.0 */
+                       compatible = "ti,sysc";
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x30000 0x1000>,
+                                <0x49030000 0x49030000 0x1000>;
+               };
+
+               mcpdm_module: target-module@32000 {     /* 0x40132000, ap 16 10.0 */
+                       compatible = "ti,sysc-omap4", "ti,sysc";
+                       ti,hwmods = "mcpdm";
+                       reg = <0x32000 0x4>,
+                             <0x32010 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP4_FREEEMU |
+                                        SYSC_OMAP4_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       /* Domains (V, P, C): core, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP5_MCPDM_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x32000 0x1000>,
+                                <0x49032000 0x49032000 0x1000>;
+
+                       /* Must be only enabled for boards with pdmclk wired */
+                       status = "disabled";
+
+                       mcpdm: mcpdm@0 {
+                               compatible = "ti,omap4-mcpdm";
+                               reg = <0x0 0x7f>, /* MPU private access */
+                                     <0x49032000 0x7f>; /* L3 Interconnect */
+                               reg-names = "mpu", "dma";
+                               interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+                               dmas = <&sdma 65>,
+                                      <&sdma 66>;
+                               dma-names = "up_link", "dn_link";
+                       };
+               };
+
+               target-module@38000 {                   /* 0x40138000, ap 18 12.0 */
+                       compatible = "ti,sysc-omap4-timer", "ti,sysc";
+                       ti,hwmods = "timer5";
+                       reg = <0x38000 0x4>,
+                             <0x38010 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP4_FREEEMU |
+                                        SYSC_OMAP4_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       /* Domains (V, P, C): core, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP5_TIMER5_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x38000 0x1000>,
+                                <0x49038000 0x49038000 0x1000>;
+
+                       timer5: timer@0 {
+                               compatible = "ti,omap5430-timer";
+                               reg = <0x0 0x80>,
+                                     <0x49038000 0x80>;
+                               clocks = <&abe_clkctrl OMAP5_TIMER5_CLKCTRL 24>;
+                               clock-names = "fck";
+                               interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+                               ti,timer-dsp;
+                               ti,timer-pwm;
+                       };
+               };
+
+               target-module@3a000 {                   /* 0x4013a000, ap 20 14.0 */
+                       compatible = "ti,sysc-omap4-timer", "ti,sysc";
+                       ti,hwmods = "timer6";
+                       reg = <0x3a000 0x4>,
+                             <0x3a010 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP4_FREEEMU |
+                                        SYSC_OMAP4_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       /* Domains (V, P, C): core, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP5_TIMER6_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x3a000 0x1000>,
+                                <0x4903a000 0x4903a000 0x1000>;
+
+                       timer6: timer@0 {
+                               compatible = "ti,omap5430-timer";
+                               reg = <0x0 0x80>,
+                                     <0x4903a000 0x80>;
+                               clocks = <&abe_clkctrl OMAP5_TIMER6_CLKCTRL 24>;
+                               clock-names = "fck";
+                               interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+                               ti,timer-dsp;
+                               ti,timer-pwm;
+                       };
+               };
+
+               target-module@3c000 {                   /* 0x4013c000, ap 22 16.0 */
+                       compatible = "ti,sysc-omap4-timer", "ti,sysc";
+                       ti,hwmods = "timer7";
+                       reg = <0x3c000 0x4>,
+                             <0x3c010 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP4_FREEEMU |
+                                        SYSC_OMAP4_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       /* Domains (V, P, C): core, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP5_TIMER7_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x3c000 0x1000>,
+                                <0x4903c000 0x4903c000 0x1000>;
+
+                       timer7: timer@0 {
+                               compatible = "ti,omap5430-timer";
+                               reg = <0x0 0x80>,
+                                     <0x4903c000 0x80>;
+                               clocks = <&abe_clkctrl OMAP5_TIMER7_CLKCTRL 24>;
+                               clock-names = "fck";
+                               interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+                               ti,timer-dsp;
+                       };
+               };
+
+               target-module@3e000 {                   /* 0x4013e000, ap 24 18.0 */
+                       compatible = "ti,sysc-omap4-timer", "ti,sysc";
+                       ti,hwmods = "timer8";
+                       reg = <0x3e000 0x4>,
+                             <0x3e010 0x4>;
+                       reg-names = "rev", "sysc";
+                       ti,sysc-mask = <(SYSC_OMAP4_FREEEMU |
+                                        SYSC_OMAP4_SOFTRESET)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
+                       /* Domains (V, P, C): core, abe_pwrdm, abe_clkdm */
+                       clocks = <&abe_clkctrl OMAP5_TIMER8_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x3e000 0x1000>,
+                                <0x4903e000 0x4903e000 0x1000>;
+
+                       timer8: timer@0 {
+                               compatible = "ti,omap5430-timer";
+                               reg = <0x0 0x80>,
+                                     <0x4903e000 0x80>;
+                               clocks = <&abe_clkctrl OMAP5_TIMER8_CLKCTRL 24>;
+                               clock-names = "fck";
+                               interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+                               ti,timer-dsp;
+                               ti,timer-pwm;
+                       };
+               };
+
+               target-module@80000 {                   /* 0x40180000, ap 26 1a.0 */
+                       compatible = "ti,sysc";
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x80000 0x10000>,
+                                <0x49080000 0x49080000 0x10000>;
+               };
+
+               target-module@a0000 {                   /* 0x401a0000, ap 28 1c.0 */
+                       compatible = "ti,sysc";
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0xa0000 0x10000>,
+                                <0x490a0000 0x490a0000 0x10000>;
+               };
+
+               target-module@c0000 {                   /* 0x401c0000, ap 30 1e.0 */
+                       compatible = "ti,sysc";
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0xc0000 0x10000>,
+                                <0x490c0000 0x490c0000 0x10000>;
+               };
+
+               target-module@f1000 {                   /* 0x401f1000, ap 32 20.0 */
+                       compatible = "ti,sysc";
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0xf1000 0x1000>,
+                                <0x490f1000 0x490f1000 0x1000>;
+               };
+       };
+};
+
index 2fefaafdf9013b416f6b14ee1f86471ae4bab213..4b40e47486490ab145077ccb177ab2668905969f 100644 (file)
                l4_per: interconnect@48000000 {
                };
 
+               l4_abe: interconnect@40100000 {
+               };
+
                ocmcram: ocmcram@40300000 {
                        compatible = "mmio-sram";
                        reg = <0x40300000 0x20000>; /* 128k */
                        ti,iommu-bus-err-back;
                };
 
-               mcpdm: mcpdm@40132000 {
-                       compatible = "ti,omap4-mcpdm";
-                       reg = <0x40132000 0x7f>, /* MPU private access */
-                             <0x49032000 0x7f>; /* L3 Interconnect */
-                       reg-names = "mpu", "dma";
-                       interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
-                       ti,hwmods = "mcpdm";
-                       dmas = <&sdma 65>,
-                              <&sdma 66>;
-                       dma-names = "up_link", "dn_link";
-                       status = "disabled";
-               };
-
-               dmic: dmic@4012e000 {
-                       compatible = "ti,omap4-dmic";
-                       reg = <0x4012e000 0x7f>, /* MPU private access */
-                             <0x4902e000 0x7f>; /* L3 Interconnect */
-                       reg-names = "mpu", "dma";
-                       interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
-                       ti,hwmods = "dmic";
-                       dmas = <&sdma 67>;
-                       dma-names = "up_link";
-                       status = "disabled";
-               };
-
-               mcbsp1: mcbsp@40122000 {
-                       compatible = "ti,omap4-mcbsp";
-                       reg = <0x40122000 0xff>, /* MPU private access */
-                             <0x49022000 0xff>; /* L3 Interconnect */
-                       reg-names = "mpu", "dma";
-                       interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "common";
-                       ti,buffer-size = <128>;
-                       ti,hwmods = "mcbsp1";
-                       dmas = <&sdma 33>,
-                              <&sdma 34>;
-                       dma-names = "tx", "rx";
-                       status = "disabled";
-               };
-
-               mcbsp2: mcbsp@40124000 {
-                       compatible = "ti,omap4-mcbsp";
-                       reg = <0x40124000 0xff>, /* MPU private access */
-                             <0x49024000 0xff>; /* L3 Interconnect */
-                       reg-names = "mpu", "dma";
-                       interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "common";
-                       ti,buffer-size = <128>;
-                       ti,hwmods = "mcbsp2";
-                       dmas = <&sdma 17>,
-                              <&sdma 18>;
-                       dma-names = "tx", "rx";
-                       status = "disabled";
-               };
-
-               mcbsp3: mcbsp@40126000 {
-                       compatible = "ti,omap4-mcbsp";
-                       reg = <0x40126000 0xff>, /* MPU private access */
-                             <0x49026000 0xff>; /* L3 Interconnect */
-                       reg-names = "mpu", "dma";
-                       interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "common";
-                       ti,buffer-size = <128>;
-                       ti,hwmods = "mcbsp3";
-                       dmas = <&sdma 19>,
-                              <&sdma 20>;
-                       dma-names = "tx", "rx";
-                       status = "disabled";
-               };
-
-               timer5: timer@40138000 {
-                       compatible = "ti,omap5430-timer";
-                       reg = <0x40138000 0x80>,
-                             <0x49038000 0x80>;
-                       interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
-                       ti,hwmods = "timer5";
-                       ti,timer-dsp;
-                       ti,timer-pwm;
-               };
-
-               timer6: timer@4013a000 {
-                       compatible = "ti,omap5430-timer";
-                       reg = <0x4013a000 0x80>,
-                             <0x4903a000 0x80>;
-                       interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
-                       ti,hwmods = "timer6";
-                       ti,timer-dsp;
-                       ti,timer-pwm;
-               };
-
-               timer7: timer@4013c000 {
-                       compatible = "ti,omap5430-timer";
-                       reg = <0x4013c000 0x80>,
-                             <0x4903c000 0x80>;
-                       interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
-                       ti,hwmods = "timer7";
-                       ti,timer-dsp;
-               };
-
-               timer8: timer@4013e000 {
-                       compatible = "ti,omap5430-timer";
-                       reg = <0x4013e000 0x80>,
-                             <0x4903e000 0x80>;
-                       interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
-                       ti,hwmods = "timer8";
-                       ti,timer-dsp;
-                       ti,timer-pwm;
-               };
-
                dmm@4e000000 {
                        compatible = "ti,omap5-dmm";
                        reg = <0x4e000000 0x800>;
 &core_thermal {
        coefficients = <0 2000>;
 };
+
+#include "omap5-l4-abe.dtsi"
+#include "omap54xx-clocks.dtsi"
index bd6907db615b4e87edd85ab16924d60f1a6f8620..65975df6a8c34d7e3ffef2c1b2e3452b026e9c7c 100644 (file)
                                        interrupt-controller;
                                        #interrupt-cells = <2>;
                                        gpio-controller;
+                                       gpio-ranges = <&pm8921_gpio 0 0 44>;
                                        #gpio-cells = <2>;
 
                                };
                                <0x04700300 0x200>,
                                <0x04700500 0x5c>;
                        reg-names = "dsi_pll", "dsi_phy", "dsi_phy_regulator";
-                       clock-names = "iface_clk";
-                       clocks = <&mmcc DSI_M_AHB_CLK>;
+                       clock-names = "iface_clk", "ref";
+                       clocks = <&mmcc DSI_M_AHB_CLK>,
+                                <&cxo_board>;
                };
 
 
index 9e75f97770ceb6263ef2090fb62d832970e915d8..1008dfbcb9728eb16b03eec99bcd8755a3c2ad14 100644 (file)
                        #address-cells = <3>;
                        #size-cells = <2>;
 
-                       ranges = <0x81000000 0 0x40200000 0x40200000 0 0x00100000
-                                 0x82000000 0 0x40300000 0x40300000 0 0x400000>;
+                       ranges = <0x81000000 0 0x40200000 0x40200000 0 0x00100000>,
+                                <0x82000000 0 0x40300000 0x40300000 0 0x00d00000>;
 
                        interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "msi";
index 02afc6a42005c79d0d9dfad44c39857fe4905d92..356e9535f7a6840568a3dfe5481c5eaf26d75b8b 100644 (file)
                                        interrupt-controller;
                                        #interrupt-cells = <2>;
                                        gpio-controller;
+                                       gpio-ranges = <&pmicgpio 0 0 6>;
                                        #gpio-cells = <2>;
                                };
                        };
index 65a994f0e09babe6edf817941c3adc61b6d846ae..ec5cbc468bd3856d61829308c02bcb933cd10355 100644 (file)
                                        interrupt-controller;
                                        #interrupt-cells = <2>;
                                        gpio-controller;
+                                       gpio-ranges = <&pm8058_gpio 0 0 44>;
                                        #gpio-cells = <2>;
 
                                };
index 8f5ea7add20f1100a615e06bf7cf06c149f721c0..ea1ca166165c0b0ea8f8be9c1943e8debca9cb32 100644 (file)
@@ -31,6 +31,7 @@
                        compatible = "qcom,pma8084-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
+                       gpio-ranges = <&pma8084_gpios 0 0 22>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index 8ee44a100e9a44c41737a1697b0950c6e4001030..ff24301dc1be54de6dad77934b75e645395d5142 100644 (file)
        };
 
        leds {
-               status = "okay";
                compatible = "gpio-leds";
 
                led0 {
                        gpios = <&port7 1 GPIO_ACTIVE_LOW>;
                };
+
+               led1 {
+                       gpios = <&io_expander1 0 GPIO_ACTIVE_LOW>;
+               };
+
+               led2 {
+                       gpios = <&io_expander1 1 GPIO_ACTIVE_LOW>;
+               };
+
+               led3 {
+                       gpios = <&io_expander1 2 GPIO_ACTIVE_LOW>;
+               };
        };
 };
 
        clock-frequency = <13330000>;
 };
 
+&i2c3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c3_pins>;
+       status = "okay";
+
+       clock-frequency = <400000>;
+
+       io_expander1: gpio@20 {
+               compatible = "onnn,cat9554";
+               reg = <0x20>;
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+
+       io_expander2: gpio@21 {
+               compatible = "onnn,cat9554";
+               reg = <0x21>;
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+
+       eeprom@50 {
+               compatible = "renesas,r1ex24016", "atmel,24c16";
+               reg = <0x50>;
+               pagesize = <16>;
+       };
+};
+
 &usb_x1_clk {
        clock-frequency = <48000000>;
 };
 };
 
 &pinctrl {
+       /* RIIC ch3 (Port Expander, EEPROM (MAC Addr), Audio Codec) */
+       i2c3_pins: i2c3 {
+               pinmux = <RZA1_PINMUX(1, 6, 1)>,        /* RIIC3SCL */
+                        <RZA1_PINMUX(1, 7, 1)>;        /* RIIC3SDA */
+       };
 
        /* Serial Console */
        scif2_pins: serial2 {
index d530f451467e2df864a836b7b8a492b32b38a2b2..f70f4a3e5c438e0a3b5272e8646baae1c3651f6e 100644 (file)
@@ -19,7 +19,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel root=/dev/nfs ip=dhcp rw";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
                stdout-path = "serial0:115200n8";
        };
 
 };
 
 &bsc {
+       flash@0 {
+               compatible = "cfi-flash", "mtd-rom";
+               reg = <0x0 0x08000000>;
+               bank-width = <2>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "uboot";
+                               reg = <0x00000000 0x00040000>;
+                               read-only;
+                       };
+                       partition@40000 {
+                               label = "uboot-env";
+                               reg = <0x00040000 0x00040000>;
+                               read-only;
+                       };
+                       partition@80000 {
+                               label = "flash";
+                               reg = <0x00080000 0x07f80000>;
+                       };
+               };
+       };
+
        ethernet@8000000 {
                compatible = "smsc,lan9220", "smsc,lan9115";
                reg = <0x08000000 0x1000>;
index 77d18242ef59ecbec8c00f8c066fdc07be789fb4..2840eb0d6fd42d37787e70c74152f3c831f4098e 100644 (file)
                stdout-path = "serial1:115200n8";
        };
 
+       hdmi-out {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_con: endpoint {
+                               remote-endpoint = <&bridge_out>;
+                       };
+               };
+       };
+
        memory@40000000 {
                device_type = "memory";
                reg = <0 0x40000000 0 0x20000000>;
        status = "okay";
 };
 
+&du {
+       pinctrl-0 = <&du0_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+
+       ports {
+               port@0 {
+                       endpoint {
+                               remote-endpoint = <&bridge_in>;
+                       };
+               };
+       };
+};
+
+&ehci1 {
+       status = "okay";
+};
+
 &extal_clk {
        clock-frequency = <20000000>;
 };
 
+&gpio2 {
+       interrupt-fixup {
+               gpio-hog;
+               gpios = <29 GPIO_ACTIVE_HIGH>;
+               line-name = "hdmi-hpd-int";
+               input;
+       };
+};
+
+&hsusb0 {
+       status = "okay";
+};
+
 &i2c3 {
        pinctrl-0 = <&i2c3_pins>;
        pinctrl-names = "default";
        };
 };
 
+&i2c4 {
+       pinctrl-0 = <&i2c4_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+       clock-frequency = <100000>;
+
+       hdmi@39 {
+               compatible = "sil,sii9022";
+               reg = <0x39>;
+               interrupt-parent = <&gpio2>;
+               interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               bridge_in: endpoint {
+                                       remote-endpoint = <&du_out_rgb0>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+                               bridge_out: endpoint {
+                                       remote-endpoint = <&hdmi_con>;
+                               };
+                       };
+               };
+       };
+};
+
+&ohci1 {
+       status = "okay";
+};
+
 &pfc {
        avb_pins: avb {
                groups = "avb_mdio", "avb_gmii_tx_rx";
                function = "avb";
        };
 
+       du0_pins: du0 {
+               groups = "du0_rgb888", "du0_sync", "du0_disp", "du0_clk0_out";
+               function = "du0";
+       };
+
+       i2c4_pins: i2c4 {
+               groups = "i2c4_e";
+               function = "i2c4";
+       };
+
        i2c3_pins: i2c3 {
                groups = "i2c3_c";
                function = "i2c3";
                function = "sdhi2";
                power-source = <1800>;
        };
+
+       usb0_pins: usb0 {
+               groups = "usb0";
+               function = "usb0";
+       };
+
+       usb1_pins: usb1 {
+               groups = "usb1";
+               function = "usb1";
+       };
 };
 
 &qspi0 {
        sd-uhs-sdr50;
        status = "okay";
 };
+
+&usb2_phy0 {
+       status = "okay";
+};
+
+&usb2_phy1 {
+       status = "okay";
+};
+
+&usbphy0 {
+       pinctrl-0 = <&usb0_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+};
+
+&usbphy1 {
+       pinctrl-0 = <&usb1_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+};
index f4e232bf9d03c3b0ef1f0c98be5af6a57f535998..56cb10b42ed940dd42b9413cb58dc2c493e4941e 100644 (file)
                        status = "disabled";
                };
 
+               hsusb0: hsusb@e6590000 {
+                       compatible = "renesas,usbhs-r8a77470",
+                                    "renesas,rcar-gen2-usbhs";
+                       reg = <0 0xe6590000 0 0x100>;
+                       interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 704>;
+                       dmas = <&usb_dmac00 0>, <&usb_dmac00 1>,
+                              <&usb_dmac10 0>, <&usb_dmac10 1>;
+                       dma-names = "ch0", "ch1", "ch2", "ch3";
+                       renesas,buswait = <4>;
+                       phys = <&usb0 1>;
+                       phy-names = "usb";
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 704>;
+                       status = "disabled";
+               };
+
+               usbphy0: usb-phy@e6590100 {
+                       compatible = "renesas,usb-phy-r8a77470",
+                                    "renesas,rcar-gen2-usb-phy";
+                       reg = <0 0xe6590100 0 0x100>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       clocks = <&cpg CPG_MOD 704>;
+                       clock-names = "usbhs";
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 704>;
+                       status = "disabled";
+
+                       usb0: usb-channel@0 {
+                               reg = <0>;
+                               #phy-cells = <1>;
+                       };
+               };
+
+               hsusb1: hsusb@e6598000 {
+                       compatible = "renesas,usbhs-r8a77470",
+                                    "renesas,rcar-gen2-usbhs";
+                       reg = <0 0xe6598000 0 0x100>;
+                       interrupts = <GIC_SPI 291 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 706>;
+                       dmas = <&usb_dmac01 0>, <&usb_dmac01 1>,
+                              <&usb_dmac11 0>, <&usb_dmac11 1>;
+                       dma-names = "ch0", "ch1", "ch2", "ch3";
+                       renesas,buswait = <4>;
+                       /* We need to turn on usbphy0 to make usbphy1 to work */
+                       phys = <&usb1 1>;
+                       phy-names = "usb";
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 706>;
+                       status = "disabled";
+               };
+
+               usbphy1: usb-phy@e6598100 {
+                       compatible = "renesas,usb-phy-r8a77470",
+                                    "renesas,rcar-gen2-usb-phy";
+                       reg = <0 0xe6598100 0 0x100>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       clocks = <&cpg CPG_MOD 706>;
+                       clock-names = "usbhs";
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 706>;
+                       status = "disabled";
+
+                       usb1: usb-channel@0 {
+                               reg = <0>;
+                               #phy-cells = <1>;
+                       };
+               };
+
                usb_dmac00: dma-controller@e65a0000 {
                        compatible = "renesas,r8a77470-usb-dmac",
                                     "renesas,usb-dmac";
                        status = "disabled";
                };
 
+               hscif0: serial@e62c0000 {
+                       compatible = "renesas,hscif-r8a77470",
+                                    "renesas,rcar-gen2-hscif", "renesas,hscif";
+                       reg = <0 0xe62c0000 0 0x60>;
+                       interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 717>,
+                                <&cpg CPG_CORE R8A77470_CLK_ZS>, <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x39>, <&dmac0 0x3a>,
+                              <&dmac1 0x39>, <&dmac1 0x3a>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 717>;
+                       status = "disabled";
+               };
+
+               hscif1: serial@e62c8000 {
+                       compatible = "renesas,hscif-r8a77470",
+                                    "renesas,rcar-gen2-hscif", "renesas,hscif";
+                       reg = <0 0xe62c8000 0 0x60>;
+                       interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 716>,
+                                <&cpg CPG_CORE R8A77470_CLK_ZS>, <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x4d>, <&dmac0 0x4e>,
+                              <&dmac1 0x4d>, <&dmac1 0x4e>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 716>;
+                       status = "disabled";
+               };
+
+               hscif2: serial@e62d0000 {
+                       compatible = "renesas,hscif-r8a77470",
+                                    "renesas,rcar-gen2-hscif", "renesas,hscif";
+                       reg = <0 0xe62d0000 0 0x60>;
+                       interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 713>,
+                                <&cpg CPG_CORE R8A77470_CLK_ZS>, <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x3b>, <&dmac0 0x3c>,
+                              <&dmac1 0x3b>, <&dmac1 0x3c>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 713>;
+                       status = "disabled";
+               };
+
+               pwm0: pwm@e6e30000 {
+                       compatible = "renesas,pwm-r8a77470", "renesas,pwm-rcar";
+                       reg = <0 0xe6e30000 0 0x8>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 523>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               pwm1: pwm@e6e31000 {
+                       compatible = "renesas,pwm-r8a77470", "renesas,pwm-rcar";
+                       reg = <0 0xe6e31000 0 0x8>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 523>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               pwm2: pwm@e6e32000 {
+                       compatible = "renesas,pwm-r8a77470", "renesas,pwm-rcar";
+                       reg = <0 0xe6e32000 0 0x8>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 523>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               pwm3: pwm@e6e33000 {
+                       compatible = "renesas,pwm-r8a77470", "renesas,pwm-rcar";
+                       reg = <0 0xe6e33000 0 0x8>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 523>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               pwm4: pwm@e6e34000 {
+                       compatible = "renesas,pwm-r8a77470", "renesas,pwm-rcar";
+                       reg = <0 0xe6e34000 0 0x8>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 523>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               pwm5: pwm@e6e35000 {
+                       compatible = "renesas,pwm-r8a77470", "renesas,pwm-rcar";
+                       reg = <0 0xe6e35000 0 0x8>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 523>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               pwm6: pwm@e6e36000 {
+                       compatible = "renesas,pwm-r8a77470", "renesas,pwm-rcar";
+                       reg = <0 0xe6e36000 0 0x8>;
+                       clocks = <&cpg CPG_MOD 523>;
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 523>;
+                       #pwm-cells = <2>;
+                       status = "disabled";
+               };
+
+               vin0: video@e6ef0000 {
+                       compatible = "renesas,vin-r8a77470",
+                                    "renesas,rcar-gen2-vin";
+                       reg = <0 0xe6ef0000 0 0x1000>;
+                       interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 811>;
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 811>;
+                       status = "disabled";
+               };
+
+               vin1: video@e6ef1000 {
+                       compatible = "renesas,vin-r8a77470",
+                                    "renesas,rcar-gen2-vin";
+                       reg = <0 0xe6ef1000 0 0x1000>;
+                       interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 810>;
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 810>;
+                       status = "disabled";
+               };
+
+               ohci0: usb@ee080000 {
+                       compatible = "generic-ohci";
+                       reg = <0 0xee080000 0 0x100>;
+                       interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 703>;
+                       phys = <&usb0 0>, <&usb2_phy0>;
+                       phy-names = "usb";
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 703>;
+                       status = "disabled";
+               };
+
+               ehci0: usb@ee080100 {
+                       compatible = "generic-ehci";
+                       reg = <0 0xee080100 0 0x100>;
+                       interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 703>;
+                       phys = <&usb0 0>, <&usb2_phy0>;
+                       phy-names = "usb";
+                       companion = <&ohci0>;
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 703>;
+                       status = "disabled";
+               };
+
+               usb2_phy0: usb-phy@ee080200 {
+                       compatible = "renesas,usb2-phy-r8a77470";
+                       reg = <0 0xee080200 0 0x700>;
+                       clocks = <&cpg CPG_MOD 703>;
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 703>;
+                       #phy-cells = <0>;
+                       status = "disabled";
+               };
+
+               ohci1: usb@ee0c0000 {
+                       compatible = "generic-ohci";
+                       reg = <0 0xee0c0000 0 0x100>;
+                       interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 705>;
+                       phys = <&usb0 1>, <&usb2_phy1>, <&usb1 0>;
+                       phy-names = "usb";
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 705>;
+                       status = "disabled";
+               };
+
+               ehci1: usb@ee0c0100 {
+                       compatible = "generic-ehci";
+                       reg = <0 0xee0c0100 0 0x100>;
+                       interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 705>;
+                       phys = <&usb0 1>, <&usb2_phy1>, <&usb1 0>;
+                       phy-names = "usb";
+                       companion = <&ohci1>;
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 705>;
+                       status = "disabled";
+               };
+
+               usb2_phy1: usb-phy@ee0c0200 {
+                       compatible = "renesas,usb2-phy-r8a77470";
+                       reg = <0 0xee0c0200 0 0x700>;
+                       clocks = <&cpg CPG_MOD 705>;
+                       power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                       resets = <&cpg 705>;
+                       #phy-cells = <0>;
+                       status = "disabled";
+               };
+
                sdhi0: sd@ee100000 {
                        compatible = "renesas,sdhi-r8a77470",
                                     "renesas,rcar-gen2-sdhi";
                        resets = <&cpg 408>;
                };
 
+               du: display@feb00000 {
+                       compatible = "renesas,du-r8a77470";
+                       reg = <0 0xfeb00000 0 0x40000>;
+                       interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 724>,
+                                <&cpg CPG_MOD 723>;
+                       clock-names = "du.0", "du.1";
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       du_out_rgb0: endpoint {
+                                       };
+                               };
+                               port@1 {
+                                       reg = <1>;
+                                       du_out_rgb1: endpoint {
+                                       };
+                               };
+                               port@2 {
+                                       reg = <2>;
+                                       du_out_lvds0: endpoint {
+                                       };
+                               };
+                       };
+               };
+
                prr: chipid@ff000044 {
                        compatible = "renesas,prr";
                        reg = <0 0xff000044 0 4>;
index cecb22924ec45c0ebd7357988c8afc63ecf83c1c..0b49956069fcd522281c170d43fee361f0d1ae84 100644 (file)
@@ -25,7 +25,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel ip=dhcp root=/dev/nfs rw";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
                stdout-path = "serial0:115200n8";
        };
 
index abc14e7a4c93ee5e61af3613430c799c1f7d5c98..d4bee1ec904459e0d196870289a617b59ae9bd43 100644 (file)
@@ -21,7 +21,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel root=/dev/nfs ip=on";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
                stdout-path = "serial0:115200n8";
        };
 
index f92301290b026fdbb9d223b9da6907c7b06b6bd9..b6fa80c3b07e2df90304c636b0af38fae9d79c4d 100644 (file)
        };
 };
 
+&iic3 {
+       status = "okay";
+
+       pmic@58 {
+               compatible = "dlg,da9063";
+               reg = <0x58>;
+               interrupt-parent = <&irqc>;
+               interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-controller;
+
+               rtc {
+                       compatible = "dlg,da9063-rtc";
+               };
+
+               wdt {
+                       compatible = "dlg,da9063-watchdog";
+               };
+       };
+};
+
 &du {
        pinctrl-0 = <&du0_pins &du1_pins>;
        pinctrl-names = "default";
index 8e9eb4b704d32f2a23179435f158030772ca2365..38fb43d11b271d5e5f91ef6a246dffdbdd95e52a 100644 (file)
@@ -22,6 +22,7 @@
                i2c3 = &i2c3;
                i2c4 = &i2c4;
                i2c5 = &i2c5;
+               i2c6 = &iic3;
                spi0 = &qspi;
                spi1 = &msiof0;
                spi2 = &msiof1;
                        status = "disabled";
                };
 
+               iic3: i2c@e60b0000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "renesas,iic-r8a7792",
+                                    "renesas,rcar-gen2-iic",
+                                    "renesas,rmobile-iic";
+                       reg = <0 0xe60b0000 0 0x425>;
+                       interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 926>;
+                       dmas = <&dmac0 0x77>, <&dmac0 0x78>,
+                              <&dmac1 0x77>, <&dmac1 0x78>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+                       resets = <&cpg 926>;
+                       status = "disabled";
+               };
+
                dmac0: dma-controller@e6700000 {
                        compatible = "renesas,dmac-r8a7792",
                                     "renesas,rcar-dmac";
index ef7e2a837df6da79596339e15bd0db2000fd27c5..0ab3d8d57f6ddc5672d94ad601a4ab9e603bbea1 100644 (file)
        };
 };
 
+&pci0 {
+       status = "okay";
+       pinctrl-0 = <&usb0_pins>;
+       pinctrl-names = "default";
+};
+
+&pci1 {
+       status = "okay";
+       pinctrl-0 = <&usb1_pins>;
+       pinctrl-names = "default";
+};
+
+&usbphy {
+       status = "okay";
+};
+
 &du {
        pinctrl-0 = <&du_pins>;
        pinctrl-names = "default";
                function = "sdhi1";
                power-source = <1800>;
        };
+
+       usb0_pins: usb0 {
+               groups = "usb0";
+               function = "usb0";
+       };
+
+       usb1_pins: usb1 {
+               groups = "usb1";
+               function = "usb1";
+       };
 };
 
 &cmt0 {
        pinctrl-names = "i2c-exio4";
 };
 
+&i2c7 {
+       status = "okay";
+       clock-frequency = <100000>;
+
+       pmic@58 {
+               compatible = "dlg,da9063";
+               reg = <0x58>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <31 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-controller;
+
+               rtc {
+                       compatible = "dlg,da9063-rtc";
+               };
+
+               wdt {
+                       compatible = "dlg,da9063-watchdog";
+               };
+       };
+};
+
 &vin0 {
        status = "okay";
        pinctrl-0 = <&vin0_pins>;
index 0173eb11ec28828b5abe2625f47d280d220d2b70..fb3cf005cc90275eaf7846e0a830ee9ba697a7b1 100644 (file)
 &pinctrl {
        leds {
                led_ctl: led-ctl {
-                       rockchip,pins = <2 30 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PD6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        pmic {
                pmic_int: pmic-int {
-                       rockchip,pins = <2 2 RK_FUNC_GPIO &pcfg_pull_default>;
+                       rockchip,pins = <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_default>;
                };
        };
 
        sdio {
                bt_wake_h: bt-wake-h {
-                       rockchip,pins = <2 8 RK_FUNC_GPIO &pcfg_pull_default>;
+                       rockchip,pins = <2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_default>;
                };
        };
 
        sdmmc {
                sdmmc_pwr: sdmmc-pwr {
-                       rockchip,pins = <2 28 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        sleep {
                global_pwroff: global-pwroff {
-                       rockchip,pins = <2 7 RK_FUNC_1 &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PA7 1 &pcfg_pull_none>;
                };
        };
 };
index 59c90863b0e7a7a544889d27c896e6e4aee88f8b..0290ea4edd321a642fa152b7af6cf7209f913e9b 100644 (file)
 
                pwm0 {
                        pwm0_pin: pwm0-pin {
-                               rockchip,pins = <0 0 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA0 2 &pcfg_pull_none>;
                        };
                };
 
                pwm1 {
                        pwm1_pin: pwm1-pin {
-                               rockchip,pins = <0 1 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA1 2 &pcfg_pull_none>;
                        };
                };
 
                pwm2 {
                        pwm2_pin: pwm2-pin {
-                               rockchip,pins = <0 1 2 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA1 2 &pcfg_pull_none>;
                        };
                };
 
                pwm3 {
                        pwm3_pin: pwm3-pin {
-                               rockchip,pins = <0 27 1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PD3 1 &pcfg_pull_none>;
                        };
                };
 
                sdmmc {
                        sdmmc_clk: sdmmc-clk {
-                               rockchip,pins = <1 16 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PC0 1 &pcfg_pull_none>;
                        };
 
                        sdmmc_cmd: sdmmc-cmd {
-                               rockchip,pins = <1 15 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PB7 1 &pcfg_pull_default>;
                        };
 
                        sdmmc_cd: sdmmc-cd {
-                               rockchip,pins = <1 17 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PC1 1 &pcfg_pull_default>;
                        };
 
                        sdmmc_bus1: sdmmc-bus1 {
-                               rockchip,pins = <1 18 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PC2 1 &pcfg_pull_default>;
                        };
 
                        sdmmc_bus4: sdmmc-bus4 {
-                               rockchip,pins = <1 18 RK_FUNC_1 &pcfg_pull_default>,
-                                               <1 19 RK_FUNC_1 &pcfg_pull_default>,
-                                               <1 20 RK_FUNC_1 &pcfg_pull_default>,
-                                               <1 21 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PC2 1 &pcfg_pull_default>,
+                                               <1 RK_PC3 1 &pcfg_pull_default>,
+                                               <1 RK_PC4 1 &pcfg_pull_default>,
+                                               <1 RK_PC5 1 &pcfg_pull_default>;
                        };
                };
 
                sdio {
                        sdio_bus1: sdio-bus1 {
-                               rockchip,pins = <0 11 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <0 RK_PB3 1 &pcfg_pull_default>;
                        };
 
                        sdio_bus4: sdio-bus4 {
-                               rockchip,pins = <0 11 RK_FUNC_1 &pcfg_pull_default>,
-                                               <0 12 RK_FUNC_1 &pcfg_pull_default>,
-                                               <0 13 RK_FUNC_1 &pcfg_pull_default>,
-                                               <0 14 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <0 RK_PB3 1 &pcfg_pull_default>,
+                                               <0 RK_PB4 1 &pcfg_pull_default>,
+                                               <0 RK_PB5 1 &pcfg_pull_default>,
+                                               <0 RK_PB6 1 &pcfg_pull_default>;
                        };
 
                        sdio_cmd: sdio-cmd {
-                               rockchip,pins = <0 8 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <0 RK_PB0 1 &pcfg_pull_default>;
                        };
 
                        sdio_clk: sdio-clk {
-                               rockchip,pins = <0 9 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PB1 1 &pcfg_pull_none>;
                        };
                };
 
                         * We also have external pulls, so disable the internal ones.
                         */
                        emmc_clk: emmc-clk {
-                               rockchip,pins = <2 4 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PA4 2 &pcfg_pull_none>;
                        };
 
                        emmc_cmd: emmc-cmd {
-                               rockchip,pins = <2 1 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <2 RK_PA1 2 &pcfg_pull_default>;
                        };
 
                        emmc_bus8: emmc-bus8 {
-                               rockchip,pins = <1 24 RK_FUNC_2 &pcfg_pull_default>,
-                                               <1 25 RK_FUNC_2 &pcfg_pull_default>,
-                                               <1 26 RK_FUNC_2 &pcfg_pull_default>,
-                                               <1 27 RK_FUNC_2 &pcfg_pull_default>,
-                                               <1 28 RK_FUNC_2 &pcfg_pull_default>,
-                                               <1 29 RK_FUNC_2 &pcfg_pull_default>,
-                                               <1 30 RK_FUNC_2 &pcfg_pull_default>,
-                                               <1 31 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PD0 2 &pcfg_pull_default>,
+                                               <1 RK_PD1 2 &pcfg_pull_default>,
+                                               <1 RK_PD2 2 &pcfg_pull_default>,
+                                               <1 RK_PD3 2 &pcfg_pull_default>,
+                                               <1 RK_PD4 2 &pcfg_pull_default>,
+                                               <1 RK_PD5 2 &pcfg_pull_default>,
+                                               <1 RK_PD6 2 &pcfg_pull_default>,
+                                               <1 RK_PD7 2 &pcfg_pull_default>;
                        };
                };
 
                emac {
                        emac_xfer: emac-xfer {
-                               rockchip,pins = <2 10 RK_FUNC_1 &pcfg_pull_default>, /* crs_dvalid */
-                                               <2 13 RK_FUNC_1 &pcfg_pull_default>, /* tx_en */
-                                               <2 14 RK_FUNC_1 &pcfg_pull_default>, /* mac_clk */
-                                               <2 15 RK_FUNC_1 &pcfg_pull_default>, /* rx_err */
-                                               <2 16 RK_FUNC_1 &pcfg_pull_default>, /* rxd1 */
-                                               <2 17 RK_FUNC_1 &pcfg_pull_default>, /* rxd0 */
-                                               <2 18 RK_FUNC_1 &pcfg_pull_default>, /* txd1 */
-                                               <2 19 RK_FUNC_1 &pcfg_pull_default>; /* txd0 */
+                               rockchip,pins = <2 RK_PB2 1 &pcfg_pull_default>, /* crs_dvalid */
+                                               <2 RK_PB5 1 &pcfg_pull_default>, /* tx_en */
+                                               <2 RK_PB6 1 &pcfg_pull_default>, /* mac_clk */
+                                               <2 RK_PB7 1 &pcfg_pull_default>, /* rx_err */
+                                               <2 RK_PC0 1 &pcfg_pull_default>, /* rxd1 */
+                                               <2 RK_PC1 1 &pcfg_pull_default>, /* rxd0 */
+                                               <2 RK_PC2 1 &pcfg_pull_default>, /* txd1 */
+                                               <2 RK_PC3 1 &pcfg_pull_default>; /* txd0 */
                        };
 
                        emac_mdio: emac-mdio {
-                               rockchip,pins = <2 12 RK_FUNC_1 &pcfg_pull_default>, /* mac_md */
-                                               <2 25 RK_FUNC_1 &pcfg_pull_default>; /* mac_mdclk */
+                               rockchip,pins = <2 RK_PB4 1 &pcfg_pull_default>, /* mac_md */
+                                               <2 RK_PD1 1 &pcfg_pull_default>; /* mac_mdclk */
                        };
                };
 
                i2c0 {
                        i2c0_xfer: i2c0-xfer {
-                               rockchip,pins = <0 0 RK_FUNC_1 &pcfg_pull_none>,
-                                               <0 1 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA0 1 &pcfg_pull_none>,
+                                               <0 RK_PA1 1 &pcfg_pull_none>;
                        };
                };
 
                i2c1 {
                        i2c1_xfer: i2c1-xfer {
-                               rockchip,pins = <0 2 RK_FUNC_1 &pcfg_pull_none>,
-                                               <0 3 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA2 1 &pcfg_pull_none>,
+                                               <0 RK_PA3 1 &pcfg_pull_none>;
                        };
                };
 
                i2c2 {
                        i2c2_xfer: i2c2-xfer {
-                               rockchip,pins = <2 20 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 21 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PC4 1 &pcfg_pull_none>,
+                                               <2 RK_PC5 1 &pcfg_pull_none>;
                        };
                };
 
                i2s {
                        i2s_bus: i2s-bus {
-                               rockchip,pins = <1 0 RK_FUNC_1 &pcfg_pull_default>,
-                                               <1 1 RK_FUNC_1 &pcfg_pull_default>,
-                                               <1 2 RK_FUNC_1 &pcfg_pull_default>,
-                                               <1 3 RK_FUNC_1 &pcfg_pull_default>,
-                                               <1 4 RK_FUNC_1 &pcfg_pull_default>,
-                                               <1 5 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PA0 1 &pcfg_pull_default>,
+                                               <1 RK_PA1 1 &pcfg_pull_default>,
+                                               <1 RK_PA2 1 &pcfg_pull_default>,
+                                               <1 RK_PA3 1 &pcfg_pull_default>,
+                                               <1 RK_PA4 1 &pcfg_pull_default>,
+                                               <1 RK_PA5 1 &pcfg_pull_default>;
                        };
                };
 
                hdmi {
                        hdmi_ctl: hdmi-ctl {
-                               rockchip,pins = <1 8  RK_FUNC_1 &pcfg_pull_none>,
-                                               <1 9  RK_FUNC_1 &pcfg_pull_none>,
-                                               <1 10 RK_FUNC_1 &pcfg_pull_none>,
-                                               <1 11 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PB0  1 &pcfg_pull_none>,
+                                               <1 RK_PB1  1 &pcfg_pull_none>,
+                                               <1 RK_PB2 1 &pcfg_pull_none>,
+                                               <1 RK_PB3 1 &pcfg_pull_none>;
                        };
                };
 
                uart0 {
                        uart0_xfer: uart0-xfer {
-                               rockchip,pins = <0 16 RK_FUNC_1 &pcfg_pull_default>,
-                                               <0 17 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PC0 1 &pcfg_pull_default>,
+                                               <0 RK_PC1 1 &pcfg_pull_none>;
                        };
 
                        uart0_cts: uart0-cts {
-                               rockchip,pins = <0 18 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <0 RK_PC2 1 &pcfg_pull_default>;
                        };
 
                        uart0_rts: uart0-rts {
-                               rockchip,pins = <0 19 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PC3 1 &pcfg_pull_none>;
                        };
                };
 
                uart1 {
                        uart1_xfer: uart1-xfer {
-                               rockchip,pins = <2 22 RK_FUNC_1 &pcfg_pull_default>,
-                                               <2 23 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PC6 1 &pcfg_pull_default>,
+                                               <2 RK_PC7 1 &pcfg_pull_none>;
                        };
                        /* no rts / cts for uart1 */
                };
 
                uart2 {
                        uart2_xfer: uart2-xfer {
-                               rockchip,pins = <1 18 RK_FUNC_2 &pcfg_pull_default>,
-                                               <1 19 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PC2 2 &pcfg_pull_default>,
+                                               <1 RK_PC3 2 &pcfg_pull_none>;
                        };
                        /* no rts / cts for uart2 */
                };
 
                spi-pins {
                        spi_txd:spi-txd {
-                               rockchip,pins = <1 29 RK_FUNC_3 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PD5 3 &pcfg_pull_default>;
                        };
 
                        spi_rxd:spi-rxd {
-                               rockchip,pins = <1 28 RK_FUNC_3 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PD4 3 &pcfg_pull_default>;
                        };
 
                        spi_clk:spi-clk {
-                               rockchip,pins = <2 0 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <2 RK_PA0 2 &pcfg_pull_default>;
                        };
 
                        spi_cs0:spi-cs0 {
-                               rockchip,pins = <1 30 RK_FUNC_3 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PD6 3 &pcfg_pull_default>;
 
                        };
 
                        spi_cs1:spi-cs1 {
-                               rockchip,pins = <1 31 RK_FUNC_3 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PD7 3 &pcfg_pull_default>;
 
                        };
                };
index ce525b956ae5ce9d640642452b1bb3edf0da005a..7e01f6406a86e1cefaee74efb8828feb9ace2bd2 100644 (file)
 &pinctrl {
        lan8720a {
                phy_int: phy-int {
-                       rockchip,pins = <RK_GPIO1 26 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 9d2216d71f707262611eedb934e49942a309efef..365eff621113f20e9fe2f3610913b022ace06f61 100644 (file)
                };
        };
 
+       hdmi_con {
+               compatible = "hdmi-connector";
+               type = "c";
+
+               port {
+                       hdmi_con_in: endpoint {
+                               remote-endpoint = <&hdmi_out_con>;
+                       };
+               };
+       };
+
        vcc_io: vcc-io {
                compatible = "regulator-fixed";
                regulator-name = "vcc_io";
        };
 };
 
+&hdmi {
+       status = "okay";
+};
+
+&hdmi_in_vop1 {
+       status = "disabled";
+};
+
+&hdmi_out {
+       hdmi_out_con: endpoint {
+               remote-endpoint = <&hdmi_con_in>;
+       };
+};
+
 &mmc0 {
        bus-width = <4>;
        cap-mmc-highspeed;
 &pinctrl {
        usb-host {
                host_drv: host-drv {
-                       rockchip,pins = <RK_GPIO0 6 RK_FUNC_GPIO &pcfg_pull_default>;
+                       rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_default>;
                };
        };
 
        usb-otg {
                otg_drv: otg-drv {
-                       rockchip,pins = <RK_GPIO0 5 RK_FUNC_GPIO &pcfg_pull_default>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_default>;
                };
        };
 
        sdmmc {
                sdmmc_pwr: sdmmc-pwr {
-                       rockchip,pins = <RK_GPIO3 7 RK_FUNC_GPIO &pcfg_pull_default>;
+                       rockchip,pins = <3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_default>;
                };
        };
 
        sdio {
                wifi_pwr: wifi-pwr {
-                       rockchip,pins = <RK_GPIO3 24 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <3 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
        status = "okay";
 };
 
+&vop0 {
+       status = "okay";
+};
+
 &wdt {
        status = "okay";
 };
index 949fa800582d81ed4eadb1164ea9cc39a66e1611..f9db6bb9fa11f19b99f22f2a459c821877d131d7 100644 (file)
 
        ak8963 {
                comp_int: comp-int {
-                       rockchip,pins = <4 17 RK_FUNC_GPIO &pcfg_pull_default>;
+                       rockchip,pins = <4 RK_PC1 RK_FUNC_GPIO &pcfg_pull_default>;
                };
        };
 
        emac {
                rmii_rst: rmii-rst {
-                       rockchip,pins = <1 30 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <1 RK_PD6 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 
        ir {
                ir_int: ir-int {
-                       rockchip,pins = <6 1 RK_FUNC_GPIO &pcfg_pull_default>;
+                       rockchip,pins = <6 RK_PA1 RK_FUNC_GPIO &pcfg_pull_default>;
                };
        };
 
        keys {
                pwr_key: pwr-key {
-                       rockchip,pins = <6 2 RK_FUNC_GPIO &pcfg_pull_default>;
+                       rockchip,pins = <6 RK_PA2 RK_FUNC_GPIO &pcfg_pull_default>;
                };
        };
 
        mma8452 {
                gsensor_int: gsensor-int {
-                       rockchip,pins = <4 16 RK_FUNC_GPIO &pcfg_pull_default>;
+                       rockchip,pins = <4 RK_PC0 RK_FUNC_GPIO &pcfg_pull_default>;
                };
        };
 
        mmc {
                sdmmc_pwr: sdmmc-pwr {
-                       rockchip,pins = <3 7 RK_FUNC_GPIO &pcfg_pull_default>;
+                       rockchip,pins = <3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_default>;
                };
        };
 
        usb_host {
                host_drv: host-drv {
-                       rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_default>;
+                       rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_default>;
                };
 
                hub_rst: hub-rst {
-                       rockchip,pins = <1 31 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <1 RK_PD7 RK_FUNC_GPIO &pcfg_output_high>;
                };
 
                sata_pwr: sata-pwr {
-                       rockchip,pins = <4 22 RK_FUNC_GPIO &pcfg_pull_default>;
+                       rockchip,pins = <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_default>;
                };
 
                sata_reset: sata-reset {
-                       rockchip,pins = <0 13 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 
        usb_otg {
                otg_drv: otg-drv {
-                       rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_default>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_default>;
                };
        };
 
        tps {
                pmic_int: pmic-int {
-                       rockchip,pins = <6 4 RK_FUNC_GPIO &pcfg_pull_default>;
+                       rockchip,pins = <6 RK_PA4 RK_FUNC_GPIO &pcfg_pull_default>;
                };
 
                pwr_hold: pwr-hold {
-                       rockchip,pins = <6 8 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <6 RK_PB0 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 };
index 653127a377faa5388f64e003e7b09c73d72286bc..3d1b02f45ffd6b9794c54c39f22fa1ec094a7baf 100644 (file)
                vop0_out: port {
                        #address-cells = <1>;
                        #size-cells = <0>;
+
+                       vop0_out_hdmi: endpoint@0 {
+                               reg = <0>;
+                               remote-endpoint = <&hdmi_in_vop0>;
+                       };
                };
        };
 
                vop1_out: port {
                        #address-cells = <1>;
                        #size-cells = <0>;
+
+                       vop1_out_hdmi: endpoint@0 {
+                               reg = <0>;
+                               remote-endpoint = <&hdmi_in_vop1>;
+                       };
+               };
+       };
+
+       hdmi: hdmi@10116000 {
+               compatible = "rockchip,rk3066-hdmi";
+               reg = <0x10116000 0x2000>;
+               interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru HCLK_HDMI>;
+               clock-names = "hclk";
+               pinctrl-names = "default";
+               pinctrl-0 = <&hdmii2c_xfer>, <&hdmi_hpd>;
+               power-domains = <&power RK3066_PD_VIO>;
+               rockchip,grf = <&grf>;
+               status = "disabled";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       hdmi_in: port@0 {
+                               reg = <0>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               hdmi_in_vop0: endpoint@0 {
+                                       reg = <0>;
+                                       remote-endpoint = <&vop0_out_hdmi>;
+                               };
+
+                               hdmi_in_vop1: endpoint@1 {
+                                       reg = <1>;
+                                       remote-endpoint = <&vop1_out_hdmi>;
+                               };
+                       };
+
+                       hdmi_out: port@1 {
+                               reg = <1>;
+                       };
                };
        };
 
 
                emac {
                        emac_xfer: emac-xfer {
-                               rockchip,pins = <RK_GPIO1 16 RK_FUNC_2 &pcfg_pull_none>, /* mac_clk */
-                                               <RK_GPIO1 17 RK_FUNC_2 &pcfg_pull_none>, /* tx_en */
-                                               <RK_GPIO1 18 RK_FUNC_2 &pcfg_pull_none>, /* txd1 */
-                                               <RK_GPIO1 19 RK_FUNC_2 &pcfg_pull_none>, /* txd0 */
-                                               <RK_GPIO1 20 RK_FUNC_2 &pcfg_pull_none>, /* rx_err */
-                                               <RK_GPIO1 21 RK_FUNC_2 &pcfg_pull_none>, /* crs_dvalid */
-                                               <RK_GPIO1 22 RK_FUNC_2 &pcfg_pull_none>, /* rxd1 */
-                                               <RK_GPIO1 23 RK_FUNC_2 &pcfg_pull_none>; /* rxd0 */
+                               rockchip,pins = <1 RK_PC0 2 &pcfg_pull_none>, /* mac_clk */
+                                               <1 RK_PC1 2 &pcfg_pull_none>, /* tx_en */
+                                               <1 RK_PC2 2 &pcfg_pull_none>, /* txd1 */
+                                               <1 RK_PC3 2 &pcfg_pull_none>, /* txd0 */
+                                               <1 RK_PC4 2 &pcfg_pull_none>, /* rx_err */
+                                               <1 RK_PC5 2 &pcfg_pull_none>, /* crs_dvalid */
+                                               <1 RK_PC6 2 &pcfg_pull_none>, /* rxd1 */
+                                               <1 RK_PC7 2 &pcfg_pull_none>; /* rxd0 */
                        };
 
                        emac_mdio: emac-mdio {
-                               rockchip,pins = <RK_GPIO1 24 RK_FUNC_2 &pcfg_pull_none>, /* mac_md */
-                                               <RK_GPIO1 25 RK_FUNC_2 &pcfg_pull_none>; /* mac_mdclk */
+                               rockchip,pins = <1 RK_PD0 2 &pcfg_pull_none>, /* mac_md */
+                                               <1 RK_PD1 2 &pcfg_pull_none>; /* mac_mdclk */
                        };
                };
 
                emmc {
                        emmc_clk: emmc-clk {
-                               rockchip,pins = <RK_GPIO3 31 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PD7 2 &pcfg_pull_default>;
                        };
 
                        emmc_cmd: emmc-cmd {
-                               rockchip,pins = <RK_GPIO4 9 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <4 RK_PB1 2 &pcfg_pull_default>;
                        };
 
                        emmc_rst: emmc-rst {
-                               rockchip,pins = <RK_GPIO4 10 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <4 RK_PB2 2 &pcfg_pull_default>;
                        };
 
                        /*
                         */
                };
 
+               hdmi {
+                       hdmi_hpd: hdmi-hpd {
+                               rockchip,pins = <0 RK_PA0 1 &pcfg_pull_default>;
+                       };
+
+                       hdmii2c_xfer: hdmii2c-xfer {
+                               rockchip,pins = <0 RK_PA1 1 &pcfg_pull_none>,
+                                               <0 RK_PA2 1 &pcfg_pull_none>;
+                       };
+               };
+
                i2c0 {
                        i2c0_xfer: i2c0-xfer {
-                               rockchip,pins = <RK_GPIO2 28 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO2 29 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PD4 1 &pcfg_pull_none>,
+                                               <2 RK_PD5 1 &pcfg_pull_none>;
                        };
                };
 
                i2c1 {
                        i2c1_xfer: i2c1-xfer {
-                               rockchip,pins = <RK_GPIO2 30 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO2 31 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PD6 1 &pcfg_pull_none>,
+                                               <2 RK_PD7 1 &pcfg_pull_none>;
                        };
                };
 
                i2c2 {
                        i2c2_xfer: i2c2-xfer {
-                               rockchip,pins = <RK_GPIO3 0 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO3 1 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PA0 1 &pcfg_pull_none>,
+                                               <3 RK_PA1 1 &pcfg_pull_none>;
                        };
                };
 
                i2c3 {
                        i2c3_xfer: i2c3-xfer {
-                               rockchip,pins = <RK_GPIO3 2 RK_FUNC_2 &pcfg_pull_none>,
-                                               <RK_GPIO3 3 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PA2 2 &pcfg_pull_none>,
+                                               <3 RK_PA3 2 &pcfg_pull_none>;
                        };
                };
 
                i2c4 {
                        i2c4_xfer: i2c4-xfer {
-                               rockchip,pins = <RK_GPIO3 4 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO3 5 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PA4 1 &pcfg_pull_none>,
+                                               <3 RK_PA5 1 &pcfg_pull_none>;
                        };
                };
 
                pwm0 {
                        pwm0_out: pwm0-out {
-                               rockchip,pins = <RK_GPIO0 3 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA3 1 &pcfg_pull_none>;
                        };
                };
 
                pwm1 {
                        pwm1_out: pwm1-out {
-                               rockchip,pins = <RK_GPIO0 4 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA4 1 &pcfg_pull_none>;
                        };
                };
 
                pwm2 {
                        pwm2_out: pwm2-out {
-                               rockchip,pins = <RK_GPIO0 30 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PD6 1 &pcfg_pull_none>;
                        };
                };
 
                pwm3 {
                        pwm3_out: pwm3-out {
-                               rockchip,pins = <RK_GPIO0 31 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PD7 1 &pcfg_pull_none>;
                        };
                };
 
                spi0 {
                        spi0_clk: spi0-clk {
-                               rockchip,pins = <RK_GPIO1 5 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PA5 2 &pcfg_pull_default>;
                        };
                        spi0_cs0: spi0-cs0 {
-                               rockchip,pins = <RK_GPIO1 4 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PA4 2 &pcfg_pull_default>;
                        };
                        spi0_tx: spi0-tx {
-                               rockchip,pins = <RK_GPIO1 7 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PA7 2 &pcfg_pull_default>;
                        };
                        spi0_rx: spi0-rx {
-                               rockchip,pins = <RK_GPIO1 6 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PA6 2 &pcfg_pull_default>;
                        };
                        spi0_cs1: spi0-cs1 {
-                               rockchip,pins = <RK_GPIO4 15 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <4 RK_PB7 1 &pcfg_pull_default>;
                        };
                };
 
                spi1 {
                        spi1_clk: spi1-clk {
-                               rockchip,pins = <RK_GPIO2 19 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <2 RK_PC3 2 &pcfg_pull_default>;
                        };
                        spi1_cs0: spi1-cs0 {
-                               rockchip,pins = <RK_GPIO2 20 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <2 RK_PC4 2 &pcfg_pull_default>;
                        };
                        spi1_rx: spi1-rx {
-                               rockchip,pins = <RK_GPIO2 22 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <2 RK_PC6 2 &pcfg_pull_default>;
                        };
                        spi1_tx: spi1-tx {
-                               rockchip,pins = <RK_GPIO2 21 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <2 RK_PC5 2 &pcfg_pull_default>;
                        };
                        spi1_cs1: spi1-cs1 {
-                               rockchip,pins = <RK_GPIO2 23 RK_FUNC_2 &pcfg_pull_default>;
+                               rockchip,pins = <2 RK_PC7 2 &pcfg_pull_default>;
                        };
                };
 
                uart0 {
                        uart0_xfer: uart0-xfer {
-                               rockchip,pins = <RK_GPIO1 0 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO1 1 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PA0 1 &pcfg_pull_default>,
+                                               <1 RK_PA1 1 &pcfg_pull_default>;
                        };
 
                        uart0_cts: uart0-cts {
-                               rockchip,pins = <RK_GPIO1 2 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PA2 1 &pcfg_pull_default>;
                        };
 
                        uart0_rts: uart0-rts {
-                               rockchip,pins = <RK_GPIO1 3 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PA3 1 &pcfg_pull_default>;
                        };
                };
 
                uart1 {
                        uart1_xfer: uart1-xfer {
-                               rockchip,pins = <RK_GPIO1 4 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO1 5 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PA4 1 &pcfg_pull_default>,
+                                               <1 RK_PA5 1 &pcfg_pull_default>;
                        };
 
                        uart1_cts: uart1-cts {
-                               rockchip,pins = <RK_GPIO1 6 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PA6 1 &pcfg_pull_default>;
                        };
 
                        uart1_rts: uart1-rts {
-                               rockchip,pins = <RK_GPIO1 7 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PA7 1 &pcfg_pull_default>;
                        };
                };
 
                uart2 {
                        uart2_xfer: uart2-xfer {
-                               rockchip,pins = <RK_GPIO1 8 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO1 9 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <1 RK_PB0 1 &pcfg_pull_default>,
+                                               <1 RK_PB1 1 &pcfg_pull_default>;
                        };
                        /* no rts / cts for uart2 */
                };
 
                uart3 {
                        uart3_xfer: uart3-xfer {
-                               rockchip,pins = <RK_GPIO3 27 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO3 28 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PD3 1 &pcfg_pull_default>,
+                                               <3 RK_PD4 1 &pcfg_pull_default>;
                        };
 
                        uart3_cts: uart3-cts {
-                               rockchip,pins = <RK_GPIO3 29 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PD5 1 &pcfg_pull_default>;
                        };
 
                        uart3_rts: uart3-rts {
-                               rockchip,pins = <RK_GPIO3 30 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PD6 1 &pcfg_pull_default>;
                        };
                };
 
                sd0 {
                        sd0_clk: sd0-clk {
-                               rockchip,pins = <RK_GPIO3 8 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PB0 1 &pcfg_pull_default>;
                        };
 
                        sd0_cmd: sd0-cmd {
-                               rockchip,pins = <RK_GPIO3 9 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PB1 1 &pcfg_pull_default>;
                        };
 
                        sd0_cd: sd0-cd {
-                               rockchip,pins = <RK_GPIO3 14 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PB6 1 &pcfg_pull_default>;
                        };
 
                        sd0_wp: sd0-wp {
-                               rockchip,pins = <RK_GPIO3 15 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PB7 1 &pcfg_pull_default>;
                        };
 
                        sd0_bus1: sd0-bus-width1 {
-                               rockchip,pins = <RK_GPIO3 10 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PB2 1 &pcfg_pull_default>;
                        };
 
                        sd0_bus4: sd0-bus-width4 {
-                               rockchip,pins = <RK_GPIO3 10 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO3 11 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO3 12 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO3 13 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PB2 1 &pcfg_pull_default>,
+                                               <3 RK_PB3 1 &pcfg_pull_default>,
+                                               <3 RK_PB4 1 &pcfg_pull_default>,
+                                               <3 RK_PB5 1 &pcfg_pull_default>;
                        };
                };
 
                sd1 {
                        sd1_clk: sd1-clk {
-                               rockchip,pins = <RK_GPIO3 21 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PC5 1 &pcfg_pull_default>;
                        };
 
                        sd1_cmd: sd1-cmd {
-                               rockchip,pins = <RK_GPIO3 16 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PC0 1 &pcfg_pull_default>;
                        };
 
                        sd1_cd: sd1-cd {
-                               rockchip,pins = <RK_GPIO3 22 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PC6 1 &pcfg_pull_default>;
                        };
 
                        sd1_wp: sd1-wp {
-                               rockchip,pins = <RK_GPIO3 23 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PC7 1 &pcfg_pull_default>;
                        };
 
                        sd1_bus1: sd1-bus-width1 {
-                               rockchip,pins = <RK_GPIO3 17 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PC1 1 &pcfg_pull_default>;
                        };
 
                        sd1_bus4: sd1-bus-width4 {
-                               rockchip,pins = <RK_GPIO3 17 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO3 18 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO3 19 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO3 20 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <3 RK_PC1 1 &pcfg_pull_default>,
+                                               <3 RK_PC2 1 &pcfg_pull_default>,
+                                               <3 RK_PC3 1 &pcfg_pull_default>,
+                                               <3 RK_PC4 1 &pcfg_pull_default>;
                        };
                };
 
                i2s0 {
                        i2s0_bus: i2s0-bus {
-                               rockchip,pins = <RK_GPIO0 7 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 8 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 9 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 10 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 11 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 12 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 13 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 14 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 15 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <0 RK_PA7 1 &pcfg_pull_default>,
+                                               <0 RK_PB0 1 &pcfg_pull_default>,
+                                               <0 RK_PB1 1 &pcfg_pull_default>,
+                                               <0 RK_PB2 1 &pcfg_pull_default>,
+                                               <0 RK_PB3 1 &pcfg_pull_default>,
+                                               <0 RK_PB4 1 &pcfg_pull_default>,
+                                               <0 RK_PB5 1 &pcfg_pull_default>,
+                                               <0 RK_PB6 1 &pcfg_pull_default>,
+                                               <0 RK_PB7 1 &pcfg_pull_default>;
                        };
                };
 
                i2s1 {
                        i2s1_bus: i2s1-bus {
-                               rockchip,pins = <RK_GPIO0 16 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 17 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 18 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 19 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 20 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 21 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <0 RK_PC0 1 &pcfg_pull_default>,
+                                               <0 RK_PC1 1 &pcfg_pull_default>,
+                                               <0 RK_PC2 1 &pcfg_pull_default>,
+                                               <0 RK_PC3 1 &pcfg_pull_default>,
+                                               <0 RK_PC4 1 &pcfg_pull_default>,
+                                               <0 RK_PC5 1 &pcfg_pull_default>;
                        };
                };
 
                i2s2 {
                        i2s2_bus: i2s2-bus {
-                               rockchip,pins = <RK_GPIO0 24 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 25 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 26 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 27 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 28 RK_FUNC_1 &pcfg_pull_default>,
-                                               <RK_GPIO0 29 RK_FUNC_1 &pcfg_pull_default>;
+                               rockchip,pins = <0 RK_PD0 1 &pcfg_pull_default>,
+                                               <0 RK_PD1 1 &pcfg_pull_default>,
+                                               <0 RK_PD2 1 &pcfg_pull_default>,
+                                               <0 RK_PD3 1 &pcfg_pull_default>,
+                                               <0 RK_PD4 1 &pcfg_pull_default>,
+                                               <0 RK_PD5 1 &pcfg_pull_default>;
                        };
                };
        };
index c0eaa9c5490b2e9c28d65ce2901d528d014009e3..c32e1d441cf70b48fd5121879fb4d0e81f555d42 100644 (file)
 
        usb {
                host_vbus_drv: host-vbus-drv {
-                       rockchip,pins = <0 3 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
                otg_vbus_drv: otg-vbus-drv {
-                       rockchip,pins = <2 31 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PD7 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 94bc81c24049b8e80eca38a7a2c5b9f1e643085b..c9a7f54099608237a9bd62d311bde4e6bf2571b5 100644 (file)
 
        act8846 {
                act8846_dvs0_ctl: act8846-dvs0-ctl {
-                       rockchip,pins = <RK_GPIO3 27 RK_FUNC_GPIO &pcfg_output_low>;
+                       rockchip,pins = <3 RK_PD3 RK_FUNC_GPIO &pcfg_output_low>;
                };
        };
 
        hym8563 {
                rtc_int: rtc-int {
-                       rockchip,pins = <RK_GPIO0 0 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        lan8720a  {
                phy_int: phy-int {
-                       rockchip,pins = <RK_GPIO3 26 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        ir-receiver {
                ir_recv_pin: ir-recv-pin {
-                       rockchip,pins = <RK_GPIO0 10 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        sd0 {
                sdmmc_pwr: sdmmc-pwr {
-                       rockchip,pins = <RK_GPIO3 1 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        usb {
                host_vbus_drv: host-vbus-drv {
-                       rockchip,pins = <0 3 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
                otg_vbus_drv: otg-vbus-drv {
-                       rockchip,pins = <2 31 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PD7 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 3ed49898f4b2edab7e6a5efbf68ea081cfa64734..10ede65d90f38812890479bcbd15a882d716c1ae 100644 (file)
 
                emmc {
                        emmc_clk: emmc-clk {
-                               rockchip,pins = <RK_GPIO0 24 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PD0 2 &pcfg_pull_none>;
                        };
 
                        emmc_cmd: emmc-cmd {
-                               rockchip,pins = <RK_GPIO0 26 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PD2 2 &pcfg_pull_up>;
                        };
 
                        emmc_rst: emmc-rst {
-                               rockchip,pins = <RK_GPIO0 27 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PD3 2 &pcfg_pull_none>;
                        };
 
                        /*
 
                emac {
                        emac_xfer: emac-xfer {
-                               rockchip,pins = <RK_GPIO3 16 RK_FUNC_2 &pcfg_pull_none>, /* tx_en */
-                                               <RK_GPIO3 17 RK_FUNC_2 &pcfg_pull_none>, /* txd1 */
-                                               <RK_GPIO3 18 RK_FUNC_2 &pcfg_pull_none>, /* txd0 */
-                                               <RK_GPIO3 19 RK_FUNC_2 &pcfg_pull_none>, /* rxd0 */
-                                               <RK_GPIO3 20 RK_FUNC_2 &pcfg_pull_none>, /* rxd1 */
-                                               <RK_GPIO3 21 RK_FUNC_2 &pcfg_pull_none>, /* mac_clk */
-                                               <RK_GPIO3 22 RK_FUNC_2 &pcfg_pull_none>, /* rx_err */
-                                               <RK_GPIO3 23 RK_FUNC_2 &pcfg_pull_none>; /* crs_dvalid */
+                               rockchip,pins = <3 RK_PC0 2 &pcfg_pull_none>, /* tx_en */
+                                               <3 RK_PC1 2 &pcfg_pull_none>, /* txd1 */
+                                               <3 RK_PC2 2 &pcfg_pull_none>, /* txd0 */
+                                               <3 RK_PC3 2 &pcfg_pull_none>, /* rxd0 */
+                                               <3 RK_PC4 2 &pcfg_pull_none>, /* rxd1 */
+                                               <3 RK_PC5 2 &pcfg_pull_none>, /* mac_clk */
+                                               <3 RK_PC6 2 &pcfg_pull_none>, /* rx_err */
+                                               <3 RK_PC7 2 &pcfg_pull_none>; /* crs_dvalid */
                        };
 
                        emac_mdio: emac-mdio {
-                               rockchip,pins = <RK_GPIO3 24 RK_FUNC_2 &pcfg_pull_none>,
-                                               <RK_GPIO3 25 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PD0 2 &pcfg_pull_none>,
+                                               <3 RK_PD1 2 &pcfg_pull_none>;
                        };
                };
 
                i2c0 {
                        i2c0_xfer: i2c0-xfer {
-                               rockchip,pins = <RK_GPIO1 24 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO1 25 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PD0 1 &pcfg_pull_none>,
+                                               <1 RK_PD1 1 &pcfg_pull_none>;
                        };
                };
 
                i2c1 {
                        i2c1_xfer: i2c1-xfer {
-                               rockchip,pins = <RK_GPIO1 26 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO1 27 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PD2 1 &pcfg_pull_none>,
+                                               <1 RK_PD3 1 &pcfg_pull_none>;
                        };
                };
 
                i2c2 {
                        i2c2_xfer: i2c2-xfer {
-                               rockchip,pins = <RK_GPIO1 28 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO1 29 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PD4 1 &pcfg_pull_none>,
+                                               <1 RK_PD5 1 &pcfg_pull_none>;
                        };
                };
 
                i2c3 {
                        i2c3_xfer: i2c3-xfer {
-                               rockchip,pins = <RK_GPIO3 14 RK_FUNC_2 &pcfg_pull_none>,
-                                               <RK_GPIO3 15 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PB6 2 &pcfg_pull_none>,
+                                               <3 RK_PB7 2 &pcfg_pull_none>;
                        };
                };
 
                i2c4 {
                        i2c4_xfer: i2c4-xfer {
-                               rockchip,pins = <RK_GPIO1 30 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO1 31 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PD6 1 &pcfg_pull_none>,
+                                               <1 RK_PD7 1 &pcfg_pull_none>;
                        };
                };
 
                lcdc1 {
                        lcdc1_dclk: lcdc1-dclk {
-                               rockchip,pins = <2 RK_PD0 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PD0 1 &pcfg_pull_none>;
                        };
 
                        lcdc1_den: lcdc1-den {
-                               rockchip,pins = <2 RK_PD1 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PD1 1 &pcfg_pull_none>;
                        };
 
                        lcdc1_hsync: lcdc1-hsync {
-                               rockchip,pins = <2 RK_PD2 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PD2 1 &pcfg_pull_none>;
                        };
 
                        lcdc1_vsync: lcdc1-vsync {
-                               rockchip,pins = <2 RK_PD3 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PD3 1 &pcfg_pull_none>;
                        };
 
                        lcdc1_rgb24: ldcd1-rgb24 {
-                               rockchip,pins = <2 RK_PA0 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PA1 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PA2 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PA3 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PA4 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PA5 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PA6 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PA7 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PB0 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PB1 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PB2 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PB3 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PB4 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PB5 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PB6 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PB7 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PC0 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PC1 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PC2 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PC3 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PC4 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PC5 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PC6 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 RK_PC7 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PA0 1 &pcfg_pull_none>,
+                                               <2 RK_PA1 1 &pcfg_pull_none>,
+                                               <2 RK_PA2 1 &pcfg_pull_none>,
+                                               <2 RK_PA3 1 &pcfg_pull_none>,
+                                               <2 RK_PA4 1 &pcfg_pull_none>,
+                                               <2 RK_PA5 1 &pcfg_pull_none>,
+                                               <2 RK_PA6 1 &pcfg_pull_none>,
+                                               <2 RK_PA7 1 &pcfg_pull_none>,
+                                               <2 RK_PB0 1 &pcfg_pull_none>,
+                                               <2 RK_PB1 1 &pcfg_pull_none>,
+                                               <2 RK_PB2 1 &pcfg_pull_none>,
+                                               <2 RK_PB3 1 &pcfg_pull_none>,
+                                               <2 RK_PB4 1 &pcfg_pull_none>,
+                                               <2 RK_PB5 1 &pcfg_pull_none>,
+                                               <2 RK_PB6 1 &pcfg_pull_none>,
+                                               <2 RK_PB7 1 &pcfg_pull_none>,
+                                               <2 RK_PC0 1 &pcfg_pull_none>,
+                                               <2 RK_PC1 1 &pcfg_pull_none>,
+                                               <2 RK_PC2 1 &pcfg_pull_none>,
+                                               <2 RK_PC3 1 &pcfg_pull_none>,
+                                               <2 RK_PC4 1 &pcfg_pull_none>,
+                                               <2 RK_PC5 1 &pcfg_pull_none>,
+                                               <2 RK_PC6 1 &pcfg_pull_none>,
+                                               <2 RK_PC7 1 &pcfg_pull_none>;
                        };
                };
 
                pwm0 {
                        pwm0_out: pwm0-out {
-                               rockchip,pins = <RK_GPIO3 27 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PD3 1 &pcfg_pull_none>;
                        };
                };
 
                pwm1 {
                        pwm1_out: pwm1-out {
-                               rockchip,pins = <RK_GPIO3 28 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PD4 1 &pcfg_pull_none>;
                        };
                };
 
                pwm2 {
                        pwm2_out: pwm2-out {
-                               rockchip,pins = <RK_GPIO3 29 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PD5 1 &pcfg_pull_none>;
                        };
                };
 
                pwm3 {
                        pwm3_out: pwm3-out {
-                               rockchip,pins = <RK_GPIO3 30 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PD6 1 &pcfg_pull_none>;
                        };
                };
 
                spi0 {
                        spi0_clk: spi0-clk {
-                               rockchip,pins = <RK_GPIO1 6 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PA6 2 &pcfg_pull_up>;
                        };
                        spi0_cs0: spi0-cs0 {
-                               rockchip,pins = <RK_GPIO1 7 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PA7 2 &pcfg_pull_up>;
                        };
                        spi0_tx: spi0-tx {
-                               rockchip,pins = <RK_GPIO1 5 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PA5 2 &pcfg_pull_up>;
                        };
                        spi0_rx: spi0-rx {
-                               rockchip,pins = <RK_GPIO1 4 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PA4 2 &pcfg_pull_up>;
                        };
                        spi0_cs1: spi0-cs1 {
-                               rockchip,pins = <RK_GPIO1 15 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PB7 1 &pcfg_pull_up>;
                        };
                };
 
                spi1 {
                        spi1_clk: spi1-clk {
-                               rockchip,pins = <RK_GPIO0 30 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PD6 1 &pcfg_pull_up>;
                        };
                        spi1_cs0: spi1-cs0 {
-                               rockchip,pins = <RK_GPIO0 31 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PD7 1 &pcfg_pull_up>;
                        };
                        spi1_rx: spi1-rx {
-                               rockchip,pins = <RK_GPIO0 28 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PD4 1 &pcfg_pull_up>;
                        };
                        spi1_tx: spi1-tx {
-                               rockchip,pins = <RK_GPIO0 29 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PD5 1 &pcfg_pull_up>;
                        };
                        spi1_cs1: spi1-cs1 {
-                               rockchip,pins = <RK_GPIO1 14 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PB6 2 &pcfg_pull_up>;
                        };
                };
 
                uart0 {
                        uart0_xfer: uart0-xfer {
-                               rockchip,pins = <RK_GPIO1 0 RK_FUNC_1 &pcfg_pull_up>,
-                                               <RK_GPIO1 1 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PA0 1 &pcfg_pull_up>,
+                                               <1 RK_PA1 1 &pcfg_pull_none>;
                        };
 
                        uart0_cts: uart0-cts {
-                               rockchip,pins = <RK_GPIO1 2 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PA2 1 &pcfg_pull_none>;
                        };
 
                        uart0_rts: uart0-rts {
-                               rockchip,pins = <RK_GPIO1 3 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PA3 1 &pcfg_pull_none>;
                        };
                };
 
                uart1 {
                        uart1_xfer: uart1-xfer {
-                               rockchip,pins = <RK_GPIO1 4 RK_FUNC_1 &pcfg_pull_up>,
-                                               <RK_GPIO1 5 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PA4 1 &pcfg_pull_up>,
+                                               <1 RK_PA5 1 &pcfg_pull_none>;
                        };
 
                        uart1_cts: uart1-cts {
-                               rockchip,pins = <RK_GPIO1 6 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PA6 1 &pcfg_pull_none>;
                        };
 
                        uart1_rts: uart1-rts {
-                               rockchip,pins = <RK_GPIO1 7 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PA7 1 &pcfg_pull_none>;
                        };
                };
 
                uart2 {
                        uart2_xfer: uart2-xfer {
-                               rockchip,pins = <RK_GPIO1 8 RK_FUNC_1 &pcfg_pull_up>,
-                                               <RK_GPIO1 9 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PB0 1 &pcfg_pull_up>,
+                                               <1 RK_PB1 1 &pcfg_pull_none>;
                        };
                        /* no rts / cts for uart2 */
                };
 
                uart3 {
                        uart3_xfer: uart3-xfer {
-                               rockchip,pins = <RK_GPIO1 10 RK_FUNC_1 &pcfg_pull_up>,
-                                               <RK_GPIO1 11 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PB2 1 &pcfg_pull_up>,
+                                               <1 RK_PB3 1 &pcfg_pull_none>;
                        };
 
                        uart3_cts: uart3-cts {
-                               rockchip,pins = <RK_GPIO1 12 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PB4 1 &pcfg_pull_none>;
                        };
 
                        uart3_rts: uart3-rts {
-                               rockchip,pins = <RK_GPIO1 13 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PB5 1 &pcfg_pull_none>;
                        };
                };
 
                sd0 {
                        sd0_clk: sd0-clk {
-                               rockchip,pins = <RK_GPIO3 2 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PA2 1 &pcfg_pull_none>;
                        };
 
                        sd0_cmd: sd0-cmd {
-                               rockchip,pins = <RK_GPIO3 3 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PA3 1 &pcfg_pull_none>;
                        };
 
                        sd0_cd: sd0-cd {
-                               rockchip,pins = <RK_GPIO3 8 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PB0 1 &pcfg_pull_none>;
                        };
 
                        sd0_wp: sd0-wp {
-                               rockchip,pins = <RK_GPIO3 9 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PB1 1 &pcfg_pull_none>;
                        };
 
                        sd0_pwr: sd0-pwr {
-                               rockchip,pins = <RK_GPIO3 1 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PA1 1 &pcfg_pull_none>;
                        };
 
                        sd0_bus1: sd0-bus-width1 {
-                               rockchip,pins = <RK_GPIO3 4 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PA4 1 &pcfg_pull_none>;
                        };
 
                        sd0_bus4: sd0-bus-width4 {
-                               rockchip,pins = <RK_GPIO3 4 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO3 5 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO3 6 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO3 7 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PA4 1 &pcfg_pull_none>,
+                                               <3 RK_PA5 1 &pcfg_pull_none>,
+                                               <3 RK_PA6 1 &pcfg_pull_none>,
+                                               <3 RK_PA7 1 &pcfg_pull_none>;
                        };
                };
 
                sd1 {
                        sd1_clk: sd1-clk {
-                               rockchip,pins = <RK_GPIO3 21 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PC5 1 &pcfg_pull_none>;
                        };
 
                        sd1_cmd: sd1-cmd {
-                               rockchip,pins = <RK_GPIO3 16 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PC0 1 &pcfg_pull_none>;
                        };
 
                        sd1_cd: sd1-cd {
-                               rockchip,pins = <RK_GPIO3 22 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PC6 1 &pcfg_pull_none>;
                        };
 
                        sd1_wp: sd1-wp {
-                               rockchip,pins = <RK_GPIO3 23 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PC7 1 &pcfg_pull_none>;
                        };
 
                        sd1_bus1: sd1-bus-width1 {
-                               rockchip,pins = <RK_GPIO3 17 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PC1 1 &pcfg_pull_none>;
                        };
 
                        sd1_bus4: sd1-bus-width4 {
-                               rockchip,pins = <RK_GPIO3 17 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO3 18 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO3 19 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO3 20 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PC1 1 &pcfg_pull_none>,
+                                               <3 RK_PC2 1 &pcfg_pull_none>,
+                                               <3 RK_PC3 1 &pcfg_pull_none>,
+                                               <3 RK_PC4 1 &pcfg_pull_none>;
                        };
                };
 
                i2s0 {
                        i2s0_bus: i2s0-bus {
-                               rockchip,pins = <RK_GPIO1 16 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO1 17 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO1 18 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO1 19 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO1 20 RK_FUNC_1 &pcfg_pull_none>,
-                                               <RK_GPIO1 21 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PC0 1 &pcfg_pull_none>,
+                                               <1 RK_PC1 1 &pcfg_pull_none>,
+                                               <1 RK_PC2 1 &pcfg_pull_none>,
+                                               <1 RK_PC3 1 &pcfg_pull_none>,
+                                               <1 RK_PC4 1 &pcfg_pull_none>,
+                                               <1 RK_PC5 1 &pcfg_pull_none>;
                        };
                };
 
                spdif {
                        spdif_tx: spdif-tx {
-                               rockchip,pins = <RK_GPIO1 14 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PB6 1 &pcfg_pull_none>;
                        };
                };
        };
index 29f19076dcebba2c32b1415536e87763c574819d..da102fff96a26b2974e86476c4f0143effe07e5b 100644 (file)
 
                emmc {
                        emmc_clk: emmc-clk {
-                               rockchip,pins = <2 7 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PA7 2 &pcfg_pull_none>;
                        };
 
                        emmc_cmd: emmc-cmd {
-                               rockchip,pins = <1 22 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PC6 2 &pcfg_pull_none>;
                        };
 
                        emmc_bus8: emmc-bus8 {
-                               rockchip,pins = <1 24 RK_FUNC_2 &pcfg_pull_none>,
-                                               <1 25 RK_FUNC_2 &pcfg_pull_none>,
-                                               <1 26 RK_FUNC_2 &pcfg_pull_none>,
-                                               <1 27 RK_FUNC_2 &pcfg_pull_none>,
-                                               <1 28 RK_FUNC_2 &pcfg_pull_none>,
-                                               <1 29 RK_FUNC_2 &pcfg_pull_none>,
-                                               <1 30 RK_FUNC_2 &pcfg_pull_none>,
-                                               <1 31 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PD0 2 &pcfg_pull_none>,
+                                               <1 RK_PD1 2 &pcfg_pull_none>,
+                                               <1 RK_PD2 2 &pcfg_pull_none>,
+                                               <1 RK_PD3 2 &pcfg_pull_none>,
+                                               <1 RK_PD4 2 &pcfg_pull_none>,
+                                               <1 RK_PD5 2 &pcfg_pull_none>,
+                                               <1 RK_PD6 2 &pcfg_pull_none>,
+                                               <1 RK_PD7 2 &pcfg_pull_none>;
                        };
                };
 
                gmac {
                        rgmii_pins: rgmii-pins {
-                               rockchip,pins = <2 14 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 12 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 25 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 19 RK_FUNC_1 &pcfg_pull_none_drv_12ma>,
-                                               <2 18 RK_FUNC_1 &pcfg_pull_none_drv_12ma>,
-                                               <2 22 RK_FUNC_1 &pcfg_pull_none_drv_12ma>,
-                                               <2 23 RK_FUNC_1 &pcfg_pull_none_drv_12ma>,
-                                               <2 9 RK_FUNC_1 &pcfg_pull_none_drv_12ma>,
-                                               <2 13 RK_FUNC_1 &pcfg_pull_none_drv_12ma>,
-                                               <2 17 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 16 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 21 RK_FUNC_2 &pcfg_pull_none>,
-                                               <2 20 RK_FUNC_2 &pcfg_pull_none>,
-                                               <2 11 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 8 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PB6 1 &pcfg_pull_none>,
+                                               <2 RK_PB4 1 &pcfg_pull_none>,
+                                               <2 RK_PD1 1 &pcfg_pull_none>,
+                                               <2 RK_PC3 1 &pcfg_pull_none_drv_12ma>,
+                                               <2 RK_PC2 1 &pcfg_pull_none_drv_12ma>,
+                                               <2 RK_PC6 1 &pcfg_pull_none_drv_12ma>,
+                                               <2 RK_PC7 1 &pcfg_pull_none_drv_12ma>,
+                                               <2 RK_PB1 1 &pcfg_pull_none_drv_12ma>,
+                                               <2 RK_PB5 1 &pcfg_pull_none_drv_12ma>,
+                                               <2 RK_PC1 1 &pcfg_pull_none>,
+                                               <2 RK_PC0 1 &pcfg_pull_none>,
+                                               <2 RK_PC5 2 &pcfg_pull_none>,
+                                               <2 RK_PC4 2 &pcfg_pull_none>,
+                                               <2 RK_PB3 1 &pcfg_pull_none>,
+                                               <2 RK_PB0 1 &pcfg_pull_none>;
                        };
 
                        rmii_pins: rmii-pins {
-                               rockchip,pins = <2 14 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 12 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 25 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 19 RK_FUNC_1 &pcfg_pull_none_drv_12ma>,
-                                               <2 18 RK_FUNC_1 &pcfg_pull_none_drv_12ma>,
-                                               <2 13 RK_FUNC_1 &pcfg_pull_none_drv_12ma>,
-                                               <2 17 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 16 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 8 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 15 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PB6 1 &pcfg_pull_none>,
+                                               <2 RK_PB4 1 &pcfg_pull_none>,
+                                               <2 RK_PD1 1 &pcfg_pull_none>,
+                                               <2 RK_PC3 1 &pcfg_pull_none_drv_12ma>,
+                                               <2 RK_PC2 1 &pcfg_pull_none_drv_12ma>,
+                                               <2 RK_PB5 1 &pcfg_pull_none_drv_12ma>,
+                                               <2 RK_PC1 1 &pcfg_pull_none>,
+                                               <2 RK_PC0 1 &pcfg_pull_none>,
+                                               <2 RK_PB0 1 &pcfg_pull_none>,
+                                               <2 RK_PB7 1 &pcfg_pull_none>;
                        };
 
                        phy_pins: phy-pins {
-                               rockchip,pins = <2 14 RK_FUNC_2 &pcfg_pull_none>,
-                                               <2 8 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PB6 2 &pcfg_pull_none>,
+                                               <2 RK_PB0 2 &pcfg_pull_none>;
                        };
                };
 
                i2c0 {
                        i2c0_xfer: i2c0-xfer {
-                               rockchip,pins = <0 0 RK_FUNC_1 &pcfg_pull_none>,
-                                               <0 1 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA0 1 &pcfg_pull_none>,
+                                               <0 RK_PA1 1 &pcfg_pull_none>;
                        };
                };
 
                i2c1 {
                        i2c1_xfer: i2c1-xfer {
-                               rockchip,pins = <0 2 RK_FUNC_1 &pcfg_pull_none>,
-                                               <0 3 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA2 1 &pcfg_pull_none>,
+                                               <0 RK_PA3 1 &pcfg_pull_none>;
                        };
                };
 
                i2c2 {
                        i2c2_xfer: i2c2-xfer {
-                               rockchip,pins = <2 20 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 21 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PC4 1 &pcfg_pull_none>,
+                                               <2 RK_PC5 1 &pcfg_pull_none>;
                        };
                };
 
                i2c3 {
                        i2c3_xfer: i2c3-xfer {
-                               rockchip,pins = <0 6 RK_FUNC_1 &pcfg_pull_none>,
-                                               <0 7 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA6 1 &pcfg_pull_none>,
+                                               <0 RK_PA7 1 &pcfg_pull_none>;
                        };
                };
 
                spi-0 {
                        spi0_clk: spi0-clk {
-                               rockchip,pins = <0 9 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PB1 2 &pcfg_pull_up>;
                        };
                        spi0_cs0: spi0-cs0 {
-                               rockchip,pins = <0 14 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PB6 2 &pcfg_pull_up>;
                        };
                        spi0_tx: spi0-tx {
-                               rockchip,pins = <0 11 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PB3 2 &pcfg_pull_up>;
                        };
                        spi0_rx: spi0-rx {
-                               rockchip,pins = <0 13 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PB5 2 &pcfg_pull_up>;
                        };
                        spi0_cs1: spi0-cs1 {
-                               rockchip,pins = <1 12 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PB4 1 &pcfg_pull_up>;
                        };
                };
 
                spi-1 {
                        spi1_clk: spi1-clk {
-                               rockchip,pins = <0 23 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PC7 2 &pcfg_pull_up>;
                        };
                        spi1_cs0: spi1-cs0 {
-                               rockchip,pins = <2 2 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <2 RK_PA2 2 &pcfg_pull_up>;
                        };
                        spi1_rx: spi1-rx {
-                               rockchip,pins = <2 0 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <2 RK_PA0 2 &pcfg_pull_up>;
                        };
                        spi1_tx: spi1-tx {
-                               rockchip,pins = <2 1 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <2 RK_PA1 2 &pcfg_pull_up>;
                        };
                        spi1_cs1: spi1-cs1 {
-                               rockchip,pins = <2 3 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <2 RK_PA3 2 &pcfg_pull_up>;
                        };
                };
 
                i2s1 {
                        i2s1_bus: i2s1-bus {
-                               rockchip,pins = <0 8 RK_FUNC_1 &pcfg_pull_none>,
-                                               <0 9 RK_FUNC_1 &pcfg_pull_none>,
-                                               <0 11 RK_FUNC_1 &pcfg_pull_none>,
-                                               <0 12 RK_FUNC_1 &pcfg_pull_none>,
-                                               <0 13 RK_FUNC_1 &pcfg_pull_none>,
-                                               <0 14 RK_FUNC_1 &pcfg_pull_none>,
-                                               <1 2 RK_FUNC_2 &pcfg_pull_none>,
-                                               <1 4 RK_FUNC_2 &pcfg_pull_none>,
-                                               <1 5 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PB0 1 &pcfg_pull_none>,
+                                               <0 RK_PB1 1 &pcfg_pull_none>,
+                                               <0 RK_PB3 1 &pcfg_pull_none>,
+                                               <0 RK_PB4 1 &pcfg_pull_none>,
+                                               <0 RK_PB5 1 &pcfg_pull_none>,
+                                               <0 RK_PB6 1 &pcfg_pull_none>,
+                                               <1 RK_PA2 2 &pcfg_pull_none>,
+                                               <1 RK_PA4 2 &pcfg_pull_none>,
+                                               <1 RK_PA5 2 &pcfg_pull_none>;
                        };
                };
 
                pwm0 {
                        pwm0_pin: pwm0-pin {
-                               rockchip,pins = <3 21 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PC5 1 &pcfg_pull_none>;
                        };
                };
 
                pwm1 {
                        pwm1_pin: pwm1-pin {
-                               rockchip,pins = <0 30 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PD6 2 &pcfg_pull_none>;
                        };
                };
 
                pwm2 {
                        pwm2_pin: pwm2-pin {
-                               rockchip,pins = <1 12 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PB4 2 &pcfg_pull_none>;
                        };
                };
 
                pwm3 {
                        pwm3_pin: pwm3-pin {
-                               rockchip,pins = <1 11 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PB3 2 &pcfg_pull_none>;
                        };
                };
 
                spdif {
                        spdif_tx: spdif-tx {
-                               rockchip,pins = <3 31 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PD7 2 &pcfg_pull_none>;
                        };
                };
 
                tsadc {
                        otp_gpio: otp-gpio {
-                               rockchip,pins = <0 24 RK_FUNC_GPIO &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
                        };
 
                        otp_out: otp-out {
-                               rockchip,pins = <0 24 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PD0 2 &pcfg_pull_none>;
                        };
                };
 
                uart0 {
                        uart0_xfer: uart0-xfer {
-                               rockchip,pins = <2 26 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 27 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PD2 1 &pcfg_pull_none>,
+                                               <2 RK_PD3 1 &pcfg_pull_none>;
                        };
 
                        uart0_cts: uart0-cts {
-                               rockchip,pins = <2 29 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PD5 1 &pcfg_pull_none>;
                        };
 
                        uart0_rts: uart0-rts {
-                               rockchip,pins = <0 17 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PC1 1 &pcfg_pull_none>;
                        };
                };
 
                uart1 {
                        uart1_xfer: uart1-xfer {
-                               rockchip,pins = <1 9 RK_FUNC_1 &pcfg_pull_none>,
-                                               <1 10 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PB1 1 &pcfg_pull_none>,
+                                               <1 RK_PB2 1 &pcfg_pull_none>;
                        };
 
                        uart1_cts: uart1-cts {
-                               rockchip,pins = <1 8 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PB0 1 &pcfg_pull_none>;
                        };
 
                        uart1_rts: uart1-rts {
-                               rockchip,pins = <1 11 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PB3 1 &pcfg_pull_none>;
                        };
                };
 
                uart2 {
                        uart2_xfer: uart2-xfer {
-                               rockchip,pins = <1 18 RK_FUNC_2 &pcfg_pull_up>,
-                                               <1 19 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PC2 2 &pcfg_pull_up>,
+                                               <1 RK_PC3 2 &pcfg_pull_none>;
                        };
 
                        uart21_xfer: uart21-xfer {
-                               rockchip,pins = <1 10 RK_FUNC_2 &pcfg_pull_up>,
-                                               <1 9 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PB2 2 &pcfg_pull_up>,
+                                               <1 RK_PB1 2 &pcfg_pull_none>;
                        };
 
                        uart2_cts: uart2-cts {
-                               rockchip,pins = <0 25 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PD1 1 &pcfg_pull_none>;
                        };
 
                        uart2_rts: uart2-rts {
-                               rockchip,pins = <0 24 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PD0 1 &pcfg_pull_none>;
                        };
                };
        };
index 6592c809e2a54140086cdd0444dd1959eadcb6df..80080767c3659ecf135df62288c2a5f65e03d72c 100644 (file)
 &pinctrl {
        lcd {
                lcd_en: lcd-en  {
-                       rockchip,pins = <7 3 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        wifi {
                wifi_pwr: wifi-pwr {
-                       rockchip,pins = <7 9 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 97e4d552ff0f050c0214226bc55e83196480e55b..820440715302d455ec6f176a905021bc15acf9ab 100644 (file)
 
        backlight {
                bl_en: bl-en {
-                       rockchip,pins = <7 2 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        buttons {
                pwrbtn: pwrbtn {
-                       rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        lcd {
                lcd_cs: lcd-cs {
-                       rockchip,pins = <7 4 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        pmic {
                pmic_int: pmic-int {
-                       rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
                 * high-speed mode on EVB board so bump up to 8ma.
                 */
                sdmmc_bus4: sdmmc-bus4 {
-                       rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
-                                       <6 17 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
-                                       <6 18 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
-                                       <6 19 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
+                       rockchip,pins = <6 RK_PC0 1 &pcfg_pull_up_drv_8ma>,
+                                       <6 RK_PC1 1 &pcfg_pull_up_drv_8ma>,
+                                       <6 RK_PC2 1 &pcfg_pull_up_drv_8ma>,
+                                       <6 RK_PC3 1 &pcfg_pull_up_drv_8ma>;
                };
 
                sdmmc_clk: sdmmc-clk {
-                       rockchip,pins = <6 20 RK_FUNC_1 &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <6 RK_PC4 1 &pcfg_pull_none_drv_8ma>;
                };
 
                sdmmc_cmd: sdmmc-cmd {
-                       rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
+                       rockchip,pins = <6 RK_PC5 1 &pcfg_pull_up_drv_8ma>;
                };
 
                sdmmc_pwr: sdmmc-pwr {
-                       rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        usb {
                host_vbus_drv: host-vbus-drv {
-                       rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        eth_phy {
                eth_phy_pwr: eth-phy-pwr {
-                       rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 29af26e6d442e224145f4a5d9476c207ed0f4386..4847cf902a154a0ab5fe7a20970e00e0beb2cb09 100644 (file)
 
        gmac {
                phy_int: phy-int {
-                       rockchip,pins = <0 9 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                phy_pmeb: phy-pmeb {
-                       rockchip,pins = <0 8 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                phy_rst: phy-rst {
-                       rockchip,pins = <4 8 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 
        pmic {
                pmic_int: pmic-int {
-                       rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        usbphy {
                host_drv: host-drv {
-                       rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 0f3c29d7fbab0e029fdb33b14b99458c46597749..135e8832141f5329c74c5da9d6916dc3cc594373 100644 (file)
 &pinctrl {
        act8846 {
                pmic_vsel: pmic-vsel {
-                       rockchip,pins = <7 1 RK_FUNC_GPIO &pcfg_output_low>;
+                       rockchip,pins = <7 RK_PA1 RK_FUNC_GPIO &pcfg_output_low>;
                };
        };
 
        ir {
                ir_int: ir-int {
-                       rockchip,pins = <7 5 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <7 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 };
index f57f286a93c3e7540d8b2890d3eea6918d44b73d..61435d8ee37bf461af7f36cb4b565c4a40267f8d 100644 (file)
 
        act8846 {
                pwr_hold: pwr-hold {
-                       rockchip,pins = <0 1 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_output_high>;
                };
 
                pmic_vsel: pmic-vsel {
-                       rockchip,pins = <7 14 RK_FUNC_GPIO &pcfg_output_low>;
+                       rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_output_low>;
                };
        };
 
        gmac {
                phy_int: phy-int {
-                       rockchip,pins = <0 9 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                phy_pmeb: phy-pmeb {
-                       rockchip,pins = <0 8 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                phy_rst: phy-rst {
-                       rockchip,pins = <4 8 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 };
index 3a646c5f4fcf01a7c022f2acba86cdc4f7b2b526..1574383fd2dc6175200e41487de728eb8ce9d250 100644 (file)
 &pinctrl {
        ir {
                ir_int: ir-int {
-                       rockchip,pins = <7 0 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <7 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        dvp {
                dvp_pwr: dvp-pwr {
-                       rockchip,pins = <0 11 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                cif_pwr: cif-pwr {
-                       rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        hym8563 {
                rtc_int: rtc-int {
-                       rockchip,pins = <7 4 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <7 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        keys {
                pwr_key: pwr-key {
-                       rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        leds {
                power_led: power-led {
-                       rockchip,pins = <8 2 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <8 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                work_led: work-led {
-                       rockchip,pins = <8 1 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <8 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
                 * high-speed mode on firefly board so bump up to 12ma.
                 */
                sdmmc_bus4: sdmmc-bus4 {
-                       rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
-                                       <6 17 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
-                                       <6 18 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
-                                       <6 19 RK_FUNC_1 &pcfg_pull_up_drv_12ma>;
+                       rockchip,pins = <6 RK_PC0 1 &pcfg_pull_up_drv_12ma>,
+                                       <6 RK_PC1 1 &pcfg_pull_up_drv_12ma>,
+                                       <6 RK_PC2 1 &pcfg_pull_up_drv_12ma>,
+                                       <6 RK_PC3 1 &pcfg_pull_up_drv_12ma>;
                };
 
                sdmmc_clk: sdmmc-clk {
-                       rockchip,pins = <6 20 RK_FUNC_1 &pcfg_pull_none_12ma>;
+                       rockchip,pins = <6 RK_PC4 1 &pcfg_pull_none_12ma>;
                };
 
                sdmmc_cmd: sdmmc-cmd {
-                       rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_up_drv_12ma>;
+                       rockchip,pins = <6 RK_PC5 1 &pcfg_pull_up_drv_12ma>;
                };
 
                sdmmc_pwr: sdmmc-pwr {
-                       rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        sdio {
                wifi_enable: wifi-enable {
-                       rockchip,pins = <4 28 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <4 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        usb_host {
                host_vbus_drv: host-vbus-drv {
-                       rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                usbhub_rst: usbhub-rst {
-                       rockchip,pins = <8 3 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <8 RK_PA3 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 
        usb_otg {
                otg_vbus_drv: otg-vbus-drv {
-                       rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 556ab42dd81cfa914501a711b599721a27300c84..313459dab2e4d60e5f1c742e66bb6a955f498181 100644 (file)
 &pinctrl {
        act8846 {
                pmic_vsel: pmic-vsel {
-                       rockchip,pins = <7 14 RK_FUNC_GPIO &pcfg_output_low>;
+                       rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_output_low>;
                };
        };
 
        ir {
                ir_int: ir-int {
-                       rockchip,pins = <7 0 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <7 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 };
index a6ff7eac4aa847a7621b9925a4f3214fa443e879..5e0a19004e46ef68aff167d380ca7730414d32f1 100644 (file)
 
        act8846 {
                pwr_hold: pwr-hold {
-                       rockchip,pins = <0 1 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 
        dvp {
                dvp_pwr: dvp-pwr {
-                       rockchip,pins = <0 11 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        gmac {
                phy_int: phy-int {
-                       rockchip,pins = <0 9 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                phy_pmeb: phy-pmeb {
-                       rockchip,pins = <0 8 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                phy_rst: phy-rst {
-                       rockchip,pins = <4 8 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 
        hym8563 {
                rtc_int: rtc-int {
-                       rockchip,pins = <7 4 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <7 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        keys {
                pwr_key: pwr-key {
-                       rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        leds {
                power_led: power-led {
-                       rockchip,pins = <8 2 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <8 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                work_led: work-led {
-                       rockchip,pins = <8 1 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <8 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
                 * high-speed mode on firefly board so bump up to 12ma.
                 */
                sdmmc_bus4: sdmmc-bus4 {
-                       rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
-                                       <6 17 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
-                                       <6 18 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
-                                       <6 19 RK_FUNC_1 &pcfg_pull_up_drv_12ma>;
+                       rockchip,pins = <6 RK_PC0 1 &pcfg_pull_up_drv_12ma>,
+                                       <6 RK_PC1 1 &pcfg_pull_up_drv_12ma>,
+                                       <6 RK_PC2 1 &pcfg_pull_up_drv_12ma>,
+                                       <6 RK_PC3 1 &pcfg_pull_up_drv_12ma>;
                };
 
                sdmmc_clk: sdmmc-clk {
-                       rockchip,pins = <6 20 RK_FUNC_1 &pcfg_pull_none_12ma>;
+                       rockchip,pins = <6 RK_PC4 1 &pcfg_pull_none_12ma>;
                };
 
                sdmmc_cmd: sdmmc-cmd {
-                       rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_up_drv_12ma>;
+                       rockchip,pins = <6 RK_PC5 1 &pcfg_pull_up_drv_12ma>;
                };
 
                sdmmc_pwr: sdmmc-pwr {
-                       rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        usb_host {
                host_vbus_drv: host-vbus-drv {
-                       rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                usbhub_rst: usbhub-rst {
-                       rockchip,pins = <8 3 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <8 RK_PA3 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 
        usb_otg {
                otg_vbus_drv: otg-vbus-drv {
-                       rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index fb7365b604bba3e0bf4c031fb1da1af22cd153f9..c41d012c88503d4663e8d5ce2c22e5eca844d819 100644 (file)
 
        act8846 {
                pmic_int: pmic-int {
-                       rockchip,pins = <0 4 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                pmic_sleep: pmic-sleep {
-                       rockchip,pins = <0 0 RK_FUNC_GPIO &pcfg_output_low>;
+                       rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_output_low>;
                };
 
                pmic_vsel: pmic-vsel {
-                       rockchip,pins = <7 1 RK_FUNC_GPIO &pcfg_output_low>;
+                       rockchip,pins = <7 RK_PA1 RK_FUNC_GPIO &pcfg_output_low>;
                };
        };
 
        gmac {
                phy_int: phy-int {
-                       rockchip,pins = <0 9 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                phy_pmeb: phy-pmeb {
-                       rockchip,pins = <0 8 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                phy_rst: phy-rst {
-                       rockchip,pins = <4 8 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 
                 * high-speed mode on firefly board so bump up to 12ma.
                 */
                sdmmc_bus4: sdmmc-bus4 {
-                       rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
-                                       <6 17 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
-                                       <6 18 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
-                                       <6 19 RK_FUNC_1 &pcfg_pull_up_drv_12ma>;
+                       rockchip,pins = <6 RK_PC0 1 &pcfg_pull_up_drv_12ma>,
+                                       <6 RK_PC1 1 &pcfg_pull_up_drv_12ma>,
+                                       <6 RK_PC2 1 &pcfg_pull_up_drv_12ma>,
+                                       <6 RK_PC3 1 &pcfg_pull_up_drv_12ma>;
                };
 
                sdmmc_clk: sdmmc-clk {
-                       rockchip,pins = <6 20 RK_FUNC_1 &pcfg_pull_none_12ma>;
+                       rockchip,pins = <6 RK_PC4 1 &pcfg_pull_none_12ma>;
                };
 
                sdmmc_cmd: sdmmc-cmd {
-                       rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_up_drv_12ma>;
+                       rockchip,pins = <6 RK_PC5 1 &pcfg_pull_up_drv_12ma>;
                };
 
                sdmmc_pwr: sdmmc-pwr {
-                       rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        usb_host {
                host_vbus_drv: host-vbus-drv {
-                       rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 7077c3403483e7453c1e2471d4f1564f96b8a355..1e33859de4847c60e4cc269cf7c6f8f688b05f23 100644 (file)
        buttons {
                user_button_pins: user-button-pins {
                        /* button 1 */
-                       rockchip,pins = <8 3 RK_FUNC_GPIO &pcfg_pull_up>,
+                       rockchip,pins = <8 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>,
                        /* button 2 */
-                                       <8 0 RK_FUNC_GPIO &pcfg_pull_up>;
+                                       <8 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        rv4162 {
                i2c_rtc_int: i2c-rtc-int {
-                       rockchip,pins = <5 10 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <5 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
                 * high-speed mode on pcm-947 board so bump up to 12 mA.
                 */
                sdmmc_bus4: sdmmc-bus4 {
-                       rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
-                                       <6 17 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
-                                       <6 18 RK_FUNC_1 &pcfg_pull_up_drv_12ma>,
-                                       <6 19 RK_FUNC_1 &pcfg_pull_up_drv_12ma>;
+                       rockchip,pins = <6 RK_PC0 1 &pcfg_pull_up_drv_12ma>,
+                                       <6 RK_PC1 1 &pcfg_pull_up_drv_12ma>,
+                                       <6 RK_PC2 1 &pcfg_pull_up_drv_12ma>,
+                                       <6 RK_PC3 1 &pcfg_pull_up_drv_12ma>;
                };
 
                sdmmc_clk: sdmmc-clk {
-                       rockchip,pins = <6 20 RK_FUNC_1 &pcfg_pull_none_12ma>;
+                       rockchip,pins = <6 RK_PC4 1 &pcfg_pull_none_12ma>;
                };
 
                sdmmc_cmd: sdmmc-cmd {
-                       rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_up_drv_12ma>;
+                       rockchip,pins = <6 RK_PC5 1 &pcfg_pull_up_drv_12ma>;
                };
 
                sdmmc_pwr: sdmmc-pwr {
-                       rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        touchscreen {
                ts_irq_pin: ts-irq-pin {
-                       rockchip,pins = <5 15 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <5 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        usb_host {
                host0_vbus_drv: host0-vbus-drv {
-                       rockchip,pins = <2 13 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                host1_vbus_drv: host1-vbus-drv {
-                       rockchip,pins = <2 0 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        usb_otg {
                otg_vbus_drv: otg-vbus-drv {
-                       rockchip,pins = <2 12 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index c218dd54c9b5896146583926781d04f181374227..77a47b9b756d6915013000e2654e46cb91570b64 100644 (file)
                 * We also have external pulls, so disable the internal ones.
                 */
                emmc_clk: emmc-clk {
-                       rockchip,pins = <3 18 RK_FUNC_2 &pcfg_pull_none_12ma>;
+                       rockchip,pins = <3 RK_PC2 2 &pcfg_pull_none_12ma>;
                };
 
                emmc_cmd: emmc-cmd {
-                       rockchip,pins = <3 16 RK_FUNC_2 &pcfg_pull_none_12ma>;
+                       rockchip,pins = <3 RK_PC0 2 &pcfg_pull_none_12ma>;
                };
 
                emmc_bus8: emmc-bus8 {
-                       rockchip,pins = <3 0 RK_FUNC_2 &pcfg_pull_none_12ma>,
-                                       <3 1 RK_FUNC_2 &pcfg_pull_none_12ma>,
-                                       <3 2 RK_FUNC_2 &pcfg_pull_none_12ma>,
-                                       <3 3 RK_FUNC_2 &pcfg_pull_none_12ma>,
-                                       <3 4 RK_FUNC_2 &pcfg_pull_none_12ma>,
-                                       <3 5 RK_FUNC_2 &pcfg_pull_none_12ma>,
-                                       <3 6 RK_FUNC_2 &pcfg_pull_none_12ma>,
-                                       <3 7 RK_FUNC_2 &pcfg_pull_none_12ma>;
+                       rockchip,pins = <3 RK_PA0 2 &pcfg_pull_none_12ma>,
+                                       <3 RK_PA1 2 &pcfg_pull_none_12ma>,
+                                       <3 RK_PA2 2 &pcfg_pull_none_12ma>,
+                                       <3 RK_PA3 2 &pcfg_pull_none_12ma>,
+                                       <3 RK_PA4 2 &pcfg_pull_none_12ma>,
+                                       <3 RK_PA5 2 &pcfg_pull_none_12ma>,
+                                       <3 RK_PA6 2 &pcfg_pull_none_12ma>,
+                                       <3 RK_PA7 2 &pcfg_pull_none_12ma>;
                };
        };
 
        gmac {
                phy_int: phy-int {
-                       rockchip,pins = <4 2 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                phy_rst: phy-rst {
-                       rockchip,pins = <4 8 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 
        leds {
                user_led: user-led {
-                       rockchip,pins = <7 2 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <7 RK_PA2 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 
        pmic {
                pmic_int: pmic-int {
-                       rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                /* Pin for switching state between sleep and non-sleep state */
                pmic_sleep: pmic-sleep {
-                       rockchip,pins = <RK_GPIO0 0 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 };
index 28972fb4e221a90b8fee239697542a2608c19494..a6ffc381abaabae5c9176642044b694ba78d83ec 100644 (file)
 
        act8846 {
                pmic_vsel: pmic-vsel {
-                       rockchip,pins = <7 1 RK_FUNC_GPIO &pcfg_output_low>;
+                       rockchip,pins = <7 RK_PA1 RK_FUNC_GPIO &pcfg_output_low>;
                };
 
                pwr_hold: pwr-hold {
-                       rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 
        buttons {
                pwrbtn: pwrbtn {
-                       rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        ir {
                ir_int: ir-int {
-                       rockchip,pins = <7 0 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <7 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        pmic {
                pmic_int: pmic-int {
-                       rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        usb {
                host_vbus_drv: host-vbus-drv {
-                       rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                otg_vbus_drv: otg-vbus-drv {
-                       rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 32e1ab33666294e048ecb1314c89c10d013c9dfd..9f9e2bfd1295e6b0a8fbc0c73b4b837383b541a0 100644 (file)
 
        emmc {
                        emmc_reset: emmc-reset {
-                               rockchip,pins = <3 9 RK_FUNC_GPIO &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
                        };
        };
 
        gmac {
                phy_rst: phy-rst {
-                       rockchip,pins = <4 8 RK_FUNC_GPIO  &pcfg_output_high>;
+                       rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO  &pcfg_output_high>;
                };
        };
 };
index 5b7e1c9e92e14caf1b2a55017505e94eca30b7cd..cdcdc921ee09b7469f5ef64e814d7267e8c55507 100644 (file)
 &pinctrl {
        ir {
                ir_int: ir-int {
-                       rockchip,pins = <8 1 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <8 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        keys {
                pwr_key: pwr-key {
-                       rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        pmic {
                pmic_int: pmic-int {
-                       rockchip,pins = <0 4 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        headphone {
                hp_det: hp-det {
-                       rockchip,pins = <7 7 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                phone_ctl: phone-ctl {
-                       rockchip,pins = <8 0 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <8 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        usb {
                host_vbus_drv: host-vbus-drv {
-                       rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        sata {
                sata_pwr_en: sata-pwr-en {
-                       rockchip,pins = <0 13 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        sdmmc {
                sdmmc_pwr: sdmmc-pwr {
-                       rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        sdio {
                wifi_enable: wifi-enable {
-                       rockchip,pins = <4 28 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <4 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index d97da89bcd51a5f21e5adb87899531e4da104c6b..970e138591985ea7da3bd629f11fcafded337a45 100644 (file)
@@ -23,3 +23,8 @@
        mmc-ddr-1_8v;
        status = "okay";
 };
+
+&hdmi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&hdmi_cec_c0>;
+};
index ef653c3209bcc995aaa5d5cd79d0b3cf3fd0f8a0..293576869546efa305ae662a9f3db1777cde4819 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "rk3288.dtsi"
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/clock/rockchip,rk808.h>
 
 / {
        chosen {
                };
        };
 
+       sdio_pwrseq: sdio-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               clocks = <&rk808 RK808_CLKOUT1>;
+               clock-names = "ext_clock";
+               pinctrl-names = "default";
+               pinctrl-0 = <&wifi_enable>;
+               reset-gpios = <&gpio4 RK_PD3 GPIO_ACTIVE_LOW>,
+                       <&gpio4 RK_PD4 GPIO_ACTIVE_LOW>;
+       };
+
        sound {
                compatible = "simple-audio-card";
                simple-audio-card,format = "i2s";
        status = "okay";
 
        sdcard-supply = <&vccio_sd>;
+       wifi-supply = <&vcc_18>;
 };
 
 &pinctrl {
 
        backlight {
                bl_en: bl-en {
-                       rockchip,pins = <7 2 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        buttons {
                pwrbtn: pwrbtn {
-                       rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        eth_phy {
                eth_phy_pwr: eth-phy-pwr {
-                       rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        pmic {
                pmic_int: pmic-int {
-                       rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO \
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO \
                                        &pcfg_pull_up>;
                };
 
                dvs_1: dvs-1 {
-                       rockchip,pins = <RK_GPIO0 11 RK_FUNC_GPIO \
+                       rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO \
                                        &pcfg_pull_down>;
                };
 
                dvs_2: dvs-2 {
-                       rockchip,pins = <RK_GPIO0 12 RK_FUNC_GPIO \
+                       rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO \
                                        &pcfg_pull_down>;
                };
        };
 
        sdmmc {
                sdmmc_bus4: sdmmc-bus4 {
-                       rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
-                                       <6 17 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
-                                       <6 18 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
-                                       <6 19 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
+                       rockchip,pins = <6 RK_PC0 1 &pcfg_pull_up_drv_8ma>,
+                                       <6 RK_PC1 1 &pcfg_pull_up_drv_8ma>,
+                                       <6 RK_PC2 1 &pcfg_pull_up_drv_8ma>,
+                                       <6 RK_PC3 1 &pcfg_pull_up_drv_8ma>;
                };
 
                sdmmc_clk: sdmmc-clk {
-                       rockchip,pins = <6 20 RK_FUNC_1 \
+                       rockchip,pins = <6 RK_PC4 1 \
                                        &pcfg_pull_none_drv_8ma>;
                };
 
                sdmmc_cmd: sdmmc-cmd {
-                       rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
+                       rockchip,pins = <6 RK_PC5 1 &pcfg_pull_up_drv_8ma>;
                };
 
                sdmmc_pwr: sdmmc-pwr {
-                       rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        usb {
                host_vbus_drv: host-vbus-drv {
-                       rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                pwr_3g: pwr-3g {
-                       rockchip,pins = <7 8 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       sdio {
+               wifi_enable: wifi-enable {
+                       rockchip,pins = <4 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>,
+                               <4 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
        vqmmc-supply = <&vccio_sd>;
 };
 
+&sdio0 {
+       bus-width = <4>;
+       cap-sd-highspeed;
+       cap-sdio-irq;
+       keep-power-in-suspend;
+       max-frequency = <50000000>;
+       mmc-pwrseq = <&sdio_pwrseq>;
+       non-removable;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdio0_bus4>, <&sdio0_cmd>, <&sdio0_clk>, <&sdio0_int>;
+       sd-uhs-sdr12;
+       sd-uhs-sdr25;
+       sd-uhs-sdr50;
+       vmmc-supply = <&vcc_io>;
+       vqmmc-supply = <&vcc_18>;
+       status = "okay";
+};
+
 &tsadc {
        rockchip,hw-tshut-mode = <1>; /* tshut mode 0:CRU 1:GPIO */
        rockchip,hw-tshut-polarity = <1>; /* tshut polarity 0:LOW 1:HIGH */
index eaf921694e6814c3e28d900f5df9313a274c2bcf..445270aa136e06399545a343c2ff49c5955c40da 100644 (file)
@@ -73,7 +73,7 @@
 &pinctrl {
        codec {
                hp_det: hp-det {
-                       rockchip,pins = <6 5 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <6 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                /*
                 * we've got a ts3a227e chip but the driver requires it.
                 */
                int_codec: int-codec {
-                       rockchip,pins = <6 7 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <6 RK_PA7 RK_FUNC_GPIO &pcfg_pull_down>;
                };
 
                mic_det: mic-det {
-                       rockchip,pins = <6 11 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <6 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        headset {
                ts3a227e_int_l: ts3a227e-int-l {
-                       rockchip,pins = <0 3 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 };
index 5c94a33d695d47f95e1b4fad04dd63f661646eaf..406146cbff296fc2ff3bc98e0c4ad78297d099de 100644 (file)
 &pinctrl {
        hdmi {
                vcc50_hdmi_en: vcc50-hdmi-en {
-                       rockchip,pins = <7 2 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        pmic {
                dvs_1: dvs-1 {
-                       rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <7 RK_PB3 RK_FUNC_GPIO &pcfg_pull_down>;
                };
 
                dvs_2: dvs-2 {
-                       rockchip,pins = <7 15 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <7 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>;
                };
        };
 
        usb-host {
                usb2_pwr_en: usb2-pwr-en {
-                       rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index b54746df3661afe92d746909ba02c9fb3ee45432..fbef34578100f443b2cfbedcf564c8d799c7116d 100644 (file)
                        regulator-min-microvolt = <3300000>;
                        regulator-max-microvolt = <3300000>;
                        regulator-state-mem {
-                               regulator-on-in-suspend;
-                               regulator-suspend-microvolt = <3300000>;
+                               regulator-off-in-suspend;
                        };
                };
        };
 &pinctrl {
        pinctrl-0 = <
                /* Common for sleep and wake, but no owners */
+               &ddr0_retention
+               &ddrio_pwroff
                &global_pwroff
 
                /* Wake only */
        >;
        pinctrl-1 = <
                /* Common for sleep and wake, but no owners */
+               &ddr0_retention
+               &ddrio_pwroff
                &global_pwroff
 
                /* Sleep only */
 
        backlight {
                bl_en: bl-en {
-                       rockchip,pins = <7 2 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        buttons {
                ap_lid_int_l: ap-lid-int-l {
-                       rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        charger {
                ac_present_ap: ac-present-ap {
-                       rockchip,pins = <0 8 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        cros-ec {
                ec_int: ec-int {
-                       rockchip,pins = <7 7 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        suspend {
                suspend_l_wake: suspend-l-wake {
-                       rockchip,pins = <0 17 RK_FUNC_GPIO &pcfg_output_low>;
+                       rockchip,pins = <0 RK_PC1 RK_FUNC_GPIO &pcfg_output_low>;
                };
 
                suspend_l_sleep: suspend-l-sleep {
-                       rockchip,pins = <0 17 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <0 RK_PC1 RK_FUNC_GPIO &pcfg_output_high>;
                };
        };
 
        trackpad {
                trackpad_int: trackpad-int {
-                       rockchip,pins = <7 3 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <7 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        usb-host {
                host1_pwr_en: host1-pwr-en {
-                       rockchip,pins = <0 11 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                usbotg_pwren_h: usbotg-pwren-h {
-                       rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 9d6814c7f285f9ac0384eb9622f6bf30b92c44e6..e248f55ee8d2e6fa6487906f31aa95b430170b84 100644 (file)
 &pinctrl {
        backlight {
                bl_pwr_en: bl_pwr_en {
-                       rockchip,pins = <2 12 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        buck-5v {
                drv_5v: drv-5v {
-                       rockchip,pins = <7 21 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        hdmi {
                vcc50_hdmi_en: vcc50-hdmi-en {
-                       rockchip,pins = <5 19 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <5 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        lcd {
                lcd_enable_h: lcd-en {
-                       rockchip,pins = <7 14 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                avdd_1v8_disp_en: avdd-1v8-disp-en {
-                       rockchip,pins = <2 13 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        pmic {
                dvs_1: dvs-1 {
-                       rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
                };
 
                dvs_2: dvs-2 {
-                       rockchip,pins = <7 15 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <7 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>;
                };
        };
 };
index 2ba89895c33a436fa4193b48e628d5ab8931769a..b1613af83d5daeb978db5dbd7dd79b70b53fb65a 100644 (file)
 
 / {
        model = "Google Jerry";
-       compatible = "google,veyron-jerry-rev7", "google,veyron-jerry-rev6",
+       compatible = "google,veyron-jerry-rev15", "google,veyron-jerry-rev14",
+                    "google,veyron-jerry-rev13", "google,veyron-jerry-rev12",
+                    "google,veyron-jerry-rev11", "google,veyron-jerry-rev10",
+                    "google,veyron-jerry-rev7", "google,veyron-jerry-rev6",
                     "google,veyron-jerry-rev5", "google,veyron-jerry-rev4",
                     "google,veyron-jerry-rev3", "google,veyron-jerry",
                     "google,veyron", "rockchip,rk3288";
@@ -61,7 +64,9 @@
 
 &rk808 {
        pinctrl-names = "default";
-       pinctrl-0 = <&pmic_int_l>;
+       pinctrl-0 = <&pmic_int_l &dvs_1 &dvs_2>;
+       dvs-gpios = <&gpio7 RK_PB4 GPIO_ACTIVE_HIGH>,
+                   <&gpio7 RK_PB7 GPIO_ACTIVE_HIGH>;
 
        regulators {
                mic_vcc: LDO_REG2 {
 &pinctrl {
        backlight {
                bl_pwr_en: bl_pwr_en {
-                       rockchip,pins = <2 12 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        buck-5v {
                drv_5v: drv-5v {
-                       rockchip,pins = <7 21 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        hdmi {
                vcc50_hdmi_en: vcc50-hdmi-en {
-                       rockchip,pins = <5 19 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <5 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        lcd {
                lcd_enable_h: lcd-en {
-                       rockchip,pins = <7 14 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                avdd_1v8_disp_en: avdd-1v8-disp-en {
-                       rockchip,pins = <2 13 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        pmic {
                dvs_1: dvs-1 {
-                       rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
                };
 
                dvs_2: dvs-2 {
-                       rockchip,pins = <7 15 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <7 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>;
                };
        };
 };
index d889ab3c8235e2d864372602acbcc8620ed73533..e852594417b585f95be5ef1666a34c42407e0c53 100644 (file)
 &pinctrl {
        hdmi {
                power_hdmi_on: power-hdmi-on {
-                       rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        pmic {
                dvs_1: dvs-1 {
-                       rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
                };
 
                dvs_2: dvs-2 {
-                       rockchip,pins = <7 15 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <7 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>;
                };
        };
 };
diff --git a/arch/arm/boot/dts/rk3288-veyron-mighty.dts b/arch/arm/boot/dts/rk3288-veyron-mighty.dts
new file mode 100644 (file)
index 0000000..27fbc07
--- /dev/null
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Veyron Mighty Rev 1+ board device tree source
+ *
+ * Copyright 2015 Google, Inc
+ */
+
+/dts-v1/;
+
+#include "rk3288-veyron-jaq.dts"
+
+/ {
+       model = "Google Mighty";
+       compatible = "google,veyron-mighty-rev5", "google,veyron-mighty-rev4",
+                    "google,veyron-mighty-rev3", "google,veyron-mighty-rev2",
+                    "google,veyron-mighty-rev1", "google,veyron-mighty",
+                    "google,veyron", "rockchip,rk3288";
+};
+
+&sdmmc {
+       pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio
+                       &sdmmc_wp_gpio &sdmmc_bus4>;
+       wp-gpios = <&gpio7 10 GPIO_ACTIVE_HIGH>;
+
+       /delete-property/ disable-wp;
+};
+
+&pinctrl {
+       sdmmc {
+               sdmmc_wp_gpio: sdmmc-wp-gpio {
+                       rockchip,pins = <7 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+};
index f95d0c5fcf71263f044cb84a7efd6599878895be..468a1818545d1c86ce8c7ac8ce8a43e321520bad 100644 (file)
 &pinctrl {
        backlight {
                bl_pwr_en: bl_pwr_en {
-                       rockchip,pins = <2 12 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        buck-5v {
                drv_5v: drv-5v {
-                       rockchip,pins = <7 21 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        buttons {
                volum_down_l: volum-down-l {
-                       rockchip,pins = <5 11 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <5 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                volum_up_l: volum-up-l {
-                       rockchip,pins = <5 10 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <5 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        hdmi {
                vcc50_hdmi_en: vcc50-hdmi-en {
-                       rockchip,pins = <5 19 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <5 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        lcd {
                lcd_enable_h: lcd-en {
-                       rockchip,pins = <7 14 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                avdd_1v8_disp_en: avdd-1v8-disp-en {
-                       rockchip,pins = <2 13 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        pmic {
                dvs_1: dvs-1 {
-                       rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
                };
 
                dvs_2: dvs-2 {
-                       rockchip,pins = <7 15 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <7 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>;
                };
        };
 
        prochot {
                gpio_prochot: gpio-prochot {
-                       rockchip,pins = <2 8 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        touchscreen {
                touch_int: touch-int {
-                       rockchip,pins = <2 14 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                touch_rst: touch-rst {
-                       rockchip,pins = <2 15 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 2950aadf49f0564aae51a5471db83a808f55577b..9645be7b3d8ce94a57de997a7b1b3e6c0c2c4897 100644 (file)
 &pinctrl {
        buttons {
                pwr_key_h: pwr-key-h {
-                       rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        emmc {
                emmc_reset: emmc-reset {
-                       rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        sdmmc {
                sdmmc_wp_gpio: sdmmc-wp-gpio {
-                       rockchip,pins = <7 10 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <7 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 };
index a4570444cc79527efeb725be0207de6845b70f0a..fe950f9863e8743e72e21805b8eb07f523c5fd92 100644 (file)
                 * We also have external pulls, so disable the internal ones.
                 */
                sdmmc_bus4: sdmmc-bus4 {
-                       rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_none_drv_8ma>,
-                                       <6 17 RK_FUNC_1 &pcfg_pull_none_drv_8ma>,
-                                       <6 18 RK_FUNC_1 &pcfg_pull_none_drv_8ma>,
-                                       <6 19 RK_FUNC_1 &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <6 RK_PC0 1 &pcfg_pull_none_drv_8ma>,
+                                       <6 RK_PC1 1 &pcfg_pull_none_drv_8ma>,
+                                       <6 RK_PC2 1 &pcfg_pull_none_drv_8ma>,
+                                       <6 RK_PC3 1 &pcfg_pull_none_drv_8ma>;
                };
 
                sdmmc_clk: sdmmc-clk {
-                       rockchip,pins = <6 20 RK_FUNC_1 &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <6 RK_PC4 1 &pcfg_pull_none_drv_8ma>;
                };
 
                sdmmc_cmd: sdmmc-cmd {
-                       rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <6 RK_PC5 1 &pcfg_pull_none_drv_8ma>;
                };
 
                /*
                 * think there's a card inserted
                 */
                sdmmc_cd_disabled: sdmmc-cd-disabled {
-                       rockchip,pins = <6 22 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <6 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                /* This is where we actually hook up CD */
                sdmmc_cd_gpio: sdmmc-cd-gpio {
-                       rockchip,pins = <7 5 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index e16421d80d2280aeb2452168737550216753e7f3..2ac8748a3a0cc0fc22d33b40bc53f49cceecd730 100644 (file)
 &pinctrl {
        backlight {
                bl_pwr_en: bl_pwr_en {
-                       rockchip,pins = <2 12 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        buck-5v {
                drv_5v: drv-5v {
-                       rockchip,pins = <7 21 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        hdmi {
                vcc50_hdmi_en: vcc50-hdmi-en {
-                       rockchip,pins = <5 19 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <5 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        lcd {
                lcd_enable_h: lcd-en {
-                       rockchip,pins = <7 14 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                avdd_1v8_disp_en: avdd-1v8-disp-en {
-                       rockchip,pins = <2 13 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        pmic {
                dvs_1: dvs-1 {
-                       rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
                };
 
                dvs_2: dvs-2 {
-                       rockchip,pins = <7 15 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <7 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>;
                };
        };
 };
index 192dbc089ade1730b9dce6bca8d356f3b0c83a00..1252522392c73f475150061672cff5251773a4e5 100644 (file)
                pinctrl-0 = <&bt_enable_l>, <&wifi_enable_h>;
 
                /*
-                * On the module itself this is one of these (depending
-                * on the actual card populated):
+                * Depending on the actual card populated GPIO4 D4 and D5
+                * correspond to one of these signals on the module:
+                *
+                * D4:
                 * - SDIO_RESET_L_WL_REG_ON
                 * - PDN (power down when low)
+                *
+                * D5:
+                * - BT_I2S_WS_BT_RFDISABLE_L
+                * - No connect
                 */
-               reset-gpios = <&gpio4 RK_PD4 GPIO_ACTIVE_LOW>;
+               reset-gpios = <&gpio4 RK_PD4 GPIO_ACTIVE_LOW>,
+                             <&gpio4 RK_PD5 GPIO_ACTIVE_LOW>;
        };
 
        vcc_5v: vcc-5v {
                regulator-boot-on;
                vin-supply = <&vcc_5v>;
        };
+
+       vdd_logic: vdd-logic {
+               compatible = "pwm-regulator";
+               regulator-name = "vdd_logic";
+
+               pwms = <&pwm1 0 1994 0>;
+               pwm-supply = <&vcc33_sys>;
+
+               pwm-dutycycle-range = <0x7b 0>;
+               pwm-dutycycle-unit = <0x94>;
+
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <950000>;
+               regulator-max-microvolt = <1350000>;
+               regulator-ramp-delay = <4000>;
+       };
 };
 
 &cpu0 {
                                regulator-max-microvolt = <1250000>;
                                regulator-ramp-delay = <6001>;
                                regulator-state-mem {
-                                       regulator-on-in-suspend;
-                                       regulator-suspend-microvolt = <1000000>;
+                                       regulator-off-in-suspend;
                                };
                        };
 
 &uart0 {
        status = "okay";
 
-       /* We need to go faster than 24MHz, so adjust clock parents / rates */
-       assigned-clocks = <&cru SCLK_UART0>;
-       assigned-clock-rates = <48000000>;
-
        /* Pins don't include flow control by default; add that in */
        pinctrl-names = "default";
        pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <
                /* Common for sleep and wake, but no owners */
+               &ddr0_retention
+               &ddrio_pwroff
                &global_pwroff
        >;
        pinctrl-1 = <
                /* Common for sleep and wake, but no owners */
+               &ddr0_retention
+               &ddrio_pwroff
                &global_pwroff
        >;
 
 
        buttons {
                pwr_key_l: pwr-key-l {
-                       rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        emmc {
                emmc_reset: emmc-reset {
-                       rockchip,pins = <2 9 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                /*
                 * We also have external pulls, so disable the internal ones.
                 */
                emmc_clk: emmc-clk {
-                       rockchip,pins = <3 18 RK_FUNC_2 &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <3 RK_PC2 2 &pcfg_pull_none_drv_8ma>;
                };
 
                emmc_cmd: emmc-cmd {
-                       rockchip,pins = <3 16 RK_FUNC_2 &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <3 RK_PC0 2 &pcfg_pull_none_drv_8ma>;
                };
 
                emmc_bus8: emmc-bus8 {
-                       rockchip,pins = <3 0 RK_FUNC_2 &pcfg_pull_none_drv_8ma>,
-                                       <3 1 RK_FUNC_2 &pcfg_pull_none_drv_8ma>,
-                                       <3 2 RK_FUNC_2 &pcfg_pull_none_drv_8ma>,
-                                       <3 3 RK_FUNC_2 &pcfg_pull_none_drv_8ma>,
-                                       <3 4 RK_FUNC_2 &pcfg_pull_none_drv_8ma>,
-                                       <3 5 RK_FUNC_2 &pcfg_pull_none_drv_8ma>,
-                                       <3 6 RK_FUNC_2 &pcfg_pull_none_drv_8ma>,
-                                       <3 7 RK_FUNC_2 &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <3 RK_PA0 2 &pcfg_pull_none_drv_8ma>,
+                                       <3 RK_PA1 2 &pcfg_pull_none_drv_8ma>,
+                                       <3 RK_PA2 2 &pcfg_pull_none_drv_8ma>,
+                                       <3 RK_PA3 2 &pcfg_pull_none_drv_8ma>,
+                                       <3 RK_PA4 2 &pcfg_pull_none_drv_8ma>,
+                                       <3 RK_PA5 2 &pcfg_pull_none_drv_8ma>,
+                                       <3 RK_PA6 2 &pcfg_pull_none_drv_8ma>,
+                                       <3 RK_PA7 2 &pcfg_pull_none_drv_8ma>;
                };
        };
 
        pmic {
                pmic_int_l: pmic-int-l {
-                       rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        reboot {
                ap_warm_reset_h: ap-warm-reset-h {
-                       rockchip,pins = <RK_GPIO0 13 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        recovery-switch {
                rec_mode_l: rec-mode-l {
-                       rockchip,pins = <0 9 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        sdio0 {
                wifi_enable_h: wifienable-h {
-                       rockchip,pins = <4 28 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <4 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                /* NOTE: mislabelled on schematic; should be bt_enable_h */
                bt_enable_l: bt-enable-l {
-                       rockchip,pins = <4 29 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <4 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                /*
                 * We also have external pulls, so disable the internal ones.
                 */
                sdio0_bus4: sdio0-bus4 {
-                       rockchip,pins = <4 20 RK_FUNC_1 &pcfg_pull_none_drv_8ma>,
-                                       <4 21 RK_FUNC_1 &pcfg_pull_none_drv_8ma>,
-                                       <4 22 RK_FUNC_1 &pcfg_pull_none_drv_8ma>,
-                                       <4 23 RK_FUNC_1 &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <4 RK_PC4 1 &pcfg_pull_none_drv_8ma>,
+                                       <4 RK_PC5 1 &pcfg_pull_none_drv_8ma>,
+                                       <4 RK_PC6 1 &pcfg_pull_none_drv_8ma>,
+                                       <4 RK_PC7 1 &pcfg_pull_none_drv_8ma>;
                };
 
                sdio0_cmd: sdio0-cmd {
-                       rockchip,pins = <4 24 RK_FUNC_1 &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <4 RK_PD0 1 &pcfg_pull_none_drv_8ma>;
                };
 
                sdio0_clk: sdio0-clk {
-                       rockchip,pins = <4 25 RK_FUNC_1 &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <4 RK_PD1 1 &pcfg_pull_none_drv_8ma>;
                };
        };
 
        tpm {
                tpm_int_h: tpm-int-h {
-                       rockchip,pins = <7 4 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        write-protect {
                fw_wp_ap: fw-wp-ap {
-                       rockchip,pins = <7 6 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <7 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 40b232eb50116c81ff31540f1cd376f926ab0808..ba06e9f97ddce272ef0a6488e683310794ed3589 100644 (file)
 
        pmic {
                pmic_int: pmic-int {
-                       rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        usb_host {
                phy_pwr_en: phy-pwr-en {
-                       rockchip,pins = <RK_GPIO2 RK_PB1 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <2 RK_PB1 RK_FUNC_GPIO &pcfg_output_high>;
                };
 
                usb2_pwr_en: usb2-pwr-en {
 
        usb_otg {
                otg_vbus_drv: otg-vbus-drv {
-                       rockchip,pins = <RK_GPIO0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
 
                };
        };
index 8ce3dd2264b1506a1bd01a3c471256cbd6bc7c53..aa017abf4f42179b11ee02008b1ab24f2c2e3386 100644 (file)
@@ -64,6 +64,7 @@
                        #cooling-cells = <2>; /* min followed by max */
                        clock-latency = <40000>;
                        clocks = <&cru ARMCLK>;
+                       dynamic-power-coefficient = <370>;
                };
                cpu1: cpu@501 {
                        device_type = "cpu";
@@ -74,6 +75,7 @@
                        #cooling-cells = <2>; /* min followed by max */
                        clock-latency = <40000>;
                        clocks = <&cru ARMCLK>;
+                       dynamic-power-coefficient = <370>;
                };
                cpu2: cpu@502 {
                        device_type = "cpu";
@@ -84,6 +86,7 @@
                        #cooling-cells = <2>; /* min followed by max */
                        clock-latency = <40000>;
                        clocks = <&cru ARMCLK>;
+                       dynamic-power-coefficient = <370>;
                };
                cpu3: cpu@503 {
                        device_type = "cpu";
@@ -94,6 +97,7 @@
                        #cooling-cells = <2>; /* min followed by max */
                        clock-latency = <40000>;
                        clocks = <&cru ARMCLK>;
+                       dynamic-power-coefficient = <370>;
                };
        };
 
                pinctrl-1 = <&otp_out>;
                pinctrl-2 = <&otp_gpio>;
                #thermal-sensor-cells = <1>;
+               rockchip,grf = <&grf>;
                rockchip,hw-tshut-temp = <95000>;
                status = "disabled";
        };
                reg = <0x0 0xffaf0080 0x0 0x20>;
        };
 
-       gic: interrupt-controller@ffc01000 {
-               compatible = "arm,gic-400";
-               interrupt-controller;
-               #interrupt-cells = <3>;
-               #address-cells = <0>;
-
-               reg = <0x0 0xffc01000 0x0 0x1000>,
-                     <0x0 0xffc02000 0x0 0x2000>,
-                     <0x0 0xffc04000 0x0 0x2000>,
-                     <0x0 0xffc06000 0x0 0x2000>;
-               interrupts = <GIC_PPI 9 0xf04>;
-       };
-
        efuse: efuse@ffb40000 {
                compatible = "rockchip,rk3288-efuse";
                reg = <0x0 0xffb40000 0x0 0x20>;
                };
        };
 
+       gic: interrupt-controller@ffc01000 {
+               compatible = "arm,gic-400";
+               interrupt-controller;
+               #interrupt-cells = <3>;
+               #address-cells = <0>;
+
+               reg = <0x0 0xffc01000 0x0 0x1000>,
+                     <0x0 0xffc02000 0x0 0x2000>,
+                     <0x0 0xffc04000 0x0 0x2000>,
+                     <0x0 0xffc06000 0x0 0x2000>;
+               interrupts = <GIC_PPI 9 0xf04>;
+       };
+
        pinctrl: pinctrl {
                compatible = "rockchip,rk3288-pinctrl";
                rockchip,grf = <&grf>;
 
                hdmi {
                        hdmi_cec_c0: hdmi-cec-c0 {
-                               rockchip,pins = <7 RK_PC0 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <7 RK_PC0 2 &pcfg_pull_none>;
                        };
 
                        hdmi_cec_c7: hdmi-cec-c7 {
-                               rockchip,pins = <7 RK_PC7 RK_FUNC_4 &pcfg_pull_none>;
+                               rockchip,pins = <7 RK_PC7 4 &pcfg_pull_none>;
                        };
 
                        hdmi_ddc: hdmi-ddc {
-                               rockchip,pins = <7 19 RK_FUNC_2 &pcfg_pull_none>,
-                                               <7 20 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <7 RK_PC3 2 &pcfg_pull_none>,
+                                               <7 RK_PC4 2 &pcfg_pull_none>;
                        };
                };
 
 
                sleep {
                        global_pwroff: global-pwroff {
-                               rockchip,pins = <0 0 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA0 1 &pcfg_pull_none>;
                        };
 
                        ddrio_pwroff: ddrio-pwroff {
-                               rockchip,pins = <0 1 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA1 1 &pcfg_pull_none>;
                        };
 
                        ddr0_retention: ddr0-retention {
-                               rockchip,pins = <0 2 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PA2 1 &pcfg_pull_up>;
                        };
 
                        ddr1_retention: ddr1-retention {
-                               rockchip,pins = <0 3 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PA3 1 &pcfg_pull_up>;
                        };
                };
 
                edp {
                        edp_hpd: edp-hpd {
-                               rockchip,pins = <7 11 RK_FUNC_2 &pcfg_pull_down>;
+                               rockchip,pins = <7 RK_PB3 2 &pcfg_pull_down>;
                        };
                };
 
                i2c0 {
                        i2c0_xfer: i2c0-xfer {
-                               rockchip,pins = <0 15 RK_FUNC_1 &pcfg_pull_none>,
-                                               <0 16 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PB7 1 &pcfg_pull_none>,
+                                               <0 RK_PC0 1 &pcfg_pull_none>;
                        };
                };
 
                i2c1 {
                        i2c1_xfer: i2c1-xfer {
-                               rockchip,pins = <8 4 RK_FUNC_1 &pcfg_pull_none>,
-                                               <8 5 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <8 RK_PA4 1 &pcfg_pull_none>,
+                                               <8 RK_PA5 1 &pcfg_pull_none>;
                        };
                };
 
                i2c2 {
                        i2c2_xfer: i2c2-xfer {
-                               rockchip,pins = <6 9 RK_FUNC_1 &pcfg_pull_none>,
-                                               <6 10 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <6 RK_PB1 1 &pcfg_pull_none>,
+                                               <6 RK_PB2 1 &pcfg_pull_none>;
                        };
                };
 
                i2c3 {
                        i2c3_xfer: i2c3-xfer {
-                               rockchip,pins = <2 16 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 17 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PC0 1 &pcfg_pull_none>,
+                                               <2 RK_PC1 1 &pcfg_pull_none>;
                        };
                };
 
                i2c4 {
                        i2c4_xfer: i2c4-xfer {
-                               rockchip,pins = <7 17 RK_FUNC_1 &pcfg_pull_none>,
-                                               <7 18 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <7 RK_PC1 1 &pcfg_pull_none>,
+                                               <7 RK_PC2 1 &pcfg_pull_none>;
                        };
                };
 
                i2c5 {
                        i2c5_xfer: i2c5-xfer {
-                               rockchip,pins = <7 19 RK_FUNC_1 &pcfg_pull_none>,
-                                               <7 20 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <7 RK_PC3 1 &pcfg_pull_none>,
+                                               <7 RK_PC4 1 &pcfg_pull_none>;
                        };
                };
 
                i2s0 {
                        i2s0_bus: i2s0-bus {
-                               rockchip,pins = <6 0 RK_FUNC_1 &pcfg_pull_none>,
-                                               <6 1 RK_FUNC_1 &pcfg_pull_none>,
-                                               <6 2 RK_FUNC_1 &pcfg_pull_none>,
-                                               <6 3 RK_FUNC_1 &pcfg_pull_none>,
-                                               <6 4 RK_FUNC_1 &pcfg_pull_none>,
-                                               <6 8 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <6 RK_PA0 1 &pcfg_pull_none>,
+                                               <6 RK_PA1 1 &pcfg_pull_none>,
+                                               <6 RK_PA2 1 &pcfg_pull_none>,
+                                               <6 RK_PA3 1 &pcfg_pull_none>,
+                                               <6 RK_PA4 1 &pcfg_pull_none>,
+                                               <6 RK_PB0 1 &pcfg_pull_none>;
                        };
                };
 
                lcdc {
                        lcdc_ctl: lcdc-ctl {
-                               rockchip,pins = <1 24 RK_FUNC_1 &pcfg_pull_none>,
-                                               <1 25 RK_FUNC_1 &pcfg_pull_none>,
-                                               <1 26 RK_FUNC_1 &pcfg_pull_none>,
-                                               <1 27 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PD0 1 &pcfg_pull_none>,
+                                               <1 RK_PD1 1 &pcfg_pull_none>,
+                                               <1 RK_PD2 1 &pcfg_pull_none>,
+                                               <1 RK_PD3 1 &pcfg_pull_none>;
                        };
                };
 
                sdmmc {
                        sdmmc_clk: sdmmc-clk {
-                               rockchip,pins = <6 20 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <6 RK_PC4 1 &pcfg_pull_none>;
                        };
 
                        sdmmc_cmd: sdmmc-cmd {
-                               rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <6 RK_PC5 1 &pcfg_pull_up>;
                        };
 
                        sdmmc_cd: sdmmc-cd {
-                               rockchip,pins = <6 22 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <6 RK_PC6 1 &pcfg_pull_up>;
                        };
 
                        sdmmc_bus1: sdmmc-bus1 {
-                               rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <6 RK_PC0 1 &pcfg_pull_up>;
                        };
 
                        sdmmc_bus4: sdmmc-bus4 {
-                               rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_up>,
-                                               <6 17 RK_FUNC_1 &pcfg_pull_up>,
-                                               <6 18 RK_FUNC_1 &pcfg_pull_up>,
-                                               <6 19 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <6 RK_PC0 1 &pcfg_pull_up>,
+                                               <6 RK_PC1 1 &pcfg_pull_up>,
+                                               <6 RK_PC2 1 &pcfg_pull_up>,
+                                               <6 RK_PC3 1 &pcfg_pull_up>;
                        };
                };
 
                sdio0 {
                        sdio0_bus1: sdio0-bus1 {
-                               rockchip,pins = <4 20 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <4 RK_PC4 1 &pcfg_pull_up>;
                        };
 
                        sdio0_bus4: sdio0-bus4 {
-                               rockchip,pins = <4 20 RK_FUNC_1 &pcfg_pull_up>,
-                                               <4 21 RK_FUNC_1 &pcfg_pull_up>,
-                                               <4 22 RK_FUNC_1 &pcfg_pull_up>,
-                                               <4 23 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <4 RK_PC4 1 &pcfg_pull_up>,
+                                               <4 RK_PC5 1 &pcfg_pull_up>,
+                                               <4 RK_PC6 1 &pcfg_pull_up>,
+                                               <4 RK_PC7 1 &pcfg_pull_up>;
                        };
 
                        sdio0_cmd: sdio0-cmd {
-                               rockchip,pins = <4 24 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <4 RK_PD0 1 &pcfg_pull_up>;
                        };
 
                        sdio0_clk: sdio0-clk {
-                               rockchip,pins = <4 25 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <4 RK_PD1 1 &pcfg_pull_none>;
                        };
 
                        sdio0_cd: sdio0-cd {
-                               rockchip,pins = <4 26 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <4 RK_PD2 1 &pcfg_pull_up>;
                        };
 
                        sdio0_wp: sdio0-wp {
-                               rockchip,pins = <4 27 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <4 RK_PD3 1 &pcfg_pull_up>;
                        };
 
                        sdio0_pwr: sdio0-pwr {
-                               rockchip,pins = <4 28 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <4 RK_PD4 1 &pcfg_pull_up>;
                        };
 
                        sdio0_bkpwr: sdio0-bkpwr {
-                               rockchip,pins = <4 29 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <4 RK_PD5 1 &pcfg_pull_up>;
                        };
 
                        sdio0_int: sdio0-int {
-                               rockchip,pins = <4 30 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <4 RK_PD6 1 &pcfg_pull_up>;
                        };
                };
 
                sdio1 {
                        sdio1_bus1: sdio1-bus1 {
-                               rockchip,pins = <3 24 4 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PD0 4 &pcfg_pull_up>;
                        };
 
                        sdio1_bus4: sdio1-bus4 {
-                               rockchip,pins = <3 24 4 &pcfg_pull_up>,
-                                               <3 25 4 &pcfg_pull_up>,
-                                               <3 26 4 &pcfg_pull_up>,
-                                               <3 27 4 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PD0 4 &pcfg_pull_up>,
+                                               <3 RK_PD1 4 &pcfg_pull_up>,
+                                               <3 RK_PD2 4 &pcfg_pull_up>,
+                                               <3 RK_PD3 4 &pcfg_pull_up>;
                        };
 
                        sdio1_cd: sdio1-cd {
-                               rockchip,pins = <3 28 4 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PD4 4 &pcfg_pull_up>;
                        };
 
                        sdio1_wp: sdio1-wp {
-                               rockchip,pins = <3 29 4 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PD5 4 &pcfg_pull_up>;
                        };
 
                        sdio1_bkpwr: sdio1-bkpwr {
-                               rockchip,pins = <3 30 4 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PD6 4 &pcfg_pull_up>;
                        };
 
                        sdio1_int: sdio1-int {
-                               rockchip,pins = <3 31 4 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PD7 4 &pcfg_pull_up>;
                        };
 
                        sdio1_cmd: sdio1-cmd {
-                               rockchip,pins = <4 6 4 &pcfg_pull_up>;
+                               rockchip,pins = <4 RK_PA6 4 &pcfg_pull_up>;
                        };
 
                        sdio1_clk: sdio1-clk {
-                               rockchip,pins = <4 7 4 &pcfg_pull_none>;
+                               rockchip,pins = <4 RK_PA7 4 &pcfg_pull_none>;
                        };
 
                        sdio1_pwr: sdio1-pwr {
-                               rockchip,pins = <4 9 4 &pcfg_pull_up>;
+                               rockchip,pins = <4 RK_PB1 4 &pcfg_pull_up>;
                        };
                };
 
                emmc {
                        emmc_clk: emmc-clk {
-                               rockchip,pins = <3 18 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PC2 2 &pcfg_pull_none>;
                        };
 
                        emmc_cmd: emmc-cmd {
-                               rockchip,pins = <3 16 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PC0 2 &pcfg_pull_up>;
                        };
 
                        emmc_pwr: emmc-pwr {
-                               rockchip,pins = <3 9 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PB1 2 &pcfg_pull_up>;
                        };
 
                        emmc_bus1: emmc-bus1 {
-                               rockchip,pins = <3 0 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PA0 2 &pcfg_pull_up>;
                        };
 
                        emmc_bus4: emmc-bus4 {
-                               rockchip,pins = <3 0 RK_FUNC_2 &pcfg_pull_up>,
-                                               <3 1 RK_FUNC_2 &pcfg_pull_up>,
-                                               <3 2 RK_FUNC_2 &pcfg_pull_up>,
-                                               <3 3 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PA0 2 &pcfg_pull_up>,
+                                               <3 RK_PA1 2 &pcfg_pull_up>,
+                                               <3 RK_PA2 2 &pcfg_pull_up>,
+                                               <3 RK_PA3 2 &pcfg_pull_up>;
                        };
 
                        emmc_bus8: emmc-bus8 {
-                               rockchip,pins = <3 0 RK_FUNC_2 &pcfg_pull_up>,
-                                               <3 1 RK_FUNC_2 &pcfg_pull_up>,
-                                               <3 2 RK_FUNC_2 &pcfg_pull_up>,
-                                               <3 3 RK_FUNC_2 &pcfg_pull_up>,
-                                               <3 4 RK_FUNC_2 &pcfg_pull_up>,
-                                               <3 5 RK_FUNC_2 &pcfg_pull_up>,
-                                               <3 6 RK_FUNC_2 &pcfg_pull_up>,
-                                               <3 7 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PA0 2 &pcfg_pull_up>,
+                                               <3 RK_PA1 2 &pcfg_pull_up>,
+                                               <3 RK_PA2 2 &pcfg_pull_up>,
+                                               <3 RK_PA3 2 &pcfg_pull_up>,
+                                               <3 RK_PA4 2 &pcfg_pull_up>,
+                                               <3 RK_PA5 2 &pcfg_pull_up>,
+                                               <3 RK_PA6 2 &pcfg_pull_up>,
+                                               <3 RK_PA7 2 &pcfg_pull_up>;
                        };
                };
 
                spi0 {
                        spi0_clk: spi0-clk {
-                               rockchip,pins = <5 12 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <5 RK_PB4 1 &pcfg_pull_up>;
                        };
                        spi0_cs0: spi0-cs0 {
-                               rockchip,pins = <5 13 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <5 RK_PB5 1 &pcfg_pull_up>;
                        };
                        spi0_tx: spi0-tx {
-                               rockchip,pins = <5 14 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <5 RK_PB6 1 &pcfg_pull_up>;
                        };
                        spi0_rx: spi0-rx {
-                               rockchip,pins = <5 15 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <5 RK_PB7 1 &pcfg_pull_up>;
                        };
                        spi0_cs1: spi0-cs1 {
-                               rockchip,pins = <5 16 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <5 RK_PC0 1 &pcfg_pull_up>;
                        };
                };
                spi1 {
                        spi1_clk: spi1-clk {
-                               rockchip,pins = <7 12 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <7 RK_PB4 2 &pcfg_pull_up>;
                        };
                        spi1_cs0: spi1-cs0 {
-                               rockchip,pins = <7 13 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <7 RK_PB5 2 &pcfg_pull_up>;
                        };
                        spi1_rx: spi1-rx {
-                               rockchip,pins = <7 14 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <7 RK_PB6 2 &pcfg_pull_up>;
                        };
                        spi1_tx: spi1-tx {
-                               rockchip,pins = <7 15 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <7 RK_PB7 2 &pcfg_pull_up>;
                        };
                };
 
                spi2 {
                        spi2_cs1: spi2-cs1 {
-                               rockchip,pins = <8 3 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <8 RK_PA3 1 &pcfg_pull_up>;
                        };
                        spi2_clk: spi2-clk {
-                               rockchip,pins = <8 6 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <8 RK_PA6 1 &pcfg_pull_up>;
                        };
                        spi2_cs0: spi2-cs0 {
-                               rockchip,pins = <8 7 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <8 RK_PA7 1 &pcfg_pull_up>;
                        };
                        spi2_rx: spi2-rx {
-                               rockchip,pins = <8 8 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <8 RK_PB0 1 &pcfg_pull_up>;
                        };
                        spi2_tx: spi2-tx {
-                               rockchip,pins = <8 9 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <8 RK_PB1 1 &pcfg_pull_up>;
                        };
                };
 
                uart0 {
                        uart0_xfer: uart0-xfer {
-                               rockchip,pins = <4 16 RK_FUNC_1 &pcfg_pull_up>,
-                                               <4 17 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <4 RK_PC0 1 &pcfg_pull_up>,
+                                               <4 RK_PC1 1 &pcfg_pull_none>;
                        };
 
                        uart0_cts: uart0-cts {
-                               rockchip,pins = <4 18 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <4 RK_PC2 1 &pcfg_pull_up>;
                        };
 
                        uart0_rts: uart0-rts {
-                               rockchip,pins = <4 19 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <4 RK_PC3 1 &pcfg_pull_none>;
                        };
                };
 
                uart1 {
                        uart1_xfer: uart1-xfer {
-                               rockchip,pins = <5 8 RK_FUNC_1 &pcfg_pull_up>,
-                                               <5 9 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <5 RK_PB0 1 &pcfg_pull_up>,
+                                               <5 RK_PB1 1 &pcfg_pull_none>;
                        };
 
                        uart1_cts: uart1-cts {
-                               rockchip,pins = <5 10 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <5 RK_PB2 1 &pcfg_pull_up>;
                        };
 
                        uart1_rts: uart1-rts {
-                               rockchip,pins = <5 11 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <5 RK_PB3 1 &pcfg_pull_none>;
                        };
                };
 
                uart2 {
                        uart2_xfer: uart2-xfer {
-                               rockchip,pins = <7 22 RK_FUNC_1 &pcfg_pull_up>,
-                                               <7 23 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <7 RK_PC6 1 &pcfg_pull_up>,
+                                               <7 RK_PC7 1 &pcfg_pull_none>;
                        };
                        /* no rts / cts for uart2 */
                };
 
                uart3 {
                        uart3_xfer: uart3-xfer {
-                               rockchip,pins = <7 7 RK_FUNC_1 &pcfg_pull_up>,
-                                               <7 8 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <7 RK_PA7 1 &pcfg_pull_up>,
+                                               <7 RK_PB0 1 &pcfg_pull_none>;
                        };
 
                        uart3_cts: uart3-cts {
-                               rockchip,pins = <7 9 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <7 RK_PB1 1 &pcfg_pull_up>;
                        };
 
                        uart3_rts: uart3-rts {
-                               rockchip,pins = <7 10 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <7 RK_PB2 1 &pcfg_pull_none>;
                        };
                };
 
                uart4 {
                        uart4_xfer: uart4-xfer {
-                               rockchip,pins = <5 15 3 &pcfg_pull_up>,
-                                               <5 14 3 &pcfg_pull_none>;
+                               rockchip,pins = <5 RK_PB7 3 &pcfg_pull_up>,
+                                               <5 RK_PB6 3 &pcfg_pull_none>;
                        };
 
                        uart4_cts: uart4-cts {
-                               rockchip,pins = <5 12 3 &pcfg_pull_up>;
+                               rockchip,pins = <5 RK_PB4 3 &pcfg_pull_up>;
                        };
 
                        uart4_rts: uart4-rts {
-                               rockchip,pins = <5 13 3 &pcfg_pull_none>;
+                               rockchip,pins = <5 RK_PB5 3 &pcfg_pull_none>;
                        };
                };
 
                tsadc {
                        otp_gpio: otp-gpio {
-                               rockchip,pins = <0 10 RK_FUNC_GPIO &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
                        };
 
                        otp_out: otp-out {
-                               rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PB2 1 &pcfg_pull_none>;
                        };
                };
 
                pwm0 {
                        pwm0_pin: pwm0-pin {
-                               rockchip,pins = <7 0 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <7 RK_PA0 1 &pcfg_pull_none>;
                        };
                };
 
                pwm1 {
                        pwm1_pin: pwm1-pin {
-                               rockchip,pins = <7 1 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <7 RK_PA1 1 &pcfg_pull_none>;
                        };
                };
 
                pwm2 {
                        pwm2_pin: pwm2-pin {
-                               rockchip,pins = <7 22 3 &pcfg_pull_none>;
+                               rockchip,pins = <7 RK_PC6 3 &pcfg_pull_none>;
                        };
                };
 
                pwm3 {
                        pwm3_pin: pwm3-pin {
-                               rockchip,pins = <7 23 3 &pcfg_pull_none>;
+                               rockchip,pins = <7 RK_PC7 3 &pcfg_pull_none>;
                        };
                };
 
                gmac {
                        rgmii_pins: rgmii-pins {
-                               rockchip,pins = <3 30 3 &pcfg_pull_none>,
-                                               <3 31 3 &pcfg_pull_none>,
-                                               <3 26 3 &pcfg_pull_none>,
-                                               <3 27 3 &pcfg_pull_none>,
-                                               <3 28 3 &pcfg_pull_none_12ma>,
-                                               <3 29 3 &pcfg_pull_none_12ma>,
-                                               <3 24 3 &pcfg_pull_none_12ma>,
-                                               <3 25 3 &pcfg_pull_none_12ma>,
-                                               <4 0 3 &pcfg_pull_none>,
-                                               <4 5 3 &pcfg_pull_none>,
-                                               <4 6 3 &pcfg_pull_none>,
-                                               <4 9 3 &pcfg_pull_none_12ma>,
-                                               <4 4 3 &pcfg_pull_none_12ma>,
-                                               <4 1 3 &pcfg_pull_none>,
-                                               <4 3 3 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PD6 3 &pcfg_pull_none>,
+                                               <3 RK_PD7 3 &pcfg_pull_none>,
+                                               <3 RK_PD2 3 &pcfg_pull_none>,
+                                               <3 RK_PD3 3 &pcfg_pull_none>,
+                                               <3 RK_PD4 3 &pcfg_pull_none_12ma>,
+                                               <3 RK_PD5 3 &pcfg_pull_none_12ma>,
+                                               <3 RK_PD0 3 &pcfg_pull_none_12ma>,
+                                               <3 RK_PD1 3 &pcfg_pull_none_12ma>,
+                                               <4 RK_PA0 3 &pcfg_pull_none>,
+                                               <4 RK_PA5 3 &pcfg_pull_none>,
+                                               <4 RK_PA6 3 &pcfg_pull_none>,
+                                               <4 RK_PB1 3 &pcfg_pull_none_12ma>,
+                                               <4 RK_PA4 3 &pcfg_pull_none_12ma>,
+                                               <4 RK_PA1 3 &pcfg_pull_none>,
+                                               <4 RK_PA3 3 &pcfg_pull_none>;
                        };
 
                        rmii_pins: rmii-pins {
-                               rockchip,pins = <3 30 3 &pcfg_pull_none>,
-                                               <3 31 3 &pcfg_pull_none>,
-                                               <3 28 3 &pcfg_pull_none>,
-                                               <3 29 3 &pcfg_pull_none>,
-                                               <4 0 3 &pcfg_pull_none>,
-                                               <4 5 3 &pcfg_pull_none>,
-                                               <4 4 3 &pcfg_pull_none>,
-                                               <4 1 3 &pcfg_pull_none>,
-                                               <4 2 3 &pcfg_pull_none>,
-                                               <4 3 3 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PD6 3 &pcfg_pull_none>,
+                                               <3 RK_PD7 3 &pcfg_pull_none>,
+                                               <3 RK_PD4 3 &pcfg_pull_none>,
+                                               <3 RK_PD5 3 &pcfg_pull_none>,
+                                               <4 RK_PA0 3 &pcfg_pull_none>,
+                                               <4 RK_PA5 3 &pcfg_pull_none>,
+                                               <4 RK_PA4 3 &pcfg_pull_none>,
+                                               <4 RK_PA1 3 &pcfg_pull_none>,
+                                               <4 RK_PA2 3 &pcfg_pull_none>,
+                                               <4 RK_PA3 3 &pcfg_pull_none>;
                        };
                };
 
                spdif {
                        spdif_tx: spdif-tx {
-                               rockchip,pins = <RK_GPIO6 11 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <6 RK_PB3 1 &pcfg_pull_none>;
                        };
                };
        };
index 1c4507b66fdd4c3a536d8e0e3d90762bcc487e3e..b1db924710c80e1dcdd1d20f33fc5fcb0f0e1d8d 100644 (file)
@@ -37,7 +37,6 @@
 &emmc {
        bus-width = <8>;
        cap-mmc-highspeed;
-       disable-wp;
        no-sd;
        no-sdio;
        non-removable;
index f47ac86d2852aa57567bfa790db0bac7e17d0833..5876690ee09e794a323897b7ec78beffa9f6623c 100644 (file)
 
                emmc {
                        emmc_bus8: emmc-bus8 {
-                               rockchip,pins = <2 RK_PA0 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                               <2 RK_PA1 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                               <2 RK_PA2 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                               <2 RK_PA3 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                               <2 RK_PA4 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                               <2 RK_PA5 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                               <2 RK_PA6 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                               <2 RK_PA7 RK_FUNC_2 &pcfg_pull_up_drv_8ma>;
+                               rockchip,pins = <2 RK_PA0 2 &pcfg_pull_up_drv_8ma>,
+                                               <2 RK_PA1 2 &pcfg_pull_up_drv_8ma>,
+                                               <2 RK_PA2 2 &pcfg_pull_up_drv_8ma>,
+                                               <2 RK_PA3 2 &pcfg_pull_up_drv_8ma>,
+                                               <2 RK_PA4 2 &pcfg_pull_up_drv_8ma>,
+                                               <2 RK_PA5 2 &pcfg_pull_up_drv_8ma>,
+                                               <2 RK_PA6 2 &pcfg_pull_up_drv_8ma>,
+                                               <2 RK_PA7 2 &pcfg_pull_up_drv_8ma>;
                        };
 
                        emmc_clk: emmc-clk {
-                               rockchip,pins = <2 RK_PB6 RK_FUNC_1 &pcfg_pull_none_drv_8ma>;
+                               rockchip,pins = <2 RK_PB6 1 &pcfg_pull_none_drv_8ma>;
                        };
 
                        emmc_cmd: emmc-cmd {
-                               rockchip,pins = <2 RK_PB4 RK_FUNC_2 &pcfg_pull_up_drv_8ma>;
+                               rockchip,pins = <2 RK_PB4 2 &pcfg_pull_up_drv_8ma>;
                        };
                };
 
                gmac {
                        rmii_pins: rmii-pins {
-                               rockchip,pins = <1 RK_PC5 RK_FUNC_2 &pcfg_pull_none>,
-                                               <1 RK_PC3 RK_FUNC_2 &pcfg_pull_none>,
-                                               <1 RK_PC4 RK_FUNC_2 &pcfg_pull_none>,
-                                               <1 RK_PB2 RK_FUNC_3 &pcfg_pull_none_drv_12ma>,
-                                               <1 RK_PB3 RK_FUNC_3 &pcfg_pull_none_drv_12ma>,
-                                               <1 RK_PB4 RK_FUNC_3 &pcfg_pull_none_drv_12ma>,
-                                               <1 RK_PB5 RK_FUNC_3 &pcfg_pull_none>,
-                                               <1 RK_PB6 RK_FUNC_3 &pcfg_pull_none>,
-                                               <1 RK_PB7 RK_FUNC_3 &pcfg_pull_none>,
-                                               <1 RK_PC2 RK_FUNC_3 &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>,
+                                               <1 RK_PB3 3 &pcfg_pull_none_drv_12ma>,
+                                               <1 RK_PB4 3 &pcfg_pull_none_drv_12ma>,
+                                               <1 RK_PB5 3 &pcfg_pull_none>,
+                                               <1 RK_PB6 3 &pcfg_pull_none>,
+                                               <1 RK_PB7 3 &pcfg_pull_none>,
+                                               <1 RK_PC2 3 &pcfg_pull_none>;
                        };
                };
 
                i2c0 {
                        i2c0_xfer: i2c0-xfer {
-                               rockchip,pins = <0 RK_PB1 RK_FUNC_1 &pcfg_pull_none_smt>,
-                                               <0 RK_PB2 RK_FUNC_1 &pcfg_pull_none_smt>;
+                               rockchip,pins = <0 RK_PB1 1 &pcfg_pull_none_smt>,
+                                               <0 RK_PB2 1 &pcfg_pull_none_smt>;
                        };
                };
 
                i2c1 {
                        i2c1_xfer: i2c1-xfer {
-                               rockchip,pins = <2 RK_PD3 RK_FUNC_1 &pcfg_pull_up>,
-                                               <2 RK_PD4 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <2 RK_PD3 1 &pcfg_pull_up>,
+                                               <2 RK_PD4 1 &pcfg_pull_up>;
                        };
                };
 
                i2c2m1 {
                        i2c2m1_xfer: i2c2m1-xfer {
-                               rockchip,pins = <0 RK_PC2 RK_FUNC_2 &pcfg_pull_none>,
-                                               <0 RK_PC6 RK_FUNC_3 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PC2 2 &pcfg_pull_none>,
+                                               <0 RK_PC6 3 &pcfg_pull_none>;
                        };
 
                        i2c2m1_gpio: i2c2m1-gpio {
 
                i2c2m05v {
                        i2c2m05v_xfer: i2c2m05v-xfer {
-                               rockchip,pins = <1 RK_PD5 RK_FUNC_2 &pcfg_pull_none>,
-                                               <1 RK_PD4 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PD5 2 &pcfg_pull_none>,
+                                               <1 RK_PD4 2 &pcfg_pull_none>;
                        };
 
                        i2c2m05v_gpio: i2c2m05v-gpio {
 
                i2c3 {
                        i2c3_xfer: i2c3-xfer {
-                               rockchip,pins = <0 RK_PB6 RK_FUNC_1 &pcfg_pull_none>,
-                                               <0 RK_PC4 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PB6 1 &pcfg_pull_none>,
+                                               <0 RK_PC4 2 &pcfg_pull_none>;
                        };
                };
 
                pwm0 {
                        pwm0_pin: pwm0-pin {
-                               rockchip,pins = <0 RK_PC5 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PC5 1 &pcfg_pull_none>;
                        };
                };
 
                pwm1 {
                        pwm1_pin: pwm1-pin {
-                               rockchip,pins = <0 RK_PC4 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PC4 1 &pcfg_pull_none>;
                        };
                };
 
                pwm2 {
                        pwm2_pin: pwm2-pin {
-                               rockchip,pins = <0 RK_PC6 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PC6 1 &pcfg_pull_none>;
                        };
                };
 
                pwm3 {
                        pwm3_pin: pwm3-pin {
-                               rockchip,pins = <0 RK_PC0 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PC0 1 &pcfg_pull_none>;
                        };
                };
 
                pwm4 {
                        pwm4_pin: pwm4-pin {
-                               rockchip,pins = <1 RK_PC1 RK_FUNC_3 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PC1 3 &pcfg_pull_none>;
                        };
                };
 
                pwm5 {
                        pwm5_pin: pwm5-pin {
-                               rockchip,pins = <1 RK_PA7 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PA7 2 &pcfg_pull_none>;
                        };
                };
 
                pwm6 {
                        pwm6_pin: pwm6-pin {
-                               rockchip,pins = <1 RK_PB0 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PB0 2 &pcfg_pull_none>;
                        };
                };
 
                pwm7 {
                        pwm7_pin: pwm7-pin {
-                               rockchip,pins = <1 RK_PB1 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PB1 2 &pcfg_pull_none>;
                        };
                };
 
                sdmmc {
                        sdmmc_clk: sdmmc-clk {
-                               rockchip,pins = <3 RK_PC4 RK_FUNC_1 &pcfg_pull_none_drv_4ma>;
+                               rockchip,pins = <3 RK_PC4 1 &pcfg_pull_none_drv_4ma>;
                        };
 
                        sdmmc_cmd: sdmmc-cmd {
-                               rockchip,pins = <3 RK_PC5 RK_FUNC_1 &pcfg_pull_up_drv_4ma>;
+                               rockchip,pins = <3 RK_PC5 1 &pcfg_pull_up_drv_4ma>;
                        };
 
                        sdmmc_cd: sdmmc-cd {
-                               rockchip,pins = <0 RK_PA1 RK_FUNC_1 &pcfg_pull_up_drv_4ma>;
+                               rockchip,pins = <0 RK_PA1 1 &pcfg_pull_up_drv_4ma>;
                        };
 
                        sdmmc_bus1: sdmmc-bus1 {
-                               rockchip,pins = <3 RK_PC3 RK_FUNC_1 &pcfg_pull_up_drv_4ma>;
+                               rockchip,pins = <3 RK_PC3 1 &pcfg_pull_up_drv_4ma>;
                        };
 
                        sdmmc_bus4: sdmmc-bus4 {
-                               rockchip,pins = <3 RK_PC3 RK_FUNC_1 &pcfg_pull_up_drv_4ma>,
-                                               <3 RK_PC2 RK_FUNC_1 &pcfg_pull_up_drv_4ma>,
-                                               <3 RK_PC1 RK_FUNC_1 &pcfg_pull_up_drv_4ma>,
-                                               <3 RK_PC0 RK_FUNC_1 &pcfg_pull_up_drv_4ma>;
+                               rockchip,pins = <3 RK_PC3 1 &pcfg_pull_up_drv_4ma>,
+                                               <3 RK_PC2 1 &pcfg_pull_up_drv_4ma>,
+                                               <3 RK_PC1 1 &pcfg_pull_up_drv_4ma>,
+                                               <3 RK_PC0 1 &pcfg_pull_up_drv_4ma>;
                        };
                };
 
                spim0 {
                        spim0_clk: spim0-clk {
-                               rockchip,pins = <1 RK_PD0 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PD0 2 &pcfg_pull_up>;
                        };
 
                        spim0_cs0: spim0-cs0 {
-                               rockchip,pins = <1 RK_PD1 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PD1 2 &pcfg_pull_up>;
                        };
 
                        spim0_tx: spim0-tx {
-                               rockchip,pins = <1 RK_PD3 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PD3 2 &pcfg_pull_up>;
                        };
 
                        spim0_rx: spim0-rx {
-                               rockchip,pins = <1 RK_PD2 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PD2 2 &pcfg_pull_up>;
                        };
                };
 
                spim1 {
                        spim1_clk: spim1-clk {
-                               rockchip,pins = <0 RK_PA3 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PA3 1 &pcfg_pull_up>;
                        };
 
                        spim1_cs0: spim1-cs0 {
-                               rockchip,pins = <0 RK_PA4 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PA4 1 &pcfg_pull_up>;
                        };
 
                        spim1_rx: spim1-rx {
-                               rockchip,pins = <0 RK_PB0 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PB0 1 &pcfg_pull_up>;
                        };
 
                        spim1_tx: spim1-tx {
-                               rockchip,pins = <0 RK_PA7 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PA7 1 &pcfg_pull_up>;
                        };
                };
 
                tsadc {
                        otp_out: otp-out {
-                               rockchip,pins = <0 RK_PB7 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PB7 1 &pcfg_pull_none>;
                        };
 
                        otp_gpio: otp-gpio {
 
                uart0 {
                        uart0_xfer: uart0-xfer {
-                               rockchip,pins = <3 RK_PA6 RK_FUNC_1 &pcfg_pull_up>,
-                                               <3 RK_PA5 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PA6 1 &pcfg_pull_up>,
+                                               <3 RK_PA5 1 &pcfg_pull_none>;
                        };
 
                        uart0_cts: uart0-cts {
-                               rockchip,pins = <3 RK_PA4 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PA4 1 &pcfg_pull_none>;
                        };
 
                        uart0_rts: uart0-rts {
-                               rockchip,pins = <3 RK_PA3 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PA3 1 &pcfg_pull_none>;
                        };
 
                        uart0_rts_gpio: uart0-rts-gpio {
 
                uart1 {
                        uart1_xfer: uart1-xfer {
-                               rockchip,pins = <1 RK_PD3 RK_FUNC_1 &pcfg_pull_up>,
-                                               <1 RK_PD2 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PD3 1 &pcfg_pull_up>,
+                                               <1 RK_PD2 1 &pcfg_pull_none>;
                        };
 
                        uart1_cts: uart1-cts {
-                               rockchip,pins = <1 RK_PD0 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PD0 1 &pcfg_pull_none>;
                        };
 
                        uart1_rts: uart1-rts {
-                               rockchip,pins = <1 RK_PD1 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PD1 1 &pcfg_pull_none>;
                        };
                };
 
                uart2m0 {
                        uart2m0_xfer: uart2m0-xfer {
-                               rockchip,pins = <2 RK_PD2 RK_FUNC_1 &pcfg_pull_up>,
-                                               <2 RK_PD1 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PD2 1 &pcfg_pull_up>,
+                                               <2 RK_PD1 1 &pcfg_pull_none>;
                        };
                };
 
                uart2m1 {
                        uart2m1_xfer: uart2m1-xfer {
-                               rockchip,pins = <3 RK_PC3 RK_FUNC_2 &pcfg_pull_up>,
-                                               <3 RK_PC2 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PC3 2 &pcfg_pull_up>,
+                                               <3 RK_PC2 2 &pcfg_pull_none>;
                        };
                };
 
                uart2_5v {
                        uart2_5v_cts: uart2_5v-cts {
-                               rockchip,pins = <1 RK_PD4 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PD4 1 &pcfg_pull_none>;
                        };
 
                        uart2_5v_rts: uart2_5v-rts {
-                               rockchip,pins = <1 RK_PD5 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PD5 1 &pcfg_pull_none>;
                        };
                };
        };
index eb6d1926c0d6640ada53f0d2617b51a166a885ab..fbbd9370740478ee5279dae5763b88efea27fa78 100644 (file)
                vdd_core-supply = <&ldo14_reg>;
 
                clock-frequency = <16000000>;
-               clocks = <&clock_cam 0>;
+               clocks = <&camera 0>;
                clock-names = "mclk";
                nreset-gpios = <&gpb 2 0>;
                nstby-gpios = <&gpb 0 0>;
index a44d5eb56bedf4876f72c1a12148b5557066d721..2ad642f51fd92c1f549f77a12a3fec944e1f7496 100644 (file)
                        clock-names = "sclk_cam0", "sclk_cam1";
                        #address-cells = <1>;
                        #size-cells = <1>;
+                       #clock-cells = <1>;
+                       clock-output-names = "cam_a_clkout", "cam_b_clkout";
                        ranges;
 
-                       clock_cam: clock-controller {
-                               #clock-cells = <1>;
-                       };
-
                        csis0: csis@fa600000 {
                                compatible = "samsung,s5pv210-csis";
                                reg = <0xfa600000 0x4000>;
index d159ee42ef294e2b978c2d7ccea7274141f225c5..2e2c1a7b1d1dc25f20831f9d1e06258f1fb1efe3 100644 (file)
@@ -1,46 +1,9 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * sama5d2.dtsi - Device Tree Include file for SAMA5D2 family SoC
  *
  *  Copyright (C) 2015 Atmel,
  *                2015 Ludovic Desroches <ludovic.desroches@atmel.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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 file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 
 #include <dt-bindings/dma/at91.h>
                                ranges = <0 0xf8044000 0x1420>;
                        };
 
-                       rstc@f8048000 {
+                       reset_controller: rstc@f8048000 {
                                compatible = "atmel,sama5d3-rstc";
                                reg = <0xf8048000 0x10>;
                                clocks = <&clk32k>;
                        };
 
-                       shdwc@f8048010 {
+                       shutdown_controller: shdwc@f8048010 {
                                compatible = "atmel,sama5d2-shdwc";
                                reg = <0xf8048010 0x10>;
                                clocks = <&clk32k>;
                                clocks = <&pmc PMC_TYPE_CORE PMC_MCK2>;
                        };
 
-                       watchdog@f8048040 {
+                       watchdog: watchdog@f8048040 {
                                compatible = "atmel,sama5d4-wdt";
                                reg = <0xf8048040 0x10>;
                                interrupts = <4 IRQ_TYPE_LEVEL_HIGH 7>;
index b632143844e5ab11200b4625d13ffc8fb520901c..66695b9a3e770241489657c5bff5225c81571adf 100644 (file)
@@ -1,45 +1,8 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * sama5d36ek_cmp.dts - Device Tree file for SAMA5D36-EK CMP board
  *
  *  Copyright (C) 2016 Atmel,
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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 file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 /dts-v1/;
 #include "sama5d36.dtsi"
index a02f59021364e59721088f6e57ff82d522898423..9d2563602cbecad654c8b7a7541db44990c90b4d 100644 (file)
@@ -1,45 +1,8 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * sama5d3xcm_cmp.dtsi - Device Tree Include file for SAMA5D36 CMP CPU Module
  *
  *  Copyright (C) 2016 Atmel,
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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 file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 
 / {
index 97e171db597006926e24d4d756691d6249c6f06c..8a6916a69da483884c133f5e190104f89909f261 100644 (file)
@@ -1,45 +1,8 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * sama5d3xmb_cmp.dts - Device Tree file for SAMA5D3x CMP mother board
  *
  *  Copyright (C) 2016 Atmel,
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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 file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 #include "sama5d3xcm_cmp.dtsi"
 
index 6c1e41f94549cab3cae29bb8f0a2d8b593eb6aee..6ab27a7b388d48cbf8279a3570753df5b09426a8 100644 (file)
@@ -1,46 +1,9 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * sama5d4.dtsi - Device Tree Include file for SAMA5D4 family SoC
  *
  *  Copyright (C) 2014 Atmel,
  *                2014 Nicolas Ferre <nicolas.ferre@atmel.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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 file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 
 #include <dt-bindings/clock/at91.h>
index df2bab1624d4013ff8e8849227438eb69bac7381..64dc0799f3d763f7bee548b644b841acc7ca2aa0 100644 (file)
@@ -9,6 +9,7 @@
 &mmc {
        status = "okay";
        cap-sd-highspeed;
+       cap-mmc-highspeed;
        broken-cd;
        bus-width = <4>;
 };
index e6ed7c0354a233cdba3f8449582a3e1fe647cadd..81fabf031effdca9424239be77bcea575854d25c 100644 (file)
                        status = "disabled";
                };
 
+               gpu@a0300000 {
+                       /*
+                        * This block is referred to as "Smart Graphics Adapter SGA500"
+                        * in documentation but is in practice a pretty straight-forward
+                        * MALI-400 GPU block.
+                        */
+                       compatible = "stericsson,db8500-mali", "arm,mali-400";
+                       reg = <0xa0300000 0x10000>;
+                       interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "gp",
+                                         "gpmmu",
+                                         "pp0",
+                                         "ppmmu0",
+                                         "combined";
+                       clocks = <&prcmu_clk PRCMU_ACLK>, <&prcmu_clk PRCMU_SGACLK>;
+                       clock-names = "bus", "core";
+                       mali-supply = <&db8500_sga_reg>;
+                       power-domains = <&pm_domains DOMAIN_VAPE>;
+               };
+
                mcde@a0350000 {
-                       compatible = "stericsson,mcde";
-                       reg = <0xa0350000 0x1000>, /* MCDE */
-                             <0xa0351000 0x1000>, /* DSI link 1 */
-                             <0xa0352000 0x1000>, /* DSI link 2 */
-                             <0xa0353000 0x1000>; /* DSI link 3 */
+                       compatible = "ste,mcde";
+                       reg = <0xa0350000 0x1000>;
                        interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+                       epod-supply = <&db8500_b2r2_mcde_reg>;
+                       vana-supply = <&ab8500_ldo_ana_reg>;
                        clocks = <&prcmu_clk PRCMU_MCDECLK>, /* Main MCDE clock */
                                 <&prcmu_clk PRCMU_LCDCLK>, /* LCD clock */
-                                <&prcmu_clk PRCMU_PLLDSI>, /* HDMI clock */
-                                <&prcmu_clk PRCMU_DSI0CLK>, /* DSI 0 */
-                                <&prcmu_clk PRCMU_DSI1CLK>, /* DSI 1 */
-                                <&prcmu_clk PRCMU_DSI0ESCCLK>, /* TVout clock 0 */
-                                <&prcmu_clk PRCMU_DSI1ESCCLK>, /* TVout clock 1 */
-                                <&prcmu_clk PRCMU_DSI2ESCCLK>; /* TVout clock 2 */
+                                <&prcmu_clk PRCMU_PLLDSI>; /* HDMI clock */
+                       clock-names = "mcde", "lcd", "hdmi";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       status = "disabled";
+
+                       dsi0: dsi@a0351000 {
+                               compatible = "ste,mcde-dsi";
+                               reg = <0xa0351000 0x1000>;
+                               vana-supply = <&ab8500_ldo_ana_reg>;
+                               clocks = <&prcmu_clk PRCMU_DSI0CLK>, <&prcmu_clk PRCMU_DSI0ESCCLK>;
+                               clock-names = "hs", "lp";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+                       dsi1: dsi@a0352000 {
+                               compatible = "ste,mcde-dsi";
+                               reg = <0xa0352000 0x1000>;
+                               vana-supply = <&ab8500_ldo_ana_reg>;
+                               clocks = <&prcmu_clk PRCMU_DSI1CLK>, <&prcmu_clk PRCMU_DSI1ESCCLK>;
+                               clock-names = "hs", "lp";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+                       dsi2: dsi@a0353000 {
+                               compatible = "ste,mcde-dsi";
+                               reg = <0xa0353000 0x1000>;
+                               vana-supply = <&ab8500_ldo_ana_reg>;
+                               /* This DSI port only has the Low Power / Energy Save clock */
+                               clocks = <&prcmu_clk PRCMU_DSI2ESCCLK>;
+                               clock-names = "lp";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
                };
 
                cryp@a03cb000 {
index 35e944d8b5c42307c8dbb9f98d34b35a7457cc46..eeaea21f5ecae49de1f4993402ae8ba9fd42bf6a 100644 (file)
                                };
                        };
                };
+
+               mcde@a0350000 {
+                       status = "okay";
+
+                       dsi@a0351000 {
+                               panel {
+                                       compatible = "samsung,s6d16d0";
+                                       reg = <0>;
+                                       vdd1-supply = <&ab8500_ldo_aux1_reg>;
+                                       reset-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
+                               };
+                       };
+               };
        };
 };
index 0e7d77d719d759955a3de5a5231d3fab16c19c0f..76868444caa43cc4db910a7794509c8389e5eec7 100644 (file)
                                };
                        };
                };
+
+               mcde@a0350000 {
+                       status = "okay";
+
+                       dsi@a0351000 {
+                               panel {
+                                       compatible = "samsung,s6d16d0";
+                                       reg = <0>;
+                                       vdd1-supply = <&ab8500_ldo_aux1_reg>;
+                                       reset-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
+                               };
+                       };
+               };
        };
 };
index 588b6ef94e93895c3afd67dd0c190fd907546dcc..4a4954492ed139e62115fa0c4993e75e9cdc95d9 100644 (file)
        };
 
        soc {
+               romem: nvmem@1fff7800 {
+                       compatible = "st,stm32f4-otp";
+                       reg = <0x1fff7800 0x400>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ts_cal1: calib@22c {
+                               reg = <0x22c 0x2>;
+                       };
+                       ts_cal2: calib@22e {
+                               reg = <0x22e 0x2>;
+                       };
+               };
+
                timer2: timer@40000000 {
                        compatible = "st,stm32-timer";
                        reg = <0x40000000 0x400>;
index 3c7216844a9bf104a0e3c9493a2870d0904f77cd..6f1d0ac8c31c7fca770623fed1d126ad2f7ccc48 100644 (file)
        };
 };
 
+&rcc {
+       compatible = "st,stm32f769-rcc", "st,stm32f746-rcc", "st,stm32-rcc";
+};
+
 &cec {
        pinctrl-0 = <&cec_pins_a>;
        pinctrl-names = "default";
index 980b2769caf9ca11539266940b82249e9c530eeb..e44e7baa3f173ad4ce4f645e826200916a41ec11 100644 (file)
                                };
                        };
 
+                       sdmmc1_b4_pins_a: sdmmc1-b4-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+                                                <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+                                                <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+                                                <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                                                <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
+                                                <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+                                       slew-rate = <3>;
+                                       drive-push-pull;
+                                       bias-disable;
+                               };
+                       };
+
+                       sdmmc1_b4_od_pins_a: sdmmc1-b4-od-0 {
+                               pins1 {
+                                       pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+                                                <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+                                                <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+                                                <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                                                <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
+                                       slew-rate = <3>;
+                                       drive-push-pull;
+                                       bias-disable;
+                               };
+                               pins2{
+                                       pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+                                       slew-rate = <3>;
+                                       drive-open-drain;
+                                       bias-disable;
+                               };
+                       };
+
+                       sdmmc1_b4_sleep_pins_a: sdmmc1-b4-sleep-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
+                                                <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
+                                                <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
+                                                <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
+                                                <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
+                                                <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
+                               };
+                       };
+
+                       sdmmc1_dir_pins_a: sdmmc1-dir-0 {
+                               pins1 {
+                                       pinmux = <STM32_PINMUX('C', 6, AF8)>, /* SDMMC1_D0DIR */
+                                                <STM32_PINMUX('C', 7, AF8)>, /* SDMMC1_D123DIR */
+                                                <STM32_PINMUX('B', 9, AF7)>; /* SDMMC1_CDIR */
+                                       slew-rate = <3>;
+                                       drive-push-pull;
+                                       bias-pull-up;
+                               };
+                               pins2{
+                                       pinmux = <STM32_PINMUX('B', 8, AF7)>; /* SDMMC1_CKIN */
+                                       bias-pull-up;
+                               };
+                       };
+
+                       sdmmc1_dir_sleep_pins_a: sdmmc1-dir-sleep-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('C', 6, ANALOG)>, /* SDMMC1_D0DIR */
+                                                <STM32_PINMUX('C', 7, ANALOG)>, /* SDMMC1_D123DIR */
+                                                <STM32_PINMUX('B', 9, ANALOG)>, /* SDMMC1_CDIR */
+                                                <STM32_PINMUX('B', 8, ANALOG)>; /* SDMMC1_CKIN */
+                               };
+                       };
+
                        usart1_pins: usart1@0 {
                                pins1 {
                                        pinmux = <STM32_PINMUX('B', 14, AF4)>; /* USART1_TX */
index 5cac79ebebb14e6b429cb3b1e1ba8aadd0c96b01..c065266ee37760940671e77ee1c04787e252eeab 100644 (file)
                        dma-requests = <32>;
                };
 
+               sdmmc1: sdmmc@52007000 {
+                       compatible = "arm,pl18x", "arm,primecell";
+                       arm,primecell-periphid = <0x10153180>;
+                       reg = <0x52007000 0x1000>;
+                       interrupts = <49>;
+                       interrupt-names = "cmd_irq";
+                       clocks = <&rcc SDMMC1_CK>;
+                       clock-names = "apb_pclk";
+                       resets = <&rcc STM32H7_AHB3_RESET(SDMMC1)>;
+                       cap-sd-highspeed;
+                       cap-mmc-highspeed;
+                       max-frequency = <120000000>;
+               };
+
                exti: interrupt-controller@58000000 {
                        compatible = "st,stm32h7-exti";
                        interrupt-controller;
index dd06c8f3d09a8279941d1350adea3065e210d799..3acd2e9c434ef09f3e7c24f277d4f6a1f5054ce0 100644 (file)
        aliases {
                serial0 = &usart2;
        };
+
+       v3v3: regulator-v3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "v3v3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
 };
 
 &clk_hse {
        };
 };
 
+&sdmmc1 {
+       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>;
+       broken-cd;
+       st,neg-edge;
+       bus-width = <4>;
+       vmmc-supply = <&v3v3>;
+       status = "okay";
+};
+
 &usart2 {
        pinctrl-0 = <&usart2_pins>;
        pinctrl-names = "default";
index ebc3f0933f5c236ab4a0069a0a6510bf5c6d617c..ab78ad53237557066680ab48d2e384680f8646a0 100644 (file)
                regulator-always-on;
        };
 
+       v2v9_sd: regulator-v2v9_sd {
+               compatible = "regulator-fixed";
+               regulator-name = "v2v9_sd";
+               regulator-min-microvolt = <2900000>;
+               regulator-max-microvolt = <2900000>;
+               regulator-always-on;
+       };
+
        usbotg_hs_phy: usb-phy {
                #phy-cells = <0>;
                compatible = "usb-nop-xceiv";
                clocks = <&rcc USB1ULPI_CK>;
                clock-names = "main_clk";
        };
-
 };
 
 &adc_12 {
        };
 };
 
+&sdmmc1 {
+       pinctrl-names = "default", "opendrain", "sleep";
+       pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
+       pinctrl-1 = <&sdmmc1_b4_od_pins_a &sdmmc1_dir_pins_a>;
+       pinctrl-2 = <&sdmmc1_b4_sleep_pins_a &sdmmc1_dir_sleep_pins_a>;
+       broken-cd;
+       st,sig-dir;
+       st,neg-edge;
+       st,use-ckin;
+       bus-width = <4>;
+       vmmc-supply = <&v2v9_sd>;
+       status = "okay";
+};
+
 &usart1 {
        pinctrl-0 = <&usart1_pins>;
        pinctrl-names = "default";
index 9ec4694e93a7f4a8decc4ce8af01d6b0e4b00594..85c417d9983b98ec1001b340c1521cc0318c664e 100644 (file)
                                };
                        };
 
+                       cec_pins_sleep_a: cec-sleep-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('A', 15, ANALOG)>; /* HDMI_CEC */
+                               };
+                       };
+
+                       cec_pins_b: cec-1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('B', 6, AF5)>;
+                                       bias-disable;
+                                       drive-open-drain;
+                                       slew-rate = <0>;
+                               };
+                       };
+
+                       cec_pins_sleep_b: cec-sleep-1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('B', 6, ANALOG)>; /* HDMI_CEC */
+                               };
+                       };
+
                        ethernet0_rgmii_pins_a: rgmii-0 {
                                pins1 {
                                        pinmux = <STM32_PINMUX('G', 5, AF11)>, /* ETH_RGMII_CLK125 */
                                };
                        };
 
+                       i2c1_pins_sleep_a: i2c1-1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('D', 12, ANALOG)>, /* I2C1_SCL */
+                                                <STM32_PINMUX('F', 15, ANALOG)>; /* I2C1_SDA */
+                               };
+                       };
+
                        i2c2_pins_a: i2c2-0 {
                                pins {
                                        pinmux = <STM32_PINMUX('H', 4, AF4)>, /* I2C2_SCL */
                                };
                        };
 
+                       i2c2_pins_sleep_a: i2c2-1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('H', 4, ANALOG)>, /* I2C2_SCL */
+                                                <STM32_PINMUX('H', 5, ANALOG)>; /* I2C2_SDA */
+                               };
+                       };
+
                        i2c5_pins_a: i2c5-0 {
                                pins {
                                        pinmux = <STM32_PINMUX('A', 11, AF4)>, /* I2C5_SCL */
                                };
                        };
 
+                       i2c5_pins_sleep_a: i2c5-1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('A', 11, ANALOG)>, /* I2C5_SCL */
+                                                <STM32_PINMUX('A', 12, ANALOG)>; /* I2C5_SDA */
+
+                               };
+                       };
+
+                       ltdc_pins_a: ltdc-a-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('G',  7, AF14)>, /* LCD_CLK */
+                                                <STM32_PINMUX('I', 10, AF14)>, /* LCD_HSYNC */
+                                                <STM32_PINMUX('I',  9, AF14)>, /* LCD_VSYNC */
+                                                <STM32_PINMUX('F', 10, AF14)>, /* LCD_DE */
+                                                <STM32_PINMUX('H',  2, AF14)>, /* LCD_R0 */
+                                                <STM32_PINMUX('H',  3, AF14)>, /* LCD_R1 */
+                                                <STM32_PINMUX('H',  8, AF14)>, /* LCD_R2 */
+                                                <STM32_PINMUX('H',  9, AF14)>, /* LCD_R3 */
+                                                <STM32_PINMUX('H', 10, AF14)>, /* LCD_R4 */
+                                                <STM32_PINMUX('C',  0, AF14)>, /* LCD_R5 */
+                                                <STM32_PINMUX('H', 12, AF14)>, /* LCD_R6 */
+                                                <STM32_PINMUX('E', 15, AF14)>, /* LCD_R7 */
+                                                <STM32_PINMUX('E',  5, AF14)>, /* LCD_G0 */
+                                                <STM32_PINMUX('E',  6, AF14)>, /* LCD_G1 */
+                                                <STM32_PINMUX('H', 13, AF14)>, /* LCD_G2 */
+                                                <STM32_PINMUX('H', 14, AF14)>, /* LCD_G3 */
+                                                <STM32_PINMUX('H', 15, AF14)>, /* LCD_G4 */
+                                                <STM32_PINMUX('I',  0, AF14)>, /* LCD_G5 */
+                                                <STM32_PINMUX('I',  1, AF14)>, /* LCD_G6 */
+                                                <STM32_PINMUX('I',  2, AF14)>, /* LCD_G7 */
+                                                <STM32_PINMUX('D',  9, AF14)>, /* LCD_B0 */
+                                                <STM32_PINMUX('G', 12, AF14)>, /* LCD_B1 */
+                                                <STM32_PINMUX('G', 10, AF14)>, /* LCD_B2 */
+                                                <STM32_PINMUX('D', 10, AF14)>, /* LCD_B3 */
+                                                <STM32_PINMUX('I',  4, AF14)>, /* LCD_B4 */
+                                                <STM32_PINMUX('A',  3, AF14)>, /* LCD_B5 */
+                                                <STM32_PINMUX('B',  8, AF14)>, /* LCD_B6 */
+                                                <STM32_PINMUX('D',  8, AF14)>; /* LCD_B7 */
+                                       bias-disable;
+                                       drive-push-pull;
+                                       slew-rate = <1>;
+                               };
+                       };
+
+                       ltdc_pins_sleep_a: ltdc-a-1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('G',  7, ANALOG)>, /* LCD_CLK */
+                                                <STM32_PINMUX('I', 10, ANALOG)>, /* LCD_HSYNC */
+                                                <STM32_PINMUX('I',  9, ANALOG)>, /* LCD_VSYNC */
+                                                <STM32_PINMUX('F', 10, ANALOG)>, /* LCD_DE */
+                                                <STM32_PINMUX('H',  2, ANALOG)>, /* LCD_R0 */
+                                                <STM32_PINMUX('H',  3, ANALOG)>, /* LCD_R1 */
+                                                <STM32_PINMUX('H',  8, ANALOG)>, /* LCD_R2 */
+                                                <STM32_PINMUX('H',  9, ANALOG)>, /* LCD_R3 */
+                                                <STM32_PINMUX('H', 10, ANALOG)>, /* LCD_R4 */
+                                                <STM32_PINMUX('C',  0, ANALOG)>, /* LCD_R5 */
+                                                <STM32_PINMUX('H', 12, ANALOG)>, /* LCD_R6 */
+                                                <STM32_PINMUX('E', 15, ANALOG)>, /* LCD_R7 */
+                                                <STM32_PINMUX('E',  5, ANALOG)>, /* LCD_G0 */
+                                                <STM32_PINMUX('E',  6, ANALOG)>, /* LCD_G1 */
+                                                <STM32_PINMUX('H', 13, ANALOG)>, /* LCD_G2 */
+                                                <STM32_PINMUX('H', 14, ANALOG)>, /* LCD_G3 */
+                                                <STM32_PINMUX('H', 15, ANALOG)>, /* LCD_G4 */
+                                                <STM32_PINMUX('I',  0, ANALOG)>, /* LCD_G5 */
+                                                <STM32_PINMUX('I',  1, ANALOG)>, /* LCD_G6 */
+                                                <STM32_PINMUX('I',  2, ANALOG)>, /* LCD_G7 */
+                                                <STM32_PINMUX('D',  9, ANALOG)>, /* LCD_B0 */
+                                                <STM32_PINMUX('G', 12, ANALOG)>, /* LCD_B1 */
+                                                <STM32_PINMUX('G', 10, ANALOG)>, /* LCD_B2 */
+                                                <STM32_PINMUX('D', 10, ANALOG)>, /* LCD_B3 */
+                                                <STM32_PINMUX('I',  4, ANALOG)>, /* LCD_B4 */
+                                                <STM32_PINMUX('A',  3, ANALOG)>, /* LCD_B5 */
+                                                <STM32_PINMUX('B',  8, ANALOG)>, /* LCD_B6 */
+                                                <STM32_PINMUX('D',  8, ANALOG)>; /* LCD_B7 */
+                               };
+                       };
+
+                       ltdc_pins_b: ltdc-b-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('I', 14, AF14)>, /* LCD_CLK */
+                                                <STM32_PINMUX('I', 12, AF14)>, /* LCD_HSYNC */
+                                                <STM32_PINMUX('I', 13, AF14)>, /* LCD_VSYNC */
+                                                <STM32_PINMUX('K',  7, AF14)>, /* LCD_DE */
+                                                <STM32_PINMUX('I', 15, AF14)>, /* LCD_R0 */
+                                                <STM32_PINMUX('J',  0, AF14)>, /* LCD_R1 */
+                                                <STM32_PINMUX('J',  1, AF14)>, /* LCD_R2 */
+                                                <STM32_PINMUX('J',  2, AF14)>, /* LCD_R3 */
+                                                <STM32_PINMUX('J',  3, AF14)>, /* LCD_R4 */
+                                                <STM32_PINMUX('J',  4, AF14)>, /* LCD_R5 */
+                                                <STM32_PINMUX('J',  5, AF14)>, /* LCD_R6 */
+                                                <STM32_PINMUX('J',  6, AF14)>, /* LCD_R7 */
+                                                <STM32_PINMUX('J',  7, AF14)>, /* LCD_G0 */
+                                                <STM32_PINMUX('J',  8, AF14)>, /* LCD_G1 */
+                                                <STM32_PINMUX('J',  9, AF14)>, /* LCD_G2 */
+                                                <STM32_PINMUX('J', 10, AF14)>, /* LCD_G3 */
+                                                <STM32_PINMUX('J', 11, AF14)>, /* LCD_G4 */
+                                                <STM32_PINMUX('K',  0, AF14)>, /* LCD_G5 */
+                                                <STM32_PINMUX('K',  1, AF14)>, /* LCD_G6 */
+                                                <STM32_PINMUX('K',  2, AF14)>, /* LCD_G7 */
+                                                <STM32_PINMUX('J', 12, AF14)>, /* LCD_B0 */
+                                                <STM32_PINMUX('J', 13, AF14)>, /* LCD_B1 */
+                                                <STM32_PINMUX('J', 14, AF14)>, /* LCD_B2 */
+                                                <STM32_PINMUX('J', 15, AF14)>, /* LCD_B3 */
+                                                <STM32_PINMUX('K',  3, AF14)>, /* LCD_B4 */
+                                                <STM32_PINMUX('K',  4, AF14)>, /* LCD_B5 */
+                                                <STM32_PINMUX('K',  5, AF14)>, /* LCD_B6 */
+                                                <STM32_PINMUX('K',  6, AF14)>; /* LCD_B7 */
+                                       bias-disable;
+                                       drive-push-pull;
+                                       slew-rate = <1>;
+                               };
+                       };
+
+                       ltdc_pins_sleep_b: ltdc-b-1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('I', 14, ANALOG)>, /* LCD_CLK */
+                                                <STM32_PINMUX('I', 12, ANALOG)>, /* LCD_HSYNC */
+                                                <STM32_PINMUX('I', 13, ANALOG)>, /* LCD_VSYNC */
+                                                <STM32_PINMUX('K',  7, ANALOG)>, /* LCD_DE */
+                                                <STM32_PINMUX('I', 15, ANALOG)>, /* LCD_R0 */
+                                                <STM32_PINMUX('J',  0, ANALOG)>, /* LCD_R1 */
+                                                <STM32_PINMUX('J',  1, ANALOG)>, /* LCD_R2 */
+                                                <STM32_PINMUX('J',  2, ANALOG)>, /* LCD_R3 */
+                                                <STM32_PINMUX('J',  3, ANALOG)>, /* LCD_R4 */
+                                                <STM32_PINMUX('J',  4, ANALOG)>, /* LCD_R5 */
+                                                <STM32_PINMUX('J',  5, ANALOG)>, /* LCD_R6 */
+                                                <STM32_PINMUX('J',  6, ANALOG)>, /* LCD_R7 */
+                                                <STM32_PINMUX('J',  7, ANALOG)>, /* LCD_G0 */
+                                                <STM32_PINMUX('J',  8, ANALOG)>, /* LCD_G1 */
+                                                <STM32_PINMUX('J',  9, ANALOG)>, /* LCD_G2 */
+                                                <STM32_PINMUX('J', 10, ANALOG)>, /* LCD_G3 */
+                                                <STM32_PINMUX('J', 11, ANALOG)>, /* LCD_G4 */
+                                                <STM32_PINMUX('K',  0, ANALOG)>, /* LCD_G5 */
+                                                <STM32_PINMUX('K',  1, ANALOG)>, /* LCD_G6 */
+                                                <STM32_PINMUX('K',  2, ANALOG)>, /* LCD_G7 */
+                                                <STM32_PINMUX('J', 12, ANALOG)>, /* LCD_B0 */
+                                                <STM32_PINMUX('J', 13, ANALOG)>, /* LCD_B1 */
+                                                <STM32_PINMUX('J', 14, ANALOG)>, /* LCD_B2 */
+                                                <STM32_PINMUX('J', 15, ANALOG)>, /* LCD_B3 */
+                                                <STM32_PINMUX('K',  3, ANALOG)>, /* LCD_B4 */
+                                                <STM32_PINMUX('K',  4, ANALOG)>, /* LCD_B5 */
+                                                <STM32_PINMUX('K',  5, ANALOG)>, /* LCD_B6 */
+                                                <STM32_PINMUX('K',  6, ANALOG)>; /* LCD_B7 */
+                               };
+                       };
+
                        m_can1_pins_a: m-can1-0 {
                                pins1 {
                                        pinmux = <STM32_PINMUX('H', 13, AF9)>; /* CAN1_TX */
                                };
                        };
 
+                       sdmmc1_b4_pins_a: sdmmc1-b4-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+                                                <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+                                                <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+                                                <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                                                <STM32_PINMUX('C', 12, AF12)>, /* SDMMC1_CK */
+                                                <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+                                       slew-rate = <3>;
+                                       drive-push-pull;
+                                       bias-disable;
+                               };
+                       };
+
+                       sdmmc1_b4_od_pins_a: sdmmc1-b4-od-0 {
+                               pins1 {
+                                       pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+                                                <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+                                                <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+                                                <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+                                                <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
+                                       slew-rate = <3>;
+                                       drive-push-pull;
+                                       bias-disable;
+                               };
+                               pins2{
+                                       pinmux = <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+                                       slew-rate = <3>;
+                                       drive-open-drain;
+                                       bias-disable;
+                               };
+                       };
+
+                       sdmmc1_b4_sleep_pins_a: sdmmc1-b4-sleep-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('C', 8, ANALOG)>, /* SDMMC1_D0 */
+                                                <STM32_PINMUX('C', 9, ANALOG)>, /* SDMMC1_D1 */
+                                                <STM32_PINMUX('C', 10, ANALOG)>, /* SDMMC1_D2 */
+                                                <STM32_PINMUX('C', 11, ANALOG)>, /* SDMMC1_D3 */
+                                                <STM32_PINMUX('C', 12, ANALOG)>, /* SDMMC1_CK */
+                                                <STM32_PINMUX('D', 2, ANALOG)>; /* SDMMC1_CMD */
+                               };
+                       };
+
+                       sdmmc1_dir_pins_a: sdmmc1-dir-0 {
+                               pins1 {
+                                       pinmux = <STM32_PINMUX('F', 2, AF11)>, /* SDMMC1_D0DIR */
+                                                <STM32_PINMUX('C', 7, AF8)>, /* SDMMC1_D123DIR */
+                                                <STM32_PINMUX('B', 9, AF11)>; /* SDMMC1_CDIR */
+                                       slew-rate = <3>;
+                                       drive-push-pull;
+                                       bias-pull-up;
+                               };
+                               pins2{
+                                       pinmux = <STM32_PINMUX('E', 4, AF8)>; /* SDMMC1_CKIN */
+                                       bias-pull-up;
+                               };
+                       };
+
+                       sdmmc1_dir_sleep_pins_a: sdmmc1-dir-sleep-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('F', 2, ANALOG)>, /* SDMMC1_D0DIR */
+                                                <STM32_PINMUX('C', 7, ANALOG)>, /* SDMMC1_D123DIR */
+                                                <STM32_PINMUX('B', 9, ANALOG)>, /* SDMMC1_CDIR */
+                                                <STM32_PINMUX('E', 4, ANALOG)>; /* SDMMC1_CKIN */
+                               };
+                       };
+
+                       spdifrx_pins_a: spdifrx-0 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('G', 12, AF8)>; /* SPDIF_IN1 */
+                                       bias-disable;
+                               };
+                       };
+
+                       spdifrx_sleep_pins_a: spdifrx-1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('G', 12, ANALOG)>; /* SPDIF_IN1 */
+                               };
+                       };
+
                        uart4_pins_a: uart4-0 {
                                pins1 {
                                        pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
                                };
                        };
 
+                       i2c4_pins_sleep_a: i2c4-1 {
+                               pins {
+                                       pinmux = <STM32_PINMUX('Z', 4, ANALOG)>, /* I2C4_SCL */
+                                                <STM32_PINMUX('Z', 5, ANALOG)>; /* I2C4_SDA */
+                               };
+                       };
+
                        spi1_pins_a: spi1-0 {
                                pins1 {
                                        pinmux = <STM32_PINMUX('Z', 0, AF5)>, /* SPI1_SCK */
diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts
new file mode 100644 (file)
index 0000000..098dbfb
--- /dev/null
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+/dts-v1/;
+
+#include "stm32mp157c.dtsi"
+#include "stm32mp157-pinctrl.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/mfd/st,stpmic1.h>
+
+/ {
+       model = "STMicroelectronics STM32MP157A-DK1 Discovery Board";
+       compatible = "st,stm32mp157a-dk1", "st,stm32mp157";
+
+       aliases {
+               ethernet0 = &ethernet0;
+               serial0 = &uart4;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@c0000000 {
+               reg = <0xc0000000 0x20000000>;
+       };
+
+       led {
+               compatible = "gpio-leds";
+               blue {
+                       label = "heartbeat";
+                       gpios = <&gpiod 11 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+                       default-state = "off";
+               };
+       };
+};
+
+&cec {
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&cec_pins_b>;
+       pinctrl-1 = <&cec_pins_sleep_b>;
+       status = "okay";
+};
+
+&ethernet0 {
+       status = "okay";
+       pinctrl-0 = <&ethernet0_rgmii_pins_a>;
+       pinctrl-1 = <&ethernet0_rgmii_pins_sleep_a>;
+       pinctrl-names = "default", "sleep";
+       phy-mode = "rgmii";
+       max-speed = <1000>;
+       phy-handle = <&phy0>;
+
+       mdio0 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "snps,dwmac-mdio";
+               phy0: ethernet-phy@0 {
+                       reg = <0>;
+               };
+       };
+};
+
+
+&i2c4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c4_pins_a>;
+       i2c-scl-rising-time-ns = <185>;
+       i2c-scl-falling-time-ns = <20>;
+       status = "okay";
+       /* spare dmas for other usage */
+       /delete-property/dmas;
+       /delete-property/dma-names;
+
+       pmic: stpmic@33 {
+               compatible = "st,stpmic1";
+               reg = <0x33>;
+               interrupts-extended = <&gpioa 0 IRQ_TYPE_EDGE_FALLING>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               status = "okay";
+
+               regulators {
+                       compatible = "st,stpmic1-regulators";
+                       ldo1-supply = <&v3v3>;
+                       ldo3-supply = <&vdd_ddr>;
+                       ldo6-supply = <&v3v3>;
+                       pwr_sw1-supply = <&bst_out>;
+                       pwr_sw2-supply = <&bst_out>;
+
+                       vddcore: buck1 {
+                               regulator-name = "vddcore";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-initial-mode = <0>;
+                               regulator-over-current-protection;
+                       };
+
+                       vdd_ddr: buck2 {
+                               regulator-name = "vdd_ddr";
+                               regulator-min-microvolt = <1350000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-initial-mode = <0>;
+                               regulator-over-current-protection;
+                       };
+
+                       vdd: buck3 {
+                               regulator-name = "vdd";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                               st,mask-reset;
+                               regulator-initial-mode = <0>;
+                               regulator-over-current-protection;
+                       };
+
+                       v3v3: buck4 {
+                               regulator-name = "v3v3";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                               regulator-over-current-protection;
+                               regulator-initial-mode = <0>;
+                       };
+
+                       v1v8_audio: ldo1 {
+                               regulator-name = "v1v8_audio";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               interrupts = <IT_CURLIM_LDO1 0>;
+                       };
+
+                       v3v3_hdmi: ldo2 {
+                               regulator-name = "v3v3_hdmi";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                               interrupts = <IT_CURLIM_LDO2 0>;
+                       };
+
+                       vtt_ddr: ldo3 {
+                               regulator-name = "vtt_ddr";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <750000>;
+                               regulator-always-on;
+                               regulator-over-current-protection;
+                       };
+
+                       vdd_usb: ldo4 {
+                               regulator-name = "vdd_usb";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               interrupts = <IT_CURLIM_LDO4 0>;
+                       };
+
+                       vdda: ldo5 {
+                               regulator-name = "vdda";
+                               regulator-min-microvolt = <2900000>;
+                               regulator-max-microvolt = <2900000>;
+                               interrupts = <IT_CURLIM_LDO5 0>;
+                               regulator-boot-on;
+                       };
+
+                       v1v2_hdmi: ldo6 {
+                               regulator-name = "v1v2_hdmi";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-always-on;
+                               interrupts = <IT_CURLIM_LDO6 0>;
+                       };
+
+                       vref_ddr: vref_ddr {
+                               regulator-name = "vref_ddr";
+                               regulator-always-on;
+                               regulator-over-current-protection;
+                       };
+
+                        bst_out: boost {
+                               regulator-name = "bst_out";
+                               interrupts = <IT_OCP_BOOST 0>;
+                        };
+
+                       vbus_otg: pwr_sw1 {
+                               regulator-name = "vbus_otg";
+                               interrupts = <IT_OCP_OTG 0>;
+                        };
+
+                        vbus_sw: pwr_sw2 {
+                               regulator-name = "vbus_sw";
+                               interrupts = <IT_OCP_SWOUT 0>;
+                               regulator-active-discharge;
+                        };
+               };
+
+               onkey {
+                       compatible = "st,stpmic1-onkey";
+                       interrupts = <IT_PONKEY_F 0>, <IT_PONKEY_R 0>;
+                       interrupt-names = "onkey-falling", "onkey-rising";
+                       power-off-time-sec = <10>;
+                       status = "okay";
+               };
+
+               watchdog {
+                       compatible = "st,stpmic1-wdt";
+                       status = "disabled";
+               };
+       };
+};
+
+&ipcc {
+       status = "okay";
+};
+
+&iwdg2 {
+       timeout-sec = <32>;
+       status = "okay";
+};
+
+&rng1 {
+       status = "okay";
+};
+
+&rtc {
+       status = "okay";
+};
+
+&sdmmc1 {
+       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>;
+       broken-cd;
+       st,neg-edge;
+       bus-width = <4>;
+       vmmc-supply = <&v3v3>;
+       status = "okay";
+};
+
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart4_pins_a>;
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts b/arch/arm/boot/dts/stm32mp157c-dk2.dts
new file mode 100644 (file)
index 0000000..20ea601
--- /dev/null
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+/dts-v1/;
+
+#include "stm32mp157a-dk1.dts"
+
+/ {
+       model = "STMicroelectronics STM32MP157C-DK2 Discovery Board";
+       compatible = "st,stm32mp157c-dk2", "st,stm32mp157";
+
+       reg18: reg18 {
+               compatible = "regulator-fixed";
+               regulator-name = "reg18";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+       };
+};
+
+&dsi {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       status = "okay";
+       phy-dsi-supply = <&reg18>;
+
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@0 {
+                       reg = <0>;
+                       dsi_in: endpoint {
+                               remote-endpoint = <&ltdc_ep1_out>;
+                       };
+               };
+
+               port@1 {
+                       reg = <1>;
+                       dsi_out: endpoint {
+                               remote-endpoint = <&panel_in>;
+                       };
+               };
+       };
+
+       panel@0 {
+               compatible = "orisetech,otm8009a";
+               reg = <0>;
+               reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>;
+               power-supply = <&v3v3>;
+               status = "okay";
+
+               port {
+                       panel_in: endpoint {
+                               remote-endpoint = <&dsi_out>;
+                       };
+               };
+       };
+};
+
+&ltdc {
+       status = "okay";
+
+       port {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ltdc_ep1_out: endpoint@1 {
+                       reg = <1>;
+                       remote-endpoint = <&dsi_in>;
+               };
+       };
+};
index d66edb0c66cd5298dccef8177a28b715ed8feac7..62a8c78e7e2e1c55e9831aa355cfccc5f3a9a670 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "stm32mp157c.dtsi"
 #include "stm32mp157-pinctrl.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/mfd/st,stpmic1.h>
 
 / {
        model = "STMicroelectronics STM32MP157C eval daughter";
                regulator-always-on;
        };
 
-       vdd_usb: vdd-usb {
-               compatible = "regulator-fixed";
-               regulator-name = "vdd_usb";
-               regulator-min-microvolt = <3300000>;
-               regulator-max-microvolt = <3300000>;
+       sd_switch: regulator-sd_switch {
+               compatible = "regulator-gpio";
+               regulator-name = "sd_switch";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <2900000>;
+               regulator-type = "voltage";
                regulator-always-on;
+
+               gpios = <&gpiof 14 GPIO_ACTIVE_HIGH>;
+               gpios-states = <0>;
+               states = <1800000 0x1 2900000 0x0>;
        };
 };
 
        i2c-scl-rising-time-ns = <185>;
        i2c-scl-falling-time-ns = <20>;
        status = "okay";
+       /* spare dmas for other usage */
+       /delete-property/dmas;
+       /delete-property/dma-names;
+
+       pmic: stpmic@33 {
+               compatible = "st,stpmic1";
+               reg = <0x33>;
+               interrupts-extended = <&gpioa 0 IRQ_TYPE_EDGE_FALLING>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               status = "okay";
+
+               regulators {
+                       compatible = "st,stpmic1-regulators";
+                       ldo1-supply = <&v3v3>;
+                       ldo2-supply = <&v3v3>;
+                       ldo3-supply = <&vdd_ddr>;
+                       ldo5-supply = <&v3v3>;
+                       ldo6-supply = <&v3v3>;
+                       pwr_sw1-supply = <&bst_out>;
+                       pwr_sw2-supply = <&bst_out>;
+
+                       vddcore: buck1 {
+                               regulator-name = "vddcore";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-initial-mode = <0>;
+                               regulator-over-current-protection;
+                       };
+
+                       vdd_ddr: buck2 {
+                               regulator-name = "vdd_ddr";
+                               regulator-min-microvolt = <1350000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-initial-mode = <0>;
+                               regulator-over-current-protection;
+                       };
+
+                       vdd: buck3 {
+                               regulator-name = "vdd";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                               st,mask-reset;
+                               regulator-initial-mode = <0>;
+                               regulator-over-current-protection;
+                       };
+
+                       v3v3: buck4 {
+                               regulator-name = "v3v3";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                               regulator-over-current-protection;
+                               regulator-initial-mode = <0>;
+                       };
+
+                       vdda: ldo1 {
+                               regulator-name = "vdda";
+                               regulator-min-microvolt = <2900000>;
+                               regulator-max-microvolt = <2900000>;
+                               interrupts = <IT_CURLIM_LDO1 0>;
+                       };
+
+                       v2v8: ldo2 {
+                               regulator-name = "v2v8";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               interrupts = <IT_CURLIM_LDO2 0>;
+                       };
+
+                       vtt_ddr: ldo3 {
+                               regulator-name = "vtt_ddr";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <750000>;
+                               regulator-always-on;
+                               regulator-over-current-protection;
+                       };
+
+                       vdd_usb: ldo4 {
+                               regulator-name = "vdd_usb";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               interrupts = <IT_CURLIM_LDO4 0>;
+                       };
+
+                       vdd_sd: ldo5 {
+                               regulator-name = "vdd_sd";
+                               regulator-min-microvolt = <2900000>;
+                               regulator-max-microvolt = <2900000>;
+                               interrupts = <IT_CURLIM_LDO5 0>;
+                               regulator-boot-on;
+                       };
+
+                       v1v8: ldo6 {
+                               regulator-name = "v1v8";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               interrupts = <IT_CURLIM_LDO6 0>;
+                       };
+
+                       vref_ddr: vref_ddr {
+                               regulator-name = "vref_ddr";
+                               regulator-always-on;
+                               regulator-over-current-protection;
+                       };
+
+                       bst_out: boost {
+                               regulator-name = "bst_out";
+                               interrupts = <IT_OCP_BOOST 0>;
+                       };
+
+                       vbus_otg: pwr_sw1 {
+                               regulator-name = "vbus_otg";
+                               interrupts = <IT_OCP_OTG 0>;
+                        };
+
+                        vbus_sw: pwr_sw2 {
+                               regulator-name = "vbus_sw";
+                               interrupts = <IT_OCP_SWOUT 0>;
+                               regulator-active-discharge;
+                        };
+               };
+
+               onkey {
+                       compatible = "st,stpmic1-onkey";
+                       interrupts = <IT_PONKEY_F 0>, <IT_PONKEY_R 0>;
+                       interrupt-names = "onkey-falling", "onkey-rising";
+                       power-off-time-sec = <10>;
+                       status = "okay";
+               };
+
+               watchdog {
+                       compatible = "st,stpmic1-wdt";
+                       status = "disabled";
+               };
+       };
+};
+
+&ipcc {
+       status = "okay";
 };
 
 &iwdg2 {
        status = "okay";
 };
 
+&sdmmc1 {
+       pinctrl-names = "default", "opendrain", "sleep";
+       pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
+       pinctrl-1 = <&sdmmc1_b4_od_pins_a &sdmmc1_dir_pins_a>;
+       pinctrl-2 = <&sdmmc1_b4_sleep_pins_a &sdmmc1_dir_sleep_pins_a>;
+       broken-cd;
+       st,sig-dir;
+       st,neg-edge;
+       st,use-ckin;
+       bus-width = <4>;
+       vmmc-supply = <&vdd_sd>;
+       vqmmc-supply = <&sd_switch>;
+       status = "okay";
+};
+
 &timers6 {
        status = "okay";
        /* spare dmas for other usage */
index f8bbfff5950b1941769d11dab3c1d884295e9103..2afeee65c3eadb5a714b3bdf228eabfe5c2378a3 100644 (file)
                        status = "disabled";
                };
 
+               spdifrx: audio-controller@4000d000 {
+                       compatible = "st,stm32h7-spdifrx";
+                       #sound-dai-cells = <0>;
+                       reg = <0x4000d000 0x400>;
+                       clocks = <&rcc SPDIF_K>;
+                       clock-names = "kclk";
+                       interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+                       dmas = <&dmamux1 93 0x400 0x01>,
+                              <&dmamux1 94 0x400 0x01>;
+                       dma-names = "rx", "rx-ctrl";
+                       status = "disabled";
+               };
+
                usart2: serial@4000e000 {
                        compatible = "st,stm32h7-uart";
                        reg = <0x4000e000 0x400>;
                        status = "disabled";
                };
 
+               ipcc: mailbox@4c001000 {
+                       compatible = "st,stm32mp1-ipcc";
+                       #mbox-cells = <1>;
+                       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";
+                       clocks = <&rcc IPCC>;
+                       wakeup-source;
+                       status = "disabled";
+               };
+
                rcc: rcc@50000000 {
                        compatible = "st,stm32mp1-rcc", "syscon";
                        reg = <0x50000000 0x1000>;
                syscfg: syscon@50020000 {
                        compatible = "st,stm32mp157-syscfg", "syscon";
                        reg = <0x50020000 0x400>;
+                       clocks = <&rcc SYSCFG>;
                };
 
                lptimer2: timer@50021000 {
                        status = "disabled";
                };
 
+               sdmmc1: sdmmc@58005000 {
+                       compatible = "arm,pl18x", "arm,primecell";
+                       arm,primecell-periphid = <0x10153180>;
+                       reg = <0x58005000 0x1000>;
+                       interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "cmd_irq";
+                       clocks = <&rcc SDMMC1_K>;
+                       clock-names = "apb_pclk";
+                       resets = <&rcc SDMMC1_R>;
+                       cap-sd-highspeed;
+                       cap-mmc-highspeed;
+                       max-frequency = <120000000>;
+               };
+
                crc1: crc@58009000 {
                        compatible = "st,stm32f7-crc";
                        reg = <0x58009000 0x400>;
                        status = "disabled";
                };
 
+               bsec: nvmem@5c005000 {
+                       compatible = "st,stm32mp15-bsec";
+                       reg = <0x5c005000 0x400>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ts_cal1: calib@5c {
+                               reg = <0x5c 0x2>;
+                       };
+                       ts_cal2: calib@5e {
+                               reg = <0x5e 0x2>;
+                       };
+               };
+
                i2c6: i2c@5c009000 {
                        compatible = "st,stm32f7-i2c";
                        reg = <0x5c009000 0x400>;
index cf7b392dff31477324e816f27e85365a98484c1c..74262988881c6aa0fff5a0564e86d9da231c3d99 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PH5";
-               function = "gpio_in";
-               bias-pull-down;
-       };
-};
-
 &reg_usb0_vbus {
        status = "okay";
 };
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
-       usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
+       usb0_vbus_det-gpios = <&pio 7 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* PH5 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
        status = "okay";
index 197a1f2b75ff722bb7aa460eeaf5bf6f0c6d9d85..7306c65df88aa1acff7bb9446e38d776b67c21ea 100644 (file)
                function = "gpio_out";
                drive-strength = <20>;
        };
-
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
 };
 
 &reg_ahci_5v {
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
        usb1_vbus-supply = <&reg_usb1_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
        status = "okay";
index 896e27a08727827aad3b73f12ccc0c18993f7404..8ee3ff42bd553814b4f31550294ae5cc16972a9e 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PH5";
-               function = "gpio_in";
-               bias-pull-down;
-       };
-};
-
 &pwm {
        pinctrl-names = "default";
        pinctrl-0 = <&pwm0_pin>;
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
-       usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
+       usb0_vbus_det-gpios = <&pio 7 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* PH5 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
        status = "okay";
index f63767cddd8e4447117c4d6b2d151736bafd1a72..bf2044bac42fb9870c0603a89de88ee08e795677 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PH5";
-               function = "gpio_in";
-               bias-pull-down;
-       };
-};
-
 &reg_usb0_vbus {
        status = "okay";
 };
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
-       usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
+       usb0_vbus_det-gpios = <&pio 7 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* PH5 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
        status = "okay";
index 26d0c1d6a02b4454ff34b214562732a86e59b8d7..ca878384e9027c94712beeb556a875707f22a36d 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PH5";
-               function = "gpio_in";
-               bias-pull-down;
-       };
-};
-
 &pwm {
        pinctrl-names = "default";
        pinctrl-0 = <&pwm0_pin>;
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
-       usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
+       usb0_vbus_det-gpios = <&pio 7 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* PH5 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
index 71c27ea0b53e18142ff9e371e2a05913f859c287..76016f2ca29daab81342102f32db82b33980a32d 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PH5";
-               function = "gpio_in";
-               bias-pull-down;
-       };
-};
-
 &reg_dcdc2 {
        regulator-always-on;
        regulator-min-microvolt = <1000000>;
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
-       usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
+       usb0_vbus_det-gpios = <&pio 7 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* PH5 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
        status = "okay";
index 2f0d966f39ad8313b507a5e537ee5edd177e1412..0a562b2cc5bc6771c65ed77c2c72d2f76c87bd55 100644 (file)
@@ -61,8 +61,6 @@
 
        gpio-keys {
                compatible = "gpio-keys-polled";
-               pinctrl-names = "default";
-               pinctrl-0 = <&key_pins_inet9f>;
                poll-interval = <20>;
 
                left-joystick-left {
@@ -70,7 +68,7 @@
                        linux,code = <ABS_X>;
                        linux,input-type = <EV_ABS>;
                        linux,input-value = <0xffffffff>; /* -1 */
-                       gpios = <&pio 0 6 GPIO_ACTIVE_LOW>; /* PA6 */
+                       gpios = <&pio 0 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA6 */
                };
 
                left-joystick-right {
@@ -78,7 +76,7 @@
                        linux,code = <ABS_X>;
                        linux,input-type = <EV_ABS>;
                        linux,input-value = <1>;
-                       gpios = <&pio 0 5 GPIO_ACTIVE_LOW>; /* PA5 */
+                       gpios = <&pio 0 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA5 */
                };
 
                left-joystick-up {
@@ -86,7 +84,7 @@
                        linux,code = <ABS_Y>;
                        linux,input-type = <EV_ABS>;
                        linux,input-value = <0xffffffff>; /* -1 */
-                       gpios = <&pio 0 8 GPIO_ACTIVE_LOW>; /* PA8 */
+                       gpios = <&pio 0 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA8 */
                };
 
                left-joystick-down {
@@ -94,7 +92,7 @@
                        linux,code = <ABS_Y>;
                        linux,input-type = <EV_ABS>;
                        linux,input-value = <1>;
-                       gpios = <&pio 0 9 GPIO_ACTIVE_LOW>; /* PA9 */
+                       gpios = <&pio 0 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA9 */
                };
 
                right-joystick-left {
                        linux,code = <ABS_Z>;
                        linux,input-type = <EV_ABS>;
                        linux,input-value = <0xffffffff>; /* -1 */
-                       gpios = <&pio 0 1 GPIO_ACTIVE_LOW>; /* PA1 */
+                       gpios = <&pio 0 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA1 */
                };
 
                right-joystick-right {
                        linux,code = <ABS_Z>;
                        linux,input-type = <EV_ABS>;
                        linux,input-value = <1>;
-                       gpios = <&pio 0 0 GPIO_ACTIVE_LOW>; /* PA0 */
+                       gpios = <&pio 0 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA0 */
                };
 
                right-joystick-up {
                        linux,code = <ABS_RZ>;
                        linux,input-type = <EV_ABS>;
                        linux,input-value = <0xffffffff>; /* -1 */
-                       gpios = <&pio 0 3 GPIO_ACTIVE_LOW>; /* PA3 */
+                       gpios = <&pio 0 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA3 */
                };
 
                right-joystick-down {
                        linux,code = <ABS_RZ>;
                        linux,input-type = <EV_ABS>;
                        linux,input-value = <1>;
-                       gpios = <&pio 0 4 GPIO_ACTIVE_LOW>; /* PA4 */
+                       gpios = <&pio 0 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA4 */
                };
 
                dpad-left {
                        linux,code = <ABS_HAT0X>;
                        linux,input-type = <EV_ABS>;
                        linux,input-value = <0xffffffff>; /* -1 */
-                       gpios = <&pio 7 23 GPIO_ACTIVE_LOW>; /* PH23 */
+                       gpios = <&pio 7 23 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PH23 */
                };
 
                dpad-right {
                        linux,code = <ABS_HAT0X>;
                        linux,input-type = <EV_ABS>;
                        linux,input-value = <1>;
-                       gpios = <&pio 7 24 GPIO_ACTIVE_LOW>; /* PH24 */
+                       gpios = <&pio 7 24 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PH24 */
                };
 
                dpad-up {
                        linux,code = <ABS_HAT0Y>;
                        linux,input-type = <EV_ABS>;
                        linux,input-value = <0xffffffff>; /* -1 */
-                       gpios = <&pio 7 25 GPIO_ACTIVE_LOW>; /* PH25 */
+                       gpios = <&pio 7 25 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PH25 */
                };
 
                dpad-down {
                        linux,code = <ABS_HAT0Y>;
                        linux,input-type = <EV_ABS>;
                        linux,input-value = <1>;
-                       gpios = <&pio 7 26 GPIO_ACTIVE_LOW>; /* PH26 */
+                       gpios = <&pio 7 26 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PH26 */
                };
 
                x {
                        label = "Button X";
                        linux,code = <BTN_X>;
-                       gpios = <&pio 0 16 GPIO_ACTIVE_LOW>; /* PA16 */
+                       gpios = <&pio 0 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA16 */
                };
 
                y {
                        label = "Button Y";
                        linux,code = <BTN_Y>;
-                       gpios = <&pio 0 14 GPIO_ACTIVE_LOW>; /* PA14 */
+                       gpios = <&pio 0 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA14 */
                };
 
                a {
                        label = "Button A";
                        linux,code = <BTN_A>;
-                       gpios = <&pio 0 17 GPIO_ACTIVE_LOW>; /* PA17 */
+                       gpios = <&pio 0 17 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA17 */
                };
 
                b {
                        label = "Button B";
                        linux,code = <BTN_B>;
-                       gpios = <&pio 0 15 GPIO_ACTIVE_LOW>; /* PA15 */
+                       gpios = <&pio 0 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA15 */
                };
 
                select {
                        label = "Select Button";
                        linux,code = <BTN_SELECT>;
-                       gpios = <&pio 0 11 GPIO_ACTIVE_LOW>; /* PA11 */
+                       gpios = <&pio 0 11 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA11 */
                };
 
                start {
                        label = "Start Button";
                        linux,code = <BTN_START>;
-                       gpios = <&pio 0 12 GPIO_ACTIVE_LOW>; /* PA12 */
+                       gpios = <&pio 0 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA12 */
                };
 
                top-left {
                        label = "Top Left Button";
                        linux,code = <BTN_TL>;
-                       gpios = <&pio 7 22 GPIO_ACTIVE_LOW>; /* PH22 */
+                       gpios = <&pio 7 22 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PH22 */
                };
 
                top-right {
                        label = "Top Right Button";
                        linux,code = <BTN_TR>;
-                       gpios = <&pio 0 13 GPIO_ACTIVE_LOW>; /* PA13 */
+                       gpios = <&pio 0 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA13 */
                };
        };
 };
        status = "okay";
 };
 
-&pio {
-       key_pins_inet9f: key-pins {
-               pins = "PA0", "PA1", "PA3", "PA4",
-                      "PA5", "PA6", "PA8", "PA9",
-                      "PA11", "PA12", "PA13",
-                      "PA14", "PA15", "PA16", "PA17",
-                      "PH22", "PH23", "PH24", "PH25", "PH26";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PH5";
-               function = "gpio_in";
-               bias-pull-down;
-       };
-};
-
 &reg_dcdc2 {
        regulator-always-on;
        regulator-min-microvolt = <1000000>;
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
-       usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
+       usb0_vbus_det-gpios = <&pio 7 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* PH5 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
        status = "okay";
index 0dbf69576512ba8bbc7720ec838eaba8cb23ba3d..58ad2ad9041f19d683b280efd6dd722b7a634603 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 &reg_usb1_vbus {
        status = "okay";
 };
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
        usb1_vbus-supply = <&reg_usb1_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
        status = "okay";
index b74a614965377f49e074567137e490dc7e352087..a8e537fd4bd612637229c8221d5edb8926543fe6 100644 (file)
                function = "gpio_out";
                drive-strength = <20>;
        };
-
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PH5";
-               function = "gpio_in";
-               bias-pull-down;
-       };
 };
 
 &reg_ahci_5v {
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio   = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
-       usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
+       usb0_vbus_det-gpios = <&pio 7 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH5 */
        usb0_vbus-supply   = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
index d82a604f3d9c76b7332bfa172e3c1afeff338cbd..0f1e781069e9d14491fd8236fa4b8959d2da6e2c 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 #include "axp209.dtsi"
 
 &reg_dcdc2 {
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
        usb1_vbus-supply = <&reg_vcc5v0>; /* USB1 VBUS is always on */
        usb2_vbus-supply = <&reg_vcc5v0>; /* USB2 VBUS is always on */
        status = "okay";
index 84b25be1ac94328ad7cd56f806c4476b8d35cbd9..24a3d23e19529b4c01e5d3942bec9657f606e9f3 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PH5";
-               function = "gpio_in";
-               bias-pull-down;
-       };
-};
-
 &pwm {
        pinctrl-names = "default";
        pinctrl-0 = <&pwm0_pin>;
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
-       usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
+       usb0_vbus_det-gpios = <&pio 7 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* PH5 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
        status = "okay";
index 73c3ac42095fba496f605be2b8a7312478ccc676..e88daa4ef1aff9a67aac12cbb6959c53137bf6c4 100644 (file)
                        #dma-cells = <2>;
                };
 
-               nfc: nand@1c03000 {
+               nfc: nand-controller@1c03000 {
                        compatible = "allwinner,sun4i-a10-nand";
                        reg = <0x01c03000 0x1000>;
                        interrupts = <37>;
                                      "tcon-ch0",
                                      "tcon-ch1";
                        clock-output-names = "tcon0-pixel-clock";
+                       #clock-cells = <0>;
                        dmas = <&dma SUN4I_DMA_DEDICATED 14>;
 
                        ports {
                                      "tcon-ch0",
                                      "tcon-ch1";
                        clock-output-names = "tcon1-pixel-clock";
+                       #clock-cells = <0>;
                        dmas = <&dma SUN4I_DMA_DEDICATED 15>;
 
                        ports {
                        phy-names = "usb";
                        extcon = <&usbphy 0>;
                        allwinner,sram = <&otg_sram 1>;
+                       dr_mode = "otg";
                        status = "disabled";
                };
 
                usbphy: phy@1c13400 {
                        #phy-cells = <1>;
                        compatible = "allwinner,sun4i-a10-usb-phy";
-                       reg = <0x01c13400 0x10 0x01c14800 0x4 0x01c1c800 0x4>;
+                       reg = <0x01c13400 0x10>, <0x01c14800 0x4>, <0x01c1c800 0x4>;
                        reg-names = "phy_ctrl", "pmu1", "pmu2";
                        clocks = <&ccu CLK_USB_PHY>;
                        clock-names = "usb_phy";
                        interrupts = <39>;
                        clocks = <&ccu CLK_AHB_EHCI0>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        interrupts = <64>;
                        clocks = <&ccu CLK_USB_OHCI0>, <&ccu CLK_AHB_OHCI0>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        interrupts = <40>;
                        clocks = <&ccu CLK_AHB_EHCI1>;
                        phys = <&usbphy 2>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        interrupts = <65>;
                        clocks = <&ccu CLK_USB_OHCI1>, <&ccu CLK_AHB_OHCI1>;
                        phys = <&usbphy 2>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
index c88f08984483ebb9c0706438f115e3ff26551c34..8af0eae2ddc195a90d5820ffd7b61ea5ad69b879 100644 (file)
 };
 
 &pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PG12";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
        led_pins_t004: led-pin {
                pins = "PB2";
                function = "gpio_out";
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+       usb0_id_det-gpios = <&pio 6 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PG12 */
        usb1_vbus-supply = <&reg_usb1_vbus>;
        status = "okay";
 };
index 262c2ffbdcfa17cd962df31ec0bb6618877dad1b..5340b4164df26e622e12bf412f09aacc4c1003f1 100644 (file)
                function = "gpio_out";
                drive-strength = <20>;
        };
-
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PG12";
-               function = "gpio_in";
-               bias-pull-up;
-       };
 };
 
 &reg_usb0_vbus {
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+       usb0_id_det-gpios = <&pio 6 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PG12 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
        status = "okay";
index f3cede9beb63d4d819fce8ed739ce7c90ecb50fb..a23bf24792ec53cf1dda5f55c79fd95f8ab398cf 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PG1";
-               function = "gpio_in";
-               bias-pull-down;
-       };
-
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PG2";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 &pwm {
        pinctrl-names = "default";
        pinctrl-0 = <&pwm0_pin>;
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
-       usb0_vbus_det-gpio = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+       usb0_id_det-gpios = <&pio 6 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PG2 */
+       usb0_vbus_det-gpios = <&pio 6 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* PG1 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_ldo3>;
        status = "okay";
index 9369f7453beb870089d830282e859741881df114..9b9f2a57485150274983d4a4be8a4f4786b0e421 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PG2";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 #include "axp209.dtsi"
 
 &reg_dcdc2 {
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpios = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
+       usb0_id_det-gpios = <&pio 6 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PG2 */
        usb0_vbus_det-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_ldo3>;
index ca8f3fd1ddfec61bfdacd10f8b8c8c1e8dbf2185..ba8d75b3c716c07dc2149c4c72c593959cbaeb44 100644 (file)
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
-       usb0_vbus_det-gpio = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+       usb0_id_det-gpios = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
+       usb0_vbus_det-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_vcc5v0>;
        status = "okay";
index 943868e495bc2d674ee00e142cf78251cdd13047..5df398d7723884777e20eb5892f1f081ed8af3fe 100644 (file)
                function = "gpio_out";
                drive-strength = <20>;
        };
-
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PG2";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PG1";
-               function = "gpio_in";
-               bias-pull-down;
-       };
 };
 
 &reg_usb0_vbus {
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
-       usb0_vbus_det-gpio = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+       usb0_id_det-gpios = <&pio 6 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PG2 */
+       usb0_vbus_det-gpios = <&pio 6 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* PG1 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
        status = "okay";
index 9409c232d48ab7c3fc58cadf7de4e871481e7a91..39101228a7556a1996d2ac0cafd20712032ab2ef 100644 (file)
@@ -74,8 +74,6 @@
 
        bridge {
                compatible = "dumb-vga-dac";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                ports {
                        #address-cells = <1>;
                function = "gpio_out";
                drive-strength = <20>;
        };
-
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PG2";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PG1";
-               function = "gpio_in";
-               bias-pull-down;
-       };
 };
 
 &reg_usb0_vbus {
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
-       usb0_vbus_det-gpio = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+       usb0_id_det-gpios = <&pio 6 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PG2 */
+       usb0_vbus_det-gpios = <&pio 6 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* PG1 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
        status = "okay";
index 7257f39b31ce99cc77f2395cc650014190141a86..fde559a8b61e0f876037c5155d4d67cf159e4374 100644 (file)
                power-supply = <&reg_vcc3v3>;
                enable-gpios = <&axp_gpio 0 GPIO_ACTIVE_HIGH>; /* AXP GPIO0 */
                backlight = <&backlight>;
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               port@0 {
-                       reg = <0>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       panel_input: endpoint@0 {
-                               reg = <0>;
+               port {
+                       panel_input: endpoint {
                                remote-endpoint = <&tcon0_out_lcd>;
                        };
                };
index 732873cbeedc67fe0d04bcf6857aa7b082722d79..be486d28d04faeb4cfe98306bdb3cf25475e8963 100644 (file)
                /delete-property/stdout-path;
        };
 
-       i2c_lcd: i2c-gpio {
+       i2c_lcd: i2c {
                /* The lcd panel i2c interface is hooked up via gpios */
                compatible = "i2c-gpio";
-               pinctrl-names = "default";
-               pinctrl-0 = <&i2c_lcd_pins>;
-               gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>, /* PG12, sda */
-                       <&pio 6 10 GPIO_ACTIVE_HIGH>; /* PG10, scl */
+               sda-gpios = <&pio 6 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PG12 */
+               scl-gpios = <&pio 6 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PG10 */
                i2c-gpio,delay-us = <5>;
        };
 };
        };
 };
 
-&pio {
-       i2c_lcd_pins: i2c-lcd-pin {
-               pins = "PG10", "PG12";
-               function = "gpio_out";
-               bias-pull-up;
-       };
-};
-
 &reg_usb0_vbus {
        gpio = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
 };
index 3f70b8c53132bd6ed98df403c1a9bbe55a0e2666..a32cde3e32eb14a2163122bb12b804b0721b7335 100644 (file)
        status = "okay";
 
        nand@0 {
-               #address-cells = <2>;
-               #size-cells = <2>;
                reg = <0>;
                allwinner,rb = <0>;
                nand-ecc-mode = "hw";
 };
 
 &usbphy {
-       usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
+       usb0_id_det-gpios = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb1_vbus-supply = <&reg_vcc5v0>;
        status = "okay";
index 86e46aa59134cc1ff97d90ed2e95d73fcc4a5997..d003b895a696eae5b4f5a88f5cfc81e2ef1f78e7 100644 (file)
 };
 
 &usbphy {
-       usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
-       usb0_vbus_det-gpio = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+       usb0_id_det-gpios = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
+       usb0_vbus_det-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
        status = "okay";
index f4298facf9dc3a41baa8845b87aad1524079396f..4bf4943d4eb77c923ca25b57ecb678b5eb347bc7 100644 (file)
@@ -84,9 +84,7 @@
 
        onewire {
                compatible = "w1-gpio";
-               gpios = <&pio 3 2 GPIO_ACTIVE_HIGH>; /* PD2 */
-               pinctrl-names = "default";
-               pinctrl-0 = <&chip_w1_pin>;
+               gpios = <&pio 3 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PD2 */
        };
 };
 
        status = "okay";
 };
 
-&pio {
-       chip_w1_pin: chip-w1-pin {
-               pins = "PD2";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 &reg_dcdc2 {
        regulator-min-microvolt = <1000000>;
        regulator-max-microvolt = <1400000>;
 &usbphy {
        status = "okay";
 
-       usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
+       usb0_id_det-gpios = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_vcc5v0>;
index 5b1f0e198eb66404908251d527719a43e0ce8009..1a9926d714108db5baa546ccb8851cbeb3c16537 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PG1";
-               function = "gpio_in";
-               bias-pull-down;
-       };
-
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PG2";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 &reg_dcdc2 {
        regulator-always-on;
        regulator-min-microvolt = <1000000>;
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
-       usb0_vbus_det-gpio = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+       usb0_id_det-gpios = <&pio 6 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PG2 */
+       usb0_vbus_det-gpios = <&pio 6 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* PG1 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_ldo3>;
index 5497d985c54a82540c6509bde54fd8b055665737..2fb438c4fe9d1bd90fe366f65aed183d82280352 100644 (file)
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
+               dma-ranges;
                ranges;
 
                system-control@1c00000 {
                        };
                };
 
+               mbus: dram-controller@1c01000 {
+                       compatible = "allwinner,sun5i-a13-mbus";
+                       reg = <0x01c01000 0x1000>;
+                       clocks = <&ccu 99>;
+                       dma-ranges = <0x00000000 0x40000000 0x20000000>;
+                       #interconnect-cells = <1>;
+               };
+
                dma: dma-controller@1c02000 {
                        compatible = "allwinner,sun4i-a10-dma";
                        reg = <0x01c02000 0x1000>;
                        #dma-cells = <2>;
                };
 
-               nfc: nand@1c03000 {
+               nfc: nand-controller@1c03000 {
                        compatible = "allwinner,sun4i-a10-nand";
                        reg = <0x01c03000 0x1000>;
                        interrupts = <37>;
                        status = "disabled";
 
                        port {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
 
-                               tve0_in_tcon0: endpoint@0 {
-                                       reg = <0>;
+                               tve0_in_tcon0: endpoint {
                                        remote-endpoint = <&tcon0_out_tve0>;
                                };
                        };
                                      "tcon-ch0",
                                      "tcon-ch1";
                        clock-output-names = "tcon-pixel-clock";
+                       #clock-cells = <0>;
                        status = "disabled";
 
                        ports {
                                #size-cells = <0>;
 
                                tcon0_in: port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       tcon0_in_be0: endpoint@0 {
-                                               reg = <0>;
+                                       tcon0_in_be0: endpoint {
                                                remote-endpoint = <&be0_out_tcon0>;
                                        };
                                };
                        phy-names = "usb";
                        extcon = <&usbphy 0>;
                        allwinner,sram = <&otg_sram 1>;
+                       dr_mode = "otg";
                        status = "disabled";
                };
 
                usbphy: phy@1c13400 {
                        #phy-cells = <1>;
                        compatible = "allwinner,sun5i-a13-usb-phy";
-                       reg = <0x01c13400 0x10 0x01c14800 0x4>;
+                       reg = <0x01c13400 0x10>, <0x01c14800 0x4>;
                        reg-names = "phy_ctrl", "pmu1";
                        clocks = <&ccu CLK_USB_PHY0>;
                        clock-names = "usb_phy";
                        interrupts = <39>;
                        clocks = <&ccu CLK_AHB_EHCI>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        interrupts = <40>;
                        clocks = <&ccu CLK_USB_OHCI>, <&ccu CLK_AHB_OHCI>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                                bias-pull-up;
                        };
 
-                       mmc2_8bit_pins: mmc2-8bit-pins {
+                       mmc2_4bit_pc_pins: mmc2-4bit-pc-pins {
                                pins = "PC6", "PC7", "PC8", "PC9",
-                                      "PC10", "PC11", "PC12", "PC13",
-                                      "PC14", "PC15";
+                                      "PC10", "PC11";
                                function = "mmc2";
                                drive-strength = <30>;
                                bias-pull-up;
                        };
 
-                       mmc2_4bit_pc_pins: mmc2-4bit-pc-pins {
+                       mmc2_8bit_pins: mmc2-8bit-pins {
                                pins = "PC6", "PC7", "PC8", "PC9",
-                                      "PC10", "PC11";
+                                      "PC10", "PC11", "PC12", "PC13",
+                                      "PC14", "PC15";
                                function = "mmc2";
                                drive-strength = <30>;
                                bias-pull-up;
                                function = "nand0";
                        };
 
+                       pwm0_pin: pwm0-pin {
+                               pins = "PB2";
+                               function = "pwm";
+                       };
+
                        spi2_pe_pins: spi2-pe-pins {
                                pins = "PE1", "PE2", "PE3";
                                function = "spi2";
                                pins = "PG11", "PG12";
                                function = "uart3";
                        };
-
-                       pwm0_pin: pwm0-pin {
-                               pins = "PB2";
-                               function = "pwm";
-                       };
                };
 
                timer@1c20c00 {
                        clock-names = "ahb", "mod",
                                      "ram";
                        resets = <&ccu RST_DE_FE>;
+                       interconnects = <&mbus 19>;
+                       interconnect-names = "dma-mem";
                        status = "disabled";
 
                        ports {
                                #size-cells = <0>;
 
                                fe0_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
 
-                                       fe0_out_be0: endpoint@0 {
-                                               reg = <0>;
+                                       fe0_out_be0: endpoint {
                                                remote-endpoint = <&be0_in_fe0>;
                                        };
                                };
                        clock-names = "ahb", "mod",
                                      "ram";
                        resets = <&ccu RST_DE_BE>;
+                       interconnects = <&mbus 18>;
+                       interconnect-names = "dma-mem";
                        status = "disabled";
 
                        assigned-clocks = <&ccu CLK_DE_BE>;
                                #size-cells = <0>;
 
                                be0_in: port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       be0_in_fe0: endpoint@0 {
-                                               reg = <0>;
+                                       be0_in_fe0: endpoint {
                                                remote-endpoint = <&fe0_out_be0>;
                                        };
                                };
 
                                be0_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
 
-                                       be0_out_tcon0: endpoint@0 {
-                                               reg = <0>;
+                                       be0_out_tcon0: endpoint {
                                                remote-endpoint = <&tcon0_in_be0>;
                                        };
                                };
index 0b7bedf85fb9fa190555fa7a48ad7c8fdb1afbe2..c3d56dc93513f58bcfa2fbaa31da6fc5616084ae 100644 (file)
        i2c_lcd: i2c {
                /* The lcd panel i2c interface is hooked up via gpios */
                compatible = "i2c-gpio";
-               pinctrl-names = "default";
-               pinctrl-0 = <&i2c_lcd_pins>;
-               gpios = <&pio 0 23 GPIO_ACTIVE_HIGH>, /* PA23, sda */
-                       <&pio 0 24 GPIO_ACTIVE_HIGH>; /* PA24, scl */
+               sda-gpios = <&pio 0 23 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PA23 */
+               scl-gpios = <&pio 0 24 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PA24 */
                i2c-gpio,delay-us = <5>;
        };
 };
        status = "okay";
 };
 
-&pio {
-       i2c_lcd_pins: i2c-lcd-pins {
-               pins = "PA23", "PA24";
-               function = "gpio_out";
-               bias-pull-up;
-       };
-};
-
 &reg_usb2_vbus {
        gpio = <&pio 7 24 GPIO_ACTIVE_HIGH>;
        status = "okay";
index e17a65b3561e73629ad59a9a9fb4301104876e01..09832b4e8fc8544574256e0bb96d3351f5ac4c2c 100644 (file)
        vga-dac {
                compatible = "dumb-vga-dac";
                vdd-supply = <&reg_vga_3v3>;
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                ports {
                        #address-cells = <1>;
                        #size-cells = <0>;
 
                        port@0 {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
                                reg = <0>;
 
-                               vga_dac_in: endpoint@0 {
-                                       reg = <0>;
+                               vga_dac_in: endpoint {
                                        remote-endpoint = <&tcon0_out_vga>;
                                };
                        };
 
                        port@1 {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
                                reg = <1>;
 
-                               vga_dac_out: endpoint@0 {
-                                       reg = <0>;
+                               vga_dac_out: endpoint {
                                        remote-endpoint = <&vga_con_in>;
                                };
                        };
 };
 
 &usbphy {
-       usb0_id_det-gpio = <&pio 0 15 GPIO_ACTIVE_HIGH>; /* PA15 */
-       usb0_vbus_det-gpio = <&pio 0 16 GPIO_ACTIVE_HIGH>; /* PA16 */
+       usb0_id_det-gpios = <&pio 0 15 GPIO_ACTIVE_HIGH>; /* PA15 */
+       usb0_vbus_det-gpios = <&pio 0 16 GPIO_ACTIVE_HIGH>; /* PA16 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_drivevbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
index 0832ac5ae3eccc693d9616a6455245e74a6e375a..091eb2ac53b307c4845366ef9baaa6c8f43c9600 100644 (file)
 &spdif {
        pinctrl-names = "default";
        pinctrl-0 = <&spdif_tx_pin>;
-       spdif-out = "okay";
        status = "okay";
 };
 
index 13304b8c51390de7c31f67b1850ed5aca931a29f..c04efad81bbc9eb05135e6b84b7c786684b7ebf8 100644 (file)
                                      "tcon-ch0",
                                      "tcon-ch1";
                        clock-output-names = "tcon0-pixel-clock";
+                       #clock-cells = <0>;
 
                        ports {
                                #address-cells = <1>;
                                      "tcon-ch0",
                                      "tcon-ch1";
                        clock-output-names = "tcon1-pixel-clock";
+                       #clock-cells = <0>;
 
                        ports {
                                #address-cells = <1>;
                                };
 
                                hdmi_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
                                };
                        };
                        phys = <&usbphy 0>;
                        phy-names = "usb";
                        extcon = <&usbphy 0>;
+                       dr_mode = "otg";
                        status = "disabled";
                };
 
                        clocks = <&ccu CLK_AHB1_EHCI0>;
                        resets = <&ccu RST_AHB1_EHCI0>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        clocks = <&ccu CLK_AHB1_OHCI0>, <&ccu CLK_USB_OHCI0>;
                        resets = <&ccu RST_AHB1_OHCI0>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        clocks = <&ccu CLK_AHB1_EHCI1>;
                        resets = <&ccu RST_AHB1_EHCI1>;
                        phys = <&usbphy 2>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        clocks = <&ccu CLK_AHB1_OHCI1>, <&ccu CLK_USB_OHCI1>;
                        resets = <&ccu RST_AHB1_OHCI1>;
                        phys = <&usbphy 2>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                };
 
                gic: interrupt-controller@1c81000 {
-                       compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
+                       compatible = "arm,gic-400";
                        reg = <0x01c81000 0x1000>,
                              <0x01c82000 0x2000>,
                              <0x01c84000 0x2000>,
                                };
 
                                be0_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
 
-                                       be0_out_drc0: endpoint@0 {
-                                               reg = <0>;
+                                       be0_out_drc0: endpoint {
                                                remote-endpoint = <&drc0_in_be0>;
                                        };
                                };
                                #size-cells = <0>;
 
                                drc0_in: port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       drc0_in_be0: endpoint@0 {
-                                               reg = <0>;
+                                       drc0_in_be0: endpoint {
                                                remote-endpoint = <&be0_out_drc0>;
                                        };
                                };
                        gpio-controller;
                        interrupt-controller;
                        #interrupt-cells = <3>;
-                       #size-cells = <0>;
                        #gpio-cells = <3>;
 
                        s_ir_rx_pin: s-ir-rx-pin {
index 60b355f7184c8faa902cc249e38836e442cda846..bc3170a0b8b5b8ee3a5033af99b2a67c9de10447 100644 (file)
 };
 
 &usbphy {
-       usb0_id_det-gpio = <&pio 0 15 GPIO_ACTIVE_HIGH>; /* PA15 */
+       usb0_id_det-gpios = <&pio 0 15 GPIO_ACTIVE_HIGH>; /* PA15 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_drivevbus>;
        usb1_vbus-supply = <&reg_dldo1>;
index 86143de21c2215a289bd201b752da978bc21840d..7de2abd541c12f84a493c1f095ef97afad0290c3 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PA15";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 &p2wi {
        status = "okay";
 
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 0 15 GPIO_ACTIVE_HIGH>; /* PA15 */
+       usb0_id_det-gpios = <&pio 0 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PA15 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_drivevbus>;
        usb1_vbus-supply = <&reg_dldo1>;
index 81bc85d398c155573b128af188673a762591fba9..4df921632f7a17dd4781222d0d9a2d2505100522 100644 (file)
                        "SPI-MISO", "SPI-CE1", "",
                "IO-6", "IO-3", "IO-2", "IO-0", "", "", "", "",
                "", "", "", "", "", "", "", "";
-
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
 };
 
 #include "axp209.dtsi"
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
index 200685b0b1cb2ae30ccf06f81ca7cd0e8eb787f2..08e5a5abf8cce46c1627ac5ef93e9b365f448bb8 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 &reg_ahci_5v {
        status = "okay";
 };
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
        usb1_vbus-supply = <&reg_usb1_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
        status = "okay";
index f91e1bee44e8c3454d5214f72df87726adfb91a4..3e170cfac86aeab3cc805c7468d8748244aa723d 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 #include "axp209.dtsi"
 
 &ac_power_supply {
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
index 823aabce046253fac96dbd92e96771a7c0e40d74..c34a83f666c72e2a61a24de9ac772e8e8ca48d47 100644 (file)
 };
 
 &usbphy {
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
-       usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+       usb0_id_det-gpios = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+       usb0_vbus_det-gpios = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
index 5e411194bf62bbd876176c2e30ecbeea128d82b4..e40dd47df8ce350f67016e1d18575879fe1b5840 100644 (file)
                function = "gpio_out";
                drive-strength = <20>;
        };
-
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PH5";
-               function = "gpio_in";
-               bias-pull-down;
-       };
 };
 
 &reg_ahci_5v {
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
-       usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
+       usb0_vbus_det-gpios = <&pio 7 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* PH5 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
index 4e1c590eb09821bb7827029c203542e9e4e1eed1..95c6f8949076842882ebafd9ad0aad0cdfb92383 100644 (file)
 };
 
 &pio {
+       vcc-pa-supply = <&reg_vcc3v3>;
+       vcc-pc-supply = <&reg_vcc3v3>;
+       vcc-pe-supply = <&reg_ldo3>;
+       vcc-pf-supply = <&reg_vcc3v3>;
+       vcc-pg-supply = <&reg_ldo4>;
+
        led_pins_olinuxinolime: led-pins {
                pins = "PH2";
                function = "gpio_out";
                drive-strength = <20>;
        };
-
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PH5";
-               function = "gpio_in";
-               bias-pull-down;
-       };
 };
 
 &reg_ahci_5v {
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
-       usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
+       usb0_vbus_det-gpios = <&pio 7 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* PH5 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
index 840ae1194a66d90bc71f098466ea06a03f95de4a..0dcba070444af0e577afc0165e800d15c15a02ea 100644 (file)
                function = "gpio_out";
                drive-strength = <20>;
        };
-
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-
-       usb0_vbus_detect_pin: usb0-vbus-detect-pin {
-               pins = "PH5";
-               function = "gpio_in";
-               bias-pull-down;
-       };
 };
 
 #include "axp209.dtsi"
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
-       usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
+       usb0_vbus_det-gpios = <&pio 7 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* PH5 */
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
index 15881081cac403375ab643ca7594d4ccbf9b3a5b..9628041bb3a3275a3af62d3f9c620e6d65311b50 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 &reg_dcdc2 {
        regulator-always-on;
        regulator-min-microvolt = <1000000>;
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
index d64de2e73a9f5cfcf0126b973660cb82e8f51c59..7b3532665c2886a1516fadf84af0b5101c7b14a7 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 &reg_dcdc2 {
        regulator-always-on;
        regulator-min-microvolt = <1000000>;
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
index 538ea15fa32fe981eb5be25727ac82a6babdb3e5..173b676436e906f348aa005ec8295adb2035243f 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 &reg_ahci_5v {
        gpio = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */
        status = "okay";
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
        usb1_vbus-supply = <&reg_usb1_vbus>;
        usb2_vbus-supply = <&reg_usb1_vbus>;
        status = "okay";
index a72ed4318d044fc3bc844010777118d6921adf7e..14a88aa16a97a26fd461b1aef590864d6ce45709 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 &reg_ahci_5v {
        gpio = <&pio 7 2 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
        usb1_vbus-supply = <&reg_usb1_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
        status = "okay";
index ffade253d129614f6821040daf6e56db839ec7f7..6a66b0432dfa8dfcd9bb1e276919a5896c6d65ae 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 &pwm {
        pinctrl-names = "default";
        pinctrl-0 = <&pwm0_pin>;
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
index c27e56091fb19cb471b54b735cc2ffa106bcfcdc..f8475a39777bf131f286f6245847aa35c891b63c 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH4";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 &reg_dcdc2 {
        regulator-always-on;
        regulator-min-microvolt = <1000000>;
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+       usb0_id_det-gpios = <&pio 7 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH4 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_usb0_vbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
index 641a8fa6d4289a6d90642def481b82d92a7dee48..9ad8e445b24017be087f35ed4854313554105a0f 100644 (file)
                        #dma-cells = <2>;
                };
 
-               nfc: nand@1c03000 {
+               nfc: nand-controller@1c03000 {
                        compatible = "allwinner,sun4i-a10-nand";
                        reg = <0x01c03000 0x1000>;
                        interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
                                      "tcon-ch0",
                                      "tcon-ch1";
                        clock-output-names = "tcon0-pixel-clock";
+                       #clock-cells = <0>;
                        dmas = <&dma SUN4I_DMA_DEDICATED 14>;
 
                        ports {
                                      "tcon-ch0",
                                      "tcon-ch1";
                        clock-output-names = "tcon1-pixel-clock";
+                       #clock-cells = <0>;
                        dmas = <&dma SUN4I_DMA_DEDICATED 15>;
 
                        ports {
                        phy-names = "usb";
                        extcon = <&usbphy 0>;
                        allwinner,sram = <&otg_sram 1>;
+                       dr_mode = "otg";
                        status = "disabled";
                };
 
                usbphy: phy@1c13400 {
                        #phy-cells = <1>;
                        compatible = "allwinner,sun7i-a20-usb-phy";
-                       reg = <0x01c13400 0x10 0x01c14800 0x4 0x01c1c800 0x4>;
+                       reg = <0x01c13400 0x10>, <0x01c14800 0x4>, <0x01c1c800 0x4>;
                        reg-names = "phy_ctrl", "pmu1", "pmu2";
                        clocks = <&ccu CLK_USB_PHY>;
                        clock-names = "usb_phy";
                        interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_AHB_EHCI0>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_USB_OHCI0>, <&ccu CLK_AHB_OHCI0>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_AHB_EHCI1>;
                        phys = <&usbphy 2>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_USB_OHCI1>, <&ccu CLK_AHB_OHCI1>;
                        phys = <&usbphy 2>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        #interrupt-cells = <3>;
                        #gpio-cells = <3>;
 
+                       /omit-if-no-ref/
+                       can_pa_pins: can-pa-pins {
+                               pins = "PA16", "PA17";
+                               function = "can";
+                       };
+
+                       /omit-if-no-ref/
                        can_ph_pins: can-ph-pins {
                                pins = "PH20", "PH21";
                                function = "can";
                        };
 
+                       /omit-if-no-ref/
                        clk_out_a_pin: clk-out-a-pin {
                                pins = "PI12";
                                function = "clk_out_a";
                        };
 
+                       /omit-if-no-ref/
                        clk_out_b_pin: clk-out-b-pin {
                                pins = "PI13";
                                function = "clk_out_b";
                        };
 
+                       /omit-if-no-ref/
                        emac_pa_pins: emac-pa-pins {
                                pins = "PA0", "PA1", "PA2",
                                       "PA3", "PA4", "PA5", "PA6",
                                function = "emac";
                        };
 
+                       /omit-if-no-ref/
+                       emac_ph_pins: emac-ph-pins {
+                               pins = "PH8", "PH9", "PH10", "PH11",
+                                      "PH14", "PH15", "PH16", "PH17",
+                                      "PH18", "PH19", "PH20", "PH21",
+                                      "PH22", "PH23", "PH24", "PH25",
+                                      "PH26";
+                               function = "emac";
+                       };
+
+                       /omit-if-no-ref/
                        gmac_mii_pins: gmac-mii-pins {
                                pins = "PA0", "PA1", "PA2",
                                       "PA3", "PA4", "PA5", "PA6",
                                function = "gmac";
                        };
 
+                       /omit-if-no-ref/
                        gmac_rgmii_pins: gmac-rgmii-pins {
                                pins = "PA0", "PA1", "PA2",
                                       "PA3", "PA4", "PA5", "PA6",
                                drive-strength = <40>;
                        };
 
+                       /omit-if-no-ref/
                        i2c0_pins: i2c0-pins {
                                pins = "PB0", "PB1";
                                function = "i2c0";
                        };
 
+                       /omit-if-no-ref/
                        i2c1_pins: i2c1-pins {
                                pins = "PB18", "PB19";
                                function = "i2c1";
                        };
 
+                       /omit-if-no-ref/
                        i2c2_pins: i2c2-pins {
                                pins = "PB20", "PB21";
                                function = "i2c2";
                        };
 
+                       /omit-if-no-ref/
                        i2c3_pins: i2c3-pins {
                                pins = "PI0", "PI1";
                                function = "i2c3";
                        };
 
+                       /omit-if-no-ref/
                        ir0_rx_pin: ir0-rx-pin {
                                pins = "PB4";
                                function = "ir0";
                        };
 
+                       /omit-if-no-ref/
                        ir0_tx_pin: ir0-tx-pin {
                                pins = "PB3";
                                function = "ir0";
                        };
 
+                       /omit-if-no-ref/
                        ir1_rx_pin: ir1-rx-pin {
                                pins = "PB23";
                                function = "ir1";
                        };
 
+                       /omit-if-no-ref/
                        ir1_tx_pin: ir1-tx-pin {
                                pins = "PB22";
                                function = "ir1";
                        };
 
+                       /omit-if-no-ref/
                        mmc0_pins: mmc0-pins {
                                pins = "PF0", "PF1", "PF2",
                                       "PF3", "PF4", "PF5";
                                bias-pull-up;
                        };
 
+                       /omit-if-no-ref/
                        mmc2_pins: mmc2-pins {
                                pins = "PC6", "PC7", "PC8",
                                       "PC9", "PC10", "PC11";
                                bias-pull-up;
                        };
 
+                       /omit-if-no-ref/
                        mmc3_pins: mmc3-pins {
                                pins = "PI4", "PI5", "PI6",
                                       "PI7", "PI8", "PI9";
                                bias-pull-up;
                        };
 
+                       /omit-if-no-ref/
                        ps2_0_pins: ps2-0-pins {
                                pins = "PI20", "PI21";
                                function = "ps2";
                        };
 
+                       /omit-if-no-ref/
                        ps2_1_ph_pins: ps2-1-ph-pins {
                                pins = "PH12", "PH13";
                                function = "ps2";
                        };
 
+                       /omit-if-no-ref/
                        pwm0_pin: pwm0-pin {
                                pins = "PB2";
                                function = "pwm";
                        };
 
+                       /omit-if-no-ref/
                        pwm1_pin: pwm1-pin {
                                pins = "PI3";
                                function = "pwm";
                        };
 
+                       /omit-if-no-ref/
                        spdif_tx_pin: spdif-tx-pin {
                                pins = "PB13";
                                function = "spdif";
                                bias-pull-up;
                        };
 
+                       /omit-if-no-ref/
                        spi0_pi_pins: spi0-pi-pins {
                                pins = "PI11", "PI12", "PI13";
                                function = "spi0";
                        };
 
+                       /omit-if-no-ref/
                        spi0_cs0_pi_pin: spi0-cs0-pi-pin {
                                pins = "PI10";
                                function = "spi0";
                        };
 
+                       /omit-if-no-ref/
                        spi0_cs1_pi_pin: spi0-cs1-pi-pin {
                                pins = "PI14";
                                function = "spi0";
                        };
 
+                       /omit-if-no-ref/
                        spi1_pi_pins: spi1-pi-pins {
                                pins = "PI17", "PI18", "PI19";
                                function = "spi1";
                        };
 
+                       /omit-if-no-ref/
                        spi1_cs0_pi_pin: spi1-cs0-pi-pin {
                                pins = "PI16";
                                function = "spi1";
                        };
 
+                       /omit-if-no-ref/
                        spi2_pb_pins: spi2-pb-pins {
                                pins = "PB15", "PB16", "PB17";
                                function = "spi2";
                        };
 
+                       /omit-if-no-ref/
                        spi2_cs0_pb_pin: spi2-cs0-pb-pin {
                                pins = "PB14";
                                function = "spi2";
                        };
 
+                       /omit-if-no-ref/
                        spi2_pc_pins: spi2-pc-pins {
                                pins = "PC20", "PC21", "PC22";
                                function = "spi2";
                        };
 
+                       /omit-if-no-ref/
                        spi2_cs0_pc_pin: spi2-cs0-pc-pin {
                                pins = "PC19";
                                function = "spi2";
                        };
 
+                       /omit-if-no-ref/
                        uart0_pb_pins: uart0-pb-pins {
                                pins = "PB22", "PB23";
                                function = "uart0";
                        };
 
+                       /omit-if-no-ref/
+                       uart0_pf_pins: uart0-pf-pins {
+                               pins = "PF2", "PF4";
+                               function = "uart0";
+                       };
+
+                       /omit-if-no-ref/
+                       uart1_pa_pins: uart1-pa-pins {
+                               pins = "PA10", "PA11";
+                               function = "uart1";
+                       };
+
+                       /omit-if-no-ref/
+                       uart1_cts_rts_pa_pins: uart1-cts-rts-pa-pins {
+                               pins = "PA12", "PA13";
+                               function = "uart1";
+                       };
+
+                       /omit-if-no-ref/
+                       uart2_pa_pins: uart2-pa-pins {
+                               pins = "PA2", "PA3";
+                               function = "uart2";
+                       };
+
+                       /omit-if-no-ref/
+                       uart2_cts_rts_pa_pins: uart2-cts-rts-pa-pins {
+                               pins = "PA0", "PA1";
+                               function = "uart2";
+                       };
+
+                       /omit-if-no-ref/
                        uart2_pi_pins: uart2-pi-pins {
                                pins = "PI18", "PI19";
                                function = "uart2";
                        };
 
+                       /omit-if-no-ref/
                        uart2_cts_rts_pi_pins: uart2-cts-rts-pi-pins {
                                pins = "PI16", "PI17";
                                function = "uart2";
                        };
 
+                       /omit-if-no-ref/
                        uart3_pg_pins: uart3-pg-pins {
                                pins = "PG6", "PG7";
                                function = "uart3";
                        };
 
+                       /omit-if-no-ref/
                        uart3_cts_rts_pg_pins: uart3-cts-rts-pg-pins {
                                pins = "PG8", "PG9";
                                function = "uart3";
                        };
 
+                       /omit-if-no-ref/
                        uart3_ph_pins: uart3-ph-pins {
                                pins = "PH0", "PH1";
                                function = "uart3";
                        };
 
+                       /omit-if-no-ref/
+                       uart3_cts_rts_ph_pins: uart3-cts-rts-ph-pins {
+                               pins = "PH2", "PH3";
+                               function = "uart3";
+                       };
+
+                       /omit-if-no-ref/
                        uart4_pg_pins: uart4-pg-pins {
                                pins = "PG10", "PG11";
                                function = "uart4";
                        };
 
+                       /omit-if-no-ref/
                        uart4_ph_pins: uart4-ph-pins {
                                pins = "PH4", "PH5";
                                function = "uart4";
                        };
 
+                       /omit-if-no-ref/
+                       uart5_ph_pins: uart5-ph-pins {
+                               pins = "PH6", "PH7";
+                               function = "uart5";
+                       };
+
+                       /omit-if-no-ref/
                        uart5_pi_pins: uart5-pi-pins {
                                pins = "PI10", "PI11";
                                function = "uart5";
                        };
 
+                       /omit-if-no-ref/
+                       uart6_pa_pins: uart6-pa-pins {
+                               pins = "PA12", "PA13";
+                               function = "uart6";
+                       };
+
+                       /omit-if-no-ref/
                        uart6_pi_pins: uart6-pi-pins {
                                pins = "PI12", "PI13";
                                function = "uart6";
                        };
 
+                       /omit-if-no-ref/
+                       uart7_pa_pins: uart7-pa-pins {
+                               pins = "PA14", "PA15";
+                               function = "uart7";
+                       };
+
+                       /omit-if-no-ref/
                        uart7_pi_pins: uart7-pi-pins {
                                pins = "PI20", "PI21";
                                function = "uart7";
                };
 
                gic: interrupt-controller@1c81000 {
-                       compatible = "arm,gic-400", "arm,cortex-a7-gic", "arm,cortex-a15-gic";
+                       compatible = "arm,gic-400";
                        reg = <0x01c81000 0x1000>,
                              <0x01c82000 0x2000>,
                              <0x01c84000 0x2000>,
index 43fe215e83ea17ac7c8d12e7eaf2e03ab2269d9e..af2fa694a467b0f4459aa5f17f6a0069d284c5ff 100644 (file)
                        #dma-cells = <1>;
                };
 
-               nfc: nand@1c03000 {
-                       compatible = "allwinner,sun4i-a10-nand";
+               nfc: nand-controller@1c03000 {
+                       compatible = "allwinner,sun8i-a23-nand-controller";
                        reg = <0x01c03000 0x1000>;
                        interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_NAND>, <&ccu CLK_NAND>;
                        clock-names = "ahb", "mod";
                        resets = <&ccu RST_BUS_NAND>;
                        reset-names = "ahb";
+                       dmas = <&dma 5>;
+                       dma-names = "rxtx";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&nand_pins &nand_cs0_pin &nand_rb0_pin>;
                        status = "disabled";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        clock-names = "ahb",
                                      "tcon-ch0";
                        clock-output-names = "tcon-pixel-clock";
+                       #clock-cells = <0>;
                        resets = <&ccu RST_BUS_LCD>;
                        reset-names = "lcd";
                        status = "disabled";
                                #size-cells = <0>;
 
                                tcon0_in: port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       tcon0_in_drc0: endpoint@0 {
-                                               reg = <0>;
+                                       tcon0_in_drc0: endpoint {
                                                remote-endpoint = <&drc0_out_tcon0>;
                                        };
                                };
 
                                tcon0_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
                                };
                        };
                        phys = <&usbphy 0>;
                        phy-names = "usb";
                        extcon = <&usbphy 0>;
+                       dr_mode = "otg";
                        status = "disabled";
                };
 
                        clocks = <&ccu CLK_BUS_EHCI>;
                        resets = <&ccu RST_BUS_EHCI>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        clocks = <&ccu CLK_BUS_OHCI>, <&ccu CLK_USB_OHCI>;
                        resets = <&ccu RST_BUS_OHCI>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                                function = "nand0";
                        };
 
-                       nand_pins_cs0: nand-pins-cs0 {
+                       nand_cs0_pin: nand-cs0-pin {
                                pins = "PC4";
                                function = "nand0";
                                bias-pull-up;
                        };
 
-                       nand_pins_cs1: nand-pins-cs1 {
+                       nand_cs1_pin: nand-cs1-pin {
                                pins = "PC3";
                                function = "nand0";
                                bias-pull-up;
                        };
 
-                       nand_pins_rb0: nand-pins-rb0 {
+                       nand_rb0_pin: nand-rb0-pin {
                                pins = "PC6";
                                function = "nand0";
                                bias-pull-up;
                        };
 
-                       nand_pins_rb1: nand-pins-rb1 {
+                       nand_rb1_pin: nand-rb1-pin {
                                pins = "PC7";
                                function = "nand0";
                                bias-pull-up;
                };
 
                gic: interrupt-controller@1c81000 {
-                       compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
+                       compatible = "arm,gic-400";
                        reg = <0x01c81000 0x1000>,
                              <0x01c82000 0x2000>,
                              <0x01c84000 0x2000>,
                                #size-cells = <0>;
 
                                fe0_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
 
-                                       fe0_out_be0: endpoint@0 {
-                                               reg = <0>;
+                                       fe0_out_be0: endpoint {
                                                remote-endpoint = <&be0_in_fe0>;
                                        };
                                };
                                #size-cells = <0>;
 
                                be0_in: port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       be0_in_fe0: endpoint@0 {
-                                               reg = <0>;
+                                       be0_in_fe0: endpoint {
                                                remote-endpoint = <&fe0_out_be0>;
                                        };
                                };
 
                                be0_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
 
-                                       be0_out_drc0: endpoint@0 {
-                                               reg = <0>;
+                                       be0_out_drc0: endpoint {
                                                remote-endpoint = <&drc0_in_be0>;
                                        };
                                };
                                #size-cells = <0>;
 
                                drc0_in: port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       drc0_in_be0: endpoint@0 {
-                                               reg = <0>;
+                                       drc0_in_be0: endpoint {
                                                remote-endpoint = <&be0_out_drc0>;
                                        };
                                };
 
                                drc0_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
 
-                                       drc0_out_tcon0: endpoint@0 {
-                                               reg = <0>;
+                                       drc0_out_tcon0: endpoint {
                                                remote-endpoint = <&tcon0_in_drc0>;
                                        };
                                };
                        status = "disabled";
                };
 
+               r_i2c: i2c@1f02400 {
+                       compatible = "allwinner,sun8i-a23-i2c",
+                                    "allwinner,sun6i-a31-i2c";
+                       reg = <0x01f02400 0x400>;
+                       interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&r_i2c_pins>;
+                       clocks = <&apb0_gates 6>;
+                       resets = <&apb0_rst 6>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
                r_pio: pinctrl@1f02c00 {
                        compatible = "allwinner,sun8i-a23-r-pinctrl";
                        reg = <0x01f02c00 0x400>;
                        #interrupt-cells = <3>;
                        #gpio-cells = <3>;
 
+                       r_i2c_pins: r-i2c-pins {
+                               pins = "PL0", "PL1";
+                               function = "s_i2c";
+                               bias-pull-up;
+                       };
+
                        r_rsb_pins: r-rsb-pins {
                                pins = "PL0", "PL1";
                                function = "s_rsb";
index d4dab7c283988b9cd6733d89a7b86eed38d56863..5659c63d7d777f21029625e22769d0288743d0ec 100644 (file)
@@ -65,3 +65,9 @@
 &panel {
        compatible = "bananapi,s070wv20-ct16", "simple-panel";
 };
+
+&tcon0_out {
+       tcon0_out_lcd: endpoint {
+               remote-endpoint = <&panel_input>;
+       };
+};
index b0bc2360f8c4954c41a0b70de47ae691bc4fa8b2..9c5750c25613f98be37dd59ffc87a11c29ecb082 100644 (file)
        model = "Q8 A33 Tablet";
        compatible = "allwinner,q8-a33", "allwinner,sun8i-a33";
 };
+
+&tcon0_out {
+       tcon0_out_lcd: endpoint@0 {
+               reg = <0>;
+               remote-endpoint = <&panel_input>;
+       };
+};
index f3667268addebb27816c33af7f28ebe314c08379..785798e3a104296c490cfb9a5e193bedebf43981 100644 (file)
 
        panel {
                compatible = "netron-dy,e231732";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               port@0 {
-                       reg = <0>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       panel_input: endpoint@0 {
-                               reg = <0>;
+               port {
+                       panel_input: endpoint {
                                remote-endpoint = <&tcon0_out_panel>;
                        };
                };
index 1111a64981023cd8bc9c7ac5b4e05b416632dd50..1532a0e59af4d28810d994aae73b7de566c2cb3c 100644 (file)
                        phys = <&dphy>;
                        phy-names = "dphy";
                        status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
 
-                       ports {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-
-                               port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
-                                       reg = <0>;
-
-                                       dsi_in_tcon0: endpoint {
-                                               remote-endpoint = <&tcon0_out_dsi>;
-                                       };
+                       port {
+                               dsi_in_tcon0: endpoint {
+                                       remote-endpoint = <&tcon0_out_dsi>;
                                };
                        };
                };
 };
 
 &tcon0_out {
+       #address-cells = <1>;
+       #size-cells = <0>;
+
        tcon0_out_dsi: endpoint@1 {
                reg = <1>;
                remote-endpoint = <&dsi_in_tcon0>;
index 838be7b3715fc07de9ed33b0907108e466a0f7c9..9d34eabba121374bd4ecd6dd80cadc946ae656ce 100644 (file)
        };
 };
 
+&usb_otg {
+       dr_mode = "otg";
+       status = "okay";
+};
+
+&usb_power_supply {
+       status = "okay";
+};
+
 &usbphy {
+       usb0_id_det-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
+       usb0_vbus_power-supply = <&usb_power_supply>;
+       usb0_vbus-supply = <&reg_drivevbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
        status = "okay";
 };
index fcbec3d7ccd78461a167edeb59e93e03a5cdfe7b..ea299d3d84d0c5a63ea1a61b0856d85e21ac7aed 100644 (file)
        };
 };
 
+&usb_otg {
+       dr_mode = "otg";
+       status = "okay";
+};
+
+&usb_power_supply {
+       status = "okay";
+};
+
 &usbphy {
+       usb0_id_det-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
+       usb0_vbus_power-supply = <&usb_power_supply>;
+       usb0_vbus-supply = <&reg_drivevbus>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
        usb2_vbus-supply = <&reg_usb2_vbus>;
        status = "okay";
index 98e8cea26dbede6adcb3ff518994af53ec0eba10..66d078053d5fbbe1cba08f16a55a67fd9a46f29b 100644 (file)
@@ -46,6 +46,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pwm/pwm.h>
+#include <dt-bindings/input/input.h>
 
 / {
        model = "TBS A711 Tablet";
                };
        };
 
+       reg_gps: reg-gps {
+               compatible = "regulator-fixed";
+               regulator-name = "gps";
+               regulator-min-microvolt = <3000000>;
+               regulator-max-microvolt = <3000000>;
+       };
+
        reg_vbat: reg-vbat {
                compatible = "regulator-fixed";
                regulator-name = "vbat";
        status = "okay";
 };
 
+&i2c1 {
+       clock-frequency = <400000>;
+       status = "okay";
+
+       accelerometer@18 {
+               compatible = "bosch,bma250";
+               reg = <0x18>;
+               interrupt-parent = <&pio>;
+               interrupts = <7 10 IRQ_TYPE_EDGE_RISING>; /* PH10 / EINT10 */
+       };
+};
+
 &mmc0 {
        vmmc-supply = <&reg_dcdc1>;
        pinctrl-names = "default";
        status = "okay";
 };
 
+&r_lradc {
+       vref-supply = <&reg_aldo2>;
+       status = "okay";
+
+       button@210 {
+               label = "Volume Up";
+               linux,code = <KEY_VOLUMEUP>;
+               channel = <0>;
+               voltage = <210000>;
+       };
+
+       button@410 {
+               label = "Volume Down";
+               linux,code = <KEY_VOLUMEDOWN>;
+               channel = <0>;
+               voltage = <410000>;
+       };
+};
+
 &r_rsb {
        status = "okay";
 
 };
 
 &tcon0_out {
-       tcon0_out_lcd: endpoint@0 {
-               reg = <0>;
+       tcon0_out_lcd: endpoint {
                remote-endpoint = <&panel_input>;
        };
 };
 &uart1 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+       uart-has-rtscts;
+       status = "okay";
+
+       bluetooth {
+               compatible = "brcm,bcm20702a1";
+               clocks = <&ac100_rtc 1>;
+               clock-names = "lpo";
+               vbat-supply = <&reg_vbat>;
+               vddio-supply = <&reg_dldo1>;
+               device-wakeup-gpios = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+               host-wakeup-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 */
+               shutdown-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */
+               max-speed = <1500000>;
+       };
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart2_pb_pins>;
        status = "okay";
+
+       gnss {
+               compatible = "u-blox,neo-6m";
+
+               v-bckp-supply = <&reg_rtc_ldo>;
+               vcc-supply = <&reg_gps>;
+               current-speed = <9600>;
+       };
 };
 
 &usb_otg {
 &usbphy {
        usb0_id_det-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
        usb0_vbus-supply = <&reg_drivevbus>;
-       usb1_vbus_supply = <&reg_vmain>;
-       usb2_vbus_supply = <&reg_vmain>;
+       usb1_vbus-supply = <&reg_vmain>;
+       usb2_vbus-supply = <&reg_vmain>;
        status = "okay";
 };
index b099d2fbb5cd739bc4076ca2bb507ccc67d2d044..392b0cabbf0d34621965fb3021a70b062dcb3c76 100644 (file)
                #size-cells = <0>;
 
                cpu0: cpu@0 {
-                       clocks = <&ccu CLK_C0CPUX>;
-                       clock-names = "cpu";
                        compatible = "arm,cortex-a7";
                        device_type = "cpu";
+                       clocks = <&ccu CLK_C0CPUX>;
                        operating-points-v2 = <&cpu0_opp_table>;
                        cci-control-port = <&cci_control0>;
                        enable-method = "allwinner,sun8i-a83t-smp";
                        reg = <0>;
+                       #cooling-cells = <2>;
                };
 
                cpu@1 {
                        compatible = "arm,cortex-a7";
                        device_type = "cpu";
+                       clocks = <&ccu CLK_C0CPUX>;
                        operating-points-v2 = <&cpu0_opp_table>;
                        cci-control-port = <&cci_control0>;
                        enable-method = "allwinner,sun8i-a83t-smp";
                        reg = <1>;
+                       #cooling-cells = <2>;
                };
 
                cpu@2 {
                        compatible = "arm,cortex-a7";
                        device_type = "cpu";
+                       clocks = <&ccu CLK_C0CPUX>;
                        operating-points-v2 = <&cpu0_opp_table>;
                        cci-control-port = <&cci_control0>;
                        enable-method = "allwinner,sun8i-a83t-smp";
                        reg = <2>;
+                       #cooling-cells = <2>;
                };
 
                cpu@3 {
                        compatible = "arm,cortex-a7";
                        device_type = "cpu";
+                       clocks = <&ccu CLK_C0CPUX>;
                        operating-points-v2 = <&cpu0_opp_table>;
                        cci-control-port = <&cci_control0>;
                        enable-method = "allwinner,sun8i-a83t-smp";
                        reg = <3>;
+                       #cooling-cells = <2>;
                };
 
                cpu100: cpu@100 {
-                       clocks = <&ccu CLK_C1CPUX>;
-                       clock-names = "cpu";
                        compatible = "arm,cortex-a7";
                        device_type = "cpu";
+                       clocks = <&ccu CLK_C1CPUX>;
                        operating-points-v2 = <&cpu1_opp_table>;
                        cci-control-port = <&cci_control1>;
                        enable-method = "allwinner,sun8i-a83t-smp";
                        reg = <0x100>;
+                       #cooling-cells = <2>;
                };
 
                cpu@101 {
                        compatible = "arm,cortex-a7";
                        device_type = "cpu";
+                       clocks = <&ccu CLK_C1CPUX>;
                        operating-points-v2 = <&cpu1_opp_table>;
                        cci-control-port = <&cci_control1>;
                        enable-method = "allwinner,sun8i-a83t-smp";
                        reg = <0x101>;
+                       #cooling-cells = <2>;
                };
 
                cpu@102 {
                        compatible = "arm,cortex-a7";
                        device_type = "cpu";
+                       clocks = <&ccu CLK_C1CPUX>;
                        operating-points-v2 = <&cpu1_opp_table>;
                        cci-control-port = <&cci_control1>;
                        enable-method = "allwinner,sun8i-a83t-smp";
                        reg = <0x102>;
+                       #cooling-cells = <2>;
                };
 
                cpu@103 {
                        compatible = "arm,cortex-a7";
                        device_type = "cpu";
+                       clocks = <&ccu CLK_C1CPUX>;
                        operating-points-v2 = <&cpu1_opp_table>;
                        cci-control-port = <&cci_control1>;
                        enable-method = "allwinner,sun8i-a83t-smp";
                        reg = <0x103>;
+                       #cooling-cells = <2>;
                };
        };
 
                                                reg = <0>;
                                                remote-endpoint = <&tcon0_in_mixer0>;
                                        };
+
+                                       mixer0_out_tcon1: endpoint@1 {
+                                               reg = <1>;
+                                               remote-endpoint = <&tcon1_in_mixer0>;
+                                       };
                                };
                        };
                };
                                #size-cells = <0>;
 
                                mixer1_out: port@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
                                        reg = <1>;
 
-                                       mixer1_out_tcon1: endpoint {
+                                       mixer1_out_tcon0: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&tcon0_in_mixer1>;
+                                       };
+
+                                       mixer1_out_tcon1: endpoint@1 {
+                                               reg = <1>;
                                                remote-endpoint = <&tcon1_in_mixer1>;
                                        };
                                };
                        clocks = <&ccu CLK_BUS_TCON0>, <&ccu CLK_TCON0>;
                        clock-names = "ahb", "tcon-ch0";
                        clock-output-names = "tcon-pixel-clock";
+                       #clock-cells = <0>;
                        resets = <&ccu RST_BUS_TCON0>, <&ccu RST_BUS_LVDS>;
                        reset-names = "lcd", "lvds";
 
                                                reg = <0>;
                                                remote-endpoint = <&mixer0_out_tcon0>;
                                        };
+
+                                       tcon0_in_mixer1: endpoint@1 {
+                                               reg = <1>;
+                                               remote-endpoint = <&mixer1_out_tcon0>;
+                                       };
                                };
 
                                tcon0_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
                                };
                        };
                                #size-cells = <0>;
 
                                tcon1_in: port@0 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       tcon1_in_mixer1: endpoint {
+                                       tcon1_in_mixer0: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&mixer0_out_tcon1>;
+                                       };
+
+                                       tcon1_in_mixer1: endpoint@1 {
+                                               reg = <1>;
                                                remote-endpoint = <&mixer1_out_tcon1>;
                                        };
                                };
                        phys = <&usbphy 0>;
                        phy-names = "usb";
                        extcon = <&usbphy 0>;
+                       dr_mode = "otg";
                        status = "disabled";
                };
 
                        clocks = <&ccu CLK_BUS_EHCI0>;
                        resets = <&ccu RST_BUS_EHCI0>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        clocks = <&ccu CLK_BUS_OHCI0>, <&ccu CLK_USB_OHCI0>;
                        resets = <&ccu RST_BUS_OHCI0>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        clocks = <&ccu CLK_BUS_EHCI1>;
                        resets = <&ccu RST_BUS_EHCI1>;
                        phys = <&usbphy 2>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                                function = "i2c1";
                        };
 
+                       /omit-if-no-ref/
+                       i2c2_pe_pins: i2c2-pe-pins {
+                               pins = "PE14", "PE15";
+                               function = "i2c2";
+                       };
+
                        i2c2_ph_pins: i2c2-ph-pins {
                                pins = "PH4", "PH5";
                                function = "i2c2";
                                pins = "PG8", "PG9";
                                function = "uart1";
                        };
+
+                       /omit-if-no-ref/
+                       uart2_pb_pins: uart2-pb-pins {
+                               pins = "PB0", "PB1";
+                               function = "uart2";
+                       };
                };
 
                timer@1c20c00 {
                        status = "disabled";
                };
 
+               uart2: serial@1c28800 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0x01c28800 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@1c28c00 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0x01c28c00 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@1c29000 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0x01c29000 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";
+               };
+
                i2c0: i2c@1c2ac00 {
                        compatible = "allwinner,sun8i-a83t-i2c",
                                     "allwinner,sun6i-a31-i2c";
                };
 
                gic: interrupt-controller@1c81000 {
-                       compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
+                       compatible = "arm,gic-400";
                        reg = <0x01c81000 0x1000>,
                              <0x01c82000 0x2000>,
                              <0x01c84000 0x2000>,
                        status = "disabled";
                };
 
+               r_lradc: lradc@1f03c00 {
+                       compatible = "allwinner,sun8i-a83t-r-lradc";
+                       reg = <0x01f03c00 0x100>;
+                       interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "disabled";
+               };
+
                r_pio: pinctrl@1f02c00 {
                        compatible = "allwinner,sun8i-a83t-r-pinctrl";
                        reg = <0x01f02c00 0x400>;
index 1db2541135a74427e7a0cc0900af4fa789622cee..78a37a47185a0930a1fcf77ab7d62a47f432aaf2 100644 (file)
@@ -28,7 +28,6 @@
 
        leds {
                compatible = "gpio-leds";
-               pinctrl-names = "default";
 
                pwr_led {
                        label = "bananapi-m2-zero:red:pwr";
@@ -39,7 +38,6 @@
 
        gpio_keys {
                compatible = "gpio-keys";
-               pinctrl-names = "default";
 
                sw4 {
                        label = "power";
@@ -67,8 +65,9 @@
 
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
-               pinctrl-names = "default";
                reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
+               clocks = <&rtc 1>;
+               clock-names = "ext_clock";
        };
 };
 
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
 &uart1 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+       uart-has-rtscts;
        status = "okay";
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               clocks = <&rtc 1>;
+               clock-names = "lpo";
+               vbat-supply = <&reg_vcc3v3>;
+               vddio-supply = <&reg_vcc3v3>;
+               device-wakeup-gpios = <&pio 6 13 GPIO_ACTIVE_HIGH>; /* PG13 */
+               host-wakeup-gpios = <&pio 6 11 GPIO_ACTIVE_HIGH>; /* PG11 */
+               shutdown-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+       };
+
 };
 
 &usb_otg {
index 84cd9c06122752e226f55b532890fde654ecf4c9..4970eda2877e1174df30d08b221b8f0758afd4f0 100644 (file)
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index 25540b7694d590dea1c3c54c5453d4a7217d9f37..6277f13f3eb32ec3a5878fa5f7cc69287815fce5 100644 (file)
 
 &ir {
        pinctrl-names = "default";
-       pinctrl-0 = <&ir_pins_a>;
+       pinctrl-0 = <&r_ir_rx_pin>;
        status = "okay";
 };
 
 
 &spdif {
        pinctrl-names = "default";
-       pinctrl-0 = <&spdif_tx_pins_a>;
+       pinctrl-0 = <&spdif_tx_pin>;
        status = "okay";
 };
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index 2c952eacfef5299689c484eda3f138772a8b43f0..ff0a7a952e0c1add68b0769df6914ab12087e8e8 100644 (file)
 
 &ir {
        pinctrl-names = "default";
-       pinctrl-0 = <&ir_pins_a>;
+       pinctrl-0 = <&r_ir_rx_pin>;
        status = "okay";
 };
 
 &mmc0 {
        vmmc-supply = <&reg_vcc3v3>;
        bus-width = <4>;
-       cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
-       cd-inverted;
+       cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
        status = "okay";
 };
 
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index 4ec94d72f02193a13e9537778bdbc0843ce3e34d..4ba533b0340f220c9ce38aba9a693bcf42e8d1a4 100644 (file)
@@ -64,7 +64,6 @@
 
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
-               pinctrl-names = "default";
                reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
        };
 
 
 &ir {
        pinctrl-names = "default";
-       pinctrl-0 = <&ir_pins_a>;
+       pinctrl-0 = <&r_ir_rx_pin>;
        status = "okay";
 };
 
index 9412668bb8881cf4e4f5aa700e209da1aa1a6eac..69243dcb30a61782c56b4217ff9e06685ccfcec2 100644 (file)
@@ -93,7 +93,7 @@
 
 &ir {
        pinctrl-names = "default";
-       pinctrl-0 = <&ir_pins_a>;
+       pinctrl-0 = <&r_ir_rx_pin>;
        status = "okay";
 };
 
index 6246d3eff39dec1a149d45455b2b41604b3a463b..07867a0d569b0a3b75d19255eab48857dc712124 100644 (file)
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index f110ee3822398eae337c2e435e9a06375163754e..4df29a65316df98a243df2702e8bdb0c2d69f0e9 100644 (file)
@@ -59,8 +59,6 @@
 
        leds {
                compatible = "gpio-leds";
-               pinctrl-names = "default";
-               pinctrl-0 = <&leds_npi>, <&leds_r_npi>;
 
                status {
                        label = "nanopi:blue:status";
@@ -78,8 +76,6 @@
        r_gpio_keys {
                compatible = "gpio-keys";
                input-name = "k1";
-               pinctrl-names = "default";
-               pinctrl-0 = <&sw_r_npi>;
 
                k1 {
                        label = "k1";
        status = "okay";
 };
 
-&pio {
-       leds_npi: led_pins {
-               pins = "PA10";
-               function = "gpio_out";
-       };
-};
-
-&r_pio {
-       leds_r_npi: led_pins {
-               pins = "PL10";
-               function = "gpio_out";
-       };
-
-       sw_r_npi: key_pins {
-               pins = "PL3";
-               function = "gpio_in";
-       };
-};
-
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index f1fc6bdca8be711d0ba0b03fc22c551754db1f92..597c425d08ecd96e10f6766adeb4a9a62f867eca 100644 (file)
@@ -75,8 +75,6 @@
 
        leds {
                compatible = "gpio-leds";
-               pinctrl-names = "default";
-               pinctrl-0 = <&leds_opc>, <&leds_r_opc>;
 
                status_led {
                        label = "orangepi:red:status";
@@ -92,8 +90,6 @@
 
        r_gpio_keys {
                compatible = "gpio-keys";
-               pinctrl-names = "default";
-               pinctrl-0 = <&sw_r_opc>;
 
                sw2 {
                        label = "sw2";
 
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
-               pinctrl-names = "default";
-               pinctrl-0 = <&wifi_pwrseq_pin_orangepi>;
                reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 WIFI_EN */
        };
 };
 
 &ir {
        pinctrl-names = "default";
-       pinctrl-0 = <&ir_pins_a>;
+       pinctrl-0 = <&r_ir_rx_pin>;
        status = "okay";
 };
 
        };
 };
 
-&pio {
-       leds_opc: led_pins {
-               pins = "PA15";
-               function = "gpio_out";
-       };
-};
-
-&r_pio {
-       leds_r_opc: led_pins {
-               pins = "PL10";
-               function = "gpio_out";
-       };
-
-       sw_r_opc: key_pins {
-               pins = "PL3", "PL4";
-               function = "gpio_in";
-       };
-
-       wifi_pwrseq_pin_orangepi: wifi_pwrseq_pin {
-               pins = "PL7";
-               function = "gpio_out";
-       };
-};
-
 &reg_usb1_vbus {
        gpio = <&pio 6 13 GPIO_ACTIVE_HIGH>;
        status = "okay";
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index 476ae8e387ca2ba3f7223213ffa1f4adbae88203..6f9c97add54e686898b53d4a2a4cc6e2f1332ecf 100644 (file)
@@ -74,8 +74,6 @@
 
        leds {
                compatible = "gpio-leds";
-               pinctrl-names = "default";
-               pinctrl-0 = <&leds_opc>, <&leds_r_opc>;
 
                pwr_led {
                        label = "orangepi:green:pwr";
@@ -91,8 +89,6 @@
 
        r_gpio_keys {
                compatible = "gpio-keys";
-               pinctrl-names = "default";
-               pinctrl-0 = <&sw_r_opc>;
 
                sw4 {
                        label = "sw4";
 
 &ir {
        pinctrl-names = "default";
-       pinctrl-0 = <&ir_pins_a>;
+       pinctrl-0 = <&r_ir_rx_pin>;
        status = "okay";
 };
 
        status = "okay";
 };
 
-&pio {
-       leds_opc: led_pins {
-               pins = "PA15";
-               function = "gpio_out";
-       };
-};
-
-&r_pio {
-       leds_r_opc: led_pins {
-               pins = "PL10";
-               function = "gpio_out";
-       };
-
-       sw_r_opc: key_pins {
-               pins = "PL3";
-               function = "gpio_in";
-       };
-};
-
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index 245fd658defbc698bf5f77fe96d8e946c37851b3..840849169bed6ac625c0d75afa0c8c2855591001 100644 (file)
@@ -73,8 +73,6 @@
 
        leds {
                compatible = "gpio-leds";
-               pinctrl-names = "default";
-               pinctrl-0 = <&leds_opc>, <&leds_r_opc>;
 
                pwr_led {
                        label = "orangepi:green:pwr";
@@ -90,8 +88,6 @@
 
        r_gpio_keys {
                compatible = "gpio-keys";
-               pinctrl-names = "default";
-               pinctrl-0 = <&sw_r_opc>;
 
                sw4 {
                        label = "sw4";
        status = "okay";
 };
 
-&pio {
-       leds_opc: led_pins {
-               pins = "PA15";
-               function = "gpio_out";
-       };
-};
-
-&r_pio {
-       leds_r_opc: led_pins {
-               pins = "PL10";
-               function = "gpio_out";
-       };
-
-       sw_r_opc: key_pins {
-               pins = "PL3";
-               function = "gpio_in";
-       };
-};
-
 &reg_usb0_vbus {
        gpio = <&r_pio 0 2 GPIO_ACTIVE_HIGH>; /* PL2 */
        status = "okay";
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index 46240334128f29bf24e79650d514ad8e1b27c1af..5aff8ecc66cbb9510571b24224cf8313e9fa9fee 100644 (file)
@@ -73,8 +73,6 @@
 
        leds {
                compatible = "gpio-leds";
-               pinctrl-names = "default";
-               pinctrl-0 = <&leds_opc>, <&leds_r_opc>;
 
                pwr_led {
                        label = "orangepi:green:pwr";
@@ -90,8 +88,6 @@
 
        r_gpio_keys {
                compatible = "gpio-keys";
-               pinctrl-names = "default";
-               pinctrl-0 = <&sw_r_opc>;
 
                sw4 {
                        label = "sw4";
 
 &ir {
        pinctrl-names = "default";
-       pinctrl-0 = <&ir_pins_a>;
+       pinctrl-0 = <&r_ir_rx_pin>;
        status = "okay";
 };
 
        status = "okay";
 };
 
-&pio {
-       leds_opc: led_pins {
-               pins = "PA15";
-               function = "gpio_out";
-       };
-};
-
 &r_i2c {
        status = "okay";
 
        };
 };
 
-&r_pio {
-       leds_r_opc: led_pins {
-               pins = "PL10";
-               function = "gpio_out";
-       };
-
-       sw_r_opc: key_pins {
-               pins = "PL3";
-               function = "gpio_in";
-       };
-};
-
 &reg_usb0_vbus {
        gpio = <&r_pio 0 2 GPIO_ACTIVE_HIGH>; /* PL2 */
        status = "okay";
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index ac8438c2cff19f8ea0c48d3d69cabeac7e10facf..97f497854e05d26819a692139f0a1e336c8de9a1 100644 (file)
@@ -63,8 +63,6 @@
 
        reg_usb3_vbus: usb3-vbus {
                compatible = "regulator-fixed";
-               pinctrl-names = "default";
-               pinctrl-0 = <&usb3_vbus_pin_a>;
                regulator-name = "usb3-vbus";
                regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
        bias-pull-up;
 };
 
-&pio {
-       usb3_vbus_pin_a: usb3_vbus_pin {
-               pins = "PG11";
-               function = "gpio_out";
-       };
-};
-
 &r_i2c {
        status = "okay";
 
index c834048c325e506fd70fadb0162d06685c71b1ba..b8f46e2802fd31c5a127a961c3c7693244dee1e3 100644 (file)
@@ -79,7 +79,6 @@
 
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
-               pinctrl-names = "default";
                reset-gpios = <&pio 0 9 GPIO_ACTIVE_LOW>; /* PA9 */
                post-power-on-delay-ms = <200>;
        };
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
diff --git a/arch/arm/boot/dts/sun8i-h3-rervision-dvk.dts b/arch/arm/boot/dts/sun8i-h3-rervision-dvk.dts
new file mode 100644 (file)
index 0000000..4738f3a
--- /dev/null
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2019 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+/dts-v1/;
+#include "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+       model = "RerVision H3-DVK";
+       compatible = "rervision,h3-dvk", "allwinner,sun8i-h3";
+
+       aliases {
+               ethernet0 = &emac;
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       connector {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_con_in: endpoint {
+                               remote-endpoint = <&hdmi_out_con>;
+                       };
+               };
+       };
+};
+
+&de {
+       status = "okay";
+};
+
+&ehci1 {
+       status = "okay";
+};
+
+&ehci2 {
+       status = "okay";
+};
+
+&ehci3 {
+       status = "okay";
+};
+
+&emac {
+       phy-handle = <&int_mii_phy>;
+       phy-mode = "mii";
+       allwinner,leds-active-low;
+       status = "okay";
+};
+
+&hdmi {
+       status = "okay";
+};
+
+&hdmi_out {
+       hdmi_out_con: endpoint {
+               remote-endpoint = <&hdmi_con_in>;
+       };
+};
+
+&mmc0 {
+       bus-width = <4>;
+       cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+       status = "okay";
+       vmmc-supply = <&reg_vcc3v3>;
+};
+
+&mmc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc2_8bit_pins>;
+       vmmc-supply = <&reg_vcc3v3>;
+       bus-width = <8>;
+       non-removable;
+       cap-mmc-hw-reset;
+       status = "okay";
+};
+
+&ohci1 {
+       status = "okay";
+};
+
+&ohci2 {
+       status = "okay";
+};
+
+&ohci3 {
+       status = "okay";
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_pa_pins>;
+       status = "okay";
+};
+
+&usb_otg {
+       status = "okay";
+       dr_mode = "peripheral";
+};
+
+&usbphy {
+       status = "okay";
+};
index 959d265e7254c8a2894e54b624a11acd579824f8..e37c30e811d3bfe25187223125fc9cc3e1440261 100644 (file)
 &rtc {
        compatible = "allwinner,sun8i-h3-rtc";
 };
+
+&sid {
+       compatible = "allwinner,sun8i-h3-sid";
+};
index 53104f4ccacc49e4fa5ac18e2fc25803d5c309f7..3d9a1524e17e4f613fd782d1807dff9a80ce3916 100644 (file)
                backlight = <&backlight>;
                enable-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */
                power-supply = <&reg_dc1sw>;
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               port@0 {
-                       reg = <0>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       panel_input: endpoint@0 {
-                               reg = <0>;
+               port {
+                       panel_input: endpoint {
                                remote-endpoint = <&tcon0_out_lcd>;
                        };
                };
        status = "okay";
 };
 
-&tcon0_out {
-       tcon0_out_lcd: endpoint@0 {
-               reg = <0>;
-               remote-endpoint = <&panel_input>;
-       };
-};
-
 &usbphy {
        usb1_vbus-supply = <&reg_dldo1>;
 };
index 32cf1ab33aabc63c2b484993b0ec15b7bc96180f..246dec5846a4d47e4e42a447e9830cf6f76f650f 100644 (file)
@@ -34,8 +34,6 @@
 
        /* 2Gb Macronix MX30LF2G18AC (3V) */
        nand@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
                reg = <0>;
                allwinner,rb = <0>;
                nand-ecc-mode = "hw";
index 316998e9ec5d94e77a34f5333204c94190bf0925..4f48eec6b2efe617f28b6d9ef0f73da2a39b15f0 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_det: usb0-id-detect-pin {
-               pins = "PD10";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 &r_rsb {
        status = "okay";
 
 
 &usbphy {
        status = "okay";
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_det>;
        usb0_vbus-supply = <&reg_drivevbus>;
-       usb0_id_det-gpios = <&pio 3 10 GPIO_ACTIVE_HIGH>; /* PD10 */
+       usb0_id_det-gpios = <&pio 3 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PD10 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb1_vbus-supply = <&reg_usb1_vbus>;
 };
index 06b685869f52d44b685b1db5878a65c3455658b7..bb856e53b806bfc261ef2838758872721115ceb7 100644 (file)
                        clocks = <&ccu CLK_BUS_EHCI1>;
                        resets = <&ccu RST_BUS_EHCI1>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                                 <&ccu CLK_USB_OHCI1>;
                        resets = <&ccu RST_BUS_OHCI1>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        clocks = <&ccu CLK_BUS_EHCI2>;
                        resets = <&ccu RST_BUS_EHCI2>;
                        phys = <&usbphy 2>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                                 <&ccu CLK_USB_OHCI2>;
                        resets = <&ccu RST_BUS_OHCI2>;
                        phys = <&usbphy 2>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_SATA>, <&ccu CLK_SATA>;
                        resets = <&ccu RST_BUS_SATA>;
-                       resets-name = "ahci";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
+                       reset-names = "ahci";
                        status = "disabled";
 
                };
                                #size-cells = <0>;
 
                                tcon_top_mixer0_in: port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       tcon_top_mixer0_in_mixer0: endpoint@0 {
-                                               reg = <0>;
+                                       tcon_top_mixer0_in_mixer0: endpoint {
                                                remote-endpoint = <&mixer0_out_tcon_top>;
                                        };
                                };
index 189e479eb95abd5c218e6f5d5b3efb23402a4325..b3d8b8f056cdf1ca6f1cd7b67555d9a24c47c8fc 100644 (file)
        status = "okay";
 };
 
-&pio {
-       usb0_id_detect_pin: usb0-id-detect-pin {
-               pins = "PH8";
-               function = "gpio_in";
-               bias-pull-up;
-       };
-};
-
 &r_rsb {
        status = "okay";
 
 };
 
 &usbphy {
-       pinctrl-names = "default";
-       pinctrl-0 = <&usb0_id_detect_pin>;
-       usb0_id_det-gpio = <&pio 7 8 GPIO_ACTIVE_HIGH>; /* PH8 */
+       usb0_id_det-gpios = <&pio 7 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH8 */
        usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_drivevbus>;
        status = "okay";
index 99c8cf7bb86cce8863bc5aba669609bc03c07824..2e4587d26ce592add121689ff4c4db9d1394c1cc 100644 (file)
@@ -96,6 +96,6 @@
 };
 
 &usbphy {
-       usb0_id_det-gpio = <&pio 5 6 GPIO_ACTIVE_HIGH>;
+       usb0_id_det-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
index 21e1806ca509d1801182922fcba76b93c44bdf0a..df72b1719c341241b9170fd7c763e9c1dbfe67f9 100644 (file)
                                #size-cells = <0>;
 
                                mixer0_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
 
-                                       mixer0_out_tcon0: endpoint@0 {
-                                               reg = <0>;
+                                       mixer0_out_tcon0: endpoint {
                                                remote-endpoint = <&tcon0_in_mixer0>;
                                        };
                                };
                        clock-names = "ahb",
                                      "tcon-ch0";
                        clock-output-names = "tcon-pixel-clock";
+                       #clock-cells = <0>;
                        resets = <&ccu RST_BUS_TCON0>;
                        reset-names = "lcd";
                        status = "disabled";
                                #size-cells = <0>;
 
                                tcon0_in: port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       tcon0_in_mixer0: endpoint@0 {
-                                               reg = <0>;
+                                       tcon0_in_mixer0: endpoint {
                                                remote-endpoint = <&mixer0_out_tcon0>;
                                        };
                                };
                };
 
                gic: interrupt-controller@1c81000 {
-                       compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
+                       compatible = "arm,gic-400";
                        reg = <0x01c81000 0x1000>,
                              <0x01c82000 0x1000>,
                              <0x01c84000 0x2000>,
index bf97f6244c233f802393133d50456735d18766e7..f05cabd34b8e397f1b97f9f90ed0bb3ad98b48f4 100644 (file)
 
 #include "axp22x.dtsi"
 
+&mmc0 {
+       vmmc-supply = <&reg_dcdc1>;
+       bus-width = <4>;
+       cd-gpios = <&pio 7 13 GPIO_ACTIVE_LOW>; /* PH13 */
+       status = "okay";
+};
+
+&mmc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc1_pg_pins>;
+       vmmc-supply = <&reg_dldo2>;
+       vqmmc-supply = <&reg_dldo1>;
+       mmc-pwrseq = <&wifi_pwrseq>;
+       bus-width = <4>;
+       non-removable;
+       status = "okay";
+};
+
 &reg_aldo3 {
        regulator-always-on;
        regulator-min-microvolt = <2700000>;
        regulator-name = "vcc-wifi";
 };
 
-&mmc0 {
-       vmmc-supply = <&reg_dcdc1>;
-       bus-width = <4>;
-       cd-gpios = <&pio 7 13 GPIO_ACTIVE_LOW>; /* PH13 */
-       status = "okay";
-};
-
-&mmc1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&mmc1_pg_pins>;
-       vmmc-supply = <&reg_dldo2>;
-       vqmmc-supply = <&reg_dldo1>;
-       mmc-pwrseq = <&wifi_pwrseq>;
-       bus-width = <4>;
-       non-removable;
-       status = "okay";
-};
-
 &uart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart0_pb_pins>;
index 28c034928d67a32184dba2eb22655a8d9a306bc2..18156ffa3ce954deb440413f32af1a459df67649 100644 (file)
        vga-dac {
                compatible = "corpro,gm7123", "adi,adv7123", "dumb-vga-dac";
                vdd-supply = <&reg_dcdc1>;
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                ports {
                        #address-cells = <1>;
                        #size-cells = <0>;
 
                        port@0 {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
                                reg = <0>;
 
-                               vga_dac_in: endpoint@0 {
-                                       reg = <0>;
+                               vga_dac_in: endpoint {
                                        remote-endpoint = <&tcon0_out_vga>;
                                };
                        };
 
                        port@1 {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
                                reg = <1>;
 
-                               vga_dac_out: endpoint@0 {
-                                       reg = <0>;
+                               vga_dac_out: endpoint {
                                        remote-endpoint = <&vga_con_in>;
                                };
                        };
 };
 
 &tcon0_out {
-       tcon0_out_vga: endpoint@0 {
-               reg = <0>;
+       tcon0_out_vga: endpoint {
                remote-endpoint = <&vga_dac_in>;
        };
 };
index 864715ec3cb0fd1110cd21f37e5e3e4478ed28eb..2ed28d9e2787a6494323adbb2b6b59efc96d65ff 100644 (file)
@@ -82,7 +82,7 @@
 
        reg_usb1_vbus: usb1-vbus {
                compatible = "regulator-fixed";
-               pinctrl-names = "default";
+               regulator-name = "usb1-vbus";
                regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
                enable-active-high;
@@ -91,7 +91,7 @@
 
        reg_usb3_vbus: usb3-vbus {
                compatible = "regulator-fixed";
-               pinctrl-names = "default";
+               regulator-name = "usb3-vbus";
                regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
                enable-active-high;
index 6fb292e0b662e1f8d91678490cf1c1ca75025d24..0c1eec9000e3369a8edb207e4bb228f26b1a8ff1 100644 (file)
                status = "disabled";
        };
 
-       soc {
+       soc@20000 {
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
                        clocks = <&usb_clocks CLK_BUS_HCI0>;
                        resets = <&usb_clocks RST_USB0_HCI>;
                        phys = <&usbphy1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                                 <&usb_clocks CLK_USB_OHCI0>;
                        resets = <&usb_clocks RST_USB0_HCI>;
                        phys = <&usbphy1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        clocks = <&usb_clocks CLK_BUS_HCI1>;
                        resets = <&usb_clocks RST_USB1_HCI>;
                        phys = <&usbphy2>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        clocks = <&usb_clocks CLK_BUS_HCI2>;
                        resets = <&usb_clocks RST_USB2_HCI>;
                        phys = <&usbphy3>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                                 <&usb_clocks CLK_USB_OHCI2>;
                        resets = <&usb_clocks RST_USB2_HCI>;
                        phys = <&usbphy3>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                };
 
                gic: interrupt-controller@1c41000 {
-                       compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
+                       compatible = "arm,gic-400";
                        reg = <0x01c41000 0x1000>,
                              <0x01c42000 0x2000>,
                              <0x01c44000 0x2000>,
                                #size-cells = <0>;
 
                                fe0_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
 
-                                       fe0_out_deu0: endpoint@0 {
-                                               reg = <0>;
+                                       fe0_out_deu0: endpoint {
                                                remote-endpoint = <&deu0_in_fe0>;
                                        };
                                };
                                #size-cells = <0>;
 
                                fe1_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
 
-                                       fe1_out_deu1: endpoint@0 {
-                                               reg = <0>;
+                                       fe1_out_deu1: endpoint {
                                                remote-endpoint = <&deu1_in_fe1>;
                                        };
                                };
                                };
 
                                be0_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
 
-                                       be0_out_drc0: endpoint@0 {
-                                               reg = <0>;
+                                       be0_out_drc0: endpoint {
                                                remote-endpoint = <&drc0_in_be0>;
                                        };
                                };
                                };
 
                                be1_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
 
-                                       be1_out_drc1: endpoint@0 {
-                                               reg = <0>;
+                                       be1_out_drc1: endpoint {
                                                remote-endpoint = <&drc1_in_be1>;
                                        };
                                };
                                #size-cells = <0>;
 
                                deu0_in: port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       deu0_in_fe0: endpoint@0 {
-                                               reg = <0>;
+                                       deu0_in_fe0: endpoint {
                                                remote-endpoint = <&fe0_out_deu0>;
                                        };
                                };
                                #size-cells = <0>;
 
                                deu1_in: port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       deu1_in_fe1: endpoint@0 {
-                                               reg = <0>;
+                                       deu1_in_fe1: endpoint {
                                                remote-endpoint = <&fe1_out_deu1>;
                                        };
                                };
                                #size-cells = <0>;
 
                                drc0_in: port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       drc0_in_be0: endpoint@0 {
-                                               reg = <0>;
+                                       drc0_in_be0: endpoint {
                                                remote-endpoint = <&be0_out_drc0>;
                                        };
                                };
 
                                drc0_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
 
-                                       drc0_out_tcon0: endpoint@0 {
-                                               reg = <0>;
+                                       drc0_out_tcon0: endpoint {
                                                remote-endpoint = <&tcon0_in_drc0>;
                                        };
                                };
                                #size-cells = <0>;
 
                                drc1_in: port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       drc1_in_be1: endpoint@0 {
-                                               reg = <0>;
+                                       drc1_in_be1: endpoint {
                                                remote-endpoint = <&be1_out_drc1>;
                                        };
                                };
 
                                drc1_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
 
-                                       drc1_out_tcon1: endpoint@0 {
-                                               reg = <0>;
+                                       drc1_out_tcon1: endpoint {
                                                remote-endpoint = <&tcon1_in_drc1>;
                                        };
                                };
                        resets = <&ccu RST_BUS_LCD0>, <&ccu RST_BUS_EDP>;
                        reset-names = "lcd", "edp";
                        clock-output-names = "tcon0-pixel-clock";
+                       #clock-cells = <0>;
 
                        ports {
                                #address-cells = <1>;
                                #size-cells = <0>;
 
                                tcon0_in: port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       tcon0_in_drc0: endpoint@0 {
-                                               reg = <0>;
+                                       tcon0_in_drc0: endpoint {
                                                remote-endpoint = <&drc0_out_tcon0>;
                                        };
                                };
 
                                tcon0_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
                                };
                        };
                                #size-cells = <0>;
 
                                tcon1_in: port@0 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       tcon1_in_drc1: endpoint@0 {
-                                               reg = <0>;
+                                       tcon1_in_drc1: endpoint {
                                                remote-endpoint = <&drc1_out_tcon1>;
                                        };
                                };
 
                                tcon1_out: port@1 {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
                                        reg = <1>;
                                };
                        };
                        gpio-controller;
                        interrupt-controller;
                        #interrupt-cells = <3>;
-                       #size-cells = <0>;
                        #gpio-cells = <3>;
 
                        gmac_rgmii_pins: gmac-rgmii-pins {
-                               allwinner,pins = "PA0", "PA1", "PA2", "PA3",
-                                                "PA4", "PA5", "PA7", "PA8",
-                                                "PA9", "PA10", "PA12", "PA13",
-                                                "PA15", "PA16", "PA17";
-                               allwinner,function = "gmac";
+                               pins = "PA0", "PA1", "PA2", "PA3", "PA4", "PA5",
+                                      "PA7", "PA8", "PA9", "PA10", "PA12",
+                                      "PA13", "PA15", "PA16", "PA17";
+                               function = "gmac";
                                /*
                                 * data lines in RGMII mode use DDR mode
                                 * and need a higher signal drive strength
index 3bed375b9c034eca066bd53ef279c8c4f624fdf5..39263e74fbb531be8b856362560328ea7d996a9f 100644 (file)
@@ -69,7 +69,6 @@
 
        leds {
                compatible = "gpio-leds";
-               pinctrl-names = "default";
 
                pwr_led {
                        label = "bananapi-m2-plus:red:pwr";
@@ -80,7 +79,6 @@
 
        gpio_keys {
                compatible = "gpio-keys";
-               pinctrl-names = "default";
 
                sw4 {
                        label = "power";
 
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
-               pinctrl-names = "default";
                reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
                clocks = <&rtc 1>;
                clock-names = "ext_clock";
 
 &ir {
        pinctrl-names = "default";
-       pinctrl-0 = <&ir_pins_a>;
+       pinctrl-0 = <&r_ir_rx_pin>;
        status = "okay";
 };
 
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index d74a6cbbfdf409585d9aef63f598002122b8d54b..84977d4eb97a918c8d76dbe905eb16634e09b5eb 100644 (file)
                        #size-cells = <0>;
                };
 
+               sid: eeprom@1c14000 {
+                       /* compatible is in per SoC .dtsi file */
+                       reg = <0x1c14000 0x400>;
+               };
+
                usb_otg: usb@1c19000 {
                        compatible = "allwinner,sun8i-h3-musb";
                        reg = <0x01c19000 0x400>;
                        phys = <&usbphy 0>;
                        phy-names = "usb";
                        extcon = <&usbphy 0>;
+                       dr_mode = "otg";
                        status = "disabled";
                };
 
                        clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>;
                        resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                                 <&ccu CLK_USB_OHCI1>;
                        resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>;
                        resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>;
                        phys = <&usbphy 2>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                                 <&ccu CLK_USB_OHCI2>;
                        resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>;
                        phys = <&usbphy 2>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>;
                        resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>;
                        phys = <&usbphy 3>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                                 <&ccu CLK_USB_OHCI3>;
                        resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>;
                        phys = <&usbphy 3>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        interrupt-controller;
                        #interrupt-cells = <3>;
 
-                       csi_pins: csi {
+                       csi_pins: csi-pins {
                                pins = "PE0", "PE2", "PE3", "PE4", "PE5",
                                       "PE6", "PE7", "PE8", "PE9", "PE10",
                                       "PE11";
                                function = "csi";
                        };
 
-                       emac_rgmii_pins: emac0 {
+                       emac_rgmii_pins: emac-rgmii-pins {
                                pins = "PD0", "PD1", "PD2", "PD3", "PD4",
                                       "PD5", "PD7", "PD8", "PD9", "PD10",
                                       "PD12", "PD13", "PD15", "PD16", "PD17";
                                drive-strength = <40>;
                        };
 
-                       i2c0_pins: i2c0 {
+                       i2c0_pins: i2c0-pins {
                                pins = "PA11", "PA12";
                                function = "i2c0";
                        };
 
-                       i2c1_pins: i2c1 {
+                       i2c1_pins: i2c1-pins {
                                pins = "PA18", "PA19";
                                function = "i2c1";
                        };
 
-                       i2c2_pins: i2c2 {
+                       i2c2_pins: i2c2-pins {
                                pins = "PE12", "PE13";
                                function = "i2c2";
                        };
 
-                       mmc0_pins: mmc0 {
+                       mmc0_pins: mmc0-pins {
                                pins = "PF0", "PF1", "PF2", "PF3",
                                       "PF4", "PF5";
                                function = "mmc0";
                                bias-pull-up;
                        };
 
-                       mmc1_pins: mmc1 {
+                       mmc1_pins: mmc1-pins {
                                pins = "PG0", "PG1", "PG2", "PG3",
                                       "PG4", "PG5";
                                function = "mmc1";
                                bias-pull-up;
                        };
 
-                       mmc2_8bit_pins: mmc2_8bit {
+                       mmc2_8bit_pins: mmc2-8bit-pins {
                                pins = "PC5", "PC6", "PC8",
                                       "PC9", "PC10", "PC11",
                                       "PC12", "PC13", "PC14",
                                bias-pull-up;
                        };
 
-                       spdif_tx_pins_a: spdif {
+                       spdif_tx_pin: spdif-tx-pin {
                                pins = "PA17";
                                function = "spdif";
                        };
 
-                       spi0_pins: spi0 {
+                       spi0_pins: spi0-pins {
                                pins = "PC0", "PC1", "PC2", "PC3";
                                function = "spi0";
                        };
 
-                       spi1_pins: spi1 {
+                       spi1_pins: spi1-pins {
                                pins = "PA15", "PA16", "PA14", "PA13";
                                function = "spi1";
                        };
 
-                       uart0_pins_a: uart0 {
+                       uart0_pa_pins: uart0-pa-pins {
                                pins = "PA4", "PA5";
                                function = "uart0";
                        };
 
-                       uart1_pins: uart1 {
+                       uart1_pins: uart1-pins {
                                pins = "PG6", "PG7";
                                function = "uart1";
                        };
 
-                       uart1_rts_cts_pins: uart1_rts_cts {
+                       uart1_rts_cts_pins: uart1-rts-cts-pins {
                                pins = "PG8", "PG9";
                                function = "uart1";
                        };
 
-                       uart2_pins: uart2 {
+                       uart2_pins: uart2-pins {
                                pins = "PA0", "PA1";
                                function = "uart2";
                        };
 
-                       uart3_pins: uart3 {
+                       uart3_pins: uart3-pins {
                                pins = "PA13", "PA14";
                                function = "uart3";
                        };
 
-                       uart3_rts_cts_pins: uart3_rts_cts {
+                       uart3_rts_cts_pins: uart3-rts-cts-pins {
                                pins = "PA15", "PA16";
                                function = "uart3";
                        };
                        interrupt-controller;
                        #interrupt-cells = <3>;
 
-                       ir_pins_a: ir {
+                       r_ir_rx_pin: r-ir-rx-pin {
                                pins = "PL11";
                                function = "s_cir_rx";
                        };
 
-                       r_i2c_pins: r-i2c {
+                       r_i2c_pins: r-i2c-pins {
                                pins = "PL0", "PL1";
                                function = "s_i2c";
                        };
index 1eadc132390ca1c97634adcef038e8025540af3b..19b3b23cfaa8673cb76648493995eb20f7d711a9 100644 (file)
 
 &ir {
        pinctrl-names = "default";
-       pinctrl-0 = <&ir_pins_a>;
+       pinctrl-0 = <&r_ir_rx_pin>;
        status = "okay";
 };
 
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index ca2c3a5578955c28df458b826bdae4458e788c46..d18eaf4a4a3a11ffd58a0542e0f9eac0e419a7b3 100644 (file)
@@ -1,42 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0 OR X11
 /*
- * Copyright 2016 Toradex AG
+ * Copyright 2016-2019 Toradex AG
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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.
- *
- *     This file 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.
- *
- * Or, alternatively
- *
- *  b) 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 , 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 
 / {
index eaee10ef6512ec0b35b6a4163eebd83bd03c230f..ceb3f6388c7dad3d6bfe8d5493b33c16e0a2d553 100644 (file)
@@ -1,42 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR X11
 /*
- * Copyright 2016-2018 Toradex AG
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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.
- *
- *     This file 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.
- *
- * Or, alternatively
- *
- *  b) 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 , 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
+ * Copyright 2016-2019 Toradex AG
  */
 
 /dts-v1/;
index 7961eb4bd8038490f5a9cd3530c93f6edc5f94fc..826b776fbe6ff649a945f791fdbef10a17d7f8be 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+// SPDX-License-Identifier: GPL-2.0 OR MIT
 /*
  * Copyright 2016-2018 Toradex AG
  */
index 367eb8c86098ebc1ff56ebf3ea53656770f2636a..0462ed2dd8b8db286cb149c25557642cbea86cc2 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+// SPDX-License-Identifier: GPL-2.0 OR MIT
 /*
  * Copyright 2016-2018 Toradex AG
  */
@@ -17,6 +17,7 @@
 
        pcie@1003000 {
                status = "okay";
+
                avddio-pex-supply = <&reg_1v05_vdd>;
                avdd-pex-pll-supply = <&reg_1v05_vdd>;
                avdd-pll-erefe-supply = <&reg_1v05_avdd>;
                       <&{/padctl@7009f000/pads/usb2/lanes/usb2-2}>,
                       <&{/padctl@7009f000/pads/pcie/lanes/pcie-0}>;
                phy-names = "usb2-0", "usb3-1", "usb2-1", "usb2-2", "usb3-0";
+
                avddio-pex-supply = <&reg_1v05_vdd>;
                avdd-pll-erefe-supply = <&reg_1v05_avdd>;
                avdd-pll-utmip-supply = <&reg_1v8_vddio>;
        };
 
        padctl@7009f000 {
+               avdd-pll-utmip-supply = <&reg_1v8_vddio>;
+               avdd-pll-erefe-supply = <&reg_1v05_avdd>;
+               avdd-pex-pll-supply = <&reg_1v05_vdd>;
+               hvdd-pex-pll-e-supply = <&reg_module_3v3>;
+
                pads {
                        usb2 {
                                status = "okay";
index 13c93cd507d8e44acc900d2e5ef69921ebe55ebd..d1e8593ef0d900f8d23d525b02f1ca41a6dfff78 100644 (file)
@@ -1,42 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR X11
 /*
- * Copyright 2016-2018 Toradex AG
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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.
- *
- *     This file 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.
- *
- * Or, alternatively
- *
- *  b) 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 , 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
+ * Copyright 2016-2019 Toradex AG
  */
 
 #include "tegra124.dtsi"
        };
 
        padctl@7009f000 {
+               avdd-pll-utmip-supply = <&reg_1v8_vddio>;
+               avdd-pll-erefe-supply = <&reg_1v05_avdd>;
+               avdd-pex-pll-supply = <&reg_1v05_vdd>;
+               hvdd-pex-pll-e-supply = <&reg_module_3v3>;
+
                pads {
                        usb2 {
                                status = "okay";
index 33bbb1c5285d8d5c11956f0c38b34c0f64352faa..d5fd642f8b7739fccecfee1e35aa9cd8f2c379ec 100644 (file)
        padctl@7009f000 {
                status = "okay";
 
+               avdd-pll-utmip-supply = <&vddio_1v8>;
+               avdd-pll-erefe-supply = <&avdd_1v05_run>;
+               avdd-pex-pll-supply = <&vdd_1v05_run>;
+               hvdd-pex-pll-e-supply = <&vdd_3v3_lp0>;
+
                pads {
                        usb2 {
                                status = "okay";
index a1acd872bcf265317a52cba943aa746133d2e3d6..3b10f475037f77f4d651276396546f08b0df58e0 100644 (file)
        padctl@7009f000 {
                status = "okay";
 
+               avdd-pll-utmip-supply = <&vddio_1v8>;
+               avdd-pll-erefe-supply = <&avdd_1v05_run>;
+               avdd-pex-pll-supply = <&vdd_1v05_run>;
+               hvdd-pex-pll-e-supply = <&vdd_3v3_lp0>;
+
                pads {
                        usb2 {
                                status = "okay";
index 4882b61fb68073cc1e1fc3b7016332fb7fdb7100..5d5e6e18bc7b6c1482af10665f171d18b4aa1727 100644 (file)
        };
 
        padctl@7009f000 {
+               avdd-pll-utmip-supply = <&vddio_1v8>;
+               avdd-pll-erefe-supply = <&avdd_1v05_run>;
+               avdd-pex-pll-supply = <&vdd_1v05_run>;
+               hvdd-pex-pll-e-supply = <&vdd_3v3_lp0>;
+
                pads {
                        usb2 {
                                status = "okay";
index d2b553f76719070e58284a49c3b62fd2c0c491be..e074258d451836c65276d79d693e1192e4b2ec65 100644 (file)
                reg = <0x6000c000 0x150>; /* AHB Arbitration + Gizmo Controller */
        };
 
+       actmon@6000c800 {
+               compatible = "nvidia,tegra30-actmon";
+               reg = <0x6000c800 0x400>;
+               interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&tegra_car TEGRA30_CLK_ACTMON>,
+                        <&tegra_car TEGRA30_CLK_EMC>;
+               clock-names = "actmon", "emc";
+               resets = <&tegra_car TEGRA30_CLK_ACTMON>;
+               reset-names = "actmon";
+       };
+
        gpio: gpio@6000d000 {
                compatible = "nvidia,tegra30-gpio";
                reg = <0x6000d000 0x1000>;
index 445c7dc306b261adeba429721c59f79174eefa9c..9466913693ac71e91df8c2a914acdd1703beb348 100644 (file)
                        label = "zii:green:debug1";
                        gpios = <&gpio2 18 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "heartbeat";
-                       max-brightness = <1>;
                };
 
                led-fail {
                        label = "zii:red:fail";
                        gpios = <&gpio3 12 GPIO_ACTIVE_LOW>;
                        default-state = "off";
-                       max-brightness = <1>;
                };
 
                led-status {
                        label = "zii:green:status";
                        gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>;
                        default-state = "off";
-                       max-brightness = <1>;
                };
 
                led-debug-a {
                        label = "zii:green:debug_a";
                        gpios = <&gpio3 14 GPIO_ACTIVE_HIGH>;
                        default-state = "off";
-                       max-brightness = <1>;
                };
 
                led-debug-b {
                        label = "zii:green:debug_b";
                        gpios = <&gpio3 15 GPIO_ACTIVE_HIGH>;
                        default-state = "off";
-                       max-brightness = <1>;
                };
        };
 
        bus-num = <1>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_dspi1>;
-       status = "okay";
-
-       m25p128@0 {
+       /*
+        * Some CFU1s come with SPI-NOR chip DNPed, so we leave this
+        * node disabled by default and rely on bootloader to enable
+        * it when appropriate.
+        */
+       status = "disabled";
+
+       flash@0 {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "m25p128", "jedec,spi-nor";
        pinctrl-0 = <&pinctrl_i2c0>;
        status = "okay";
 
-       pca9554@22 {
+       io-expander@22 {
                compatible = "nxp,pca9554";
                reg = <0x22>;
                gpio-controller;
                reg = <0x48>;
        };
 
-       at24c04@52 {
+       eeprom@52 {
                compatible = "atmel,24c04";
                reg = <0x52>;
                label = "nvm";
        };
 
-       at24c04@54 {
+       eeprom@54 {
                compatible = "atmel,24c04";
                reg = <0x54>;
                label = "nameplate";
        };
 };
 
+&snvsrtc {
+       status = "disabled";
+};
+
 &uart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart0>;
index bd79e00bf6153a5a66c4e63025ed3ee73ec69dae..48086c5e8549e075a22403ef9ab122bf21150a91 100644 (file)
@@ -1,45 +1,6 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
 /*
  * Copyright (C) 2015, 2016 Zodiac Inflight Innovations
- *
- * Based on an original 'vf610-twr.dts' which is Copyright 2015,
- * Freescale Semiconductor, Inc.
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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.
- *
- *     This file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 
 /dts-v1/;
                gpio-sck  = <&gpio1 12 GPIO_ACTIVE_HIGH>;
                gpio-mosi = <&gpio1 11 GPIO_ACTIVE_HIGH>;
                gpio-miso = <&gpio1 10 GPIO_ACTIVE_HIGH>;
-               cs-gpios  = <&gpio1  9 GPIO_ACTIVE_HIGH
+               cs-gpios  = <&gpio1  9 GPIO_ACTIVE_LOW
                             &gpio1  8 GPIO_ACTIVE_HIGH>;
                num-chipselects = <2>;
 
-               m25p128@0 {
+               flash@0 {
                        compatible = "m25p128", "jedec,spi-nor";
                        #address-cells = <1>;
                        #size-cells = <1>;
        pinctrl-0 = <&pinctrl_i2c0>;
        status = "okay";
 
-       gpio5: pca9554@20 {
+       gpio5: io-expander@20 {
                compatible = "nxp,pca9554";
                reg = <0x20>;
                gpio-controller;
 
        };
 
-       gpio6: pca9554@22 {
+       gpio6: io-expander@22 {
                compatible = "nxp,pca9554";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_pca9554_22>;
                        #size-cells = <0>;
                        reg = <0>;
 
-                       sfp1: at24c04@50 {
+                       sfp1: eeprom@50 {
                                compatible = "atmel,24c02";
                                reg = <0x50>;
                        };
                        #size-cells = <0>;
                        reg = <1>;
 
-                       sfp2: at24c04@50 {
+                       sfp2: eeprom@50 {
                                compatible = "atmel,24c02";
                                reg = <0x50>;
                        };
                        #size-cells = <0>;
                        reg = <2>;
 
-                       sfp3: at24c04@50 {
+                       sfp3: eeprom@50 {
                                compatible = "atmel,24c02";
                                reg = <0x50>;
                        };
                        #size-cells = <0>;
                        reg = <3>;
 
-                       sfp4: at24c04@50 {
+                       sfp4: eeprom@50 {
                                compatible = "atmel,24c02";
                                reg = <0x50>;
                        };
index 6f4a5602cefd510b8fb5df499ff8ad9dfd4330a0..778e02c000d1638764280dccfa50638b0abc3537 100644 (file)
@@ -1,45 +1,6 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
 /*
  * Copyright (C) 2015, 2016 Zodiac Inflight Innovations
- *
- * Based on an original 'vf610-twr.dts' which is Copyright 2015,
- * Freescale Semiconductor, Inc.
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file 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.
- *
- *     This file 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.
- *
- * Or, alternatively,
- *
- *  b) 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 , 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 AUTHORS OR COPYRIGHT
- *     HOLDERS 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.
  */
 
 /dts-v1/;
        status = "okay";
        spi-num-chipselects = <2>;
 
-       m25p128@0 {
+       flash@0 {
                compatible = "m25p128", "jedec,spi-nor";
                #address-cells = <1>;
                #size-cells = <1>;
         *    P1 - WE2_CMD
         *    P2 - WE2_CLK
         */
-       gpio5: pca9557@18 {
+       gpio5: io-expander@18 {
                compatible = "nxp,pca9557";
                reg = <0x18>;
                gpio-controller;
         *     IO0 - WE1_CLK
         *     IO1 - WE1_CMD
         */
-       gpio7: pca9554@22 {
+       gpio7: io-expander@22 {
                compatible = "nxp,pca9554";
                reg = <0x22>;
                gpio-controller;
 };
 
 &i2c1 {
-       at24mac602@50 {
+       eeprom@50 {
                compatible = "atmel,24c02";
                reg = <0x50>;
                read-only;
index 19eb4a849efb45d9d7f14f27b7373644ea7bbac5..0507e6dcbb216a9f46a8735dc768e5b8aa7e9900 100644 (file)
        pinctrl-names = "default", "gpio";
        pinctrl-0 = <&pinctrl_i2c0>;
        pinctrl-1 = <&pinctrl_i2c0_gpio>;
-       scl-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+       scl-gpios = <&gpio1 4 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        sda-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
        status = "okay";
 
                reg = <0x48>;
        };
 
-       at24c04@50 {
+       eeprom@50 {
                compatible = "atmel,24c04";
                reg = <0x50>;
        };
 
-       at24c04@52 {
+       eeprom@52 {
                compatible = "atmel,24c04";
                reg = <0x52>;
        };
index de6dfa57bec5456a92c5f84a399c383af979ea46..d7019e89f5887407d822a3c98fadb31ce44c93c0 100644 (file)
        pinctrl-0 = <&pinctrl_i2c0>;
        status = "okay";
 
-       gpio5: pca9554@20 {
+       gpio5: io-expander@20 {
                compatible = "nxp,pca9554";
                reg = <0x20>;
                gpio-controller;
                #gpio-cells = <2>;
        };
 
-       gpio6: pca9554@22 {
+       gpio6: io-expander@22 {
                compatible = "nxp,pca9554";
                reg = <0x22>;
                gpio-controller;
                reg = <0x48>;
        };
 
-       at24c04@50 {
+       eeprom@50 {
                compatible = "atmel,24c04";
                reg = <0x50>;
        };
 
-       at24c04@52 {
+       eeprom@52 {
                compatible = "atmel,24c04";
                reg = <0x52>;
        };
                reg = <0x4f>;
        };
 
-       gpio7: pca9555@23 {
+       gpio7: io-expander@23 {
                compatible = "nxp,pca9555";
                gpio-controller;
                #gpio-cells = <2>;
        };
 };
 
+&snvsrtc {
+       status = "disabled";
+};
+
 &uart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart0>;
diff --git a/arch/arm/boot/dts/vf610-zii-spb4.dts b/arch/arm/boot/dts/vf610-zii-spb4.dts
new file mode 100644 (file)
index 0000000..9dde83c
--- /dev/null
@@ -0,0 +1,359 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+
+/*
+ * Device tree file for ZII's SPB4 board
+ *
+ * SPB - Seat Power Box
+ *
+ * Copyright (C) 2019 Zodiac Inflight Innovations
+ */
+
+/dts-v1/;
+#include "vf610.dtsi"
+
+/ {
+       model = "ZII VF610 SPB4 Board";
+       compatible = "zii,vf610spb4", "zii,vf610dev", "fsl,vf610";
+
+       chosen {
+               stdout-path = &uart0;
+       };
+
+       memory@80000000 {
+               device_type = "memory";
+               reg = <0x80000000 0x20000000>;
+       };
+
+       gpio-leds {
+               compatible = "gpio-leds";
+               pinctrl-0 = <&pinctrl_leds_debug>;
+               pinctrl-names = "default";
+
+               led-debug {
+                       label = "zii:green:debug1";
+                       gpios = <&gpio2 18 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       reg_vcc_3v3_mcu: regulator-vcc-3v3-mcu {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_3v3_mcu";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+};
+
+&adc0 {
+       vref-supply = <&reg_vcc_3v3_mcu>;
+       status = "okay";
+};
+
+&adc1 {
+       vref-supply = <&reg_vcc_3v3_mcu>;
+       status = "okay";
+};
+
+&dspi1 {
+       bus-num = <1>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_dspi1>;
+       status = "okay";
+
+       flash@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "m25p128", "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <50000000>;
+       };
+};
+
+&edma0 {
+       status = "okay";
+};
+
+&edma1 {
+       status = "okay";
+};
+
+&esdhc0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_esdhc0>;
+       bus-width = <8>;
+       non-removable;
+       no-1-8-v;
+       keep-power-in-suspend;
+       no-sdio;
+       no-sd;
+       status = "okay";
+};
+
+&esdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_esdhc1>;
+       bus-width = <4>;
+       no-sdio;
+       status = "okay";
+};
+
+&fec1 {
+       phy-mode = "rmii";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec1>;
+       status = "okay";
+
+       fixed-link {
+               speed = <100>;
+               full-duplex;
+       };
+
+       mdio1: mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "okay";
+
+               switch0: switch0@0 {
+                       compatible = "marvell,mv88e6190";
+                       pinctrl-0 = <&pinctrl_gpio_switch0>;
+                       pinctrl-names = "default";
+                       reg = <0>;
+                       eeprom-length = <65536>;
+                       reset-gpios = <&gpio3 11 GPIO_ACTIVE_LOW>;
+                       interrupt-parent = <&gpio3>;
+                       interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       label = "cpu";
+                                       ethernet = <&fec1>;
+
+                                       fixed-link {
+                                               speed = <100>;
+                                               full-duplex;
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                                       label = "eth_cu_1000_1";
+                               };
+
+                               port@2 {
+                                       reg = <2>;
+                                       label = "eth_cu_1000_2";
+                               };
+
+                               port@3 {
+                                       reg = <3>;
+                                       label = "eth_cu_1000_3";
+                               };
+
+                               port@4 {
+                                       reg = <4>;
+                                       label = "eth_cu_1000_4";
+                               };
+
+                               port@5 {
+                                       reg = <5>;
+                                       label = "eth_cu_1000_5";
+                               };
+
+                               port@6 {
+                                       reg = <6>;
+                                       label = "eth_cu_1000_6";
+                               };
+                       };
+               };
+       };
+};
+
+&i2c0 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c0>;
+       status = "okay";
+
+       io-expander@22 {
+               compatible = "nxp,pca9554";
+               reg = <0x22>;
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c04";
+               reg = <0x50>;
+               label = "nameplate";
+       };
+
+       eeprom@52 {
+               compatible = "atmel,24c04";
+               reg = <0x52>;
+       };
+};
+
+&snvsrtc {
+       status = "disabled";
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart0>;
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       status = "okay";
+
+       rave-sp {
+               compatible = "zii,rave-sp-rdu2";
+               current-speed = <1000000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               watchdog {
+                       compatible = "zii,rave-sp-watchdog";
+               };
+
+               eeprom@a3 {
+                       compatible = "zii,rave-sp-eeprom";
+                       reg = <0xa3 0x4000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       zii,eeprom-name = "main-eeprom";
+               };
+       };
+};
+
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
+       status = "okay";
+};
+
+&wdoga5 {
+       status = "disabled";
+};
+
+&iomuxc {
+       pinctrl_dspi1: dspi1grp {
+               fsl,pins = <
+                       VF610_PAD_PTD5__DSPI1_CS0               0x1182
+                       VF610_PAD_PTD4__DSPI1_CS1               0x1182
+                       VF610_PAD_PTC6__DSPI1_SIN               0x1181
+                       VF610_PAD_PTC7__DSPI1_SOUT              0x1182
+                       VF610_PAD_PTC8__DSPI1_SCK               0x1182
+               >;
+       };
+
+       pinctrl_esdhc0: esdhc0grp {
+               fsl,pins = <
+                       VF610_PAD_PTC0__ESDHC0_CLK              0x31ef
+                       VF610_PAD_PTC1__ESDHC0_CMD              0x31ef
+                       VF610_PAD_PTC2__ESDHC0_DAT0             0x31ef
+                       VF610_PAD_PTC3__ESDHC0_DAT1             0x31ef
+                       VF610_PAD_PTC4__ESDHC0_DAT2             0x31ef
+                       VF610_PAD_PTC5__ESDHC0_DAT3             0x31ef
+                       VF610_PAD_PTD23__ESDHC0_DAT4            0x31ef
+                       VF610_PAD_PTD22__ESDHC0_DAT5            0x31ef
+                       VF610_PAD_PTD21__ESDHC0_DAT6            0x31ef
+                       VF610_PAD_PTD20__ESDHC0_DAT7            0x31ef
+               >;
+       };
+
+       pinctrl_esdhc1: esdhc1grp {
+               fsl,pins = <
+                       VF610_PAD_PTA24__ESDHC1_CLK             0x31ef
+                       VF610_PAD_PTA25__ESDHC1_CMD             0x31ef
+                       VF610_PAD_PTA26__ESDHC1_DAT0            0x31ef
+                       VF610_PAD_PTA27__ESDHC1_DAT1            0x31ef
+                       VF610_PAD_PTA28__ESDHC1_DATA2           0x31ef
+                       VF610_PAD_PTA29__ESDHC1_DAT3            0x31ef
+               >;
+       };
+
+       pinctrl_fec1: fec1grp {
+               fsl,pins = <
+                       VF610_PAD_PTA6__RMII_CLKIN              0x30d1
+                       VF610_PAD_PTC9__ENET_RMII1_MDC          0x30d2
+                       VF610_PAD_PTC10__ENET_RMII1_MDIO        0x30d3
+                       VF610_PAD_PTC11__ENET_RMII1_CRS         0x30d1
+                       VF610_PAD_PTC12__ENET_RMII1_RXD1        0x30d1
+                       VF610_PAD_PTC13__ENET_RMII1_RXD0        0x30d1
+                       VF610_PAD_PTC14__ENET_RMII1_RXER        0x30d1
+                       VF610_PAD_PTC15__ENET_RMII1_TXD1        0x30d2
+                       VF610_PAD_PTC16__ENET_RMII1_TXD0        0x30d2
+                       VF610_PAD_PTC17__ENET_RMII1_TXEN        0x30d2
+               >;
+       };
+
+       pinctrl_gpio_switch0: pinctrl-gpio-switch0 {
+               fsl,pins = <
+                       VF610_PAD_PTE2__GPIO_107                0x31c2
+                       VF610_PAD_PTB28__GPIO_98                0x219d
+               >;
+       };
+
+       pinctrl_i2c0: i2c0grp {
+               fsl,pins = <
+                       VF610_PAD_PTB14__I2C0_SCL               0x37ff
+                       VF610_PAD_PTB15__I2C0_SDA               0x37ff
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       VF610_PAD_PTB16__I2C1_SCL               0x37ff
+                       VF610_PAD_PTB17__I2C1_SDA               0x37ff
+               >;
+       };
+
+       pinctrl_leds_debug: pinctrl-leds-debug {
+               fsl,pins = <
+                       VF610_PAD_PTD3__GPIO_82                 0x31c2
+               >;
+       };
+
+       pinctrl_uart0: uart0grp {
+               fsl,pins = <
+                       VF610_PAD_PTB10__UART0_TX               0x21a2
+                       VF610_PAD_PTB11__UART0_RX               0x21a1
+               >;
+       };
+
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       VF610_PAD_PTB23__UART1_TX               0x21a2
+                       VF610_PAD_PTB24__UART1_RX               0x21a1
+               >;
+       };
+
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       VF610_PAD_PTD0__UART2_TX                0x21a2
+                       VF610_PAD_PTD1__UART2_RX                0x21a1
+               >;
+       };
+
+       pinctrl_uart3: uart3grp {
+               fsl,pins = <
+                       VF610_PAD_PTA30__UART3_TX               0x21a2
+                       VF610_PAD_PTA31__UART3_RX               0x21a1
+               >;
+       };
+};
index 2b10672fadbd5027a693cbd06021e6c0f75c1d65..847c5858fea12a6eab5a3739a80b5db51685c3ff 100644 (file)
@@ -37,7 +37,6 @@
                        label = "zii:green:debug1";
                        gpios = <&gpio2 18 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "heartbeat";
-                       max-brightness = <1>;
                };
        };
 
        };
 };
 
+&snvsrtc {
+       status = "disabled";
+};
+
 &uart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart0>;
index 0d9fe5ac83a37574b48b1297021e2542fc872f32..453fce80f858d61267753208f56b771f21dc14ca 100644 (file)
@@ -37,7 +37,6 @@
                        label = "zii:green:debug1";
                        gpios = <&gpio2 18 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "heartbeat";
-                       max-brightness = <1>;
                };
        };
 
@@ -70,7 +69,7 @@
         */
        status = "disabled";
 
-       m25p128@0 {
+       flash@0 {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "m25p128", "jedec,spi-nor";
        pinctrl-0 = <&pinctrl_i2c0>;
        status = "okay";
 
-       gpio6: pca9505@22 {
+       gpio6: io-expander@22 {
                compatible = "nxp,pca9554";
                reg = <0x22>;
                gpio-controller;
                reg = <0x48>;
        };
 
-       at24c04@50 {
+       eeprom@50 {
                compatible = "atmel,24c04";
                reg = <0x50>;
                label = "nameplate";
        };
 
-       at24c04@52 {
+       eeprom@52 {
                compatible = "atmel,24c04";
                reg = <0x52>;
        };
 };
 
+&snvsrtc {
+       status = "disabled";
+};
+
 &uart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart0>;
        };
 };
 
+&wdoga5 {
+       status = "disabled";
+};
+
 &iomuxc {
        pinctrl_dspi1: dspi1grp {
                fsl,pins = <
index 45412d21aa6b7da2241cb6377a747977a1f80748..179ca8757a743f502e7bc62980a9001eaa96c534 100644 (file)
@@ -32,7 +32,7 @@
 #include <mach/hardware.h>
 #include <asm/mach/irq.h>
 #include <asm/mach-types.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include <asm/hardware/sa1111.h>
 
index bdbade6af9c72693c83700ee75365b62fcd7b104..190d6e9d3296e320acc064d8fd433ec62f0a64fd 100644 (file)
@@ -247,7 +247,6 @@ CONFIG_PANIC_TIMEOUT=-1
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_SCHED_STACK_END_CHECK=y
 CONFIG_FUNCTION_TRACER=y
-# CONFIG_TRACING_EVENTS_GPIO is not set
 # CONFIG_RUNTIME_TESTING_MENU is not set
 CONFIG_DEBUG_WX=y
 CONFIG_DEBUG_USER=y
index 4bde84eae4ebbf77116c8d6a8da01daf7bbd0ba9..407ffb7655a80019aa392c4c889415414877aaec 100644 (file)
@@ -247,7 +247,6 @@ CONFIG_PANIC_TIMEOUT=-1
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_SCHED_STACK_END_CHECK=y
 CONFIG_FUNCTION_TRACER=y
-# CONFIG_TRACING_EVENTS_GPIO is not set
 # CONFIG_RUNTIME_TESTING_MENU is not set
 CONFIG_DEBUG_WX=y
 CONFIG_DEBUG_USER=y
index b7752929975ca77a5814e8a741fb46bc140be1e2..a88e314498800cbbaeea5a3d4969cf2b77519c93 100644 (file)
@@ -55,7 +55,7 @@ CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_DATAFLASH=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
 CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_GLUEBI=y
index 09ae750164e098f50b472d5968125bfd5f9e3b3f..c255dab36bdec8d31747751fcf24850d4be2ff46 100644 (file)
@@ -35,7 +35,7 @@ CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_CFI_STAA=y
 CONFIG_MTD_PLATRAM=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_GPIO=y
 CONFIG_NETDEVICES=y
 # CONFIG_NET_CADENCE is not set
index fb45b4983d3cfd7a22eaf6082d624faf252e3e7f..5344434df6520d7d8d6d7275f7f3257f4daf2177 100644 (file)
@@ -58,7 +58,7 @@ CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_CFI_STAA=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_PXA2XX=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_GPIO=m
 CONFIG_MTD_NAND_CM_X270=y
 CONFIG_MTD_NAND_PLATFORM=y
index 5e349c625b71c8b06092929c066ba6065f376c0b..3707a014cbc466b746de28f15d113fcd551f7a1e 100644 (file)
@@ -48,7 +48,7 @@ CONFIG_LIB80211=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_MARVELL=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
index 8995695fc118bf642f38e0ff667687ed3d3bee2b..8d484e4d51cc05f1d17888c83163c3aa244f7759 100644 (file)
@@ -64,7 +64,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_PXA2XX=y
 CONFIG_MTD_BLOCK2MTD=y
-CONFIG_MTD_NAND=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
index 09e1672777c9b0e76ea42acde31cb7e011e159ff..d99725984947130b604776959207a7ee1a8b17a9 100644 (file)
@@ -87,7 +87,7 @@ CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_ROM=y
 CONFIG_MTD_COMPLEX_MAPPINGS=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_SHARPSL=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_SD=y
index 207962a656a26b0d6cc07d6f40586e54d3c0701a..4a8cad4d37073d7c2584d3edc961a2fff5b70d96 100644 (file)
@@ -74,7 +74,7 @@ CONFIG_MTD_CFI_INTELEXT=m
 CONFIG_MTD_CFI_AMDSTD=m
 CONFIG_MTD_PHYSMAP=m
 CONFIG_MTD_M25P80=m
-CONFIG_MTD_NAND=m
+CONFIG_MTD_RAW_NAND=m
 CONFIG_MTD_NAND_DAVINCI=m
 CONFIG_MTD_SPI_NOR=m
 CONFIG_MTD_UBI=m
index 30a67523f860d1bbd3e79d9553f47e229e3e4540..61228a25ba8d297160a2543463428de362c42616 100644 (file)
@@ -54,7 +54,7 @@ CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_CFI_STAA=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_PXA2XX=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_PLATFORM=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
index 78cd73d1c795bb6857ccefc9302dd409c6c9f93e..14889a785f07ca0423f59607f6e60b7235b5332f 100644 (file)
@@ -63,7 +63,7 @@ CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_CFI_STAA=y
 CONFIG_MTD_ROM=y
 CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_BLK_DEV_NBD=y
 CONFIG_EEPROM_LEGACY=y
 CONFIG_SCSI=y
index eabb784cf7da5525a9eb1fe3a16e1819a7def8d4..b85575867d21d3dce1699c08d9134b0d8c3f29e1 100644 (file)
@@ -43,7 +43,7 @@ CONFIG_MAC80211_RC_PID=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 CONFIG_MTD=m
-CONFIG_MTD_NAND=m
+CONFIG_MTD_RAW_NAND=m
 CONFIG_MTD_NAND_TMIO=m
 CONFIG_BLK_DEV_LOOP=m
 # CONFIG_SCSI_PROC_FS is not set
index d635edfb6ff29a138dc542330c8cc003c891c8db..c95c54284da211c42c70fe856d3fb667a539354a 100644 (file)
@@ -9,7 +9,6 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_ARCH_EXYNOS=y
 CONFIG_ARCH_EXYNOS3=y
-CONFIG_EXYNOS5420_MCPM=y
 CONFIG_SMP=y
 CONFIG_BIG_LITTLE=y
 CONFIG_NR_CPUS=8
index b37f8e675e4081b200bfd9b9a97d565efce1d1f7..f2cf0722e8e1a41ac049ac406f686279cf43162e 100644 (file)
@@ -61,7 +61,7 @@ CONFIG_MTD_CFI_GEOMETRY=y
 # CONFIG_MTD_CFI_I2 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_MXC=y
 CONFIG_MTD_UBI=y
 CONFIG_EEPROM_AT24=y
index 50fb01d70b1030ca6d2f721b30eaa8078894b589..8116648a8efd0240233f1df173e3a5cf51a24b8d 100644 (file)
@@ -110,7 +110,7 @@ CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_MTD_DATAFLASH=y
 CONFIG_MTD_M25P80=y
 CONFIG_MTD_SST25L=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_GPMI_NAND=y
 CONFIG_MTD_NAND_VF610_NFC=y
 CONFIG_MTD_NAND_MXC=y
index 8c3c99cd6de950dc79efc91257b1c196dd62c933..39ebcce3bc2f52d93d3b4256a97a678924866d4a 100644 (file)
@@ -112,7 +112,7 @@ CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_MTD_IXP4XX=y
-CONFIG_MTD_NAND=m
+CONFIG_MTD_RAW_NAND=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
index 3ded35a07f45a00173c51d987a733c14033c3df3..72fee57aad2fa204d5a38034c467bf482905a36d 100644 (file)
@@ -124,7 +124,7 @@ CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_PLATRAM=y
 CONFIG_MTD_M25P80=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_DAVINCI=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_MTD_UBI=y
index e752fb704df062b1c9942a87a5e5ea79860859d4..4b3b2c693c296e1600b417faf6dcd46a5f822868 100644 (file)
@@ -47,7 +47,7 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_SLC_LPC32XX=y
 CONFIG_MTD_NAND_MLC_LPC32XX=y
 CONFIG_MTD_UBI=y
index d95a8059d30bebb36e3f3639e558f39c7f90bbf9..7d26ca0b13025283ab3b5fd7cfb6ce2fa342b482 100644 (file)
@@ -92,7 +92,7 @@ CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_CFI_STAA=y
 CONFIG_MTD_RAM=y
 CONFIG_MTD_ROM=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_S3C2410=y
 CONFIG_MTD_NAND_PLATFORM=y
 CONFIG_MTD_LPDDR=y
@@ -152,7 +152,7 @@ CONFIG_SPI_S3C24XX=y
 CONFIG_SPI_SPIDEV=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_SENSORS_LM75=y
-CONFIG_THERMAL=m
+CONFIG_THERMAL=y
 CONFIG_WATCHDOG=y
 CONFIG_S3C2410_WATCHDOG=y
 CONFIG_FB=y
index 1eeee7f11d91f051434a333fdb4f16d49d65ba96..94deb0ed0541d74dbbac06ae837c0be6bd7f7e3f 100644 (file)
@@ -28,7 +28,7 @@ CONFIG_IP_PNP=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_ONENAND=y
 CONFIG_MTD_ONENAND_GENERIC=y
 # CONFIG_BLK_DEV is not set
index eeea0c41138bf0e082321469da3843f8d740991a..0b42bddfbc826b1efe3197ebee6818c27a2789ea 100644 (file)
@@ -38,7 +38,7 @@ CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_CFI_STAA=y
 CONFIG_MTD_PLATRAM=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_GPIO=y
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
index 318b76fa26d1fd54c0f8e2ea4785c576587d3b8b..63b5a8824f0fa5d3c2a0427f8c38346466096c6e 100644 (file)
@@ -87,7 +87,7 @@ CONFIG_MTD_CFI_GEOMETRY=y
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_STAA=y
 CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
 CONFIG_MTD_NAND_ORION=y
 CONFIG_MTD_SPI_NOR=y
index c75051b9392c5138dde3b2acdd178f813f656c10..6b748f214eae9aa484eba18deb7e19bee048258e 100644 (file)
@@ -5,10 +5,6 @@ CONFIG_CGROUPS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_CMDLINE_PARTITION=y
 CONFIG_ARCH_VIRT=y
 CONFIG_ARCH_ALPINE=y
 CONFIG_ARCH_ARTPEC=y
@@ -33,7 +29,6 @@ CONFIG_MACH_BERLIN_BG2CD=y
 CONFIG_MACH_BERLIN_BG2Q=y
 CONFIG_ARCH_DIGICOLOR=y
 CONFIG_ARCH_EXYNOS=y
-CONFIG_EXYNOS5420_MCPM=y
 CONFIG_ARCH_HIGHBANK=y
 CONFIG_ARCH_HISI=y
 CONFIG_ARCH_HI3xxx=y
@@ -48,8 +43,8 @@ CONFIG_SOC_IMX6Q=y
 CONFIG_SOC_IMX6SL=y
 CONFIG_SOC_IMX6SX=y
 CONFIG_SOC_IMX6UL=y
-CONFIG_SOC_IMX7D=y
 CONFIG_SOC_LS1021A=y
+CONFIG_SOC_IMX7D=y
 CONFIG_SOC_VF610=y
 CONFIG_ARCH_KEYSTONE=y
 CONFIG_ARCH_MEDIATEK=y
@@ -76,24 +71,6 @@ CONFIG_ARCH_MSM8960=y
 CONFIG_ARCH_MSM8974=y
 CONFIG_ARCH_ROCKCHIP=y
 CONFIG_ARCH_RENESAS=y
-CONFIG_ARCH_EMEV2=y
-CONFIG_ARCH_R7S72100=y
-CONFIG_ARCH_R7S9210=y
-CONFIG_ARCH_R8A73A4=y
-CONFIG_ARCH_R8A7740=y
-CONFIG_ARCH_R8A7743=y
-CONFIG_ARCH_R8A7744=y
-CONFIG_ARCH_R8A7745=y
-CONFIG_ARCH_R8A77470=y
-CONFIG_ARCH_R8A7778=y
-CONFIG_ARCH_R8A7779=y
-CONFIG_ARCH_R8A7790=y
-CONFIG_ARCH_R8A7791=y
-CONFIG_ARCH_R8A7792=y
-CONFIG_ARCH_R8A7793=y
-CONFIG_ARCH_R8A7794=y
-CONFIG_ARCH_R9A06G032=y
-CONFIG_ARCH_SH73A0=y
 CONFIG_ARCH_SOCFPGA=y
 CONFIG_PLAT_SPEAR=y
 CONFIG_ARCH_SPEAR13XX=y
@@ -109,16 +86,6 @@ CONFIG_ARCH_VEXPRESS=y
 CONFIG_ARCH_VEXPRESS_TC2_PM=y
 CONFIG_ARCH_WM8850=y
 CONFIG_ARCH_ZYNQ=y
-CONFIG_PCIEPORTBUS=y
-CONFIG_PCI_MVEBU=y
-CONFIG_PCI_TEGRA=y
-CONFIG_PCI_RCAR_GEN2=y
-CONFIG_PCIE_RCAR=y
-CONFIG_PCI_DRA7XX_EP=y
-CONFIG_PCI_KEYSTONE=y
-CONFIG_PCI_ENDPOINT=y
-CONFIG_PCI_ENDPOINT_CONFIGFS=y
-CONFIG_PCI_EPF_TEST=m
 CONFIG_SMP=y
 CONFIG_NR_CPUS=16
 CONFIG_SECCOMP=y
@@ -141,6 +108,29 @@ CONFIG_ARM_CPUIDLE=y
 CONFIG_ARM_ZYNQ_CPUIDLE=y
 CONFIG_ARM_EXYNOS_CPUIDLE=y
 CONFIG_KERNEL_MODE_NEON=y
+CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_TRUSTED_FOUNDATIONS=y
+CONFIG_BCM47XX_NVRAM=y
+CONFIG_BCM47XX_SPROM=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
+CONFIG_CRYPTO_SHA2_ARM_CE=m
+CONFIG_CRYPTO_SHA512_ARM=m
+CONFIG_CRYPTO_AES_ARM=m
+CONFIG_CRYPTO_AES_ARM_BS=m
+CONFIG_CRYPTO_AES_ARM_CE=m
+CONFIG_CRYPTO_GHASH_ARM_CE=m
+CONFIG_CRYPTO_CRC32_ARM_CE=m
+CONFIG_CRYPTO_CHACHA20_NEON=m
+CONFIG_GCC_PLUGINS=y
+CONFIG_GCC_PLUGIN_STRUCTLEAK=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_CMDLINE_PARTITION=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -175,16 +165,29 @@ CONFIG_MAC80211=m
 CONFIG_RFKILL=y
 CONFIG_RFKILL_INPUT=y
 CONFIG_RFKILL_GPIO=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCI_MVEBU=y
+CONFIG_PCI_TEGRA=y
+CONFIG_PCI_RCAR_GEN2=y
+CONFIG_PCIE_RCAR=y
+CONFIG_PCI_DRA7XX_EP=y
+CONFIG_PCI_KEYSTONE=y
+CONFIG_PCI_ENDPOINT=y
+CONFIG_PCI_ENDPOINT_CONFIGFS=y
+CONFIG_PCI_EPF_TEST=m
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_CMA_SIZE_MBYTES=64
 CONFIG_OMAP_OCP2SCP=y
 CONFIG_SIMPLE_PM_BUS=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_MTD_M25P80=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_DENALI_DT=y
 CONFIG_MTD_NAND_OMAP2=y
 CONFIG_MTD_NAND_OMAP_BCH=y
@@ -195,7 +198,6 @@ CONFIG_MTD_NAND_BRCMNAND=y
 CONFIG_MTD_NAND_VF610_NFC=y
 CONFIG_MTD_NAND_DAVINCI=y
 CONFIG_MTD_SPI_NOR=y
-CONFIG_SPI_FSL_QUADSPI=m
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
@@ -230,7 +232,6 @@ CONFIG_VIRTIO_NET=y
 CONFIG_B53_SPI_DRIVER=m
 CONFIG_B53_MDIO_DRIVER=m
 CONFIG_B53_MMAP_DRIVER=m
-CONFIG_B53_SRAB_DRIVER=m
 CONFIG_NET_DSA_BCM_SF2=m
 CONFIG_SUN4I_EMAC=y
 CONFIG_BCMGENET=m
@@ -259,7 +260,6 @@ CONFIG_BROADCOM_PHY=y
 CONFIG_ICPLUS_PHY=y
 CONFIG_MARVELL_PHY=y
 CONFIG_MICREL_PHY=y
-CONFIG_REALTEK_PHY=y
 CONFIG_ROCKCHIP_PHY=y
 CONFIG_SMSC_PHY=y
 CONFIG_USB_PEGASUS=y
@@ -288,6 +288,7 @@ CONFIG_MOUSE_ELAN_I2C=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ADC=m
 CONFIG_TOUCHSCREEN_ATMEL_MXT=m
+CONFIG_TOUCHSCREEN_ELAN=m
 CONFIG_TOUCHSCREEN_MMS114=m
 CONFIG_TOUCHSCREEN_WM97XX=m
 CONFIG_TOUCHSCREEN_ST1232=m
@@ -299,6 +300,7 @@ CONFIG_INPUT_MAX8997_HAPTIC=m
 CONFIG_INPUT_CPCAP_PWRBUTTON=m
 CONFIG_INPUT_AXP20X_PEK=m
 CONFIG_INPUT_ADXL34X=m
+CONFIG_INPUT_STPMIC1_ONKEY=y
 CONFIG_SERIO_AMBAKMI=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
@@ -349,6 +351,8 @@ CONFIG_SERIAL_DEV_BUS=y
 CONFIG_VIRTIO_CONSOLE=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_ST=y
+CONFIG_TCG_TPM=m
+CONFIG_TCG_TIS_I2C_INFINEON=m
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_ARB_GPIO_CHALLENGE=m
 CONFIG_I2C_MUX_PCA954x=y
@@ -386,6 +390,7 @@ CONFIG_SPI_BCM2835=y
 CONFIG_SPI_BCM2835AUX=y
 CONFIG_SPI_CADENCE=y
 CONFIG_SPI_DAVINCI=y
+CONFIG_SPI_FSL_QUADSPI=m
 CONFIG_SPI_GPIO=m
 CONFIG_SPI_FSL_DSPI=m
 CONFIG_SPI_OMAP24XX=y
@@ -444,9 +449,11 @@ CONFIG_POWER_RESET_RMOBILE=y
 CONFIG_BATTERY_ACT8945A=y
 CONFIG_BATTERY_CPCAP=m
 CONFIG_BATTERY_SBS=y
+CONFIG_BATTERY_BQ27XXX=m
 CONFIG_AXP20X_POWER=m
 CONFIG_BATTERY_MAX17040=m
 CONFIG_BATTERY_MAX17042=m
+CONFIG_CHARGER_GPIO=m
 CONFIG_CHARGER_CPCAP=m
 CONFIG_CHARGER_MAX14577=m
 CONFIG_CHARGER_MAX77693=m
@@ -486,6 +493,7 @@ CONFIG_TEGRA_WATCHDOG=m
 CONFIG_MESON_WATCHDOG=y
 CONFIG_DIGICOLOR_WATCHDOG=y
 CONFIG_RENESAS_WDT=m
+CONFIG_STPMIC1_WATCHDOG=y
 CONFIG_BCM47XX_WDT=y
 CONFIG_BCM2835_WDT=y
 CONFIG_BCM_KONA_WDT=y
@@ -505,6 +513,7 @@ CONFIG_MFD_AXP20X_RSB=y
 CONFIG_MFD_CROS_EC=m
 CONFIG_CROS_EC_I2C=m
 CONFIG_CROS_EC_SPI=m
+CONFIG_MFD_CROS_EC_CHARDEV=m
 CONFIG_MFD_DA9063=m
 CONFIG_MFD_MAX14577=y
 CONFIG_MFD_MAX77686=y
@@ -527,6 +536,7 @@ CONFIG_MFD_TPS65218=y
 CONFIG_MFD_TPS6586X=y
 CONFIG_MFD_TPS65910=y
 CONFIG_MFD_STM32_LPTIMER=m
+CONFIG_MFD_STPMIC1=y
 CONFIG_REGULATOR_ACT8865=y
 CONFIG_REGULATOR_ACT8945A=y
 CONFIG_REGULATOR_ANATOP=y
@@ -559,6 +569,7 @@ CONFIG_REGULATOR_RN5T618=y
 CONFIG_REGULATOR_S2MPS11=y
 CONFIG_REGULATOR_S5M8767=y
 CONFIG_REGULATOR_STM32_VREFBUF=m
+CONFIG_REGULATOR_STPMIC1=y
 CONFIG_REGULATOR_TI_ABB=y
 CONFIG_REGULATOR_TPS51632=y
 CONFIG_REGULATOR_TPS62360=y
@@ -579,8 +590,6 @@ CONFIG_MEDIA_USB_SUPPORT=y
 CONFIG_USB_VIDEO_CLASS=m
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_VIDEO_STM32_DCMI=m
-CONFIG_SOC_CAMERA=m
-CONFIG_SOC_CAMERA_PLATFORM=m
 CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS=m
 CONFIG_VIDEO_S5P_FIMC=m
 CONFIG_VIDEO_S5P_MIPI_CSIS=m
@@ -626,10 +635,12 @@ CONFIG_DRM_RCAR_LVDS=y
 CONFIG_DRM_SUN4I=m
 CONFIG_DRM_FSL_DCU=m
 CONFIG_DRM_TEGRA=y
-CONFIG_DRM_PANEL_ORISETECH_OTM8009A=m
-CONFIG_DRM_PANEL_RAYDIUM_RM68200=m
+CONFIG_DRM_STM=m
+CONFIG_DRM_STM_DSI=m
 CONFIG_DRM_PANEL_SIMPLE=y
 CONFIG_DRM_PANEL_SAMSUNG_LD9040=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_DUMB_VGA_DAC=m
@@ -641,8 +652,6 @@ CONFIG_DRM_TOSHIBA_TC358764=m
 CONFIG_DRM_I2C_ADV7511=m
 CONFIG_DRM_I2C_ADV7511_AUDIO=y
 CONFIG_DRM_STI=m
-CONFIG_DRM_STM=m
-CONFIG_DRM_STM_DSI=m
 CONFIG_DRM_VC4=m
 CONFIG_DRM_ETNAVIV=m
 CONFIG_DRM_MXSFB=m
@@ -701,7 +710,6 @@ CONFIG_SND_SOC_SGTL5000=m
 CONFIG_SND_SOC_SPDIF=m
 CONFIG_SND_SOC_STI_SAS=m
 CONFIG_SND_SOC_WM8978=m
-CONFIG_SND_SIMPLE_SCU_CARD=m
 CONFIG_USB=y
 CONFIG_USB_OTG=y
 CONFIG_USB_XHCI_HCD=y
@@ -877,7 +885,6 @@ CONFIG_UNIPHIER_MDMAC=y
 CONFIG_XILINX_DMA=y
 CONFIG_QCOM_BAM_DMA=y
 CONFIG_DW_DMAC=y
-CONFIG_SH_DMAE=y
 CONFIG_RCAR_DMAC=y
 CONFIG_RENESAS_USB_DMAC=m
 CONFIG_VIRTIO_PCI=y
@@ -910,6 +917,24 @@ CONFIG_QCOM_GSBI=y
 CONFIG_QCOM_PM=y
 CONFIG_QCOM_SMD_RPM=m
 CONFIG_QCOM_WCNSS_CTRL=m
+CONFIG_ARCH_EMEV2=y
+CONFIG_ARCH_R7S72100=y
+CONFIG_ARCH_R7S9210=y
+CONFIG_ARCH_R8A73A4=y
+CONFIG_ARCH_R8A7740=y
+CONFIG_ARCH_R8A7743=y
+CONFIG_ARCH_R8A7744=y
+CONFIG_ARCH_R8A7745=y
+CONFIG_ARCH_R8A77470=y
+CONFIG_ARCH_R8A7778=y
+CONFIG_ARCH_R8A7779=y
+CONFIG_ARCH_R8A7790=y
+CONFIG_ARCH_R8A7791=y
+CONFIG_ARCH_R8A7792=y
+CONFIG_ARCH_R8A7793=y
+CONFIG_ARCH_R8A7794=y
+CONFIG_ARCH_R9A06G032=y
+CONFIG_ARCH_SH73A0=y
 CONFIG_ROCKCHIP_PM_DOMAINS=y
 CONFIG_ARCH_TEGRA_2x_SOC=y
 CONFIG_ARCH_TEGRA_3x_SOC=y
@@ -925,6 +950,7 @@ CONFIG_AT91_SAMA5D2_ADC=m
 CONFIG_BERLIN2_ADC=m
 CONFIG_CPCAP_ADC=m
 CONFIG_EXYNOS_ADC=m
+CONFIG_MESON_SARADC=m
 CONFIG_STM32_ADC_CORE=m
 CONFIG_STM32_ADC=m
 CONFIG_STM32_DFSDM_ADC=m
@@ -932,8 +958,12 @@ CONFIG_VF610_ADC=m
 CONFIG_XILINX_XADC=y
 CONFIG_STM32_LPTIMER_CNT=m
 CONFIG_STM32_DAC=m
+CONFIG_ROCKCHIP_SARADC=m
+CONFIG_IIO_CROS_EC_SENSORS_CORE=m
+CONFIG_IIO_CROS_EC_SENSORS=m
 CONFIG_MPU3050_I2C=y
 CONFIG_CM36651=m
+CONFIG_IIO_CROS_EC_LIGHT_PROX=m
 CONFIG_SENSORS_ISL29018=y
 CONFIG_SENSORS_ISL29028=y
 CONFIG_AK8975=y
@@ -969,24 +999,21 @@ CONFIG_PHY_RCAR_GEN2=m
 CONFIG_PHY_ROCKCHIP_DP=m
 CONFIG_PHY_ROCKCHIP_USB=y
 CONFIG_PHY_SAMSUNG_USB2=m
+CONFIG_PHY_UNIPHIER_USB2=y
+CONFIG_PHY_UNIPHIER_USB3=y
 CONFIG_PHY_MIPHY28LP=y
 CONFIG_PHY_STIH407_USB=y
 CONFIG_PHY_STM32_USBPHYC=y
 CONFIG_PHY_TEGRA_XUSB=y
 CONFIG_PHY_DM816X_USB=m
-CONFIG_PHY_UNIPHIER_USB3=y
-CONFIG_PHY_UNIPHIER_USB2=y
 CONFIG_OMAP_USB2=y
 CONFIG_TI_PIPE3=y
 CONFIG_TWL4030_USB=m
+CONFIG_MESON_MX_EFUSE=m
+CONFIG_ROCKCHIP_EFUSE=m
 CONFIG_NVMEM_IMX_OCOTP=y
 CONFIG_NVMEM_SUNXI_SID=y
 CONFIG_NVMEM_VF610_OCOTP=y
-CONFIG_RASPBERRYPI_FIRMWARE=y
-CONFIG_BCM47XX_NVRAM=y
-CONFIG_BCM47XX_SPROM=y
-CONFIG_EFI_VARS=m
-CONFIG_EFI_CAPSULE_LOADER=m
 CONFIG_EXT4_FS=y
 CONFIG_AUTOFS4_FS=y
 CONFIG_MSDOS_FS=y
@@ -1008,8 +1035,6 @@ CONFIG_ROOT_NFS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_UTF8=y
-CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
@@ -1023,16 +1048,6 @@ CONFIG_CRYPTO_DEV_ATMEL_TDES=m
 CONFIG_CRYPTO_DEV_ATMEL_SHA=m
 CONFIG_CRYPTO_DEV_SUN4I_SS=m
 CONFIG_CRYPTO_DEV_ROCKCHIP=m
-CONFIG_ARM_CRYPTO=y
-CONFIG_CRYPTO_SHA1_ARM_NEON=m
-CONFIG_CRYPTO_SHA1_ARM_CE=m
-CONFIG_CRYPTO_SHA2_ARM_CE=m
-CONFIG_CRYPTO_SHA512_ARM=m
-CONFIG_CRYPTO_AES_ARM=m
-CONFIG_CRYPTO_AES_ARM_BS=m
-CONFIG_CRYPTO_AES_ARM_CE=m
-CONFIG_CRYPTO_GHASH_ARM_CE=m
-CONFIG_CRYPTO_CRC32_ARM_CE=m
-CONFIG_CRYPTO_CHACHA20_NEON=m
-CONFIG_GCC_PLUGINS=y
-CONFIG_GCC_PLUGIN_STRUCTLEAK=y
+CONFIG_CMA_SIZE_MBYTES=64
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
index 0448bd8075acda0cb6568889f99e5ec744f17789..e9567513f0685f72dd8f61b4cf9346e1b12f164a 100644 (file)
@@ -47,7 +47,7 @@ CONFIG_MTD_CFI_GEOMETRY=y
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_ORION=y
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_SCSI_PROC_FS is not set
index 4b598da0d086eb1fe5da1cc2a62d0f81fd737834..0e5577a31851b4968902bc87072e86f30f6aa353 100644 (file)
@@ -77,7 +77,7 @@ CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_STAA=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_M25P80=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_ORION=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_BLK_DEV_LOOP=y
index 55140219ab110a88560e2bd3d259309e3fef0bde..48f7b4277b8ddd83dd2b24f465ac6438cefb6a69 100644 (file)
@@ -52,7 +52,7 @@ CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_CFI_STAA=y
 CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_MTD_M25P80=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_MARVELL=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_MTD_UBI=y
index 38480596c44983de48d7ff37ea7e274b4f1eaad5..ed570a0d1f2ac530e47e90e9d8cff21fad546b46 100644 (file)
@@ -50,7 +50,7 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_DATAFLASH=y
 CONFIG_MTD_M25P80=y
 CONFIG_MTD_SST25L=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_GPMI_NAND=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_MTD_UBI=y
index 5f4c6aaa07f628c21f28b03c0cb75f3e80911f0e..cfc094189d09a32adf9548a026c8ba8fa70ff873 100644 (file)
@@ -53,8 +53,8 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_ONENAND=y
 CONFIG_MTD_ONENAND_VERIFY_WRITE=y
 CONFIG_MTD_ONENAND_GENERIC=y
-CONFIG_MTD_NAND_ECC_SMC=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_FSMC=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=y
index 8448a7f407a4e1595664a95b8ba319d74eb6db29..82af77c093f16dd34dc924a1e2642e4e7a368591 100644 (file)
@@ -89,7 +89,7 @@ CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=2
index 3f03ec6d26442df96b7e265db3f17293618163d2..c7bf9c4936460ab3cd3bcc1b3e7a9917ac274de2 100644 (file)
@@ -143,8 +143,8 @@ CONFIG_MTD_M25P80=m
 CONFIG_MTD_ONENAND=y
 CONFIG_MTD_ONENAND_VERIFY_WRITE=y
 CONFIG_MTD_ONENAND_OMAP2=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ECC_BCH=y
+CONFIG_MTD_RAW_NAND=y
+CONFIG_MTD_NAND_ECC_SW_BCH=y
 CONFIG_MTD_NAND_OMAP2=y
 CONFIG_MTD_NAND_OMAP_BCH=y
 CONFIG_MTD_SPI_NOR=m
index bf9046331f6ef479ee02a6de98b1f30912e3612c..077e0fde1ff95e91c23e0e9148dbc420e792ff3e 100644 (file)
@@ -70,7 +70,7 @@ CONFIG_MTD_CFI_GEOMETRY=y
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_PLATFORM=y
 CONFIG_MTD_NAND_ORION=y
 CONFIG_BLK_DEV_LOOP=y
index f6ba32c9d17339c4e2dbc35228b0be5b0d0b021c..cae0db6b4eaf30e2cf943a2678f2b66a442f2d4a 100644 (file)
@@ -50,7 +50,7 @@ CONFIG_SIMPLE_PM_BUS=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_OXNAS=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
index 3e0de035ab7725fb742b9f47806c474ae7d87868..7681eea601276f3f0b4a1fa43699ed57d42d7373 100644 (file)
@@ -31,7 +31,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_MARVELL=y
 CONFIG_MTD_ONENAND=y
 CONFIG_MTD_ONENAND_VERIFY_WRITE=y
index d4654755b09cbad7b862ede4e9e26eb053dc925e..07ebbdce36451c85e0a868d501821583f7c35315 100644 (file)
@@ -185,8 +185,8 @@ CONFIG_MTD_PXA2XX=m
 CONFIG_MTD_M25P80=m
 CONFIG_MTD_BLOCK2MTD=y
 CONFIG_MTD_DOCG3=m
-CONFIG_MTD_NAND=m
-CONFIG_MTD_NAND_ECC_BCH=y
+CONFIG_MTD_RAW_NAND=m
+CONFIG_MTD_NAND_ECC_SW_BCH=y
 CONFIG_MTD_NAND_GPIO=m
 CONFIG_MTD_NAND_DISKONCHIP=m
 CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED=y
@@ -387,7 +387,7 @@ CONFIG_SENSORS_LM75=m
 CONFIG_SENSORS_LM90=m
 CONFIG_SENSORS_LM95245=m
 CONFIG_SENSORS_NTC_THERMISTOR=m
-CONFIG_THERMAL=m
+CONFIG_THERMAL=y
 CONFIG_WATCHDOG=y
 CONFIG_XILINX_WATCHDOG=m
 CONFIG_SA1100_WATCHDOG=m
index bd6440f234939eb450cd47af85e292429eaf0821..c1854751c99af28c7b242877056654a785770b57 100644 (file)
@@ -50,14 +50,15 @@ 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_CFG80211=y
+CONFIG_CFG80211=m
+CONFIG_MAC80211=m
 CONFIG_RFKILL=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_M25P80=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_QCOM=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_BLK_DEV_LOOP=y
@@ -72,6 +73,8 @@ CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_ATA=y
 CONFIG_SATA_AHCI=y
 CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=m
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
 CONFIG_ATL1C=y
@@ -85,6 +88,7 @@ CONFIG_SLIP_MODE_SLIP6=y
 CONFIG_USB_USBNET=y
 # CONFIG_USB_NET_AX8817X is not set
 # CONFIG_USB_NET_ZAURUS is not set
+CONFIG_WCN36XX=m
 CONFIG_BRCMFMAC=m
 CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
@@ -94,6 +98,8 @@ CONFIG_KEYBOARD_PMIC8XXX=y
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_INPUT_MISC=y
+CONFIG_INPUT_MSM_VIBRATOR=m
+CONFIG_INPUT_PM8941_PWRKEY=m
 CONFIG_INPUT_PM8XXX_VIBRATOR=y
 CONFIG_INPUT_PMIC8XXX_PWRKEY=y
 CONFIG_INPUT_UINPUT=y
@@ -127,6 +133,7 @@ CONFIG_GPIO_SYSFS=y
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_MSM=y
 CONFIG_CHARGER_QCOM_SMBB=y
+CONFIG_CHARGER_BQ24190=m
 CONFIG_THERMAL=y
 CONFIG_QCOM_TSENS=y
 CONFIG_MFD_PM8XXX=y
@@ -226,7 +233,11 @@ CONFIG_IIO=y
 CONFIG_IIO_BUFFER_CB=y
 CONFIG_IIO_SW_TRIGGER=y
 CONFIG_KXSD9=y
+CONFIG_QCOM_SPMI_IADC=m
+CONFIG_QCOM_SPMI_VADC=m
 CONFIG_MPU3050_I2C=y
+CONFIG_INV_MPU6050_I2C=m
+CONFIG_TSL2772=m
 CONFIG_AK8975=y
 CONFIG_IIO_HRTIMER_TRIGGER=y
 CONFIG_BMP280=y
index 2afb359f3168d50d2fb2a7ed47bf3f515ff3e7af..39c648594d934c2864d6ecf71589ca0a1e626430 100644 (file)
@@ -192,7 +192,7 @@ CONFIG_MTD_JEDECPROBE=y
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_ROM=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_S3C2410=y
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=m
index 507d7ad7523a795afb7f48a5eb96e3932b931824..6e2656567da64d7b6678f234f43a47334ff484e1 100644 (file)
@@ -23,7 +23,7 @@ CONFIG_CMDLINE="console=ttySAC0,115200 root=/dev/ram init=/linuxrc initrd=0x5100
 CONFIG_VFP=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_S3C2410=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
index b0026f73083d7b1f929202405c286047a8fb1769..515cb37eeab68f277de3f3e8eca194d5f8e39b57 100644 (file)
@@ -66,7 +66,7 @@ CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_M25P80=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_MTD_UBI=y
index 9b0efac101abc992effd69cdd000b02143b26418..eb02ba9ec6e625f9264b9a09e754408d320a0221 100644 (file)
@@ -43,11 +43,13 @@ CONFIG_PCI_RCAR_GEN2=y
 CONFIG_PCIE_RCAR=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_DMA_CMA=y
-CONFIG_CMA_SIZE_MBYTES=64
 CONFIG_SIMPLE_PM_BUS=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_MTD_M25P80=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_EEPROM_AT24=y
@@ -123,7 +125,6 @@ CONFIG_VIDEO_ADV7604=y
 CONFIG_VIDEO_ML86V7667=y
 CONFIG_DRM=y
 CONFIG_DRM_RCAR_DU=y
-CONFIG_DRM_RCAR_LVDS=y
 CONFIG_DRM_DUMB_VGA_DAC=y
 CONFIG_DRM_SII902X=y
 CONFIG_DRM_I2C_ADV7511=y
@@ -141,12 +142,13 @@ CONFIG_SND_SOC_RCAR=y
 CONFIG_SND_SOC_AK4642=y
 CONFIG_SND_SOC_SGTL5000=y
 CONFIG_SND_SOC_WM8978=y
-CONFIG_SND_SIMPLE_SCU_CARD=y
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_PLATFORM=y
 CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
 CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
 CONFIG_USB_R8A66597_HCD=y
 CONFIG_USB_RENESAS_USBHS=y
 CONFIG_USB_GADGET=y
@@ -197,6 +199,7 @@ CONFIG_PWM_RENESAS_TPU=y
 CONFIG_RESET_CONTROLLER=y
 CONFIG_GENERIC_PHY=y
 CONFIG_PHY_RCAR_GEN2=y
+CONFIG_PHY_RCAR_GEN3_USB2=y
 # CONFIG_DNOTIFY is not set
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
@@ -209,6 +212,8 @@ CONFIG_NFS_V4_1=y
 CONFIG_ROOT_NFS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=64
 CONFIG_PRINTK_TIME=y
 # CONFIG_ENABLE_MUST_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
index 08d1b3e11d68c81cd917eae56b9d226671888809..9d42cfe85f5bbbb8bb3d9d2ad736064bf6d8ad71 100644 (file)
@@ -51,7 +51,7 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_M25P80=y
-CONFIG_MTD_NAND=y
+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
@@ -106,6 +106,7 @@ CONFIG_SENSORS_LTC2978_REGULATOR=y
 CONFIG_WATCHDOG=y
 CONFIG_DW_WATCHDOG=y
 CONFIG_MFD_ALTERA_A10SR=y
+CONFIG_MFD_ALTERA_SYSMGR=y
 CONFIG_MFD_STMPE=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
index 7b36eeb928bb1125e53bd66157cdcee645bf89a7..8ee3679ca8b29dbcfafdf18b64b91e02dcf4eb70 100644 (file)
@@ -32,7 +32,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_OF_PARTS=y
 CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_FSMC=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=16384
index f1b52fb3461b2c32a03f1c94c7f76e6deaac9e8c..ddd73b25f75e86b22c35c006f54fb783652ca522 100644 (file)
@@ -17,7 +17,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_OF_PARTS=y
 CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_FSMC=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=16384
index 124c244d8df12d71f832dd05c3ae5a65e75a743a..5b410f0a365b1af6fab83aefd9fa8f1a8ee63501 100644 (file)
@@ -14,7 +14,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_OF_PARTS=y
 CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_FSMC=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=16384
index 9ea82c118661b179dea1284ac55b7ac7fde12d1e..f6d2f674517c2768e8369a37890402878b9a129c 100644 (file)
@@ -84,7 +84,7 @@ CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_ROM=y
 CONFIG_MTD_COMPLEX_MAPPINGS=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_SHARPSL=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_SD=y
index 68725d4eae4531a09042df1497859cbfee389b70..68eb16e583ac2a3ac2b56eceac9f33ea2c1cc254 100644 (file)
@@ -39,7 +39,7 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
 CONFIG_MTD_TESTS=m
 CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_TANGO=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_SCSI=y
index c7b99ebf5fcf43b98872caa20852d2c17d8fe435..8f5c6a5b444c5a76162ef9ad509231db0f15e299 100644 (file)
@@ -1,6 +1,7 @@
 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
@@ -14,23 +15,9 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=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_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_ARCH_TEGRA=y
-CONFIG_PCI=y
-CONFIG_PCIEPORTBUS=y
-CONFIG_PCI_MSI=y
-CONFIG_PCI_TEGRA=y
 CONFIG_SMP=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
-CONFIG_CMA=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_KEXEC=y
@@ -40,6 +27,13 @@ CONFIG_CPUFREQ_DT=y
 CONFIG_CPU_IDLE=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_CMA=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -73,10 +67,12 @@ CONFIG_MAC80211=y
 CONFIG_RFKILL=y
 CONFIG_RFKILL_INPUT=y
 CONFIG_RFKILL_GPIO=y
+CONFIG_PCI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_TEGRA=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_DMA_CMA=y
-CONFIG_CMA_SIZE_MBYTES=64
 CONFIG_TEGRA_GMI=y
 CONFIG_MTD=y
 CONFIG_MTD_M25P80=y
@@ -152,7 +148,6 @@ CONFIG_WATCHDOG=y
 CONFIG_TEGRA_WATCHDOG=y
 CONFIG_MFD_AS3722=y
 CONFIG_MFD_CROS_EC=y
-CONFIG_MFD_CROS_EC_SPI=y
 CONFIG_MFD_MAX8907=y
 CONFIG_MFD_STMPE=y
 CONFIG_MFD_PALMAS=y
@@ -180,6 +175,7 @@ CONFIG_DRM_NOUVEAU=m
 CONFIG_DRM_TEGRA=y
 CONFIG_DRM_PANEL_SIMPLE=y
 # CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_BACKLIGHT_GENERIC is not set
 CONFIG_BACKLIGHT_PWM=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
@@ -288,6 +284,10 @@ CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRC_CCITT=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=64
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_INFO=y
 CONFIG_MAGIC_SYSRQ=y
@@ -300,5 +300,3 @@ CONFIG_DEBUG_MUTEXES=y
 CONFIG_DEBUG_SG=y
 CONFIG_DEBUG_LL=y
 CONFIG_EARLY_PRINTK=y
-CONFIG_CRYPTO_TWOFISH=y
-CONFIG_CRC_CCITT=y
index 2b5a224d2da1a6c31e36b3c2eed288e4483f12c9..ecad22501b48f213f2c313c14d39f59183c10d32 100644 (file)
@@ -76,7 +76,7 @@ CONFIG_MTD_DOC2001PLUS=y
 CONFIG_MTD_DOCPROBE_ADVANCED=y
 CONFIG_MTD_DOCPROBE_ADDRESS=0x4000000
 CONFIG_MTD_DOCPROBE_HIGH=y
-CONFIG_MTD_NAND=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
index 831ba6a9ee8b30fb63fe6584eb081beccb7b43ed..bedf397c75dec42b6f5f66d4106200bd4cf781aa 100644 (file)
@@ -26,7 +26,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_FSMC=y
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
diff --git a/arch/arm/firmware/Kconfig b/arch/arm/firmware/Kconfig
deleted file mode 100644 (file)
index ad396af..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-config ARCH_SUPPORTS_FIRMWARE
-       bool
-
-config ARCH_SUPPORTS_TRUSTED_FOUNDATIONS
-       bool
-       select ARCH_SUPPORTS_FIRMWARE
-
-menu "Firmware options"
-       depends on ARCH_SUPPORTS_FIRMWARE
-
-config TRUSTED_FOUNDATIONS
-       bool "Trusted Foundations secure monitor support"
-       depends on ARCH_SUPPORTS_TRUSTED_FOUNDATIONS
-       default y
-       help
-         Some devices (including most Tegra-based consumer devices on the
-         market) are booted with the Trusted Foundations secure monitor
-         active, requiring some core operations to be performed by the secure
-         monitor instead of the kernel.
-
-         This option allows the kernel to invoke the secure monitor whenever
-         required on devices using Trusted Foundations. See
-         arch/arm/include/asm/trusted_foundations.h or the
-         tlm,trusted-foundations device tree binding documentation for details
-         on how to use it.
-
-         Say n if you don't know what this is about.
-
-endmenu
diff --git a/arch/arm/firmware/Makefile b/arch/arm/firmware/Makefile
deleted file mode 100644 (file)
index 6e41336..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-obj-$(CONFIG_TRUSTED_FOUNDATIONS)      += trusted_foundations.o
-
-# tf_generic_smc() fails to build with -fsanitize-coverage=trace-pc
-KCOV_INSTRUMENT                := n
diff --git a/arch/arm/firmware/trusted_foundations.c b/arch/arm/firmware/trusted_foundations.c
deleted file mode 100644 (file)
index 689e656..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Trusted Foundations support for ARM CPUs
- *
- * Copyright (c) 2013, NVIDIA 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; 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/of.h>
-#include <asm/firmware.h>
-#include <asm/trusted_foundations.h>
-
-#define TF_SET_CPU_BOOT_ADDR_SMC 0xfffff200
-
-#define TF_CPU_PM              0xfffffffc
-#define TF_CPU_PM_S3           0xffffffe3
-#define TF_CPU_PM_S2           0xffffffe6
-#define TF_CPU_PM_S2_NO_MC_CLK 0xffffffe5
-#define TF_CPU_PM_S1           0xffffffe4
-#define TF_CPU_PM_S1_NOFLUSH_L2        0xffffffe7
-
-static unsigned long cpu_boot_addr;
-
-static void tf_generic_smc(u32 type, u32 arg1, u32 arg2)
-{
-       register u32 r0 asm("r0") = type;
-       register u32 r1 asm("r1") = arg1;
-       register u32 r2 asm("r2") = arg2;
-
-       asm volatile(
-               ".arch_extension        sec\n\t"
-               "stmfd  sp!, {r4 - r11}\n\t"
-               __asmeq("%0", "r0")
-               __asmeq("%1", "r1")
-               __asmeq("%2", "r2")
-               "mov    r3, #0\n\t"
-               "mov    r4, #0\n\t"
-               "smc    #0\n\t"
-               "ldmfd  sp!, {r4 - r11}\n\t"
-               :
-               : "r" (r0), "r" (r1), "r" (r2)
-               : "memory", "r3", "r12", "lr");
-}
-
-static int tf_set_cpu_boot_addr(int cpu, unsigned long boot_addr)
-{
-       cpu_boot_addr = boot_addr;
-       tf_generic_smc(TF_SET_CPU_BOOT_ADDR_SMC, cpu_boot_addr, 0);
-
-       return 0;
-}
-
-static int tf_prepare_idle(void)
-{
-       tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1_NOFLUSH_L2, cpu_boot_addr);
-
-       return 0;
-}
-
-static const struct firmware_ops trusted_foundations_ops = {
-       .set_cpu_boot_addr = tf_set_cpu_boot_addr,
-       .prepare_idle = tf_prepare_idle,
-};
-
-void register_trusted_foundations(struct trusted_foundations_platform_data *pd)
-{
-       /*
-        * we are not using version information for now since currently
-        * supported SMCs are compatible with all TF releases
-        */
-       register_firmware_ops(&trusted_foundations_ops);
-}
-
-void of_register_trusted_foundations(void)
-{
-       struct device_node *node;
-       struct trusted_foundations_platform_data pdata;
-       int err;
-
-       node = of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations");
-       if (!node)
-               return;
-
-       err = of_property_read_u32(node, "tlm,version-major",
-                                  &pdata.version_major);
-       if (err != 0)
-               panic("Trusted Foundation: missing version-major property\n");
-       err = of_property_read_u32(node, "tlm,version-minor",
-                                  &pdata.version_minor);
-       if (err != 0)
-               panic("Trusted Foundation: missing version-minor property\n");
-       register_trusted_foundations(&pdata);
-}
index 41deac2451af48ada5b7f59ccea8091bdc78be18..60de9d13181ad07e0449bfdd69a45336d5294f27 100644 (file)
@@ -14,10 +14,8 @@ generic-y += msi.h
 generic-y += parport.h
 generic-y += preempt.h
 generic-y += seccomp.h
-generic-y += segment.h
 generic-y += serial.h
 generic-y += simd.h
-generic-y += sizes.h
 generic-y += trace_clock.h
 
 generated-y += mach-types.h
index 99d9f630d6b6838954bde8ddbdd90b0b5ace17b8..1888c2d15da5463e8020a88a93c87ef6cb52448d 100644 (file)
@@ -133,9 +133,11 @@ static inline void modify_domain(unsigned dom, unsigned type)      { }
  * instructions (inline assembly)
  */
 #ifdef CONFIG_CPU_USE_DOMAINS
-#define TUSER(instr)   #instr "t"
+#define TUSER(instr)           TUSERCOND(instr, )
+#define TUSERCOND(instr, cond) #instr "t" #cond
 #else
-#define TUSER(instr)   #instr
+#define TUSER(instr)           TUSERCOND(instr, )
+#define TUSERCOND(instr, cond) #instr #cond
 #endif
 
 #else /* __ASSEMBLY__ */
index 34c1d96ef46df68f0f354c111c121f9cee1067ca..6698272bbcbf9679468fa864504e64b5426d1a06 100644 (file)
@@ -24,7 +24,7 @@ struct firmware_ops {
        /*
         * Inform the firmware we intend to enter CPU idle mode
         */
-       int (*prepare_idle)(void);
+       int (*prepare_idle)(unsigned long mode);
        /*
         * Enters CPU idle mode
         */
index 0a46676b4245b3d15292eac1c03f5915033d8cae..83c391b597d45f82f107ac55103bf80b52b8045a 100644 (file)
@@ -110,10 +110,11 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
        preempt_disable();
        __ua_flags = uaccess_save_and_enable();
        __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
+       "       .syntax unified\n"
        "1:     " TUSER(ldr) "  %1, [%4]\n"
        "       teq     %1, %2\n"
        "       it      eq      @ explicit IT needed for the 2b label\n"
-       "2:     " TUSER(streq) "        %3, [%4]\n"
+       "2:     " TUSERCOND(str, eq) "  %3, [%4]\n"
        __futex_atomic_ex_table("%5")
        : "+r" (ret), "=&r" (val)
        : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
index cba23eaa607215aaaab9342c6a661b06ebd07db8..7a88f160b1fbe9b84a6f39c04a311b02d996b447 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
+/* number of IPIS _not_ including IPI_CPU_BACKTRACE */
 #define NR_IPI 7
 
 typedef struct {
index 8927cae7c96662a4f4bb3187a8beca641cbe6e5a..efb0e2c0d84cdf866a2a4572e1dc01a9a6e945da 100644 (file)
@@ -343,4 +343,6 @@ static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu,
        }
 }
 
+static inline void vcpu_ptrauth_setup_lazy(struct kvm_vcpu *vcpu) {}
+
 #endif /* __ARM_KVM_EMULATE_H__ */
index 770d73257ad936d6dea09f11d05b9639bd00b051..075e1921fdd909096715f6c23c2ab0eb185f0b1a 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef __ARM_KVM_HOST_H__
 #define __ARM_KVM_HOST_H__
 
+#include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/kvm_types.h>
 #include <asm/cputype.h>
@@ -53,6 +54,8 @@
 
 DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
 
+static inline int kvm_arm_init_sve(void) { return 0; }
+
 u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
@@ -150,9 +153,13 @@ struct kvm_cpu_context {
        u32 cp15[NR_CP15_REGS];
 };
 
-typedef struct kvm_cpu_context kvm_cpu_context_t;
+struct kvm_host_data {
+       struct kvm_cpu_context host_ctxt;
+};
+
+typedef struct kvm_host_data kvm_host_data_t;
 
-static inline void kvm_init_host_cpu_context(kvm_cpu_context_t *cpu_ctxt,
+static inline void kvm_init_host_cpu_context(struct kvm_cpu_context *cpu_ctxt,
                                             int cpu)
 {
        /* The host's MPIDR is immutable, so let's set it up at boot time */
@@ -182,7 +189,7 @@ struct kvm_vcpu_arch {
        struct kvm_vcpu_fault_info fault;
 
        /* Host FP context */
-       kvm_cpu_context_t *host_cpu_context;
+       struct kvm_cpu_context *host_cpu_context;
 
        /* VGIC state */
        struct vgic_cpu vgic_cpu;
@@ -361,6 +368,9 @@ static inline void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu) {}
 static inline void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu) {}
 static inline void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu) {}
 
+static inline void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu) {}
+static inline void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu) {}
+
 static inline void kvm_arm_vhe_guest_enter(void) {}
 static inline void kvm_arm_vhe_guest_exit(void) {}
 
@@ -409,4 +419,14 @@ static inline int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
        return 0;
 }
 
+static inline int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature)
+{
+       return -EINVAL;
+}
+
+static inline bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
+{
+       return true;
+}
+
 #endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm/include/asm/limits.h b/arch/arm/include/asm/limits.h
deleted file mode 100644 (file)
index ab15937..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __ASM_PIPE_H
-#define __ASM_PIPE_H
-
-#ifndef PAGE_SIZE
-#include <asm/page.h>
-#endif
-
-#define PIPE_BUF       PAGE_SIZE
-
-#endif
-
index 57fe73ea0f7258af4315ea6b7fcecea7566d838e..5d06f75ffad47ab486b43552ca7814d50086cdba 100644 (file)
@@ -135,8 +135,8 @@ static inline void prefetchw(const void *ptr)
        __asm__ __volatile__(
                ".arch_extension        mp\n"
                __ALT_SMP_ASM(
-                       WASM(pldw)              "\t%a0",
-                       WASM(pld)               "\t%a0"
+                       "pldw\t%a0",
+                       "pld\t%a0"
                )
                :: "p" (ptr));
 }
diff --git a/arch/arm/include/asm/trusted_foundations.h b/arch/arm/include/asm/trusted_foundations.h
deleted file mode 100644 (file)
index 0074835..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2013, NVIDIA 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; 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.
- */
-
-/*
- * Support for the Trusted Foundations secure monitor.
- *
- * Trusted Foundation comes active on some ARM consumer devices (most
- * Tegra-based devices sold on the market are concerned). Such devices can only
- * perform some basic operations, like setting the CPU reset vector, through
- * SMC calls to the secure monitor. The calls are completely specific to
- * Trusted Foundations, and do *not* follow the SMC calling convention or the
- * PSCI standard.
- */
-
-#ifndef __ASM_ARM_TRUSTED_FOUNDATIONS_H
-#define __ASM_ARM_TRUSTED_FOUNDATIONS_H
-
-#include <linux/printk.h>
-#include <linux/bug.h>
-#include <linux/of.h>
-#include <linux/cpu.h>
-#include <linux/smp.h>
-
-struct trusted_foundations_platform_data {
-       unsigned int version_major;
-       unsigned int version_minor;
-};
-
-#if IS_ENABLED(CONFIG_TRUSTED_FOUNDATIONS)
-
-void register_trusted_foundations(struct trusted_foundations_platform_data *pd);
-void of_register_trusted_foundations(void);
-
-#else /* CONFIG_TRUSTED_FOUNDATIONS */
-
-static inline void register_trusted_foundations(
-                                  struct trusted_foundations_platform_data *pd)
-{
-       /*
-        * If the system requires TF and we cannot provide it, continue booting
-        * but disable features that cannot be provided.
-        */
-       pr_err("No support for Trusted Foundations, continuing in degraded mode.\n");
-       pr_err("Secondary processors as well as CPU PM will be disabled.\n");
-#if IS_ENABLED(CONFIG_SMP)
-       setup_max_cpus = 0;
-#endif
-       cpu_idle_poll_ctrl(true);
-}
-
-static inline void of_register_trusted_foundations(void)
-{
-       /*
-        * If we find the target should enable TF but does not support it,
-        * fail as the system won't be able to do much anyway
-        */
-       if (of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations"))
-               register_trusted_foundations(NULL);
-}
-#endif /* CONFIG_TRUSTED_FOUNDATIONS */
-
-#endif
index dff49845eb87628a007776e695fc4103db1a7a58..d49ce8f48be38bbc4c8fc4c357dfacf9a79a29f5 100644 (file)
@@ -112,10 +112,11 @@ static inline void __user *__uaccess_mask_range_ptr(const void __user *ptr,
        unsigned long tmp;
 
        asm volatile(
+       "       .syntax unified\n"
        "       sub     %1, %3, #1\n"
        "       subs    %1, %1, %0\n"
        "       addhs   %1, %1, #1\n"
-       "       subhss  %1, %1, %2\n"
+       "       subshs  %1, %1, %2\n"
        "       movlo   %0, #0\n"
        : "+r" (safe_ptr), "=&r" (tmp)
        : "r" (size), "r" (current_thread_info()->addr_limit)
index 20110022630163e29183b7bac67ed39ff0c325e7..067e12edc34199edbb77617654b5ef5bb0b49e48 100644 (file)
@@ -5,7 +5,7 @@ void convert_to_tag_list(struct tag *tags);
 const struct machine_desc *setup_machine_tags(phys_addr_t __atags_pointer,
        unsigned int machine_nr);
 #else
-static inline const struct machine_desc *
+static inline const struct machine_desc * __init __noreturn
 setup_machine_tags(phys_addr_t __atags_pointer, unsigned int machine_nr)
 {
        early_print("no ATAGS support: can't continue\n");
index facd4240ca02c776716a2e1e14c803c359967cc8..ebc53804d57b717270a03f3806bacf64000f9f09 100644 (file)
@@ -70,6 +70,10 @@ enum ipi_msg_type {
        IPI_CPU_STOP,
        IPI_IRQ_WORK,
        IPI_COMPLETION,
+       /*
+        * CPU_BACKTRACE is special and not included in NR_IPI
+        * or tracable with trace_ipi_*
+        */
        IPI_CPU_BACKTRACE,
        /*
         * SGI8-15 can be reserved by secure firmware, and thus may
@@ -754,15 +758,20 @@ static int cpufreq_callback(struct notifier_block *nb,
                                        unsigned long val, void *data)
 {
        struct cpufreq_freqs *freq = data;
-       int cpu = freq->cpu;
+       struct cpumask *cpus = freq->policy->cpus;
+       int cpu, first = cpumask_first(cpus);
+       unsigned int lpj;
 
        if (freq->flags & CPUFREQ_CONST_LOOPS)
                return NOTIFY_OK;
 
-       if (!per_cpu(l_p_j_ref, cpu)) {
-               per_cpu(l_p_j_ref, cpu) =
-                       per_cpu(cpu_data, cpu).loops_per_jiffy;
-               per_cpu(l_p_j_ref_freq, cpu) = freq->old;
+       if (!per_cpu(l_p_j_ref, first)) {
+               for_each_cpu(cpu, cpus) {
+                       per_cpu(l_p_j_ref, cpu) =
+                               per_cpu(cpu_data, cpu).loops_per_jiffy;
+                       per_cpu(l_p_j_ref_freq, cpu) = freq->old;
+               }
+
                if (!global_l_p_j_ref) {
                        global_l_p_j_ref = loops_per_jiffy;
                        global_l_p_j_ref_freq = freq->old;
@@ -774,10 +783,11 @@ static int cpufreq_callback(struct notifier_block *nb,
                loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
                                                global_l_p_j_ref_freq,
                                                freq->new);
-               per_cpu(cpu_data, cpu).loops_per_jiffy =
-                       cpufreq_scale(per_cpu(l_p_j_ref, cpu),
-                                       per_cpu(l_p_j_ref_freq, cpu),
-                                       freq->new);
+
+               lpj = cpufreq_scale(per_cpu(l_p_j_ref, first),
+                                   per_cpu(l_p_j_ref_freq, first), freq->new);
+               for_each_cpu(cpu, cpus)
+                       per_cpu(cpu_data, cpu).loops_per_jiffy = lpj;
        }
        return NOTIFY_OK;
 }
@@ -797,7 +807,7 @@ core_initcall(register_cpufreq_notifier);
 
 static void raise_nmi(cpumask_t *mask)
 {
-       smp_cross_call(mask, IPI_CPU_BACKTRACE);
+       __smp_cross_call(mask, IPI_CPU_BACKTRACE);
 }
 
 void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
index ff097ecfa451e24ab4912c0f4de0cf2fd7baad69..51a892702e2782f7337215f734fab30e835b7a1c 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/platform_data/spi-davinci.h>
 #include <linux/platform_data/usb-davinci.h>
 #include <linux/platform_data/ti-aemif.h>
+#include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/nvmem-provider.h>
 
@@ -53,14 +54,50 @@ static const short da830_evm_usb11_pins[] = {
        -1
 };
 
-static struct gpiod_lookup_table da830_evm_usb_gpio_lookup = {
+static struct regulator_consumer_supply da830_evm_usb_supplies[] = {
+       REGULATOR_SUPPLY("vbus", NULL),
+};
+
+static struct regulator_init_data da830_evm_usb_vbus_data = {
+       .consumer_supplies      = da830_evm_usb_supplies,
+       .num_consumer_supplies  = ARRAY_SIZE(da830_evm_usb_supplies),
+};
+
+static struct fixed_voltage_config da830_evm_usb_vbus = {
+       .supply_name            = "vbus",
+       .microvolts             = 33000000,
+       .init_data              = &da830_evm_usb_vbus_data,
+};
+
+static struct platform_device da830_evm_usb_vbus_device = {
+       .name           = "reg-fixed-voltage",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &da830_evm_usb_vbus,
+       },
+};
+
+static struct gpiod_lookup_table da830_evm_usb_oc_gpio_lookup = {
        .dev_id         = "ohci-da8xx",
        .table = {
-               GPIO_LOOKUP("davinci_gpio", ON_BD_USB_DRV, "vbus", 0),
                GPIO_LOOKUP("davinci_gpio", ON_BD_USB_OVC, "oc", 0),
+               { }
        },
 };
 
+static struct gpiod_lookup_table da830_evm_usb_vbus_gpio_lookup = {
+       .dev_id         = "reg-fixed-voltage.0",
+       .table = {
+               GPIO_LOOKUP("davinci_gpio", ON_BD_USB_DRV, "vbus", 0),
+               { }
+       },
+};
+
+static struct gpiod_lookup_table *da830_evm_usb_gpio_lookups[] = {
+       &da830_evm_usb_oc_gpio_lookup,
+       &da830_evm_usb_vbus_gpio_lookup,
+};
+
 static struct da8xx_ohci_root_hub da830_evm_usb11_pdata = {
        /* TPS2065 switch @ 5V */
        .potpgt         = (3 + 1) / 2,  /* 3 ms max */
@@ -75,6 +112,9 @@ static __init void da830_evm_usb_init(void)
                pr_warn("%s: USB PHY CLK registration failed: %d\n",
                        __func__, ret);
 
+       gpiod_add_lookup_tables(da830_evm_usb_gpio_lookups,
+                               ARRAY_SIZE(da830_evm_usb_gpio_lookups));
+
        ret = da8xx_register_usb_phy();
        if (ret)
                pr_warn("%s: USB PHY registration failed: %d\n",
@@ -100,7 +140,11 @@ static __init void da830_evm_usb_init(void)
                return;
        }
 
-       gpiod_add_lookup_table(&da830_evm_usb_gpio_lookup);
+       ret = platform_device_register(&da830_evm_usb_vbus_device);
+       if (ret) {
+               pr_warn("%s: Unable to register the vbus supply\n", __func__);
+               return;
+       }
 
        ret = da8xx_register_usb11(&da830_evm_usb11_pdata);
        if (ret)
@@ -156,6 +200,7 @@ static struct gpiod_lookup_table mmc_gpios_table = {
                            GPIO_ACTIVE_LOW),
                GPIO_LOOKUP("davinci_gpio", DA830_MMCSD_WP_PIN, "wp",
                            GPIO_ACTIVE_LOW),
+               { }
        },
 };
 
index 1fdc9283a8c50f5b458c94b26f84eb202ed7dc32..4ee65a8a3b8035483f98e335cda7c12c54854bbf 100644 (file)
@@ -784,6 +784,7 @@ static struct gpiod_lookup_table mmc_gpios_table = {
                            GPIO_ACTIVE_LOW),
                GPIO_LOOKUP("davinci_gpio", DA850_MMCSD_WP_PIN, "wp",
                            GPIO_ACTIVE_HIGH),
+               { }
        },
 };
 
index 64d81fc86f14f67cf53fd883d64e8ae97b600d71..5113273fda6916c04b5c31d1143444a31f64c9bf 100644 (file)
@@ -121,6 +121,7 @@ static struct gpiod_lookup_table i2c_recovery_gpiod_table = {
                            GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
                GPIO_LOOKUP("davinci_gpio", DM355_I2C_SCL_PIN, "scl",
                            GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
+               { }
        },
 };
 
index de15f782816e25e3ea7b71ba9f0a09540a46296e..9d87d4e440eaa4a7f552cd6c55ae71989c5a3ca7 100644 (file)
@@ -663,6 +663,7 @@ static struct gpiod_lookup_table i2c_recovery_gpiod_table = {
                            GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
                GPIO_LOOKUP("davinci_gpio", DM644X_I2C_SCL_PIN, "scl",
                            GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
+               { }
        },
 };
 
index 0896af2bed24206a5b65b5e9aa76cf6029d7c7f9..db177a6a7e48c243efd926e4d9f2264802e3d7d3 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/platform_data/mtd-davinci.h>
 #include <linux/platform_data/mtd-davinci-aemif.h>
 #include <linux/platform_data/ti-aemif.h>
+#include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 
 #include <asm/mach-types.h>
@@ -298,14 +299,50 @@ static const short da850_hawk_usb11_pins[] = {
        -1
 };
 
-static struct gpiod_lookup_table hawk_usb_gpio_lookup = {
+static struct regulator_consumer_supply hawk_usb_supplies[] = {
+       REGULATOR_SUPPLY("vbus", NULL),
+};
+
+static struct regulator_init_data hawk_usb_vbus_data = {
+       .consumer_supplies      = hawk_usb_supplies,
+       .num_consumer_supplies  = ARRAY_SIZE(hawk_usb_supplies),
+};
+
+static struct fixed_voltage_config hawk_usb_vbus = {
+       .supply_name            = "vbus",
+       .microvolts             = 3300000,
+       .init_data              = &hawk_usb_vbus_data,
+};
+
+static struct platform_device hawk_usb_vbus_device = {
+       .name           = "reg-fixed-voltage",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &hawk_usb_vbus,
+       },
+};
+
+static struct gpiod_lookup_table hawk_usb_oc_gpio_lookup = {
        .dev_id         = "ohci-da8xx",
        .table = {
-               GPIO_LOOKUP("davinci_gpio", DA850_USB1_VBUS_PIN, "vbus", 0),
                GPIO_LOOKUP("davinci_gpio", DA850_USB1_OC_PIN, "oc", 0),
+               { }
        },
 };
 
+static struct gpiod_lookup_table hawk_usb_vbus_gpio_lookup = {
+       .dev_id         = "reg-fixed-voltage.0",
+       .table = {
+               GPIO_LOOKUP("davinci_gpio", DA850_USB1_VBUS_PIN, NULL, 0),
+               { }
+       },
+};
+
+static struct gpiod_lookup_table *hawk_usb_gpio_lookups[] = {
+       &hawk_usb_oc_gpio_lookup,
+       &hawk_usb_vbus_gpio_lookup,
+};
+
 static struct da8xx_ohci_root_hub omapl138_hawk_usb11_pdata = {
        /* TPS2087 switch @ 5V */
        .potpgt         = (3 + 1) / 2,  /* 3 ms max */
@@ -326,12 +363,19 @@ static __init void omapl138_hawk_usb_init(void)
                pr_warn("%s: USB PHY CLK registration failed: %d\n",
                        __func__, ret);
 
+       gpiod_add_lookup_tables(hawk_usb_gpio_lookups,
+                               ARRAY_SIZE(hawk_usb_gpio_lookups));
+
        ret = da8xx_register_usb_phy();
        if (ret)
                pr_warn("%s: USB PHY registration failed: %d\n",
                        __func__, ret);
 
-       gpiod_add_lookup_table(&hawk_usb_gpio_lookup);
+       ret = platform_device_register(&hawk_usb_vbus_device);
+       if (ret) {
+               pr_warn("%s: Unable to register the vbus supply\n", __func__);
+               return;
+       }
 
        ret = da8xx_register_usb11(&omapl138_hawk_usb11_pdata);
        if (ret)
index 63511f638ce4714f17fe6029a576bb6d0b69896f..e6b8ffd934a114c9a0654749c61592671e301d68 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/clk/davinci.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/irqchip/irq-davinci-cp-intc.h>
 #include <linux/platform_data/gpio-davinci.h>
 
index 67ab71ba3ad3bcde17e15fec131f308ad85c86b1..77bc64d6e39be1eb5b2751d88315cf3caf341269 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/cpufreq.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/irqchip/irq-davinci-cp-intc.h>
 #include <linux/mfd/da8xx-cfgchip.h>
 #include <linux/platform_data/clk-da8xx-cfgchip.h>
index b8dc674e06bcf04a35735d27fe60524c6052d204..036139fe0d0f5e2b0c7d67d63af0a4982c0e3d48 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/dma-contiguous.h>
 #include <linux/dmaengine.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/reboot.h>
 #include <linux/serial_8250.h>
index 4a482445b9a28f46cbf71d784f974798b42e364a..c6073326be2e16cff3488c4c7cd064e679773f3b 100644 (file)
@@ -15,6 +15,7 @@
 #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>
index 8e0a77315add741643463f3fc98d8a52132be169..2f9ae6431bf54d627aeecaf7d941db998466f7ea 100644 (file)
@@ -19,6 +19,7 @@
 #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>
index cecc7ceb8d34a67259dd9f4ef7d64953a2efec60..1b9e9a6192ef181f22c7b92f05872cabfae13338 100644 (file)
@@ -14,6 +14,7 @@
 #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>
index f33392f77a0367f176921df701ddc35ec388dea4..62ca952fe1613ba125ffbe37f1bac89d9dedf8af 100644 (file)
@@ -15,6 +15,7 @@
 #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>
index 0d420a2bfe3ecb8d22dc87fe38e09a1213893ab4..d7b826d2695cde8aa4298d6e35cf9cec8d983667 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/clk-provider.h>
 #include <linux/dma-mapping.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/platform_data/dma-mv_xor.h>
index bda6c3a5c923c4d27715a5862f77e0cb20939251..5d3a3e3020126d1ed8e35150c6975ffee9467abe 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/sizes.h>
 
-#include <mach/hardware.h>
+#include "hardware.h"
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
index d2eee707d27f8e94bf9cb0bf7a7eb70c93dba2ab..b9f523d9dc8cf18ad7ae8dd942039cfa1d1a6140 100644 (file)
@@ -20,8 +20,9 @@
 #include <linux/io.h>
 #include <linux/spinlock.h>
 #include <linux/clkdev.h>
+#include <linux/soc/cirrus/ep93xx.h>
 
-#include <mach/hardware.h>
+#include "hardware.h"
 
 #include <asm/div64.h>
 
index 706515faee066e71ae4b195869ee72297fe590aa..cc1382f879afd6a21e2e074b99a040519483b73a 100644 (file)
 #include <linux/usb/ohci_pdriver.h>
 #include <linux/random.h>
 
-#include <mach/hardware.h>
+#include "hardware.h"
 #include <linux/platform_data/video-ep93xx.h>
 #include <linux/platform_data/keypad-ep93xx.h>
 #include <linux/platform_data/spi-ep93xx.h>
-#include <mach/gpio-ep93xx.h>
+#include <linux/soc/cirrus/ep93xx.h>
+
+#include "gpio-ep93xx.h"
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -123,7 +125,7 @@ void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits)
 /**
  * ep93xx_chip_revision() - returns the EP93xx chip revision
  *
- * See <mach/platform.h> for more information.
+ * See "platform.h" for more information.
  */
 unsigned int ep93xx_chip_revision(void)
 {
index 88a4c9b089a559c07d6d0d6c2e7159438d036351..821427107b11275a35fa36702ce23d4833b48837 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/platform_device.h>
 
 #include <linux/platform_data/dma-ep93xx.h>
-#include <mach/hardware.h>
+#include "hardware.h"
 
 #include "soc.h"
 
index 34e18e9556d9b928b3505594dd5583835743a0d8..c8c47122cf1de889941d002d00a6c242b9cf9914 100644 (file)
 
 #include <sound/cs4271.h>
 
-#include <mach/hardware.h>
+#include "hardware.h"
 #include <linux/platform_data/video-ep93xx.h>
 #include <linux/platform_data/spi-ep93xx.h>
-#include <mach/gpio-ep93xx.h>
+#include "gpio-ep93xx.h"
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
index 0cca5b1833093524d1c7468003bbae19c4f0c514..ac48e34765877b6dd340fad8dd0c5c1b8381f0fa 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/sizes.h>
 
-#include <mach/hardware.h>
+#include "hardware.h"
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
diff --git a/arch/arm/mach-ep93xx/gpio-ep93xx.h b/arch/arm/mach-ep93xx/gpio-ep93xx.h
new file mode 100644 (file)
index 0000000..242af4a
--- /dev/null
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Include file for the EP93XX GPIO controller machine specifics */
+
+#ifndef __GPIO_EP93XX_H
+#define __GPIO_EP93XX_H
+
+#include <mach/ep93xx-regs.h>
+
+#define EP93XX_GPIO_PHYS_BASE          EP93XX_APB_PHYS(0x00040000)
+#define EP93XX_GPIO_BASE               EP93XX_APB_IOMEM(0x00040000)
+#define EP93XX_GPIO_REG(x)             (EP93XX_GPIO_BASE + (x))
+#define EP93XX_GPIO_F_INT_STATUS       EP93XX_GPIO_REG(0x5c)
+#define EP93XX_GPIO_A_INT_STATUS       EP93XX_GPIO_REG(0xa0)
+#define EP93XX_GPIO_B_INT_STATUS       EP93XX_GPIO_REG(0xbc)
+#define EP93XX_GPIO_EEDRIVE            EP93XX_GPIO_REG(0xc8)
+
+/* GPIO port A.  */
+#define EP93XX_GPIO_LINE_A(x)          ((x) + 0)
+#define EP93XX_GPIO_LINE_EGPIO0                EP93XX_GPIO_LINE_A(0)
+#define EP93XX_GPIO_LINE_EGPIO1                EP93XX_GPIO_LINE_A(1)
+#define EP93XX_GPIO_LINE_EGPIO2                EP93XX_GPIO_LINE_A(2)
+#define EP93XX_GPIO_LINE_EGPIO3                EP93XX_GPIO_LINE_A(3)
+#define EP93XX_GPIO_LINE_EGPIO4                EP93XX_GPIO_LINE_A(4)
+#define EP93XX_GPIO_LINE_EGPIO5                EP93XX_GPIO_LINE_A(5)
+#define EP93XX_GPIO_LINE_EGPIO6                EP93XX_GPIO_LINE_A(6)
+#define EP93XX_GPIO_LINE_EGPIO7                EP93XX_GPIO_LINE_A(7)
+
+/* GPIO port B.  */
+#define EP93XX_GPIO_LINE_B(x)          ((x) + 8)
+#define EP93XX_GPIO_LINE_EGPIO8                EP93XX_GPIO_LINE_B(0)
+#define EP93XX_GPIO_LINE_EGPIO9                EP93XX_GPIO_LINE_B(1)
+#define EP93XX_GPIO_LINE_EGPIO10       EP93XX_GPIO_LINE_B(2)
+#define EP93XX_GPIO_LINE_EGPIO11       EP93XX_GPIO_LINE_B(3)
+#define EP93XX_GPIO_LINE_EGPIO12       EP93XX_GPIO_LINE_B(4)
+#define EP93XX_GPIO_LINE_EGPIO13       EP93XX_GPIO_LINE_B(5)
+#define EP93XX_GPIO_LINE_EGPIO14       EP93XX_GPIO_LINE_B(6)
+#define EP93XX_GPIO_LINE_EGPIO15       EP93XX_GPIO_LINE_B(7)
+
+/* GPIO port C.  */
+#define EP93XX_GPIO_LINE_C(x)          ((x) + 40)
+#define EP93XX_GPIO_LINE_ROW0          EP93XX_GPIO_LINE_C(0)
+#define EP93XX_GPIO_LINE_ROW1          EP93XX_GPIO_LINE_C(1)
+#define EP93XX_GPIO_LINE_ROW2          EP93XX_GPIO_LINE_C(2)
+#define EP93XX_GPIO_LINE_ROW3          EP93XX_GPIO_LINE_C(3)
+#define EP93XX_GPIO_LINE_ROW4          EP93XX_GPIO_LINE_C(4)
+#define EP93XX_GPIO_LINE_ROW5          EP93XX_GPIO_LINE_C(5)
+#define EP93XX_GPIO_LINE_ROW6          EP93XX_GPIO_LINE_C(6)
+#define EP93XX_GPIO_LINE_ROW7          EP93XX_GPIO_LINE_C(7)
+
+/* GPIO port D.  */
+#define EP93XX_GPIO_LINE_D(x)          ((x) + 24)
+#define EP93XX_GPIO_LINE_COL0          EP93XX_GPIO_LINE_D(0)
+#define EP93XX_GPIO_LINE_COL1          EP93XX_GPIO_LINE_D(1)
+#define EP93XX_GPIO_LINE_COL2          EP93XX_GPIO_LINE_D(2)
+#define EP93XX_GPIO_LINE_COL3          EP93XX_GPIO_LINE_D(3)
+#define EP93XX_GPIO_LINE_COL4          EP93XX_GPIO_LINE_D(4)
+#define EP93XX_GPIO_LINE_COL5          EP93XX_GPIO_LINE_D(5)
+#define EP93XX_GPIO_LINE_COL6          EP93XX_GPIO_LINE_D(6)
+#define EP93XX_GPIO_LINE_COL7          EP93XX_GPIO_LINE_D(7)
+
+/* GPIO port E.  */
+#define EP93XX_GPIO_LINE_E(x)          ((x) + 32)
+#define EP93XX_GPIO_LINE_GRLED         EP93XX_GPIO_LINE_E(0)
+#define EP93XX_GPIO_LINE_RDLED         EP93XX_GPIO_LINE_E(1)
+#define EP93XX_GPIO_LINE_DIORn         EP93XX_GPIO_LINE_E(2)
+#define EP93XX_GPIO_LINE_IDECS1n       EP93XX_GPIO_LINE_E(3)
+#define EP93XX_GPIO_LINE_IDECS2n       EP93XX_GPIO_LINE_E(4)
+#define EP93XX_GPIO_LINE_IDEDA0                EP93XX_GPIO_LINE_E(5)
+#define EP93XX_GPIO_LINE_IDEDA1                EP93XX_GPIO_LINE_E(6)
+#define EP93XX_GPIO_LINE_IDEDA2                EP93XX_GPIO_LINE_E(7)
+
+/* GPIO port F.  */
+#define EP93XX_GPIO_LINE_F(x)          ((x) + 16)
+#define EP93XX_GPIO_LINE_WP            EP93XX_GPIO_LINE_F(0)
+#define EP93XX_GPIO_LINE_MCCD1         EP93XX_GPIO_LINE_F(1)
+#define EP93XX_GPIO_LINE_MCCD2         EP93XX_GPIO_LINE_F(2)
+#define EP93XX_GPIO_LINE_MCBVD1                EP93XX_GPIO_LINE_F(3)
+#define EP93XX_GPIO_LINE_MCBVD2                EP93XX_GPIO_LINE_F(4)
+#define EP93XX_GPIO_LINE_VS1           EP93XX_GPIO_LINE_F(5)
+#define EP93XX_GPIO_LINE_READY         EP93XX_GPIO_LINE_F(6)
+#define EP93XX_GPIO_LINE_VS2           EP93XX_GPIO_LINE_F(7)
+
+/* GPIO port G.  */
+#define EP93XX_GPIO_LINE_G(x)          ((x) + 48)
+#define EP93XX_GPIO_LINE_EECLK         EP93XX_GPIO_LINE_G(0)
+#define EP93XX_GPIO_LINE_EEDAT         EP93XX_GPIO_LINE_G(1)
+#define EP93XX_GPIO_LINE_SLA0          EP93XX_GPIO_LINE_G(2)
+#define EP93XX_GPIO_LINE_SLA1          EP93XX_GPIO_LINE_G(3)
+#define EP93XX_GPIO_LINE_DD12          EP93XX_GPIO_LINE_G(4)
+#define EP93XX_GPIO_LINE_DD13          EP93XX_GPIO_LINE_G(5)
+#define EP93XX_GPIO_LINE_DD14          EP93XX_GPIO_LINE_G(6)
+#define EP93XX_GPIO_LINE_DD15          EP93XX_GPIO_LINE_G(7)
+
+/* GPIO port H.  */
+#define EP93XX_GPIO_LINE_H(x)          ((x) + 56)
+#define EP93XX_GPIO_LINE_DD0           EP93XX_GPIO_LINE_H(0)
+#define EP93XX_GPIO_LINE_DD1           EP93XX_GPIO_LINE_H(1)
+#define EP93XX_GPIO_LINE_DD2           EP93XX_GPIO_LINE_H(2)
+#define EP93XX_GPIO_LINE_DD3           EP93XX_GPIO_LINE_H(3)
+#define EP93XX_GPIO_LINE_DD4           EP93XX_GPIO_LINE_H(4)
+#define EP93XX_GPIO_LINE_DD5           EP93XX_GPIO_LINE_H(5)
+#define EP93XX_GPIO_LINE_DD6           EP93XX_GPIO_LINE_H(6)
+#define EP93XX_GPIO_LINE_DD7           EP93XX_GPIO_LINE_H(7)
+
+/* maximum value for gpio line identifiers */
+#define EP93XX_GPIO_LINE_MAX           EP93XX_GPIO_LINE_H(7)
+
+/* maximum value for irq capable line identifiers */
+#define EP93XX_GPIO_LINE_MAX_IRQ       EP93XX_GPIO_LINE_F(7)
+
+#endif /* __GPIO_EP93XX_H */
diff --git a/arch/arm/mach-ep93xx/hardware.h b/arch/arm/mach-ep93xx/hardware.h
new file mode 100644 (file)
index 0000000..e7d850e
--- /dev/null
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * arch/arm/mach-ep93xx/include/mach/hardware.h
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include "platform.h"
+
+/*
+ * The EP93xx has two external crystal oscillators.  To generate the
+ * required high-frequency clocks, the processor uses two phase-locked-
+ * loops (PLLs) to multiply the incoming external clock signal to much
+ * higher frequencies that are then divided down by programmable dividers
+ * to produce the needed clocks.  The PLLs operate independently of one
+ * another.
+ */
+#define EP93XX_EXT_CLK_RATE    14745600
+#define EP93XX_EXT_RTC_RATE    32768
+
+#define EP93XX_KEYTCHCLK_DIV4  (EP93XX_EXT_CLK_RATE / 4)
+#define EP93XX_KEYTCHCLK_DIV16 (EP93XX_EXT_CLK_RATE / 16)
+
+#endif
diff --git a/arch/arm/mach-ep93xx/include/mach/gpio-ep93xx.h b/arch/arm/mach-ep93xx/include/mach/gpio-ep93xx.h
deleted file mode 100644 (file)
index 242af4a..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Include file for the EP93XX GPIO controller machine specifics */
-
-#ifndef __GPIO_EP93XX_H
-#define __GPIO_EP93XX_H
-
-#include <mach/ep93xx-regs.h>
-
-#define EP93XX_GPIO_PHYS_BASE          EP93XX_APB_PHYS(0x00040000)
-#define EP93XX_GPIO_BASE               EP93XX_APB_IOMEM(0x00040000)
-#define EP93XX_GPIO_REG(x)             (EP93XX_GPIO_BASE + (x))
-#define EP93XX_GPIO_F_INT_STATUS       EP93XX_GPIO_REG(0x5c)
-#define EP93XX_GPIO_A_INT_STATUS       EP93XX_GPIO_REG(0xa0)
-#define EP93XX_GPIO_B_INT_STATUS       EP93XX_GPIO_REG(0xbc)
-#define EP93XX_GPIO_EEDRIVE            EP93XX_GPIO_REG(0xc8)
-
-/* GPIO port A.  */
-#define EP93XX_GPIO_LINE_A(x)          ((x) + 0)
-#define EP93XX_GPIO_LINE_EGPIO0                EP93XX_GPIO_LINE_A(0)
-#define EP93XX_GPIO_LINE_EGPIO1                EP93XX_GPIO_LINE_A(1)
-#define EP93XX_GPIO_LINE_EGPIO2                EP93XX_GPIO_LINE_A(2)
-#define EP93XX_GPIO_LINE_EGPIO3                EP93XX_GPIO_LINE_A(3)
-#define EP93XX_GPIO_LINE_EGPIO4                EP93XX_GPIO_LINE_A(4)
-#define EP93XX_GPIO_LINE_EGPIO5                EP93XX_GPIO_LINE_A(5)
-#define EP93XX_GPIO_LINE_EGPIO6                EP93XX_GPIO_LINE_A(6)
-#define EP93XX_GPIO_LINE_EGPIO7                EP93XX_GPIO_LINE_A(7)
-
-/* GPIO port B.  */
-#define EP93XX_GPIO_LINE_B(x)          ((x) + 8)
-#define EP93XX_GPIO_LINE_EGPIO8                EP93XX_GPIO_LINE_B(0)
-#define EP93XX_GPIO_LINE_EGPIO9                EP93XX_GPIO_LINE_B(1)
-#define EP93XX_GPIO_LINE_EGPIO10       EP93XX_GPIO_LINE_B(2)
-#define EP93XX_GPIO_LINE_EGPIO11       EP93XX_GPIO_LINE_B(3)
-#define EP93XX_GPIO_LINE_EGPIO12       EP93XX_GPIO_LINE_B(4)
-#define EP93XX_GPIO_LINE_EGPIO13       EP93XX_GPIO_LINE_B(5)
-#define EP93XX_GPIO_LINE_EGPIO14       EP93XX_GPIO_LINE_B(6)
-#define EP93XX_GPIO_LINE_EGPIO15       EP93XX_GPIO_LINE_B(7)
-
-/* GPIO port C.  */
-#define EP93XX_GPIO_LINE_C(x)          ((x) + 40)
-#define EP93XX_GPIO_LINE_ROW0          EP93XX_GPIO_LINE_C(0)
-#define EP93XX_GPIO_LINE_ROW1          EP93XX_GPIO_LINE_C(1)
-#define EP93XX_GPIO_LINE_ROW2          EP93XX_GPIO_LINE_C(2)
-#define EP93XX_GPIO_LINE_ROW3          EP93XX_GPIO_LINE_C(3)
-#define EP93XX_GPIO_LINE_ROW4          EP93XX_GPIO_LINE_C(4)
-#define EP93XX_GPIO_LINE_ROW5          EP93XX_GPIO_LINE_C(5)
-#define EP93XX_GPIO_LINE_ROW6          EP93XX_GPIO_LINE_C(6)
-#define EP93XX_GPIO_LINE_ROW7          EP93XX_GPIO_LINE_C(7)
-
-/* GPIO port D.  */
-#define EP93XX_GPIO_LINE_D(x)          ((x) + 24)
-#define EP93XX_GPIO_LINE_COL0          EP93XX_GPIO_LINE_D(0)
-#define EP93XX_GPIO_LINE_COL1          EP93XX_GPIO_LINE_D(1)
-#define EP93XX_GPIO_LINE_COL2          EP93XX_GPIO_LINE_D(2)
-#define EP93XX_GPIO_LINE_COL3          EP93XX_GPIO_LINE_D(3)
-#define EP93XX_GPIO_LINE_COL4          EP93XX_GPIO_LINE_D(4)
-#define EP93XX_GPIO_LINE_COL5          EP93XX_GPIO_LINE_D(5)
-#define EP93XX_GPIO_LINE_COL6          EP93XX_GPIO_LINE_D(6)
-#define EP93XX_GPIO_LINE_COL7          EP93XX_GPIO_LINE_D(7)
-
-/* GPIO port E.  */
-#define EP93XX_GPIO_LINE_E(x)          ((x) + 32)
-#define EP93XX_GPIO_LINE_GRLED         EP93XX_GPIO_LINE_E(0)
-#define EP93XX_GPIO_LINE_RDLED         EP93XX_GPIO_LINE_E(1)
-#define EP93XX_GPIO_LINE_DIORn         EP93XX_GPIO_LINE_E(2)
-#define EP93XX_GPIO_LINE_IDECS1n       EP93XX_GPIO_LINE_E(3)
-#define EP93XX_GPIO_LINE_IDECS2n       EP93XX_GPIO_LINE_E(4)
-#define EP93XX_GPIO_LINE_IDEDA0                EP93XX_GPIO_LINE_E(5)
-#define EP93XX_GPIO_LINE_IDEDA1                EP93XX_GPIO_LINE_E(6)
-#define EP93XX_GPIO_LINE_IDEDA2                EP93XX_GPIO_LINE_E(7)
-
-/* GPIO port F.  */
-#define EP93XX_GPIO_LINE_F(x)          ((x) + 16)
-#define EP93XX_GPIO_LINE_WP            EP93XX_GPIO_LINE_F(0)
-#define EP93XX_GPIO_LINE_MCCD1         EP93XX_GPIO_LINE_F(1)
-#define EP93XX_GPIO_LINE_MCCD2         EP93XX_GPIO_LINE_F(2)
-#define EP93XX_GPIO_LINE_MCBVD1                EP93XX_GPIO_LINE_F(3)
-#define EP93XX_GPIO_LINE_MCBVD2                EP93XX_GPIO_LINE_F(4)
-#define EP93XX_GPIO_LINE_VS1           EP93XX_GPIO_LINE_F(5)
-#define EP93XX_GPIO_LINE_READY         EP93XX_GPIO_LINE_F(6)
-#define EP93XX_GPIO_LINE_VS2           EP93XX_GPIO_LINE_F(7)
-
-/* GPIO port G.  */
-#define EP93XX_GPIO_LINE_G(x)          ((x) + 48)
-#define EP93XX_GPIO_LINE_EECLK         EP93XX_GPIO_LINE_G(0)
-#define EP93XX_GPIO_LINE_EEDAT         EP93XX_GPIO_LINE_G(1)
-#define EP93XX_GPIO_LINE_SLA0          EP93XX_GPIO_LINE_G(2)
-#define EP93XX_GPIO_LINE_SLA1          EP93XX_GPIO_LINE_G(3)
-#define EP93XX_GPIO_LINE_DD12          EP93XX_GPIO_LINE_G(4)
-#define EP93XX_GPIO_LINE_DD13          EP93XX_GPIO_LINE_G(5)
-#define EP93XX_GPIO_LINE_DD14          EP93XX_GPIO_LINE_G(6)
-#define EP93XX_GPIO_LINE_DD15          EP93XX_GPIO_LINE_G(7)
-
-/* GPIO port H.  */
-#define EP93XX_GPIO_LINE_H(x)          ((x) + 56)
-#define EP93XX_GPIO_LINE_DD0           EP93XX_GPIO_LINE_H(0)
-#define EP93XX_GPIO_LINE_DD1           EP93XX_GPIO_LINE_H(1)
-#define EP93XX_GPIO_LINE_DD2           EP93XX_GPIO_LINE_H(2)
-#define EP93XX_GPIO_LINE_DD3           EP93XX_GPIO_LINE_H(3)
-#define EP93XX_GPIO_LINE_DD4           EP93XX_GPIO_LINE_H(4)
-#define EP93XX_GPIO_LINE_DD5           EP93XX_GPIO_LINE_H(5)
-#define EP93XX_GPIO_LINE_DD6           EP93XX_GPIO_LINE_H(6)
-#define EP93XX_GPIO_LINE_DD7           EP93XX_GPIO_LINE_H(7)
-
-/* maximum value for gpio line identifiers */
-#define EP93XX_GPIO_LINE_MAX           EP93XX_GPIO_LINE_H(7)
-
-/* maximum value for irq capable line identifiers */
-#define EP93XX_GPIO_LINE_MAX_IRQ       EP93XX_GPIO_LINE_F(7)
-
-#endif /* __GPIO_EP93XX_H */
diff --git a/arch/arm/mach-ep93xx/include/mach/hardware.h b/arch/arm/mach-ep93xx/include/mach/hardware.h
deleted file mode 100644 (file)
index 8938906..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * arch/arm/mach-ep93xx/include/mach/hardware.h
- */
-
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-#include <mach/platform.h>
-
-/*
- * The EP93xx has two external crystal oscillators.  To generate the
- * required high-frequency clocks, the processor uses two phase-locked-
- * loops (PLLs) to multiply the incoming external clock signal to much
- * higher frequencies that are then divided down by programmable dividers
- * to produce the needed clocks.  The PLLs operate independently of one
- * another.
- */
-#define EP93XX_EXT_CLK_RATE    14745600
-#define EP93XX_EXT_RTC_RATE    32768
-
-#define EP93XX_KEYTCHCLK_DIV4  (EP93XX_EXT_CLK_RATE / 4)
-#define EP93XX_KEYTCHCLK_DIV16 (EP93XX_EXT_CLK_RATE / 16)
-
-#endif
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
deleted file mode 100644 (file)
index 6c41c79..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * arch/arm/mach-ep93xx/include/mach/platform.h
- */
-
-#ifndef __ASSEMBLY__
-
-#include <linux/reboot.h>
-
-struct device;
-struct i2c_board_info;
-struct spi_board_info;
-struct platform_device;
-struct ep93xxfb_mach_info;
-struct ep93xx_keypad_platform_data;
-struct ep93xx_spi_info;
-
-struct ep93xx_eth_data
-{
-       unsigned char   dev_addr[6];
-       unsigned char   phy_id;
-};
-
-void ep93xx_map_io(void);
-void ep93xx_init_irq(void);
-
-#define EP93XX_CHIP_REV_D0     3
-#define EP93XX_CHIP_REV_D1     4
-#define EP93XX_CHIP_REV_E0     5
-#define EP93XX_CHIP_REV_E1     6
-#define EP93XX_CHIP_REV_E2     7
-
-unsigned int ep93xx_chip_revision(void);
-
-void ep93xx_register_flash(unsigned int width,
-                          resource_size_t start, resource_size_t size);
-
-void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
-void ep93xx_register_i2c(struct i2c_board_info *devices, int num);
-void ep93xx_register_spi(struct ep93xx_spi_info *info,
-                        struct spi_board_info *devices, int num);
-void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
-void ep93xx_register_pwm(int pwm0, int pwm1);
-int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);
-void ep93xx_pwm_release_gpio(struct platform_device *pdev);
-void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data);
-int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
-void ep93xx_keypad_release_gpio(struct platform_device *pdev);
-void ep93xx_register_i2s(void);
-int ep93xx_i2s_acquire(void);
-void ep93xx_i2s_release(void);
-void ep93xx_register_ac97(void);
-void ep93xx_register_ide(void);
-void ep93xx_register_adc(void);
-int ep93xx_ide_acquire_gpio(struct platform_device *pdev);
-void ep93xx_ide_release_gpio(struct platform_device *pdev);
-
-struct device *ep93xx_init_devices(void);
-extern void ep93xx_timer_init(void);
-
-void ep93xx_restart(enum reboot_mode, const char *);
-void ep93xx_init_late(void);
-
-#ifdef CONFIG_CRUNCH
-int crunch_init(void);
-#else
-static inline int crunch_init(void) { return 0; }
-#endif
-
-#endif
index 373583c298255179d5b4f553d61dc9d38081e874..c7f64e4ff6c71374d0bb21c5b14e60ab0f44a083 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
-#include <mach/hardware.h>
+#include "hardware.h"
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
diff --git a/arch/arm/mach-ep93xx/platform.h b/arch/arm/mach-ep93xx/platform.h
new file mode 100644 (file)
index 0000000..b4045a1
--- /dev/null
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * arch/arm/mach-ep93xx/include/mach/platform.h
+ */
+
+#ifndef __ASSEMBLY__
+
+#include <linux/platform_data/eth-ep93xx.h>
+#include <linux/reboot.h>
+
+struct device;
+struct i2c_board_info;
+struct spi_board_info;
+struct platform_device;
+struct ep93xxfb_mach_info;
+struct ep93xx_keypad_platform_data;
+struct ep93xx_spi_info;
+
+void ep93xx_map_io(void);
+void ep93xx_init_irq(void);
+
+void ep93xx_register_flash(unsigned int width,
+                          resource_size_t start, resource_size_t size);
+
+void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
+void ep93xx_register_i2c(struct i2c_board_info *devices, int num);
+void ep93xx_register_spi(struct ep93xx_spi_info *info,
+                        struct spi_board_info *devices, int num);
+void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
+void ep93xx_register_pwm(int pwm0, int pwm1);
+void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data);
+void ep93xx_register_i2s(void);
+void ep93xx_register_ac97(void);
+void ep93xx_register_ide(void);
+void ep93xx_register_adc(void);
+
+struct device *ep93xx_init_devices(void);
+extern void ep93xx_timer_init(void);
+
+void ep93xx_restart(enum reboot_mode, const char *);
+void ep93xx_init_late(void);
+
+#ifdef CONFIG_CRUNCH
+int crunch_init(void);
+#else
+static inline int crunch_init(void) { return 0; }
+#endif
+
+#endif
index f0f38c0dba527572428c05474955c734ba360945..5a3c32fa7ace008fa464dd16effca06ed37708b0 100644 (file)
@@ -27,8 +27,8 @@
 #include <linux/gpio.h>
 #include <linux/gpio/machine.h>
 
-#include <mach/hardware.h>
-#include <mach/gpio-ep93xx.h>
+#include "hardware.h"
+#include "gpio-ep93xx.h"
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
index cf0cb58b3454009d6d41fbf1c5d0431674dca5e9..f8f89551dbed460d6b7babdd1a73a0f054a11b02 100644 (file)
@@ -25,9 +25,9 @@
 
 #include <linux/mtd/platnand.h>
 
-#include <mach/hardware.h>
+#include "hardware.h"
 #include <linux/platform_data/video-ep93xx.h>
-#include <mach/gpio-ep93xx.h>
+#include "gpio-ep93xx.h"
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
index a3a20c83c6b8f930f2ea45955d965dc16842917b..e9f3690672932bb2a0a795e0e657d37a347af9dd 100644 (file)
@@ -24,8 +24,8 @@
 #include <linux/platform_data/spi-ep93xx.h>
 #include <linux/gpio/machine.h>
 
-#include <mach/gpio-ep93xx.h>
-#include <mach/hardware.h>
+#include "gpio-ep93xx.h"
+#include "hardware.h"
 #include <mach/irqs.h>
 
 #include <asm/mach-types.h>
index f95a644769e485b939f190790c803c416880ee06..d44db6d67f35660f581449dbe69b40aa751a8a27 100644 (file)
 
 #include <sound/cs4271.h>
 
-#include <mach/hardware.h>
+#include "hardware.h"
 #include <linux/platform_data/video-ep93xx.h>
 #include <linux/platform_data/spi-ep93xx.h>
-#include <mach/gpio-ep93xx.h>
+#include "gpio-ep93xx.h"
 
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
index b40963cf91c77d211f5b25cddaf3565f2832e85d..1c518b8ee520cca3854c3a12d4b7b165f3a515d4 100644 (file)
@@ -106,21 +106,15 @@ config SOC_EXYNOS5420
        bool "SAMSUNG EXYNOS5420"
        default y
        depends on ARCH_EXYNOS5
+       select MCPM if SMP
+       select ARM_CCI400_PORT_CTRL
+       select ARM_CPU_SUSPEND
 
 config SOC_EXYNOS5800
        bool "SAMSUNG EXYNOS5800"
        default y
        depends on SOC_EXYNOS5420
 
-config EXYNOS5420_MCPM
-       bool "Exynos5420 Multi-Cluster PM support"
-       depends on MCPM && SOC_EXYNOS5420
-       select ARM_CCI400_PORT_CTRL
-       select ARM_CPU_SUSPEND
-       help
-         This is needed to provide CPU and cluster power management
-         on Exynos5420 implementing big.LITTLE.
-
 config EXYNOS_CPU_SUSPEND
        bool
        select ARM_CPU_SUSPEND
index cd00c82a1add02ff0cc9e314dde5ad345c190aea..264dbaa89c3db721478fe7f2ba001b01a2883523 100644 (file)
@@ -18,5 +18,5 @@ plus_sec := $(call as-instr,.arch_extension sec,+sec)
 AFLAGS_exynos-smc.o            :=-Wa,-march=armv7-a$(plus_sec)
 AFLAGS_sleep.o                 :=-Wa,-march=armv7-a$(plus_sec)
 
-obj-$(CONFIG_EXYNOS5420_MCPM)  += mcpm-exynos.o
+obj-$(CONFIG_MCPM)             += mcpm-exynos.o
 CFLAGS_mcpm-exynos.o           += -march=armv7-a
index 1b8699e940989b5e9f45e26650da0811f0a2e812..c93356a8d662beaeddb1f6f871455479f5f281db 100644 (file)
@@ -91,6 +91,7 @@ extern u32 cp15_save_power;
 
 extern void __iomem *sysram_ns_base_addr;
 extern void __iomem *sysram_base_addr;
+extern phys_addr_t sysram_base_phys;
 extern void __iomem *pmu_base_addr;
 void exynos_sysram_init(void);
 
index 865dcc4c3181a1e4540e094baa0ef976d876b0b5..9aa483366ebcbcde3597fe5e2a9911d2840508a4 100644 (file)
@@ -33,6 +33,7 @@ static struct platform_device exynos_cpuidle = {
 };
 
 void __iomem *sysram_base_addr __ro_after_init;
+phys_addr_t sysram_base_phys __ro_after_init;
 void __iomem *sysram_ns_base_addr __ro_after_init;
 
 void __init exynos_sysram_init(void)
@@ -43,6 +44,8 @@ void __init exynos_sysram_init(void)
                if (!of_device_is_available(node))
                        continue;
                sysram_base_addr = of_iomap(node, 0);
+               sysram_base_phys = of_translate_address(node,
+                                          of_get_address(node, 0, NULL, NULL));
                break;
        }
 
index d602e3bf3f9665cd367e52d67069c2018748407d..2eaf2dbb8e815bf2809bf48deec0ff9779b79e6e 100644 (file)
@@ -196,6 +196,7 @@ bool __init exynos_secure_firmware_available(void)
                return false;
 
        addr = of_get_address(nd, 0, NULL, NULL);
+       of_node_put(nd);
        if (!addr) {
                pr_err("%s: No address specified.\n", __func__);
                return false;
index 72bc035bedbe2702b08a866f1bfc5973a48e9879..9a681b421ae119887dc8abf90de2cf889489b389 100644 (file)
@@ -75,14 +75,25 @@ static int exynos_cpu_powerup(unsigned int cpu, unsigned int cluster)
                 */
                if (cluster &&
                    cluster == MPIDR_AFFINITY_LEVEL(cpu_logical_map(0), 1)) {
+                       unsigned int timeout = 16;
+
                        /*
                         * Before we reset the Little cores, we should wait
                         * the SPARE2 register is set to 1 because the init
                         * codes of the iROM will set the register after
                         * initialization.
                         */
-                       while (!pmu_raw_readl(S5P_PMU_SPARE2))
+                       while (timeout && !pmu_raw_readl(S5P_PMU_SPARE2)) {
+                               timeout--;
                                udelay(10);
+                       }
+
+                       if (timeout == 0) {
+                               pr_err("cpu %u cluster %u powerup failed\n",
+                                      cpu, cluster);
+                               exynos_cpu_power_down(cpunr);
+                               return -ETIMEDOUT;
+                       }
 
                        pmu_raw_writel(EXYNOS5420_KFC_CORE_RESET(cpu),
                                        EXYNOS_SWRESET);
index abcac616423319bf0634bce260a85c3fe9134b60..0cbbae8bf1f85ef4dcf4dc245c12760fdd0c4e6a 100644 (file)
@@ -214,13 +214,20 @@ static inline void __iomem *cpu_boot_reg(int cpu)
  */
 void exynos_core_restart(u32 core_id)
 {
+       unsigned int timeout = 16;
        u32 val;
 
        if (!of_machine_is_compatible("samsung,exynos3250"))
                return;
 
-       while (!pmu_raw_readl(S5P_PMU_SPARE2))
+       while (timeout && !pmu_raw_readl(S5P_PMU_SPARE2)) {
+               timeout--;
                udelay(10);
+       }
+       if (timeout == 0) {
+               pr_err("cpu core %u restart failed\n", core_id);
+               return;
+       }
        udelay(10);
 
        val = pmu_raw_readl(EXYNOS_ARM_CORE_STATUS(core_id));
index f355185d4239b9fa6df3fb6048602744ad23e901..98832e50852ddb2faa4e35c350ce5f5e368e4ca4 100644 (file)
 #define SMC_CMD_L2X0INVALL     (-24)
 #define SMC_CMD_L2X0DEBUG      (-25)
 
+/* For Accessing CP15/SFR (General) */
+#define SMC_CMD_REG            (-101)
+
+/* defines for SMC_CMD_REG */
+#define SMC_REG_CLASS_SFR_W    (0x1 << 30)
+#define SMC_REG_ID_SFR_W(addr) (SMC_REG_CLASS_SFR_W | ((addr) >> 2))
+
 #ifndef __ASSEMBLY__
 
 extern void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3);
index 0850505ac78b2c52c42c6eed6b4d2e8b8ee841db..be122af0de8f8df4ad645ee8680bfe2f43cef831 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/suspend.h>
 
 #include "common.h"
+#include "smc.h"
 
 #define REG_TABLE_END (-1U)
 
@@ -62,6 +63,8 @@ struct exynos_pm_state {
        int cpu_state;
        unsigned int pmu_spare3;
        void __iomem *sysram_base;
+       phys_addr_t sysram_phys;
+       bool secure_firmware;
 };
 
 static const struct exynos_pm_data *pm_data __ro_after_init;
@@ -265,9 +268,7 @@ static int exynos5420_cpu_suspend(unsigned long arg)
        unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
        unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
 
-       writel_relaxed(0x0, pm_state.sysram_base + EXYNOS5420_CPU_STATE);
-
-       if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) {
+       if (IS_ENABLED(CONFIG_MCPM)) {
                mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume);
                mcpm_cpu_suspend();
        }
@@ -341,11 +342,16 @@ static void exynos5420_pm_prepare(void)
         */
        pm_state.cpu_state = readl_relaxed(pm_state.sysram_base +
                                           EXYNOS5420_CPU_STATE);
+       writel_relaxed(0x0, pm_state.sysram_base + EXYNOS5420_CPU_STATE);
+       if (pm_state.secure_firmware)
+               exynos_smc(SMC_CMD_REG, SMC_REG_ID_SFR_W(pm_state.sysram_phys +
+                                                        EXYNOS5420_CPU_STATE),
+                          0, 0);
 
        exynos_pm_enter_sleep_mode();
 
        /* ensure at least INFORM0 has the resume address */
-       if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
+       if (IS_ENABLED(CONFIG_MCPM))
                pmu_raw_writel(__pa_symbol(mcpm_entry_point), S5P_INFORM0);
 
        tmp = pmu_raw_readl(EXYNOS_L2_OPTION(0));
@@ -444,8 +450,27 @@ early_wakeup:
 
 static void exynos5420_prepare_pm_resume(void)
 {
-       if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
+       unsigned int mpidr, cluster;
+
+       mpidr = read_cpuid_mpidr();
+       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+       if (IS_ENABLED(CONFIG_MCPM))
                WARN_ON(mcpm_cpu_powered_up());
+
+       if (IS_ENABLED(CONFIG_HW_PERF_EVENTS) && cluster != 0) {
+               /*
+                * When system is resumed on the LITTLE/KFC core (cluster 1),
+                * the DSCR is not properly updated until the power is turned
+                * on also for the cluster 0. Enable it for a while to
+                * propagate the SPNIDEN and SPIDEN signals from Secure JTAG
+                * block and avoid undefined instruction issue on CP14 reset.
+                */
+               pmu_raw_writel(S5P_CORE_LOCAL_PWR_EN,
+                               EXYNOS_COMMON_CONFIGURATION(0));
+               pmu_raw_writel(0,
+                               EXYNOS_COMMON_CONFIGURATION(0));
+       }
 }
 
 static void exynos5420_pm_resume(void)
@@ -460,6 +485,11 @@ static void exynos5420_pm_resume(void)
        /* Restore the sysram cpu state register */
        writel_relaxed(pm_state.cpu_state,
                       pm_state.sysram_base + EXYNOS5420_CPU_STATE);
+       if (pm_state.secure_firmware)
+               exynos_smc(SMC_CMD_REG,
+                          SMC_REG_ID_SFR_W(pm_state.sysram_phys +
+                                           EXYNOS5420_CPU_STATE),
+                          EXYNOS_AFTR_MAGIC, 0);
 
        pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL,
                        S5P_CENTRAL_SEQ_OPTION);
@@ -639,8 +669,10 @@ void __init exynos_pm_init(void)
 
        if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) {
                pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
+               of_node_put(np);
                return;
        }
+       of_node_put(np);
 
        pm_data = (const struct exynos_pm_data *) match->data;
 
@@ -659,8 +691,11 @@ void __init exynos_pm_init(void)
         * Applicable as of now only to Exynos542x. If booted under secure
         * firmware, the non-secure region of sysram should be used.
         */
-       if (exynos_secure_firmware_available())
+       if (exynos_secure_firmware_available()) {
+               pm_state.sysram_phys = sysram_base_phys;
                pm_state.sysram_base = sysram_ns_base_addr;
-       else
+               pm_state.secure_firmware = true;
+       } else {
                pm_state.sysram_base = sysram_base_addr;
+       }
 }
index b403a4fe2892b3773f3b92ea6f8520b077269588..605c0af5851d1274831fa12670fb5b25272d5f3e 100644 (file)
@@ -7,7 +7,7 @@
  * Free Software Foundation.
  */
 #include <linux/dma-mapping.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include "../hardware.h"
 #include "devices-common.h"
index 486282539c76e72dd01e7dfefa317491f1cedb4f..9f0a132ea1bc5b02031e0c367991eae312e3b79a 100644 (file)
@@ -15,7 +15,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
  * Boston, MA  02110-1301, USA.
  */
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include "../hardware.h"
 #include "devices-common.h"
index 8c134c8d7500349f1040cca3fcad40ea851a1bcd..0c6d3c05fd6db311cd1db70f99fd5ab1375d311a 100644 (file)
@@ -6,7 +6,7 @@
  * the terms of the GNU General Public License version 2 as published by the
  * Free Software Foundation.
  */
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include "../hardware.h"
 #include "devices-common.h"
index 676df4920c7b6d6e06a7e86309c5d1455a3c1648..046e0cc826c188f4357df4a50ec3649e5c89880f 100644 (file)
@@ -6,7 +6,7 @@
  * the terms of the GNU General Public License version 2 as published by the
  * Free Software Foundation.
  */
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include "../hardware.h"
 #include "devices-common.h"
index 90e10cbd8fd11de166b82291a4244fb7cbccbc8d..b5ca8cebe1d65fffc9f058aa8bf00e95a073b15c 100644 (file)
@@ -24,7 +24,7 @@
 #include <asm/io.h>
 #include <soc/imx/revision.h>
 #endif
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #define addr_in_module(addr, mod) \
        ((unsigned long)(addr) - mod ## _BASE_ADDR < mod ## _SIZE)
index e67e0b2d4ce0737e79a951e592c9e6f8f90d522a..e527532f6931cf39ae2e6a36f7f26d83ab9c4186 100644 (file)
@@ -354,9 +354,11 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode)
         *
         * Note that IRQ #32 is GIC SPI #0.
         */
-       imx_gpc_hwirq_unmask(0);
+       if (mode != WAIT_CLOCKED)
+               imx_gpc_hwirq_unmask(0);
        writel_relaxed(val, ccm_base + CLPCR);
-       imx_gpc_hwirq_mask(0);
+       if (mode != WAIT_CLOCKED)
+               imx_gpc_hwirq_mask(0);
 
        return 0;
 }
index 8dfad012dfae720db702c7a329b7d3724790688f..6ddbe153910a68edb218ce27992d348e6b739f79 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/irqchip/arm-vic.h>
 #include <linux/gpio/machine.h>
 
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include "lm.h"
 #include "impd1.h"
 
index 070d92ae1b6f91a9878c8a89808079c779427d54..8426ab9e2f5a34cd07fcc79a53eb090f30eae562 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/export.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/signal.h>
 #include <asm/mach/pci.h>
 #include "pci.h"
index 116feb6b261eb7b0e08ee7ce248e44682e537898..d3d8c78e7d1087e42bb2abab459df0967eb6546f 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <asm/irq.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <mach/irqs.h>
 
 /* assumes CONTROLLER_ONLY# is never asserted in the ESSR register */
index fea008123eb1555c39b310ada81d18d028be1132..83afb80d38a8b6bf07292f3bae5eb01372c13882 100644 (file)
@@ -4,6 +4,20 @@ menu "Intel IXP4xx Implementation Options"
 
 comment "IXP4xx Platforms"
 
+config MACH_IXP4XX_OF
+       bool
+       prompt "Devce Tree IXP4xx boards"
+       default y
+       select ARM_APPENDED_DTB # Old Redboot bootloaders deployed
+       select I2C
+       select I2C_IOP3XX
+       select PCI
+       select SERIAL_OF_PLATFORM
+       select TIMER_OF
+       select USE_OF
+       help
+         Say 'Y' here to support Device Tree-based IXP4xx platforms.
+
 config MACH_NSLU2
        bool
        prompt "Linksys NSLU2"
@@ -222,19 +236,6 @@ config IXP4XX_INDIRECT_PCI
          need to use the indirect method instead. If you don't know
          what you need, leave this option unselected.
 
-config IXP4XX_QMGR
-       tristate "IXP4xx Queue Manager support"
-       help
-         This driver supports IXP4xx built-in hardware queue manager
-         and is automatically selected by Ethernet and HSS drivers.
-
-config IXP4XX_NPE
-       tristate "IXP4xx Network Processor Engine support"
-       select FW_LOADER
-       help
-         This driver supports IXP4xx built-in network coprocessors
-         and is automatically selected by Ethernet and HSS drivers.
-
 endmenu
 
 endif
index f09994500a34c51d2d3c2d82cb7e51f65e525815..1fa4e66057823c6bcee8278e229cf008440c867a 100644 (file)
@@ -6,6 +6,9 @@
 obj-pci-y      :=
 obj-pci-n      :=
 
+# Device tree platform
+obj-pci-$(CONFIG_MACH_IXP4XX_OF)       += ixp4xx-of.o
+
 obj-pci-$(CONFIG_ARCH_IXDP4XX)         += ixdp425-pci.o
 obj-pci-$(CONFIG_MACH_AVILA)           += avila-pci.o
 obj-pci-$(CONFIG_MACH_IXDPG425)                += ixdpg425-pci.o
@@ -40,5 +43,3 @@ obj-$(CONFIG_MACH_GORAMO_MLR) += goramo_mlr.o
 obj-$(CONFIG_MACH_ARCOM_VULCAN)        += vulcan-setup.o
 
 obj-$(CONFIG_PCI)              += $(obj-pci-$(CONFIG_PCI)) common-pci.o
-obj-$(CONFIG_IXP4XX_QMGR)      += ixp4xx_qmgr.o
-obj-$(CONFIG_IXP4XX_NPE)       += ixp4xx_npe.o
index 548c7d43ade6791ad7ca13dbae8f8342b5fcb751..9c834f0f4231cd1f96a106385ab041803272d000 100644 (file)
@@ -27,6 +27,8 @@
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 
+#include "irqs.h"
+
 #define AVILA_MAX_DEV  4
 #define LOFT_MAX_DEV   6
 #define IRQ_LINES      4
index 44cbbce6bda6a85da36b895ef3b212bb0e036f2b..1981b33109cb3e5415bf98f95ba9e9a1666d15c8 100644 (file)
@@ -28,6 +28,8 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
+#include "irqs.h"
+
 #define AVILA_SDA_PIN  7
 #define AVILA_SCL_PIN  6
 
index 6835b17113e57f3e5c936c2150c6d33ce385fcd6..a53104bb28f54d7517121e06cb1649039656e60c 100644 (file)
@@ -31,7 +31,7 @@
 
 #include <asm/cputype.h>
 #include <asm/irq.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/mach/pci.h>
 #include <mach/hardware.h>
 
index 846e033c56fa74a6a6873534255653b8593b3382..cc5f15679d29ed7e610931134cdb8848bb38a9b1 100644 (file)
 #include <linux/serial_core.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
-#include <linux/time.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
 #include <linux/io.h>
 #include <linux/export.h>
-#include <linux/gpio/driver.h>
 #include <linux/cpu.h>
 #include <linux/pci.h>
 #include <linux/sched_clock.h>
+#include <linux/bitops.h>
+#include <linux/irqchip/irq-ixp4xx.h>
+#include <linux/platform_data/timer-ixp4xx.h>
 #include <mach/udc.h>
 #include <mach/hardware.h>
 #include <mach/io.h>
 #include <linux/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
+#include <asm/exception.h>
 #include <asm/irq.h>
 #include <asm/system_misc.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 
-#define IXP4XX_TIMER_FREQ 66666000
-
-/*
- * The timer register doesn't allow to specify the two least significant bits of
- * the timeout value and assumes them being zero. So make sure IXP4XX_LATCH is
- * the best value with the two least significant bits unset.
- */
-#define IXP4XX_LATCH DIV_ROUND_CLOSEST(IXP4XX_TIMER_FREQ, \
-                                      (IXP4XX_OST_RELOAD_MASK + 1) * HZ) * \
-                       (IXP4XX_OST_RELOAD_MASK + 1)
+#include "irqs.h"
 
-static void __init ixp4xx_clocksource_init(void);
-static void __init ixp4xx_clockevent_init(void);
-static struct clock_event_device clockevent_ixp4xx;
+#define IXP4XX_TIMER_FREQ 66666000
 
 /*************************************************************************
  * IXP4xx chipset I/O mapping
@@ -77,11 +66,6 @@ static struct map_desc ixp4xx_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(IXP4XX_PCI_CFG_BASE_PHYS),
                .length         = IXP4XX_PCI_CFG_REGION_SIZE,
                .type           = MT_DEVICE
-       }, {    /* Queue Manager */
-               .virtual        = (unsigned long)IXP4XX_QMGR_BASE_VIRT,
-               .pfn            = __phys_to_pfn(IXP4XX_QMGR_BASE_PHYS),
-               .length         = IXP4XX_QMGR_REGION_SIZE,
-               .type           = MT_DEVICE
        },
 };
 
@@ -90,258 +74,23 @@ void __init ixp4xx_map_io(void)
        iotable_init(ixp4xx_io_desc, ARRAY_SIZE(ixp4xx_io_desc));
 }
 
-/*
- * GPIO-functions
- */
-/*
- * The following converted to the real HW bits the gpio_line_config
- */
-/* GPIO pin types */
-#define IXP4XX_GPIO_OUT                0x1
-#define IXP4XX_GPIO_IN                 0x2
-
-/* GPIO signal types */
-#define IXP4XX_GPIO_LOW                        0
-#define IXP4XX_GPIO_HIGH               1
-
-/* GPIO Clocks */
-#define IXP4XX_GPIO_CLK_0              14
-#define IXP4XX_GPIO_CLK_1              15
-
-static void gpio_line_config(u8 line, u32 direction)
-{
-       if (direction == IXP4XX_GPIO_IN)
-               *IXP4XX_GPIO_GPOER |= (1 << line);
-       else
-               *IXP4XX_GPIO_GPOER &= ~(1 << line);
-}
-
-static void gpio_line_get(u8 line, int *value)
-{
-       *value = (*IXP4XX_GPIO_GPINR >> line) & 0x1;
-}
-
-static void gpio_line_set(u8 line, int value)
-{
-       if (value == IXP4XX_GPIO_HIGH)
-           *IXP4XX_GPIO_GPOUTR |= (1 << line);
-       else if (value == IXP4XX_GPIO_LOW)
-           *IXP4XX_GPIO_GPOUTR &= ~(1 << line);
-}
-
-/*************************************************************************
- * IXP4xx chipset IRQ handling
- *
- * TODO: GPIO IRQs should be marked invalid until the user of the IRQ
- *       (be it PCI or something else) configures that GPIO line
- *       as an IRQ.
- **************************************************************************/
-enum ixp4xx_irq_type {
-       IXP4XX_IRQ_LEVEL, IXP4XX_IRQ_EDGE
-};
-
-/* Each bit represents an IRQ: 1: edge-triggered, 0: level triggered */
-static unsigned long long ixp4xx_irq_edge = 0;
-
-/*
- * IRQ -> GPIO mapping table
- */
-static signed char irq2gpio[32] = {
-       -1, -1, -1, -1, -1, -1,  0,  1,
-       -1, -1, -1, -1, -1, -1, -1, -1,
-       -1, -1, -1,  2,  3,  4,  5,  6,
-        7,  8,  9, 10, 11, 12, -1, -1,
-};
-
-static int ixp4xx_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
-{
-       int irq;
-
-       for (irq = 0; irq < 32; irq++) {
-               if (irq2gpio[irq] == gpio)
-                       return irq;
-       }
-       return -EINVAL;
-}
-
-static int ixp4xx_set_irq_type(struct irq_data *d, unsigned int type)
-{
-       int line = irq2gpio[d->irq];
-       u32 int_style;
-       enum ixp4xx_irq_type irq_type;
-       volatile u32 *int_reg;
-
-       /*
-        * Only for GPIO IRQs
-        */
-       if (line < 0)
-               return -EINVAL;
-
-       switch (type){
-       case IRQ_TYPE_EDGE_BOTH:
-               int_style = IXP4XX_GPIO_STYLE_TRANSITIONAL;
-               irq_type = IXP4XX_IRQ_EDGE;
-               break;
-       case IRQ_TYPE_EDGE_RISING:
-               int_style = IXP4XX_GPIO_STYLE_RISING_EDGE;
-               irq_type = IXP4XX_IRQ_EDGE;
-               break;
-       case IRQ_TYPE_EDGE_FALLING:
-               int_style = IXP4XX_GPIO_STYLE_FALLING_EDGE;
-               irq_type = IXP4XX_IRQ_EDGE;
-               break;
-       case IRQ_TYPE_LEVEL_HIGH:
-               int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
-               irq_type = IXP4XX_IRQ_LEVEL;
-               break;
-       case IRQ_TYPE_LEVEL_LOW:
-               int_style = IXP4XX_GPIO_STYLE_ACTIVE_LOW;
-               irq_type = IXP4XX_IRQ_LEVEL;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (irq_type == IXP4XX_IRQ_EDGE)
-               ixp4xx_irq_edge |= (1 << d->irq);
-       else
-               ixp4xx_irq_edge &= ~(1 << d->irq);
-
-       if (line >= 8) {        /* pins 8-15 */
-               line -= 8;
-               int_reg = IXP4XX_GPIO_GPIT2R;
-       } else {                /* pins 0-7 */
-               int_reg = IXP4XX_GPIO_GPIT1R;
-       }
-
-       /* Clear the style for the appropriate pin */
-       *int_reg &= ~(IXP4XX_GPIO_STYLE_CLEAR <<
-                       (line * IXP4XX_GPIO_STYLE_SIZE));
-
-       *IXP4XX_GPIO_GPISR = (1 << line);
-
-       /* Set the new style */
-       *int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE));
-
-       /* Configure the line as an input */
-       gpio_line_config(irq2gpio[d->irq], IXP4XX_GPIO_IN);
-
-       return 0;
-}
-
-static void ixp4xx_irq_mask(struct irq_data *d)
-{
-       if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && d->irq >= 32)
-               *IXP4XX_ICMR2 &= ~(1 << (d->irq - 32));
-       else
-               *IXP4XX_ICMR &= ~(1 << d->irq);
-}
-
-static void ixp4xx_irq_ack(struct irq_data *d)
-{
-       int line = (d->irq < 32) ? irq2gpio[d->irq] : -1;
-
-       if (line >= 0)
-               *IXP4XX_GPIO_GPISR = (1 << line);
-}
-
-/*
- * Level triggered interrupts on GPIO lines can only be cleared when the
- * interrupt condition disappears.
- */
-static void ixp4xx_irq_unmask(struct irq_data *d)
-{
-       if (!(ixp4xx_irq_edge & (1 << d->irq)))
-               ixp4xx_irq_ack(d);
-
-       if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && d->irq >= 32)
-               *IXP4XX_ICMR2 |= (1 << (d->irq - 32));
-       else
-               *IXP4XX_ICMR |= (1 << d->irq);
-}
-
-static struct irq_chip ixp4xx_irq_chip = {
-       .name           = "IXP4xx",
-       .irq_ack        = ixp4xx_irq_ack,
-       .irq_mask       = ixp4xx_irq_mask,
-       .irq_unmask     = ixp4xx_irq_unmask,
-       .irq_set_type   = ixp4xx_set_irq_type,
-};
-
 void __init ixp4xx_init_irq(void)
 {
-       int i = 0;
-
        /*
         * ixp4xx does not implement the XScale PWRMODE register
         * so it must not call cpu_do_idle().
         */
        cpu_idle_poll_ctrl(true);
 
-       /* Route all sources to IRQ instead of FIQ */
-       *IXP4XX_ICLR = 0x0;
-
-       /* Disable all interrupt */
-       *IXP4XX_ICMR = 0x0; 
-
-       if (cpu_is_ixp46x() || cpu_is_ixp43x()) {
-               /* Route upper 32 sources to IRQ instead of FIQ */
-               *IXP4XX_ICLR2 = 0x00;
-
-               /* Disable upper 32 interrupts */
-               *IXP4XX_ICMR2 = 0x00;
-       }
-
-        /* Default to all level triggered */
-       for(i = 0; i < NR_IRQS; i++) {
-               irq_set_chip_and_handler(i, &ixp4xx_irq_chip,
-                                        handle_level_irq);
-               irq_clear_status_flags(i, IRQ_NOREQUEST);
-       }
+       ixp4xx_irq_init(IXP4XX_INTC_BASE_PHYS,
+                       (cpu_is_ixp46x() || cpu_is_ixp43x()));
 }
 
-
-/*************************************************************************
- * IXP4xx timer tick
- * We use OS timer1 on the CPU for the timer tick and the timestamp 
- * counter as a source of real clock ticks to account for missed jiffies.
- *************************************************************************/
-
-static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id)
-{
-       struct clock_event_device *evt = dev_id;
-
-       /* Clear Pending Interrupt by writing '1' to it */
-       *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
-
-       evt->event_handler(evt);
-
-       return IRQ_HANDLED;
-}
-
-static struct irqaction ixp4xx_timer_irq = {
-       .name           = "timer1",
-       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = ixp4xx_timer_interrupt,
-       .dev_id         = &clockevent_ixp4xx,
-};
-
 void __init ixp4xx_timer_init(void)
 {
-       /* Reset/disable counter */
-       *IXP4XX_OSRT1 = 0;
-
-       /* Clear Pending Interrupt by writing '1' to it */
-       *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
-
-       /* Reset time-stamp counter */
-       *IXP4XX_OSTS = 0;
-
-       /* Connect the interrupt handler and enable the interrupt */
-       setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq);
-
-       ixp4xx_clocksource_init();
-       ixp4xx_clockevent_init();
+       return ixp4xx_timer_setup(IXP4XX_TIMER_BASE_PHYS,
+                                 IRQ_IXP4XX_TIMER1,
+                                 IXP4XX_TIMER_FREQ);
 }
 
 static struct pxa2xx_udc_mach_info ixp4xx_udc_info;
@@ -364,6 +113,24 @@ static struct resource ixp4xx_udc_resources[] = {
        },
 };
 
+static struct resource ixp4xx_gpio_resource[] = {
+       {
+               .start = IXP4XX_GPIO_BASE_PHYS,
+               .end = IXP4XX_GPIO_BASE_PHYS + 0xfff,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device ixp4xx_gpio_device = {
+       .name           = "ixp4xx-gpio",
+       .id             = -1,
+       .dev = {
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .resource = ixp4xx_gpio_resource,
+       .num_resources  = ARRAY_SIZE(ixp4xx_gpio_resource),
+};
+
 /*
  * USB device controller. The IXP4xx uses the same controller as PXA25X,
  * so we just use the same device.
@@ -378,7 +145,61 @@ static struct platform_device ixp4xx_udc_device = {
        },
 };
 
+static struct resource ixp4xx_npe_resources[] = {
+       {
+               .start = IXP4XX_NPEA_BASE_PHYS,
+               .end = IXP4XX_NPEA_BASE_PHYS + 0xfff,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IXP4XX_NPEB_BASE_PHYS,
+               .end = IXP4XX_NPEB_BASE_PHYS + 0xfff,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IXP4XX_NPEC_BASE_PHYS,
+               .end = IXP4XX_NPEC_BASE_PHYS + 0xfff,
+               .flags = IORESOURCE_MEM,
+       },
+
+};
+
+static struct platform_device ixp4xx_npe_device = {
+       .name           = "ixp4xx-npe",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(ixp4xx_npe_resources),
+       .resource       = ixp4xx_npe_resources,
+};
+
+static struct resource ixp4xx_qmgr_resources[] = {
+       {
+               .start = IXP4XX_QMGR_BASE_PHYS,
+               .end = IXP4XX_QMGR_BASE_PHYS + 0x3fff,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_IXP4XX_QM1,
+               .end = IRQ_IXP4XX_QM1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_IXP4XX_QM2,
+               .end = IRQ_IXP4XX_QM2,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device ixp4xx_qmgr_device = {
+       .name           = "ixp4xx-qmgr",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(ixp4xx_qmgr_resources),
+       .resource       = ixp4xx_qmgr_resources,
+};
+
 static struct platform_device *ixp4xx_devices[] __initdata = {
+       &ixp4xx_npe_device,
+       &ixp4xx_qmgr_device,
+       &ixp4xx_gpio_device,
        &ixp4xx_udc_device,
 };
 
@@ -413,56 +234,12 @@ static struct platform_device *ixp46x_devices[] __initdata = {
 unsigned long ixp4xx_exp_bus_size;
 EXPORT_SYMBOL(ixp4xx_exp_bus_size);
 
-static int ixp4xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
-{
-       gpio_line_config(gpio, IXP4XX_GPIO_IN);
-
-       return 0;
-}
-
-static int ixp4xx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
-                                       int level)
-{
-       gpio_line_set(gpio, level);
-       gpio_line_config(gpio, IXP4XX_GPIO_OUT);
-
-       return 0;
-}
-
-static int ixp4xx_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
-{
-       int value;
-
-       gpio_line_get(gpio, &value);
-
-       return value;
-}
-
-static void ixp4xx_gpio_set_value(struct gpio_chip *chip, unsigned gpio,
-                                 int value)
-{
-       gpio_line_set(gpio, value);
-}
-
-static struct gpio_chip ixp4xx_gpio_chip = {
-       .label                  = "IXP4XX_GPIO_CHIP",
-       .direction_input        = ixp4xx_gpio_direction_input,
-       .direction_output       = ixp4xx_gpio_direction_output,
-       .get                    = ixp4xx_gpio_get_value,
-       .set                    = ixp4xx_gpio_set_value,
-       .to_irq                 = ixp4xx_gpio_to_irq,
-       .base                   = 0,
-       .ngpio                  = 16,
-};
-
 void __init ixp4xx_sys_init(void)
 {
        ixp4xx_exp_bus_size = SZ_16M;
 
        platform_add_devices(ixp4xx_devices, ARRAY_SIZE(ixp4xx_devices));
 
-       gpiochip_add_data(&ixp4xx_gpio_chip, NULL);
-
        if (cpu_is_ixp46x()) {
                int region;
 
@@ -481,103 +258,8 @@ void __init ixp4xx_sys_init(void)
                        ixp4xx_exp_bus_size >> 20);
 }
 
-/*
- * sched_clock()
- */
-static u64 notrace ixp4xx_read_sched_clock(void)
-{
-       return *IXP4XX_OSTS;
-}
-
-/*
- * clocksource
- */
-
-static u64 ixp4xx_clocksource_read(struct clocksource *c)
-{
-       return *IXP4XX_OSTS;
-}
-
 unsigned long ixp4xx_timer_freq = IXP4XX_TIMER_FREQ;
 EXPORT_SYMBOL(ixp4xx_timer_freq);
-static void __init ixp4xx_clocksource_init(void)
-{
-       sched_clock_register(ixp4xx_read_sched_clock, 32, ixp4xx_timer_freq);
-
-       clocksource_mmio_init(NULL, "OSTS", ixp4xx_timer_freq, 200, 32,
-                       ixp4xx_clocksource_read);
-}
-
-/*
- * clockevents
- */
-static int ixp4xx_set_next_event(unsigned long evt,
-                                struct clock_event_device *unused)
-{
-       unsigned long opts = *IXP4XX_OSRT1 & IXP4XX_OST_RELOAD_MASK;
-
-       *IXP4XX_OSRT1 = (evt & ~IXP4XX_OST_RELOAD_MASK) | opts;
-
-       return 0;
-}
-
-static int ixp4xx_shutdown(struct clock_event_device *evt)
-{
-       unsigned long opts = *IXP4XX_OSRT1 & IXP4XX_OST_RELOAD_MASK;
-       unsigned long osrt = *IXP4XX_OSRT1 & ~IXP4XX_OST_RELOAD_MASK;
-
-       opts &= ~IXP4XX_OST_ENABLE;
-       *IXP4XX_OSRT1 = osrt | opts;
-       return 0;
-}
-
-static int ixp4xx_set_oneshot(struct clock_event_device *evt)
-{
-       unsigned long opts = IXP4XX_OST_ENABLE | IXP4XX_OST_ONE_SHOT;
-       unsigned long osrt = 0;
-
-       /* period set by 'set next_event' */
-       *IXP4XX_OSRT1 = osrt | opts;
-       return 0;
-}
-
-static int ixp4xx_set_periodic(struct clock_event_device *evt)
-{
-       unsigned long opts = IXP4XX_OST_ENABLE;
-       unsigned long osrt = IXP4XX_LATCH & ~IXP4XX_OST_RELOAD_MASK;
-
-       *IXP4XX_OSRT1 = osrt | opts;
-       return 0;
-}
-
-static int ixp4xx_resume(struct clock_event_device *evt)
-{
-       unsigned long opts = *IXP4XX_OSRT1 & IXP4XX_OST_RELOAD_MASK;
-       unsigned long osrt = *IXP4XX_OSRT1 & ~IXP4XX_OST_RELOAD_MASK;
-
-       opts |= IXP4XX_OST_ENABLE;
-       *IXP4XX_OSRT1 = osrt | opts;
-       return 0;
-}
-
-static struct clock_event_device clockevent_ixp4xx = {
-       .name                   = "ixp4xx timer1",
-       .features               = CLOCK_EVT_FEAT_PERIODIC |
-                                 CLOCK_EVT_FEAT_ONESHOT,
-       .rating                 = 200,
-       .set_state_shutdown     = ixp4xx_shutdown,
-       .set_state_periodic     = ixp4xx_set_periodic,
-       .set_state_oneshot      = ixp4xx_set_oneshot,
-       .tick_resume            = ixp4xx_resume,
-       .set_next_event         = ixp4xx_set_next_event,
-};
-
-static void __init ixp4xx_clockevent_init(void)
-{
-       clockevent_ixp4xx.cpumask = cpumask_of(0);
-       clockevents_config_and_register(&clockevent_ixp4xx, IXP4XX_TIMER_FREQ,
-                                       0xf, 0xfffffffe);
-}
 
 void ixp4xx_restart(enum reboot_mode mode, const char *cmd)
 {
index 5d14ce2aee6d9c77a334ee171da39064502b42dc..a16c35d2bb96958be64d44fc4d8e208c49ff325f 100644 (file)
@@ -23,6 +23,8 @@
 #include <asm/irq.h>
 #include <asm/mach/pci.h>
 
+#include "irqs.h"
+
 #define SLOT0_DEVID    14
 #define SLOT1_DEVID    15
 
index 7e40fe70933bcf4190117aa29a8cbb6b9dbe138d..7ca43ca2816d73d6d3af01510dda4afe78ae041b 100644 (file)
@@ -25,6 +25,8 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
+#include "irqs.h"
+
 #define COYOTE_IDE_BASE_PHYS   IXP4XX_EXP_BUS_BASE(3)
 #define COYOTE_IDE_BASE_VIRT   0xFFFE1000
 #define COYOTE_IDE_REGION_SIZE 0x1000
index 8dca769377238f69a6757c84a9bedb18291587b6..6899023bd1b7b9337e73040e0552feea6a075a3d 100644 (file)
@@ -22,6 +22,8 @@
 #include <asm/mach/pci.h>
 #include <asm/mach-types.h>
 
+#include "irqs.h"
+
 #define MAX_DEV                4
 #define IRQ_LINES      3
 
index 397190f3a8da6cdbc87a3fac2296f793a497cf8f..4d4c62fced714a81d3d16b4468f8eefcf1c67974 100644 (file)
@@ -35,6 +35,8 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/time.h>
 
+#include "irqs.h"
+
 #define DSMG600_SDA_PIN                5
 #define DSMG600_SCL_PIN                4
 
@@ -268,9 +270,6 @@ static void __init dsmg600_init(void)
 {
        ixp4xx_sys_init();
 
-       /* Make sure that GPIO14 and GPIO15 are not used as clocks */
-       *IXP4XX_GPIO_GPCLKR = 0;
-
        dsmg600_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
        dsmg600_flash_resource.end =
                IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
index fd4a8625b4ae7508eda6b100de10343687561c83..6c08bb9d980769dd24984614e934b5a9f5bbef6c 100644 (file)
@@ -22,6 +22,8 @@
 #include <asm/mach/pci.h>
 #include <asm/mach-types.h>
 
+#include "irqs.h"
+
 #define MAX_DEV                3
 #define IRQ_LINES      3
 
index f0a152e365b10cd63ad523667cf2c09f05f98522..648932d8d7a8fbec25211201469c302f725d7df6 100644 (file)
@@ -29,6 +29,8 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
+#include "irqs.h"
+
 #define FSG_SDA_PIN            12
 #define FSG_SCL_PIN            13
 
index d9d6cc0897070c60f76f0efe676879d42b73883a..903c75330b7611b247c1edca77f678cd95f4d9e0 100644 (file)
@@ -27,6 +27,8 @@
 
 #include <asm/mach/pci.h>
 
+#include "irqs.h"
+
 void __init gateway7001_pci_preinit(void)
 {
        irq_set_irq_type(IRQ_IXP4XX_GPIO10, IRQ_TYPE_LEVEL_LOW);
index 1be6faf6da9a3f69528c8196adefdef2df25ae38..678e7dfff0e5a403dd0b549c0c79b507158086f1 100644 (file)
@@ -28,6 +28,8 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
+#include "irqs.h"
+
 static struct flash_platform_data gateway7001_flash_data = {
        .map_name       = "cfi_probe",
        .width          = 2,
index 551d114c9e144a3fad9152c2ef9d99fc98ebb857..1223d160448f3b5f4a20460cd1ef2c42c032337f 100644 (file)
@@ -30,6 +30,8 @@
 #include <mach/hardware.h>
 #include <asm/mach/pci.h>
 
+#include "irqs.h"
+
 #define SLOT0_DEVID    0
 #define SLOT1_DEVID    1
 #define INTA           10 /* slot 1 has INTA and INTB crossed */
index 16a12994fb5378c8bc77a0b4b73d3e7da453bcee..5dbdde8e2338329692a6c709d7bc3ca09362bb9b 100644 (file)
@@ -36,6 +36,8 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
+#include "irqs.h"
+
 /* GPIO 5,6,7 and 12 are hard wired to the Kendin KS8995M Switch
    and operate as an SPI type interface.  The details of the interface
    are available on Kendin/Micrel's web site. */
diff --git a/arch/arm/mach-ixp4xx/include/mach/entry-macro.S b/arch/arm/mach-ixp4xx/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 79adf83..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for IXP4xx-based platforms
- *
- * 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 <mach/hardware.h>
-
-               .macro  get_irqnr_preamble, base, tmp
-               .endm
-
-               .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
-               ldr     \irqstat, =(IXP4XX_INTC_BASE_VIRT+IXP4XX_ICIP_OFFSET)
-               ldr     \irqstat, [\irqstat]            @ get interrupts
-               cmp     \irqstat, #0
-               beq     1001f                           @ upper IRQ?
-               clz     \irqnr, \irqstat
-               mov     \base, #31
-               sub     \irqnr, \base, \irqnr
-               b       1002f                           @ lower IRQ being
-                                                       @ handled
-
-1001:
-               /*
-                * IXP465/IXP435 has an upper IRQ status register
-                */
-#if defined(CONFIG_CPU_IXP46X) || defined(CONFIG_CPU_IXP43X)
-               ldr     \irqstat, =(IXP4XX_INTC_BASE_VIRT+IXP4XX_ICIP2_OFFSET)
-               ldr     \irqstat, [\irqstat]            @ get upper interrupts
-               mov     \irqnr, #63
-               clz     \irqstat, \irqstat
-               cmp     \irqstat, #32
-               subne   \irqnr, \irqnr, \irqstat
-#endif
-1002:
-               .endm
-
-
diff --git a/arch/arm/mach-ixp4xx/include/mach/irqs.h b/arch/arm/mach-ixp4xx/include/mach/irqs.h
deleted file mode 100644 (file)
index 7e6d4cc..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/include/mach/irqs.h 
- *
- * IRQ definitions for IXP4XX based systems
- *
- * Copyright (C) 2002 Intel Corporation.
- * Copyright (C) 2003 MontaVista Software, Inc.
- *
- * 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.
- *
- */
-
-#ifndef _ARCH_IXP4XX_IRQS_H_
-#define _ARCH_IXP4XX_IRQS_H_
-
-#define IRQ_IXP4XX_NPEA                0
-#define IRQ_IXP4XX_NPEB                1
-#define IRQ_IXP4XX_NPEC                2
-#define IRQ_IXP4XX_QM1         3
-#define IRQ_IXP4XX_QM2         4
-#define IRQ_IXP4XX_TIMER1      5
-#define IRQ_IXP4XX_GPIO0       6
-#define IRQ_IXP4XX_GPIO1       7
-#define IRQ_IXP4XX_PCI_INT     8
-#define IRQ_IXP4XX_PCI_DMA1    9
-#define IRQ_IXP4XX_PCI_DMA2    10
-#define IRQ_IXP4XX_TIMER2      11
-#define IRQ_IXP4XX_USB         12
-#define IRQ_IXP4XX_UART2       13
-#define IRQ_IXP4XX_TIMESTAMP   14
-#define IRQ_IXP4XX_UART1       15
-#define IRQ_IXP4XX_WDOG                16
-#define IRQ_IXP4XX_AHB_PMU     17
-#define IRQ_IXP4XX_XSCALE_PMU  18
-#define IRQ_IXP4XX_GPIO2       19
-#define IRQ_IXP4XX_GPIO3       20
-#define IRQ_IXP4XX_GPIO4       21
-#define IRQ_IXP4XX_GPIO5       22
-#define IRQ_IXP4XX_GPIO6       23
-#define IRQ_IXP4XX_GPIO7       24
-#define IRQ_IXP4XX_GPIO8       25
-#define IRQ_IXP4XX_GPIO9       26
-#define IRQ_IXP4XX_GPIO10      27
-#define IRQ_IXP4XX_GPIO11      28
-#define IRQ_IXP4XX_GPIO12      29
-#define IRQ_IXP4XX_SW_INT1     30
-#define IRQ_IXP4XX_SW_INT2     31
-#define IRQ_IXP4XX_USB_HOST    32
-#define IRQ_IXP4XX_I2C         33
-#define IRQ_IXP4XX_SSP         34
-#define IRQ_IXP4XX_TSYNC       35
-#define IRQ_IXP4XX_EAU_DONE    36
-#define IRQ_IXP4XX_SHA_DONE    37
-#define IRQ_IXP4XX_SWCP_PE     58
-#define IRQ_IXP4XX_QM_PE       60
-#define IRQ_IXP4XX_MCU_ECC     61
-#define IRQ_IXP4XX_EXP_PE      62
-
-#define _IXP4XX_GPIO_IRQ(n)    (IRQ_IXP4XX_GPIO ## n)
-#define IXP4XX_GPIO_IRQ(n)     _IXP4XX_GPIO_IRQ(n)
-
-/*
- * Only first 32 sources are valid if running on IXP42x systems
- */
-#if defined(CONFIG_CPU_IXP46X) || defined(CONFIG_CPU_IXP43X)
-#define NR_IRQS                        64
-#else
-#define NR_IRQS                        32
-#endif
-
-#define        XSCALE_PMU_IRQ          (IRQ_IXP4XX_XSCALE_PMU)
-
-#endif
index b7ddd27419c223541f28f5ed9de000ab86ac727b..588b7665108563e82596642168cd6d2a579ee8c8 100644 (file)
@@ -43,8 +43,6 @@
  * Queue Manager
  */
 #define IXP4XX_QMGR_BASE_PHYS          0x60000000
-#define IXP4XX_QMGR_BASE_VIRT          IOMEM(0xFEF15000)
-#define IXP4XX_QMGR_REGION_SIZE                0x00004000
 
 /*
  * Peripheral space, including debug UART. Must be section-aligned so that
 #define IXP4XX_INTC_BASE_VIRT          (IXP4XX_PERIPHERAL_BASE_VIRT + 0x3000)
 #define IXP4XX_GPIO_BASE_VIRT          (IXP4XX_PERIPHERAL_BASE_VIRT + 0x4000)
 #define IXP4XX_TIMER_BASE_VIRT         (IXP4XX_PERIPHERAL_BASE_VIRT + 0x5000)
-#define IXP4XX_NPEA_BASE_VIRT          (IXP4XX_PERIPHERAL_BASE_VIRT + 0x6000)
-#define IXP4XX_NPEB_BASE_VIRT          (IXP4XX_PERIPHERAL_BASE_VIRT + 0x7000)
-#define IXP4XX_NPEC_BASE_VIRT          (IXP4XX_PERIPHERAL_BASE_VIRT + 0x8000)
 #define IXP4XX_EthB_BASE_VIRT          (IXP4XX_PERIPHERAL_BASE_VIRT + 0x9000)
 #define IXP4XX_EthC_BASE_VIRT          (IXP4XX_PERIPHERAL_BASE_VIRT + 0xA000)
 #define IXP4XX_USB_BASE_VIRT           (IXP4XX_PERIPHERAL_BASE_VIRT + 0xB000)
 #define IXP4XX_I2C_BASE_VIRT           (IXP4XX_PERIPHERAL_BASE_VIRT + 0x11000)
 #define IXP4XX_SSP_BASE_VIRT           (IXP4XX_PERIPHERAL_BASE_VIRT + 0x12000)
 
-/*
- * Constants to make it easy to access  Interrupt Controller registers
- */
-#define IXP4XX_ICPR_OFFSET     0x00 /* Interrupt Status */
-#define IXP4XX_ICMR_OFFSET     0x04 /* Interrupt Enable */
-#define IXP4XX_ICLR_OFFSET     0x08 /* Interrupt IRQ/FIQ Select */
-#define IXP4XX_ICIP_OFFSET      0x0C /* IRQ Status */
-#define IXP4XX_ICFP_OFFSET     0x10 /* FIQ Status */
-#define IXP4XX_ICHR_OFFSET     0x14 /* Interrupt Priority */
-#define IXP4XX_ICIH_OFFSET     0x18 /* IRQ Highest Pri Int */
-#define IXP4XX_ICFH_OFFSET     0x1C /* FIQ Highest Pri Int */
-
-/*
- * IXP465-only
- */
-#define        IXP4XX_ICPR2_OFFSET     0x20 /* Interrupt Status 2 */
-#define        IXP4XX_ICMR2_OFFSET     0x24 /* Interrupt Enable 2 */
-#define        IXP4XX_ICLR2_OFFSET     0x28 /* Interrupt IRQ/FIQ Select 2 */
-#define IXP4XX_ICIP2_OFFSET     0x2C /* IRQ Status */
-#define IXP4XX_ICFP2_OFFSET    0x30 /* FIQ Status */
-#define IXP4XX_ICEEN_OFFSET    0x34 /* Error High Pri Enable */
-
-
-/*
- * Interrupt Controller Register Definitions.
- */
-
-#define IXP4XX_INTC_REG(x) ((volatile u32 *)(IXP4XX_INTC_BASE_VIRT+(x)))
-
-#define IXP4XX_ICPR    IXP4XX_INTC_REG(IXP4XX_ICPR_OFFSET)
-#define IXP4XX_ICMR     IXP4XX_INTC_REG(IXP4XX_ICMR_OFFSET)
-#define IXP4XX_ICLR     IXP4XX_INTC_REG(IXP4XX_ICLR_OFFSET)
-#define IXP4XX_ICIP     IXP4XX_INTC_REG(IXP4XX_ICIP_OFFSET)
-#define IXP4XX_ICFP     IXP4XX_INTC_REG(IXP4XX_ICFP_OFFSET)
-#define IXP4XX_ICHR     IXP4XX_INTC_REG(IXP4XX_ICHR_OFFSET)
-#define IXP4XX_ICIH     IXP4XX_INTC_REG(IXP4XX_ICIH_OFFSET) 
-#define IXP4XX_ICFH     IXP4XX_INTC_REG(IXP4XX_ICFH_OFFSET)
-#define IXP4XX_ICPR2   IXP4XX_INTC_REG(IXP4XX_ICPR2_OFFSET)
-#define IXP4XX_ICMR2    IXP4XX_INTC_REG(IXP4XX_ICMR2_OFFSET)
-#define IXP4XX_ICLR2    IXP4XX_INTC_REG(IXP4XX_ICLR2_OFFSET)
-#define IXP4XX_ICIP2    IXP4XX_INTC_REG(IXP4XX_ICIP2_OFFSET)
-#define IXP4XX_ICFP2    IXP4XX_INTC_REG(IXP4XX_ICFP2_OFFSET)
-#define IXP4XX_ICEEN    IXP4XX_INTC_REG(IXP4XX_ICEEN_OFFSET)
-                                                                                
-/*
- * Constants to make it easy to access GPIO registers
- */
-#define IXP4XX_GPIO_GPOUTR_OFFSET       0x00
-#define IXP4XX_GPIO_GPOER_OFFSET        0x04
-#define IXP4XX_GPIO_GPINR_OFFSET        0x08
-#define IXP4XX_GPIO_GPISR_OFFSET        0x0C
-#define IXP4XX_GPIO_GPIT1R_OFFSET      0x10
-#define IXP4XX_GPIO_GPIT2R_OFFSET      0x14
-#define IXP4XX_GPIO_GPCLKR_OFFSET      0x18
-#define IXP4XX_GPIO_GPDBSELR_OFFSET    0x1C
-
-/* 
- * GPIO Register Definitions.
- * [Only perform 32bit reads/writes]
- */
-#define IXP4XX_GPIO_REG(x) ((volatile u32 *)(IXP4XX_GPIO_BASE_VIRT+(x)))
-
-#define IXP4XX_GPIO_GPOUTR     IXP4XX_GPIO_REG(IXP4XX_GPIO_GPOUTR_OFFSET)
-#define IXP4XX_GPIO_GPOER       IXP4XX_GPIO_REG(IXP4XX_GPIO_GPOER_OFFSET)
-#define IXP4XX_GPIO_GPINR       IXP4XX_GPIO_REG(IXP4XX_GPIO_GPINR_OFFSET)
-#define IXP4XX_GPIO_GPISR       IXP4XX_GPIO_REG(IXP4XX_GPIO_GPISR_OFFSET)
-#define IXP4XX_GPIO_GPIT1R      IXP4XX_GPIO_REG(IXP4XX_GPIO_GPIT1R_OFFSET)
-#define IXP4XX_GPIO_GPIT2R      IXP4XX_GPIO_REG(IXP4XX_GPIO_GPIT2R_OFFSET)
-#define IXP4XX_GPIO_GPCLKR      IXP4XX_GPIO_REG(IXP4XX_GPIO_GPCLKR_OFFSET)
-#define IXP4XX_GPIO_GPDBSELR    IXP4XX_GPIO_REG(IXP4XX_GPIO_GPDBSELR_OFFSET)
-
-/*
- * GPIO register bit definitions
- */
-
-/* Interrupt styles
- */
-#define IXP4XX_GPIO_STYLE_ACTIVE_HIGH  0x0
-#define IXP4XX_GPIO_STYLE_ACTIVE_LOW   0x1
-#define IXP4XX_GPIO_STYLE_RISING_EDGE  0x2
-#define IXP4XX_GPIO_STYLE_FALLING_EDGE 0x3
-#define IXP4XX_GPIO_STYLE_TRANSITIONAL 0x4
-
-/* 
- * Mask used to clear interrupt styles 
- */
-#define IXP4XX_GPIO_STYLE_CLEAR                0x7
-#define IXP4XX_GPIO_STYLE_SIZE         3
-
 /*
  * Constants to make it easy to access Timer Control/Status registers
  */
diff --git a/arch/arm/mach-ixp4xx/include/mach/npe.h b/arch/arm/mach-ixp4xx/include/mach/npe.h
deleted file mode 100644 (file)
index 3a98084..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __IXP4XX_NPE_H
-#define __IXP4XX_NPE_H
-
-#include <linux/kernel.h>
-
-extern const char *npe_names[];
-
-struct npe_regs {
-       u32 exec_addr, exec_data, exec_status_cmd, exec_count;
-       u32 action_points[4];
-       u32 watchpoint_fifo, watch_count;
-       u32 profile_count;
-       u32 messaging_status, messaging_control;
-       u32 mailbox_status, /*messaging_*/ in_out_fifo;
-};
-
-struct npe {
-       struct resource *mem_res;
-       struct npe_regs __iomem *regs;
-       u32 regs_phys;
-       int id;
-       int valid;
-};
-
-
-static inline const char *npe_name(struct npe *npe)
-{
-       return npe_names[npe->id];
-}
-
-int npe_running(struct npe *npe);
-int npe_send_message(struct npe *npe, const void *msg, const char *what);
-int npe_recv_message(struct npe *npe, void *msg, const char *what);
-int npe_send_recv_message(struct npe *npe, void *msg, const char *what);
-int npe_load_firmware(struct npe *npe, const char *name, struct device *dev);
-struct npe *npe_request(unsigned id);
-void npe_release(struct npe *npe);
-
-#endif /* __IXP4XX_NPE_H */
diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
deleted file mode 100644 (file)
index 4de8da5..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License
- * as published by the Free Software Foundation.
- */
-
-#ifndef IXP4XX_QMGR_H
-#define IXP4XX_QMGR_H
-
-#include <linux/io.h>
-#include <linux/kernel.h>
-
-#define DEBUG_QMGR     0
-
-#define HALF_QUEUES    32
-#define QUEUES         64
-#define MAX_QUEUE_LENGTH 4     /* in dwords */
-
-#define QUEUE_STAT1_EMPTY              1 /* queue status bits */
-#define QUEUE_STAT1_NEARLY_EMPTY       2
-#define QUEUE_STAT1_NEARLY_FULL                4
-#define QUEUE_STAT1_FULL               8
-#define QUEUE_STAT2_UNDERFLOW          1
-#define QUEUE_STAT2_OVERFLOW           2
-
-#define QUEUE_WATERMARK_0_ENTRIES      0
-#define QUEUE_WATERMARK_1_ENTRY                1
-#define QUEUE_WATERMARK_2_ENTRIES      2
-#define QUEUE_WATERMARK_4_ENTRIES      3
-#define QUEUE_WATERMARK_8_ENTRIES      4
-#define QUEUE_WATERMARK_16_ENTRIES     5
-#define QUEUE_WATERMARK_32_ENTRIES     6
-#define QUEUE_WATERMARK_64_ENTRIES     7
-
-/* queue interrupt request conditions */
-#define QUEUE_IRQ_SRC_EMPTY            0
-#define QUEUE_IRQ_SRC_NEARLY_EMPTY     1
-#define QUEUE_IRQ_SRC_NEARLY_FULL      2
-#define QUEUE_IRQ_SRC_FULL             3
-#define QUEUE_IRQ_SRC_NOT_EMPTY                4
-#define QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY 5
-#define QUEUE_IRQ_SRC_NOT_NEARLY_FULL  6
-#define QUEUE_IRQ_SRC_NOT_FULL         7
-
-struct qmgr_regs {
-       u32 acc[QUEUES][MAX_QUEUE_LENGTH]; /* 0x000 - 0x3FF */
-       u32 stat1[4];           /* 0x400 - 0x40F */
-       u32 stat2[2];           /* 0x410 - 0x417 */
-       u32 statne_h;           /* 0x418 - queue nearly empty */
-       u32 statf_h;            /* 0x41C - queue full */
-       u32 irqsrc[4];          /* 0x420 - 0x42F IRC source */
-       u32 irqen[2];           /* 0x430 - 0x437 IRQ enabled */
-       u32 irqstat[2];         /* 0x438 - 0x43F - IRQ access only */
-       u32 reserved[1776];
-       u32 sram[2048];         /* 0x2000 - 0x3FFF - config and buffer */
-};
-
-void qmgr_set_irq(unsigned int queue, int src,
-                 void (*handler)(void *pdev), void *pdev);
-void qmgr_enable_irq(unsigned int queue);
-void qmgr_disable_irq(unsigned int queue);
-
-/* request_ and release_queue() must be called from non-IRQ context */
-
-#if DEBUG_QMGR
-extern char qmgr_queue_descs[QUEUES][32];
-
-int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
-                      unsigned int nearly_empty_watermark,
-                      unsigned int nearly_full_watermark,
-                      const char *desc_format, const char* name);
-#else
-int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
-                        unsigned int nearly_empty_watermark,
-                        unsigned int nearly_full_watermark);
-#define qmgr_request_queue(queue, len, nearly_empty_watermark,         \
-                          nearly_full_watermark, desc_format, name)    \
-       __qmgr_request_queue(queue, len, nearly_empty_watermark,        \
-                            nearly_full_watermark)
-#endif
-
-void qmgr_release_queue(unsigned int queue);
-
-
-static inline void qmgr_put_entry(unsigned int queue, u32 val)
-{
-       struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
-#if DEBUG_QMGR
-       BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
-
-       printk(KERN_DEBUG "Queue %s(%i) put %X\n",
-              qmgr_queue_descs[queue], queue, val);
-#endif
-       __raw_writel(val, &qmgr_regs->acc[queue][0]);
-}
-
-static inline u32 qmgr_get_entry(unsigned int queue)
-{
-       u32 val;
-       const struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
-       val = __raw_readl(&qmgr_regs->acc[queue][0]);
-#if DEBUG_QMGR
-       BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
-
-       printk(KERN_DEBUG "Queue %s(%i) get %X\n",
-              qmgr_queue_descs[queue], queue, val);
-#endif
-       return val;
-}
-
-static inline int __qmgr_get_stat1(unsigned int queue)
-{
-       const struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
-       return (__raw_readl(&qmgr_regs->stat1[queue >> 3])
-               >> ((queue & 7) << 2)) & 0xF;
-}
-
-static inline int __qmgr_get_stat2(unsigned int queue)
-{
-       const struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
-       BUG_ON(queue >= HALF_QUEUES);
-       return (__raw_readl(&qmgr_regs->stat2[queue >> 4])
-               >> ((queue & 0xF) << 1)) & 0x3;
-}
-
-/**
- * qmgr_stat_empty() - checks if a hardware queue is empty
- * @queue:     queue number
- *
- * Returns non-zero value if the queue is empty.
- */
-static inline int qmgr_stat_empty(unsigned int queue)
-{
-       BUG_ON(queue >= HALF_QUEUES);
-       return __qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY;
-}
-
-/**
- * qmgr_stat_below_low_watermark() - checks if a queue is below low watermark
- * @queue:     queue number
- *
- * Returns non-zero value if the queue is below low watermark.
- */
-static inline int qmgr_stat_below_low_watermark(unsigned int queue)
-{
-       const struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
-       if (queue >= HALF_QUEUES)
-               return (__raw_readl(&qmgr_regs->statne_h) >>
-                       (queue - HALF_QUEUES)) & 0x01;
-       return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY;
-}
-
-/**
- * qmgr_stat_above_high_watermark() - checks if a queue is above high watermark
- * @queue:     queue number
- *
- * Returns non-zero value if the queue is above high watermark
- */
-static inline int qmgr_stat_above_high_watermark(unsigned int queue)
-{
-       BUG_ON(queue >= HALF_QUEUES);
-       return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL;
-}
-
-/**
- * qmgr_stat_full() - checks if a hardware queue is full
- * @queue:     queue number
- *
- * Returns non-zero value if the queue is full.
- */
-static inline int qmgr_stat_full(unsigned int queue)
-{
-       const struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
-       if (queue >= HALF_QUEUES)
-               return (__raw_readl(&qmgr_regs->statf_h) >>
-                       (queue - HALF_QUEUES)) & 0x01;
-       return __qmgr_get_stat1(queue) & QUEUE_STAT1_FULL;
-}
-
-/**
- * qmgr_stat_underflow() - checks if a hardware queue experienced underflow
- * @queue:     queue number
- *
- * Returns non-zero value if the queue experienced underflow.
- */
-static inline int qmgr_stat_underflow(unsigned int queue)
-{
-       return __qmgr_get_stat2(queue) & QUEUE_STAT2_UNDERFLOW;
-}
-
-/**
- * qmgr_stat_overflow() - checks if a hardware queue experienced overflow
- * @queue:     queue number
- *
- * Returns non-zero value if the queue experienced overflow.
- */
-static inline int qmgr_stat_overflow(unsigned int queue)
-{
-       return __qmgr_get_stat2(queue) & QUEUE_STAT2_OVERFLOW;
-}
-
-#endif
diff --git a/arch/arm/mach-ixp4xx/irqs.h b/arch/arm/mach-ixp4xx/irqs.h
new file mode 100644 (file)
index 0000000..6b7f220
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * arch/arm/mach-ixp4xx/include/mach/irqs.h 
+ *
+ * IRQ definitions for IXP4XX based systems
+ *
+ * Copyright (C) 2002 Intel Corporation.
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _ARCH_IXP4XX_IRQS_H_
+#define _ARCH_IXP4XX_IRQS_H_
+
+#define IRQ_IXP4XX_BASE                16
+
+#define IRQ_IXP4XX_NPEA                (IRQ_IXP4XX_BASE + 0)
+#define IRQ_IXP4XX_NPEB                (IRQ_IXP4XX_BASE + 1)
+#define IRQ_IXP4XX_NPEC                (IRQ_IXP4XX_BASE + 2)
+#define IRQ_IXP4XX_QM1         (IRQ_IXP4XX_BASE + 3)
+#define IRQ_IXP4XX_QM2         (IRQ_IXP4XX_BASE + 4)
+#define IRQ_IXP4XX_TIMER1      (IRQ_IXP4XX_BASE + 5)
+#define IRQ_IXP4XX_GPIO0       (IRQ_IXP4XX_BASE + 6)
+#define IRQ_IXP4XX_GPIO1       (IRQ_IXP4XX_BASE + 7)
+#define IRQ_IXP4XX_PCI_INT     (IRQ_IXP4XX_BASE + 8)
+#define IRQ_IXP4XX_PCI_DMA1    (IRQ_IXP4XX_BASE + 9)
+#define IRQ_IXP4XX_PCI_DMA2    (IRQ_IXP4XX_BASE + 10)
+#define IRQ_IXP4XX_TIMER2      (IRQ_IXP4XX_BASE + 11)
+#define IRQ_IXP4XX_USB         (IRQ_IXP4XX_BASE + 12)
+#define IRQ_IXP4XX_UART2       (IRQ_IXP4XX_BASE + 13)
+#define IRQ_IXP4XX_TIMESTAMP   (IRQ_IXP4XX_BASE + 14)
+#define IRQ_IXP4XX_UART1       (IRQ_IXP4XX_BASE + 15)
+#define IRQ_IXP4XX_WDOG                (IRQ_IXP4XX_BASE + 16)
+#define IRQ_IXP4XX_AHB_PMU     (IRQ_IXP4XX_BASE + 17)
+#define IRQ_IXP4XX_XSCALE_PMU  (IRQ_IXP4XX_BASE + 18)
+#define IRQ_IXP4XX_GPIO2       (IRQ_IXP4XX_BASE + 19)
+#define IRQ_IXP4XX_GPIO3       (IRQ_IXP4XX_BASE + 20)
+#define IRQ_IXP4XX_GPIO4       (IRQ_IXP4XX_BASE + 21)
+#define IRQ_IXP4XX_GPIO5       (IRQ_IXP4XX_BASE + 22)
+#define IRQ_IXP4XX_GPIO6       (IRQ_IXP4XX_BASE + 23)
+#define IRQ_IXP4XX_GPIO7       (IRQ_IXP4XX_BASE + 24)
+#define IRQ_IXP4XX_GPIO8       (IRQ_IXP4XX_BASE + 25)
+#define IRQ_IXP4XX_GPIO9       (IRQ_IXP4XX_BASE + 26)
+#define IRQ_IXP4XX_GPIO10      (IRQ_IXP4XX_BASE + 27)
+#define IRQ_IXP4XX_GPIO11      (IRQ_IXP4XX_BASE + 28)
+#define IRQ_IXP4XX_GPIO12      (IRQ_IXP4XX_BASE + 29)
+#define IRQ_IXP4XX_SW_INT1     (IRQ_IXP4XX_BASE + 30)
+#define IRQ_IXP4XX_SW_INT2     (IRQ_IXP4XX_BASE + 31)
+#define IRQ_IXP4XX_USB_HOST    (IRQ_IXP4XX_BASE + 32)
+#define IRQ_IXP4XX_I2C         (IRQ_IXP4XX_BASE + 33)
+#define IRQ_IXP4XX_SSP         (IRQ_IXP4XX_BASE + 34)
+#define IRQ_IXP4XX_TSYNC       (IRQ_IXP4XX_BASE + 35)
+#define IRQ_IXP4XX_EAU_DONE    (IRQ_IXP4XX_BASE + 36)
+#define IRQ_IXP4XX_SHA_DONE    (IRQ_IXP4XX_BASE + 37)
+#define IRQ_IXP4XX_SWCP_PE     (IRQ_IXP4XX_BASE + 58)
+#define IRQ_IXP4XX_QM_PE       (IRQ_IXP4XX_BASE + 60)
+#define IRQ_IXP4XX_MCU_ECC     (IRQ_IXP4XX_BASE + 61)
+#define IRQ_IXP4XX_EXP_PE      (IRQ_IXP4XX_BASE + 62)
+
+#define _IXP4XX_GPIO_IRQ(n)    (IRQ_IXP4XX_GPIO ## n)
+#define IXP4XX_GPIO_IRQ(n)     _IXP4XX_GPIO_IRQ(n)
+
+#define        XSCALE_PMU_IRQ          (IRQ_IXP4XX_XSCALE_PMU)
+
+#endif
index 318424dd3c5095869469ca56f128799944d60552..c1340465b2eaebc951aa0648ae34c4259e80952a 100644 (file)
@@ -24,6 +24,8 @@
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 
+#include "irqs.h"
+
 #define MAX_DEV                4
 #define IRQ_LINES      4
 
index 57d7df79d8389b8373d1e0c24a3133f26ba70643..6f0f7ed18ea8b93e8164195da9496c028dac0cc2 100644 (file)
@@ -32,6 +32,8 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
+#include "irqs.h"
+
 #define IXDP425_SDA_PIN                7
 #define IXDP425_SCL_PIN                6
 
index 1f8717ba13dcf111211a64b3260a08e8e59d277d..ac0e9bc6eb4dbfdceb4031542c302324c937c87e 100644 (file)
@@ -23,6 +23,8 @@
 
 #include <asm/mach/pci.h>
 
+#include "irqs.h"
+
 void __init ixdpg425_pci_preinit(void)
 {
        irq_set_irq_type(IRQ_IXP4XX_GPIO6, IRQ_TYPE_LEVEL_LOW);
diff --git a/arch/arm/mach-ixp4xx/ixp4xx-of.c b/arch/arm/mach-ixp4xx/ixp4xx-of.c
new file mode 100644 (file)
index 0000000..7449b83
--- /dev/null
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IXP4xx Device Tree boot support
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/ixp4xx-regs.h>
+
+static struct map_desc ixp4xx_of_io_desc[] __initdata = {
+       /*
+        * This is needed for runtime system configuration checks,
+        * such as reading if hardware so-and-so is present. This
+        * could eventually be converted into a syscon once all boards
+        * are converted to device tree.
+        */
+       {
+               .virtual = IXP4XX_EXP_CFG_BASE_VIRT,
+               .pfn = __phys_to_pfn(IXP4XX_EXP_CFG_BASE_PHYS),
+               .length = SZ_4K,
+               .type = MT_DEVICE,
+       },
+#ifdef CONFIG_DEBUG_UART_8250
+       /* This is needed for LL-debug/earlyprintk/debug-macro.S */
+       {
+               .virtual = CONFIG_DEBUG_UART_VIRT,
+               .pfn = __phys_to_pfn(CONFIG_DEBUG_UART_PHYS),
+               .length = SZ_4K,
+               .type = MT_DEVICE,
+       },
+#endif
+};
+
+static void __init ixp4xx_of_map_io(void)
+{
+       iotable_init(ixp4xx_of_io_desc, ARRAY_SIZE(ixp4xx_of_io_desc));
+}
+
+/*
+ * We handle 4 differen SoC families. These compatible strings are enough
+ * to provide the core so that different boards can add their more detailed
+ * specifics.
+ */
+static const char *ixp4xx_of_board_compat[] = {
+       "intel,ixp42x",
+       "intel,ixp43x",
+       "intel,ixp45x",
+       "intel,ixp46x",
+       NULL,
+};
+
+DT_MACHINE_START(IXP4XX_DT, "IXP4xx (Device Tree)")
+       .map_io         = ixp4xx_of_map_io,
+       .dt_compat      = ixp4xx_of_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_npe.c b/arch/arm/mach-ixp4xx/ixp4xx_npe.c
deleted file mode 100644 (file)
index d4eb09a..0000000
+++ /dev/null
@@ -1,742 +0,0 @@
-/*
- * Intel IXP4xx Network Processor Engine driver for Linux
- *
- * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License
- * as published by the Free Software Foundation.
- *
- * The code is based on publicly available information:
- * - Intel IXP4xx Developer's Manual and other e-papers
- * - Intel IXP400 Access Library Software (BSD license)
- * - previous works by Christian Hohnstaedt <chohnstaedt@innominate.com>
- *   Thanks, Christian.
- */
-
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/firmware.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <mach/npe.h>
-
-#define DEBUG_MSG                      0
-#define DEBUG_FW                       0
-
-#define NPE_COUNT                      3
-#define MAX_RETRIES                    1000    /* microseconds */
-#define NPE_42X_DATA_SIZE              0x800   /* in dwords */
-#define NPE_46X_DATA_SIZE              0x1000
-#define NPE_A_42X_INSTR_SIZE           0x1000
-#define NPE_B_AND_C_42X_INSTR_SIZE     0x800
-#define NPE_46X_INSTR_SIZE             0x1000
-#define REGS_SIZE                      0x1000
-
-#define NPE_PHYS_REG                   32
-
-#define FW_MAGIC                       0xFEEDF00D
-#define FW_BLOCK_TYPE_INSTR            0x0
-#define FW_BLOCK_TYPE_DATA             0x1
-#define FW_BLOCK_TYPE_EOF              0xF
-
-/* NPE exec status (read) and command (write) */
-#define CMD_NPE_STEP                   0x01
-#define CMD_NPE_START                  0x02
-#define CMD_NPE_STOP                   0x03
-#define CMD_NPE_CLR_PIPE               0x04
-#define CMD_CLR_PROFILE_CNT            0x0C
-#define CMD_RD_INS_MEM                 0x10 /* instruction memory */
-#define CMD_WR_INS_MEM                 0x11
-#define CMD_RD_DATA_MEM                        0x12 /* data memory */
-#define CMD_WR_DATA_MEM                        0x13
-#define CMD_RD_ECS_REG                 0x14 /* exec access register */
-#define CMD_WR_ECS_REG                 0x15
-
-#define STAT_RUN                       0x80000000
-#define STAT_STOP                      0x40000000
-#define STAT_CLEAR                     0x20000000
-#define STAT_ECS_K                     0x00800000 /* pipeline clean */
-
-#define NPE_STEVT                      0x1B
-#define NPE_STARTPC                    0x1C
-#define NPE_REGMAP                     0x1E
-#define NPE_CINDEX                     0x1F
-
-#define INSTR_WR_REG_SHORT             0x0000C000
-#define INSTR_WR_REG_BYTE              0x00004000
-#define INSTR_RD_FIFO                  0x0F888220
-#define INSTR_RESET_MBOX               0x0FAC8210
-
-#define ECS_BG_CTXT_REG_0              0x00 /* Background Executing Context */
-#define ECS_BG_CTXT_REG_1              0x01 /*         Stack level */
-#define ECS_BG_CTXT_REG_2              0x02
-#define ECS_PRI_1_CTXT_REG_0           0x04 /* Priority 1 Executing Context */
-#define ECS_PRI_1_CTXT_REG_1           0x05 /*         Stack level */
-#define ECS_PRI_1_CTXT_REG_2           0x06
-#define ECS_PRI_2_CTXT_REG_0           0x08 /* Priority 2 Executing Context */
-#define ECS_PRI_2_CTXT_REG_1           0x09 /*         Stack level */
-#define ECS_PRI_2_CTXT_REG_2           0x0A
-#define ECS_DBG_CTXT_REG_0             0x0C /* Debug Executing Context */
-#define ECS_DBG_CTXT_REG_1             0x0D /*         Stack level */
-#define ECS_DBG_CTXT_REG_2             0x0E
-#define ECS_INSTRUCT_REG               0x11 /* NPE Instruction Register */
-
-#define ECS_REG_0_ACTIVE               0x80000000 /* all levels */
-#define ECS_REG_0_NEXTPC_MASK          0x1FFF0000 /* BG/PRI1/PRI2 levels */
-#define ECS_REG_0_LDUR_BITS            8
-#define ECS_REG_0_LDUR_MASK            0x00000700 /* all levels */
-#define ECS_REG_1_CCTXT_BITS           16
-#define ECS_REG_1_CCTXT_MASK           0x000F0000 /* all levels */
-#define ECS_REG_1_SELCTXT_BITS         0
-#define ECS_REG_1_SELCTXT_MASK         0x0000000F /* all levels */
-#define ECS_DBG_REG_2_IF               0x00100000 /* debug level */
-#define ECS_DBG_REG_2_IE               0x00080000 /* debug level */
-
-/* NPE watchpoint_fifo register bit */
-#define WFIFO_VALID                    0x80000000
-
-/* NPE messaging_status register bit definitions */
-#define MSGSTAT_OFNE   0x00010000 /* OutFifoNotEmpty */
-#define MSGSTAT_IFNF   0x00020000 /* InFifoNotFull */
-#define MSGSTAT_OFNF   0x00040000 /* OutFifoNotFull */
-#define MSGSTAT_IFNE   0x00080000 /* InFifoNotEmpty */
-#define MSGSTAT_MBINT  0x00100000 /* Mailbox interrupt */
-#define MSGSTAT_IFINT  0x00200000 /* InFifo interrupt */
-#define MSGSTAT_OFINT  0x00400000 /* OutFifo interrupt */
-#define MSGSTAT_WFINT  0x00800000 /* WatchFifo interrupt */
-
-/* NPE messaging_control register bit definitions */
-#define MSGCTL_OUT_FIFO                        0x00010000 /* enable output FIFO */
-#define MSGCTL_IN_FIFO                 0x00020000 /* enable input FIFO */
-#define MSGCTL_OUT_FIFO_WRITE          0x01000000 /* enable FIFO + WRITE */
-#define MSGCTL_IN_FIFO_WRITE           0x02000000
-
-/* NPE mailbox_status value for reset */
-#define RESET_MBOX_STAT                        0x0000F0F0
-
-#define NPE_A_FIRMWARE "NPE-A"
-#define NPE_B_FIRMWARE "NPE-B"
-#define NPE_C_FIRMWARE "NPE-C"
-
-const char *npe_names[] = { NPE_A_FIRMWARE, NPE_B_FIRMWARE, NPE_C_FIRMWARE };
-
-#define print_npe(pri, npe, fmt, ...)                                  \
-       printk(pri "%s: " fmt, npe_name(npe), ## __VA_ARGS__)
-
-#if DEBUG_MSG
-#define debug_msg(npe, fmt, ...)                                       \
-       print_npe(KERN_DEBUG, npe, fmt, ## __VA_ARGS__)
-#else
-#define debug_msg(npe, fmt, ...)
-#endif
-
-static struct {
-       u32 reg, val;
-} ecs_reset[] = {
-       { ECS_BG_CTXT_REG_0,    0xA0000000 },
-       { ECS_BG_CTXT_REG_1,    0x01000000 },
-       { ECS_BG_CTXT_REG_2,    0x00008000 },
-       { ECS_PRI_1_CTXT_REG_0, 0x20000080 },
-       { ECS_PRI_1_CTXT_REG_1, 0x01000000 },
-       { ECS_PRI_1_CTXT_REG_2, 0x00008000 },
-       { ECS_PRI_2_CTXT_REG_0, 0x20000080 },
-       { ECS_PRI_2_CTXT_REG_1, 0x01000000 },
-       { ECS_PRI_2_CTXT_REG_2, 0x00008000 },
-       { ECS_DBG_CTXT_REG_0,   0x20000000 },
-       { ECS_DBG_CTXT_REG_1,   0x00000000 },
-       { ECS_DBG_CTXT_REG_2,   0x001E0000 },
-       { ECS_INSTRUCT_REG,     0x1003C00F },
-};
-
-static struct npe npe_tab[NPE_COUNT] = {
-       {
-               .id     = 0,
-               .regs   = (struct npe_regs __iomem *)IXP4XX_NPEA_BASE_VIRT,
-               .regs_phys = IXP4XX_NPEA_BASE_PHYS,
-       }, {
-               .id     = 1,
-               .regs   = (struct npe_regs __iomem *)IXP4XX_NPEB_BASE_VIRT,
-               .regs_phys = IXP4XX_NPEB_BASE_PHYS,
-       }, {
-               .id     = 2,
-               .regs   = (struct npe_regs __iomem *)IXP4XX_NPEC_BASE_VIRT,
-               .regs_phys = IXP4XX_NPEC_BASE_PHYS,
-       }
-};
-
-int npe_running(struct npe *npe)
-{
-       return (__raw_readl(&npe->regs->exec_status_cmd) & STAT_RUN) != 0;
-}
-
-static void npe_cmd_write(struct npe *npe, u32 addr, int cmd, u32 data)
-{
-       __raw_writel(data, &npe->regs->exec_data);
-       __raw_writel(addr, &npe->regs->exec_addr);
-       __raw_writel(cmd, &npe->regs->exec_status_cmd);
-}
-
-static u32 npe_cmd_read(struct npe *npe, u32 addr, int cmd)
-{
-       __raw_writel(addr, &npe->regs->exec_addr);
-       __raw_writel(cmd, &npe->regs->exec_status_cmd);
-       /* Iintroduce extra read cycles after issuing read command to NPE
-          so that we read the register after the NPE has updated it.
-          This is to overcome race condition between XScale and NPE */
-       __raw_readl(&npe->regs->exec_data);
-       __raw_readl(&npe->regs->exec_data);
-       return __raw_readl(&npe->regs->exec_data);
-}
-
-static void npe_clear_active(struct npe *npe, u32 reg)
-{
-       u32 val = npe_cmd_read(npe, reg, CMD_RD_ECS_REG);
-       npe_cmd_write(npe, reg, CMD_WR_ECS_REG, val & ~ECS_REG_0_ACTIVE);
-}
-
-static void npe_start(struct npe *npe)
-{
-       /* ensure only Background Context Stack Level is active */
-       npe_clear_active(npe, ECS_PRI_1_CTXT_REG_0);
-       npe_clear_active(npe, ECS_PRI_2_CTXT_REG_0);
-       npe_clear_active(npe, ECS_DBG_CTXT_REG_0);
-
-       __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
-       __raw_writel(CMD_NPE_START, &npe->regs->exec_status_cmd);
-}
-
-static void npe_stop(struct npe *npe)
-{
-       __raw_writel(CMD_NPE_STOP, &npe->regs->exec_status_cmd);
-       __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); /*FIXME?*/
-}
-
-static int __must_check npe_debug_instr(struct npe *npe, u32 instr, u32 ctx,
-                                       u32 ldur)
-{
-       u32 wc;
-       int i;
-
-       /* set the Active bit, and the LDUR, in the debug level */
-       npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG,
-                     ECS_REG_0_ACTIVE | (ldur << ECS_REG_0_LDUR_BITS));
-
-       /* set CCTXT at ECS DEBUG L3 to specify in which context to execute
-          the instruction, and set SELCTXT at ECS DEBUG Level to specify
-          which context store to access.
-          Debug ECS Level Reg 1 has form 0x000n000n, where n = context number
-       */
-       npe_cmd_write(npe, ECS_DBG_CTXT_REG_1, CMD_WR_ECS_REG,
-                     (ctx << ECS_REG_1_CCTXT_BITS) |
-                     (ctx << ECS_REG_1_SELCTXT_BITS));
-
-       /* clear the pipeline */
-       __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
-
-       /* load NPE instruction into the instruction register */
-       npe_cmd_write(npe, ECS_INSTRUCT_REG, CMD_WR_ECS_REG, instr);
-
-       /* we need this value later to wait for completion of NPE execution
-          step */
-       wc = __raw_readl(&npe->regs->watch_count);
-
-       /* issue a Step One command via the Execution Control register */
-       __raw_writel(CMD_NPE_STEP, &npe->regs->exec_status_cmd);
-
-       /* Watch Count register increments when NPE completes an instruction */
-       for (i = 0; i < MAX_RETRIES; i++) {
-               if (wc != __raw_readl(&npe->regs->watch_count))
-                       return 0;
-               udelay(1);
-       }
-
-       print_npe(KERN_ERR, npe, "reset: npe_debug_instr(): timeout\n");
-       return -ETIMEDOUT;
-}
-
-static int __must_check npe_logical_reg_write8(struct npe *npe, u32 addr,
-                                              u8 val, u32 ctx)
-{
-       /* here we build the NPE assembler instruction: mov8 d0, #0 */
-       u32 instr = INSTR_WR_REG_BYTE | /* OpCode */
-               addr << 9 |             /* base Operand */
-               (val & 0x1F) << 4 |     /* lower 5 bits to immediate data */
-               (val & ~0x1F) << (18 - 5);/* higher 3 bits to CoProc instr. */
-       return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
-}
-
-static int __must_check npe_logical_reg_write16(struct npe *npe, u32 addr,
-                                               u16 val, u32 ctx)
-{
-       /* here we build the NPE assembler instruction: mov16 d0, #0 */
-       u32 instr = INSTR_WR_REG_SHORT | /* OpCode */
-               addr << 9 |             /* base Operand */
-               (val & 0x1F) << 4 |     /* lower 5 bits to immediate data */
-               (val & ~0x1F) << (18 - 5);/* higher 11 bits to CoProc instr. */
-       return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
-}
-
-static int __must_check npe_logical_reg_write32(struct npe *npe, u32 addr,
-                                               u32 val, u32 ctx)
-{
-       /* write in 16 bit steps first the high and then the low value */
-       if (npe_logical_reg_write16(npe, addr, val >> 16, ctx))
-               return -ETIMEDOUT;
-       return npe_logical_reg_write16(npe, addr + 2, val & 0xFFFF, ctx);
-}
-
-static int npe_reset(struct npe *npe)
-{
-       u32 val, ctl, exec_count, ctx_reg2;
-       int i;
-
-       ctl = (__raw_readl(&npe->regs->messaging_control) | 0x3F000000) &
-               0x3F3FFFFF;
-
-       /* disable parity interrupt */
-       __raw_writel(ctl & 0x3F00FFFF, &npe->regs->messaging_control);
-
-       /* pre exec - debug instruction */
-       /* turn off the halt bit by clearing Execution Count register. */
-       exec_count = __raw_readl(&npe->regs->exec_count);
-       __raw_writel(0, &npe->regs->exec_count);
-       /* ensure that IF and IE are on (temporarily), so that we don't end up
-          stepping forever */
-       ctx_reg2 = npe_cmd_read(npe, ECS_DBG_CTXT_REG_2, CMD_RD_ECS_REG);
-       npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2 |
-                     ECS_DBG_REG_2_IF | ECS_DBG_REG_2_IE);
-
-       /* clear the FIFOs */
-       while (__raw_readl(&npe->regs->watchpoint_fifo) & WFIFO_VALID)
-               ;
-       while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE)
-               /* read from the outFIFO until empty */
-               print_npe(KERN_DEBUG, npe, "npe_reset: read FIFO = 0x%X\n",
-                         __raw_readl(&npe->regs->in_out_fifo));
-
-       while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)
-               /* step execution of the NPE intruction to read inFIFO using
-                  the Debug Executing Context stack */
-               if (npe_debug_instr(npe, INSTR_RD_FIFO, 0, 0))
-                       return -ETIMEDOUT;
-
-       /* reset the mailbox reg from the XScale side */
-       __raw_writel(RESET_MBOX_STAT, &npe->regs->mailbox_status);
-       /* from NPE side */
-       if (npe_debug_instr(npe, INSTR_RESET_MBOX, 0, 0))
-               return -ETIMEDOUT;
-
-       /* Reset the physical registers in the NPE register file */
-       for (val = 0; val < NPE_PHYS_REG; val++) {
-               if (npe_logical_reg_write16(npe, NPE_REGMAP, val >> 1, 0))
-                       return -ETIMEDOUT;
-               /* address is either 0 or 4 */
-               if (npe_logical_reg_write32(npe, (val & 1) * 4, 0, 0))
-                       return -ETIMEDOUT;
-       }
-
-       /* Reset the context store = each context's Context Store registers */
-
-       /* Context 0 has no STARTPC. Instead, this value is used to set NextPC
-          for Background ECS, to set where NPE starts executing code */
-       val = npe_cmd_read(npe, ECS_BG_CTXT_REG_0, CMD_RD_ECS_REG);
-       val &= ~ECS_REG_0_NEXTPC_MASK;
-       val |= (0 /* NextPC */ << 16) & ECS_REG_0_NEXTPC_MASK;
-       npe_cmd_write(npe, ECS_BG_CTXT_REG_0, CMD_WR_ECS_REG, val);
-
-       for (i = 0; i < 16; i++) {
-               if (i) {        /* Context 0 has no STEVT nor STARTPC */
-                       /* STEVT = off, 0x80 */
-                       if (npe_logical_reg_write8(npe, NPE_STEVT, 0x80, i))
-                               return -ETIMEDOUT;
-                       if (npe_logical_reg_write16(npe, NPE_STARTPC, 0, i))
-                               return -ETIMEDOUT;
-               }
-               /* REGMAP = d0->p0, d8->p2, d16->p4 */
-               if (npe_logical_reg_write16(npe, NPE_REGMAP, 0x820, i))
-                       return -ETIMEDOUT;
-               if (npe_logical_reg_write8(npe, NPE_CINDEX, 0, i))
-                       return -ETIMEDOUT;
-       }
-
-       /* post exec */
-       /* clear active bit in debug level */
-       npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, 0);
-       /* clear the pipeline */
-       __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
-       /* restore previous values */
-       __raw_writel(exec_count, &npe->regs->exec_count);
-       npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2);
-
-       /* write reset values to Execution Context Stack registers */
-       for (val = 0; val < ARRAY_SIZE(ecs_reset); val++)
-               npe_cmd_write(npe, ecs_reset[val].reg, CMD_WR_ECS_REG,
-                             ecs_reset[val].val);
-
-       /* clear the profile counter */
-       __raw_writel(CMD_CLR_PROFILE_CNT, &npe->regs->exec_status_cmd);
-
-       __raw_writel(0, &npe->regs->exec_count);
-       __raw_writel(0, &npe->regs->action_points[0]);
-       __raw_writel(0, &npe->regs->action_points[1]);
-       __raw_writel(0, &npe->regs->action_points[2]);
-       __raw_writel(0, &npe->regs->action_points[3]);
-       __raw_writel(0, &npe->regs->watch_count);
-
-       val = ixp4xx_read_feature_bits();
-       /* reset the NPE */
-       ixp4xx_write_feature_bits(val &
-                                 ~(IXP4XX_FEATURE_RESET_NPEA << npe->id));
-       /* deassert reset */
-       ixp4xx_write_feature_bits(val |
-                                 (IXP4XX_FEATURE_RESET_NPEA << npe->id));
-       for (i = 0; i < MAX_RETRIES; i++) {
-               if (ixp4xx_read_feature_bits() &
-                   (IXP4XX_FEATURE_RESET_NPEA << npe->id))
-                       break;  /* NPE is back alive */
-               udelay(1);
-       }
-       if (i == MAX_RETRIES)
-               return -ETIMEDOUT;
-
-       npe_stop(npe);
-
-       /* restore NPE configuration bus Control Register - parity settings */
-       __raw_writel(ctl, &npe->regs->messaging_control);
-       return 0;
-}
-
-
-int npe_send_message(struct npe *npe, const void *msg, const char *what)
-{
-       const u32 *send = msg;
-       int cycles = 0;
-
-       debug_msg(npe, "Trying to send message %s [%08X:%08X]\n",
-                 what, send[0], send[1]);
-
-       if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) {
-               debug_msg(npe, "NPE input FIFO not empty\n");
-               return -EIO;
-       }
-
-       __raw_writel(send[0], &npe->regs->in_out_fifo);
-
-       if (!(__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNF)) {
-               debug_msg(npe, "NPE input FIFO full\n");
-               return -EIO;
-       }
-
-       __raw_writel(send[1], &npe->regs->in_out_fifo);
-
-       while ((cycles < MAX_RETRIES) &&
-              (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)) {
-               udelay(1);
-               cycles++;
-       }
-
-       if (cycles == MAX_RETRIES) {
-               debug_msg(npe, "Timeout sending message\n");
-               return -ETIMEDOUT;
-       }
-
-#if DEBUG_MSG > 1
-       debug_msg(npe, "Sending a message took %i cycles\n", cycles);
-#endif
-       return 0;
-}
-
-int npe_recv_message(struct npe *npe, void *msg, const char *what)
-{
-       u32 *recv = msg;
-       int cycles = 0, cnt = 0;
-
-       debug_msg(npe, "Trying to receive message %s\n", what);
-
-       while (cycles < MAX_RETRIES) {
-               if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) {
-                       recv[cnt++] = __raw_readl(&npe->regs->in_out_fifo);
-                       if (cnt == 2)
-                               break;
-               } else {
-                       udelay(1);
-                       cycles++;
-               }
-       }
-
-       switch(cnt) {
-       case 1:
-               debug_msg(npe, "Received [%08X]\n", recv[0]);
-               break;
-       case 2:
-               debug_msg(npe, "Received [%08X:%08X]\n", recv[0], recv[1]);
-               break;
-       }
-
-       if (cycles == MAX_RETRIES) {
-               debug_msg(npe, "Timeout waiting for message\n");
-               return -ETIMEDOUT;
-       }
-
-#if DEBUG_MSG > 1
-       debug_msg(npe, "Receiving a message took %i cycles\n", cycles);
-#endif
-       return 0;
-}
-
-int npe_send_recv_message(struct npe *npe, void *msg, const char *what)
-{
-       int result;
-       u32 *send = msg, recv[2];
-
-       if ((result = npe_send_message(npe, msg, what)) != 0)
-               return result;
-       if ((result = npe_recv_message(npe, recv, what)) != 0)
-               return result;
-
-       if ((recv[0] != send[0]) || (recv[1] != send[1])) {
-               debug_msg(npe, "Message %s: unexpected message received\n",
-                         what);
-               return -EIO;
-       }
-       return 0;
-}
-
-
-int npe_load_firmware(struct npe *npe, const char *name, struct device *dev)
-{
-       const struct firmware *fw_entry;
-
-       struct dl_block {
-               u32 type;
-               u32 offset;
-       } *blk;
-
-       struct dl_image {
-               u32 magic;
-               u32 id;
-               u32 size;
-               union {
-                       u32 data[0];
-                       struct dl_block blocks[0];
-               };
-       } *image;
-
-       struct dl_codeblock {
-               u32 npe_addr;
-               u32 size;
-               u32 data[0];
-       } *cb;
-
-       int i, j, err, data_size, instr_size, blocks, table_end;
-       u32 cmd;
-
-       if ((err = request_firmware(&fw_entry, name, dev)) != 0)
-               return err;
-
-       err = -EINVAL;
-       if (fw_entry->size < sizeof(struct dl_image)) {
-               print_npe(KERN_ERR, npe, "incomplete firmware file\n");
-               goto err;
-       }
-       image = (struct dl_image*)fw_entry->data;
-
-#if DEBUG_FW
-       print_npe(KERN_DEBUG, npe, "firmware: %08X %08X %08X (0x%X bytes)\n",
-                 image->magic, image->id, image->size, image->size * 4);
-#endif
-
-       if (image->magic == swab32(FW_MAGIC)) { /* swapped file */
-               image->id = swab32(image->id);
-               image->size = swab32(image->size);
-       } else if (image->magic != FW_MAGIC) {
-               print_npe(KERN_ERR, npe, "bad firmware file magic: 0x%X\n",
-                         image->magic);
-               goto err;
-       }
-       if ((image->size * 4 + sizeof(struct dl_image)) != fw_entry->size) {
-               print_npe(KERN_ERR, npe,
-                         "inconsistent size of firmware file\n");
-               goto err;
-       }
-       if (((image->id >> 24) & 0xF /* NPE ID */) != npe->id) {
-               print_npe(KERN_ERR, npe, "firmware file NPE ID mismatch\n");
-               goto err;
-       }
-       if (image->magic == swab32(FW_MAGIC))
-               for (i = 0; i < image->size; i++)
-                       image->data[i] = swab32(image->data[i]);
-
-       if (cpu_is_ixp42x() && ((image->id >> 28) & 0xF /* device ID */)) {
-               print_npe(KERN_INFO, npe, "IXP43x/IXP46x firmware ignored on "
-                         "IXP42x\n");
-               goto err;
-       }
-
-       if (npe_running(npe)) {
-               print_npe(KERN_INFO, npe, "unable to load firmware, NPE is "
-                         "already running\n");
-               err = -EBUSY;
-               goto err;
-       }
-#if 0
-       npe_stop(npe);
-       npe_reset(npe);
-#endif
-
-       print_npe(KERN_INFO, npe, "firmware functionality 0x%X, "
-                 "revision 0x%X:%X\n", (image->id >> 16) & 0xFF,
-                 (image->id >> 8) & 0xFF, image->id & 0xFF);
-
-       if (cpu_is_ixp42x()) {
-               if (!npe->id)
-                       instr_size = NPE_A_42X_INSTR_SIZE;
-               else
-                       instr_size = NPE_B_AND_C_42X_INSTR_SIZE;
-               data_size = NPE_42X_DATA_SIZE;
-       } else {
-               instr_size = NPE_46X_INSTR_SIZE;
-               data_size = NPE_46X_DATA_SIZE;
-       }
-
-       for (blocks = 0; blocks * sizeof(struct dl_block) / 4 < image->size;
-            blocks++)
-               if (image->blocks[blocks].type == FW_BLOCK_TYPE_EOF)
-                       break;
-       if (blocks * sizeof(struct dl_block) / 4 >= image->size) {
-               print_npe(KERN_INFO, npe, "firmware EOF block marker not "
-                         "found\n");
-               goto err;
-       }
-
-#if DEBUG_FW
-       print_npe(KERN_DEBUG, npe, "%i firmware blocks found\n", blocks);
-#endif
-
-       table_end = blocks * sizeof(struct dl_block) / 4 + 1 /* EOF marker */;
-       for (i = 0, blk = image->blocks; i < blocks; i++, blk++) {
-               if (blk->offset > image->size - sizeof(struct dl_codeblock) / 4
-                   || blk->offset < table_end) {
-                       print_npe(KERN_INFO, npe, "invalid offset 0x%X of "
-                                 "firmware block #%i\n", blk->offset, i);
-                       goto err;
-               }
-
-               cb = (struct dl_codeblock*)&image->data[blk->offset];
-               if (blk->type == FW_BLOCK_TYPE_INSTR) {
-                       if (cb->npe_addr + cb->size > instr_size)
-                               goto too_big;
-                       cmd = CMD_WR_INS_MEM;
-               } else if (blk->type == FW_BLOCK_TYPE_DATA) {
-                       if (cb->npe_addr + cb->size > data_size)
-                               goto too_big;
-                       cmd = CMD_WR_DATA_MEM;
-               } else {
-                       print_npe(KERN_INFO, npe, "invalid firmware block #%i "
-                                 "type 0x%X\n", i, blk->type);
-                       goto err;
-               }
-               if (blk->offset + sizeof(*cb) / 4 + cb->size > image->size) {
-                       print_npe(KERN_INFO, npe, "firmware block #%i doesn't "
-                                 "fit in firmware image: type %c, start 0x%X,"
-                                 " length 0x%X\n", i,
-                                 blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
-                                 cb->npe_addr, cb->size);
-                       goto err;
-               }
-
-               for (j = 0; j < cb->size; j++)
-                       npe_cmd_write(npe, cb->npe_addr + j, cmd, cb->data[j]);
-       }
-
-       npe_start(npe);
-       if (!npe_running(npe))
-               print_npe(KERN_ERR, npe, "unable to start\n");
-       release_firmware(fw_entry);
-       return 0;
-
-too_big:
-       print_npe(KERN_INFO, npe, "firmware block #%i doesn't fit in NPE "
-                 "memory: type %c, start 0x%X, length 0x%X\n", i,
-                 blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
-                 cb->npe_addr, cb->size);
-err:
-       release_firmware(fw_entry);
-       return err;
-}
-
-
-struct npe *npe_request(unsigned id)
-{
-       if (id < NPE_COUNT)
-               if (npe_tab[id].valid)
-                       if (try_module_get(THIS_MODULE))
-                               return &npe_tab[id];
-       return NULL;
-}
-
-void npe_release(struct npe *npe)
-{
-       module_put(THIS_MODULE);
-}
-
-
-static int __init npe_init_module(void)
-{
-
-       int i, found = 0;
-
-       for (i = 0; i < NPE_COUNT; i++) {
-               struct npe *npe = &npe_tab[i];
-               if (!(ixp4xx_read_feature_bits() &
-                     (IXP4XX_FEATURE_RESET_NPEA << i)))
-                       continue; /* NPE already disabled or not present */
-               if (!(npe->mem_res = request_mem_region(npe->regs_phys,
-                                                       REGS_SIZE,
-                                                       npe_name(npe)))) {
-                       print_npe(KERN_ERR, npe,
-                                 "failed to request memory region\n");
-                       continue;
-               }
-
-               if (npe_reset(npe))
-                       continue;
-               npe->valid = 1;
-               found++;
-       }
-
-       if (!found)
-               return -ENODEV;
-       return 0;
-}
-
-static void __exit npe_cleanup_module(void)
-{
-       int i;
-
-       for (i = 0; i < NPE_COUNT; i++)
-               if (npe_tab[i].mem_res) {
-                       npe_reset(&npe_tab[i]);
-                       release_resource(npe_tab[i].mem_res);
-               }
-}
-
-module_init(npe_init_module);
-module_exit(npe_cleanup_module);
-
-MODULE_AUTHOR("Krzysztof Halasa");
-MODULE_LICENSE("GPL v2");
-MODULE_FIRMWARE(NPE_A_FIRMWARE);
-MODULE_FIRMWARE(NPE_B_FIRMWARE);
-MODULE_FIRMWARE(NPE_C_FIRMWARE);
-
-EXPORT_SYMBOL(npe_names);
-EXPORT_SYMBOL(npe_running);
-EXPORT_SYMBOL(npe_request);
-EXPORT_SYMBOL(npe_release);
-EXPORT_SYMBOL(npe_load_firmware);
-EXPORT_SYMBOL(npe_send_message);
-EXPORT_SYMBOL(npe_recv_message);
-EXPORT_SYMBOL(npe_send_recv_message);
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
deleted file mode 100644 (file)
index 9d1b6b7..0000000
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Intel IXP4xx Queue Manager driver for Linux
- *
- * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License
- * as published by the Free Software Foundation.
- */
-
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <mach/qmgr.h>
-
-static struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
-static struct resource *mem_res;
-static spinlock_t qmgr_lock;
-static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
-static void (*irq_handlers[QUEUES])(void *pdev);
-static void *irq_pdevs[QUEUES];
-
-#if DEBUG_QMGR
-char qmgr_queue_descs[QUEUES][32];
-#endif
-
-void qmgr_set_irq(unsigned int queue, int src,
-                 void (*handler)(void *pdev), void *pdev)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&qmgr_lock, flags);
-       if (queue < HALF_QUEUES) {
-               u32 __iomem *reg;
-               int bit;
-               BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL);
-               reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */
-               bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
-               __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit),
-                            reg);
-       } else
-               /* IRQ source for queues 32-63 is fixed */
-               BUG_ON(src != QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY);
-
-       irq_handlers[queue] = handler;
-       irq_pdevs[queue] = pdev;
-       spin_unlock_irqrestore(&qmgr_lock, flags);
-}
-
-
-static irqreturn_t qmgr_irq1_a0(int irq, void *pdev)
-{
-       int i, ret = 0;
-       u32 en_bitmap, src, stat;
-
-       /* ACK - it may clear any bits so don't rely on it */
-       __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]);
-
-       en_bitmap = qmgr_regs->irqen[0];
-       while (en_bitmap) {
-               i = __fls(en_bitmap); /* number of the last "low" queue */
-               en_bitmap &= ~BIT(i);
-               src = qmgr_regs->irqsrc[i >> 3];
-               stat = qmgr_regs->stat1[i >> 3];
-               if (src & 4) /* the IRQ condition is inverted */
-                       stat = ~stat;
-               if (stat & BIT(src & 3)) {
-                       irq_handlers[i](irq_pdevs[i]);
-                       ret = IRQ_HANDLED;
-               }
-       }
-       return ret;
-}
-
-
-static irqreturn_t qmgr_irq2_a0(int irq, void *pdev)
-{
-       int i, ret = 0;
-       u32 req_bitmap;
-
-       /* ACK - it may clear any bits so don't rely on it */
-       __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[1]);
-
-       req_bitmap = qmgr_regs->irqen[1] & qmgr_regs->statne_h;
-       while (req_bitmap) {
-               i = __fls(req_bitmap); /* number of the last "high" queue */
-               req_bitmap &= ~BIT(i);
-               irq_handlers[HALF_QUEUES + i](irq_pdevs[HALF_QUEUES + i]);
-               ret = IRQ_HANDLED;
-       }
-       return ret;
-}
-
-
-static irqreturn_t qmgr_irq(int irq, void *pdev)
-{
-       int i, half = (irq == IRQ_IXP4XX_QM1 ? 0 : 1);
-       u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[half]);
-
-       if (!req_bitmap)
-               return 0;
-       __raw_writel(req_bitmap, &qmgr_regs->irqstat[half]); /* ACK */
-
-       while (req_bitmap) {
-               i = __fls(req_bitmap); /* number of the last queue */
-               req_bitmap &= ~BIT(i);
-               i += half * HALF_QUEUES;
-               irq_handlers[i](irq_pdevs[i]);
-       }
-       return IRQ_HANDLED;
-}
-
-
-void qmgr_enable_irq(unsigned int queue)
-{
-       unsigned long flags;
-       int half = queue / 32;
-       u32 mask = 1 << (queue & (HALF_QUEUES - 1));
-
-       spin_lock_irqsave(&qmgr_lock, flags);
-       __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) | mask,
-                    &qmgr_regs->irqen[half]);
-       spin_unlock_irqrestore(&qmgr_lock, flags);
-}
-
-void qmgr_disable_irq(unsigned int queue)
-{
-       unsigned long flags;
-       int half = queue / 32;
-       u32 mask = 1 << (queue & (HALF_QUEUES - 1));
-
-       spin_lock_irqsave(&qmgr_lock, flags);
-       __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) & ~mask,
-                    &qmgr_regs->irqen[half]);
-       __raw_writel(mask, &qmgr_regs->irqstat[half]); /* clear */
-       spin_unlock_irqrestore(&qmgr_lock, flags);
-}
-
-static inline void shift_mask(u32 *mask)
-{
-       mask[3] = mask[3] << 1 | mask[2] >> 31;
-       mask[2] = mask[2] << 1 | mask[1] >> 31;
-       mask[1] = mask[1] << 1 | mask[0] >> 31;
-       mask[0] <<= 1;
-}
-
-#if DEBUG_QMGR
-int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
-                      unsigned int nearly_empty_watermark,
-                      unsigned int nearly_full_watermark,
-                      const char *desc_format, const char* name)
-#else
-int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
-                        unsigned int nearly_empty_watermark,
-                        unsigned int nearly_full_watermark)
-#endif
-{
-       u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
-       int err;
-
-       BUG_ON(queue >= QUEUES);
-
-       if ((nearly_empty_watermark | nearly_full_watermark) & ~7)
-               return -EINVAL;
-
-       switch (len) {
-       case  16:
-               cfg = 0 << 24;
-               mask[0] = 0x1;
-               break;
-       case  32:
-               cfg = 1 << 24;
-               mask[0] = 0x3;
-               break;
-       case  64:
-               cfg = 2 << 24;
-               mask[0] = 0xF;
-               break;
-       case 128:
-               cfg = 3 << 24;
-               mask[0] = 0xFF;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       cfg |= nearly_empty_watermark << 26;
-       cfg |= nearly_full_watermark << 29;
-       len /= 16;              /* in 16-dwords: 1, 2, 4 or 8 */
-       mask[1] = mask[2] = mask[3] = 0;
-
-       if (!try_module_get(THIS_MODULE))
-               return -ENODEV;
-
-       spin_lock_irq(&qmgr_lock);
-       if (__raw_readl(&qmgr_regs->sram[queue])) {
-               err = -EBUSY;
-               goto err;
-       }
-
-       while (1) {
-               if (!(used_sram_bitmap[0] & mask[0]) &&
-                   !(used_sram_bitmap[1] & mask[1]) &&
-                   !(used_sram_bitmap[2] & mask[2]) &&
-                   !(used_sram_bitmap[3] & mask[3]))
-                       break; /* found free space */
-
-               addr++;
-               shift_mask(mask);
-               if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) {
-                       printk(KERN_ERR "qmgr: no free SRAM space for"
-                              " queue %i\n", queue);
-                       err = -ENOMEM;
-                       goto err;
-               }
-       }
-
-       used_sram_bitmap[0] |= mask[0];
-       used_sram_bitmap[1] |= mask[1];
-       used_sram_bitmap[2] |= mask[2];
-       used_sram_bitmap[3] |= mask[3];
-       __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
-#if DEBUG_QMGR
-       snprintf(qmgr_queue_descs[queue], sizeof(qmgr_queue_descs[0]),
-                desc_format, name);
-       printk(KERN_DEBUG "qmgr: requested queue %s(%i) addr = 0x%02X\n",
-              qmgr_queue_descs[queue], queue, addr);
-#endif
-       spin_unlock_irq(&qmgr_lock);
-       return 0;
-
-err:
-       spin_unlock_irq(&qmgr_lock);
-       module_put(THIS_MODULE);
-       return err;
-}
-
-void qmgr_release_queue(unsigned int queue)
-{
-       u32 cfg, addr, mask[4];
-
-       BUG_ON(queue >= QUEUES); /* not in valid range */
-
-       spin_lock_irq(&qmgr_lock);
-       cfg = __raw_readl(&qmgr_regs->sram[queue]);
-       addr = (cfg >> 14) & 0xFF;
-
-       BUG_ON(!addr);          /* not requested */
-
-       switch ((cfg >> 24) & 3) {
-       case 0: mask[0] = 0x1; break;
-       case 1: mask[0] = 0x3; break;
-       case 2: mask[0] = 0xF; break;
-       case 3: mask[0] = 0xFF; break;
-       }
-
-       mask[1] = mask[2] = mask[3] = 0;
-
-       while (addr--)
-               shift_mask(mask);
-
-#if DEBUG_QMGR
-       printk(KERN_DEBUG "qmgr: releasing queue %s(%i)\n",
-              qmgr_queue_descs[queue], queue);
-       qmgr_queue_descs[queue][0] = '\x0';
-#endif
-
-       while ((addr = qmgr_get_entry(queue)))
-               printk(KERN_ERR "qmgr: released queue %i not empty: 0x%08X\n",
-                      queue, addr);
-
-       __raw_writel(0, &qmgr_regs->sram[queue]);
-
-       used_sram_bitmap[0] &= ~mask[0];
-       used_sram_bitmap[1] &= ~mask[1];
-       used_sram_bitmap[2] &= ~mask[2];
-       used_sram_bitmap[3] &= ~mask[3];
-       irq_handlers[queue] = NULL; /* catch IRQ bugs */
-       spin_unlock_irq(&qmgr_lock);
-
-       module_put(THIS_MODULE);
-}
-
-static int qmgr_init(void)
-{
-       int i, err;
-       irq_handler_t handler1, handler2;
-
-       mem_res = request_mem_region(IXP4XX_QMGR_BASE_PHYS,
-                                    IXP4XX_QMGR_REGION_SIZE,
-                                    "IXP4xx Queue Manager");
-       if (mem_res == NULL)
-               return -EBUSY;
-
-       /* reset qmgr registers */
-       for (i = 0; i < 4; i++) {
-               __raw_writel(0x33333333, &qmgr_regs->stat1[i]);
-               __raw_writel(0, &qmgr_regs->irqsrc[i]);
-       }
-       for (i = 0; i < 2; i++) {
-               __raw_writel(0, &qmgr_regs->stat2[i]);
-               __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */
-               __raw_writel(0, &qmgr_regs->irqen[i]);
-       }
-
-       __raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h);
-       __raw_writel(0, &qmgr_regs->statf_h);
-
-       for (i = 0; i < QUEUES; i++)
-               __raw_writel(0, &qmgr_regs->sram[i]);
-
-       if (cpu_is_ixp42x_rev_a0()) {
-               handler1 = qmgr_irq1_a0;
-               handler2 = qmgr_irq2_a0;
-       } else
-               handler1 = handler2 = qmgr_irq;
-
-       err = request_irq(IRQ_IXP4XX_QM1, handler1, 0, "IXP4xx Queue Manager",
-                         NULL);
-       if (err) {
-               printk(KERN_ERR "qmgr: failed to request IRQ%i (%i)\n",
-                      IRQ_IXP4XX_QM1, err);
-               goto error_irq;
-       }
-
-       err = request_irq(IRQ_IXP4XX_QM2, handler2, 0, "IXP4xx Queue Manager",
-                         NULL);
-       if (err) {
-               printk(KERN_ERR "qmgr: failed to request IRQ%i (%i)\n",
-                      IRQ_IXP4XX_QM2, err);
-               goto error_irq2;
-       }
-
-       used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
-       spin_lock_init(&qmgr_lock);
-
-       printk(KERN_INFO "IXP4xx Queue Manager initialized.\n");
-       return 0;
-
-error_irq2:
-       free_irq(IRQ_IXP4XX_QM1, NULL);
-error_irq:
-       release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
-       return err;
-}
-
-static void qmgr_remove(void)
-{
-       free_irq(IRQ_IXP4XX_QM1, NULL);
-       free_irq(IRQ_IXP4XX_QM2, NULL);
-       synchronize_irq(IRQ_IXP4XX_QM1);
-       synchronize_irq(IRQ_IXP4XX_QM2);
-       release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
-}
-
-module_init(qmgr_init);
-module_exit(qmgr_remove);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Krzysztof Halasa");
-
-EXPORT_SYMBOL(qmgr_set_irq);
-EXPORT_SYMBOL(qmgr_enable_irq);
-EXPORT_SYMBOL(qmgr_disable_irq);
-#if DEBUG_QMGR
-EXPORT_SYMBOL(qmgr_queue_descs);
-EXPORT_SYMBOL(qmgr_request_queue);
-#else
-EXPORT_SYMBOL(__qmgr_request_queue);
-#endif
-EXPORT_SYMBOL(qmgr_release_queue);
index 8f0eba0a6800ab1d2122b076667f457c00c66d2e..925ef805f9667c6c0ad4cffd05794a63a7176e5e 100644 (file)
@@ -21,6 +21,8 @@
 #include <asm/mach/pci.h>
 #include <asm/mach-types.h>
 
+#include "irqs.h"
+
 #define MAX_DEV                3
 #define IRQ_LINES      3
 
index 4138d6aa4c52e6f4ab61a31af908eecdceb1e0ce..c142cfa8c5d69278ecebb1551d3d061d5082e07a 100644 (file)
@@ -34,6 +34,8 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
+#include "irqs.h"
+
 #define NAS100D_SDA_PIN                5
 #define NAS100D_SCL_PIN                6
 
@@ -279,9 +281,6 @@ static void __init nas100d_init(void)
 
        ixp4xx_sys_init();
 
-       /* gpio 14 and 15 are _not_ clocks */
-       *IXP4XX_GPIO_GPCLKR = 0;
-
        nas100d_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
        nas100d_flash_resource.end =
                IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
index 032defe111aa99d1b274649b3d4cb8d10573fe49..d69ee4066d20cf83f737979a0871a6663cba93e5 100644 (file)
@@ -21,6 +21,8 @@
 #include <asm/mach/pci.h>
 #include <asm/mach-types.h>
 
+#include "irqs.h"
+
 #define MAX_DEV                3
 #define IRQ_LINES      3
 
index 341b263482ef98a7045d4ea31a1a9ddc2ab890d6..ee1877fcfafea40671eb344d61c75452740f1ee9 100644 (file)
@@ -32,6 +32,8 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/time.h>
 
+#include "irqs.h"
+
 #define NSLU2_SDA_PIN          7
 #define NSLU2_SCL_PIN          6
 
@@ -125,10 +127,18 @@ static struct platform_device nslu2_i2c_gpio = {
        },
 };
 
+static struct resource nslu2_beeper_resources[] = {
+       {
+               .start  = IRQ_IXP4XX_TIMER2,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
 static struct platform_device nslu2_beeper = {
        .name                   = "ixp4xx-beeper",
        .id                     = NSLU2_GPIO_BUZZ,
-       .num_resources          = 0,
+       .resource               = nslu2_beeper_resources,
+       .num_resources          = ARRAY_SIZE(nslu2_beeper_resources),
 };
 
 static struct resource nslu2_uart_resources[] = {
index c92e5b82af3686c47fab014cb13d9c6b01da7f0a..cf83f7e24179051f74a128e42cf3d917feb3ff4b 100644 (file)
@@ -27,6 +27,8 @@
 
 #include <asm/mach/pci.h>
 
+#include "irqs.h"
+
 void __init wg302v2_pci_preinit(void)
 {
        irq_set_irq_type(IRQ_IXP4XX_GPIO8, IRQ_TYPE_LEVEL_LOW);
index 90b3c604e8b6108d1c8882e3bef0567c18cb8576..8711e299229b2350abc0cdfae51a9b9f0b3e8f84 100644 (file)
@@ -29,6 +29,8 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
+#include "irqs.h"
+
 static struct flash_platform_data wg302v2_flash_data = {
        .map_name       = "cfi_probe",
        .width          = 2,
index 959c748ee8bbe27b179c237a2445aedf8288f20d..877629b3d944e0b91a2f7e1629b91df1c890795e 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 /*
  * Clocks are derived from MCLK, which is 25MHz
index b3be60a8e467cae44185f786a113718d5cd77115..66701bf432488bede04a1b706c6975fddc9425e2 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Platform support for LPC32xx SoC
  *
@@ -5,44 +6,14 @@
  *
  * Copyright (C) 2012 Roland Stigge <stigge@antcom.de>
  * Copyright (C) 2010 NXP Semiconductors
- *
- * 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.
  */
 
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/clcd.h>
 #include <linux/amba/pl08x.h>
-#include <linux/amba/mmci.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/clk.h>
-#include <linux/mtd/lpc32xx_slc.h>
 #include <linux/mtd/lpc32xx_mlc.h>
+#include <linux/mtd/lpc32xx_slc.h>
+#include <linux/of_platform.h>
 
-#include <asm/setup.h>
-#include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-
-#include <mach/hardware.h>
-#include <mach/platform.h>
-#include <mach/board.h>
 #include "common.h"
 
 static struct pl08x_channel_data pl08x_slave_channels[] = {
@@ -90,8 +61,6 @@ static struct lpc32xx_mlc_platform_data lpc32xx_mlc_data = {
 };
 
 static const struct of_dev_auxdata lpc32xx_auxdata_lookup[] __initconst = {
-       OF_DEV_AUXDATA("arm,pl022", 0x20084000, "dev:ssp0", NULL),
-       OF_DEV_AUXDATA("arm,pl022", 0x2008C000, "dev:ssp1", NULL),
        OF_DEV_AUXDATA("arm,pl080", 0x31000000, "pl08xdmac", &pl08x_pd),
        OF_DEV_AUXDATA("nxp,lpc3220-slc", 0x20020000, "20020000.flash",
                       &lpc32xx_slc_data),
@@ -104,11 +73,6 @@ static void __init lpc3250_machine_init(void)
 {
        lpc32xx_serial_init();
 
-       /* Test clock needed for UDA1380 initial init */
-       __raw_writel(LPC32XX_CLKPWR_TESTCLK2_SEL_MOSC |
-               LPC32XX_CLKPWR_TESTCLK_TESTCLK2_EN,
-               LPC32XX_CLKPWR_TEST_CLK_SEL);
-
        of_platform_default_populate(NULL, lpc32xx_auxdata_lookup, NULL);
 }
 
index b6a81ba1ce321ac91cd13a403bb980c74ec97511..5a9c016b3c6cca79ec9f46dca05e2e0c648f26cd 100644 (file)
@@ -15,6 +15,7 @@
  * GNU General Public License for more details.
  */
 #include <linux/init.h>
+#include <linux/io.h>
 #include <asm/mach/arch.h>
 #include <linux/of.h>
 #include <linux/clk-provider.h>
index f72e1e9f5fc55b87e14cc7f7a9609317e1f7d274..dd762d1b083fd0f1ded564c2a278f03af169ae02 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 #include <linux/ata_platform.h>
index 5875a5098d35ff43211c8a54730998fcc92d1119..e7c8ac7d83e3c1a62afc021c2575c04931653179 100644 (file)
@@ -36,7 +36,7 @@
 #ifndef __ASM_ARCH_OMAP_HARDWARE_H
 #define __ASM_ARCH_OMAP_HARDWARE_H
 
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #ifndef __ASSEMBLER__
 #include <asm/types.h>
 #include <mach/soc.h>
index 129455e822e42564fbeefffabe2d3dbb5eed3102..6316da3623b3bc8bc9bb2e69dcf1bc091f02600c 100644 (file)
@@ -336,6 +336,15 @@ static inline void omap5_secondary_hyp_startup(void)
 }
 #endif
 
+#ifdef CONFIG_SOC_DRA7XX
+extern int dra7xx_pciess_reset(struct omap_hwmod *oh);
+#else
+static inline int dra7xx_pciess_reset(struct omap_hwmod *oh)
+{
+       return 0;
+}
+#endif
+
 void pdata_quirks_init(const struct of_device_id *);
 void omap_auxdata_legacy_init(struct device *dev);
 void omap_pcs_legacy_init(int irq, void (*rearm)(void));
index 37ff25ee3d8966d93e79a692d9e17618477f2de5..1d8efc303daf52e874c4385f5067a744291d87e6 100644 (file)
@@ -53,15 +53,10 @@ int omap_i2c_reset(struct omap_hwmod *oh)
        u16 i2c_con;
        int c = 0;
 
-       if (oh->class->rev == OMAP_I2C_IP_VERSION_2) {
-               i2c_con = OMAP4_I2C_CON_OFFSET;
-       } else if (oh->class->rev == OMAP_I2C_IP_VERSION_1) {
+       if (soc_is_omap24xx() || soc_is_omap34xx() || soc_is_am35xx())
                i2c_con = OMAP2_I2C_CON_OFFSET;
-       } else {
-               WARN(1, "Cannot reset I2C block %s: unsupported revision\n",
-                    oh->name);
-               return -EINVAL;
-       }
+       else
+               i2c_con = OMAP4_I2C_CON_OFFSET;
 
        /* Disable I2C */
        v = omap_hwmod_read(oh, i2c_con);
index bb8e0bb7ef5de71d713beeda76eff14d17981099..5e69c8caa1dbab56acd5ff0df3902eb36e1b4081 100644 (file)
@@ -411,14 +411,9 @@ static int _set_hwmod_postsetup_state(struct omap_hwmod *oh, void *data)
 
 static void __init __maybe_unused omap_hwmod_init_postsetup(void)
 {
-       u8 postsetup_state;
+       u8 postsetup_state = _HWMOD_STATE_DEFAULT;
 
        /* Set the default postsetup state for all hwmods */
-#ifdef CONFIG_PM
-       postsetup_state = _HWMOD_STATE_IDLE;
-#else
-       postsetup_state = _HWMOD_STATE_ENABLED;
-#endif
        omap_hwmod_for_each(_set_hwmod_postsetup_state, &postsetup_state);
 }
 
index 9145a6f720fcd14c7ecb50d0176997249a88ec41..7f4e053c3434472b763705459466809f46bc9d43 100644 (file)
@@ -7,7 +7,15 @@
 #define OMAP4_MMC_REG_OFFSET   0x100
 
 struct omap_hwmod;
+
+#ifdef CONFIG_SOC_OMAP2420
 int omap_msdi_reset(struct omap_hwmod *oh);
+#else
+static inline int omap_msdi_reset(struct omap_hwmod *oh)
+{
+       return 0;
+}
+#endif
 
 /* called from board-specific card detection service routine */
 extern void omap_mmc_notify_cover_event(struct device *dev, int slot,
index 17558be4bf0a528700939684e4f39c002e0215c7..7dcbe1736f7e4a40d0815f08c7541f88d9ae7fa4 100644 (file)
@@ -436,13 +436,13 @@ static int irq_notifier(struct notifier_block *self, unsigned long cmd,   void *v)
 {
        switch (cmd) {
        case CPU_CLUSTER_PM_ENTER:
-               if (omap_type() == OMAP2_DEVICE_TYPE_GP)
+               if (omap_type() == OMAP2_DEVICE_TYPE_GP || soc_is_am43xx())
                        irq_save_context();
                else
                        irq_save_secure_context();
                break;
        case CPU_CLUSTER_PM_EXIT:
-               if (omap_type() == OMAP2_DEVICE_TYPE_GP)
+               if (omap_type() == OMAP2_DEVICE_TYPE_GP || soc_is_am43xx())
                        irq_restore_context();
                break;
        }
index baadddf9aad49eb44d9d0974e6b6e11c28fd661c..405ac24def05f60558f27b3700f038fdad09d3ad 100644 (file)
 #include "soc.h"
 #include "common.h"
 #include "clockdomain.h"
+#include "hdq1w.h"
+#include "mmc.h"
 #include "powerdomain.h"
 #include "cm2xxx.h"
 #include "cm3xxx.h"
 #include "prm33xx.h"
 #include "prminst44xx.h"
 #include "pm.h"
+#include "wd_timer.h"
 
 /* Name of the OMAP hwmod for the MPU */
 #define MPU_INITIATOR_NAME             "mpu"
@@ -204,6 +207,20 @@ struct clkctrl_provider {
 
 static LIST_HEAD(clkctrl_providers);
 
+/**
+ * struct omap_hwmod_reset - IP specific reset functions
+ * @match: string to match against the module name
+ * @len: number of characters to match
+ * @reset: IP specific reset function
+ *
+ * Used only in cases where struct omap_hwmod is dynamically allocated.
+ */
+struct omap_hwmod_reset {
+       const char *match;
+       int len;
+       int (*reset)(struct omap_hwmod *oh);
+};
+
 /**
  * struct omap_hwmod_soc_ops - fn ptrs for some SoC-specific operations
  * @enable_module: function to enable a module (via MODULEMODE)
@@ -235,6 +252,7 @@ static struct omap_hwmod_soc_ops soc_ops;
 
 /* omap_hwmod_list contains all registered struct omap_hwmods */
 static LIST_HEAD(omap_hwmod_list);
+static DEFINE_MUTEX(list_lock);
 
 /* mpu_oh: used to add/remove MPU initiator from sleepdep list */
 static struct omap_hwmod *mpu_oh;
@@ -2465,7 +2483,7 @@ static void _setup_iclk_autoidle(struct omap_hwmod *oh)
  */
 static int _setup_reset(struct omap_hwmod *oh)
 {
-       int r;
+       int r = 0;
 
        if (oh->_state != _HWMOD_STATE_INITIALIZED)
                return -EINVAL;
@@ -2624,7 +2642,7 @@ static int _setup(struct omap_hwmod *oh, void *data)
  * that the copy process would be relatively complex due to the large number
  * of substructures.
  */
-static int __init _register(struct omap_hwmod *oh)
+static int _register(struct omap_hwmod *oh)
 {
        if (!oh || !oh->name || !oh->class || !oh->class->name ||
            (oh->_state != _HWMOD_STATE_UNKNOWN))
@@ -2663,7 +2681,7 @@ static int __init _register(struct omap_hwmod *oh)
  * locking in this code.  Changes to this assumption will require
  * additional locking.  Returns 0.
  */
-static int __init _add_link(struct omap_hwmod_ocp_if *oi)
+static int _add_link(struct omap_hwmod_ocp_if *oi)
 {
        pr_debug("omap_hwmod: %s -> %s: adding link\n", oi->master->name,
                 oi->slave->name);
@@ -3241,9 +3259,10 @@ static int omap_hwmod_init_regbits(struct device *dev,
  * @sysc_offs: sysc register offset
  * @syss_offs: syss register offset
  */
-int omap_hwmod_init_reg_offs(struct device *dev,
-                            const struct ti_sysc_module_data *data,
-                            s32 *rev_offs, s32 *sysc_offs, s32 *syss_offs)
+static int omap_hwmod_init_reg_offs(struct device *dev,
+                                   const struct ti_sysc_module_data *data,
+                                   s32 *rev_offs, s32 *sysc_offs,
+                                   s32 *syss_offs)
 {
        *rev_offs = -ENODEV;
        *sysc_offs = 0;
@@ -3267,9 +3286,9 @@ int omap_hwmod_init_reg_offs(struct device *dev,
  * @data: module data
  * @sysc_flags: module configuration
  */
-int omap_hwmod_init_sysc_flags(struct device *dev,
-                              const struct ti_sysc_module_data *data,
-                              u32 *sysc_flags)
+static int omap_hwmod_init_sysc_flags(struct device *dev,
+                                     const struct ti_sysc_module_data *data,
+                                     u32 *sysc_flags)
 {
        *sysc_flags = 0;
 
@@ -3341,9 +3360,9 @@ int omap_hwmod_init_sysc_flags(struct device *dev,
  * @data: module data
  * @idlemodes: module supported idle modes
  */
-int omap_hwmod_init_idlemodes(struct device *dev,
-                             const struct ti_sysc_module_data *data,
-                             u32 *idlemodes)
+static int omap_hwmod_init_idlemodes(struct device *dev,
+                                    const struct ti_sysc_module_data *data,
+                                    u32 *idlemodes)
 {
        *idlemodes = 0;
 
@@ -3434,14 +3453,18 @@ static int omap_hwmod_check_module(struct device *dev,
  *
  * Note that the allocations here cannot use devm as ti-sysc can rebind.
  */
-int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
-                              const struct ti_sysc_module_data *data,
-                              struct sysc_regbits *sysc_fields,
-                              s32 rev_offs, s32 sysc_offs, s32 syss_offs,
-                              u32 sysc_flags, u32 idlemodes)
+static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
+                                     const struct ti_sysc_module_data *data,
+                                     struct sysc_regbits *sysc_fields,
+                                     s32 rev_offs, s32 sysc_offs,
+                                     s32 syss_offs, u32 sysc_flags,
+                                     u32 idlemodes)
 {
        struct omap_hwmod_class_sysconfig *sysc;
-       struct omap_hwmod_class *class;
+       struct omap_hwmod_class *class = NULL;
+       struct omap_hwmod_ocp_if *oi = NULL;
+       struct clockdomain *clkdm = NULL;
+       struct clk *clk = NULL;
        void __iomem *regs = NULL;
        unsigned long flags;
 
@@ -3465,26 +3488,128 @@ int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
        }
 
        /*
-        * We need new oh->class as the other devices in the same class
+        * We may need a new oh->class as the other devices in the same class
         * may not yet have ioremapped their registers.
         */
-       class = kmemdup(oh->class, sizeof(*oh->class), GFP_KERNEL);
-       if (!class)
-               return -ENOMEM;
+       if (oh->class->name && strcmp(oh->class->name, data->name)) {
+               class = kmemdup(oh->class, sizeof(*oh->class), GFP_KERNEL);
+               if (!class)
+                       return -ENOMEM;
+       }
 
-       class->sysc = sysc;
+       if (list_empty(&oh->slave_ports)) {
+               oi = kcalloc(1, sizeof(*oi), GFP_KERNEL);
+               if (!oi)
+                       return -ENOMEM;
+
+               /*
+                * Note that we assume interconnect interface clocks will be
+                * managed by the interconnect driver for OCPIF_SWSUP_IDLE case
+                * on omap24xx and omap3.
+                */
+               oi->slave = oh;
+               oi->user = OCP_USER_MPU | OCP_USER_SDMA;
+       }
+
+       if (!oh->_clk) {
+               struct clk_hw_omap *hwclk;
+
+               clk = of_clk_get_by_name(dev->of_node, "fck");
+               if (!IS_ERR(clk))
+                       clk_prepare(clk);
+               else
+                       clk = NULL;
+
+               /*
+                * Populate clockdomain based on dts clock. It is needed for
+                * clkdm_deny_idle() and clkdm_allow_idle() until we have have
+                * interconnect driver and reset driver capable of blocking
+                * clockdomain idle during reset, enable and idle.
+                */
+               if (clk) {
+                       hwclk = to_clk_hw_omap(__clk_get_hw(clk));
+                       if (hwclk && hwclk->clkdm_name)
+                               clkdm = clkdm_lookup(hwclk->clkdm_name);
+               }
+
+               /*
+                * Note that we assume interconnect driver manages the clocks
+                * and do not need to populate oh->_clk for dynamically
+                * allocated modules.
+                */
+               clk_unprepare(clk);
+               clk_put(clk);
+       }
 
        spin_lock_irqsave(&oh->_lock, flags);
        if (regs)
                oh->_mpu_rt_va = regs;
-       oh->class = class;
+       if (class)
+               oh->class = class;
+       oh->class->sysc = sysc;
+       if (oi)
+               _add_link(oi);
+       if (clkdm)
+               oh->clkdm = clkdm;
        oh->_state = _HWMOD_STATE_INITIALIZED;
+       oh->_postsetup_state = _HWMOD_STATE_DEFAULT;
        _setup(oh, NULL);
        spin_unlock_irqrestore(&oh->_lock, flags);
 
        return 0;
 }
 
+static const struct omap_hwmod_reset omap24xx_reset_quirks[] = {
+       { .match = "msdi", .len = 4, .reset = omap_msdi_reset, },
+};
+
+static const struct omap_hwmod_reset dra7_reset_quirks[] = {
+       { .match = "pcie", .len = 4, .reset = dra7xx_pciess_reset, },
+};
+
+static const struct omap_hwmod_reset omap_reset_quirks[] = {
+       { .match = "dss", .len = 3, .reset = omap_dss_reset, },
+       { .match = "hdq1w", .len = 5, .reset = omap_hdq1w_reset, },
+       { .match = "i2c", .len = 3, .reset = omap_i2c_reset, },
+       { .match = "wd_timer", .len = 8, .reset = omap2_wd_timer_reset, },
+};
+
+static void
+omap_hwmod_init_reset_quirk(struct device *dev, struct omap_hwmod *oh,
+                           const struct ti_sysc_module_data *data,
+                           const struct omap_hwmod_reset *quirks,
+                           int quirks_sz)
+{
+       const struct omap_hwmod_reset *quirk;
+       int i;
+
+       for (i = 0; i < quirks_sz; i++) {
+               quirk = &quirks[i];
+               if (!strncmp(data->name, quirk->match, quirk->len)) {
+                       oh->class->reset = quirk->reset;
+
+                       return;
+               }
+       }
+}
+
+static void
+omap_hwmod_init_reset_quirks(struct device *dev, struct omap_hwmod *oh,
+                            const struct ti_sysc_module_data *data)
+{
+       if (soc_is_omap24xx())
+               omap_hwmod_init_reset_quirk(dev, oh, data,
+                                           omap24xx_reset_quirks,
+                                           ARRAY_SIZE(omap24xx_reset_quirks));
+
+       if (soc_is_dra7xx())
+               omap_hwmod_init_reset_quirk(dev, oh, data, dra7_reset_quirks,
+                                           ARRAY_SIZE(dra7_reset_quirks));
+
+       omap_hwmod_init_reset_quirk(dev, oh, data, omap_reset_quirks,
+                                   ARRAY_SIZE(omap_reset_quirks));
+}
+
 /**
  * omap_hwmod_init_module - initialize new module
  * @dev: struct device
@@ -3505,8 +3630,31 @@ int omap_hwmod_init_module(struct device *dev,
                return -EINVAL;
 
        oh = _lookup(data->name);
-       if (!oh)
-               return -ENODEV;
+       if (!oh) {
+               oh = kzalloc(sizeof(*oh), GFP_KERNEL);
+               if (!oh)
+                       return -ENOMEM;
+
+               oh->name = data->name;
+               oh->_state = _HWMOD_STATE_UNKNOWN;
+               lockdep_register_key(&oh->hwmod_key);
+
+               /* Unused, can be handled by PRM driver handling resets */
+               oh->prcm.omap4.flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT;
+
+               oh->class = kzalloc(sizeof(*oh->class), GFP_KERNEL);
+               if (!oh->class) {
+                       kfree(oh);
+                       return -ENOMEM;
+               }
+
+               omap_hwmod_init_reset_quirks(dev, oh, data);
+
+               oh->class->name = data->name;
+               mutex_lock(&list_lock);
+               error = _register(oh);
+               mutex_unlock(&list_lock);
+       }
 
        cookie->data = oh;
 
@@ -3527,10 +3675,20 @@ int omap_hwmod_init_module(struct device *dev,
        if (error)
                return error;
 
+       if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE)
+               oh->flags |= HWMOD_NO_IDLE;
        if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE_ON_INIT)
                oh->flags |= HWMOD_INIT_NO_IDLE;
        if (data->cfg->quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
                oh->flags |= HWMOD_INIT_NO_RESET;
+       if (data->cfg->quirks & SYSC_QUIRK_USE_CLOCKACT)
+               oh->flags |= HWMOD_SET_DEFAULT_CLOCKACT;
+       if (data->cfg->quirks & SYSC_QUIRK_SWSUP_SIDLE)
+               oh->flags |= HWMOD_SWSUP_SIDLE;
+       if (data->cfg->quirks & SYSC_QUIRK_SWSUP_SIDLE_ACT)
+               oh->flags |= HWMOD_SWSUP_SIDLE_ACT;
+       if (data->cfg->quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
+               oh->flags |= HWMOD_SWSUP_MSTANDBY;
 
        error = omap_hwmod_check_module(dev, oh, data, sysc_fields,
                                        rev_offs, sysc_offs, syss_offs,
index b70cdc21f8a2b1ecfdffb7157c67c65a18d80db1..fca9e072154b542b9d33fd954087e71e77019361 100644 (file)
@@ -493,11 +493,16 @@ struct omap_hwmod_omap4_prcm {
 #define _HWMOD_STATE_IDLE                      5
 #define _HWMOD_STATE_DISABLED                  6
 
+#ifdef CONFIG_PM
+#define _HWMOD_STATE_DEFAULT                   _HWMOD_STATE_IDLE
+#else
+#define _HWMOD_STATE_DEFAULT                   _HWMOD_STATE_ENABLED
+#endif
+
 /**
  * struct omap_hwmod_class - the type of an IP block
  * @name: name of the hwmod_class
  * @sysc: device SYSCONFIG/SYSSTATUS register data
- * @rev: revision of the IP class
  * @pre_shutdown: ptr to fn to be executed immediately prior to device shutdown
  * @reset: ptr to fn to be executed in place of the standard hwmod reset fn
  * @enable_preprogram:  ptr to fn to be executed during device enable
@@ -523,7 +528,6 @@ struct omap_hwmod_omap4_prcm {
 struct omap_hwmod_class {
        const char                              *name;
        struct omap_hwmod_class_sysconfig       *sysc;
-       u32                                     rev;
        int                                     (*pre_shutdown)(struct omap_hwmod *oh);
        int                                     (*reset)(struct omap_hwmod *oh);
        int                                     (*enable_preprogram)(struct omap_hwmod *oh);
index d684fac8f592846ced792ac45a87f3c297b01baa..8122c8d4b69a5df5f8301f11b90ef0c8bfcd5021 100644 (file)
@@ -91,7 +91,6 @@ static struct omap_hwmod_class_sysconfig i2c_sysc = {
 static struct omap_hwmod_class i2c_class = {
        .name           = "i2c",
        .sysc           = &i2c_sysc,
-       .rev            = OMAP_I2C_IP_VERSION_1,
        .reset          = &omap_i2c_reset,
 };
 
index abef9f6f9bf57dd95452c73c22c41168aa7c5de2..f27cb60bde772a934a137afdae0ea8a5023448d1 100644 (file)
@@ -68,7 +68,6 @@ static struct omap_hwmod_class_sysconfig i2c_sysc = {
 static struct omap_hwmod_class i2c_class = {
        .name           = "i2c",
        .sysc           = &i2c_sysc,
-       .rev            = OMAP_I2C_IP_VERSION_1,
        .reset          = &omap_i2c_reset,
 };
 
index 9b30b6b471ae3bb274aa32be7cc625af96ca80dd..e19f620c407453d2d002fdcf446cb35471b4ff19 100644 (file)
@@ -11,7 +11,7 @@
  * XXX handle crossbar/shared link difference for L3?
  * XXX these should be marked initdata for multi-OMAP kernels
  */
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include "omap_hwmod.h"
 #include "l3_2xxx.h"
index 5345919a81f8b19c0f69a556ec1816482f35887c..ed5f39d948de57ce5e1f3e5371f9c483b8cea572 100644 (file)
@@ -96,7 +96,6 @@ static struct omap_hwmod_class_sysconfig omap2xxx_gpio_sysc = {
 struct omap_hwmod_class omap2xxx_gpio_hwmod_class = {
        .name = "gpio",
        .sysc = &omap2xxx_gpio_sysc,
-       .rev = 0,
 };
 
 /* system dma */
index 6f81d7a4fec1820969bf173237a6534293f849bd..aaa6092426ea2b9d3c25ed584607de67b4b2325b 100644 (file)
@@ -30,24 +30,16 @@ extern struct omap_hwmod_ocp_if am33xx_l3_main__gfx;
 extern struct omap_hwmod_ocp_if am33xx_l4_wkup__rtc;
 extern struct omap_hwmod_ocp_if am33xx_l4_per__dcan0;
 extern struct omap_hwmod_ocp_if am33xx_l4_per__dcan1;
-extern struct omap_hwmod_ocp_if am33xx_l4_per__gpio1;
-extern struct omap_hwmod_ocp_if am33xx_l4_per__gpio2;
-extern struct omap_hwmod_ocp_if am33xx_l4_per__gpio3;
 extern struct omap_hwmod_ocp_if am33xx_cpgmac0__mdio;
 extern struct omap_hwmod_ocp_if am33xx_l4_ls__elm;
 extern struct omap_hwmod_ocp_if am33xx_l4_ls__epwmss0;
 extern struct omap_hwmod_ocp_if am33xx_l4_ls__epwmss1;
 extern struct omap_hwmod_ocp_if am33xx_l4_ls__epwmss2;
 extern struct omap_hwmod_ocp_if am33xx_l3_s__gpmc;
-extern struct omap_hwmod_ocp_if am33xx_l4_per__i2c2;
-extern struct omap_hwmod_ocp_if am33xx_l4_per__i2c3;
 extern struct omap_hwmod_ocp_if am33xx_l4_per__mailbox;
 extern struct omap_hwmod_ocp_if am33xx_l4_ls__spinlock;
 extern struct omap_hwmod_ocp_if am33xx_l4_ls__mcasp0;
 extern struct omap_hwmod_ocp_if am33xx_l4_ls__mcasp1;
-extern struct omap_hwmod_ocp_if am33xx_l4_ls__mmc0;
-extern struct omap_hwmod_ocp_if am33xx_l4_ls__mmc1;
-extern struct omap_hwmod_ocp_if am33xx_l3_s__mmc2;
 extern struct omap_hwmod_ocp_if am33xx_l4_ls__mcspi0;
 extern struct omap_hwmod_ocp_if am33xx_l4_ls__mcspi1;
 extern struct omap_hwmod_ocp_if am33xx_l4_ls__timer2;
@@ -60,11 +52,6 @@ extern struct omap_hwmod_ocp_if am33xx_l3_main__tpcc;
 extern struct omap_hwmod_ocp_if am33xx_l3_main__tptc0;
 extern struct omap_hwmod_ocp_if am33xx_l3_main__tptc1;
 extern struct omap_hwmod_ocp_if am33xx_l3_main__tptc2;
-extern struct omap_hwmod_ocp_if am33xx_l4_ls__uart2;
-extern struct omap_hwmod_ocp_if am33xx_l4_ls__uart3;
-extern struct omap_hwmod_ocp_if am33xx_l4_ls__uart4;
-extern struct omap_hwmod_ocp_if am33xx_l4_ls__uart5;
-extern struct omap_hwmod_ocp_if am33xx_l4_ls__uart6;
 extern struct omap_hwmod_ocp_if am33xx_l3_main__ocmc;
 extern struct omap_hwmod_ocp_if am33xx_l3_main__sha0;
 extern struct omap_hwmod_ocp_if am33xx_l3_main__aes0;
@@ -93,19 +80,10 @@ extern struct omap_hwmod am33xx_elm_hwmod;
 extern struct omap_hwmod am33xx_epwmss0_hwmod;
 extern struct omap_hwmod am33xx_epwmss1_hwmod;
 extern struct omap_hwmod am33xx_epwmss2_hwmod;
-extern struct omap_hwmod am33xx_gpio1_hwmod;
-extern struct omap_hwmod am33xx_gpio2_hwmod;
-extern struct omap_hwmod am33xx_gpio3_hwmod;
 extern struct omap_hwmod am33xx_gpmc_hwmod;
-extern struct omap_hwmod am33xx_i2c1_hwmod;
-extern struct omap_hwmod am33xx_i2c2_hwmod;
-extern struct omap_hwmod am33xx_i2c3_hwmod;
 extern struct omap_hwmod am33xx_mailbox_hwmod;
 extern struct omap_hwmod am33xx_mcasp0_hwmod;
 extern struct omap_hwmod am33xx_mcasp1_hwmod;
-extern struct omap_hwmod am33xx_mmc0_hwmod;
-extern struct omap_hwmod am33xx_mmc1_hwmod;
-extern struct omap_hwmod am33xx_mmc2_hwmod;
 extern struct omap_hwmod am33xx_rtc_hwmod;
 extern struct omap_hwmod am33xx_spi0_hwmod;
 extern struct omap_hwmod am33xx_spi1_hwmod;
@@ -121,19 +99,12 @@ extern struct omap_hwmod am33xx_tpcc_hwmod;
 extern struct omap_hwmod am33xx_tptc0_hwmod;
 extern struct omap_hwmod am33xx_tptc1_hwmod;
 extern struct omap_hwmod am33xx_tptc2_hwmod;
-extern struct omap_hwmod am33xx_uart1_hwmod;
-extern struct omap_hwmod am33xx_uart2_hwmod;
-extern struct omap_hwmod am33xx_uart3_hwmod;
-extern struct omap_hwmod am33xx_uart4_hwmod;
-extern struct omap_hwmod am33xx_uart5_hwmod;
-extern struct omap_hwmod am33xx_uart6_hwmod;
 extern struct omap_hwmod am33xx_wd_timer1_hwmod;
 
 extern struct omap_hwmod_class am33xx_emif_hwmod_class;
 extern struct omap_hwmod_class am33xx_l4_hwmod_class;
 extern struct omap_hwmod_class am33xx_wkup_m3_hwmod_class;
 extern struct omap_hwmod_class am33xx_control_hwmod_class;
-extern struct omap_hwmod_class am33xx_gpio_hwmod_class;
 extern struct omap_hwmod_class am33xx_timer_hwmod_class;
 extern struct omap_hwmod_class am33xx_epwmss_hwmod_class;
 extern struct omap_hwmod_class am33xx_ehrpwm_hwmod_class;
index e0001232bb4f787aaef25fb80064894650c5ec56..47a0e301b193f598d3b9f6b9438626552cee0b69 100644 (file)
@@ -122,30 +122,6 @@ struct omap_hwmod_ocp_if am33xx_l4_per__dcan1 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4 per/ls -> GPIO2 */
-struct omap_hwmod_ocp_if am33xx_l4_per__gpio1 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_gpio1_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4 per/ls -> gpio3 */
-struct omap_hwmod_ocp_if am33xx_l4_per__gpio2 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_gpio2_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4 per/ls -> gpio4 */
-struct omap_hwmod_ocp_if am33xx_l4_per__gpio3 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_gpio3_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 struct omap_hwmod_ocp_if am33xx_cpgmac0__mdio = {
        .master         = &am33xx_cpgmac0_hwmod,
        .slave          = &am33xx_mdio_hwmod,
@@ -188,21 +164,6 @@ struct omap_hwmod_ocp_if am33xx_l3_s__gpmc = {
        .user           = OCP_USER_MPU,
 };
 
-/* i2c2 */
-struct omap_hwmod_ocp_if am33xx_l4_per__i2c2 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_i2c2_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU,
-};
-
-struct omap_hwmod_ocp_if am33xx_l4_per__i2c3 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_i2c3_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU,
-};
-
 /* l4 ls -> mailbox */
 struct omap_hwmod_ocp_if am33xx_l4_per__mailbox = {
        .master         = &am33xx_l4_ls_hwmod,
@@ -235,30 +196,6 @@ struct omap_hwmod_ocp_if am33xx_l4_ls__mcasp1 = {
        .user           = OCP_USER_MPU,
 };
 
-/* l4 ls -> mmc0 */
-struct omap_hwmod_ocp_if am33xx_l4_ls__mmc0 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_mmc0_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU,
-};
-
-/* l4 ls -> mmc1 */
-struct omap_hwmod_ocp_if am33xx_l4_ls__mmc1 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_mmc1_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU,
-};
-
-/* l3 s -> mmc2 */
-struct omap_hwmod_ocp_if am33xx_l3_s__mmc2 = {
-       .master         = &am33xx_l3_s_hwmod,
-       .slave          = &am33xx_mmc2_hwmod,
-       .clk            = "l3s_gclk",
-       .user           = OCP_USER_MPU,
-};
-
 /* l4 ls -> mcspi0 */
 struct omap_hwmod_ocp_if am33xx_l4_ls__mcspi0 = {
        .master         = &am33xx_l4_ls_hwmod,
@@ -355,46 +292,6 @@ struct omap_hwmod_ocp_if am33xx_l3_main__tptc2 = {
        .user           = OCP_USER_MPU,
 };
 
-/* l4 ls -> uart2 */
-struct omap_hwmod_ocp_if am33xx_l4_ls__uart2 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_uart2_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU,
-};
-
-/* l4 ls -> uart3 */
-struct omap_hwmod_ocp_if am33xx_l4_ls__uart3 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_uart3_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU,
-};
-
-/* l4 ls -> uart4 */
-struct omap_hwmod_ocp_if am33xx_l4_ls__uart4 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_uart4_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU,
-};
-
-/* l4 ls -> uart5 */
-struct omap_hwmod_ocp_if am33xx_l4_ls__uart5 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_uart5_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU,
-};
-
-/* l4 ls -> uart6 */
-struct omap_hwmod_ocp_if am33xx_l4_ls__uart6 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am33xx_uart6_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU,
-};
-
 /* l3 main -> ocmc */
 struct omap_hwmod_ocp_if am33xx_l3_main__ocmc = {
        .master         = &am33xx_l3_main_hwmod,
index 9ded7bf972e714dba0fc12e7b261b512823fe2a7..4c3543bae562a18ebca8a28968e7735b858598cc 100644 (file)
@@ -16,9 +16,7 @@
 
 #include <linux/types.h>
 
-#include <linux/platform_data/hsmmc-omap.h>
 #include "omap_hwmod.h"
-#include "i2c.h"
 #include "wd_timer.h"
 #include "cm33xx.h"
 #include "prm33xx.h"
@@ -534,7 +532,6 @@ static struct omap_hwmod_class_sysconfig am33xx_gpio_sysc = {
 struct omap_hwmod_class am33xx_gpio_hwmod_class = {
        .name           = "gpio",
        .sysc           = &am33xx_gpio_sysc,
-       .rev            = 2,
 };
 
 /* gpio1 */
@@ -627,68 +624,6 @@ struct omap_hwmod am33xx_gpmc_hwmod = {
        },
 };
 
-/* 'i2c' class */
-static struct omap_hwmod_class_sysconfig am33xx_i2c_sysc = {
-       .rev_offs       = 0,
-       .sysc_offs      = 0x0010,
-       .syss_offs      = 0x0090,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-                         SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
-                         SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                         SIDLE_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class i2c_class = {
-       .name           = "i2c",
-       .sysc           = &am33xx_i2c_sysc,
-       .rev            = OMAP_I2C_IP_VERSION_2,
-       .reset          = &omap_i2c_reset,
-};
-
-/* i2c1 */
-struct omap_hwmod am33xx_i2c1_hwmod = {
-       .name           = "i2c1",
-       .class          = &i2c_class,
-       .clkdm_name     = "l4_wkup_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "dpll_per_m2_div4_wkupdm_ck",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* i2c1 */
-struct omap_hwmod am33xx_i2c2_hwmod = {
-       .name           = "i2c2",
-       .class          = &i2c_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "dpll_per_m2_div4_ck",
-       .prcm           = {
-               .omap4 = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* i2c3 */
-struct omap_hwmod am33xx_i2c3_hwmod = {
-       .name           = "i2c3",
-       .class          = &i2c_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "dpll_per_m2_div4_ck",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
 /*
  * 'mailbox' class
  * mailbox module allowing communication between the on-chip processors using a
@@ -762,76 +697,6 @@ struct omap_hwmod am33xx_mcasp1_hwmod = {
        },
 };
 
-/* 'mmc' class */
-static struct omap_hwmod_class_sysconfig am33xx_mmc_sysc = {
-       .rev_offs       = 0x2fc,
-       .sysc_offs      = 0x110,
-       .syss_offs      = 0x114,
-       .sysc_flags     = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
-                         SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
-                         SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class am33xx_mmc_hwmod_class = {
-       .name           = "mmc",
-       .sysc           = &am33xx_mmc_sysc,
-};
-
-/* mmc0 */
-static struct omap_hsmmc_dev_attr am33xx_mmc0_dev_attr = {
-       .flags          = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
-};
-
-struct omap_hwmod am33xx_mmc0_hwmod = {
-       .name           = "mmc1",
-       .class          = &am33xx_mmc_hwmod_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .main_clk       = "mmc_clk",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-       .dev_attr       = &am33xx_mmc0_dev_attr,
-};
-
-/* mmc1 */
-static struct omap_hsmmc_dev_attr am33xx_mmc1_dev_attr = {
-       .flags          = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
-};
-
-struct omap_hwmod am33xx_mmc1_hwmod = {
-       .name           = "mmc2",
-       .class          = &am33xx_mmc_hwmod_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .main_clk       = "mmc_clk",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-       .dev_attr       = &am33xx_mmc1_dev_attr,
-};
-
-/* mmc2 */
-static struct omap_hsmmc_dev_attr am33xx_mmc2_dev_attr = {
-       .flags          = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
-};
-struct omap_hwmod am33xx_mmc2_hwmod = {
-       .name           = "mmc3",
-       .class          = &am33xx_mmc_hwmod_class,
-       .clkdm_name     = "l3s_clkdm",
-       .main_clk       = "mmc_clk",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-       .dev_attr       = &am33xx_mmc2_dev_attr,
-};
-
 /*
  * 'rtc' class
  * rtc subsystem
@@ -1132,102 +997,6 @@ struct omap_hwmod am33xx_tptc2_hwmod = {
        },
 };
 
-/* 'uart' class */
-static struct omap_hwmod_class_sysconfig uart_sysc = {
-       .rev_offs       = 0x50,
-       .sysc_offs      = 0x54,
-       .syss_offs      = 0x58,
-       .sysc_flags     = (SYSC_HAS_SIDLEMODE | SYSC_HAS_ENAWAKEUP |
-                         SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                         SIDLE_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class uart_class = {
-       .name           = "uart",
-       .sysc           = &uart_sysc,
-};
-
-struct omap_hwmod am33xx_uart1_hwmod = {
-       .name           = "uart1",
-       .class          = &uart_class,
-       .clkdm_name     = "l4_wkup_clkdm",
-       .flags          = DEBUG_AM33XXUART1_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "dpll_per_m2_div4_wkupdm_ck",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-struct omap_hwmod am33xx_uart2_hwmod = {
-       .name           = "uart2",
-       .class          = &uart_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "dpll_per_m2_div4_ck",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart3 */
-struct omap_hwmod am33xx_uart3_hwmod = {
-       .name           = "uart3",
-       .class          = &uart_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "dpll_per_m2_div4_ck",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-struct omap_hwmod am33xx_uart4_hwmod = {
-       .name           = "uart4",
-       .class          = &uart_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "dpll_per_m2_div4_ck",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-struct omap_hwmod am33xx_uart5_hwmod = {
-       .name           = "uart5",
-       .class          = &uart_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "dpll_per_m2_div4_ck",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-struct omap_hwmod am33xx_uart6_hwmod = {
-       .name           = "uart6",
-       .class          = &uart_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "dpll_per_m2_div4_ck",
-       .prcm           = {
-               .omap4  = {
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
 /* 'wd_timer' class */
 static struct omap_hwmod_class_sysconfig wdt_sysc = {
        .rev_offs       = 0x0,
@@ -1265,11 +1034,6 @@ struct omap_hwmod am33xx_wd_timer1_hwmod = {
 
 static void omap_hwmod_am33xx_clkctrl(void)
 {
-       CLKCTRL(am33xx_uart2_hwmod, AM33XX_CM_PER_UART1_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_uart3_hwmod, AM33XX_CM_PER_UART2_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_uart4_hwmod, AM33XX_CM_PER_UART3_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_uart5_hwmod, AM33XX_CM_PER_UART4_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_uart6_hwmod, AM33XX_CM_PER_UART5_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_dcan0_hwmod, AM33XX_CM_PER_DCAN0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_dcan1_hwmod, AM33XX_CM_PER_DCAN1_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_elm_hwmod, AM33XX_CM_PER_ELM_CLKCTRL_OFFSET);
@@ -1279,13 +1043,9 @@ static void omap_hwmod_am33xx_clkctrl(void)
        CLKCTRL(am33xx_gpio1_hwmod, AM33XX_CM_PER_GPIO1_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_gpio2_hwmod, AM33XX_CM_PER_GPIO2_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_gpio3_hwmod, AM33XX_CM_PER_GPIO3_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_i2c2_hwmod, AM33XX_CM_PER_I2C1_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_i2c3_hwmod, AM33XX_CM_PER_I2C2_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_mailbox_hwmod, AM33XX_CM_PER_MAILBOX0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_mcasp0_hwmod, AM33XX_CM_PER_MCASP0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_mcasp1_hwmod, AM33XX_CM_PER_MCASP1_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_mmc0_hwmod, AM33XX_CM_PER_MMC0_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_mmc1_hwmod, AM33XX_CM_PER_MMC1_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_spi0_hwmod, AM33XX_CM_PER_SPI0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_spi1_hwmod, AM33XX_CM_PER_SPI1_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_spinlock_hwmod, AM33XX_CM_PER_SPINLOCK_CLKCTRL_OFFSET);
@@ -1299,13 +1059,10 @@ static void omap_hwmod_am33xx_clkctrl(void)
                AM33XX_CM_WKUP_SMARTREFLEX0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_smartreflex1_hwmod,
                AM33XX_CM_WKUP_SMARTREFLEX1_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_uart1_hwmod, AM33XX_CM_WKUP_UART0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_timer1_hwmod, AM33XX_CM_WKUP_TIMER1_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_i2c1_hwmod, AM33XX_CM_WKUP_I2C0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_wd_timer1_hwmod, AM33XX_CM_WKUP_WDT1_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_rtc_hwmod, AM33XX_CM_RTC_RTC_CLKCTRL_OFFSET);
        PRCM_FLAGS(am33xx_rtc_hwmod, HWMOD_OMAP4_ZERO_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_mmc2_hwmod, AM33XX_CM_PER_MMC2_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_gpmc_hwmod, AM33XX_CM_PER_GPMC_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_l4_ls_hwmod, AM33XX_CM_PER_L4LS_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_l4_wkup_hwmod, AM33XX_CM_WKUP_L4WKUP_CLKCTRL_OFFSET);
@@ -1340,11 +1097,6 @@ void omap_hwmod_am33xx_reg(void)
 
 static void omap_hwmod_am43xx_clkctrl(void)
 {
-       CLKCTRL(am33xx_uart2_hwmod, AM43XX_CM_PER_UART1_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_uart3_hwmod, AM43XX_CM_PER_UART2_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_uart4_hwmod, AM43XX_CM_PER_UART3_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_uart5_hwmod, AM43XX_CM_PER_UART4_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_uart6_hwmod, AM43XX_CM_PER_UART5_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_dcan0_hwmod, AM43XX_CM_PER_DCAN0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_dcan1_hwmod, AM43XX_CM_PER_DCAN1_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_elm_hwmod, AM43XX_CM_PER_ELM_CLKCTRL_OFFSET);
@@ -1354,13 +1106,9 @@ static void omap_hwmod_am43xx_clkctrl(void)
        CLKCTRL(am33xx_gpio1_hwmod, AM43XX_CM_PER_GPIO1_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_gpio2_hwmod, AM43XX_CM_PER_GPIO2_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_gpio3_hwmod, AM43XX_CM_PER_GPIO3_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_i2c2_hwmod, AM43XX_CM_PER_I2C1_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_i2c3_hwmod, AM43XX_CM_PER_I2C2_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_mailbox_hwmod, AM43XX_CM_PER_MAILBOX0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_mcasp0_hwmod, AM43XX_CM_PER_MCASP0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_mcasp1_hwmod, AM43XX_CM_PER_MCASP1_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_mmc0_hwmod, AM43XX_CM_PER_MMC0_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_mmc1_hwmod, AM43XX_CM_PER_MMC1_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_spi0_hwmod, AM43XX_CM_PER_SPI0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_spi1_hwmod, AM43XX_CM_PER_SPI1_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_spinlock_hwmod, AM43XX_CM_PER_SPINLOCK_CLKCTRL_OFFSET);
@@ -1374,12 +1122,9 @@ static void omap_hwmod_am43xx_clkctrl(void)
                AM43XX_CM_WKUP_SMARTREFLEX0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_smartreflex1_hwmod,
                AM43XX_CM_WKUP_SMARTREFLEX1_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_uart1_hwmod, AM43XX_CM_WKUP_UART0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_timer1_hwmod, AM43XX_CM_WKUP_TIMER1_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_i2c1_hwmod, AM43XX_CM_WKUP_I2C0_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_wd_timer1_hwmod, AM43XX_CM_WKUP_WDT1_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_rtc_hwmod, AM43XX_CM_RTC_RTC_CLKCTRL_OFFSET);
-       CLKCTRL(am33xx_mmc2_hwmod, AM43XX_CM_PER_MMC2_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_gpmc_hwmod, AM43XX_CM_PER_GPMC_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_l4_ls_hwmod, AM43XX_CM_PER_L4LS_CLKCTRL_OFFSET);
        CLKCTRL(am33xx_l4_wkup_hwmod, AM43XX_CM_WKUP_L4WKUP_CLKCTRL_OFFSET);
index c9483bc062280bf2174ee83730a7455d93591161..c965af275e34148668d4f99adbefd99a26dd466b 100644 (file)
@@ -14,8 +14,6 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/platform_data/i2c-omap.h>
-
 #include "omap_hwmod.h"
 #include "omap_hwmod_common_data.h"
 
@@ -23,7 +21,6 @@
 #include "cm33xx.h"
 #include "prm33xx.h"
 #include "prm-regbits-33xx.h"
-#include "i2c.h"
 #include "wd_timer.h"
 #include "omap_hwmod_33xx_43xx_common_data.h"
 
@@ -230,27 +227,6 @@ static struct omap_hwmod am33xx_control_hwmod = {
        },
 };
 
-/* gpio0 */
-static struct omap_hwmod_opt_clk gpio0_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio0_dbclk" },
-};
-
-static struct omap_hwmod am33xx_gpio0_hwmod = {
-       .name           = "gpio1",
-       .class          = &am33xx_gpio_hwmod_class,
-       .clkdm_name     = "l4_wkup_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "dpll_core_m4_div2_ck",
-       .prcm           = {
-               .omap4  = {
-                       .clkctrl_offs   = AM33XX_CM_WKUP_GPIO0_CLKCTRL_OFFSET,
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = gpio0_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio0_opt_clks),
-};
-
 /* lcdc */
 static struct omap_hwmod_class_sysconfig lcdc_sysc = {
        .rev_offs       = 0x0,
@@ -388,22 +364,6 @@ static struct omap_hwmod_ocp_if am33xx_l4_wkup__control = {
        .user           = OCP_USER_MPU,
 };
 
-/* L4 WKUP -> I2C1 */
-static struct omap_hwmod_ocp_if am33xx_l4_wkup__i2c1 = {
-       .master         = &am33xx_l4_wkup_hwmod,
-       .slave          = &am33xx_i2c1_hwmod,
-       .clk            = "dpll_core_m4_div2_ck",
-       .user           = OCP_USER_MPU,
-};
-
-/* L4 WKUP -> GPIO1 */
-static struct omap_hwmod_ocp_if am33xx_l4_wkup__gpio0 = {
-       .master         = &am33xx_l4_wkup_hwmod,
-       .slave          = &am33xx_gpio0_hwmod,
-       .clk            = "dpll_core_m4_div2_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* L4 WKUP -> ADC_TSC */
 static struct omap_hwmod_ocp_if am33xx_l4_wkup__adc_tsc = {
        .master         = &am33xx_l4_wkup_hwmod,
@@ -434,14 +394,6 @@ static struct omap_hwmod_ocp_if am33xx_l4_wkup__timer1 = {
        .user           = OCP_USER_MPU,
 };
 
-/* l4 wkup -> uart1 */
-static struct omap_hwmod_ocp_if am33xx_l4_wkup__uart1 = {
-       .master         = &am33xx_l4_wkup_hwmod,
-       .slave          = &am33xx_uart1_hwmod,
-       .clk            = "dpll_core_m4_div2_ck",
-       .user           = OCP_USER_MPU,
-};
-
 /* l4 wkup -> wd_timer1 */
 static struct omap_hwmod_ocp_if am33xx_l4_wkup__wd_timer1 = {
        .master         = &am33xx_l4_wkup_hwmod,
@@ -479,27 +431,16 @@ static struct omap_hwmod_ocp_if *am33xx_hwmod_ocp_ifs[] __initdata = {
        &am33xx_l4_wkup__control,
        &am33xx_l4_wkup__smartreflex0,
        &am33xx_l4_wkup__smartreflex1,
-       &am33xx_l4_wkup__uart1,
        &am33xx_l4_wkup__timer1,
        &am33xx_l4_wkup__rtc,
-       &am33xx_l4_wkup__i2c1,
-       &am33xx_l4_wkup__gpio0,
        &am33xx_l4_wkup__adc_tsc,
        &am33xx_l4_wkup__wd_timer1,
        &am33xx_l4_hs__pruss,
        &am33xx_l4_per__dcan0,
        &am33xx_l4_per__dcan1,
-       &am33xx_l4_per__gpio1,
-       &am33xx_l4_per__gpio2,
-       &am33xx_l4_per__gpio3,
-       &am33xx_l4_per__i2c2,
-       &am33xx_l4_per__i2c3,
        &am33xx_l4_per__mailbox,
        &am33xx_l4_ls__mcasp0,
        &am33xx_l4_ls__mcasp1,
-       &am33xx_l4_ls__mmc0,
-       &am33xx_l4_ls__mmc1,
-       &am33xx_l3_s__mmc2,
        &am33xx_l4_ls__timer2,
        &am33xx_l4_ls__timer3,
        &am33xx_l4_ls__timer4,
@@ -507,11 +448,6 @@ static struct omap_hwmod_ocp_if *am33xx_hwmod_ocp_ifs[] __initdata = {
        &am33xx_l4_ls__timer6,
        &am33xx_l4_ls__timer7,
        &am33xx_l3_main__tpcc,
-       &am33xx_l4_ls__uart2,
-       &am33xx_l4_ls__uart3,
-       &am33xx_l4_ls__uart4,
-       &am33xx_l4_ls__uart5,
-       &am33xx_l4_ls__uart6,
        &am33xx_l4_ls__spinlock,
        &am33xx_l4_ls__elm,
        &am33xx_l4_ls__epwmss0,
index 23e6a41a18eb3c184f562215c0970a4d9d828268..edff39921bf80bb447578bdf6a1df1200fa549ed 100644 (file)
@@ -484,7 +484,6 @@ static struct omap_hwmod am35xx_uart4_hwmod = {
 static struct omap_hwmod_class i2c_class = {
        .name   = "i2c",
        .sysc   = &i2c_sysc,
-       .rev    = OMAP_I2C_IP_VERSION_1,
        .reset  = &omap_i2c_reset,
 };
 
@@ -707,7 +706,6 @@ static struct omap_hwmod_class_sysconfig omap3xxx_gpio_sysc = {
 static struct omap_hwmod_class omap3xxx_gpio_hwmod_class = {
        .name = "gpio",
        .sysc = &omap3xxx_gpio_sysc,
-       .rev = 1,
 };
 
 /* gpio1 */
@@ -1029,7 +1027,6 @@ static struct omap_hwmod_class_sysconfig omap34xx_sr_sysc = {
 static struct omap_hwmod_class omap34xx_smartreflex_hwmod_class = {
        .name = "smartreflex",
        .sysc = &omap34xx_sr_sysc,
-       .rev  = 1,
 };
 
 static struct omap_hwmod_class_sysconfig omap36xx_sr_sysc = {
@@ -1044,7 +1041,6 @@ static struct omap_hwmod_class_sysconfig omap36xx_sr_sysc = {
 static struct omap_hwmod_class omap36xx_smartreflex_hwmod_class = {
        .name = "smartreflex",
        .sysc = &omap36xx_sr_sysc,
-       .rev  = 2,
 };
 
 /* SR1 */
index aa271ac5ebac51dbe909552b3b807a0f5575b2dc..69571abc14fd063192d445fdd69f5142d5cf7fbd 100644 (file)
@@ -87,26 +87,6 @@ static struct omap_hwmod am43xx_control_hwmod = {
        },
 };
 
-static struct omap_hwmod_opt_clk gpio0_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio0_dbclk" },
-};
-
-static struct omap_hwmod am43xx_gpio0_hwmod = {
-       .name           = "gpio1",
-       .class          = &am33xx_gpio_hwmod_class,
-       .clkdm_name     = "l4_wkup_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "sys_clkin_ck",
-       .prcm           = {
-               .omap4  = {
-                       .clkctrl_offs   = AM43XX_CM_WKUP_GPIO0_CLKCTRL_OFFSET,
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = gpio0_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio0_opt_clks),
-};
-
 static struct omap_hwmod_class_sysconfig am43xx_synctimer_sysc = {
        .rev_offs       = 0x0,
        .sysc_offs      = 0x4,
@@ -264,46 +244,6 @@ static struct omap_hwmod am43xx_spi4_hwmod = {
        },
 };
 
-static struct omap_hwmod_opt_clk gpio4_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio4_dbclk" },
-};
-
-static struct omap_hwmod am43xx_gpio4_hwmod = {
-       .name           = "gpio5",
-       .class          = &am33xx_gpio_hwmod_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4ls_gclk",
-       .prcm           = {
-               .omap4  = {
-                       .clkctrl_offs = AM43XX_CM_PER_GPIO4_CLKCTRL_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = gpio4_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio4_opt_clks),
-};
-
-static struct omap_hwmod_opt_clk gpio5_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio5_dbclk" },
-};
-
-static struct omap_hwmod am43xx_gpio5_hwmod = {
-       .name           = "gpio6",
-       .class          = &am33xx_gpio_hwmod_class,
-       .clkdm_name     = "l4ls_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4ls_gclk",
-       .prcm           = {
-               .omap4  = {
-                       .clkctrl_offs = AM43XX_CM_PER_GPIO5_CLKCTRL_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = gpio5_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio5_opt_clks),
-};
-
 static struct omap_hwmod_class am43xx_ocp2scp_hwmod_class = {
        .name   = "ocp2scp",
 };
@@ -650,20 +590,6 @@ static struct omap_hwmod_ocp_if am43xx_l4_wkup__control = {
        .user           = OCP_USER_MPU,
 };
 
-static struct omap_hwmod_ocp_if am43xx_l4_wkup__i2c1 = {
-       .master         = &am33xx_l4_wkup_hwmod,
-       .slave          = &am33xx_i2c1_hwmod,
-       .clk            = "sys_clkin_ck",
-       .user           = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_ocp_if am43xx_l4_wkup__gpio0 = {
-       .master         = &am33xx_l4_wkup_hwmod,
-       .slave          = &am43xx_gpio0_hwmod,
-       .clk            = "sys_clkin_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 static struct omap_hwmod_ocp_if am43xx_l4_wkup__adc_tsc = {
        .master         = &am33xx_l4_wkup_hwmod,
        .slave          = &am43xx_adc_tsc_hwmod,
@@ -685,13 +611,6 @@ static struct omap_hwmod_ocp_if am43xx_l4_wkup__timer1 = {
        .user           = OCP_USER_MPU,
 };
 
-static struct omap_hwmod_ocp_if am43xx_l4_wkup__uart1 = {
-       .master         = &am33xx_l4_wkup_hwmod,
-       .slave          = &am33xx_uart1_hwmod,
-       .clk            = "sys_clkin_ck",
-       .user           = OCP_USER_MPU,
-};
-
 static struct omap_hwmod_ocp_if am43xx_l4_wkup__wd_timer1 = {
        .master         = &am33xx_l4_wkup_hwmod,
        .slave          = &am33xx_wd_timer1_hwmod,
@@ -776,20 +695,6 @@ static struct omap_hwmod_ocp_if am43xx_l4_ls__mcspi4 = {
        .user           = OCP_USER_MPU,
 };
 
-static struct omap_hwmod_ocp_if am43xx_l4_ls__gpio4 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am43xx_gpio4_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_ocp_if am43xx_l4_ls__gpio5 = {
-       .master         = &am33xx_l4_ls_hwmod,
-       .slave          = &am43xx_gpio5_hwmod,
-       .clk            = "l4ls_gclk",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 static struct omap_hwmod_ocp_if am43xx_l4_ls__ocp2scp0 = {
        .master         = &am33xx_l4_ls_hwmod,
        .slave          = &am43xx_ocp2scp0_hwmod,
@@ -907,8 +812,6 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = {
        &am43xx_l4_ls__mcspi2,
        &am43xx_l4_ls__mcspi3,
        &am43xx_l4_ls__mcspi4,
-       &am43xx_l4_ls__gpio4,
-       &am43xx_l4_ls__gpio5,
        &am43xx_l3_main__pruss,
        &am33xx_mpu__l3_main,
        &am33xx_mpu__prcm,
@@ -927,27 +830,16 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = {
        &am43xx_l4_wkup__control,
        &am43xx_l4_wkup__smartreflex0,
        &am43xx_l4_wkup__smartreflex1,
-       &am43xx_l4_wkup__uart1,
        &am43xx_l4_wkup__timer1,
-       &am43xx_l4_wkup__i2c1,
-       &am43xx_l4_wkup__gpio0,
        &am43xx_l4_wkup__wd_timer1,
        &am43xx_l4_wkup__adc_tsc,
        &am43xx_l3_s__qspi,
        &am33xx_l4_per__dcan0,
        &am33xx_l4_per__dcan1,
-       &am33xx_l4_per__gpio1,
-       &am33xx_l4_per__gpio2,
-       &am33xx_l4_per__gpio3,
-       &am33xx_l4_per__i2c2,
-       &am33xx_l4_per__i2c3,
        &am33xx_l4_per__mailbox,
        &am33xx_l4_per__rng,
        &am33xx_l4_ls__mcasp0,
        &am33xx_l4_ls__mcasp1,
-       &am33xx_l4_ls__mmc0,
-       &am33xx_l4_ls__mmc1,
-       &am33xx_l3_s__mmc2,
        &am33xx_l4_ls__timer2,
        &am33xx_l4_ls__timer3,
        &am33xx_l4_ls__timer4,
@@ -955,11 +847,6 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = {
        &am33xx_l4_ls__timer6,
        &am33xx_l4_ls__timer7,
        &am33xx_l3_main__tpcc,
-       &am33xx_l4_ls__uart2,
-       &am33xx_l4_ls__uart3,
-       &am33xx_l4_ls__uart4,
-       &am33xx_l4_ls__uart5,
-       &am33xx_l4_ls__uart6,
        &am33xx_l4_ls__spinlock,
        &am33xx_l4_ls__elm,
        &am33xx_l4_ls__epwmss0,
index a95dbac57a814a92d23e660f2273549da6cce2cc..b8de550a15b44bf57e9a6a5d09a9130632c21a49 100644 (file)
@@ -21,9 +21,7 @@
  */
 
 #include <linux/io.h>
-#include <linux/platform_data/hsmmc-omap.h>
 #include <linux/power/smartreflex.h>
-#include <linux/platform_data/i2c-omap.h>
 
 #include <linux/omap-dma.h>
 
@@ -33,7 +31,6 @@
 #include "cm2_44xx.h"
 #include "prm44xx.h"
 #include "prm-regbits-44xx.h"
-#include "i2c.h"
 #include "wd_timer.h"
 
 /* Base offset for all OMAP4 interrupts external to MPUSS */
@@ -1055,160 +1052,6 @@ static struct omap_hwmod omap44xx_fdif_hwmod = {
        },
 };
 
-/*
- * 'gpio' class
- * general purpose io module
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_gpio_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0010,
-       .syss_offs      = 0x0114,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
-                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
-                          SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_gpio_hwmod_class = {
-       .name   = "gpio",
-       .sysc   = &omap44xx_gpio_sysc,
-       .rev    = 2,
-};
-
-/* gpio1 */
-static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio1_dbclk" },
-};
-
-static struct omap_hwmod omap44xx_gpio1_hwmod = {
-       .name           = "gpio1",
-       .class          = &omap44xx_gpio_hwmod_class,
-       .clkdm_name     = "l4_wkup_clkdm",
-       .main_clk       = "l4_wkup_clk_mux_ck",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_WKUP_GPIO1_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_WKUP_GPIO1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio1_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio1_opt_clks),
-};
-
-/* gpio2 */
-static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio2_dbclk" },
-};
-
-static struct omap_hwmod omap44xx_gpio2_hwmod = {
-       .name           = "gpio2",
-       .class          = &omap44xx_gpio_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4_div_ck",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_GPIO2_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_GPIO2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio2_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio2_opt_clks),
-};
-
-/* gpio3 */
-static struct omap_hwmod_opt_clk gpio3_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio3_dbclk" },
-};
-
-static struct omap_hwmod omap44xx_gpio3_hwmod = {
-       .name           = "gpio3",
-       .class          = &omap44xx_gpio_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4_div_ck",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_GPIO3_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_GPIO3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio3_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio3_opt_clks),
-};
-
-/* gpio4 */
-static struct omap_hwmod_opt_clk gpio4_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio4_dbclk" },
-};
-
-static struct omap_hwmod omap44xx_gpio4_hwmod = {
-       .name           = "gpio4",
-       .class          = &omap44xx_gpio_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4_div_ck",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_GPIO4_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_GPIO4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio4_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio4_opt_clks),
-};
-
-/* gpio5 */
-static struct omap_hwmod_opt_clk gpio5_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio5_dbclk" },
-};
-
-static struct omap_hwmod omap44xx_gpio5_hwmod = {
-       .name           = "gpio5",
-       .class          = &omap44xx_gpio_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4_div_ck",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_GPIO5_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_GPIO5_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio5_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio5_opt_clks),
-};
-
-/* gpio6 */
-static struct omap_hwmod_opt_clk gpio6_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio6_dbclk" },
-};
-
-static struct omap_hwmod omap44xx_gpio6_hwmod = {
-       .name           = "gpio6",
-       .class          = &omap44xx_gpio_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4_div_ck",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_GPIO6_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_GPIO6_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio6_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio6_opt_clks),
-};
-
 /*
  * 'gpmc' class
  * general purpose memory controller
@@ -1354,94 +1197,6 @@ static struct omap_hwmod omap44xx_hsi_hwmod = {
        },
 };
 
-/*
- * 'i2c' class
- * multimaster high-speed i2c controller
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_i2c_sysc = {
-       .rev_offs       = 0,
-       .sysc_offs      = 0x0010,
-       .syss_offs      = 0x0090,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-                          SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
-                          SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_i2c_hwmod_class = {
-       .name   = "i2c",
-       .sysc   = &omap44xx_i2c_sysc,
-       .rev    = OMAP_I2C_IP_VERSION_2,
-       .reset  = &omap_i2c_reset,
-};
-
-/* i2c1 */
-static struct omap_hwmod omap44xx_i2c1_hwmod = {
-       .name           = "i2c1",
-       .class          = &omap44xx_i2c_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_I2C1_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_I2C1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* i2c2 */
-static struct omap_hwmod omap44xx_i2c2_hwmod = {
-       .name           = "i2c2",
-       .class          = &omap44xx_i2c_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_I2C2_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_I2C2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* i2c3 */
-static struct omap_hwmod omap44xx_i2c3_hwmod = {
-       .name           = "i2c3",
-       .class          = &omap44xx_i2c_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_I2C3_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_I2C3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* i2c4 */
-static struct omap_hwmod omap44xx_i2c4_hwmod = {
-       .name           = "i2c4",
-       .class          = &omap44xx_i2c_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_I2C4_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_I2C4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
 /*
  * 'ipu' class
  * imaging processor unit
@@ -1818,189 +1573,6 @@ static struct omap_hwmod omap44xx_mcpdm_hwmod = {
        },
 };
 
-/*
- * 'mcspi' class
- * multichannel serial port interface (mcspi) / master/slave synchronous serial
- * bus
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_mcspi_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0010,
-       .sysc_flags     = (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
-                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap44xx_mcspi_hwmod_class = {
-       .name   = "mcspi",
-       .sysc   = &omap44xx_mcspi_sysc,
-};
-
-/* mcspi1 */
-static struct omap_hwmod omap44xx_mcspi1_hwmod = {
-       .name           = "mcspi1",
-       .class          = &omap44xx_mcspi_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_MCSPI1_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_MCSPI1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* mcspi2 */
-static struct omap_hwmod omap44xx_mcspi2_hwmod = {
-       .name           = "mcspi2",
-       .class          = &omap44xx_mcspi_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_MCSPI2_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_MCSPI2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* mcspi3 */
-static struct omap_hwmod omap44xx_mcspi3_hwmod = {
-       .name           = "mcspi3",
-       .class          = &omap44xx_mcspi_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_MCSPI3_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_MCSPI3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* mcspi4 */
-static struct omap_hwmod omap44xx_mcspi4_hwmod = {
-       .name           = "mcspi4",
-       .class          = &omap44xx_mcspi_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_MCSPI4_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_MCSPI4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/*
- * 'mmc' class
- * multimedia card high-speed/sd/sdio (mmc/sd/sdio) host controller
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_mmc_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0010,
-       .sysc_flags     = (SYSC_HAS_EMUFREE | SYSC_HAS_MIDLEMODE |
-                          SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
-                          SYSC_HAS_SOFTRESET),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
-                          MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap44xx_mmc_hwmod_class = {
-       .name   = "mmc",
-       .sysc   = &omap44xx_mmc_sysc,
-};
-
-/* mmc1 */
-static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
-       .flags  = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
-};
-
-static struct omap_hwmod omap44xx_mmc1_hwmod = {
-       .name           = "mmc1",
-       .class          = &omap44xx_mmc_hwmod_class,
-       .clkdm_name     = "l3_init_clkdm",
-       .main_clk       = "hsmmc1_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L3INIT_MMC1_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L3INIT_MMC1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .dev_attr       = &mmc1_dev_attr,
-};
-
-/* mmc2 */
-static struct omap_hwmod omap44xx_mmc2_hwmod = {
-       .name           = "mmc2",
-       .class          = &omap44xx_mmc_hwmod_class,
-       .clkdm_name     = "l3_init_clkdm",
-       .main_clk       = "hsmmc2_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L3INIT_MMC2_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L3INIT_MMC2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* mmc3 */
-static struct omap_hwmod omap44xx_mmc3_hwmod = {
-       .name           = "mmc3",
-       .class          = &omap44xx_mmc_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_MMCSD3_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_MMCSD3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* mmc4 */
-static struct omap_hwmod omap44xx_mmc4_hwmod = {
-       .name           = "mmc4",
-       .class          = &omap44xx_mmc_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_MMCSD4_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_MMCSD4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* mmc5 */
-static struct omap_hwmod omap44xx_mmc5_hwmod = {
-       .name           = "mmc5",
-       .class          = &omap44xx_mmc_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_MMCSD5_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_MMCSD5_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
 /*
  * 'mmu' class
  * The memory management unit performs virtual to physical address translation
@@ -2367,7 +1939,6 @@ static struct omap_hwmod_class_sysconfig omap44xx_smartreflex_sysc = {
 static struct omap_hwmod_class omap44xx_smartreflex_hwmod_class = {
        .name   = "smartreflex",
        .sysc   = &omap44xx_smartreflex_sysc,
-       .rev    = 2,
 };
 
 /* smartreflex_core */
@@ -2672,92 +2243,6 @@ static struct omap_hwmod omap44xx_timer11_hwmod = {
        },
 };
 
-/*
- * 'uart' class
- * universal asynchronous receiver/transmitter (uart)
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_uart_sysc = {
-       .rev_offs       = 0x0050,
-       .sysc_offs      = 0x0054,
-       .syss_offs      = 0x0058,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
-                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
-                          SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_uart_hwmod_class = {
-       .name   = "uart",
-       .sysc   = &omap44xx_uart_sysc,
-};
-
-/* uart1 */
-static struct omap_hwmod omap44xx_uart1_hwmod = {
-       .name           = "uart1",
-       .class          = &omap44xx_uart_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_UART1_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_UART1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart2 */
-static struct omap_hwmod omap44xx_uart2_hwmod = {
-       .name           = "uart2",
-       .class          = &omap44xx_uart_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_UART2_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_UART2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart3 */
-static struct omap_hwmod omap44xx_uart3_hwmod = {
-       .name           = "uart3",
-       .class          = &omap44xx_uart_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .flags          = DEBUG_OMAP4UART3_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_UART3_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_UART3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart4 */
-static struct omap_hwmod omap44xx_uart4_hwmod = {
-       .name           = "uart4",
-       .class          = &omap44xx_uart_hwmod_class,
-       .clkdm_name     = "l4_per_clkdm",
-       .flags          = DEBUG_OMAP4UART4_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP4_CM_L4PER_UART4_CLKCTRL_OFFSET,
-                       .context_offs = OMAP4_RM_L4PER_UART4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
 /*
  * 'usb_host_fs' class
  * full-speed usb host controller
@@ -3082,22 +2567,6 @@ static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_1 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* mmc1 -> l3_main_1 */
-static struct omap_hwmod_ocp_if omap44xx_mmc1__l3_main_1 = {
-       .master         = &omap44xx_mmc1_hwmod,
-       .slave          = &omap44xx_l3_main_1_hwmod,
-       .clk            = "l3_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mmc2 -> l3_main_1 */
-static struct omap_hwmod_ocp_if omap44xx_mmc2__l3_main_1 = {
-       .master         = &omap44xx_mmc2_hwmod,
-       .slave          = &omap44xx_l3_main_1_hwmod,
-       .clk            = "l3_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* mpu -> l3_main_1 */
 static struct omap_hwmod_ocp_if omap44xx_mpu__l3_main_1 = {
        .master         = &omap44xx_mpu_hwmod,
@@ -3554,54 +3023,6 @@ static struct omap_hwmod_ocp_if omap44xx_l4_cfg__fdif = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_wkup -> gpio1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_wkup__gpio1 = {
-       .master         = &omap44xx_l4_wkup_hwmod,
-       .slave          = &omap44xx_gpio1_hwmod,
-       .clk            = "l4_wkup_clk_mux_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio2 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_gpio2_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio3 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_gpio3_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio4 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio4 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_gpio4_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio5 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio5 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_gpio5_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio6 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio6 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_gpio6_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l3_main_2 -> gpmc */
 static struct omap_hwmod_ocp_if omap44xx_l3_main_2__gpmc = {
        .master         = &omap44xx_l3_main_2_hwmod,
@@ -3634,38 +3055,6 @@ static struct omap_hwmod_ocp_if omap44xx_l4_cfg__hsi = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_per -> i2c1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__i2c1 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_i2c1_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> i2c2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__i2c2 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_i2c2_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> i2c3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__i2c3 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_i2c3_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> i2c4 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__i2c4 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_i2c4_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l3_main_2 -> ipu */
 static struct omap_hwmod_ocp_if omap44xx_l3_main_2__ipu = {
        .master         = &omap44xx_l3_main_2_hwmod,
@@ -3770,78 +3159,6 @@ static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcpdm = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_per -> mcspi1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi1 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_mcspi1_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mcspi2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi2 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_mcspi2_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mcspi3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi3 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_mcspi3_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mcspi4 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi4 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_mcspi4_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mmc1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc1 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_mmc1_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mmc2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc2 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_mmc2_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mmc3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc3 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_mmc3_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mmc4 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc4 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_mmc4_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mmc5 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc5 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_mmc5_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l3_main_2 -> ocmc_ram */
 static struct omap_hwmod_ocp_if omap44xx_l3_main_2__ocmc_ram = {
        .master         = &omap44xx_l3_main_2_hwmod,
@@ -4050,38 +3367,6 @@ static struct omap_hwmod_ocp_if omap44xx_l4_per__timer11 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_per -> uart1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__uart1 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_uart1_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> uart2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__uart2 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_uart2_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> uart3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__uart3 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_uart3_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> uart4 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__uart4 = {
-       .master         = &omap44xx_l4_per_hwmod,
-       .slave          = &omap44xx_uart4_hwmod,
-       .clk            = "l4_div_ck",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l4_cfg -> usb_host_fs */
 static struct omap_hwmod_ocp_if __maybe_unused omap44xx_l4_cfg__usb_host_fs = {
        .master         = &omap44xx_l4_cfg_hwmod,
@@ -4164,8 +3449,6 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
        &omap44xx_dss__l3_main_1,
        &omap44xx_l3_main_2__l3_main_1,
        &omap44xx_l4_cfg__l3_main_1,
-       &omap44xx_mmc1__l3_main_1,
-       &omap44xx_mmc2__l3_main_1,
        &omap44xx_mpu__l3_main_1,
        &omap44xx_debugss__l3_main_2,
        &omap44xx_dma_system__l3_main_2,
@@ -4222,20 +3505,10 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
        &omap44xx_l4_per__dss_venc,
        &omap44xx_l4_per__elm,
        &omap44xx_l4_cfg__fdif,
-       &omap44xx_l4_wkup__gpio1,
-       &omap44xx_l4_per__gpio2,
-       &omap44xx_l4_per__gpio3,
-       &omap44xx_l4_per__gpio4,
-       &omap44xx_l4_per__gpio5,
-       &omap44xx_l4_per__gpio6,
        &omap44xx_l3_main_2__gpmc,
        &omap44xx_l3_main_2__gpu,
        &omap44xx_l4_per__hdq1w,
        &omap44xx_l4_cfg__hsi,
-       &omap44xx_l4_per__i2c1,
-       &omap44xx_l4_per__i2c2,
-       &omap44xx_l4_per__i2c3,
-       &omap44xx_l4_per__i2c4,
        &omap44xx_l3_main_2__ipu,
        &omap44xx_l3_main_2__iss,
        /* &omap44xx_iva__sl2if, */
@@ -4249,15 +3522,6 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
        &omap44xx_l4_abe__mcbsp3,
        &omap44xx_l4_per__mcbsp4,
        &omap44xx_l4_abe__mcpdm,
-       &omap44xx_l4_per__mcspi1,
-       &omap44xx_l4_per__mcspi2,
-       &omap44xx_l4_per__mcspi3,
-       &omap44xx_l4_per__mcspi4,
-       &omap44xx_l4_per__mmc1,
-       &omap44xx_l4_per__mmc2,
-       &omap44xx_l4_per__mmc3,
-       &omap44xx_l4_per__mmc4,
-       &omap44xx_l4_per__mmc5,
        &omap44xx_l3_main_2__mmu_ipu,
        &omap44xx_l4_cfg__mmu_dsp,
        &omap44xx_l3_main_2__ocmc_ram,
@@ -4286,10 +3550,6 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
        &omap44xx_l4_per__timer9,
        &omap44xx_l4_per__timer10,
        &omap44xx_l4_per__timer11,
-       &omap44xx_l4_per__uart1,
-       &omap44xx_l4_per__uart2,
-       &omap44xx_l4_per__uart3,
-       &omap44xx_l4_per__uart4,
        /* &omap44xx_l4_cfg__usb_host_fs, */
        &omap44xx_l4_cfg__usb_host_hs,
        &omap44xx_l4_cfg__usb_otg_hs,
index 115473d441cde08bdbf360572b35ca41ae500ebd..29805cc9d74c6bb3536ee4ea713df9157d53b281 100644 (file)
@@ -18,9 +18,7 @@
  */
 
 #include <linux/io.h>
-#include <linux/platform_data/hsmmc-omap.h>
 #include <linux/power/smartreflex.h>
-#include <linux/platform_data/i2c-omap.h>
 
 #include <linux/omap-dma.h>
 
@@ -29,7 +27,6 @@
 #include "cm1_54xx.h"
 #include "cm2_54xx.h"
 #include "prm54xx.h"
-#include "i2c.h"
 #include "wd_timer.h"
 
 /* Base offset for all OMAP5 interrupts external to MPUSS */
@@ -600,308 +597,6 @@ static struct omap_hwmod omap54xx_emif2_hwmod = {
        },
 };
 
-/*
- * 'gpio' class
- * general purpose io module
- */
-
-static struct omap_hwmod_class_sysconfig omap54xx_gpio_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0010,
-       .syss_offs      = 0x0114,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
-                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
-                          SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap54xx_gpio_hwmod_class = {
-       .name   = "gpio",
-       .sysc   = &omap54xx_gpio_sysc,
-       .rev    = 2,
-};
-
-/* gpio1 */
-static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio1_dbclk" },
-};
-
-static struct omap_hwmod omap54xx_gpio1_hwmod = {
-       .name           = "gpio1",
-       .class          = &omap54xx_gpio_hwmod_class,
-       .clkdm_name     = "wkupaon_clkdm",
-       .main_clk       = "wkupaon_iclk_mux",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_WKUPAON_GPIO1_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_WKUPAON_GPIO1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio1_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio1_opt_clks),
-};
-
-/* gpio2 */
-static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio2_dbclk" },
-};
-
-static struct omap_hwmod omap54xx_gpio2_hwmod = {
-       .name           = "gpio2",
-       .class          = &omap54xx_gpio_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4_root_clk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_GPIO2_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_GPIO2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio2_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio2_opt_clks),
-};
-
-/* gpio3 */
-static struct omap_hwmod_opt_clk gpio3_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio3_dbclk" },
-};
-
-static struct omap_hwmod omap54xx_gpio3_hwmod = {
-       .name           = "gpio3",
-       .class          = &omap54xx_gpio_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4_root_clk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_GPIO3_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_GPIO3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio3_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio3_opt_clks),
-};
-
-/* gpio4 */
-static struct omap_hwmod_opt_clk gpio4_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio4_dbclk" },
-};
-
-static struct omap_hwmod omap54xx_gpio4_hwmod = {
-       .name           = "gpio4",
-       .class          = &omap54xx_gpio_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4_root_clk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_GPIO4_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_GPIO4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio4_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio4_opt_clks),
-};
-
-/* gpio5 */
-static struct omap_hwmod_opt_clk gpio5_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio5_dbclk" },
-};
-
-static struct omap_hwmod omap54xx_gpio5_hwmod = {
-       .name           = "gpio5",
-       .class          = &omap54xx_gpio_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4_root_clk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_GPIO5_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_GPIO5_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio5_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio5_opt_clks),
-};
-
-/* gpio6 */
-static struct omap_hwmod_opt_clk gpio6_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio6_dbclk" },
-};
-
-static struct omap_hwmod omap54xx_gpio6_hwmod = {
-       .name           = "gpio6",
-       .class          = &omap54xx_gpio_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4_root_clk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_GPIO6_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_GPIO6_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio6_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio6_opt_clks),
-};
-
-/* gpio7 */
-static struct omap_hwmod_opt_clk gpio7_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio7_dbclk" },
-};
-
-static struct omap_hwmod omap54xx_gpio7_hwmod = {
-       .name           = "gpio7",
-       .class          = &omap54xx_gpio_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4_root_clk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_GPIO7_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_GPIO7_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio7_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio7_opt_clks),
-};
-
-/* gpio8 */
-static struct omap_hwmod_opt_clk gpio8_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio8_dbclk" },
-};
-
-static struct omap_hwmod omap54xx_gpio8_hwmod = {
-       .name           = "gpio8",
-       .class          = &omap54xx_gpio_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l4_root_clk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_GPIO8_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_GPIO8_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio8_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio8_opt_clks),
-};
-
-/*
- * 'i2c' class
- * multimaster high-speed i2c controller
- */
-
-static struct omap_hwmod_class_sysconfig omap54xx_i2c_sysc = {
-       .rev_offs       = 0,
-       .sysc_offs      = 0x0010,
-       .syss_offs      = 0x0090,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-                          SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
-                          SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap54xx_i2c_hwmod_class = {
-       .name   = "i2c",
-       .sysc   = &omap54xx_i2c_sysc,
-       .reset  = &omap_i2c_reset,
-       .rev    = OMAP_I2C_IP_VERSION_2,
-};
-
-/* i2c1 */
-static struct omap_hwmod omap54xx_i2c1_hwmod = {
-       .name           = "i2c1",
-       .class          = &omap54xx_i2c_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_I2C1_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_I2C1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* i2c2 */
-static struct omap_hwmod omap54xx_i2c2_hwmod = {
-       .name           = "i2c2",
-       .class          = &omap54xx_i2c_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_I2C2_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_I2C2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* i2c3 */
-static struct omap_hwmod omap54xx_i2c3_hwmod = {
-       .name           = "i2c3",
-       .class          = &omap54xx_i2c_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_I2C3_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_I2C3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* i2c4 */
-static struct omap_hwmod omap54xx_i2c4_hwmod = {
-       .name           = "i2c4",
-       .class          = &omap54xx_i2c_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_I2C4_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_I2C4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* i2c5 */
-static struct omap_hwmod omap54xx_i2c5_hwmod = {
-       .name           = "i2c5",
-       .class          = &omap54xx_i2c_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_I2C5_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_I2C5_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
 /*
  * 'kbd' class
  * keyboard controller
@@ -1184,115 +879,6 @@ static struct omap_hwmod omap54xx_mcspi4_hwmod = {
        },
 };
 
-/*
- * 'mmc' class
- * multimedia card high-speed/sd/sdio (mmc/sd/sdio) host controller
- */
-
-static struct omap_hwmod_class_sysconfig omap54xx_mmc_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0010,
-       .sysc_flags     = (SYSC_HAS_EMUFREE | SYSC_HAS_MIDLEMODE |
-                          SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
-                          SYSC_HAS_SOFTRESET),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
-                          MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap54xx_mmc_hwmod_class = {
-       .name   = "mmc",
-       .sysc   = &omap54xx_mmc_sysc,
-};
-
-/* mmc1 */
-static struct omap_hwmod_opt_clk mmc1_opt_clks[] = {
-       { .role = "32khz_clk", .clk = "mmc1_32khz_clk" },
-};
-
-/* mmc1 dev_attr */
-static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
-       .flags  = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
-};
-
-static struct omap_hwmod omap54xx_mmc1_hwmod = {
-       .name           = "mmc1",
-       .class          = &omap54xx_mmc_hwmod_class,
-       .clkdm_name     = "l3init_clkdm",
-       .main_clk       = "mmc1_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L3INIT_MMC1_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L3INIT_MMC1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = mmc1_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(mmc1_opt_clks),
-       .dev_attr       = &mmc1_dev_attr,
-};
-
-/* mmc2 */
-static struct omap_hwmod omap54xx_mmc2_hwmod = {
-       .name           = "mmc2",
-       .class          = &omap54xx_mmc_hwmod_class,
-       .clkdm_name     = "l3init_clkdm",
-       .main_clk       = "mmc2_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L3INIT_MMC2_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L3INIT_MMC2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* mmc3 */
-static struct omap_hwmod omap54xx_mmc3_hwmod = {
-       .name           = "mmc3",
-       .class          = &omap54xx_mmc_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_MMC3_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_MMC3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* mmc4 */
-static struct omap_hwmod omap54xx_mmc4_hwmod = {
-       .name           = "mmc4",
-       .class          = &omap54xx_mmc_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_MMC4_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_MMC4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* mmc5 */
-static struct omap_hwmod omap54xx_mmc5_hwmod = {
-       .name           = "mmc5",
-       .class          = &omap54xx_mmc_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_MMC5_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_MMC5_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
 /*
  * 'mmu' class
  * The memory management unit performs virtual to physical address translation
@@ -1657,124 +1243,6 @@ static struct omap_hwmod omap54xx_timer11_hwmod = {
        },
 };
 
-/*
- * 'uart' class
- * universal asynchronous receiver/transmitter (uart)
- */
-
-static struct omap_hwmod_class_sysconfig omap54xx_uart_sysc = {
-       .rev_offs       = 0x0050,
-       .sysc_offs      = 0x0054,
-       .syss_offs      = 0x0058,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
-                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
-                          SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap54xx_uart_hwmod_class = {
-       .name   = "uart",
-       .sysc   = &omap54xx_uart_sysc,
-};
-
-/* uart1 */
-static struct omap_hwmod omap54xx_uart1_hwmod = {
-       .name           = "uart1",
-       .class          = &omap54xx_uart_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_UART1_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_UART1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart2 */
-static struct omap_hwmod omap54xx_uart2_hwmod = {
-       .name           = "uart2",
-       .class          = &omap54xx_uart_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_UART2_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_UART2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart3 */
-static struct omap_hwmod omap54xx_uart3_hwmod = {
-       .name           = "uart3",
-       .class          = &omap54xx_uart_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = DEBUG_OMAP4UART3_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_UART3_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_UART3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart4 */
-static struct omap_hwmod omap54xx_uart4_hwmod = {
-       .name           = "uart4",
-       .class          = &omap54xx_uart_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = DEBUG_OMAP4UART4_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_UART4_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_UART4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart5 */
-static struct omap_hwmod omap54xx_uart5_hwmod = {
-       .name           = "uart5",
-       .class          = &omap54xx_uart_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_UART5_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_UART5_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart6 */
-static struct omap_hwmod omap54xx_uart6_hwmod = {
-       .name           = "uart6",
-       .class          = &omap54xx_uart_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .main_clk       = "func_48m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = OMAP54XX_CM_L4PER_UART6_CLKCTRL_OFFSET,
-                       .context_offs = OMAP54XX_RM_L4PER_UART6_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
 /*
  * 'usb_host_hs' class
  * high-speed multi-port usb host controller
@@ -2274,110 +1742,6 @@ static struct omap_hwmod_ocp_if omap54xx_mpu__emif2 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_wkup -> gpio1 */
-static struct omap_hwmod_ocp_if omap54xx_l4_wkup__gpio1 = {
-       .master         = &omap54xx_l4_wkup_hwmod,
-       .slave          = &omap54xx_gpio1_hwmod,
-       .clk            = "wkupaon_iclk_mux",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio2 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__gpio2 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_gpio2_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio3 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__gpio3 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_gpio3_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio4 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__gpio4 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_gpio4_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio5 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__gpio5 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_gpio5_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio6 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__gpio6 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_gpio6_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio7 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__gpio7 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_gpio7_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio8 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__gpio8 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_gpio8_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> i2c1 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__i2c1 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_i2c1_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> i2c2 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__i2c2 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_i2c2_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> i2c3 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__i2c3 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_i2c3_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> i2c4 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__i2c4 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_i2c4_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> i2c5 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__i2c5 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_i2c5_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l4_wkup -> kbd */
 static struct omap_hwmod_ocp_if omap54xx_l4_wkup__kbd = {
        .master         = &omap54xx_l4_wkup_hwmod,
@@ -2458,46 +1822,6 @@ static struct omap_hwmod_ocp_if omap54xx_l4_per__mcspi4 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_per -> mmc1 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__mmc1 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_mmc1_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mmc2 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__mmc2 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_mmc2_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mmc3 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__mmc3 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_mmc3_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mmc4 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__mmc4 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_mmc4_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> mmc5 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__mmc5 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_mmc5_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l4_cfg -> mpu */
 static struct omap_hwmod_ocp_if omap54xx_l4_cfg__mpu = {
        .master         = &omap54xx_l4_cfg_hwmod,
@@ -2610,54 +1934,6 @@ static struct omap_hwmod_ocp_if omap54xx_l4_per__timer11 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_per -> uart1 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__uart1 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_uart1_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> uart2 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__uart2 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_uart2_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> uart3 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__uart3 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_uart3_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> uart4 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__uart4 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_uart4_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> uart5 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__uart5 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_uart5_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> uart6 */
-static struct omap_hwmod_ocp_if omap54xx_l4_per__uart6 = {
-       .master         = &omap54xx_l4_per_hwmod,
-       .slave          = &omap54xx_uart6_hwmod,
-       .clk            = "l4_root_clk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l4_cfg -> usb_host_hs */
 static struct omap_hwmod_ocp_if omap54xx_l4_cfg__usb_host_hs = {
        .master         = &omap54xx_l4_cfg_hwmod,
@@ -2719,19 +1995,6 @@ static struct omap_hwmod_ocp_if *omap54xx_hwmod_ocp_ifs[] __initdata = {
        &omap54xx_l3_main_2__dss_rfbi,
        &omap54xx_mpu__emif1,
        &omap54xx_mpu__emif2,
-       &omap54xx_l4_wkup__gpio1,
-       &omap54xx_l4_per__gpio2,
-       &omap54xx_l4_per__gpio3,
-       &omap54xx_l4_per__gpio4,
-       &omap54xx_l4_per__gpio5,
-       &omap54xx_l4_per__gpio6,
-       &omap54xx_l4_per__gpio7,
-       &omap54xx_l4_per__gpio8,
-       &omap54xx_l4_per__i2c1,
-       &omap54xx_l4_per__i2c2,
-       &omap54xx_l4_per__i2c3,
-       &omap54xx_l4_per__i2c4,
-       &omap54xx_l4_per__i2c5,
        &omap54xx_l3_main_2__mmu_ipu,
        &omap54xx_l4_wkup__kbd,
        &omap54xx_l4_cfg__mailbox,
@@ -2743,11 +2006,6 @@ static struct omap_hwmod_ocp_if *omap54xx_hwmod_ocp_ifs[] __initdata = {
        &omap54xx_l4_per__mcspi2,
        &omap54xx_l4_per__mcspi3,
        &omap54xx_l4_per__mcspi4,
-       &omap54xx_l4_per__mmc1,
-       &omap54xx_l4_per__mmc2,
-       &omap54xx_l4_per__mmc3,
-       &omap54xx_l4_per__mmc4,
-       &omap54xx_l4_per__mmc5,
        &omap54xx_l4_cfg__mpu,
        &omap54xx_l4_cfg__spinlock,
        &omap54xx_l4_cfg__ocp2scp1,
@@ -2762,12 +2020,6 @@ static struct omap_hwmod_ocp_if *omap54xx_hwmod_ocp_ifs[] __initdata = {
        &omap54xx_l4_per__timer9,
        &omap54xx_l4_per__timer10,
        &omap54xx_l4_per__timer11,
-       &omap54xx_l4_per__uart1,
-       &omap54xx_l4_per__uart2,
-       &omap54xx_l4_per__uart3,
-       &omap54xx_l4_per__uart4,
-       &omap54xx_l4_per__uart5,
-       &omap54xx_l4_per__uart6,
        &omap54xx_l4_cfg__usb_host_hs,
        &omap54xx_l4_cfg__usb_tll_hs,
        &omap54xx_l4_cfg__usb_otg_ss,
index e6c7061a8e73679695f7816c0461ccccf66151c6..7e85bd27ce9ac9a06b7ae471f0e62fa4a93d2f2d 100644 (file)
@@ -18,9 +18,7 @@
  */
 
 #include <linux/io.h>
-#include <linux/platform_data/hsmmc-omap.h>
 #include <linux/power/smartreflex.h>
-#include <linux/platform_data/i2c-omap.h>
 
 #include <linux/omap-dma.h>
 
@@ -29,7 +27,6 @@
 #include "cm1_7xx.h"
 #include "cm2_7xx.h"
 #include "prm7xx.h"
-#include "i2c.h"
 #include "wd_timer.h"
 #include "soc.h"
 
@@ -693,7 +690,6 @@ static struct omap_hwmod_class_sysconfig dra7xx_aes_sysc = {
 static struct omap_hwmod_class dra7xx_aes_hwmod_class = {
        .name   = "aes",
        .sysc   = &dra7xx_aes_sysc,
-       .rev    = 2,
 };
 
 /* AES1 */
@@ -737,7 +733,6 @@ static struct omap_hwmod_class_sysconfig dra7xx_sha0_sysc = {
 static struct omap_hwmod_class dra7xx_sha0_hwmod_class = {
        .name           = "sham",
        .sysc           = &dra7xx_sha0_sysc,
-       .rev            = 2,
 };
 
 struct omap_hwmod dra7xx_sha0_hwmod = {
@@ -791,205 +786,6 @@ static struct omap_hwmod dra7xx_elm_hwmod = {
        },
 };
 
-/*
- * 'gpio' class
- *
- */
-
-static struct omap_hwmod_class_sysconfig dra7xx_gpio_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0010,
-       .syss_offs      = 0x0114,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
-                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
-                          SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class dra7xx_gpio_hwmod_class = {
-       .name   = "gpio",
-       .sysc   = &dra7xx_gpio_sysc,
-       .rev    = 2,
-};
-
-/* gpio1 */
-static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio1_dbclk" },
-};
-
-static struct omap_hwmod dra7xx_gpio1_hwmod = {
-       .name           = "gpio1",
-       .class          = &dra7xx_gpio_hwmod_class,
-       .clkdm_name     = "wkupaon_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "wkupaon_iclk_mux",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_WKUPAON_GPIO1_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_WKUPAON_GPIO1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio1_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio1_opt_clks),
-};
-
-/* gpio2 */
-static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio2_dbclk" },
-};
-
-static struct omap_hwmod dra7xx_gpio2_hwmod = {
-       .name           = "gpio2",
-       .class          = &dra7xx_gpio_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l3_iclk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_GPIO2_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_GPIO2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio2_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio2_opt_clks),
-};
-
-/* gpio3 */
-static struct omap_hwmod_opt_clk gpio3_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio3_dbclk" },
-};
-
-static struct omap_hwmod dra7xx_gpio3_hwmod = {
-       .name           = "gpio3",
-       .class          = &dra7xx_gpio_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l3_iclk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_GPIO3_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_GPIO3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio3_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio3_opt_clks),
-};
-
-/* gpio4 */
-static struct omap_hwmod_opt_clk gpio4_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio4_dbclk" },
-};
-
-static struct omap_hwmod dra7xx_gpio4_hwmod = {
-       .name           = "gpio4",
-       .class          = &dra7xx_gpio_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l3_iclk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_GPIO4_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_GPIO4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio4_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio4_opt_clks),
-};
-
-/* gpio5 */
-static struct omap_hwmod_opt_clk gpio5_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio5_dbclk" },
-};
-
-static struct omap_hwmod dra7xx_gpio5_hwmod = {
-       .name           = "gpio5",
-       .class          = &dra7xx_gpio_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l3_iclk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_GPIO5_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_GPIO5_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio5_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio5_opt_clks),
-};
-
-/* gpio6 */
-static struct omap_hwmod_opt_clk gpio6_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio6_dbclk" },
-};
-
-static struct omap_hwmod dra7xx_gpio6_hwmod = {
-       .name           = "gpio6",
-       .class          = &dra7xx_gpio_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l3_iclk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_GPIO6_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_GPIO6_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio6_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio6_opt_clks),
-};
-
-/* gpio7 */
-static struct omap_hwmod_opt_clk gpio7_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio7_dbclk" },
-};
-
-static struct omap_hwmod dra7xx_gpio7_hwmod = {
-       .name           = "gpio7",
-       .class          = &dra7xx_gpio_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l3_iclk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_GPIO7_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_GPIO7_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio7_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio7_opt_clks),
-};
-
-/* gpio8 */
-static struct omap_hwmod_opt_clk gpio8_opt_clks[] = {
-       { .role = "dbclk", .clk = "gpio8_dbclk" },
-};
-
-static struct omap_hwmod dra7xx_gpio8_hwmod = {
-       .name           = "gpio8",
-       .class          = &dra7xx_gpio_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-       .main_clk       = "l3_iclk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_GPIO8_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_GPIO8_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_HWCTRL,
-               },
-       },
-       .opt_clks       = gpio8_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(gpio8_opt_clks),
-};
-
 /*
  * 'gpmc' class
  *
@@ -1064,110 +860,6 @@ static struct omap_hwmod dra7xx_hdq1w_hwmod = {
        },
 };
 
-/*
- * 'i2c' class
- *
- */
-
-static struct omap_hwmod_class_sysconfig dra7xx_i2c_sysc = {
-       .rev_offs       = 0,
-       .sysc_offs      = 0x0010,
-       .syss_offs      = 0x0090,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-                          SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
-                          SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class dra7xx_i2c_hwmod_class = {
-       .name   = "i2c",
-       .sysc   = &dra7xx_i2c_sysc,
-       .reset  = &omap_i2c_reset,
-       .rev    = OMAP_I2C_IP_VERSION_2,
-};
-
-/* i2c1 */
-static struct omap_hwmod dra7xx_i2c1_hwmod = {
-       .name           = "i2c1",
-       .class          = &dra7xx_i2c_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_I2C1_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_I2C1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* i2c2 */
-static struct omap_hwmod dra7xx_i2c2_hwmod = {
-       .name           = "i2c2",
-       .class          = &dra7xx_i2c_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_I2C2_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_I2C2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* i2c3 */
-static struct omap_hwmod dra7xx_i2c3_hwmod = {
-       .name           = "i2c3",
-       .class          = &dra7xx_i2c_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_I2C3_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_I2C3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* i2c4 */
-static struct omap_hwmod dra7xx_i2c4_hwmod = {
-       .name           = "i2c4",
-       .class          = &dra7xx_i2c_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_I2C4_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_I2C4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* i2c5 */
-static struct omap_hwmod dra7xx_i2c5_hwmod = {
-       .name           = "i2c5",
-       .class          = &dra7xx_i2c_hwmod_class,
-       .clkdm_name     = "ipu_clkdm",
-       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
-       .main_clk       = "func_96m_fclk",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_IPU_I2C5_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_IPU_I2C5_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
 /*
  * 'mailbox' class
  *
@@ -1631,118 +1323,6 @@ static struct omap_hwmod dra7xx_mcasp8_hwmod = {
        .opt_clks_cnt   = ARRAY_SIZE(mcasp8_opt_clks),
 };
 
-/*
- * 'mmc' class
- *
- */
-
-static struct omap_hwmod_class_sysconfig dra7xx_mmc_sysc = {
-       .rev_offs       = 0x0000,
-       .sysc_offs      = 0x0010,
-       .sysc_flags     = (SYSC_HAS_EMUFREE | SYSC_HAS_MIDLEMODE |
-                          SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
-                          SYSC_HAS_SOFTRESET),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
-                          MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class dra7xx_mmc_hwmod_class = {
-       .name   = "mmc",
-       .sysc   = &dra7xx_mmc_sysc,
-};
-
-/* mmc1 */
-static struct omap_hwmod_opt_clk mmc1_opt_clks[] = {
-       { .role = "clk32k", .clk = "mmc1_clk32k" },
-};
-
-/* mmc1 dev_attr */
-static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
-       .flags  = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
-};
-
-static struct omap_hwmod dra7xx_mmc1_hwmod = {
-       .name           = "mmc1",
-       .class          = &dra7xx_mmc_hwmod_class,
-       .clkdm_name     = "l3init_clkdm",
-       .main_clk       = "mmc1_fclk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L3INIT_MMC1_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L3INIT_MMC1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = mmc1_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(mmc1_opt_clks),
-       .dev_attr       = &mmc1_dev_attr,
-};
-
-/* mmc2 */
-static struct omap_hwmod_opt_clk mmc2_opt_clks[] = {
-       { .role = "clk32k", .clk = "mmc2_clk32k" },
-};
-
-static struct omap_hwmod dra7xx_mmc2_hwmod = {
-       .name           = "mmc2",
-       .class          = &dra7xx_mmc_hwmod_class,
-       .clkdm_name     = "l3init_clkdm",
-       .main_clk       = "mmc2_fclk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L3INIT_MMC2_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L3INIT_MMC2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = mmc2_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(mmc2_opt_clks),
-};
-
-/* mmc3 */
-static struct omap_hwmod_opt_clk mmc3_opt_clks[] = {
-       { .role = "clk32k", .clk = "mmc3_clk32k" },
-};
-
-static struct omap_hwmod dra7xx_mmc3_hwmod = {
-       .name           = "mmc3",
-       .class          = &dra7xx_mmc_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .main_clk       = "mmc3_gfclk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_MMC3_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_MMC3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = mmc3_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(mmc3_opt_clks),
-};
-
-/* mmc4 */
-static struct omap_hwmod_opt_clk mmc4_opt_clks[] = {
-       { .role = "clk32k", .clk = "mmc4_clk32k" },
-};
-
-static struct omap_hwmod dra7xx_mmc4_hwmod = {
-       .name           = "mmc4",
-       .class          = &dra7xx_mmc_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .main_clk       = "mmc4_gfclk_div",
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_MMC4_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_MMC4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-       .opt_clks       = mmc4_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(mmc4_opt_clks),
-};
-
 /*
  * 'mpu' class
  *
@@ -1832,7 +1412,7 @@ static struct omap_hwmod dra7xx_ocp2scp3_hwmod = {
  * We use a PCIeSS HWMOD class specific reset handler to deassert the hardreset
  * lines after asserting them.
  */
-static int dra7xx_pciess_reset(struct omap_hwmod *oh)
+int dra7xx_pciess_reset(struct omap_hwmod *oh)
 {
        int i;
 
@@ -2019,7 +1599,6 @@ static struct omap_hwmod_class_sysconfig dra7xx_smartreflex_sysc = {
 static struct omap_hwmod_class dra7xx_smartreflex_hwmod_class = {
        .name   = "smartreflex",
        .sysc   = &dra7xx_smartreflex_sysc,
-       .rev    = 2,
 };
 
 /* smartreflex_core */
@@ -2375,188 +1954,6 @@ static struct omap_hwmod dra7xx_timer16_hwmod = {
        },
 };
 
-/*
- * 'uart' class
- *
- */
-
-static struct omap_hwmod_class_sysconfig dra7xx_uart_sysc = {
-       .rev_offs       = 0x0050,
-       .sysc_offs      = 0x0054,
-       .syss_offs      = 0x0058,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
-                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
-                          SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
-       .sysc_fields    = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class dra7xx_uart_hwmod_class = {
-       .name   = "uart",
-       .sysc   = &dra7xx_uart_sysc,
-};
-
-/* uart1 */
-static struct omap_hwmod dra7xx_uart1_hwmod = {
-       .name           = "uart1",
-       .class          = &dra7xx_uart_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .main_clk       = "uart1_gfclk_mux",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT | DEBUG_OMAP2UART1_FLAGS,
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_UART1_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_UART1_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart2 */
-static struct omap_hwmod dra7xx_uart2_hwmod = {
-       .name           = "uart2",
-       .class          = &dra7xx_uart_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .main_clk       = "uart2_gfclk_mux",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_UART2_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_UART2_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart3 */
-static struct omap_hwmod dra7xx_uart3_hwmod = {
-       .name           = "uart3",
-       .class          = &dra7xx_uart_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .main_clk       = "uart3_gfclk_mux",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT | DEBUG_OMAP4UART3_FLAGS,
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_UART3_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_UART3_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart4 */
-static struct omap_hwmod dra7xx_uart4_hwmod = {
-       .name           = "uart4",
-       .class          = &dra7xx_uart_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .main_clk       = "uart4_gfclk_mux",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT | DEBUG_OMAP4UART4_FLAGS,
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_UART4_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_UART4_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart5 */
-static struct omap_hwmod dra7xx_uart5_hwmod = {
-       .name           = "uart5",
-       .class          = &dra7xx_uart_hwmod_class,
-       .clkdm_name     = "l4per_clkdm",
-       .main_clk       = "uart5_gfclk_mux",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER_UART5_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER_UART5_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart6 */
-static struct omap_hwmod dra7xx_uart6_hwmod = {
-       .name           = "uart6",
-       .class          = &dra7xx_uart_hwmod_class,
-       .clkdm_name     = "ipu_clkdm",
-       .main_clk       = "uart6_gfclk_mux",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_IPU_UART6_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_IPU_UART6_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart7 */
-static struct omap_hwmod dra7xx_uart7_hwmod = {
-       .name           = "uart7",
-       .class          = &dra7xx_uart_hwmod_class,
-       .clkdm_name     = "l4per2_clkdm",
-       .main_clk       = "uart7_gfclk_mux",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER2_UART7_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER2_UART7_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart8 */
-static struct omap_hwmod dra7xx_uart8_hwmod = {
-       .name           = "uart8",
-       .class          = &dra7xx_uart_hwmod_class,
-       .clkdm_name     = "l4per2_clkdm",
-       .main_clk       = "uart8_gfclk_mux",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER2_UART8_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER2_UART8_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart9 */
-static struct omap_hwmod dra7xx_uart9_hwmod = {
-       .name           = "uart9",
-       .class          = &dra7xx_uart_hwmod_class,
-       .clkdm_name     = "l4per2_clkdm",
-       .main_clk       = "uart9_gfclk_mux",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_L4PER2_UART9_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_L4PER2_UART9_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
-/* uart10 */
-static struct omap_hwmod dra7xx_uart10_hwmod = {
-       .name           = "uart10",
-       .class          = &dra7xx_uart_hwmod_class,
-       .clkdm_name     = "wkupaon_clkdm",
-       .main_clk       = "uart10_gfclk_mux",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
-       .prcm = {
-               .omap4 = {
-                       .clkctrl_offs = DRA7XX_CM_WKUPAON_UART10_CLKCTRL_OFFSET,
-                       .context_offs = DRA7XX_RM_WKUPAON_UART10_CONTEXT_OFFSET,
-                       .modulemode   = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
 /* DES (the 'P' (public) device) */
 static struct omap_hwmod_class_sysconfig dra7xx_des_sysc = {
        .rev_offs       = 0x0030,
@@ -3113,70 +2510,6 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per1__elm = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_wkup -> gpio1 */
-static struct omap_hwmod_ocp_if dra7xx_l4_wkup__gpio1 = {
-       .master         = &dra7xx_l4_wkup_hwmod,
-       .slave          = &dra7xx_gpio1_hwmod,
-       .clk            = "wkupaon_iclk_mux",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> gpio2 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio2 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_gpio2_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> gpio3 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio3 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_gpio3_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> gpio4 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio4 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_gpio4_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> gpio5 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio5 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_gpio5_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> gpio6 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio6 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_gpio6_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> gpio7 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio7 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_gpio7_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> gpio8 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio8 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_gpio8_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l3_main_1 -> gpmc */
 static struct omap_hwmod_ocp_if dra7xx_l3_main_1__gpmc = {
        .master         = &dra7xx_l3_main_1_hwmod,
@@ -3193,46 +2526,6 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per1__hdq1w = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_per1 -> i2c1 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__i2c1 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_i2c1_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> i2c2 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__i2c2 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_i2c2_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> i2c3 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__i2c3 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_i2c3_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> i2c4 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__i2c4 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_i2c4_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> i2c5 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__i2c5 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_i2c5_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l4_cfg -> mailbox1 */
 static struct omap_hwmod_ocp_if dra7xx_l4_cfg__mailbox1 = {
        .master         = &dra7xx_l4_cfg_hwmod,
@@ -3369,38 +2662,6 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per1__mcspi4 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_per1 -> mmc1 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__mmc1 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_mmc1_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> mmc2 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__mmc2 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_mmc2_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> mmc3 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__mmc3 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_mmc3_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> mmc4 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__mmc4 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_mmc4_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l4_cfg -> mpu */
 static struct omap_hwmod_ocp_if dra7xx_l4_cfg__mpu = {
        .master         = &dra7xx_l4_cfg_hwmod,
@@ -3633,62 +2894,6 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per3__timer16 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_per1 -> uart1 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart1 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_uart1_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> uart2 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart2 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_uart2_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> uart3 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart3 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_uart3_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> uart4 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart4 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_uart4_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> uart5 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart5 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_uart5_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per1 -> uart6 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart6 = {
-       .master         = &dra7xx_l4_per1_hwmod,
-       .slave          = &dra7xx_uart6_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per2 -> uart7 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart7 = {
-       .master         = &dra7xx_l4_per2_hwmod,
-       .slave          = &dra7xx_uart7_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l4_per1 -> des */
 static struct omap_hwmod_ocp_if dra7xx_l4_per1__des = {
        .master         = &dra7xx_l4_per1_hwmod,
@@ -3697,30 +2902,6 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per1__des = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
-/* l4_per2 -> uart8 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart8 = {
-       .master         = &dra7xx_l4_per2_hwmod,
-       .slave          = &dra7xx_uart8_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per2 -> uart9 */
-static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart9 = {
-       .master         = &dra7xx_l4_per2_hwmod,
-       .slave          = &dra7xx_uart9_hwmod,
-       .clk            = "l3_iclk_div",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_wkup -> uart10 */
-static struct omap_hwmod_ocp_if dra7xx_l4_wkup__uart10 = {
-       .master         = &dra7xx_l4_wkup_hwmod,
-       .slave          = &dra7xx_uart10_hwmod,
-       .clk            = "wkupaon_iclk_mux",
-       .user           = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
 /* l4_per1 -> rng */
 static struct omap_hwmod_ocp_if dra7xx_l4_per1__rng = {
        .master         = &dra7xx_l4_per1_hwmod,
@@ -3866,21 +3047,8 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
        &dra7xx_l3_main_1__aes2,
        &dra7xx_l3_main_1__sha0,
        &dra7xx_l4_per1__elm,
-       &dra7xx_l4_wkup__gpio1,
-       &dra7xx_l4_per1__gpio2,
-       &dra7xx_l4_per1__gpio3,
-       &dra7xx_l4_per1__gpio4,
-       &dra7xx_l4_per1__gpio5,
-       &dra7xx_l4_per1__gpio6,
-       &dra7xx_l4_per1__gpio7,
-       &dra7xx_l4_per1__gpio8,
        &dra7xx_l3_main_1__gpmc,
        &dra7xx_l4_per1__hdq1w,
-       &dra7xx_l4_per1__i2c1,
-       &dra7xx_l4_per1__i2c2,
-       &dra7xx_l4_per1__i2c3,
-       &dra7xx_l4_per1__i2c4,
-       &dra7xx_l4_per1__i2c5,
        &dra7xx_l4_cfg__mailbox1,
        &dra7xx_l4_per3__mailbox2,
        &dra7xx_l4_per3__mailbox3,
@@ -3898,10 +3066,6 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
        &dra7xx_l4_per1__mcspi2,
        &dra7xx_l4_per1__mcspi3,
        &dra7xx_l4_per1__mcspi4,
-       &dra7xx_l4_per1__mmc1,
-       &dra7xx_l4_per1__mmc2,
-       &dra7xx_l4_per1__mmc3,
-       &dra7xx_l4_per1__mmc4,
        &dra7xx_l4_cfg__mpu,
        &dra7xx_l4_cfg__ocp2scp1,
        &dra7xx_l4_cfg__ocp2scp3,
@@ -3929,16 +3093,6 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
        &dra7xx_l4_per3__timer14,
        &dra7xx_l4_per3__timer15,
        &dra7xx_l4_per3__timer16,
-       &dra7xx_l4_per1__uart1,
-       &dra7xx_l4_per1__uart2,
-       &dra7xx_l4_per1__uart3,
-       &dra7xx_l4_per1__uart4,
-       &dra7xx_l4_per1__uart5,
-       &dra7xx_l4_per1__uart6,
-       &dra7xx_l4_per2__uart7,
-       &dra7xx_l4_per2__uart8,
-       &dra7xx_l4_per2__uart9,
-       &dra7xx_l4_wkup__uart10,
        &dra7xx_l4_per1__des,
        &dra7xx_l4_per3__usb_otg_ss1,
        &dra7xx_l4_per3__usb_otg_ss2,
index debcd88ab9712961ef911ff6d74cdc92a50e2e61..83230d9ce5edd91abc95aa2cb91aa87b0016cc94 100644 (file)
@@ -484,7 +484,6 @@ static struct omap_hwmod_class_sysconfig dm81xx_gpio_sysc = {
 static struct omap_hwmod_class dm81xx_gpio_hwmod_class = {
        .name   = "gpio",
        .sysc   = &dm81xx_gpio_sysc,
-       .rev    = 2,
 };
 
 static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
index 724cf5774a6cb403bdd06fa63f5d5acf388a4d89..f11442ed3efff29869be77daf7759f29f0cd1569 100644 (file)
 #include <asm/suspend.h>
 #include <linux/errno.h>
 #include <linux/platform_data/pm33xx.h>
+#include <linux/clk.h>
+#include <linux/platform_data/gpio-omap.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/wkup_m3_ipc.h>
+#include <linux/of.h>
+#include <linux/rtc.h>
 
 #include "cm33xx.h"
 #include "common.h"
@@ -38,6 +44,29 @@ static int am43xx_map_scu(void)
        return 0;
 }
 
+static int am33xx_check_off_mode_enable(void)
+{
+       if (enable_off_mode)
+               pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n");
+
+       /* off mode not supported on am335x so return 0 always */
+       return 0;
+}
+
+static int am43xx_check_off_mode_enable(void)
+{
+       /*
+        * Check for am437x-gp-evm which has the right Hardware design to
+        * support this mode reliably.
+        */
+       if (of_machine_is_compatible("ti,am437x-gp-evm") && enable_off_mode)
+               return enable_off_mode;
+       else if (enable_off_mode)
+               pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n");
+
+       return 0;
+}
+
 static int amx3_common_init(void)
 {
        gfx_pwrdm = pwrdm_lookup("gfx_pwrdm");
@@ -51,10 +80,12 @@ static int amx3_common_init(void)
 
        /* CEFUSE domain can be turned off post bootup */
        cefuse_pwrdm = pwrdm_lookup("cefuse_pwrdm");
-       if (cefuse_pwrdm)
-               omap_set_pwrdm_state(cefuse_pwrdm, PWRDM_POWER_OFF);
-       else
+       if (!cefuse_pwrdm)
                pr_err("PM: Failed to get cefuse_pwrdm\n");
+       else if (omap_type() != OMAP2_DEVICE_TYPE_GP)
+               pr_info("PM: Leaving EFUSE power domain active\n");
+       else
+               omap_set_pwrdm_state(cefuse_pwrdm, PWRDM_POWER_OFF);
 
        return 0;
 }
@@ -139,7 +170,9 @@ static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long),
        scu_power_mode(scu_base, SCU_PM_POWEROFF);
        ret = cpu_suspend(args, fn);
        scu_power_mode(scu_base, SCU_PM_NORMAL);
-       amx3_post_suspend_common();
+
+       if (!am43xx_check_off_mode_enable())
+               amx3_post_suspend_common();
 
        return ret;
 }
@@ -161,10 +194,48 @@ void __iomem *am43xx_get_rtc_base_addr(void)
        return omap_hwmod_get_mpu_rt_va(rtc_oh);
 }
 
+static void am43xx_save_context(void)
+{
+}
+
+static void am33xx_save_context(void)
+{
+       omap_intc_save_context();
+}
+
+static void am33xx_restore_context(void)
+{
+       omap_intc_restore_context();
+}
+
+static void am43xx_restore_context(void)
+{
+       /*
+        * HACK: restore dpll_per_clkdcoldo register contents, to avoid
+        * breaking suspend-resume
+        */
+       writel_relaxed(0x0, AM33XX_L4_WK_IO_ADDRESS(0x44df2e14));
+}
+
+static void am43xx_prepare_rtc_suspend(void)
+{
+       omap_hwmod_enable(rtc_oh);
+}
+
+static void am43xx_prepare_rtc_resume(void)
+{
+       omap_hwmod_idle(rtc_oh);
+}
+
 static struct am33xx_pm_platform_data am33xx_ops = {
        .init = am33xx_suspend_init,
        .soc_suspend = am33xx_suspend,
        .get_sram_addrs = amx3_get_sram_addrs,
+       .save_context = am33xx_save_context,
+       .restore_context = am33xx_restore_context,
+       .prepare_rtc_suspend = am43xx_prepare_rtc_suspend,
+       .prepare_rtc_resume = am43xx_prepare_rtc_resume,
+       .check_off_mode_enable = am33xx_check_off_mode_enable,
        .get_rtc_base_addr = am43xx_get_rtc_base_addr,
 };
 
@@ -172,6 +243,11 @@ static struct am33xx_pm_platform_data am43xx_ops = {
        .init = am43xx_suspend_init,
        .soc_suspend = am43xx_suspend,
        .get_sram_addrs = amx3_get_sram_addrs,
+       .save_context = am43xx_save_context,
+       .restore_context = am43xx_restore_context,
+       .prepare_rtc_suspend = am43xx_prepare_rtc_suspend,
+       .prepare_rtc_resume = am43xx_prepare_rtc_resume,
+       .check_off_mode_enable = am43xx_check_off_mode_enable,
        .get_rtc_base_addr = am43xx_get_rtc_base_addr,
 };
 
index 5b9343b58fc700de1738601ac091b5990061fb7a..0c1031442571ff3933789ba72068429782f1e144 100644 (file)
@@ -368,6 +368,9 @@ wait_emif_enable1:
        mov     r1, #AM43XX_EMIF_POWEROFF_DISABLE
        str     r1, [r2, #0x0]
 
+       ldr     r1, [r9, #EMIF_PM_RUN_HW_LEVELING]
+       blx     r1
+
 #ifdef CONFIG_CACHE_L2X0
        ldr     r2, l2_cache_base
        ldr     r0, [r2, #L2X0_CTRL]
index 0854ed9ff379804c3c41a7e4e275a9f231930ad1..248f6d9a1bb3f5d1cec287dd5176d773140c0c1b 100644 (file)
@@ -119,7 +119,10 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
        }
 
        sr_data->name = oh->name;
-       sr_data->ip_type = oh->class->rev;
+       if (cpu_is_omap343x())
+               sr_data->ip_type = 1;
+       else
+               sr_data->ip_type = 2;
        sr_data->senn_mod = 0x1;
        sr_data->senp_mod = 0x1;
 
index c67f92bfa30e4326fb3b1dda3ce221d52370ce1d..7bcb41137bbf6357d75aab7ea9059d9985fe7958 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/serial_8250.h>
index ffe05c27087e88340c40f3a302f87aae19e1d81e..1607deab52907cd78ef8a8e5b4a32ca45c50d904 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <linux/of.h>
index 4bcbd3d55b367108a372a4fcd95d6ff199473f1c..1f24e0259f997e0bbae524bc080a4134c69ca24b 100644 (file)
@@ -35,7 +35,7 @@
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
index e68acdd0cdbb1e7279c46a906074fc6372884f68..510625dde3cb8a7de7d56ce232e5e41f45c38344 100644 (file)
@@ -24,7 +24,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 #include <asm/mach-types.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include <mach/audio.h>
 #include "colibri.h"
index 6a5558d95d4e7b2d2606d7d5a042de5ff7eba4e1..2f635bdc797f51cbd551de0e2f86b8095c3fd2ff 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/interrupt.h>
 
 #include <asm/mach-types.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 
index 17067a3039a847c35acc233a8922ed938cef99f7..ffcefe6dbc82fa99feab2adb1855ca3013eaf1d9 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/usb/gpio_vbus.h>
 
 #include <asm/mach-types.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 
index e31a591e949f3914bea2205fed5a7b9cde05539d..0c88e4e417b4173b7474c9dd83655f7190a94ebf 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/etherdevice.h>
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/system_info.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
index 4764acca548007bb3944cc8dc27d8496cd7f5cc3..eb03283ccdeec454b4330d396cae7772f00fb7eb 100644 (file)
@@ -33,7 +33,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
index e9f401b0a4329847d175897c2d03f333bda9799f..5c03c4f7b82e4fb075536701defa14aaba37b2e4 100644 (file)
@@ -33,7 +33,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
index c1bd0d544981928254848eff8faf35cb4a49414d..825939877839d51944055ba23dd544fe51cbc0c3 100644 (file)
@@ -39,7 +39,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
index d6e17d407ac0c555912379441a946e15d2649b27..b3f8592eebe6f2b4051f117218500e35dee0f089 100644 (file)
@@ -40,7 +40,7 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
index c76f1daecfc95209c824bd39294451751485ddf3..99a2ee433f1fadfa01b5024827a2c7e0b19ea585 100644 (file)
@@ -35,7 +35,7 @@
 #include <asm/memory.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
index ab2f89266bbd44d1ebc8ff0e3018ae3a0dc09636..c4c25a2f24f64499463186c027ec3bcaed9c2236 100644 (file)
@@ -58,7 +58,7 @@
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/irq.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/system_info.h>
 
 #include <asm/mach/arch.h>
index 51984a40b097f1d7aa255e8028148f6c846dbcaa..4675d9202000b83cb36a476ae1f14b78ccf92784 100644 (file)
@@ -245,6 +245,7 @@ static int __init rockchip_smp_prepare_pmu(void)
        }
 
        pmu_base = of_iomap(node, 0);
+       of_node_put(node);
        if (!pmu_base) {
                pr_err("%s: could not map pmu registers\n", __func__);
                return -ENOMEM;
index 0592534e0b88c47c203686faafc8ba5650cd7d54..065b09e6f1eb73660eca3cd077700073d291b475 100644 (file)
@@ -59,7 +59,7 @@ static inline u32 rk3288_l2_config(void)
        return l2ctlr;
 }
 
-static void rk3288_config_bootdata(void)
+static void __init rk3288_config_bootdata(void)
 {
        rkpm_bootdata_cpusp = rk3288_bootram_phy + (SZ_4K - 8);
        rkpm_bootdata_cpu_code = __pa_symbol(cpu_resume);
@@ -230,7 +230,7 @@ static void rk3288_suspend_finish(void)
                pr_err("%s: Suspend finish failed\n", __func__);
 }
 
-static int rk3288_suspend_init(struct device_node *np)
+static int __init rk3288_suspend_init(struct device_node *np)
 {
        struct device_node *sram_np;
        struct resource res;
index e41cabc4dc2bbb3e5bc5cdd65075835e9eaf70a8..06ab03b93109e20b3194967e38f5459c482d1594 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/of_platform.h>
 #include <linux/irqchip.h>
 #include <linux/clk-provider.h>
index 1b2975708e3ffe48326c2a0628a26141e7f2d8ac..f28ac6c78d8229d73b65e7e6f4fc1e366ff6e7b9 100644 (file)
@@ -15,7 +15,7 @@ extern unsigned int s3c2410_modify_misccr(unsigned int clr, unsigned int chg);
 
 #endif /* __ASSEMBLY__ */
 
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <mach/map.h>
 
 #endif /* __ASM_ARCH_HARDWARE_H */
index 76c4855a03bce23b21a4f178e1a562c1e3511cc6..937d0a83f8fdc5a2b54886fb00eb2c7adbabeba5 100644 (file)
@@ -328,6 +328,8 @@ static const struct {
        int num_i2c_devs;
        const struct spi_board_info *spi_devs;
        int num_spi_devs;
+
+       struct gpiod_lookup_table *gpiod_table;
 } gf_mods[] = {
        { .id = 0x01, .rev = 0xff, .name = "1250-EV1 Springbank" },
        { .id = 0x02, .rev = 0xff, .name = "1251-EV1 Jura" },
@@ -362,13 +364,16 @@ static const struct {
          .i2c_devs = wm1255_devs, .num_i2c_devs = ARRAY_SIZE(wm1255_devs) },
        { .id = 0x3c, .rev = 0xff, .name = "1273-EV1 Longmorn" },
        { .id = 0x3d, .rev = 0xff, .name = "1277-EV1 Littlemill",
-         .i2c_devs = wm1277_devs, .num_i2c_devs = ARRAY_SIZE(wm1277_devs) },
+         .i2c_devs = wm1277_devs, .num_i2c_devs = ARRAY_SIZE(wm1277_devs),
+         .gpiod_table = &wm8994_gpiod_table },
        { .id = 0x3e, .rev = 0, .name = "WM5102-6271-EV1-CS127 Amrut",
          .spi_devs = wm5102_reva_spi_devs,
-         .num_spi_devs = ARRAY_SIZE(wm5102_reva_spi_devs) },
+         .num_spi_devs = ARRAY_SIZE(wm5102_reva_spi_devs),
+         .gpiod_table = &wm5102_reva_gpiod_table },
        { .id = 0x3e, .rev = -1, .name = "WM5102-6271-EV1-CS127 Amrut",
          .spi_devs = wm5102_spi_devs,
-         .num_spi_devs = ARRAY_SIZE(wm5102_spi_devs) },
+         .num_spi_devs = ARRAY_SIZE(wm5102_spi_devs),
+         .gpiod_table = &wm5102_gpiod_table },
        { .id = 0x3f, .rev = -1, .name = "WM2200-6271-CS90-M-REV1",
          .i2c_devs = wm2200_i2c, .num_i2c_devs = ARRAY_SIZE(wm2200_i2c) },
 };
@@ -408,6 +413,9 @@ static int wlf_gf_module_probe(struct i2c_client *i2c,
 
                spi_register_board_info(gf_mods[i].spi_devs,
                                        gf_mods[i].num_spi_devs);
+
+               if (gf_mods[i].gpiod_table)
+                       gpiod_add_lookup_table(gf_mods[i].gpiod_table);
        } else {
                dev_warn(&i2c->dev, "Unknown module ID 0x%x revision %d\n",
                         id, rev + 1);
index fa5cf474499295b1b718feaabb1980966fbb6f5c..3b19296f5062da6e1c01e36b35abad7a46e3f989 100644 (file)
@@ -8,7 +8,7 @@
 #ifndef __ASM_ARCH_MEMORY_H
 #define __ASM_ARCH_MEMORY_H
 
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 /*
  * Because of the wide memory address space between physical RAM banks on the
index eb60a71cf125a4b78c57e51bcbe5d55f53eb49c6..a671e4c994cfa315ea2b8025523abc9dbbf40ea5 100644 (file)
@@ -21,7 +21,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
 #include <asm/hardware/sa1111.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include <mach/hardware.h>
 #include <mach/assabet.h>
index 8c2a205915245a65a72db531b3aa26473e3a8db3..e84599dd96f1a2d2b83eaa2fba2dcc9528df0874 100644 (file)
@@ -72,6 +72,7 @@ void __init rcar_gen2_pm_init(void)
        }
 
        error = of_address_to_resource(np, 0, &res);
+       of_node_put(np);
        if (error) {
                pr_err("Failed to get smp-sram address: %d\n", error);
                return;
index dc526ef2e9b313b28afaf531497c6a3201deebe4..ee949255ced3f01ad4256b2b7bea3ba669006309 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * R-Car Generation 2 da9063/da9210 regulator quirk
+ * R-Car Generation 2 da9063(L)/da9210 regulator quirk
  *
  * Certain Gen2 development boards have an da9063 and one or more da9210
  * regulators. All of these regulators have their interrupt request lines
@@ -65,6 +65,7 @@ static struct i2c_msg da9210_msg = {
 
 static const struct of_device_id rcar_gen2_quirk_match[] = {
        { .compatible = "dlg,da9063", .data = &da9063_msg },
+       { .compatible = "dlg,da9063l", .data = &da9063_msg },
        { .compatible = "dlg,da9210", .data = &da9210_msg },
        {},
 };
@@ -147,6 +148,7 @@ static int __init rcar_gen2_regulator_quirk(void)
 
        if (!of_machine_is_compatible("renesas,koelsch") &&
            !of_machine_is_compatible("renesas,lager") &&
+           !of_machine_is_compatible("renesas,porter") &&
            !of_machine_is_compatible("renesas,stout") &&
            !of_machine_is_compatible("renesas,gose"))
                return -ENODEV;
@@ -210,7 +212,7 @@ static int __init rcar_gen2_regulator_quirk(void)
                goto err_free;
        }
 
-       pr_info("IRQ2 is asserted, installing da9063/da9210 regulator quirk\n");
+       pr_info("IRQ2 is asserted, installing regulator quirk\n");
 
        bus_register_notifier(&i2c_bus_type, &regulator_quirk_nb);
        return 0;
index 713c068b953fb36187512bdfc1e2906e929dcf89..651bdf4f9c9e418165ede6fe4ae630ca2490cbde 100644 (file)
@@ -4,6 +4,7 @@ menuconfig ARCH_STM32
        select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
        select ARM_GIC if ARCH_MULTI_V7
        select ARM_PSCI if ARCH_MULTI_V7
+       select ARM_AMBA
        select ARCH_HAS_RESET_CONTROLLER
        select CLKSRC_STM32
        select PINCTRL
@@ -18,22 +19,18 @@ if ARM_SINGLE_ARMV7M
 
 config MACH_STM32F429
        bool "STMicroelectronics STM32F429"
-       select ARM_AMBA
        default y
 
 config MACH_STM32F469
        bool "STMicroelectronics STM32F469"
-       select ARM_AMBA
        default y
 
 config MACH_STM32F746
        bool "STMicroelectronics STM32F746"
-       select ARM_AMBA
        default y
 
 config MACH_STM32F769
        bool "STMicroelectronics STM32F769"
-       select ARM_AMBA
        default y
 
 config MACH_STM32H743
index b4037b603897d62e15eeafb099c4ef1163328d29..239084cf8192d3b30c7e00fd0aa5c0bbb8c2a11b 100644 (file)
@@ -89,6 +89,7 @@ static bool sunxi_core_is_cortex_a15(unsigned int core, unsigned int cluster)
 {
        struct device_node *node;
        int cpu = cluster * SUNXI_CPUS_PER_CLUSTER + core;
+       bool is_compatible;
 
        node = of_cpu_device_node_get(cpu);
 
@@ -107,7 +108,9 @@ static bool sunxi_core_is_cortex_a15(unsigned int core, unsigned int cluster)
                return false;
        }
 
-       return of_device_is_compatible(node, "arm,cortex-a15");
+       is_compatible = of_device_is_compatible(node, "arm,cortex-a15");
+       of_node_put(node);
+       return is_compatible;
 }
 
 static int sunxi_cpu_power_switch_set(unsigned int cpu, unsigned int cluster,
index 8fb5088464db3dc932d367ff8272e303d1401b48..bdde9ef3aaa91c96f09f13b275b4622a89a9b19d 100644 (file)
@@ -50,6 +50,7 @@ static void __init sun6i_smp_prepare_cpus(unsigned int max_cpus)
        }
 
        prcm_membase = of_iomap(node, 0);
+       of_node_put(node);
        if (!prcm_membase) {
                pr_err("Couldn't map A31 PRCM registers\n");
                return;
@@ -63,6 +64,7 @@ static void __init sun6i_smp_prepare_cpus(unsigned int max_cpus)
        }
 
        cpucfg_membase = of_iomap(node, 0);
+       of_node_put(node);
        if (!cpucfg_membase)
                pr_err("Couldn't map A31 CPU config registers\n");
 
@@ -133,6 +135,7 @@ static void __init sun8i_smp_prepare_cpus(unsigned int max_cpus)
        }
 
        prcm_membase = of_iomap(node, 0);
+       of_node_put(node);
        if (!prcm_membase) {
                pr_err("Couldn't map A23 PRCM registers\n");
                return;
@@ -146,6 +149,7 @@ static void __init sun8i_smp_prepare_cpus(unsigned int max_cpus)
        }
 
        cpucfg_membase = of_iomap(node, 0);
+       of_node_put(node);
        if (!cpucfg_membase)
                pr_err("Couldn't map A23 CPU config registers\n");
 
index 7f3b83e0d324620a32949c42bef926bfb34e96db..3a06ba263e3450e1b8ee446729a71064c63af746 100644 (file)
@@ -2,7 +2,7 @@
 menuconfig ARCH_TEGRA
        bool "NVIDIA Tegra"
        depends on ARCH_MULTI_V7
-       select ARCH_SUPPORTS_TRUSTED_FOUNDATIONS
+       select ARCH_HAS_RESET_CONTROLLER
        select ARM_AMBA
        select ARM_GIC
        select CLKSRC_MMIO
@@ -10,8 +10,8 @@ menuconfig ARCH_TEGRA
        select HAVE_ARM_SCU if SMP
        select HAVE_ARM_TWD if SMP
        select PINCTRL
+       select PM
        select PM_OPP
-       select ARCH_HAS_RESET_CONTROLLER
        select RESET_CONTROLLER
        select SOC_BUS
        select ZONE_DMA if ARM_LPAE
index e3fbcfedf845937436011fd20325cbe073097fc3..43c695d83f03467eb89e316d29d213385a80b85d 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 
+#include <linux/firmware/trusted_foundations.h>
+
 #include <asm/cpuidle.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
@@ -46,7 +48,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev,
        tegra_set_cpu_in_lp2();
        cpu_pm_enter();
 
-       call_firmware_op(prepare_idle);
+       call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2);
 
        /* Do suspend by ourselves if the firmware does not implement it */
        if (call_firmware_op(do_idle, 0) == -ENOSYS)
index 3f24addd7972b9bb3ede7b79cf9983e781389956..6620d61b5ec532951d60e9b1f42fcbb918641036 100644 (file)
@@ -61,7 +61,8 @@ static struct cpuidle_driver tegra_idle_driver = {
                        .exit_latency     = 5000,
                        .target_residency = 10000,
                        .power_usage      = 0,
-                       .flags            = CPUIDLE_FLAG_COUPLED,
+                       .flags            = CPUIDLE_FLAG_COUPLED |
+                                           CPUIDLE_FLAG_TIMER_STOP,
                        .name             = "powered-down",
                        .desc             = "CPU power gated",
                },
@@ -136,12 +137,8 @@ static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
        if (tegra20_reset_cpu_1() || !tegra_cpu_rail_off_ready())
                return false;
 
-       tick_broadcast_enter();
-
        tegra_idle_lp2_last();
 
-       tick_broadcast_exit();
-
        if (cpu_online(1))
                tegra20_wake_cpu1_from_reset();
 
@@ -153,14 +150,10 @@ static bool tegra20_idle_enter_lp2_cpu_1(struct cpuidle_device *dev,
                                         struct cpuidle_driver *drv,
                                         int index)
 {
-       tick_broadcast_enter();
-
        cpu_suspend(0, tegra20_sleep_cpu_secondary_finish);
 
        tegra20_cpu_clear_resettable();
 
-       tick_broadcast_exit();
-
        return true;
 }
 #else
index c1417361e10ee55558ae5b7bc3bf946bb2a347fa..c8fe0447e3a93714ec8a090df332d9b7fcea3490 100644 (file)
@@ -56,6 +56,7 @@ static struct cpuidle_driver tegra_idle_driver = {
                        .exit_latency           = 2000,
                        .target_residency       = 2200,
                        .power_usage            = 0,
+                       .flags                  = CPUIDLE_FLAG_TIMER_STOP,
                        .name                   = "powered-down",
                        .desc                   = "CPU power gated",
                },
@@ -76,12 +77,8 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
                return false;
        }
 
-       tick_broadcast_enter();
-
        tegra_idle_lp2_last();
 
-       tick_broadcast_exit();
-
        return true;
 }
 
@@ -90,14 +87,10 @@ static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
                                        struct cpuidle_driver *drv,
                                        int index)
 {
-       tick_broadcast_enter();
-
        smp_wmb();
 
        cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
 
-       tick_broadcast_exit();
-
        return true;
 }
 #else
index 9bc291e76887aa42e71e504e39803a32cb94d00c..ba61db7fe533260868b0fdc11b64f9d42b6c7e5a 100644 (file)
@@ -20,7 +20,7 @@
 #define __MACH_TEGRA_IOMAP_H
 
 #include <asm/pgtable.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #define TEGRA_IRAM_BASE                        0x40000000
 #define TEGRA_IRAM_SIZE                        SZ_256K
 #define TEGRA_PMC_BASE                 0x7000E400
 #define TEGRA_PMC_SIZE                 SZ_256
 
-#define TEGRA_MC_BASE                  0x7000F000
-#define TEGRA_MC_SIZE                  SZ_1K
-
 #define TEGRA_EMC_BASE                 0x7000F400
 #define TEGRA_EMC_SIZE                 SZ_1K
 
-#define TEGRA114_MC_BASE               0x70019000
-#define TEGRA114_MC_SIZE               SZ_4K
-
 #define TEGRA_EMC0_BASE                        0x7001A000
 #define TEGRA_EMC0_SIZE                        SZ_2K
 
 #define TEGRA_EMC1_BASE                        0x7001A800
 #define TEGRA_EMC1_SIZE                        SZ_2K
 
-#define TEGRA124_MC_BASE               0x70019000
-#define TEGRA124_MC_SIZE               SZ_4K
-
 #define TEGRA124_EMC_BASE              0x7001B000
 #define TEGRA124_EMC_SIZE              SZ_2K
 
index e32e1742c9a11730bd287ecc93cd09f2c1b33f6d..6a7bb887585e71b1467ee0c30071b6fd7b8f76c1 100644 (file)
@@ -17,7 +17,7 @@
 #ifndef __MACH_TEGRA_IRAMMAP_H
 #define __MACH_TEGRA_IRAMMAP_H
 
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 /* The first 1K of IRAM is permanently reserved for the CPU reset handler */
 #define TEGRA_IRAM_RESET_HANDLER_OFFSET        0
index 1ad5719779b00ab1fa4ea5d6a1c2d944e5b7e0f0..1b0ade06f204e667847fa4e86452373b9fa7c53c 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/suspend.h>
 
+#include <linux/firmware/trusted_foundations.h>
+
 #include <soc/tegra/flowctrl.h>
 #include <soc/tegra/fuse.h>
 #include <soc/tegra/pm.h>
 #include <soc/tegra/pmc.h>
 
 #include <asm/cacheflush.h>
+#include <asm/firmware.h>
 #include <asm/idmap.h>
 #include <asm/proc-fns.h>
 #include <asm/smp_plat.h>
@@ -159,6 +162,28 @@ int tegra_cpu_do_idle(void)
 
 static int tegra_sleep_cpu(unsigned long v2p)
 {
+       /*
+        * L2 cache disabling using kernel API only allowed when all
+        * secondary CPU's are offline. Cache have to be disabled with
+        * MMU-on if cache maintenance is done via Trusted Foundations
+        * firmware. Note that CPUIDLE won't ever enter powergate on Tegra30
+        * if any of secondary CPU's is online and this is the LP2-idle
+        * code-path only for Tegra20/30.
+        */
+       if (trusted_foundations_registered())
+               outer_disable();
+
+       /*
+        * Note that besides of setting up CPU reset vector this firmware
+        * call may also do the following, depending on the FW version:
+        *  1) Disable L2. But this doesn't matter since we already
+        *     disabled the L2.
+        *  2) Disable D-cache. This need to be taken into account in
+        *     particular by the tegra_disable_clean_inv_dcache() which
+        *     shall avoid the re-disable.
+        */
+       call_firmware_op(prepare_idle, TF_PM_MODE_LP2);
+
        setup_mm_for_reboot();
        tegra_sleep_cpu_finish(v2p);
 
@@ -197,6 +222,14 @@ void tegra_idle_lp2_last(void)
 
        cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
 
+       /*
+        * Resume L2 cache if it wasn't re-enabled early during resume,
+        * which is the case for Tegra30 that has to re-enable the cache
+        * via firmware call. In other cases cache is already enabled and
+        * hence re-enabling is a no-op. This is always a no-op on Tegra114+.
+        */
+       outer_resume();
+
        restore_cpu_complex();
        cpu_cluster_pm_exit();
 }
@@ -215,6 +248,15 @@ enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
 
 static int tegra_sleep_core(unsigned long v2p)
 {
+       /*
+        * Cache have to be disabled with MMU-on if cache maintenance is done
+        * via Trusted Foundations firmware. This is a no-op on Tegra114+.
+        */
+       if (trusted_foundations_registered())
+               outer_disable();
+
+       call_firmware_op(prepare_idle, TF_PM_MODE_LP1);
+
        setup_mm_for_reboot();
        tegra_sleep_core_finish(v2p);
 
@@ -342,6 +384,14 @@ static int tegra_suspend_enter(suspend_state_t state)
 
        cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, tegra_sleep_func);
 
+       /*
+        * Resume L2 cache if it wasn't re-enabled early during resume,
+        * which is the case for Tegra30 that has to re-enable the cache
+        * via firmware call. In other cases cache is already enabled and
+        * hence re-enabling is a no-op.
+        */
+       outer_resume();
+
        switch (mode) {
        case TEGRA_SUSPEND_LP1:
                tegra_suspend_exit_lp1();
index e22ccf87eded394ff99df3187ddf5309f886fdc4..cd94d7c41fc0c8bab458ed0703a66449a14dccc3 100644 (file)
@@ -20,6 +20,7 @@
 #include <soc/tegra/flowctrl.h>
 #include <soc/tegra/fuse.h>
 
+#include <asm/assembler.h>
 #include <asm/asm-offsets.h>
 #include <asm/cache.h>
 
@@ -29,8 +30,6 @@
 
 #define PMC_SCRATCH41  0x140
 
-#define RESET_DATA(x)  ((TEGRA_RESET_##x)*4)
-
 #ifdef CONFIG_PM_SLEEP
 /*
  *     tegra_resume
@@ -78,6 +77,7 @@ ENTRY(tegra_resume)
        orr     r1, r1, #1
        str     r1, [r0]
 #endif
+       bl      tegra_resume_trusted_foundations
 
 #ifdef CONFIG_CACHE_L2X0
        /* L2 cache resume & re-enable */
@@ -90,6 +90,30 @@ end_ca9_scu_l2_resume:
 
        b       cpu_resume
 ENDPROC(tegra_resume)
+
+/*
+ *     tegra_resume_trusted_foundations
+ *
+ *       Trusted Foundations firmware initialization.
+ *
+ *     Doesn't return if firmware presents.
+ *     Corrupted registers: r1, r2
+ */
+ENTRY(tegra_resume_trusted_foundations)
+       /* Check whether Trusted Foundations firmware presents. */
+       mov32   r2, TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET
+       ldr     r1, =__tegra_cpu_reset_handler_data_offset + \
+                                                       RESET_DATA(TF_PRESENT)
+       ldr     r1, [r2, r1]
+       cmp     r1, #0
+       reteq   lr
+
+ .arch_extension sec
+       /* First call after suspend wakes firmware. No arguments required. */
+       smc     #0
+
+       b       cpu_resume
+ENDPROC(tegra_resume_trusted_foundations)
 #endif
 
        .align L1_CACHE_SHIFT
@@ -115,12 +139,19 @@ ENTRY(__tegra_cpu_reset_handler_start)
  *       must be position-independent.
  */
 
+       .arm
        .align L1_CACHE_SHIFT
 ENTRY(__tegra_cpu_reset_handler)
 
        cpsid   aif, 0x13                       @ SVC mode, interrupts disabled
 
        tegra_get_soc_id TEGRA_APB_MISC_BASE, r6
+
+       adr     r12, __tegra_cpu_reset_handler_data
+       ldr     r5, [r12, #RESET_DATA(TF_PRESENT)]
+       cmp     r5, #0
+       bne     after_errata
+
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
 t20_check:
        cmp     r6, #TEGRA20
@@ -155,7 +186,6 @@ after_errata:
        and     r10, r10, #0x3                  @ R10 = CPU number
        mov     r11, #1
        mov     r11, r11, lsl r10               @ R11 = CPU mask
-       adr     r12, __tegra_cpu_reset_handler_data
 
 #ifdef CONFIG_SMP
        /* Does the OS know about this CPU? */
@@ -169,10 +199,9 @@ after_errata:
        cmp     r6, #TEGRA20
        bne     1f
        /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
-       mov32   r5, TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET
        mov     r0, #CPU_NOT_RESETTABLE
        cmp     r10, #0
-       strbne  r0, [r5, #__tegra20_cpu1_resettable_status_offset]
+       strbne  r0, [r12, #RESET_DATA(RESETTABLE_STATUS)]
 1:
 #endif
 
@@ -277,14 +306,13 @@ ENDPROC(__tegra_cpu_reset_handler)
        .align L1_CACHE_SHIFT
        .type   __tegra_cpu_reset_handler_data, %object
        .globl  __tegra_cpu_reset_handler_data
+       .globl  __tegra_cpu_reset_handler_data_offset
+       .equ    __tegra_cpu_reset_handler_data_offset, \
+                                       . - __tegra_cpu_reset_handler_start
 __tegra_cpu_reset_handler_data:
-       .rept   TEGRA_RESET_DATA_SIZE
-       .long   0
+       .rept   TEGRA_RESET_DATA_SIZE
+       .long   0
        .endr
-       .globl  __tegra20_cpu1_resettable_status_offset
-       .equ    __tegra20_cpu1_resettable_status_offset, \
-                                       . - __tegra_cpu_reset_handler_start
-       .byte   0
        .align L1_CACHE_SHIFT
 
 ENTRY(__tegra_cpu_reset_handler_end)
index dc558892753c69c3c12829d27f03282f9ae1e49b..35dc5d419b6f2351b93c7af6b44097b4202d7bf1 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/init.h>
 #include <linux/io.h>
 
+#include <linux/firmware/trusted_foundations.h>
+
 #include <soc/tegra/fuse.h>
 
 #include <asm/cacheflush.h>
@@ -89,6 +91,8 @@ static void __init tegra_cpu_reset_handler_enable(void)
 
 void __init tegra_cpu_reset_handler_init(void)
 {
+       __tegra_cpu_reset_handler_data[TEGRA_RESET_TF_PRESENT] =
+               trusted_foundations_registered();
 
 #ifdef CONFIG_SMP
        __tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] =
index 9c479c7925b85fc3e72032bdd9385a51160dc0e0..db0e6b3097ab26a7e941f9766587e0d3f668273c 100644 (file)
 #define TEGRA_RESET_STARTUP_SECONDARY  3
 #define TEGRA_RESET_STARTUP_LP2                4
 #define TEGRA_RESET_STARTUP_LP1                5
-#define TEGRA_RESET_DATA_SIZE          6
+#define TEGRA_RESET_RESETTABLE_STATUS  6
+#define TEGRA_RESET_TF_PRESENT         7
+#define TEGRA_RESET_DATA_SIZE          8
+
+#define RESET_DATA(x)  ((TEGRA_RESET_##x)*4)
 
 #ifndef __ASSEMBLY__
 
@@ -49,7 +53,8 @@ void __tegra_cpu_reset_handler_end(void);
         (u32)__tegra_cpu_reset_handler_start)))
 #define tegra20_cpu1_resettable_status \
        (IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
-        (u32)__tegra20_cpu1_resettable_status_offset))
+       ((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_RESETTABLE_STATUS] - \
+        (u32)__tegra_cpu_reset_handler_start)))
 #endif
 
 #define tegra_cpu_reset_handler_offset \
index dedeebfccc55b45ba2b8d03d88aa5dd6d400263a..50d51d3465f6e0010848834fb8e273e222dd4472 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/cache.h>
 
 #include "irammap.h"
+#include "reset.h"
 #include "sleep.h"
 
 #define EMC_CFG                                0xc
@@ -53,6 +54,9 @@
 #define APB_MISC_XM2CFGCPADCTRL2       0x8e4
 #define APB_MISC_XM2CFGDPADCTRL2       0x8e8
 
+#define __tegra20_cpu1_resettable_status_offset \
+       (__tegra_cpu_reset_handler_data_offset + RESET_DATA(RESETTABLE_STATUS))
+
 .macro pll_enable, rd, r_car_base, pll_base
        ldr     \rd, [\r_car_base, #\pll_base]
        tst     \rd, #(1 << 30)
index d0b4c486ddbfaa1067d366c375675835910a1750..7727e005c30e38fa1938569dd884b32316392984 100644 (file)
@@ -44,8 +44,6 @@
 #define EMC_XM2VTTGENPADCTRL           0x310
 #define EMC_XM2VTTGENPADCTRL2          0x314
 
-#define MC_EMEM_ARB_CFG                        0x90
-
 #define PMC_CTRL                       0x0
 #define PMC_CTRL_SIDE_EFFECT_LP0 (1 << 14) /* enter LP0 when CPU pwr gated */
 
@@ -420,22 +418,6 @@ _pll_m_c_x_done:
        movweq  r0, #:lower16:TEGRA124_EMC_BASE
        movteq  r0, #:upper16:TEGRA124_EMC_BASE
 
-       cmp     r10, #TEGRA30
-       moveq   r2, #0x20
-       movweq  r4, #:lower16:TEGRA_MC_BASE
-       movteq  r4, #:upper16:TEGRA_MC_BASE
-       cmp     r10, #TEGRA114
-       moveq   r2, #0x34
-       movweq  r4, #:lower16:TEGRA114_MC_BASE
-       movteq  r4, #:upper16:TEGRA114_MC_BASE
-       cmp     r10, #TEGRA124
-       moveq   r2, #0x20
-       movweq  r4, #:lower16:TEGRA124_MC_BASE
-       movteq  r4, #:upper16:TEGRA124_MC_BASE
-
-       ldr     r1, [r5, r2]            @ restore MC_EMEM_ARB_CFG
-       str     r1, [r4, #MC_EMEM_ARB_CFG]
-
 exit_self_refresh:
        ldr     r1, [r5, #0xC]          @ restore EMC_XM2VTTGENPADCTRL
        str     r1, [r0, #EMC_XM2VTTGENPADCTRL]
@@ -564,7 +546,6 @@ tegra30_sdram_pad_address:
        .word   TEGRA_PMC_BASE + PMC_IO_DPD_STATUS                      @0x14
        .word   TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT     @0x18
        .word   TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST             @0x1c
-       .word   TEGRA_MC_BASE + MC_EMEM_ARB_CFG                         @0x20
 tegra30_sdram_pad_address_end:
 
 tegra114_sdram_pad_address:
@@ -581,7 +562,6 @@ tegra114_sdram_pad_address:
        .word   TEGRA_EMC1_BASE + EMC_AUTO_CAL_INTERVAL                 @0x28
        .word   TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL                  @0x2c
        .word   TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL2                 @0x30
-       .word   TEGRA114_MC_BASE + MC_EMEM_ARB_CFG                      @0x34
 tegra114_sdram_pad_adress_end:
 
 tegra124_sdram_pad_address:
@@ -593,7 +573,6 @@ tegra124_sdram_pad_address:
        .word   TEGRA_PMC_BASE + PMC_IO_DPD_STATUS                      @0x14
        .word   TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT     @0x18
        .word   TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST             @0x1c
-       .word   TEGRA124_MC_BASE + MC_EMEM_ARB_CFG                      @0x20
 tegra124_sdram_pad_address_end:
 
 tegra30_sdram_pad_size:
index 5e3496753df184a556f0143cfc357e58224d7803..1735ded5a81292cc5c1fbd40e632c3403c01eaec 100644 (file)
@@ -49,8 +49,9 @@ ENTRY(tegra_disable_clean_inv_dcache)
 
        /* Disable the D-cache */
        mrc     p15, 0, r2, c1, c0, 0
+       tst     r2, #CR_C                       @ see tegra_sleep_cpu()
        bic     r2, r2, #CR_C
-       mcr     p15, 0, r2, c1, c0, 0
+       mcrne   p15, 0, r2, c1, c0, 0
        isb
 
        /* Flush the D-cache */
@@ -132,10 +133,13 @@ ENTRY(tegra_shut_off_mmu)
 #ifdef CONFIG_CACHE_L2X0
        /* Disable L2 cache */
        check_cpu_part_num 0xc09, r9, r10
-       movweq  r2, #:lower16:(TEGRA_ARM_PERIF_BASE + 0x3000)
-       movteq  r2, #:upper16:(TEGRA_ARM_PERIF_BASE + 0x3000)
-       moveq   r3, #0
-       streq   r3, [r2, #L2X0_CTRL]
+       retne   r0
+
+       mov32   r2, TEGRA_ARM_PERIF_BASE + 0x3000
+       ldr     r3, [r2, #L2X0_CTRL]
+       tst     r3, #L2X0_CTRL_EN               @ see tegra_sleep_cpu()
+       mov     r3, #0
+       strne   r3, [r2, #L2X0_CTRL]
 #endif
        ret     r0
 ENDPROC(tegra_shut_off_mmu)
index f9587be482351fc463800f63253b767a55507a30..3e88f67dd5217965d3da344b6f9d51d59b8a50cf 100644 (file)
 #include <linux/sys_soc.h>
 #include <linux/usb/tegra_usb_phy.h>
 
+#include <linux/firmware/trusted_foundations.h>
+
 #include <soc/tegra/fuse.h>
 #include <soc/tegra/pmc.h>
 
+#include <asm/firmware.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
-#include <asm/trusted_foundations.h>
 
 #include "board.h"
 #include "common.h"
@@ -74,6 +76,7 @@ static void __init tegra_init_early(void)
 {
        of_register_trusted_foundations();
        tegra_cpu_reset_handler_init();
+       call_firmware_op(l2x0_init);
 }
 
 static void __init tegra_dt_init_irq(void)
index 595b574c2c50df7018f77172696fb7f0b5ef3b03..96ec72bd39283541f1a354a4ab375c73215b7193 100644 (file)
@@ -130,3 +130,5 @@ static int __init u300_init_boardpower(void)
 }
 
 device_initcall(u300_init_boardpower);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Linus Walleij");
index fe3c6265a466f5dcec13d54a5fa4fee1ef27e485..2e6555df538e65c18cb8b3d7c5d0fcba03a273a4 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <mach/map.h>
 
 #endif /* __ASM_ARCH_HARDWARE_H */
index 6aba9ebf80411d7f595ebce446c83856189d7283..7f634eaeaf1057e07728fd6c21b45af9d460bf97 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/cpumask.h>
 #include <linux/platform_device.h>
index 43f46aa7ef3351e6cc278d42ea8ab7d0dc861dcb..0a75058c11f36746b15fe53d5bb273afe394d4c8 100644 (file)
@@ -1577,31 +1577,21 @@ static int __arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma
                    void *cpu_addr, dma_addr_t dma_addr, size_t size,
                    unsigned long attrs)
 {
-       unsigned long uaddr = vma->vm_start;
-       unsigned long usize = vma->vm_end - vma->vm_start;
        struct page **pages = __iommu_get_pages(cpu_addr, attrs);
        unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
-       unsigned long off = vma->vm_pgoff;
+       int err;
 
        if (!pages)
                return -ENXIO;
 
-       if (off >= nr_pages || (usize >> PAGE_SHIFT) > nr_pages - off)
+       if (vma->vm_pgoff >= nr_pages)
                return -ENXIO;
 
-       pages += off;
-
-       do {
-               int ret = vm_insert_page(vma, uaddr, *pages++);
-               if (ret) {
-                       pr_err("Remapping memory failed: %d\n", ret);
-                       return ret;
-               }
-               uaddr += PAGE_SIZE;
-               usize -= PAGE_SIZE;
-       } while (usize > 0);
+       err = vm_map_pages(vma, pages, nr_pages);
+       if (err)
+               pr_err("Remapping memory failed: %d\n", err);
 
-       return 0;
+       return err;
 }
 static int arm_iommu_mmap_attrs(struct device *dev,
                struct vm_area_struct *vma, void *cpu_addr,
index c2daabbe0af05da23a469efe0ea2ed1a6eb2eb7b..be0b42937888d734aa386978d4ad57263bda874e 100644 (file)
@@ -182,21 +182,6 @@ int pfn_valid(unsigned long pfn)
 EXPORT_SYMBOL(pfn_valid);
 #endif
 
-#ifndef CONFIG_SPARSEMEM
-static void __init arm_memory_present(void)
-{
-}
-#else
-static void __init arm_memory_present(void)
-{
-       struct memblock_region *reg;
-
-       for_each_memblock(memory, reg)
-               memory_present(0, memblock_region_memory_base_pfn(reg),
-                              memblock_region_memory_end_pfn(reg));
-}
-#endif
-
 static bool arm_memblock_steal_permitted = true;
 
 phys_addr_t __init arm_memblock_steal(phys_addr_t size, phys_addr_t align)
@@ -293,7 +278,7 @@ void __init bootmem_init(void)
         * Sparsemem tries to allocate bootmem in memory_present(),
         * so must be done after the fixed reservations
         */
-       arm_memory_present();
+       memblocks_present();
 
        /*
         * sparse_init() needs the bootmem allocator up and running.
@@ -695,27 +680,14 @@ void free_initmem(void)
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-
-static int keep_initrd;
-
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       if (!keep_initrd) {
-               if (start == initrd_start)
-                       start = round_down(start, PAGE_SIZE);
-               if (end == initrd_end)
-                       end = round_up(end, PAGE_SIZE);
-
-               poison_init_mem((void *)start, PAGE_ALIGN(end) - start);
-               free_reserved_area((void *)start, (void *)end, -1, "initrd");
-       }
-}
+       if (start == initrd_start)
+               start = round_down(start, PAGE_SIZE);
+       if (end == initrd_end)
+               end = round_up(end, PAGE_SIZE);
 
-static int __init keepinitrd_setup(char *__unused)
-{
-       keep_initrd = 1;
-       return 1;
+       poison_init_mem((void *)start, PAGE_ALIGN(end) - start);
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
-
-__setup("keepinitrd", keepinitrd_setup);
 #endif
index f519199741837664df922fc60e31c42de8eab145..bf25f780c1c9ebad4b059e6b4607322378c4a063 100644 (file)
@@ -183,18 +183,12 @@ static int pxa_ssp_probe(struct platform_device *pdev)
 
 static int pxa_ssp_remove(struct platform_device *pdev)
 {
-       struct resource *res;
        struct ssp_device *ssp;
 
        ssp = platform_get_drvdata(pdev);
        if (ssp == NULL)
                return -ENODEV;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
-
-       clk_put(ssp->clk);
-
        mutex_lock(&ssp_lock);
        list_del(&ssp->node);
        mutex_unlock(&ssp_lock);
index 0393917eaa57aaf8cda4548b9a34a705be6c73a0..aaf479a9e92d17ab08294d7e96442d77dd37fcdd 100644 (file)
 425    common  io_uring_setup                  sys_io_uring_setup
 426    common  io_uring_enter                  sys_io_uring_enter
 427    common  io_uring_register               sys_io_uring_register
+428    common  open_tree                       sys_open_tree
+429    common  move_mount                      sys_move_mount
+430    common  fsopen                          sys_fsopen
+431    common  fsconfig                        sys_fsconfig
+432    common  fsmount                         sys_fsmount
+433    common  fspick                          sys_fspick
index f4efff9d3afbb68e6ae9d09f0b4cd3538bb66f63..fadf554d939176c99db0c6e7ac5a0f2acca70b4c 100644 (file)
@@ -10,12 +10,12 @@ obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
 ccflags-y := -fPIC -fno-common -fno-builtin -fno-stack-protector
 ccflags-y += -DDISABLE_BRANCH_PROFILING
 
-VDSO_LDFLAGS := -Wl,-Bsymbolic -Wl,--no-undefined -Wl,-soname=linux-vdso.so.1
-VDSO_LDFLAGS += -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
-VDSO_LDFLAGS += -nostdlib -shared
-VDSO_LDFLAGS += $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
-VDSO_LDFLAGS += $(call cc-ldoption, -Wl$(comma)--build-id)
-VDSO_LDFLAGS += $(call cc-ldoption, -fuse-ld=bfd)
+ldflags-y = -Bsymbolic --no-undefined -soname=linux-vdso.so.1 \
+           -z max-page-size=4096 -z common-page-size=4096 \
+           -nostdlib -shared \
+           $(call ld-option, --hash-style=sysv) \
+           $(call ld-option, --build-id) \
+           -T
 
 obj-$(CONFIG_VDSO) += vdso.o
 extra-$(CONFIG_VDSO) += vdso.lds
@@ -37,8 +37,8 @@ KCOV_INSTRUMENT := n
 $(obj)/vdso.o : $(obj)/vdso.so
 
 # Link rule for the .so file
-$(obj)/vdso.so.raw: $(src)/vdso.lds $(obj-vdso) FORCE
-       $(call if_changed,vdsold)
+$(obj)/vdso.so.raw: $(obj)/vdso.lds $(obj-vdso) FORCE
+       $(call if_changed,ld)
 
 $(obj)/vdso.so.dbg: $(obj)/vdso.so.raw $(obj)/vdsomunge FORCE
        $(call if_changed,vdsomunge)
@@ -48,11 +48,6 @@ $(obj)/%.so: OBJCOPYFLAGS := -S
 $(obj)/%.so: $(obj)/%.so.dbg FORCE
        $(call if_changed,objcopy)
 
-# Actual build commands
-quiet_cmd_vdsold = VDSO    $@
-      cmd_vdsold = $(CC) $(c_flags) $(VDSO_LDFLAGS) \
-                   -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@
-
 quiet_cmd_vdsomunge = MUNGE   $@
       cmd_vdsomunge = $(objtree)/$(obj)/vdsomunge $< $@
 
index e70a49fc8dcd1f8c13a260c91ace70a2e299393c..da2a7044a124df5f829615dddef11a6e4e2cc6c5 100644 (file)
@@ -70,8 +70,9 @@ unsigned long __pfn_to_mfn(unsigned long pfn)
                entry = rb_entry(n, struct xen_p2m_entry, rbnode_phys);
                if (entry->pfn <= pfn &&
                                entry->pfn + entry->nr_pages > pfn) {
+                       unsigned long mfn = entry->mfn + (pfn - entry->pfn);
                        read_unlock_irqrestore(&p2m_lock, irqflags);
-                       return entry->mfn + (pfn - entry->pfn);
+                       return mfn;
                }
                if (pfn < entry->pfn)
                        n = n->rb_left;
@@ -156,6 +157,7 @@ bool __set_phys_to_machine_multi(unsigned long pfn,
        rc = xen_add_phys_to_mach_entry(p2m_entry);
        if (rc < 0) {
                write_unlock_irqrestore(&p2m_lock, irqflags);
+               kfree(p2m_entry);
                return false;
        }
        write_unlock_irqrestore(&p2m_lock, irqflags);
index 3f957443f2869b3b32d803f19411be414d9a7420..4780eb7af842a188c4bc1f472909edf624b88ea8 100644 (file)
@@ -19,8 +19,9 @@ config ARM64
        select ARCH_HAS_FAST_MULTIPLIER
        select ARCH_HAS_FORTIFY_SOURCE
        select ARCH_HAS_GCOV_PROFILE_ALL
-       select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA
+       select ARCH_HAS_GIGANTIC_PAGE
        select ARCH_HAS_KCOV
+       select ARCH_HAS_KEEPINITRD
        select ARCH_HAS_MEMBARRIER_SYNC_CORE
        select ARCH_HAS_PTE_SPECIAL
        select ARCH_HAS_SETUP_DMA_OPS
@@ -59,6 +60,7 @@ config ARM64
        select ARCH_INLINE_SPIN_UNLOCK_BH if !PREEMPT
        select ARCH_INLINE_SPIN_UNLOCK_IRQ if !PREEMPT
        select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE if !PREEMPT
+       select ARCH_KEEP_MEMBLOCK
        select ARCH_USE_CMPXCHG_LOCKREF
        select ARCH_USE_QUEUED_RWLOCKS
        select ARCH_USE_QUEUED_SPINLOCKS
@@ -1339,6 +1341,7 @@ menu "ARMv8.3 architectural features"
 config ARM64_PTR_AUTH
        bool "Enable support for pointer authentication"
        default y
+       depends on !KVM || ARM64_VHE
        help
          Pointer authentication (part of the ARMv8.3 Extensions) provides
          instructions for signing and authenticating pointers against secret
@@ -1352,8 +1355,9 @@ config ARM64_PTR_AUTH
          context-switched along with the process.
 
          The feature is detected at runtime. If the feature is not present in
-         hardware it will not be advertised to userspace nor will it be
-         enabled.
+         hardware it will not be advertised to userspace/KVM guest nor will it
+         be enabled. However, KVM guest also require VHE mode and hence
+         CONFIG_ARM64_VHE=y option to use this feature.
 
 endmenu
 
index b5ca9c50876d9a23947dde5d7fe553104c9c0805..0f4d91824e4b9cee6102ceedcb8427bba9166618 100644 (file)
@@ -7,6 +7,11 @@ config ARCH_ACTIONS
        help
          This enables support for the Actions Semiconductor S900 SoC family.
 
+config ARCH_AGILEX
+       bool "Intel's Agilex SoCFPGA Family"
+       help
+         This enables support for Intel's Agilex SoCFPGA Family.
+
 config ARCH_SUNXI
        bool "Allwinner sunxi 64-bit SoC Family"
        select ARCH_HAS_RESET_CONTROLLER
index 5bc7533a12c7a297ce959b11cbe85c0815f5c167..f19b762c008d80c181377ff67825cf5d43ebebd5 100644 (file)
@@ -13,6 +13,7 @@ subdir-y += cavium
 subdir-y += exynos
 subdir-y += freescale
 subdir-y += hisilicon
+subdir-y += intel
 subdir-y += lg
 subdir-y += marvell
 subdir-y += mediatek
index 0b09171110994053aa8d5896e6587219f9d0a5ba..f6db0611cb85c48186d60cf460cb1fa5bc386977 100644 (file)
@@ -2,6 +2,7 @@
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-amarula-relic.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-bananapi-m64.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-nanopi-a64.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-oceanic-5205-5inmfd.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-olinuxino.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-orangepi-win.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pine64-lts.dtb
@@ -19,6 +20,8 @@ dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-pc2.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-prime.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-zero-plus.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-zero-plus2.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-beelink-gs1.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-orangepi-3.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-orangepi-lite2.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-orangepi-one-plus.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-pine-h64.dtb
index 6cb2b7f0c8173387f1914ab5b3f143494ad1523b..019ae09ea0fdd415d5898f63afa17b9a115b4feb 100644 (file)
                stdout-path = "serial0:115200n8";
        };
 
+       i2c {
+               compatible = "i2c-gpio";
+               sda-gpios = <&pio 4 13 GPIO_ACTIVE_HIGH>;
+               scl-gpios = <&pio 4 12 GPIO_ACTIVE_HIGH>;
+               i2c-gpio,delay-us = <5>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ov5640: camera@3c {
+                       compatible = "ovti,ov5640";
+                       reg = <0x3c>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&csi_mclk_pin>;
+                       clocks = <&ccu CLK_CSI_MCLK>;
+                       clock-names = "xclk";
+
+                       AVDD-supply = <&reg_aldo1>;
+                       DOVDD-supply = <&reg_dldo3>;
+                       DVDD-supply = <&reg_eldo3>;
+                       reset-gpios = <&pio 4 14 GPIO_ACTIVE_LOW>; /* CSI-RST-R: PE14 */
+                       powerdown-gpios = <&pio 4 15 GPIO_ACTIVE_HIGH>; /* CSI-STBY-R: PE15 */
+
+                       port {
+                               ov5640_ep: endpoint {
+                                       remote-endpoint = <&csi_ep>;
+                                       bus-width = <8>;
+                                       hsync-active = <1>; /* Active high */
+                                       vsync-active = <0>; /* Active low */
+                                       data-active = <1>;  /* Active high */
+                                       pclk-sample = <1>;  /* Rising */
+                               };
+                       };
+               };
+       };
+
        wifi_pwrseq: wifi-pwrseq {
                compatible = "mmc-pwrseq-simple";
                clocks = <&rtc 1>;
        };
 };
 
+&csi {
+       status = "okay";
+
+       port {
+               csi_ep: endpoint {
+                       remote-endpoint = <&ov5640_ep>;
+                       bus-width = <8>;
+                       hsync-active = <1>; /* Active high */
+                       vsync-active = <0>; /* Active low */
+                       data-active = <1>;  /* Active high */
+                       pclk-sample = <1>;  /* Rising */
+               };
+       };
+};
+
 &ehci0 {
        status = "okay";
 };
 
+&i2c0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c0_pins>;
+       status = "okay";
+
+       sensor@48 {
+               compatible = "st,stlm75";
+               reg = <0x48>;
+       };
+};
+
+&i2c0_pins {
+       bias-pull-up;
+};
+
 &mmc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&mmc1_pins>;
index 7793ebb5d2b83d8b7be5164e62d95bf984071bb2..0a56c0c23ba1b771e275c361d5b836a120658335 100644 (file)
 };
 
 &codec_analog {
-       hpvcc-supply = <&reg_eldo1>;
+       cpvdd-supply = <&reg_eldo1>;
        status = "okay";
 };
 
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-oceanic-5205-5inmfd.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-oceanic-5205-5inmfd.dts
new file mode 100644 (file)
index 0000000..6a21545
--- /dev/null
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2019 Oceanic Systems (UK) Ltd.
+ * Copyright (C) 2019 Amarula Solutions B.V.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+/dts-v1/;
+
+#include "sun50i-a64-sopine.dtsi"
+
+/ {
+       model = "Oceanic 5205 5inMFD";
+       compatible = "oceanic,5205-5inmfd", "allwinner,sun50i-a64";
+
+       aliases {
+               ethernet0 = &emac;
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+};
+
+&ehci0 {
+       status = "okay";
+};
+
+&emac {
+       pinctrl-names = "default";
+       pinctrl-0 = <&rgmii_pins>;
+       phy-mode = "rgmii";
+       phy-handle = <&ext_rgmii_phy>;
+       phy-supply = <&reg_dc1sw>;
+       allwinner,tx-delay-ps = <600>;
+       status = "okay";
+};
+
+&mdio {
+       ext_rgmii_phy: ethernet-phy@1 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <1>;
+       };
+};
+
+&ohci0 {
+       status = "okay";
+};
+
+&reg_dc1sw {
+       regulator-name = "vcc-phy";
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_pb_pins>;
+       status = "okay";
+};
+
+&usb_otg {
+       dr_mode = "host";
+       status = "okay";
+};
+
+&usbphy {
+       status = "okay";
+};
index c0b9cc7a6b3a11134a876a15560c47c60df2ff0d..b7ac6374b178d8a276d81c57bd7da9fc3d5c9e27 100644 (file)
@@ -80,7 +80,7 @@
 };
 
 &codec_analog {
-       hpvcc-supply = <&reg_eldo1>;
+       cpvdd-supply = <&reg_eldo1>;
        status = "okay";
 };
 
index d22736a624812daa2d165f106e2591198def37d8..2b6345db7dc099cdb6534f340e4e2fef12fe4f43 100644 (file)
@@ -94,7 +94,7 @@
 };
 
 &codec_analog {
-       hpvcc-supply = <&reg_eldo1>;
+       cpvdd-supply = <&reg_eldo1>;
        status = "okay";
 };
 
 
 &ehci0 {
        phys = <&usbphy 0>;
-       phy-names = "usb";
        status = "okay";
 };
 
 
 &ohci0 {
        phys = <&usbphy 0>;
-       phy-names = "usb";
        status = "okay";
 };
 
index d2651f284aa0d5dc2336a091ca464985848989a4..9d20e13f0c02b877a7649ddb29dc9725c798f2a0 100644 (file)
@@ -48,7 +48,7 @@
 #include <dt-bindings/gpio/gpio.h>
 
 &codec_analog {
-       hpvcc-supply = <&reg_eldo1>;
+       cpvdd-supply = <&reg_eldo1>;
 };
 
 &mmc0 {
index 7b7b14ba58e68436595633e4239bf6b76d0b8741..0ec46b969a75c3ad147666528337941deb4be700 100644 (file)
                serial0 = &uart0;
        };
 
+       backlight: backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm 0 50000 0>;
+               power-supply = <&reg_dcdc1>;
+               brightness-levels = <0 5 7 10 14 20 28 40 56 80 112>;
+               default-brightness-level = <5>;
+               enable-gpios = <&pio 3 23 GPIO_ACTIVE_HIGH>; /* PD23 */
+       };
+
        chosen {
                stdout-path = "serial0:115200n8";
 
        status = "okay";
 };
 
+&pwm {
+       status = "okay";
+};
+
 &r_rsb {
        status = "okay";
 
index e628d063931ba2106af08be383ba252bb5b5bf2f..8c5b521e6389dfc9e12c82f2adb92f455c84eaea 100644 (file)
                #size-cells = <1>;
                ranges;
 
-               de2@1000000 {
+               bus@1000000 {
                        compatible = "allwinner,sun50i-a64-de2";
                        reg = <0x1000000 0x400000>;
                        allwinner,sram = <&de2_sram 1>;
                                        #size-cells = <0>;
 
                                        mixer0_out: port@1 {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
                                                reg = <1>;
 
-                                               mixer0_out_tcon0: endpoint {
+                                               mixer0_out_tcon0: endpoint@0 {
+                                                       reg = <0>;
                                                        remote-endpoint = <&tcon0_in_mixer0>;
                                                };
+
+                                               mixer0_out_tcon1: endpoint@1 {
+                                                       reg = <1>;
+                                                       remote-endpoint = <&tcon1_in_mixer0>;
+                                               };
                                        };
                                };
                        };
                                        #size-cells = <0>;
 
                                        mixer1_out: port@1 {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
                                                reg = <1>;
 
-                                               mixer1_out_tcon1: endpoint {
+                                               mixer1_out_tcon0: endpoint@0 {
+                                                       reg = <0>;
+                                                       remote-endpoint = <&tcon0_in_mixer1>;
+                                               };
+
+                                               mixer1_out_tcon1: endpoint@1 {
+                                                       reg = <1>;
                                                        remote-endpoint = <&tcon1_in_mixer1>;
                                                };
                                        };
                        clocks = <&ccu CLK_BUS_TCON0>, <&ccu CLK_TCON0>;
                        clock-names = "ahb", "tcon-ch0";
                        clock-output-names = "tcon-pixel-clock";
+                       #clock-cells = <0>;
                        resets = <&ccu RST_BUS_TCON0>, <&ccu RST_BUS_LVDS>;
                        reset-names = "lcd", "lvds";
 
                                                reg = <0>;
                                                remote-endpoint = <&mixer0_out_tcon0>;
                                        };
+
+                                       tcon0_in_mixer1: endpoint@1 {
+                                               reg = <1>;
+                                               remote-endpoint = <&mixer1_out_tcon0>;
+                                       };
                                };
 
                                tcon0_out: port@1 {
                                #size-cells = <0>;
 
                                tcon1_in: port@0 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
                                        reg = <0>;
 
-                                       tcon1_in_mixer1: endpoint {
+                                       tcon1_in_mixer0: endpoint@0 {
+                                               reg = <0>;
+                                               remote-endpoint = <&mixer0_out_tcon1>;
+                                       };
+
+                                       tcon1_in_mixer1: endpoint@1 {
+                                               reg = <1>;
                                                remote-endpoint = <&mixer1_out_tcon1>;
                                        };
                                };
                        phys = <&usbphy 0>;
                        phy-names = "usb";
                        extcon = <&usbphy 0>;
+                       dr_mode = "otg";
                        status = "disabled";
                };
 
                        resets = <&ccu RST_BUS_OHCI1>,
                                 <&ccu RST_BUS_EHCI1>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                                 <&ccu CLK_USB_OHCI1>;
                        resets = <&ccu RST_BUS_OHCI1>;
                        phys = <&usbphy 1>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&ccu 58>;
+                       clocks = <&ccu 58>, <&osc24M>, <&rtc 0>;
+                       clock-names = "apb", "hosc", "losc";
                        gpio-controller;
                        #gpio-cells = <3>;
                        interrupt-controller;
                                function = "csi";
                        };
 
-                       i2c0_pins: i2c0_pins {
+                       /omit-if-no-ref/
+                       csi_mclk_pin: csi-mclk-pin {
+                               pins = "PE1";
+                               function = "csi";
+                       };
+
+                       i2c0_pins: i2c0-pins {
                                pins = "PH0", "PH1";
                                function = "i2c0";
                        };
 
-                       i2c1_pins: i2c1_pins {
+                       i2c1_pins: i2c1-pins {
                                pins = "PH2", "PH3";
                                function = "i2c1";
                        };
                                bias-pull-up;
                        };
 
-                       pwm_pin: pwm_pin {
+                       pwm_pin: pwm-pin {
                                pins = "PD22";
                                function = "pwm";
                        };
 
-                       rmii_pins: rmii_pins {
+                       rmii_pins: rmii-pins {
                                pins = "PD10", "PD11", "PD13", "PD14", "PD17",
                                       "PD18", "PD19", "PD20", "PD22", "PD23";
                                function = "emac";
                                drive-strength = <40>;
                        };
 
-                       rgmii_pins: rgmii_pins {
+                       rgmii_pins: rgmii-pins {
                                pins = "PD8", "PD9", "PD10", "PD11", "PD12",
                                       "PD13", "PD15", "PD16", "PD17", "PD18",
                                       "PD19", "PD20", "PD21", "PD22", "PD23";
                                drive-strength = <40>;
                        };
 
-                       spdif_tx_pin: spdif {
+                       spdif_tx_pin: spdif-tx-pin {
                                pins = "PH8";
                                function = "spdif";
                        };
 
-                       spi0_pins: spi0 {
+                       spi0_pins: spi0-pins {
                                pins = "PC0", "PC1", "PC2", "PC3";
                                function = "spi0";
                        };
 
-                       spi1_pins: spi1 {
+                       spi1_pins: spi1-pins {
                                pins = "PD0", "PD1", "PD2", "PD3";
                                function = "spi1";
                        };
                                function = "uart0";
                        };
 
-                       uart1_pins: uart1_pins {
+                       uart1_pins: uart1-pins {
                                pins = "PG6", "PG7";
                                function = "uart1";
                        };
 
-                       uart1_rts_cts_pins: uart1_rts_cts_pins {
+                       uart1_rts_cts_pins: uart1-rts-cts-pins {
                                pins = "PG8", "PG9";
                                function = "uart1";
                        };
                        clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
                        clock-names = "apb", "mod";
                        resets = <&ccu RST_BUS_CODEC>;
-                       reset-names = "rst";
                        dmas = <&dma 15>, <&dma 15>;
                        dma-names = "rx", "tx";
                        status = "disabled";
                                function = "s_i2c";
                        };
 
-                       r_pwm_pin: pwm {
+                       r_pwm_pin: r-pwm-pin {
                                pins = "PL10";
                                function = "s_pwm";
                        };
 
-                       r_rsb_pins: rsb {
+                       r_rsb_pins: r-rsb-pins {
                                pins = "PL0", "PL1";
                                function = "s_rsb";
                        };
index 85e7993a74e7cf27a3fc387d65490902e9506a65..62409afbaf06f5032fb69a8e5e54bcc2d3324e9c 100644 (file)
@@ -46,7 +46,6 @@
 
        vdd_cpux: gpio-regulator {
                compatible = "regulator-gpio";
-               pinctrl-names = "default";
                regulator-name = "vdd-cpux";
                regulator-type = "voltage";
                regulator-boot-on;
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index e4d50373c8ef12d62fb8fd6defd243b078566cc1..82f4b44d525f54f4bada369f97ed0b152b3180f4 100644 (file)
@@ -21,7 +21,6 @@
 
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
-               pinctrl-names = "default";
                reset-gpios = <&pio 2 7 GPIO_ACTIVE_LOW>; /* PC7 */
                post-power-on-delay-ms = <200>;
        };
index 506e25ba028abc9c0b3c73b67622a8be9bf0df96..9887948d5c8608451008a3ecf34a9cb00eb43f61 100644 (file)
@@ -78,7 +78,6 @@
 
        reg_gmac_3v3: gmac-3v3 {
                compatible = "regulator-fixed";
-               pinctrl-names = "default";
                regulator-name = "gmac-3v3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
@@ -96,7 +95,6 @@
 
        vdd_cpux: gpio-regulator {
                compatible = "regulator-gpio";
-               pinctrl-names = "default";
                regulator-name = "vdd-cpux";
                regulator-type = "voltage";
                regulator-boot-on;
 
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
-               pinctrl-names = "default";
                reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
                post-power-on-delay-ms = <200>;
        };
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index cc268a69786c532f46e9d8d1ae81e9eadc24c2d0..57a6f45036c1faf26d5d85251ee9679cdee9cc9c 100644 (file)
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index 3e0d5a9c096d37cdc878d07aadb79cee4009b972..e126c1c9f05ced2830729ca289a96fabe1952d45 100644 (file)
 
 &ir {
        pinctrl-names = "default";
-       pinctrl-0 = <&ir_pins_a>;
+       pinctrl-0 = <&r_ir_rx_pin>;
        status = "okay";
 };
 
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index b75ca4d7d00199b7972718a6dd55306ecfc01933..d9b3ed257088a3e20a29e1fd0bd29f7c7fd80003 100644 (file)
 
 &ir {
        pinctrl-names = "default";
-       pinctrl-0 = <&ir_pins_a>;
+       pinctrl-0 = <&r_ir_rx_pin>;
        status = "okay";
 };
 
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index 1238de25a9691a8adc8d38f1a7011f8cf7fc72e7..db6ea7b58999b2d2159902e2c836c6c715b76b9c 100644 (file)
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index 53c8c11620e0e32cae0642990f2c6a4e314a8683..dacf6139952722a590f3f6da636b52ead3843bfc 100644 (file)
@@ -78,7 +78,6 @@
 
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
-               pinctrl-names = "default";
                reset-gpios = <&pio 0 9 GPIO_ACTIVE_LOW>; /* PA9 */
                post-power-on-delay-ms = <200>;
        };
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_pins_a>;
+       pinctrl-0 = <&uart0_pa_pins>;
        status = "okay";
 };
 
index 96acafd3a852bba72686442d9d6014572584bfbd..f002a496d7cbb649898f94a62f67db79455601e8 100644 (file)
 &rtc {
        compatible = "allwinner,sun50i-h5-rtc";
 };
+
+&sid {
+       compatible = "allwinner,sun50i-h5-sid";
+};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts
new file mode 100644 (file)
index 0000000..0dc33c9
--- /dev/null
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+/*
+ * Copyright (C) 2019 Clément Péron <peron.clem@gmail.com>
+ */
+
+/dts-v1/;
+
+#include "sun50i-h6.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       model = "Beelink GS1";
+       compatible = "azw,beelink-gs1", "allwinner,sun50i-h6";
+
+       aliases {
+               ethernet0 = &emac;
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       connector {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_con_in: endpoint {
+                               remote-endpoint = <&hdmi_out_con>;
+                       };
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               power {
+                       label = "beelink:white:power";
+                       gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */
+                       default-state = "on";
+               };
+       };
+
+       reg_vcc5v: vcc5v {
+               /* board wide 5V supply directly from the DC jack */
+               compatible = "regulator-fixed";
+               regulator-name = "vcc-5v";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+       };
+};
+
+&de {
+       status = "okay";
+};
+
+&ehci0 {
+       status = "okay";
+};
+
+&emac {
+       pinctrl-names = "default";
+       pinctrl-0 = <&ext_rgmii_pins>;
+       phy-mode = "rgmii";
+       phy-handle = <&ext_rgmii_phy>;
+       phy-supply = <&reg_aldo2>;
+       status = "okay";
+};
+
+&hdmi {
+       status = "okay";
+};
+
+&hdmi_out {
+       hdmi_out_con: endpoint {
+               remote-endpoint = <&hdmi_con_in>;
+       };
+};
+
+&mdio {
+       ext_rgmii_phy: ethernet-phy@1 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <1>;
+       };
+};
+
+&mmc0 {
+       vmmc-supply = <&reg_cldo1>;
+       cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
+       bus-width = <4>;
+       status = "okay";
+};
+
+&mmc2 {
+       vmmc-supply = <&reg_cldo1>;
+       vqmmc-supply = <&reg_bldo2>;
+       non-removable;
+       cap-mmc-hw-reset;
+       bus-width = <8>;
+       status = "okay";
+};
+
+&ohci0 {
+       status = "okay";
+};
+
+&pio {
+       vcc-pd-supply = <&reg_cldo1>;
+       vcc-pg-supply = <&reg_aldo1>;
+};
+
+&r_i2c {
+       status = "okay";
+
+       axp805: pmic@36 {
+               compatible = "x-powers,axp805", "x-powers,axp806";
+               reg = <0x36>;
+               interrupt-parent = <&r_intc>;
+               interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               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-pl";
+                       };
+
+                       reg_aldo2: aldo2 {
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc-ac200";
+                               regulator-enable-ramp-delay = <100000>;
+                       };
+
+                       reg_aldo3: aldo3 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc25-dram";
+                       };
+
+                       reg_bldo1: bldo1 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "vcc-bias-pll";
+                       };
+
+                       reg_bldo2: bldo2 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "vcc-efuse-pcie-hdmi-io";
+                       };
+
+                       reg_bldo3: bldo3 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "vcc-dcxoio";
+                       };
+
+                       bldo4 {
+                               /* unused */
+                       };
+
+                       reg_cldo1: cldo1 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc-3v3";
+                       };
+
+                       reg_cldo2: cldo2 {
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc-wifi-1";
+                       };
+
+                       reg_cldo3: cldo3 {
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc-wifi-2";
+                       };
+
+                       reg_dcdca: dcdca {
+                               regulator-always-on;
+                               regulator-min-microvolt = <810000>;
+                               regulator-max-microvolt = <1080000>;
+                               regulator-name = "vdd-cpu";
+                       };
+
+                       reg_dcdcc: dcdcc {
+                               regulator-min-microvolt = <810000>;
+                               regulator-max-microvolt = <1080000>;
+                               regulator-name = "vdd-gpu";
+                       };
+
+                       reg_dcdcd: dcdcd {
+                               regulator-always-on;
+                               regulator-min-microvolt = <960000>;
+                               regulator-max-microvolt = <960000>;
+                               regulator-name = "vdd-sys";
+                       };
+
+                       reg_dcdce: dcdce {
+                               regulator-always-on;
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-name = "vcc-dram";
+                       };
+
+                       sw {
+                               /* unused */
+                       };
+               };
+       };
+};
+
+&r_pio {
+       /*
+        * PL0 and PL1 are used for PMIC I2C
+        * don't enable the pl-supply else
+        * it will fail at boot
+        *
+        * vcc-pl-supply = <&reg_aldo1>;
+        */
+       vcc-pm-supply = <&reg_aldo1>;
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_ph_pins>;
+       status = "okay";
+};
+
+&usb2otg {
+       dr_mode = "host";
+       status = "okay";
+};
+
+&usb2phy {
+       usb0_vbus-supply = <&reg_vcc5v>;
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
new file mode 100644 (file)
index 0000000..17d4969
--- /dev/null
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+/*
+ * Copyright (C) 2019 Ondřej Jirman <megous@megous.com>
+ */
+
+/dts-v1/;
+
+#include "sun50i-h6.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       model = "OrangePi 3";
+       compatible = "xunlong,orangepi-3", "allwinner,sun50i-h6";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               power {
+                       label = "orangepi:red:power";
+                       gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */
+                       default-state = "on";
+               };
+
+               status {
+                       label = "orangepi:green:status";
+                       gpios = <&r_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */
+               };
+       };
+
+       reg_vcc5v: vcc5v {
+               /* board wide 5V supply directly from the DC jack */
+               compatible = "regulator-fixed";
+               regulator-name = "vcc-5v";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+       };
+};
+
+&cpu0 {
+       cpu-supply = <&reg_dcdca>;
+};
+
+&ehci0 {
+       status = "okay";
+};
+
+&ehci3 {
+       status = "okay";
+};
+
+&mmc0 {
+       vmmc-supply = <&reg_cldo1>;
+       cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+       bus-width = <4>;
+       status = "okay";
+};
+
+&ohci0 {
+       status = "okay";
+};
+
+&ohci3 {
+       status = "okay";
+};
+
+&pio {
+       vcc-pc-supply = <&reg_bldo2>;
+       vcc-pd-supply = <&reg_cldo1>;
+};
+
+&r_i2c {
+       status = "okay";
+
+       axp805: pmic@36 {
+               compatible = "x-powers,axp805", "x-powers,axp806";
+               reg = <0x36>;
+               interrupt-parent = <&r_intc>;
+               interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               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-pl-led-ir";
+                       };
+
+                       reg_aldo2: aldo2 {
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc33-audio-tv-ephy-mac";
+                       };
+
+                       /* ALDO3 is shorted to CLDO1 */
+                       reg_aldo3: aldo3 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc33-io-pd-emmc-sd-usb-uart-1";
+                       };
+
+                       reg_bldo1: bldo1 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "vcc18-dram-bias-pll";
+                       };
+
+                       reg_bldo2: bldo2 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "vcc-efuse-pcie-hdmi-pc";
+                       };
+
+                       bldo3 {
+                               /* unused */
+                       };
+
+                       bldo4 {
+                               /* unused */
+                       };
+
+                       reg_cldo1: cldo1 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc33-io-pd-emmc-sd-usb-uart-2";
+                       };
+
+                       cldo2 {
+                               /* unused */
+                       };
+
+                       cldo3 {
+                               /* unused */
+                       };
+
+                       reg_dcdca: dcdca {
+                               regulator-always-on;
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1160000>;
+                               regulator-name = "vdd-cpu";
+                       };
+
+                       reg_dcdcc: dcdcc {
+                               regulator-min-microvolt = <810000>;
+                               regulator-max-microvolt = <1080000>;
+                               regulator-name = "vdd-gpu";
+                       };
+
+                       reg_dcdcd: dcdcd {
+                               regulator-always-on;
+                               regulator-min-microvolt = <960000>;
+                               regulator-max-microvolt = <960000>;
+                               regulator-name = "vdd-sys";
+                       };
+
+                       reg_dcdce: dcdce {
+                               regulator-always-on;
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-name = "vcc-dram";
+                       };
+
+                       sw {
+                               /* unused */
+                       };
+               };
+       };
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_ph_pins>;
+       status = "okay";
+};
+
+&usb2otg {
+       /*
+        * This board doesn't have a controllable VBUS even though it
+        * does have an ID pin. Using it as anything but a USB host is
+        * unsafe.
+        */
+       dr_mode = "host";
+       status = "okay";
+};
+
+&usb2phy {
+       usb0_id_det-gpios = <&pio 2 15 GPIO_ACTIVE_HIGH>; /* PC15 */
+       usb0_vbus-supply = <&reg_vcc5v>;
+       usb3_vbus-supply = <&reg_vcc5v>;
+       status = "okay";
+};
index b2526dac2fcfab3c7473b6745a68ecff2b0ee22f..62e27948a3faed9d7ae7f022fedf2b1cd2cd6eb5 100644 (file)
@@ -56,8 +56,6 @@
 };
 
 &mmc0 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&mmc0_pins>;
        vmmc-supply = <&reg_cldo1>;
        cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
        bus-width = <4>;
index bdb8470fc8dc96925007922a0a6d8a1dd663d886..4802902e128f980d58baf7bbdd93094230840b30 100644 (file)
 };
 
 &mmc0 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&mmc0_pins>;
        vmmc-supply = <&reg_cldo1>;
        cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
        bus-width = <4>;
 };
 
 &mmc2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&mmc2_pins>;
        vmmc-supply = <&reg_cldo1>;
        vqmmc-supply = <&reg_bldo2>;
        non-removable;
index c9e861a50a63349355cf771e6450d68d46513236..16c5c3d0fd813bda73d3ac0c65c5827d7d035f95 100644 (file)
                #size-cells = <1>;
                ranges;
 
-               display-engine@1000000 {
+               bus@1000000 {
                        compatible = "allwinner,sun50i-h6-de3",
                                     "allwinner,sun50i-a64-de2";
                        reg = <0x1000000 0x400000>;
                        };
                };
 
+               video-codec@1c0e000 {
+                       compatible = "allwinner,sun50i-h6-video-engine";
+                       reg = <0x01c0e000 0x2000>;
+                       clocks = <&ccu CLK_BUS_VE>, <&ccu CLK_VE>,
+                                <&ccu CLK_MBUS_VE>;
+                       clock-names = "ahb", "mod", "ram";
+                       resets = <&ccu RST_BUS_VE>;
+                       interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+                       allwinner,sram = <&ve_sram 1>;
+               };
+
                syscon: syscon@3000000 {
                        compatible = "allwinner,sun50i-h6-system-control",
                                     "allwinner,sun50i-a64-system-control";
                        #reset-cells = <1>;
                };
 
+               sid: sid@3006000 {
+                       compatible = "allwinner,sun50i-h6-sid";
+                       reg = <0x03006000 0x400>;
+               };
+
                pio: pinctrl@300b000 {
                        compatible = "allwinner,sun50i-h6-pinctrl";
                        reg = <0x0300b000 0x400>;
                        interrupt-controller;
                        #interrupt-cells = <3>;
 
-                       ext_rgmii_pins: rgmii_pins {
+                       ext_rgmii_pins: rgmii-pins {
                                pins = "PD0", "PD1", "PD2", "PD3", "PD4",
                                       "PD5", "PD7", "PD8", "PD9", "PD10",
                                       "PD11", "PD12", "PD13", "PD19", "PD20";
                                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 = "PC1", "PC4", "PC5", "PC6",
                                       "PC7", "PC8", "PC9", "PC10",
                                bias-pull-up;
                        };
 
-                       uart0_ph_pins: uart0-ph {
+                       uart0_ph_pins: uart0-ph-pins {
                                pins = "PH0", "PH1";
                                function = "uart0";
                        };
                        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";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        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";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        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";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        resets = <&ccu RST_BUS_OHCI3>,
                                 <&ccu RST_BUS_EHCI3>;
                        phys = <&usb2phy 3>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                                 <&ccu CLK_USB_OHCI3>;
                        resets = <&ccu RST_BUS_OHCI3>;
                        phys = <&usb2phy 3>;
-                       phy-names = "usb";
                        status = "disabled";
                };
 
                        interrupt-controller;
                        #interrupt-cells = <3>;
 
-                       r_i2c_pins: r-i2c {
+                       r_i2c_pins: r-i2c-pins {
                                pins = "PL0", "PL1";
                                function = "s_i2c";
                        };
index a2cec6218211b6aad8ff5e1da84c6aee750ebd50..fe107ce115efd1d663de22fca85c7a23b211a275 100644 (file)
                };
 
                sysmgr: sysmgr@ffd12000 {
-                       compatible = "altr,sys-mgr", "syscon";
+                       compatible = "altr,sys-mgr-s10","altr,sys-mgr";
                        reg = <0xffd12000 0x228>;
                };
 
index 2e3863ee12b3e43be56d41bc7af86e87eac930f9..d037563ad21ca5f6f992bb2c5b7ef74628342a90 100644 (file)
 &mmc {
        status = "okay";
        cap-sd-highspeed;
+       cap-mmc-highspeed;
        broken-cd;
        bus-width = <4>;
 };
                #size-cells = <1>;
                compatible = "n25q00a";
                reg = <0>;
-               spi-max-frequency = <50000000>;
+               spi-max-frequency = <100000000>;
 
                m25p,fast-read;
                cdns,page-size = <256>;
index 0821fed4c0749bad166d92521c84d9440b3cbe29..e129c03ced140713c6d3ec3f59ff4327c73351bd 100644 (file)
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 dtb-$(CONFIG_ARCH_MESON) += meson-axg-s400.dtb
+dtb-$(CONFIG_ARCH_MESON) += meson-g12a-sei510.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-g12a-u200.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-g12a-x96-max.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nanopi-k2.dtb
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts
new file mode 100644 (file)
index 0000000..34b4058
--- /dev/null
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 BayLibre SAS. All rights reserved.
+ */
+
+/dts-v1/;
+
+#include "meson-g12a.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/meson-g12a-gpio.h>
+
+/ {
+       compatible = "seirobotics,sei510", "amlogic,g12a";
+       model = "SEI Robotics SEI510";
+
+       aliases {
+               serial0 = &uart_AO;
+       };
+
+       adc_keys {
+               compatible = "adc-keys";
+               io-channels = <&saradc 0>;
+               io-channel-names = "buttons";
+               keyup-threshold-microvolt = <1800000>;
+
+               button-onoff {
+                       label = "On/Off";
+                       linux,code = <KEY_POWER>;
+                       press-threshold-microvolt = <1700000>;
+               };
+       };
+
+       ao_5v: regulator-ao_5v {
+               compatible = "regulator-fixed";
+               regulator-name = "AO_5V";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&dc_in>;
+               regulator-always-on;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       cvbs-connector {
+               compatible = "composite-video-connector";
+
+               port {
+                       cvbs_connector_in: endpoint {
+                               remote-endpoint = <&cvbs_vdac_out>;
+                       };
+               };
+       };
+
+       dc_in: regulator-dc_in {
+               compatible = "regulator-fixed";
+               regulator-name = "DC_IN";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+       };
+
+       emmc_1v8: regulator-emmc_1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "EMMC_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vddao_3v3>;
+               regulator-always-on;
+       };
+
+       hdmi-connector {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_connector_in: endpoint {
+                               remote-endpoint = <&hdmi_tx_tmds_out>;
+                       };
+               };
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x40000000>;
+       };
+
+       reserved-memory {
+               /* TEE Reserved Memory */
+               bl32_reserved: bl32@5000000 {
+                       reg = <0x0 0x05300000 0x0 0x2000000>;
+                       no-map;
+               };
+       };
+
+       vddao_3v3: regulator-vddao_3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDAO_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&dc_in>;
+               regulator-always-on;
+       };
+
+       vddao_3v3_t: regultor-vddao_3v3_t {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDAO_3V3_T";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vddao_3v3>;
+               gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>;
+               enable-active-high;
+       };
+
+       vddio_ao1v8: regulator-vddio_ao1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDIO_AO1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vddao_3v3>;
+               regulator-always-on;
+       };
+};
+
+&cec_AO {
+       pinctrl-0 = <&cec_ao_a_h_pins>;
+       pinctrl-names = "default";
+       status = "disabled";
+       hdmi-phandle = <&hdmi_tx>;
+};
+
+&cecb_AO {
+       pinctrl-0 = <&cec_ao_b_h_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+       hdmi-phandle = <&hdmi_tx>;
+};
+
+&cvbs_vdac_port {
+       cvbs_vdac_out: endpoint {
+               remote-endpoint = <&cvbs_connector_in>;
+       };
+};
+
+&saradc {
+       status = "okay";
+       vref-supply = <&vddio_ao1v8>;
+};
+
+&uart_A {
+       status = "okay";
+       pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
+       pinctrl-names = "default";
+       uart-has-rtscts;
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
+       };
+};
+
+&hdmi_tx {
+       status = "okay";
+       pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>;
+       pinctrl-names = "default";
+};
+
+&hdmi_tx_tmds_port {
+       hdmi_tx_tmds_out: endpoint {
+               remote-endpoint = <&hdmi_connector_in>;
+       };
+};
+
+&uart_AO {
+       status = "okay";
+       pinctrl-0 = <&uart_ao_a_pins>;
+       pinctrl-names = "default";
+};
+
+&usb {
+       status = "okay";
+       dr_mode = "host";
+};
index c44dbdddf2cf62360a43740c633d547b50a8ec58..0e8045b8a9158f4fc7d67d43f0dd6a6d35271bdb 100644 (file)
@@ -6,6 +6,8 @@
 /dts-v1/;
 
 #include "meson-g12a.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/gpio/meson-g12a-gpio.h>
 
 / {
        compatible = "amlogic,u200", "amlogic,g12a";
                device_type = "memory";
                reg = <0x0 0x0 0x0 0x40000000>;
        };
+
+       cvbs-connector {
+               compatible = "composite-video-connector";
+
+               port {
+                       cvbs_connector_in: endpoint {
+                               remote-endpoint = <&cvbs_vdac_out>;
+                       };
+               };
+       };
+
+       flash_1v8: regulator-flash_1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "FLASH_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vcc_3v3>;
+               regulator-always-on;
+       };
+
+       hdmi-connector {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_connector_in: endpoint {
+                               remote-endpoint = <&hdmi_tx_tmds_out>;
+                       };
+               };
+       };
+
+       main_12v: regulator-main_12v {
+               compatible = "regulator-fixed";
+               regulator-name = "12V";
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+               regulator-always-on;
+       };
+
+       vcc_1v8: regulator-vcc_1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vcc_3v3>;
+               regulator-always-on;
+       };
+
+       vcc_3v3: regulator-vcc_3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vddao_3v3>;
+               regulator-always-on;
+               /* FIXME: actually controlled by VDDCPU_B_EN */
+       };
+
+       vcc_5v: regulator-vcc_5v {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC_5V";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&main_12v>;
+
+               gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>;
+               enable-active-high;
+       };
+
+       usb_pwr_en: regulator-usb_pwr_en {
+               compatible = "regulator-fixed";
+               regulator-name = "USB_PWR_EN";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc_5v>;
+
+               gpio = <&gpio GPIOH_6 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       vddao_1v8: regulator-vddao_1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDAO_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vddao_3v3>;
+               regulator-always-on;
+       };
+
+       vddao_3v3: regulator-vddao_3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDAO_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&main_12v>;
+               regulator-always-on;
+       };
+
+};
+
+&cec_AO {
+       pinctrl-0 = <&cec_ao_a_h_pins>;
+       pinctrl-names = "default";
+       status = "disabled";
+       hdmi-phandle = <&hdmi_tx>;
+};
+
+&cecb_AO {
+       pinctrl-0 = <&cec_ao_b_h_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+       hdmi-phandle = <&hdmi_tx>;
+};
+
+&cvbs_vdac_port {
+       cvbs_vdac_out: endpoint {
+               remote-endpoint = <&cvbs_connector_in>;
+       };
+};
+
+&hdmi_tx {
+       status = "okay";
+       pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>;
+       pinctrl-names = "default";
+       hdmi-supply = <&vcc_5v>;
+};
+
+&hdmi_tx_tmds_port {
+       hdmi_tx_tmds_out: endpoint {
+               remote-endpoint = <&hdmi_connector_in>;
+       };
 };
 
 &uart_AO {
        status = "okay";
+       pinctrl-0 = <&uart_ao_a_pins>;
+       pinctrl-names = "default";
 };
 
+&usb {
+       status = "okay";
+       vbus-supply = <&usb_pwr_en>;
+};
+
+&usb2_phy0 {
+       phy-supply = <&vcc_5v>;
+};
+
+&usb2_phy1 {
+       phy-supply = <&vcc_5v>;
+};
index c62d3d5706ff17f93826d54603f3da8e2149e244..b3d913f28f1211785cb4ba0940fa641ce7cd5219 100644 (file)
@@ -6,6 +6,8 @@
 /dts-v1/;
 
 #include "meson-g12a.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/gpio/meson-g12a-gpio.h>
 
 / {
        compatible = "amediatech,x96-max", "amlogic,u200", "amlogic,g12a";
                device_type = "memory";
                reg = <0x0 0x0 0x0 0x40000000>;
        };
+
+       cvbs-connector {
+               compatible = "composite-video-connector";
+
+               port {
+                       cvbs_connector_in: endpoint {
+                               remote-endpoint = <&cvbs_vdac_out>;
+                       };
+               };
+       };
+
+       hdmi-connector {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_connector_in: endpoint {
+                               remote-endpoint = <&hdmi_tx_tmds_out>;
+                       };
+               };
+       };
+
+       flash_1v8: regulator-flash_1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "FLASH_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vcc_3v3>;
+               regulator-always-on;
+       };
+
+       dc_in: regulator-dc_in {
+               compatible = "regulator-fixed";
+               regulator-name = "DC_IN";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+       };
+
+       vcc_1v8: regulator-vcc_1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vcc_3v3>;
+               regulator-always-on;
+       };
+
+       vcc_3v3: regulator-vcc_3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vddao_3v3>;
+               regulator-always-on;
+               /* FIXME: actually controlled by VDDCPU_B_EN */
+       };
+
+       vcc_5v: regulator-vcc_5v {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC_5V";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&dc_in>;
+
+               gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>;
+               enable-active-low;
+       };
+
+       vddao_1v8: regulator-vddao_1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDAO_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vddao_3v3>;
+               regulator-always-on;
+       };
+
+       vddao_3v3: regulator-vddao_3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDAO_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&dc_in>;
+               regulator-always-on;
+       };
+};
+
+&cec_AO {
+       pinctrl-0 = <&cec_ao_a_h_pins>;
+       pinctrl-names = "default";
+       status = "disabled";
+       hdmi-phandle = <&hdmi_tx>;
+};
+
+&cecb_AO {
+       pinctrl-0 = <&cec_ao_b_h_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+       hdmi-phandle = <&hdmi_tx>;
+};
+
+&cvbs_vdac_port {
+       cvbs_vdac_out: endpoint {
+               remote-endpoint = <&cvbs_connector_in>;
+       };
+};
+
+&hdmi_tx {
+       status = "okay";
+       pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>;
+       pinctrl-names = "default";
+       hdmi-supply = <&vcc_5v>;
+};
+
+&hdmi_tx_tmds_port {
+       hdmi_tx_tmds_out: endpoint {
+               remote-endpoint = <&hdmi_connector_in>;
+       };
+};
+
+&uart_A {
+       status = "okay";
+       pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
+       pinctrl-names = "default";
+       uart-has-rtscts;
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
+       };
 };
 
 &uart_AO {
        status = "okay";
+       pinctrl-0 = <&uart_ao_a_pins>;
+       pinctrl-names = "default";
+};
+
+&usb {
+       status = "okay";
+       dr_mode = "host";
 };
index 17c6217f8a849ad14490b92fae5b3d3eec5a7a61..9f72396ba7103dcea37f8b13ce2b6f410d4ae2ec 100644 (file)
@@ -3,9 +3,13 @@
  * Copyright (c) 2018 Amlogic, Inc. All rights reserved.
  */
 
+#include <dt-bindings/phy/phy.h>
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/g12a-clkc.h>
+#include <dt-bindings/clock/g12a-aoclkc.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/reset/amlogic,meson-g12a-reset.h>
 
 / {
        compatible = "amlogic,g12a";
                };
        };
 
+       efuse: efuse {
+               compatible = "amlogic,meson-gxbb-efuse";
+               clocks = <&clkc CLKID_EFUSE>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               read-only;
+       };
+
        psci {
                compatible = "arm,psci-1.0";
                method = "smc";
                        reg = <0x0 0x05000000 0x0 0x300000>;
                        no-map;
                };
+
+               linux,cma {
+                       compatible = "shared-dma-pool";
+                       reusable;
+                       size = <0x0 0x10000000>;
+                       alignment = <0x0 0x400000>;
+                       linux,cma-default;
+               };
+       };
+
+       sm: secure-monitor {
+               compatible = "amlogic,meson-gxbb-sm";
        };
 
        soc {
                        #size-cells = <2>;
                        ranges = <0x0 0x0 0x0 0xff600000 0x0 0x200000>;
 
+                       hdmi_tx: hdmi-tx@0 {
+                               compatible = "amlogic,meson-g12a-dw-hdmi";
+                               reg = <0x0 0x0 0x0 0x10000>;
+                               interrupts = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>;
+                               resets = <&reset RESET_HDMITX_CAPB3>,
+                                        <&reset RESET_HDMITX_PHY>,
+                                        <&reset RESET_HDMITX>;
+                               reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy";
+                               clocks = <&clkc CLKID_HDMI>,
+                                        <&clkc CLKID_HTX_PCLK>,
+                                        <&clkc CLKID_VPU_INTR>;
+                               clock-names = "isfr", "iahb", "venci";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+
+                               /* VPU VENC Input */
+                               hdmi_tx_venc_port: port@0 {
+                                       reg = <0>;
+
+                                       hdmi_tx_in: endpoint {
+                                               remote-endpoint = <&hdmi_tx_out>;
+                                       };
+                               };
+
+                               /* TMDS Output */
+                               hdmi_tx_tmds_port: port@1 {
+                                       reg = <1>;
+                               };
+                       };
+
                        periphs: bus@34400 {
                                compatible = "simple-bus";
                                reg = <0x0 0x34400 0x0 0x400>;
                                #address-cells = <2>;
                                #size-cells = <2>;
                                ranges = <0x0 0x0 0x0 0x34400 0x0 0x400>;
+
+                               periphs_pinctrl: pinctrl@40 {
+                                       compatible = "amlogic,meson-g12a-periphs-pinctrl";
+                                       #address-cells = <2>;
+                                       #size-cells = <2>;
+                                       ranges;
+
+                                       gpio: bank@40 {
+                                               reg = <0x0 0x40  0x0 0x4c>,
+                                                     <0x0 0xe8  0x0 0x18>,
+                                                     <0x0 0x120 0x0 0x18>,
+                                                     <0x0 0x2c0 0x0 0x40>,
+                                                     <0x0 0x340 0x0 0x1c>;
+                                               reg-names = "gpio",
+                                                           "pull",
+                                                           "pull-enable",
+                                                           "mux",
+                                                           "ds";
+                                               gpio-controller;
+                                               #gpio-cells = <2>;
+                                               gpio-ranges = <&periphs_pinctrl 0 0 86>;
+                                       };
+
+                                       cec_ao_a_h_pins: cec_ao_a_h {
+                                               mux {
+                                                       groups = "cec_ao_a_h";
+                                                       function = "cec_ao_a_h";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       cec_ao_b_h_pins: cec_ao_b_h {
+                                               mux {
+                                                       groups = "cec_ao_b_h";
+                                                       function = "cec_ao_b_h";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       hdmitx_ddc_pins: hdmitx_ddc {
+                                               mux {
+                                                       groups = "hdmitx_sda",
+                                                                "hdmitx_sck";
+                                                       function = "hdmitx";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       hdmitx_hpd_pins: hdmitx_hpd {
+                                               mux {
+                                                       groups = "hdmitx_hpd_in";
+                                                       function = "hdmitx";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       uart_a_pins: uart-a {
+                                               mux {
+                                                       groups = "uart_a_tx",
+                                                                "uart_a_rx";
+                                                       function = "uart_a";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       uart_a_cts_rts_pins: uart-a-cts-rts {
+                                               mux {
+                                                       groups = "uart_a_cts",
+                                                                "uart_a_rts";
+                                                       function = "uart_a";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       uart_b_pins: uart-b {
+                                               mux {
+                                                       groups = "uart_b_tx",
+                                                                "uart_b_rx";
+                                                       function = "uart_b";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       uart_c_pins: uart-c {
+                                               mux {
+                                                       groups = "uart_c_tx",
+                                                                "uart_c_rx";
+                                                       function = "uart_c";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       uart_c_cts_rts_pins: uart-c-cts-rts {
+                                               mux {
+                                                       groups = "uart_c_cts",
+                                                                "uart_c_rts";
+                                                       function = "uart_c";
+                                                       bias-disable;
+                                               };
+                                       };
+                               };
+                       };
+
+                       usb2_phy0: phy@36000 {
+                               compatible = "amlogic,g12a-usb2-phy";
+                               reg = <0x0 0x36000 0x0 0x2000>;
+                               clocks = <&xtal>;
+                               clock-names = "xtal";
+                               resets = <&reset RESET_USB_PHY20>;
+                               reset-names = "phy";
+                               #phy-cells = <0>;
+                       };
+
+                       dmc: bus@38000 {
+                               compatible = "simple-bus";
+                               reg = <0x0 0x38000 0x0 0x400>;
+                               #address-cells = <2>;
+                               #size-cells = <2>;
+                               ranges = <0x0 0x0 0x0 0x38000 0x0 0x400>;
+
+                               canvas: video-lut@48 {
+                                       compatible = "amlogic,canvas";
+                                       reg = <0x0 0x48 0x0 0x14>;
+                               };
+                       };
+
+                       usb2_phy1: phy@3a000 {
+                               compatible = "amlogic,g12a-usb2-phy";
+                               reg = <0x0 0x3a000 0x0 0x2000>;
+                               clocks = <&xtal>;
+                               clock-names = "xtal";
+                               resets = <&reset RESET_USB_PHY21>;
+                               reset-names = "phy";
+                               #phy-cells = <0>;
                        };
 
                        hiu: bus@3c000 {
                                        };
                                };
                        };
+
+                       usb3_pcie_phy: phy@46000 {
+                               compatible = "amlogic,g12a-usb3-pcie-phy";
+                               reg = <0x0 0x46000 0x0 0x2000>;
+                               clocks = <&clkc CLKID_PCIE_PLL>;
+                               clock-names = "ref_clk";
+                               resets = <&reset RESET_PCIE_PHY>;
+                               reset-names = "phy";
+                               assigned-clocks = <&clkc CLKID_PCIE_PLL>;
+                               assigned-clock-rates = <100000000>;
+                               #phy-cells = <1>;
+                       };
                };
 
                aobus: bus@ff800000 {
                        #size-cells = <2>;
                        ranges = <0x0 0x0 0x0 0xff800000 0x0 0x100000>;
 
+                       rti: sys-ctrl@0 {
+                               compatible = "amlogic,meson-gx-ao-sysctrl",
+                                            "simple-mfd", "syscon";
+                               reg = <0x0 0x0 0x0 0x100>;
+                               #address-cells = <2>;
+                               #size-cells = <2>;
+                               ranges = <0x0 0x0 0x0 0x0 0x0 0x100>;
+
+                               clkc_AO: clock-controller {
+                                       compatible = "amlogic,meson-g12a-aoclkc";
+                                       #clock-cells = <1>;
+                                       #reset-cells = <1>;
+                                       clocks = <&xtal>, <&clkc CLKID_CLK81>;
+                                       clock-names = "xtal", "mpeg-clk";
+                               };
+
+                               pwrc_vpu: power-controller-vpu {
+                                       compatible = "amlogic,meson-g12a-pwrc-vpu";
+                                       #power-domain-cells = <0>;
+                                       amlogic,hhi-sysctrl = <&hhi>;
+                                       resets = <&reset RESET_VIU>,
+                                                <&reset RESET_VENC>,
+                                                <&reset RESET_VCBUS>,
+                                                <&reset RESET_BT656>,
+                                                <&reset RESET_RDMA>,
+                                                <&reset RESET_VENCI>,
+                                                <&reset RESET_VENCP>,
+                                                <&reset RESET_VDAC>,
+                                                <&reset RESET_VDI6>,
+                                                <&reset RESET_VENCL>,
+                                                <&reset RESET_VID_LOCK>;
+                                       clocks = <&clkc CLKID_VPU>,
+                                                <&clkc CLKID_VAPB>;
+                                       clock-names = "vpu", "vapb";
+                                       /*
+                                        * VPU clocking is provided by two identical clock paths
+                                        * VPU_0 and VPU_1 muxed to a single clock by a glitch
+                                        * free mux to safely change frequency while running.
+                                        * Same for VAPB but with a final gate after the glitch free mux.
+                                        */
+                                       assigned-clocks = <&clkc CLKID_VPU_0_SEL>,
+                                                         <&clkc CLKID_VPU_0>,
+                                                         <&clkc CLKID_VPU>, /* Glitch free mux */
+                                                         <&clkc CLKID_VAPB_0_SEL>,
+                                                         <&clkc CLKID_VAPB_0>,
+                                                         <&clkc CLKID_VAPB_SEL>; /* Glitch free mux */
+                                       assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>,
+                                                                <0>, /* Do Nothing */
+                                                                <&clkc CLKID_VPU_0>,
+                                                                <&clkc CLKID_FCLK_DIV4>,
+                                                                <0>, /* Do Nothing */
+                                                                <&clkc CLKID_VAPB_0>;
+                                       assigned-clock-rates = <0>, /* Do Nothing */
+                                                              <666666666>,
+                                                              <0>, /* Do Nothing */
+                                                              <0>, /* Do Nothing */
+                                                              <250000000>,
+                                                              <0>; /* Do Nothing */
+                               };
+
+                               ao_pinctrl: pinctrl@14 {
+                                       compatible = "amlogic,meson-g12a-aobus-pinctrl";
+                                       #address-cells = <2>;
+                                       #size-cells = <2>;
+                                       ranges;
+
+                                       gpio_ao: bank@14 {
+                                               reg = <0x0 0x14 0x0 0x8>,
+                                                     <0x0 0x1c 0x0 0x8>,
+                                                     <0x0 0x24 0x0 0x14>;
+                                               reg-names = "mux",
+                                                           "ds",
+                                                           "gpio";
+                                               gpio-controller;
+                                               #gpio-cells = <2>;
+                                               gpio-ranges = <&ao_pinctrl 0 0 15>;
+                                       };
+
+                                       uart_ao_a_pins: uart-a-ao {
+                                               mux {
+                                                       groups = "uart_ao_a_tx",
+                                                                "uart_ao_a_rx";
+                                                       function = "uart_ao_a";
+                                                       bias-disable;
+                                               };
+                                       };
+
+                                       uart_ao_a_cts_rts_pins: uart-ao-a-cts-rts {
+                                               mux {
+                                                       groups = "uart_ao_a_cts",
+                                                                "uart_ao_a_rts";
+                                                       function = "uart_ao_a";
+                                                       bias-disable;
+                                               };
+                                       };
+                               };
+                       };
+
+                       cec_AO: cec@100 {
+                               compatible = "amlogic,meson-gx-ao-cec";
+                               reg = <0x0 0x00100 0x0 0x14>;
+                               interrupts = <GIC_SPI 199 IRQ_TYPE_EDGE_RISING>;
+                               clocks = <&clkc_AO CLKID_AO_CEC>;
+                               clock-names = "core";
+                               status = "disabled";
+                       };
+
+                       sec_AO: ao-secure@140 {
+                               compatible = "amlogic,meson-gx-ao-secure", "syscon";
+                               reg = <0x0 0x140 0x0 0x140>;
+                               amlogic,has-chip-id;
+                       };
+
+                       cecb_AO: cec@280 {
+                               compatible = "amlogic,meson-g12a-ao-cec";
+                               reg = <0x0 0x00280 0x0 0x1c>;
+                               interrupts = <GIC_SPI 203 IRQ_TYPE_EDGE_RISING>;
+                               clocks = <&clkc_AO CLKID_AO_CTS_OSCIN>;
+                               clock-names = "oscin";
+                               status = "disabled";
+                       };
+
                        uart_AO: serial@3000 {
                                compatible = "amlogic,meson-gx-uart",
                                             "amlogic,meson-ao-uart";
                                clock-names = "xtal", "pclk", "baud";
                                status = "disabled";
                        };
+
+                       saradc: adc@9000 {
+                               compatible = "amlogic,meson-g12a-saradc",
+                                            "amlogic,meson-saradc";
+                               reg = <0x0 0x9000 0x0 0x48>;
+                               #io-channel-cells = <1>;
+                               interrupts = <GIC_SPI 200 IRQ_TYPE_EDGE_RISING>;
+                               clocks = <&xtal>,
+                                        <&clkc_AO CLKID_AO_SAR_ADC>,
+                                        <&clkc_AO CLKID_AO_SAR_ADC_CLK>,
+                                        <&clkc_AO CLKID_AO_SAR_ADC_SEL>;
+                               clock-names = "clkin", "core", "adc_clk", "adc_sel";
+                               status = "disabled";
+                       };
+               };
+
+               vpu: vpu@ff900000 {
+                       compatible = "amlogic,meson-g12a-vpu";
+                       reg = <0x0 0xff900000 0x0 0x100000>,
+                             <0x0 0xff63c000 0x0 0x1000>;
+                       reg-names = "vpu", "hhi";
+                       interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       amlogic,canvas = <&canvas>;
+                       power-domains = <&pwrc_vpu>;
+
+                       /* CVBS VDAC output port */
+                       cvbs_vdac_port: port@0 {
+                               reg = <0>;
+                       };
+
+                       /* HDMI-TX output port */
+                       hdmi_tx_port: port@1 {
+                               reg = <1>;
+
+                               hdmi_tx_out: endpoint {
+                                       remote-endpoint = <&hdmi_tx_in>;
+                               };
+                       };
                };
 
                gic: interrupt-controller@ffc01000 {
                        #size-cells = <2>;
                        ranges = <0x0 0x0 0x0 0xffd00000 0x0 0x100000>;
 
+                       reset: reset-controller@1004 {
+                               compatible = "amlogic,meson-g12a-reset",
+                                            "amlogic,meson-axg-reset";
+                               reg = <0x0 0x1004 0x0 0x9c>;
+                               #reset-cells = <1>;
+                       };
+
                        clk_msr: clock-measure@18000 {
                                compatible = "amlogic,meson-g12a-clk-measure";
                                reg = <0x0 0x18000 0x0 0x10>;
                        };
+
+                       uart_C: serial@22000 {
+                               compatible = "amlogic,meson-gx-uart";
+                               reg = <0x0 0x22000 0x0 0x18>;
+                               interrupts = <GIC_SPI 93 IRQ_TYPE_EDGE_RISING>;
+                               clocks = <&xtal>, <&clkc CLKID_UART2>, <&xtal>;
+                               clock-names = "xtal", "pclk", "baud";
+                               status = "disabled";
+                       };
+
+                       uart_B: serial@23000 {
+                               compatible = "amlogic,meson-gx-uart";
+                               reg = <0x0 0x23000 0x0 0x18>;
+                               interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>;
+                               clocks = <&xtal>, <&clkc CLKID_UART1>, <&xtal>;
+                               clock-names = "xtal", "pclk", "baud";
+                               status = "disabled";
+                       };
+
+                       uart_A: serial@24000 {
+                               compatible = "amlogic,meson-gx-uart";
+                               reg = <0x0 0x24000 0x0 0x18>;
+                               interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
+                               clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>;
+                               clock-names = "xtal", "pclk", "baud";
+                               status = "disabled";
+                       };
+               };
+
+               usb: usb@ffe09000 {
+                       status = "disabled";
+                       compatible = "amlogic,meson-g12a-usb-ctrl";
+                       reg = <0x0 0xffe09000 0x0 0xa0>;
+                       interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       clocks = <&clkc CLKID_USB>;
+                       resets = <&reset RESET_USB>;
+
+                       dr_mode = "otg";
+
+                       phys = <&usb2_phy0>, <&usb2_phy1>,
+                              <&usb3_pcie_phy PHY_TYPE_USB3>;
+                       phy-names = "usb2-phy0", "usb2-phy1", "usb3-phy0";
+
+                       dwc2: usb@ff400000 {
+                               compatible = "amlogic,meson-g12a-usb", "snps,dwc2";
+                               reg = <0x0 0xff400000 0x0 0x40000>;
+                               interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clkc CLKID_USB1_DDR_BRIDGE>;
+                               clock-names = "ddr";
+                               phys = <&usb2_phy1>;
+                               dr_mode = "peripheral";
+                               g-rx-fifo-size = <192>;
+                               g-np-tx-fifo-size = <128>;
+                               g-tx-fifo-size = <128 128 16 16 16>;
+                       };
+
+                       dwc3: usb@ff500000 {
+                               compatible = "snps,dwc3";
+                               reg = <0x0 0xff500000 0x0 0x100000>;
+                               interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+                               dr_mode = "host";
+                               snps,dis_u2_susphy_quirk;
+                               snps,quirk-frame-length-adjustment;
+                       };
+               };
+
+               mali: gpu@ffe40000 {
+                       compatible = "amlogic,meson-g12a-mali", "arm,mali-bifrost";
+                       reg = <0x0 0xffe40000 0x0 0x40000>;
+                       interrupt-parent = <&gic>;
+                       interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "gpu", "mmu", "job";
+                       clocks = <&clkc CLKID_MALI>;
+                       resets = <&reset RESET_DVALIN_CAPB3>, <&reset RESET_DVALIN>;
+
+                       /*
+                        * Mali clocking is provided by two identical clock paths
+                        * MALI_0 and MALI_1 muxed to a single clock by a glitch
+                        * free mux to safely change frequency while running.
+                        */
+                       assigned-clocks = <&clkc CLKID_MALI_0_SEL>,
+                                         <&clkc CLKID_MALI_0>,
+                                         <&clkc CLKID_MALI>; /* Glitch free mux */
+                       assigned-clock-parents = <&clkc CLKID_FCLK_DIV2P5>,
+                                                <0>, /* Do Nothing */
+                                                <&clkc CLKID_MALI_0>;
+                       assigned-clock-rates = <0>, /* Do Nothing */
+                                              <800000000>,
+                                              <0>; /* Do Nothing */
                };
        };
 
index 9a8a8a7e4b535a0dae9a33845947c35e651cac71..b5667f1fb2c8f8fd7f551576ce4115d52f1065d6 100644 (file)
        cvbs-connector {
                status = "disabled";
        };
+
+       leds {
+               compatible = "gpio-leds";
+
+               status {
+                       label = "n1:white:status";
+                       gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>;
+                       default-state = "on";
+               };
+       };
 };
 
 &cvbs_vdac_port {
index 8acfd40090d2e0b558f5e8bc2f6201ff5dad5560..25f3b6b1404365c83a272ee0e131db077aca023b 100644 (file)
        pinctrl-0 = <&uart_ao_a_pins>;
        pinctrl-names = "default";
 };
+
+&usb0 {
+       status = "okay";
+};
index ed3a3d5adf316700e48f33e59f6664e3a969d007..7a85a82bf65d874ed42510824824d9d331e73272 100644 (file)
                reset-names = "phy";
                status = "okay";
        };
+
+       mali: gpu@c0000 {
+               compatible = "amlogic,meson-gxm-mali", "arm,mali-t820";
+               reg = <0x0 0xc0000 0x0 0x40000>;
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "gpu", "mmu", "job";
+               clocks = <&clkc CLKID_MALI>;
+               resets = <&reset RESET_MALI_CAPB3>, <&reset RESET_MALI>;
+
+               /*
+                * Mali clocking is provided by two identical clock paths
+                * MALI_0 and MALI_1 muxed to a single clock by a glitch
+                * free mux to safely change frequency while running.
+                */
+               assigned-clocks = <&clkc CLKID_MALI_0_SEL>,
+                                 <&clkc CLKID_MALI_0>,
+                                 <&clkc CLKID_MALI>; /* Glitch free mux */
+               assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>,
+                                        <0>, /* Do Nothing */
+                                        <&clkc CLKID_MALI_0>;
+               assigned-clock-rates = <0>, /* Do Nothing */
+                                      <666666666>,
+                                      <0>; /* Do Nothing */
+       };
 };
 
 &clkc_AO {
index 6a32555971383bc7434eb07a711ff7ef5d060fd4..3e8c70778e24872bc2705eb811584aa804cfec9a 100644 (file)
@@ -8,6 +8,28 @@
 
 #include "bm1880.dtsi"
 
+/*
+ * GPIO name legend: proper name = the GPIO line is used as GPIO
+ *         NC = not connected (pin out but not routed from the chip to
+ *              anything the board)
+ *         "[PER]" = pin is muxed for [peripheral] (not GPIO)
+ *         LSEC = Low Speed External Connector
+ *         HSEC = High Speed External Connector
+ *
+ * Line names are taken from the schematic "sophon-edge-schematics"
+ * version, 1.0210.
+ *
+ * For the lines routed to the external connectors the
+ * lines are named after the 96Boards CE Specification 1.0,
+ * Appendix "Expansion Connector Signal Description".
+ *
+ * When the 96Board naming of a line and the schematic name of
+ * the same line are in conflict, the 96Board specification
+ * takes precedence. This is only for the informational
+ * lines i.e. "[FOO]", the GPIO named lines "GPIO-A" thru "GPIO-L"
+ * are the only ones actually used for GPIO.
+ */
+
 / {
        compatible = "bitmain,sophon-edge", "bitmain,bm1880";
        model = "Sophon Edge";
                clock-frequency = <500000000>;
                #clock-cells = <0>;
        };
+
+       soc {
+               gpio0: gpio@50027000 {
+                       porta: gpio-controller@0 {
+                               gpio-line-names =
+                                       "GPIO-A", /* GPIO0, LSEC pin 23 */
+                                       "GPIO-C", /* GPIO1, LSEC pin 25 */
+                                       "[GPIO2_PHY0_RST]", /* GPIO2 */
+                                       "GPIO-E", /* GPIO3, LSEC pin 27 */
+                                       "[USB_DET]", /* GPIO4 */
+                                       "[EN_P5V]", /* GPIO5 */
+                                       "[VDDIO_MS1_SEL]", /* GPIO6 */
+                                       "GPIO-G", /* GPIO7, LSEC pin 29 */
+                                       "[BM_TUSB_RST_L]", /* GPIO8 */
+                                       "[EN_P5V_USBHUB]", /* GPIO9 */
+                                       "NC",
+                                       "LED_WIFI", /* GPIO11 */
+                                       "LED_BT", /* GPIO12 */
+                                       "[BM_BLM8221_EN_L]", /* GPIO13 */
+                                       "NC", /* GPIO14 */
+                                       "NC", /* GPIO15 */
+                                       "NC", /* GPIO16 */
+                                       "NC", /* GPIO17 */
+                                       "NC", /* GPIO18 */
+                                       "NC", /* GPIO19 */
+                                       "NC", /* GPIO20 */
+                                       "NC", /* GPIO21 */
+                                       "NC", /* GPIO22 */
+                                       "NC", /* GPIO23 */
+                                       "NC", /* GPIO24 */
+                                       "NC", /* GPIO25 */
+                                       "NC", /* GPIO26 */
+                                       "NC", /* GPIO27 */
+                                       "NC", /* GPIO28 */
+                                       "NC", /* GPIO29 */
+                                       "NC", /* GPIO30 */
+                                       "NC"; /* GPIO31 */
+                       };
+               };
+
+               gpio1: gpio@50027400 {
+                       portb: gpio-controller@0 {
+                               gpio-line-names =
+                                       "NC", /* GPIO32 */
+                                       "NC", /* GPIO33 */
+                                       "[I2C0_SDA]", /* GPIO34, LSEC pin 17 */
+                                       "[I2C0_SCL]", /* GPIO35, LSEC pin 15 */
+                                       "[JTAG0_TDO]", /* GPIO36 */
+                                       "[JTAG0_TCK]", /* GPIO37 */
+                                       "[JTAG0_TDI]", /* GPIO38 */
+                                       "[JTAG0_TMS]", /* GPIO39 */
+                                       "[JTAG0_TRST_X]", /* GPIO40 */
+                                       "[JTAG1_TDO]", /* GPIO41 */
+                                       "[JTAG1_TCK]", /* GPIO42 */
+                                       "[JTAG1_TDI]", /* GPIO43 */
+                                       "[CPU_TX]", /* GPIO44 */
+                                       "[CPU_RX]", /* GPIO45 */
+                                       "[UART1_TXD]", /* GPIO46 */
+                                       "[UART1_RXD]", /* GPIO47 */
+                                       "[UART0_TXD]", /* GPIO48 */
+                                       "[UART0_RXD]", /* GPIO49 */
+                                       "GPIO-I", /* GPIO50, LSEC pin 31 */
+                                       "GPIO-K", /* GPIO51, LSEC pin 33 */
+                                       "USER_LED2", /* GPIO52 */
+                                       "USER_LED1", /* GPIO53 */
+                                       "[UART0_RTS]", /* GPIO54 */
+                                       "[UART0_CTS]", /* GPIO55 */
+                                       "USER_LED4", /* GPIO56, JTAG1_TRST_X */
+                                       "USER_LED3", /* GPIO57, JTAG1_TMS */
+                                       "[I2S0_SCLK]", /* GPIO58 */
+                                       "[I2S0_FS]", /* GPIO59 */
+                                       "[I2S0_SDI]", /* GPIO60 */
+                                       "[I2S0_SDO]", /* GPIO61 */
+                                       "GPIO-B", /* GPIO62, LSEC pin 24 */
+                                       "GPIO-F"; /* GPIO63, I2S1_SCLK, LSEC pin 28 */
+                       };
+               };
+
+               gpio2: gpio@50027800 {
+                       portc: gpio-controller@0 {
+                               gpio-line-names =
+                                       "GPIO-D", /* GPIO64, I2S1_FS, LSEC pin 26 */
+                                       "GPIO-J", /* GPIO65, I2S1_SDI, LSEC pin 32 */
+                                       "GPIO-H", /* GPIO66, I2S1_SDO, LSEC pin 30 */
+                                       "GPIO-L", /* GPIO67, LSEC pin 34 */
+                                       "[SPI0_CS]", /* GPIO68, SPI1_CS, LSEC pin 12 */
+                                       "[SPI0_DIN]", /* GPIO69, SPI1_SDI, LSEC pin 10 */
+                                       "[SPI0_DOUT]", /* GPIO70, SPI1_SDO, LSEC pin 14 */
+                                       "[SPI0_SCLK]"; /* GPIO71, SPI1_SCK, LSEC pin 8 */
+                       };
+               };
+       };
+};
+
+&pinctrl {
+       pinctrl_uart0_default: pinctrl-uart0-default {
+               pinmux {
+                       groups = "uart0_grp";
+                       function = "uart0";
+               };
+       };
+
+       pinctrl_uart1_default: pinctrl-uart1-default {
+               pinmux {
+                       groups = "uart1_grp";
+                       function = "uart1";
+               };
+       };
+
+       pinctrl_uart2_default: pinctrl-uart2-default {
+               pinmux {
+                       groups = "uart2_grp";
+                       function = "uart2";
+               };
+       };
 };
 
 &uart0 {
        status = "okay";
        clocks = <&uart_clk>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart0_default>;
 };
 
 &uart1 {
        status = "okay";
        clocks = <&uart_clk>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1_default>;
 };
 
 &uart2 {
        status = "okay";
        clocks = <&uart_clk>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2_default>;
 };
index 55a4769e0de2335b4b4a520b55a4a0eb131c7b88..7726fd4c6be6f68bf9cfaef8cf038a73ae445d7d 100644 (file)
                        #interrupt-cells = <3>;
                };
 
+               sctrl: system-controller@50010000 {
+                       compatible = "bitmain,bm1880-sctrl", "syscon",
+                                    "simple-mfd";
+                       reg = <0x0 0x50010000 0x0 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x0 0x50010000 0x1000>;
+
+                       pinctrl: pinctrl@50 {
+                               compatible = "bitmain,bm1880-pinctrl";
+                               reg = <0x50 0x4B0>;
+                       };
+               };
+
+               gpio0: gpio@50027000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "snps,dw-apb-gpio";
+                       reg = <0x0 0x50027000 0x0 0x400>;
+
+                       porta: gpio-controller@0 {
+                               compatible = "snps,dw-apb-gpio-port";
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               snps,nr-gpios = <32>;
+                               reg = <0>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                               interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+               };
+
+               gpio1: gpio@50027400 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "snps,dw-apb-gpio";
+                       reg = <0x0 0x50027400 0x0 0x400>;
+
+                       portb: gpio-controller@0 {
+                               compatible = "snps,dw-apb-gpio-port";
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               snps,nr-gpios = <32>;
+                               reg = <0>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                               interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+               };
+
+               gpio2: gpio@50027800 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "snps,dw-apb-gpio";
+                       reg = <0x0 0x50027800 0x0 0x400>;
+
+                       portc: gpio-controller@0 {
+                               compatible = "snps,dw-apb-gpio-port";
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               snps,nr-gpios = <8>;
+                               reg = <0>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                               interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+               };
+
                uart0: serial@58018000 {
                        compatible = "snps,dw-apb-uart";
                        reg = <0x0 0x58018000 0x0 0x2000>;
index d88e2f0e179a96c632ffe30cb50e4c1852f9f5f1..d2de16645e101d13e5766ce8d7a20403f0406ec8 100644 (file)
        assigned-clock-parents = <&cmu_top CLK_ACLK_MFC_400>;
 };
 
+&cmu_mif {
+       assigned-clocks = <&cmu_mif CLK_MOUT_SCLK_DSD_A>, <&cmu_mif CLK_DIV_SCLK_DSD>;
+       assigned-clock-parents = <&cmu_mif CLK_MOUT_MFC_PLL_DIV2>;
+       assigned-clock-rates = <0>, <333000000>;
+};
+
 &cmu_mscl {
        assigned-clocks = <&cmu_mscl CLK_MOUT_ACLK_MSCL_400_USER>,
                          <&cmu_mscl CLK_MOUT_SCLK_JPEG_USER>,
index 3d7e0a782243df3033b0a14aa7d2387bba28fa0b..dda5d2746a74f6062e0ad5dc7dcab2dab0d71786 100644 (file)
@@ -33,7 +33,8 @@
                          <&cmu_disp CLK_MOUT_DISP_PLL>,
                          <&cmu_mif CLK_MOUT_SCLK_DECON_TV_ECLK_A>,
                          <&cmu_disp CLK_MOUT_SCLK_DECON_TV_ECLK_USER>,
-                         <&cmu_disp CLK_MOUT_SCLK_DECON_TV_ECLK>;
+                         <&cmu_disp CLK_MOUT_SCLK_DECON_TV_ECLK>,
+                         <&cmu_disp CLK_MOUT_SCLK_DSD_USER>;
        assigned-clock-parents = <0>, <0>,
                                 <&cmu_mif CLK_ACLK_DISP_333>,
                                 <&cmu_mif CLK_SCLK_DSIM0_DISP>,
@@ -45,7 +46,8 @@
                                 <&cmu_disp CLK_FOUT_DISP_PLL>,
                                 <&cmu_mif CLK_MOUT_BUS_PLL_DIV2>,
                                 <&cmu_mif CLK_SCLK_DECON_TV_ECLK_DISP>,
-                                <&cmu_disp CLK_MOUT_SCLK_DECON_TV_ECLK_USER>;
+                                <&cmu_disp CLK_MOUT_SCLK_DECON_TV_ECLK_USER>,
+                                <&cmu_mif CLK_SCLK_DSD_DISP>;
        assigned-clock-rates = <250000000>, <400000000>;
 };
 
index a04e80327b6e3c26cd1ce1fd45811c589f2b67f8..d29d13f4694f026ed51239cda91994ae96185c17 100644 (file)
 
        interrupt-parent = <&gic>;
 
+       arm_a53_pmu {
+               compatible = "arm,cortex-a53-pmu", "arm,armv8-pmuv3";
+               interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+       };
+
+       arm_a57_pmu {
+               compatible = "arm,cortex-a57-pmu", "arm,armv8-pmuv3";
+               interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&cpu4>, <&cpu5>, <&cpu6>, <&cpu7>;
+       };
+
+       xxti: clock {
+               /* XXTI */
+               compatible = "fixed-clock";
+               clock-output-names = "oscclk";
+               #clock-cells = <0>;
+       };
+
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
                #size-cells = <1>;
                ranges;
 
-               arm_a53_pmu {
-                       compatible = "arm,cortex-a53-pmu", "arm,armv8-pmuv3";
-                       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
-               };
-
-               arm_a57_pmu {
-                       compatible = "arm,cortex-a57-pmu", "arm,armv8-pmuv3";
-                       interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-affinity = <&cpu4>, <&cpu5>, <&cpu6>, <&cpu7>;
-               };
-
                chipid@10000000 {
                        compatible = "samsung,exynos4210-chipid";
                        reg = <0x10000000 0x100>;
                };
 
-               xxti: xxti {
-                       compatible = "fixed-clock";
-                       clock-output-names = "oscclk";
-                       #clock-cells = <0>;
-               };
-
                cmu_top: clock-controller@10030000 {
                        compatible = "samsung,exynos5433-cmu-top";
                        reg = <0x10030000 0x1000>;
                                <&cmu_top CLK_DIV_ACLK_IMEM_200>;
                };
 
+               slim_sss: slim-sss@11140000 {
+                       compatible = "samsung,exynos5433-slim-sss";
+                       reg = <0x11140000 0x1000>;
+                       interrupts = <GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>;
+                       clock-names = "aclk", "pclk";
+                       clocks = <&cmu_imem CLK_ACLK_SLIMSSS>,
+                                <&cmu_imem CLK_PCLK_SLIMSSS>;
+               };
+
                pd_gscl: power-domain@105c4000 {
                        compatible = "samsung,exynos5433-pd";
                        reg = <0x105c4000 0x20>;
                                <&cmu_disp CLK_ACLK_XIU_DECON1X>,
                                <&cmu_disp CLK_PCLK_SMMU_DECON1X>,
                                <&cmu_disp CLK_SCLK_DECON_VCLK>,
-                               <&cmu_disp CLK_SCLK_DECON_ECLK>;
+                               <&cmu_disp CLK_SCLK_DECON_ECLK>,
+                               <&cmu_disp CLK_SCLK_DSD>;
                        clock-names = "pclk", "aclk_decon", "aclk_smmu_decon0x",
                                "aclk_xiu_decon0x", "pclk_smmu_decon0x",
                                "aclk_smmu_decon1x", "aclk_xiu_decon1x",
                                "pclk_smmu_decon1x", "sclk_decon_vclk",
-                               "sclk_decon_eclk";
+                               "sclk_decon_eclk", "dsd";
                        power-domains = <&pd_disp>;
                        interrupt-names = "fifo", "vsync", "lcd_sys";
                        interrupts = <GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH>,
                                 <&cmu_disp CLK_ACLK_XIU_TV1X>,
                                 <&cmu_disp CLK_PCLK_SMMU_TV1X>,
                                 <&cmu_disp CLK_SCLK_DECON_TV_VCLK>,
-                                <&cmu_disp CLK_SCLK_DECON_TV_ECLK>;
+                                <&cmu_disp CLK_SCLK_DECON_TV_ECLK>,
+                                <&cmu_disp CLK_SCLK_DSD>;
                        clock-names = "pclk", "aclk_decon", "aclk_smmu_decon0x",
                                      "aclk_xiu_decon0x", "pclk_smmu_decon0x",
                                      "aclk_smmu_decon1x", "aclk_xiu_decon1x",
                                      "pclk_smmu_decon1x", "sclk_decon_vclk",
-                                     "sclk_decon_eclk";
+                                     "sclk_decon_eclk", "dsd";
                        samsung,disp-sysreg = <&syscon_disp>;
                        power-domains = <&pd_disp>;
                        interrupt-names = "fifo", "vsync", "lcd_sys";
                        reg = <0x13c00000 0x1000>;
                        interrupts = <GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>;
                        clock-names = "pclk", "aclk", "aclk_xiu",
-                                     "aclk_gsclbend";
+                                     "aclk_gsclbend", "gsd";
                        clocks = <&cmu_gscl CLK_PCLK_GSCL0>,
                                 <&cmu_gscl CLK_ACLK_GSCL0>,
                                 <&cmu_gscl CLK_ACLK_XIU_GSCLX>,
-                                <&cmu_gscl CLK_ACLK_GSCLBEND_333>;
+                                <&cmu_gscl CLK_ACLK_GSCLBEND_333>,
+                                <&cmu_gscl CLK_ACLK_GSD>;
                        iommus = <&sysmmu_gscl0>;
                        power-domains = <&pd_gscl>;
                };
                        reg = <0x13c10000 0x1000>;
                        interrupts = <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>;
                        clock-names = "pclk", "aclk", "aclk_xiu",
-                                     "aclk_gsclbend";
+                                     "aclk_gsclbend", "gsd";
                        clocks = <&cmu_gscl CLK_PCLK_GSCL1>,
                                 <&cmu_gscl CLK_ACLK_GSCL1>,
                                 <&cmu_gscl CLK_ACLK_XIU_GSCLX>,
-                                <&cmu_gscl CLK_ACLK_GSCLBEND_333>;
+                                <&cmu_gscl CLK_ACLK_GSCLBEND_333>,
+                                <&cmu_gscl CLK_ACLK_GSD>;
                        iommus = <&sysmmu_gscl1>;
                        power-domains = <&pd_gscl>;
                };
                        reg = <0x13c20000 0x1000>;
                        interrupts = <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
                        clock-names = "pclk", "aclk", "aclk_xiu",
-                                     "aclk_gsclbend";
+                                     "aclk_gsclbend", "gsd";
                        clocks = <&cmu_gscl CLK_PCLK_GSCL2>,
                                 <&cmu_gscl CLK_ACLK_GSCL2>,
                                 <&cmu_gscl CLK_ACLK_XIU_GSCLX>,
-                                <&cmu_gscl CLK_ACLK_GSCLBEND_333>;
+                                <&cmu_gscl CLK_ACLK_GSCLBEND_333>,
+                                <&cmu_gscl CLK_ACLK_GSD>;
                        iommus = <&sysmmu_gscl2>;
                        power-domains = <&pd_gscl>;
                };
index 967558a93d8204d5a55f7b5d4ce05c14863f5f97..077d234789019d06703831f3c9509b0b9024b79b 100644 (file)
                tmuctrl0 = &tmuctrl_0;
        };
 
+       arm-pmu {
+               compatible = "arm,cortex-a57-pmu", "arm,armv8-pmuv3";
+               interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&cpu_atlas0>, <&cpu_atlas1>,
+                                    <&cpu_atlas2>, <&cpu_atlas3>;
+       };
+
+       fin_pll: clock {
+               /* XXTI */
+               compatible = "fixed-clock";
+               clock-output-names = "fin_pll";
+               #clock-cells = <0>;
+       };
+
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
                        reg = <0x10000000 0x100>;
                };
 
-               fin_pll: xxti {
-                       compatible = "fixed-clock";
-                       clock-output-names = "fin_pll";
-                       #clock-cells = <0>;
-               };
-
                gic: interrupt-controller@11001000 {
                        compatible = "arm,gic-400";
                        #interrupt-cells = <3>;
                        status = "disabled";
                };
 
-               arm-pmu {
-                       compatible = "arm,cortex-a57-pmu", "arm,armv8-pmuv3";
-                       interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-affinity = <&cpu_atlas0>, <&cpu_atlas1>,
-                                            <&cpu_atlas2>, <&cpu_atlas3>;
-               };
-
-               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)>;
-               };
-
                pmu_system_controller: system-controller@105c0000 {
                        compatible = "samsung,exynos7-pmu", "syscon";
                        reg = <0x105c0000 0x5000>;
                        };
                };
        };
+
+       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)>;
+       };
 };
 
 #include "exynos7-pinctrl.dtsi"
index 13604e558dc10183f5f9858cc2de23aae47d62a1..0bd122f605495b4db9d4fe03c2acfd68b0775633 100644 (file)
@@ -20,5 +20,8 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2088a-rdb.dtb
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-qds.dtb
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-rdb.dtb
 
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-rmb3.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-zest.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek.dtb
index 7c726267ec8f6aec8adc408976d9e4e95b2e5422..9927b096d343be178d575e4eb4d36c3a82a145f8 100644 (file)
        status = "okay";
 };
 
+&pcie {
+       status = "okay";
+};
+
 &sai2 {
        status = "okay";
 };
index 1ce0042b2a14f1a3471bc1c83968547cd8a8fd43..ec6257a5b251504f23dcd752a6fa61757a57d92e 100644 (file)
                        interrupts = <0 126 IRQ_TYPE_LEVEL_HIGH>;
                };
 
-               pcie@3400000 {
+               pcie: pcie@3400000 {
                        compatible = "fsl,ls1012a-pcie";
                        reg = <0x00 0x03400000 0x0 0x00100000   /* controller registers */
                               0x40 0x00000000 0x0 0x00002000>; /* configuration space */
index 14c79f4691eafc7a5b853ddd2df2a3218e938b54..b359068d9605654fc438a63e6107af024648e7c7 100644 (file)
                device_type = "memory";
                reg = <0x0 0x80000000 0x1 0x00000000>;
        };
+
+       sys_mclk: clock-mclk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <25000000>;
+       };
+
+       reg_1p8v: regulator-1p8v {
+               compatible = "regulator-fixed";
+               regulator-name = "1P8V";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+       };
+
+       sound {
+               compatible = "simple-audio-card";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,widgets =
+                       "Microphone", "Microphone Jack",
+                       "Headphone", "Headphone Jack",
+                       "Speaker", "Speaker Ext",
+                       "Line", "Line In Jack";
+               simple-audio-card,routing =
+                       "MIC_IN", "Microphone Jack",
+                       "Microphone Jack", "Mic Bias",
+                       "LINE_IN", "Line In Jack",
+                       "Headphone Jack", "HP_OUT",
+                       "Speaker Ext", "LINE_OUT";
+
+               simple-audio-card,cpu {
+                       sound-dai = <&sai1>;
+                       frame-master;
+                       bitclock-master;
+               };
+
+               simple-audio-card,codec {
+                       sound-dai = <&sgtl5000>;
+                       frame-master;
+                       bitclock-master;
+                       system-clock-frequency = <25000000>;
+               };
+       };
 };
 
 &duart0 {
                                reg = <0x57>;
                        };
                };
+
+               i2c@5 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x5>;
+
+                       sgtl5000: audio-codec@a {
+                               #sound-dai-cells = <0>;
+                               compatible = "fsl,sgtl5000";
+                               reg = <0xa>;
+                               VDDA-supply = <&reg_1p8v>;
+                               VDDIO-supply = <&reg_1p8v>;
+                               clocks = <&sys_mclk>;
+                       };
+               };
        };
 };
+
+&sai1 {
+       status = "okay";
+};
index f86b054a74aede5d2bbee126cf06edf3d206bca4..f9c272fb0738f95c4bf5ecde223551fe5c05aed1 100644 (file)
                device_type = "memory";
                reg = <0x0 0x80000000 0x1 0x0000000>;
        };
+
+       sys_mclk: clock-mclk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <25000000>;
+       };
+
+       reg_1p8v: regulator-1p8v {
+               compatible = "regulator-fixed";
+               regulator-name = "1P8V";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+       };
+
+       sound {
+               compatible = "simple-audio-card";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,widgets =
+                       "Microphone", "Microphone Jack",
+                       "Headphone", "Headphone Jack",
+                       "Speaker", "Speaker Ext",
+                       "Line", "Line In Jack";
+               simple-audio-card,routing =
+                       "MIC_IN", "Microphone Jack",
+                       "Microphone Jack", "Mic Bias",
+                       "LINE_IN", "Line In Jack",
+                       "Headphone Jack", "HP_OUT",
+                       "Speaker Ext", "LINE_OUT";
+
+               simple-audio-card,cpu {
+                       sound-dai = <&sai4>;
+                       frame-master;
+                       bitclock-master;
+               };
+
+               simple-audio-card,codec {
+                       sound-dai = <&sgtl5000>;
+                       frame-master;
+                       bitclock-master;
+                       system-clock-frequency = <25000000>;
+               };
+       };
 };
 
 &i2c0 {
                #address-cells = <1>;
                #size-cells = <0>;
 
+               i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x1>;
+
+                       sgtl5000: audio-codec@a {
+                               #sound-dai-cells = <0>;
+                               compatible = "fsl,sgtl5000";
+                               reg = <0xa>;
+                               VDDA-supply = <&reg_1p8v>;
+                               VDDIO-supply = <&reg_1p8v>;
+                               clocks = <&sys_mclk>;
+                               sclk-strength = <3>;
+                       };
+               };
+
                i2c@2 {
                        #address-cells = <1>;
                        #size-cells = <0>;
 &enetc_port1 {
        status = "disabled";
 };
+
+&sai4 {
+       status = "okay";
+};
index 2896bbcfa3bb8d1a5d85e927a7fd18e5f4a91fb5..b04581249f0bca701dfe8134ffc7f65a44a2fbd4 100644 (file)
                                          IRQ_TYPE_LEVEL_LOW)>;
        };
 
+       pmu {
+               compatible = "arm,cortex-a72-pmu";
+               interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
+       };
+
        gic: interrupt-controller@6000000 {
                compatible= "arm,gic-v3";
                #address-cells = <2>;
                        status = "disabled";
                };
 
+               edma0: dma-controller@22c0000 {
+                       #dma-cells = <2>;
+                       compatible = "fsl,vf610-edma";
+                       reg = <0x0 0x22c0000 0x0 0x10000>,
+                             <0x0 0x22d0000 0x0 0x10000>,
+                             <0x0 0x22e0000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "edma-tx", "edma-err";
+                       dma-channels = <32>;
+                       clock-names = "dmamux0", "dmamux1";
+                       clocks = <&clockgen 4 1>,
+                                <&clockgen 4 1>;
+               };
+
                gpio1: gpio@2300000 {
                        compatible = "fsl,qoriq-gpio";
                        reg = <0x0 0x2300000 0x0 0x10000>;
                sata: sata@3200000 {
                        compatible = "fsl,ls1028a-ahci";
                        reg = <0x0 0x3200000 0x0 0x10000>,
-                               <0x0 0x20140520 0x0 0x4>;
+                               <0x7 0x100520 0x0 0x4>;
                        reg-names = "ahci", "sata-ecc";
                        interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&clockgen 4 1>;
                                     <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH>;
                };
 
+               sai1: audio-controller@f100000 {
+                       #sound-dai-cells = <0>;
+                       compatible = "fsl,vf610-sai";
+                       reg = <0x0 0xf100000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 1>, <&clockgen 4 1>,
+                                <&clockgen 4 1>, <&clockgen 4 1>;
+                       clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                       dma-names = "tx", "rx";
+                       dmas = <&edma0 1 4>,
+                              <&edma0 1 3>;
+                       status = "disabled";
+               };
+
+               sai2: audio-controller@f110000 {
+                       #sound-dai-cells = <0>;
+                       compatible = "fsl,vf610-sai";
+                       reg = <0x0 0xf110000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 1>, <&clockgen 4 1>,
+                                <&clockgen 4 1>, <&clockgen 4 1>;
+                       clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                       dma-names = "tx", "rx";
+                       dmas = <&edma0 1 6>,
+                              <&edma0 1 5>;
+                       status = "disabled";
+               };
+
+               sai4: audio-controller@f130000 {
+                       #sound-dai-cells = <0>;
+                       compatible = "fsl,vf610-sai";
+                       reg = <0x0 0xf130000 0x0 0x10000>;
+                       interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 1>, <&clockgen 4 1>,
+                                <&clockgen 4 1>, <&clockgen 4 1>;
+                       clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                       dma-names = "tx", "rx";
+                       dmas = <&edma0 1 10>,
+                              <&edma0 1 9>;
+                       status = "disabled";
+               };
+
                pcie@1f0000000 { /* Integrated Endpoint Root Complex */
                        compatible = "pci-host-ecam-generic";
                        reg = <0x01 0xf0000000 0x0 0x100000>;
index 17ca357e854f2ec0fbb0ca2e4260a5b4591bbbde..4223a2352d45adda2b39b427ca8e2313d2446df7 100644 (file)
@@ -15,7 +15,6 @@
        model = "LS1043A RDB Board";
 
        aliases {
-               crypto = &crypto;
                serial0 = &duart0;
                serial1 = &duart1;
                serial2 = &duart2;
index 6fd6116509cc79e2c745be27e74a3c7a480f56ad..71d9ed9ff985a296d71243d78f9ac4e8467cab98 100644 (file)
@@ -18,6 +18,7 @@
        #size-cells = <2>;
 
        aliases {
+               crypto = &crypto;
                fman0 = &fman0;
                ethernet0 = &enet0;
                ethernet1 = &enet1;
                        interrupts = <0 99 0x4>;
                        clock-names = "qspi_en", "qspi";
                        clocks = <&clockgen 4 0>, <&clockgen 4 0>;
-                       big-endian;
                        status = "disabled";
                };
 
index cb7185014d3a61f4c03ecfbf58ac0fc35474d728..b0ef08b090ddb1161b570701a850132a64ca359f 100644 (file)
                        interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
                        clock-names = "qspi_en", "qspi";
                        clocks = <&clockgen 4 1>, <&clockgen 4 1>;
-                       big-endian;
-                       fsl,qspi-has-second-chip;
                        status = "disabled";
                };
 
index 99a22abbe72582035f45a3ac737aa77230cc1159..1a5acf62f23c658cd50e5a7d18200ad2bb3d2c27 100644 (file)
        };
 };
 
+&sata0 {
+       status = "okay";
+};
+
+&sata1 {
+       status = "okay";
+};
+
+&sata2 {
+       status = "okay";
+};
+
+&sata3 {
+       status = "okay";
+};
+
 &uart0 {
        status = "okay";
 };
index 9df37b1594157c9bcbcd6cd7c0c7185f4fe6ff26..c2817b784232dcf43b621f58878ec5ac39e0f94f 100644 (file)
        };
 };
 
+&sata0 {
+       status = "okay";
+};
+
+&sata1 {
+       status = "okay";
+};
+
+&sata2 {
+       status = "okay";
+};
+
+&sata3 {
+       status = "okay";
+};
+
 &uart0 {
        status = "okay";
 };
index fe87204850b5ac7d46d2b21fb2763f43c869632a..125a8cc2c5b3febd23d784601a240d3ce1eb8318 100644 (file)
@@ -33,6 +33,7 @@
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster0_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@1 {
@@ -48,6 +49,7 @@
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster0_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@100 {
@@ -63,6 +65,7 @@
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster1_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@101 {
@@ -78,6 +81,7 @@
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster1_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@200 {
@@ -93,6 +97,7 @@
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster2_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@201 {
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster2_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@300 {
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster3_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@301 {
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster3_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@400 {
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster4_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@401 {
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster4_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@500 {
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster5_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@501 {
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster5_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@600 {
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster6_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@601 {
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster6_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@700 {
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster7_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cpu@701 {
                        i-cache-line-size = <64>;
                        i-cache-sets = <192>;
                        next-level-cache = <&cluster7_l2>;
+                       cpu-idle-states = <&cpu_pw20>;
                };
 
                cluster0_l2: l2-cache0 {
                        cache-sets = <1024>;
                        cache-level = <2>;
                };
+
+               cpu_pw20: cpu-pw20 {
+                       compatible = "arm,idle-state";
+                       idle-state-name = "PW20";
+                       arm,psci-suspend-param = <0x0>;
+                       entry-latency-us = <2000>;
+                       exit-latency-us = <2000>;
+                       min-residency-us = <6000>;
+                 };
        };
 
        gic: interrupt-controller@6000000 {
                        status = "disabled";
                };
 
+               sata0: sata@3200000 {
+                       compatible = "fsl,lx2160a-ahci";
+                       reg = <0x0 0x3200000 0x0 0x10000>,
+                             <0x7 0x100520 0x0 0x4>;
+                       reg-names = "ahci", "sata-ecc";
+                       interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 3>;
+                       dma-coherent;
+                       status = "disabled";
+               };
+
+               sata1: sata@3210000 {
+                       compatible = "fsl,lx2160a-ahci";
+                       reg = <0x0 0x3210000 0x0 0x10000>,
+                             <0x7 0x100520 0x0 0x4>;
+                       reg-names = "ahci", "sata-ecc";
+                       interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 3>;
+                       dma-coherent;
+                       status = "disabled";
+               };
+
+               sata2: sata@3220000 {
+                       compatible = "fsl,lx2160a-ahci";
+                       reg = <0x0 0x3220000 0x0 0x10000>,
+                             <0x7 0x100520 0x0 0x4>;
+                       reg-names = "ahci", "sata-ecc";
+                       interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 3>;
+                       dma-coherent;
+                       status = "disabled";
+               };
+
+               sata3: sata@3230000 {
+                       compatible = "fsl,lx2160a-ahci";
+                       reg = <0x0 0x3230000 0x0 0x10000>,
+                             <0x7 0x100520 0x0 0x4>;
+                       reg-names = "ahci", "sata-ecc";
+                       interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clockgen 4 3>;
+                       dma-coherent;
+                       status = "disabled";
+               };
+
                smmu: iommu@5000000 {
                        compatible = "arm,mmu-500";
                        reg = <0 0x5000000 0 0x800000>;
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk.dts
new file mode 100644 (file)
index 0000000..2d5d894
--- /dev/null
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2019 NXP
+ */
+
+/dts-v1/;
+
+#include "imx8mm.dtsi"
+
+/ {
+       model = "FSL i.MX8MM EVK board";
+       compatible = "fsl,imx8mm-evk", "fsl,imx8mm";
+
+       chosen {
+               stdout-path = &uart2;
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_led>;
+
+               status {
+                       label = "status";
+                       gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>;
+                       default-state = "on";
+               };
+       };
+
+       reg_usdhc2_vmmc: regulator-usdhc2 {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+               regulator-name = "VSD_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+};
+
+&fec1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec1>;
+       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>;
+                       at803x,led-act-blind-workaround;
+                       at803x,eee-okay;
+                       at803x,vddio-1p8v;
+               };
+       };
+};
+
+&uart2 { /* console */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       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 = <&gpio1 15 GPIO_ACTIVE_LOW>;
+       bus-width = <4>;
+       vmmc-supply = <&reg_usdhc2_vmmc>;
+       status = "okay";
+};
+
+&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;
+       status = "okay";
+};
+
+&wdog1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wdog>;
+       fsl,ext-reset-output;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl-names = "default";
+
+       pinctrl_fec1: fec1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_ENET_MDC_ENET1_MDC                 0x3
+                       MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO               0x3
+                       MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3           0x1f
+                       MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2           0x1f
+                       MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1           0x1f
+                       MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0           0x1f
+                       MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3           0x91
+                       MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2           0x91
+                       MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1           0x91
+                       MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0           0x91
+                       MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC           0x1f
+                       MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC           0x91
+                       MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL     0x91
+                       MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL     0x1f
+                       MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22                0x19
+               >;
+       };
+
+       pinctrl_gpio_led: gpioledgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_NAND_READY_B_GPIO3_IO16    0x19
+               >;
+       };
+
+       pinctrl_reg_usdhc2_vmmc: regusdhc2vmmc {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19     0x41
+               >;
+       };
+
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_UART2_RXD_UART2_DCE_RX     0x140
+                       MX8MM_IOMUXC_UART2_TXD_UART2_DCE_TX     0x140
+               >;
+       };
+
+       pinctrl_usdhc2_gpio: usdhc2grpgpio {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15      0x1c4
+               >;
+       };
+
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK         0x190
+                       MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD         0x1d0
+                       MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0     0x1d0
+                       MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1     0x1d0
+                       MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2     0x1d0
+                       MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3     0x1d0
+                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT  0x1d0
+               >;
+       };
+
+       pinctrl_usdhc2_100mhz: usdhc2grp100mhz {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK         0x194
+                       MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD         0x1d4
+                       MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0     0x1d4
+                       MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1     0x1d4
+                       MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2     0x1d4
+                       MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3     0x1d4
+                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT  0x1d0
+               >;
+       };
+
+       pinctrl_usdhc2_200mhz: usdhc2grp200mhz {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK         0x196
+                       MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD         0x1d6
+                       MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0     0x1d6
+                       MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1     0x1d6
+                       MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2     0x1d6
+                       MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3     0x1d6
+                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT  0x1d0
+               >;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK               0x190
+                       MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD               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_CE2_B_USDHC3_DATA5            0x1d0
+                       MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d0
+                       MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d0
+                       MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x190
+               >;
+       };
+
+       pinctrl_usdhc3_100mhz: usdhc3grp100mhz {
+               fsl,pins = <
+                       MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK               0x194
+                       MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD               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_CE2_B_USDHC3_DATA5            0x1d4
+                       MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d4
+                       MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d4
+                       MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x194
+               >;
+       };
+
+       pinctrl_usdhc3_200mhz: usdhc3grp200mhz {
+               fsl,pins = <
+                       MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK               0x196
+                       MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD               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_CE2_B_USDHC3_DATA5            0x1d6
+                       MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d6
+                       MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d6
+                       MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x196
+               >;
+       };
+
+       pinctrl_wdog: wdoggrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B    0xc6
+               >;
+       };
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
new file mode 100644 (file)
index 0000000..6b407a9
--- /dev/null
@@ -0,0 +1,733 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <dt-bindings/clock/imx8mm-clock.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/thermal/thermal.h>
+
+#include "imx8mm-pinfunc.h"
+
+/ {
+       compatible = "fsl,imx8mm";
+       interrupt-parent = <&gic>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       aliases {
+               ethernet0 = &fec1;
+               i2c0 = &i2c1;
+               i2c1 = &i2c2;
+               i2c2 = &i2c3;
+               i2c3 = &i2c4;
+               serial0 = &uart1;
+               serial1 = &uart2;
+               serial2 = &uart3;
+               serial3 = &uart4;
+               spi0 = &ecspi1;
+               spi1 = &ecspi2;
+               spi2 = &ecspi3;
+               mmc0 = &usdhc1;
+               mmc1 = &usdhc2;
+               mmc2 = &usdhc3;
+               gpio0 = &gpio1;
+               gpio1 = &gpio2;
+               gpio2 = &gpio3;
+               gpio3 = &gpio4;
+               gpio4 = &gpio5;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               A53_0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0>;
+                       clock-latency = <61036>; /* two CLK32 periods */
+                       clocks = <&clk IMX8MM_CLK_ARM>;
+                       enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
+                       operating-points-v2 = <&a53_opp_table>;
+               };
+
+               A53_1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x1>;
+                       clock-latency = <61036>; /* two CLK32 periods */
+                       clocks = <&clk IMX8MM_CLK_ARM>;
+                       enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
+                       operating-points-v2 = <&a53_opp_table>;
+               };
+
+               A53_2: cpu@2 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x2>;
+                       clock-latency = <61036>; /* two CLK32 periods */
+                       clocks = <&clk IMX8MM_CLK_ARM>;
+                       enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
+                       operating-points-v2 = <&a53_opp_table>;
+               };
+
+               A53_3: cpu@3 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53";
+                       reg = <0x3>;
+                       clock-latency = <61036>; /* two CLK32 periods */
+                       clocks = <&clk IMX8MM_CLK_ARM>;
+                       enable-method = "psci";
+                       next-level-cache = <&A53_L2>;
+                       operating-points-v2 = <&a53_opp_table>;
+               };
+
+               A53_L2: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       a53_opp_table: opp-table {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-1200000000 {
+                       opp-hz = /bits/ 64 <1200000000>;
+                       opp-microvolt = <850000>;
+                       clock-latency-ns = <150000>;
+               };
+
+               opp-1600000000 {
+                       opp-hz = /bits/ 64 <1600000000>;
+                       opp-microvolt = <900000>;
+                       clock-latency-ns = <150000>;
+                       opp-suspend;
+               };
+       };
+
+       memory@40000000 {
+               device_type = "memory";
+               reg = <0x0 0x40000000 0 0x80000000>;
+       };
+
+       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";
+       };
+
+       clk_ext2: clock-ext2 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <133000000>;
+               clock-output-names = "clk_ext2";
+       };
+
+       clk_ext3: clock-ext3 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <133000000>;
+               clock-output-names = "clk_ext3";
+       };
+
+       clk_ext4: clock-ext4 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency= <133000000>;
+               clock-output-names = "clk_ext4";
+       };
+
+       gic: interrupt-controller@38800000 {
+               compatible = "arm,gic-v3";
+               reg = <0x0 0x38800000 0 0x10000>, /* GIC Dist */
+                     <0x0 0x38880000 0 0xC0000>; /* GICR (RD_base + SGI_base) */
+               #interrupt-cells = <3>;
+               interrupt-controller;
+               interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+       };
+
+       psci {
+               compatible = "arm,psci-1.0";
+               method = "smc";
+       };
+
+       pmu {
+               compatible = "arm,armv8-pmuv3";
+               interrupts = <GIC_PPI 7
+                            (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_HIGH)>;
+               interrupt-affinity = <&A53_0>, <&A53_1>, <&A53_2>, <&A53_3>;
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>, /* Physical Secure */
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>, /* Physical Non-Secure */
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>, /* Virtual */
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>; /* Hypervisor */
+               clock-frequency = <8000000>;
+               arm,no-tick-in-suspend;
+       };
+
+       soc {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0x0 0x3e000000>;
+
+               aips1: bus@30000000 {
+                       compatible = "fsl,aips-bus", "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       gpio1: gpio@30200000 {
+                               compatible = "fsl,imx8mm-gpio", "fsl,imx35-gpio";
+                               reg = <0x30200000 0x10000>;
+                               interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                       };
+
+                       gpio2: gpio@30210000 {
+                               compatible = "fsl,imx8mm-gpio", "fsl,imx35-gpio";
+                               reg = <0x30210000 0x10000>;
+                               interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                       };
+
+                       gpio3: gpio@30220000 {
+                               compatible = "fsl,imx8mm-gpio", "fsl,imx35-gpio";
+                               reg = <0x30220000 0x10000>;
+                               interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                       };
+
+                       gpio4: gpio@30230000 {
+                               compatible = "fsl,imx8mm-gpio", "fsl,imx35-gpio";
+                               reg = <0x30230000 0x10000>;
+                               interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                       };
+
+                       gpio5: gpio@30240000 {
+                               compatible = "fsl,imx8mm-gpio", "fsl,imx35-gpio";
+                               reg = <0x30240000 0x10000>;
+                               interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                       };
+
+                       wdog1: watchdog@30280000 {
+                               compatible = "fsl,imx8mm-wdt", "fsl,imx21-wdt";
+                               reg = <0x30280000 0x10000>;
+                               interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_WDOG1_ROOT>;
+                               status = "disabled";
+                       };
+
+                       wdog2: watchdog@30290000 {
+                               compatible = "fsl,imx8mm-wdt", "fsl,imx21-wdt";
+                               reg = <0x30290000 0x10000>;
+                               interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_WDOG2_ROOT>;
+                               status = "disabled";
+                       };
+
+                       wdog3: watchdog@302a0000 {
+                               compatible = "fsl,imx8mm-wdt", "fsl,imx21-wdt";
+                               reg = <0x302a0000 0x10000>;
+                               interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_WDOG3_ROOT>;
+                               status = "disabled";
+                       };
+
+                       sdma2: dma-controller@302c0000 {
+                               compatible = "fsl,imx8mm-sdma", "fsl,imx7d-sdma";
+                               reg = <0x302c0000 0x10000>;
+                               interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_SDMA2_ROOT>,
+                                        <&clk IMX8MM_CLK_SDMA2_ROOT>;
+                               clock-names = "ipg", "ahb";
+                               #dma-cells = <3>;
+                               fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin";
+                       };
+
+                       sdma3: dma-controller@302b0000 {
+                               compatible = "fsl,imx8mm-sdma", "fsl,imx7d-sdma";
+                               reg = <0x302b0000 0x10000>;
+                               interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_SDMA3_ROOT>,
+                                <&clk IMX8MM_CLK_SDMA3_ROOT>;
+                               clock-names = "ipg", "ahb";
+                               #dma-cells = <3>;
+                               fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin";
+                       };
+
+                       iomuxc: pinctrl@30330000 {
+                               compatible = "fsl,imx8mm-iomuxc";
+                               reg = <0x30330000 0x10000>;
+                       };
+
+                       gpr: iomuxc-gpr@30340000 {
+                               compatible = "fsl,imx8mm-iomuxc-gpr", "syscon";
+                               reg = <0x30340000 0x10000>;
+                       };
+
+                       ocotp: ocotp-ctrl@30350000 {
+                               compatible = "fsl,imx8mm-ocotp", "fsl,imx7d-ocotp", "syscon";
+                               reg = <0x30350000 0x10000>;
+                               clocks = <&clk IMX8MM_CLK_OCOTP_ROOT>;
+                               /* For nvmem subnodes */
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                       };
+
+                       anatop: anatop@30360000 {
+                               compatible = "fsl,imx8mm-anatop", "syscon", "simple-bus";
+                               reg = <0x30360000 0x10000>;
+                       };
+
+                       snvs: snvs@30370000 {
+                               compatible = "fsl,sec-v4.0-mon","syscon", "simple-mfd";
+                               reg = <0x30370000 0x10000>;
+
+                               snvs_rtc: snvs-rtc-lp {
+                                       compatible = "fsl,sec-v4.0-mon-rtc-lp";
+                                       regmap = <&snvs>;
+                                       offset = <0x34>;
+                                       interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+                                                    <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+                               };
+
+                               snvs_pwrkey: snvs-powerkey {
+                                       compatible = "fsl,sec-v4.0-pwrkey";
+                                       regmap = <&snvs>;
+                                       interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+                                       linux,keycode = <KEY_POWER>;
+                                       wakeup-source;
+                               };
+                       };
+
+                       clk: clock-controller@30380000 {
+                               compatible = "fsl,imx8mm-ccm";
+                               reg = <0x30380000 0x10000>;
+                               #clock-cells = <1>;
+                               clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>,
+                                        <&clk_ext3>, <&clk_ext4>;
+                               clock-names = "osc_32k", "osc_24m", "clk_ext1", "clk_ext2",
+                                             "clk_ext3", "clk_ext4";
+                       };
+
+                       src: reset-controller@30390000 {
+                               compatible = "fsl,imx8mm-src", "syscon";
+                               reg = <0x30390000 0x10000>;
+                               interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+                               #reset-cells = <1>;
+                       };
+               };
+
+               aips2: bus@30400000 {
+                       compatible = "fsl,aips-bus", "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       pwm1: pwm@30660000 {
+                               compatible = "fsl,imx8mm-pwm", "fsl,imx27-pwm";
+                               reg = <0x30660000 0x10000>;
+                               interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_PWM1_ROOT>,
+                                       <&clk IMX8MM_CLK_PWM1_ROOT>;
+                               clock-names = "ipg", "per";
+                               #pwm-cells = <2>;
+                               status = "disabled";
+                       };
+
+                       pwm2: pwm@30670000 {
+                               compatible = "fsl,imx8mm-pwm", "fsl,imx27-pwm";
+                               reg = <0x30670000 0x10000>;
+                               interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_PWM2_ROOT>,
+                                        <&clk IMX8MM_CLK_PWM2_ROOT>;
+                               clock-names = "ipg", "per";
+                               #pwm-cells = <2>;
+                               status = "disabled";
+                       };
+
+                       pwm3: pwm@30680000 {
+                               compatible = "fsl,imx8mm-pwm", "fsl,imx27-pwm";
+                               reg = <0x30680000 0x10000>;
+                               interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_PWM3_ROOT>,
+                                        <&clk IMX8MM_CLK_PWM3_ROOT>;
+                               clock-names = "ipg", "per";
+                               #pwm-cells = <2>;
+                               status = "disabled";
+                       };
+
+                       pwm4: pwm@30690000 {
+                               compatible = "fsl,imx8mm-pwm", "fsl,imx27-pwm";
+                               reg = <0x30690000 0x10000>;
+                               interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_PWM4_ROOT>,
+                                        <&clk IMX8MM_CLK_PWM4_ROOT>;
+                               clock-names = "ipg", "per";
+                               #pwm-cells = <2>;
+                               status = "disabled";
+                       };
+               };
+
+               aips3: bus@30800000 {
+                       compatible = "fsl,aips-bus", "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       ecspi1: spi@30820000 {
+                               compatible = "fsl,imx8mm-ecspi", "fsl,imx51-ecspi";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0x30820000 0x10000>;
+                               interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_ECSPI1_ROOT>,
+                                        <&clk IMX8MM_CLK_ECSPI1_ROOT>;
+                               clock-names = "ipg", "per";
+                               dmas = <&sdma1 0 7 1>, <&sdma1 1 7 2>;
+                               dma-names = "rx", "tx";
+                               status = "disabled";
+                       };
+
+                       ecspi2: spi@30830000 {
+                               compatible = "fsl,imx8mm-ecspi", "fsl,imx51-ecspi";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0x30830000 0x10000>;
+                               interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_ECSPI2_ROOT>,
+                                        <&clk IMX8MM_CLK_ECSPI2_ROOT>;
+                               clock-names = "ipg", "per";
+                               dmas = <&sdma1 2 7 1>, <&sdma1 3 7 2>;
+                               dma-names = "rx", "tx";
+                               status = "disabled";
+                       };
+
+                       ecspi3: spi@30840000 {
+                               compatible = "fsl,imx8mm-ecspi", "fsl,imx51-ecspi";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0x30840000 0x10000>;
+                               interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_ECSPI3_ROOT>,
+                                        <&clk IMX8MM_CLK_ECSPI3_ROOT>;
+                               clock-names = "ipg", "per";
+                               dmas = <&sdma1 4 7 1>, <&sdma1 5 7 2>;
+                               dma-names = "rx", "tx";
+                               status = "disabled";
+                       };
+
+                       uart1: serial@30860000 {
+                               compatible = "fsl,imx8mm-uart", "fsl,imx6q-uart";
+                               reg = <0x30860000 0x10000>;
+                               interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_UART1_ROOT>,
+                                        <&clk IMX8MM_CLK_UART1_ROOT>;
+                               clock-names = "ipg", "per";
+                               dmas = <&sdma1 22 4 0>, <&sdma1 23 4 0>;
+                               dma-names = "rx", "tx";
+                               status = "disabled";
+                       };
+
+                       uart3: serial@30880000 {
+                               compatible = "fsl,imx8mm-uart", "fsl,imx6q-uart";
+                               reg = <0x30880000 0x10000>;
+                               interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_UART3_ROOT>,
+                                        <&clk IMX8MM_CLK_UART3_ROOT>;
+                               clock-names = "ipg", "per";
+                               dmas = <&sdma1 26 4 0>, <&sdma1 27 4 0>;
+                               dma-names = "rx", "tx";
+                               status = "disabled";
+                       };
+
+                       uart2: serial@30890000 {
+                               compatible = "fsl,imx8mm-uart", "fsl,imx6q-uart";
+                               reg = <0x30890000 0x10000>;
+                               interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_UART2_ROOT>,
+                                        <&clk IMX8MM_CLK_UART2_ROOT>;
+                               clock-names = "ipg", "per";
+                               status = "disabled";
+                       };
+
+                       i2c1: i2c@30a20000 {
+                               compatible = "fsl,imx8mm-i2c", "fsl,imx21-i2c";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0x30a20000 0x10000>;
+                               interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_I2C1_ROOT>;
+                               status = "disabled";
+                       };
+
+                       i2c2: i2c@30a30000 {
+                               compatible = "fsl,imx8mm-i2c", "fsl,imx21-i2c";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0x30a30000 0x10000>;
+                               interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_I2C2_ROOT>;
+                               status = "disabled";
+                       };
+
+                       i2c3: i2c@30a40000 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,imx8mm-i2c", "fsl,imx21-i2c";
+                               reg = <0x30a40000 0x10000>;
+                               interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_I2C3_ROOT>;
+                               status = "disabled";
+                       };
+
+                       i2c4: i2c@30a50000 {
+                               compatible = "fsl,imx8mm-i2c", "fsl,imx21-i2c";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0x30a50000 0x10000>;
+                               interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_I2C4_ROOT>;
+                               status = "disabled";
+                       };
+
+                       uart4: serial@30a60000 {
+                               compatible = "fsl,imx8mm-uart", "fsl,imx6q-uart";
+                               reg = <0x30a60000 0x10000>;
+                               interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_UART4_ROOT>,
+                                        <&clk IMX8MM_CLK_UART4_ROOT>;
+                               clock-names = "ipg", "per";
+                               dmas = <&sdma1 28 4 0>, <&sdma1 29 4 0>;
+                               dma-names = "rx", "tx";
+                               status = "disabled";
+                       };
+
+                       usdhc1: mmc@30b40000 {
+                               compatible = "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc";
+                               reg = <0x30b40000 0x10000>;
+                               interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_DUMMY>,
+                                        <&clk IMX8MM_CLK_NAND_USDHC_BUS>,
+                                        <&clk IMX8MM_CLK_USDHC1_ROOT>;
+                               clock-names = "ipg", "ahb", "per";
+                               assigned-clocks = <&clk IMX8MM_CLK_USDHC1>;
+                               assigned-clock-rates = <400000000>;
+                               fsl,tuning-start-tap = <20>;
+                               fsl,tuning-step= <2>;
+                               bus-width = <4>;
+                               status = "disabled";
+                       };
+
+                       usdhc2: mmc@30b50000 {
+                               compatible = "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc";
+                               reg = <0x30b50000 0x10000>;
+                               interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_DUMMY>,
+                                        <&clk IMX8MM_CLK_NAND_USDHC_BUS>,
+                                        <&clk IMX8MM_CLK_USDHC2_ROOT>;
+                               clock-names = "ipg", "ahb", "per";
+                               fsl,tuning-start-tap = <20>;
+                               fsl,tuning-step= <2>;
+                               bus-width = <4>;
+                               status = "disabled";
+                       };
+
+                       usdhc3: mmc@30b60000 {
+                               compatible = "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc";
+                               reg = <0x30b60000 0x10000>;
+                               interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_DUMMY>,
+                                        <&clk IMX8MM_CLK_NAND_USDHC_BUS>,
+                                        <&clk IMX8MM_CLK_USDHC3_ROOT>;
+                               clock-names = "ipg", "ahb", "per";
+                               assigned-clocks = <&clk IMX8MM_CLK_USDHC3_ROOT>;
+                               assigned-clock-rates = <400000000>;
+                               fsl,tuning-start-tap = <20>;
+                               fsl,tuning-step= <2>;
+                               bus-width = <4>;
+                               status = "disabled";
+                       };
+
+                       sdma1: dma-controller@30bd0000 {
+                               compatible = "fsl,imx8mm-sdma", "fsl,imx7d-sdma";
+                               reg = <0x30bd0000 0x10000>;
+                               interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_SDMA1_ROOT>,
+                                        <&clk IMX8MM_CLK_SDMA1_ROOT>;
+                               clock-names = "ipg", "ahb";
+                               #dma-cells = <3>;
+                               fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin";
+                       };
+
+                       fec1: ethernet@30be0000 {
+                               compatible = "fsl,imx8mm-fec", "fsl,imx6sx-fec";
+                               reg = <0x30be0000 0x10000>;
+                               interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_ENET1_ROOT>,
+                                        <&clk IMX8MM_CLK_ENET1_ROOT>,
+                                        <&clk IMX8MM_CLK_ENET_TIMER>,
+                                        <&clk IMX8MM_CLK_ENET_REF>,
+                                        <&clk IMX8MM_CLK_ENET_PHY_REF>;
+                               clock-names = "ipg", "ahb", "ptp",
+                                             "enet_clk_ref", "enet_out";
+                               assigned-clocks = <&clk IMX8MM_CLK_ENET_AXI>,
+                                                 <&clk IMX8MM_CLK_ENET_TIMER>,
+                                                 <&clk IMX8MM_CLK_ENET_REF>,
+                                                 <&clk IMX8MM_CLK_ENET_TIMER>;
+                               assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_266M>,
+                                                        <&clk IMX8MM_SYS_PLL2_100M>,
+                                                        <&clk IMX8MM_SYS_PLL2_125M>;
+                               assigned-clock-rates = <0>, <0>, <125000000>, <100000000>;
+                               fsl,num-tx-queues = <3>;
+                               fsl,num-rx-queues = <3>;
+                               status = "disabled";
+                       };
+
+               };
+
+               aips4: bus@32c00000 {
+                       compatible = "fsl,aips-bus", "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       usbotg1: usb@32e40000 {
+                               compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb";
+                               reg = <0x32e40000 0x200>;
+                               interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>;
+                               clock-names = "usb1_ctrl_root_clk";
+                               assigned-clocks = <&clk IMX8MM_CLK_USB_BUS>,
+                                                 <&clk IMX8MM_CLK_USB_CORE_REF>;
+                               assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_500M>,
+                                                        <&clk IMX8MM_SYS_PLL1_100M>;
+                               fsl,usbphy = <&usbphynop1>;
+                               fsl,usbmisc = <&usbmisc1 0>;
+                               status = "disabled";
+                       };
+
+                       usbphynop1: usbphynop1 {
+                               compatible = "usb-nop-xceiv";
+                               clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
+                               assigned-clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
+                               assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_100M>;
+                               clock-names = "main_clk";
+                       };
+
+                       usbmisc1: usbmisc@32e40200 {
+                               compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc";
+                               #index-cells = <1>;
+                               reg = <0x32e40200 0x200>;
+                       };
+
+                       usbotg2: usb@32e50000 {
+                               compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb";
+                               reg = <0x32e50000 0x200>;
+                               interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>;
+                               clock-names = "usb1_ctrl_root_clk";
+                               assigned-clocks = <&clk IMX8MM_CLK_USB_BUS>,
+                                                 <&clk IMX8MM_CLK_USB_CORE_REF>;
+                               assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_500M>,
+                                                        <&clk IMX8MM_SYS_PLL1_100M>;
+                               fsl,usbphy = <&usbphynop2>;
+                               fsl,usbmisc = <&usbmisc2 0>;
+                               status = "disabled";
+                       };
+
+                       usbphynop2: usbphynop2 {
+                               compatible = "usb-nop-xceiv";
+                               clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
+                               assigned-clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
+                               assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_100M>;
+                               clock-names = "main_clk";
+                       };
+
+                       usbmisc2: usbmisc@32e50200 {
+                               compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc";
+                               #index-cells = <1>;
+                               reg = <0x32e50200 0x200>;
+                       };
+
+               };
+
+               dma_apbh: dma-controller@33000000 {
+                       compatible = "fsl,imx7d-dma-apbh", "fsl,imx28-dma-apbh";
+                       reg = <0x33000000 0x2000>;
+                       interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "gpmi0", "gpmi1", "gpmi2", "gpmi3";
+                       #dma-cells = <1>;
+                       dma-channels = <4>;
+                       clocks = <&clk IMX8MM_CLK_NAND_USDHC_BUS_RAWNAND_CLK>;
+               };
+
+               gpmi: nand-controller@33002000{
+                       compatible = "fsl,imx8mm-gpmi-nand", "fsl,imx7d-gpmi-nand";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0x33002000 0x2000>, <0x33004000 0x4000>;
+                       reg-names = "gpmi-nand", "bch";
+                       interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "bch";
+                       clocks = <&clk IMX8MM_CLK_NAND_ROOT>,
+                                <&clk IMX8MM_CLK_NAND_USDHC_BUS_RAWNAND_CLK>;
+                       clock-names = "gpmi_io", "gpmi_bch_apb";
+                       dmas = <&dma_apbh 0>;
+                       dma-names = "rx-tx";
+                       status = "disabled";
+               };
+       };
+};
index 54737bf1772fef8e26af05f245c8eb9ecf5c3eb2..b2038be8bbd7f679d31873f3095c88148caf74f8 100644 (file)
                reg = <0x00000000 0x40000000 0 0xc0000000>;
        };
 
+       pcie0_refclk: pcie0-refclk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <100000000>;
+       };
+
        reg_usdhc2_vmmc: regulator-vsd-3v3 {
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_reg_usdhc2>;
                gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
                enable-active-high;
        };
+
+       buck2_reg: regulator-buck2 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_buck2>;
+               compatible = "regulator-gpio";
+               regulator-name = "vdd_arm";
+               regulator-min-microvolt = <900000>;
+               regulator-max-microvolt = <1000000>;
+               gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
+               states = <1000000 0x0
+                         900000 0x1>;
+       };
+
+       wm8524: audio-codec {
+               #sound-dai-cells = <0>;
+               compatible = "wlf,wm8524";
+               wlf,mute-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
+       };
+
+       sound-wm8524 {
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "wm8524-audio";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,frame-master = <&cpudai>;
+               simple-audio-card,bitclock-master = <&cpudai>;
+               simple-audio-card,widgets =
+                       "Line", "Left Line Out Jack",
+                       "Line", "Right Line Out Jack";
+               simple-audio-card,routing =
+                       "Left Line Out Jack", "LINEVOUTL",
+                       "Right Line Out Jack", "LINEVOUTR";
+
+               cpudai: simple-audio-card,cpu {
+                       sound-dai = <&sai2>;
+               };
+
+               link_codec: simple-audio-card,codec {
+                       sound-dai = <&wm8524>;
+                       clocks = <&clk IMX8MQ_CLK_SAI2_ROOT>;
+               };
+       };
+};
+
+&A53_0 {
+       cpu-supply = <&buck2_reg>;
+};
+
+&A53_1 {
+       cpu-supply = <&buck2_reg>;
+};
+
+&A53_2 {
+       cpu-supply = <&buck2_reg>;
+};
+
+&A53_3 {
+       cpu-supply = <&buck2_reg>;
 };
 
 &fec1 {
        };
 };
 
+&sai2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sai2>;
+       assigned-clocks = <&clk IMX8MQ_CLK_SAI2>;
+       assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1_OUT>;
+       assigned-clock-rates = <24576000>;
+       status = "okay";
+};
+
+&gpio5 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wifi_reset>;
+
+       wl-reg-on {
+               gpio-hog;
+               gpios = <29 GPIO_ACTIVE_HIGH>;
+               output-high;
+       };
+};
+
 &i2c1 {
        clock-frequency = <100000>;
        pinctrl-names = "default";
        };
 };
 
+&pcie0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie0>;
+       reset-gpio = <&gpio5 28 GPIO_ACTIVE_LOW>;
+       clocks = <&clk IMX8MQ_CLK_PCIE1_ROOT>,
+                <&clk IMX8MQ_CLK_PCIE1_AUX>,
+                <&clk IMX8MQ_CLK_PCIE1_PHY>,
+                <&pcie0_refclk>;
+       clock-names = "pcie", "pcie_aux", "pcie_phy", "pcie_bus";
+       status = "okay";
+};
+
+&pgc_gpu {
+       power-supply = <&sw1a_reg>;
+};
+
 &uart1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart1>;
 };
 
 &iomuxc {
+       pinctrl_buck2: vddarmgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_GPIO1_IO13_GPIO1_IO13              0x19
+               >;
+
+       };
+
        pinctrl_fec1: fec1grp {
                fsl,pins = <
                        MX8MQ_IOMUXC_ENET_MDC_ENET1_MDC                 0x3
                >;
        };
 
+       pinctrl_pcie0: pcie0grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_I2C4_SCL_PCIE1_CLKREQ_B            0x76
+                       MX8MQ_IOMUXC_UART4_RXD_GPIO5_IO28               0x16
+               >;
+       };
+
        pinctrl_qspi: qspigrp {
                fsl,pins = <
                        MX8MQ_IOMUXC_NAND_ALE_QSPI_A_SCLK       0x82
                >;
        };
 
+       pinctrl_sai2: sai2grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SAI2_TXFS_SAI2_TX_SYNC     0xd6
+                       MX8MQ_IOMUXC_SAI2_TXC_SAI2_TX_BCLK      0xd6
+                       MX8MQ_IOMUXC_SAI2_MCLK_SAI2_MCLK        0xd6
+                       MX8MQ_IOMUXC_SAI2_TXD0_SAI2_TX_DATA0    0xd6
+                       MX8MQ_IOMUXC_GPIO1_IO08_GPIO1_IO8       0xd6
+               >;
+       };
+
        pinctrl_uart1: uart1grp {
                fsl,pins = <
                        MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX             0x49
                        MX8MQ_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B            0xc6
                >;
        };
+
+       pinctrl_wifi_reset: wifiresetgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_UART4_TXD_GPIO5_IO29               0x16
+               >;
+       };
 };
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-zii-ultra-rmb3.dts b/arch/arm64/boot/dts/freescale/imx8mq-zii-ultra-rmb3.dts
new file mode 100644 (file)
index 0000000..d2a6da4
--- /dev/null
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2019 Zodiac Inflight Innovations
+ */
+
+/dts-v1/;
+
+#include "imx8mq-zii-ultra.dtsi"
+
+/ {
+       model = "ZII i.MX8MQ Ultra RMB3 Board";
+       compatible = "zii,imx8mq-ultra-rmb3", "zii,imx8mq-ultra", "fsl,imx8mq";
+};
+
+&ecspi1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi1>;
+       cs-gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       nor_flash: flash@0 {
+               compatible = "st,n25q128a13", "jedec,spi-nor";
+               spi-max-frequency = <20000000>;
+               reg = <0>;
+       };
+};
+
+&i2c2 {
+       temp-sense@48 {
+               compatible = "national,lm75";
+               reg = <0x48>;
+       };
+};
+
+&i2c4 {
+       touchscreen@20 {
+               compatible = "syna,rmi4-i2c";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_ts>;
+               reg = <0x20>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               rmi4-f01@1 {
+                       reg = <0x1>;
+                       syna,nosleep-mode = <2>;
+               };
+
+               rmi4-f11@11 {
+                       reg = <0x11>;
+                       touchscreen-inverted-x;
+                       touchscreen-swapped-x-y;
+                       syna,sensor-type = <1>;
+               };
+
+               rmi4-f12@12 {
+                       reg = <0x12>;
+                       touchscreen-inverted-x;
+                       touchscreen-swapped-x-y;
+                       syna,sensor-type = <1>;
+               };
+       };
+
+       touchscreen@2a {
+               compatible = "eeti,exc3000";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_ts>;
+               reg = <0x2a>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
+               touchscreen-inverted-x;
+               touchscreen-swapped-x-y;
+               status = "disabled";
+       };
+};
+
+&usbhub {
+       swap-dx-lanes = <0>;
+};
+
+&iomuxc {
+       pinctrl_ecspi1: ecspi1grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_ECSPI1_SS0_GPIO5_IO9       0x19
+                       MX8MQ_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK    0x82
+                       MX8MQ_IOMUXC_ECSPI1_MISO_ECSPI1_MISO    0x82
+                       MX8MQ_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI    0x82
+               >;
+       };
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-zii-ultra-zest.dts b/arch/arm64/boot/dts/freescale/imx8mq-zii-ultra-zest.dts
new file mode 100644 (file)
index 0000000..1084d93
--- /dev/null
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2019 Zodiac Inflight Innovations
+ */
+
+/dts-v1/;
+
+#include "imx8mq-zii-ultra.dtsi"
+
+/ {
+       model = "ZII i.MX8MQ Ultra Zest Board";
+       compatible = "zii,imx8mq-ultra-zest", "zii,imx8mq-ultra", "fsl,imx8mq";
+};
+
+&i2c4 {
+       touchscreen@4a {
+               compatible = "atmel,maxtouch";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_ts>;
+               reg = <0x4a>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
+       };
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-zii-ultra.dtsi b/arch/arm64/boot/dts/freescale/imx8mq-zii-ultra.dtsi
new file mode 100644 (file)
index 0000000..7a1706f
--- /dev/null
@@ -0,0 +1,725 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2019 Zodiac Inflight Innovations
+ */
+
+#include "imx8mq.dtsi"
+
+/ {
+       aliases {
+               mdio-gpio0 = &mdio0;
+               rtc0 = &ds1341;
+       };
+
+       chosen {
+               stdout-path = &uart1;
+       };
+
+       mdio0: bitbang-mdio {
+               compatible = "virtual,mdio-gpio";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_mdio_bitbang>, <&pinctrl_fec1_phy_reset>;
+               gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>, /* MDC */
+                       <&gpio1 14 GPIO_ACTIVE_HIGH>; /* MDIO */
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               phy0: ethernet-phy@0 {
+                       reg = <0>;
+                       reset-gpios = <&gpio1 29 GPIO_ACTIVE_LOW>;
+               };
+       };
+
+       pcie0_refclk: clock-pcie0-refclk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <100000000>;
+       };
+
+       pcie1_refclk: clock-pcie1-refclk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <100000000>;
+       };
+
+       reg_12p0_main: regulator-12p0-main {
+               compatible = "regulator-fixed";
+               regulator-name = "12V_MAIN";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+       };
+
+       reg_5p0_main: regulator-5p0-main {
+               compatible = "regulator-fixed";
+               vin-supply = <&reg_12p0_main>;
+               regulator-name = "5V_MAIN";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+       };
+
+       reg_3p3_main: regulator-3p3-main {
+               compatible = "regulator-fixed";
+               vin-supply = <&reg_12p0_main>;
+               regulator-name = "3V3V_MAIN";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+
+       reg_5p0_user_usb: regulator-5p0-user-usb {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_user_usb>;
+               vin-supply = <&reg_5p0_main>;
+               regulator-name = "5V_USER_USB";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               gpio = <&gpio3 12 GPIO_ACTIVE_LOW>;
+               startup-delay-us = <1000>;
+       };
+
+       reg_usdhc2_vmmc: regulator-vsd-3v3 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_usdhc2>;
+               compatible = "regulator-fixed";
+               vin-supply = <&reg_3p3_main>;
+               regulator-name = "3V3_SD";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_arm: regulator-arm {
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_arm>;
+               compatible = "regulator-gpio";
+               vin-supply = <&reg_12p0_main>;
+               regulator-name = "0V9_ARM";
+               regulator-min-microvolt = <900000>;
+               regulator-max-microvolt = <1000000>;
+               gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
+               states = <1000000 0x0
+                          900000 0x1>;
+               regulator-always-on;
+       };
+};
+
+&A53_0 {
+       cpu-supply = <&reg_arm>;
+};
+
+&A53_1 {
+       cpu-supply = <&reg_arm>;
+};
+
+&A53_2 {
+       cpu-supply = <&reg_arm>;
+};
+
+&A53_3 {
+       cpu-supply = <&reg_arm>;
+};
+
+&fec1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec1>;
+
+       phy-handle = <&phy0>;
+       phy-mode = "rmii";
+       status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "okay";
+
+               switch: switch@0 {
+                       compatible = "marvell,mv88e6085";
+                       pinctrl-0 = <&pinctrl_switch_irq>;
+                       pinctrl-names = "default";
+                       reg = <0>;
+                       dsa,member = <0 0>;
+                       eeprom-length = <512>;
+                       interrupt-parent = <&gpio1>;
+                       interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       label = "gigabit_proc";
+                                       phy-handle = <&switchphy0>;
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                                       label = "netaux";
+                                       phy-handle = <&switchphy1>;
+                               };
+
+                               port@2 {
+                                       reg = <2>;
+                                       label = "cpu";
+                                       ethernet = <&fec1>;
+
+                                       fixed-link {
+                                               speed = <100>;
+                                               full-duplex;
+                                       };
+                               };
+
+                               port@3 {
+                                       reg = <3>;
+                                       label = "netright";
+                                       phy-handle = <&switchphy3>;
+                               };
+
+                               port@4 {
+                                       reg = <4>;
+                                       label = "netleft";
+                                       phy-handle = <&switchphy4>;
+                               };
+                       };
+
+                       mdio {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               switchphy0: switchphy@0 {
+                                       reg = <0>;
+                                       interrupt-parent = <&switch>;
+                                       interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+                               };
+
+                               switchphy1: switchphy@1 {
+                                       reg = <1>;
+                                       interrupt-parent = <&switch>;
+                                       interrupts = <1 IRQ_TYPE_LEVEL_HIGH>;
+                               };
+
+                               switchphy2: switchphy@2 {
+                                       reg = <2>;
+                                       interrupt-parent = <&switch>;
+                                       interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
+                               };
+
+                               switchphy3: switchphy@3 {
+                                       reg = <3>;
+                                       interrupt-parent = <&switch>;
+                                       interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
+                               };
+
+                               switchphy4: switchphy@4 {
+                                       reg = <4>;
+                                       interrupt-parent = <&switch>;
+                                       interrupts = <4 IRQ_TYPE_LEVEL_HIGH>;
+                               };
+                       };
+               };
+       };
+};
+
+&gpio3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpio3_hog>;
+
+       usb-emulation {
+               gpio-hog;
+               gpios = <10 GPIO_ACTIVE_HIGH>;
+               output-low;
+               line-name = "usb-emulation";
+       };
+
+       usb-mode1 {
+               gpio-hog;
+               gpios = <11 GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "usb-mode1";
+       };
+
+       usb-mode2 {
+               gpio-hog;
+               gpios = <13 GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "usb-mode2";
+       };
+};
+
+&i2c1 {
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       status = "okay";
+};
+
+&i2c2 {
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       status = "okay";
+
+       pmic@8 {
+               compatible = "fsl,pfuze100";
+               reg = <0x8>;
+
+               regulators {
+                       sw1a_reg: sw1ab {
+                               regulator-min-microvolt = <825000>;
+                               regulator-max-microvolt = <1100000>;
+                       };
+
+                       sw1c_reg: sw1c {
+                               regulator-min-microvolt = <825000>;
+                               regulator-max-microvolt = <1100000>;
+                       };
+
+                       sw2_reg: sw2 {
+                               regulator-min-microvolt = <1100000>;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-always-on;
+                       };
+
+                       sw3a_reg: sw3ab {
+                               regulator-min-microvolt = <825000>;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-always-on;
+                       };
+
+                       sw4_reg: sw4 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                       };
+
+                       swbst_reg: swbst {
+                               regulator-min-microvolt = <5000000>;
+                               regulator-max-microvolt = <5150000>;
+                       };
+
+                       snvs_reg: vsnvs {
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-always-on;
+                       };
+
+                       vref_reg: vrefddr {
+                               regulator-always-on;
+                       };
+
+                       vgen1_reg: vgen1 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1550000>;
+                       };
+
+                       vgen2_reg: vgen2 {
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <975000>;
+                               regulator-always-on;
+                       };
+
+                       vgen3_reg: vgen3 {
+                               regulator-min-microvolt = <1675000>;
+                               regulator-max-microvolt = <1975000>;
+                               regulator-always-on;
+                       };
+
+                       vgen4_reg: vgen4 {
+                               regulator-min-microvolt = <1625000>;
+                               regulator-max-microvolt = <1875000>;
+                               regulator-always-on;
+                       };
+
+                       vgen5_reg: vgen5 {
+                               regulator-min-microvolt = <3075000>;
+                               regulator-max-microvolt = <3625000>;
+                               regulator-always-on;
+                       };
+
+                       vgen6_reg: vgen6 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+               };
+       };
+
+       eeprom@54 {
+               compatible = "atmel,24c128";
+               reg = <0x54>;
+       };
+
+       ds1341: rtc@68 {
+               compatible = "dallas,ds1341";
+               reg = <0x68>;
+       };
+};
+
+&i2c3 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       status = "okay";
+
+       usbhub: usbhub@2c {
+               compatible ="microchip,usb2513b";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usbhub>;
+               reg = <0x2c>;
+               reset-gpios = <&gpio3 25 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c4>;
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       status = "okay";
+
+       rave-sp {
+               compatible = "zii,rave-sp-rdu2";
+               current-speed = <1000000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               watchdog {
+                       compatible = "zii,rave-sp-watchdog";
+               };
+
+               backlight {
+                       compatible = "zii,rave-sp-backlight";
+               };
+
+               pwrbutton {
+                       compatible = "zii,rave-sp-pwrbutton";
+               };
+
+               eeprom@a3 {
+                       compatible = "zii,rave-sp-eeprom";
+                       reg = <0xa3 0x4000>;
+                       zii,eeprom-name = "dds-eeprom";
+               };
+
+               eeprom@a4 {
+                       compatible = "zii,rave-sp-eeprom";
+                       reg = <0xa4 0x4000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       zii,eeprom-name = "main-eeprom";
+               };
+       };
+};
+
+&usb3_phy0 {
+       vbus-supply = <&reg_5p0_user_usb>;
+       status = "okay";
+};
+
+&usb_dwc3_0 {
+       dr_mode = "host";
+       status = "okay";
+};
+
+&usb3_phy1 {
+       vbus-supply = <&reg_5p0_main>;
+       status = "okay";
+};
+
+&usb_dwc3_1 {
+       dr_mode = "host";
+       status = "okay";
+};
+
+&pcie0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie0>;
+       reset-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
+       clocks = <&clk IMX8MQ_CLK_PCIE1_ROOT>,
+                <&clk IMX8MQ_CLK_PCIE1_AUX>,
+                <&clk IMX8MQ_CLK_PCIE1_PHY>,
+                <&pcie0_refclk>;
+       clock-names = "pcie", "pcie_aux", "pcie_phy", "pcie_bus";
+       status = "okay";
+};
+
+&pcie1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie1>;
+       reset-gpio = <&gpio1 6 GPIO_ACTIVE_LOW>;
+       clocks = <&clk IMX8MQ_CLK_PCIE2_ROOT>,
+                <&clk IMX8MQ_CLK_PCIE2_AUX>,
+                <&clk IMX8MQ_CLK_PCIE2_PHY>,
+                <&pcie1_refclk>;
+       clock-names = "pcie", "pcie_aux", "pcie_phy", "pcie_bus";
+       status = "okay";
+};
+
+&pgc_gpu {
+       power-supply = <&sw1a_reg>;
+};
+
+&pgc_vpu {
+       power-supply = <&sw1c_reg>;
+};
+
+&usdhc1 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc1>;
+       pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+       vqmmc-supply = <&sw4_reg>;
+       bus-width = <8>;
+       non-removable;
+       no-sd;
+       no-sdio;
+       status = "okay";
+};
+
+&usdhc2 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc2>;
+       pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
+       cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+       vmmc-supply = <&reg_usdhc2_vmmc>;
+       status = "okay";
+};
+
+&snvs_rtc {
+       status = "disabled";
+};
+
+&iomuxc {
+       pinctrl_fec1: fec1grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_ENET_MDC_ENET1_MDC                 0x3
+                       MX8MQ_IOMUXC_ENET_MDIO_ENET1_MDIO               0x23
+                       MX8MQ_IOMUXC_ENET_TD1_ENET1_RGMII_TD1           0x1f
+                       MX8MQ_IOMUXC_ENET_TD0_ENET1_RGMII_TD0           0x1f
+                       MX8MQ_IOMUXC_ENET_RD1_ENET1_RGMII_RD1           0x91
+                       MX8MQ_IOMUXC_ENET_RD0_ENET1_RGMII_RD0           0x91
+                       MX8MQ_IOMUXC_ENET_TD2_ENET1_TX_CLK              0x1f
+                       MX8MQ_IOMUXC_ENET_RXC_ENET1_RX_ER               0x91
+                       MX8MQ_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL     0x91
+                       MX8MQ_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL     0x1f
+               >;
+       };
+
+       pinctrl_fec1_phy_reset: fec1phyresetgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_ENET_RD3_GPIO1_IO29                0x11
+               >;
+       };
+
+       pinctrl_gpio3_hog: gpio3hoggrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_NAND_DATA04_GPIO3_IO10             0x6
+                       MX8MQ_IOMUXC_NAND_DATA05_GPIO3_IO11             0x6
+                       MX8MQ_IOMUXC_NAND_DATA07_GPIO3_IO13             0x6
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_I2C1_SCL_I2C1_SCL                  0x4000007f
+                       MX8MQ_IOMUXC_I2C1_SDA_I2C1_SDA                  0x4000007f
+               >;
+       };
+
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_I2C2_SCL_I2C2_SCL                  0x4000007f
+                       MX8MQ_IOMUXC_I2C2_SDA_I2C2_SDA                  0x4000007f
+               >;
+       };
+
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_I2C3_SCL_I2C3_SCL                  0x4000007f
+                       MX8MQ_IOMUXC_I2C3_SDA_I2C3_SDA                  0x4000007f
+               >;
+       };
+
+       pinctrl_i2c4: i2c4grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_I2C4_SCL_I2C4_SCL                  0x4000007f
+                       MX8MQ_IOMUXC_I2C4_SDA_I2C4_SDA                  0x4000007f
+               >;
+       };
+
+       pinctrl_mdio_bitbang: bitbangmdiogrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_GPIO1_IO13_GPIO1_IO13              0x44
+                       MX8MQ_IOMUXC_GPIO1_IO14_GPIO1_IO14              0x64
+               >;
+       };
+
+       pinctrl_pcie0: pcie0grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_UART4_RXD_PCIE1_CLKREQ_B           0x66
+                       MX8MQ_IOMUXC_GPIO1_IO03_GPIO1_IO3               0x6
+               >;
+       };
+
+       pinctrl_pcie1: pcie1grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_UART4_TXD_PCIE2_CLKREQ_B           0x66
+                       MX8MQ_IOMUXC_GPIO1_IO06_GPIO1_IO6               0x6
+               >;
+       };
+
+       pinctrl_reg_arm: regarmgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_NAND_READY_B_GPIO3_IO16            0x19
+               >;
+       };
+
+       pinctrl_reg_usdhc2: regusdhc2grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD2_RESET_B_GPIO2_IO19             0x41
+               >;
+       };
+
+       pinctrl_reg_user_usb: reguserusbgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_NAND_DATA06_GPIO3_IO12             0x6
+               >;
+       };
+
+       pinctrl_switch_irq: switchgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_GPIO1_IO15_GPIO1_IO15              0x41
+               >;
+       };
+
+       pinctrl_ts: tsgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_GPIO1_IO11_GPIO1_IO11              0x96
+                       MX8MQ_IOMUXC_GPIO1_IO12_GPIO1_IO12              0x96
+               >;
+       };
+
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX             0x49
+                       MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX             0x49
+               >;
+       };
+
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_UART2_RXD_UART2_DCE_RX             0x49
+                       MX8MQ_IOMUXC_UART2_TXD_UART2_DCE_TX             0x49
+               >;
+       };
+
+       pinctrl_usbhub: usbhubgrp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SAI5_MCLK_GPIO3_IO25               0x41
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK                 0x83
+                       MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD                 0xc3
+                       MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0             0xc3
+                       MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1             0xc3
+                       MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2             0xc3
+                       MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3             0xc3
+                       MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4             0xc3
+                       MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5             0xc3
+                       MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6             0xc3
+                       MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7             0xc3
+                       MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE           0x83
+                       MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B         0xc1
+               >;
+       };
+
+       pinctrl_usdhc1_100mhz: usdhc1-100grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK                 0x8d
+                       MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD                 0xcd
+                       MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0             0xcd
+                       MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1             0xcd
+                       MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2             0xcd
+                       MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3             0xcd
+                       MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4             0xcd
+                       MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5             0xcd
+                       MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6             0xcd
+                       MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7             0xcd
+                       MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE           0x8d
+                       MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B         0xc1
+               >;
+       };
+
+       pinctrl_usdhc1_200mhz: usdhc1-200grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD1_CLK_USDHC1_CLK                 0x9f
+                       MX8MQ_IOMUXC_SD1_CMD_USDHC1_CMD                 0xdf
+                       MX8MQ_IOMUXC_SD1_DATA0_USDHC1_DATA0             0xdf
+                       MX8MQ_IOMUXC_SD1_DATA1_USDHC1_DATA1             0xdf
+                       MX8MQ_IOMUXC_SD1_DATA2_USDHC1_DATA2             0xdf
+                       MX8MQ_IOMUXC_SD1_DATA3_USDHC1_DATA3             0xdf
+                       MX8MQ_IOMUXC_SD1_DATA4_USDHC1_DATA4             0xdf
+                       MX8MQ_IOMUXC_SD1_DATA5_USDHC1_DATA5             0xdf
+                       MX8MQ_IOMUXC_SD1_DATA6_USDHC1_DATA6             0xdf
+                       MX8MQ_IOMUXC_SD1_DATA7_USDHC1_DATA7             0xdf
+                       MX8MQ_IOMUXC_SD1_STROBE_USDHC1_STROBE           0x9f
+                       MX8MQ_IOMUXC_SD1_RESET_B_USDHC1_RESET_B         0xc1
+               >;
+       };
+
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK                 0x83
+                       MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD                 0xc3
+                       MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0             0xc3
+                       MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1             0xc3
+                       MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2             0xc3
+                       MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3             0xc3
+                       MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0xc1
+               >;
+       };
+
+       pinctrl_usdhc2_100mhz: usdhc2-100grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK                 0x85
+                       MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD                 0xc5
+                       MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0             0xc5
+                       MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1             0xc5
+                       MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2             0xc5
+                       MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3             0xc5
+                       MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0xc1
+               >;
+       };
+
+       pinctrl_usdhc2_200mhz: usdhc2-200grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SD2_CLK_USDHC2_CLK                 0x87
+                       MX8MQ_IOMUXC_SD2_CMD_USDHC2_CMD                 0xc7
+                       MX8MQ_IOMUXC_SD2_DATA0_USDHC2_DATA0             0xc7
+                       MX8MQ_IOMUXC_SD2_DATA1_USDHC2_DATA1             0xc7
+                       MX8MQ_IOMUXC_SD2_DATA2_USDHC2_DATA2             0xc7
+                       MX8MQ_IOMUXC_SD2_DATA3_USDHC2_DATA3             0xc7
+                       MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0xc1
+               >;
+       };
+};
index 9155bd4784ebf9a1934a3c325ffcdcb7a48e3aed..6d635ba0904c509c4f035721934285549c815acd 100644 (file)
@@ -6,8 +6,10 @@
 
 #include <dt-bindings/clock/imx8mq-clock.h>
 #include <dt-bindings/power/imx8mq-power.h>
+#include <dt-bindings/reset/imx8mq-reset.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/thermal/thermal.h>
 #include "imx8mq-pinfunc.h"
 
 / {
                        device_type = "cpu";
                        compatible = "arm,cortex-a53";
                        reg = <0x0>;
+                       clock-latency = <61036>; /* two CLK32 periods */
+                       clocks = <&clk IMX8MQ_CLK_ARM>;
                        enable-method = "psci";
                        next-level-cache = <&A53_L2>;
+                       operating-points-v2 = <&a53_opp_table>;
+                       #cooling-cells = <2>;
                };
 
                A53_1: cpu@1 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a53";
                        reg = <0x1>;
+                       clock-latency = <61036>; /* two CLK32 periods */
+                       clocks = <&clk IMX8MQ_CLK_ARM>;
                        enable-method = "psci";
                        next-level-cache = <&A53_L2>;
+                       operating-points-v2 = <&a53_opp_table>;
+                       #cooling-cells = <2>;
                };
 
                A53_2: cpu@2 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a53";
                        reg = <0x2>;
+                       clock-latency = <61036>; /* two CLK32 periods */
+                       clocks = <&clk IMX8MQ_CLK_ARM>;
                        enable-method = "psci";
                        next-level-cache = <&A53_L2>;
+                       operating-points-v2 = <&a53_opp_table>;
+                       #cooling-cells = <2>;
                };
 
                A53_3: cpu@3 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a53";
                        reg = <0x3>;
+                       clock-latency = <61036>; /* two CLK32 periods */
+                       clocks = <&clk IMX8MQ_CLK_ARM>;
                        enable-method = "psci";
                        next-level-cache = <&A53_L2>;
+                       operating-points-v2 = <&a53_opp_table>;
+                       #cooling-cells = <2>;
                };
 
                A53_L2: l2-cache0 {
                };
        };
 
+       a53_opp_table: opp-table {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-800000000 {
+                       opp-hz = /bits/ 64 <800000000>;
+                       opp-microvolt = <900000>;
+                       clock-latency-ns = <150000>;
+               };
+
+               opp-1300000000 {
+                       opp-hz = /bits/ 64 <1300000000>;
+                       opp-microvolt = <1000000>;
+                       clock-latency-ns = <150000>;
+                       opp-suspend;
+               };
+       };
+
        pmu {
                compatible = "arm,cortex-a53-pmu";
                interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
                method = "smc";
        };
 
+       thermal-zones {
+               cpu-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <2000>;
+                       thermal-sensors = <&tmu 0>;
+
+                       trips {
+                               cpu_alert: cpu-alert {
+                                       temperature = <80000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               cpu-crit {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu_alert>;
+                                       cooling-device =
+                                               <&A53_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&A53_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&A53_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                               <&A53_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               gpu-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <2000>;
+                       thermal-sensors = <&tmu 1>;
+
+                       trips {
+                               gpu-crit {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               vpu-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <2000>;
+                       thermal-sensors = <&tmu 2>;
+
+                       trips {
+                               vpu-crit {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+       };
+
        timer {
                compatible = "arm,armv8-timer";
                interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, /* Physical Secure */
                                reg = <0x30200000 0x10000>;
                                interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MQ_CLK_GPIO1_ROOT>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
                                reg = <0x30210000 0x10000>;
                                interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MQ_CLK_GPIO2_ROOT>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
                                reg = <0x30220000 0x10000>;
                                interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MQ_CLK_GPIO3_ROOT>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
                                reg = <0x30230000 0x10000>;
                                interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MQ_CLK_GPIO4_ROOT>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
                                reg = <0x30240000 0x10000>;
                                interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MQ_CLK_GPIO5_ROOT>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
                                #interrupt-cells = <2>;
                        };
 
+                       tmu: tmu@30260000 {
+                               compatible = "fsl,imx8mq-tmu";
+                               reg = <0x30260000 0x10000>;
+                               interrupt = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+                               little-endian;
+                               fsl,tmu-range = <0xb0000 0xa0026 0x80048 0x70061>;
+                               fsl,tmu-calibration = <0x00000000 0x00000023
+                                                      0x00000001 0x00000029
+                                                      0x00000002 0x0000002f
+                                                      0x00000003 0x00000035
+                                                      0x00000004 0x0000003d
+                                                      0x00000005 0x00000043
+                                                      0x00000006 0x0000004b
+                                                      0x00000007 0x00000051
+                                                      0x00000008 0x00000057
+                                                      0x00000009 0x0000005f
+                                                      0x0000000a 0x00000067
+                                                      0x0000000b 0x0000006f
+
+                                                      0x00010000 0x0000001b
+                                                      0x00010001 0x00000023
+                                                      0x00010002 0x0000002b
+                                                      0x00010003 0x00000033
+                                                      0x00010004 0x0000003b
+                                                      0x00010005 0x00000043
+                                                      0x00010006 0x0000004b
+                                                      0x00010007 0x00000055
+                                                      0x00010008 0x0000005d
+                                                      0x00010009 0x00000067
+                                                      0x0001000a 0x00000070
+
+                                                      0x00020000 0x00000017
+                                                      0x00020001 0x00000023
+                                                      0x00020002 0x0000002d
+                                                      0x00020003 0x00000037
+                                                      0x00020004 0x00000041
+                                                      0x00020005 0x0000004b
+                                                      0x00020006 0x00000057
+                                                      0x00020007 0x00000063
+                                                      0x00020008 0x0000006f
+
+                                                      0x00030000 0x00000015
+                                                      0x00030001 0x00000021
+                                                      0x00030002 0x0000002d
+                                                      0x00030003 0x00000039
+                                                      0x00030004 0x00000045
+                                                      0x00030005 0x00000053
+                                                      0x00030006 0x0000005f
+                                                      0x00030007 0x00000071>;
+                               #thermal-sensor-cells =  <1>;
+                       };
+
                        wdog1: watchdog@30280000 {
                                compatible = "fsl,imx8mq-wdt", "fsl,imx21-wdt";
                                reg = <0x30280000 0x10000>;
                                status = "disabled";
                        };
 
+                       sdma2: sdma@302c0000 {
+                               compatible = "fsl,imx8mq-sdma","fsl,imx7d-sdma";
+                               reg = <0x302c0000 0x10000>;
+                               interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MQ_CLK_SDMA2_ROOT>,
+                                        <&clk IMX8MQ_CLK_SDMA2_ROOT>;
+                               clock-names = "ipg", "ahb";
+                               #dma-cells = <3>;
+                               fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin";
+                       };
+
                        iomuxc: iomuxc@30330000 {
                                compatible = "fsl,imx8mq-iomuxc";
                                reg = <0x30330000 0x10000>;
                        };
 
                        iomuxc_gpr: syscon@30340000 {
-                               compatible = "fsl,imx8mq-iomuxc-gpr", "syscon";
+                               compatible = "fsl,imx8mq-iomuxc-gpr", "fsl,imx6q-iomuxc-gpr", "syscon";
                                reg = <0x30340000 0x10000>;
                        };
 
+                       ocotp: ocotp-ctrl@30350000 {
+                               compatible = "fsl,imx8mq-ocotp", "syscon";
+                               reg = <0x30350000 0x10000>;
+                               clocks = <&clk IMX8MQ_CLK_OCOTP_ROOT>;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                       };
+
                        anatop: syscon@30360000 {
                                compatible = "fsl,imx8mq-anatop", "syscon";
                                reg = <0x30360000 0x10000>;
                                              "clk_ext3", "clk_ext4";
                        };
 
+                       src: reset-controller@30390000 {
+                               compatible = "fsl,imx8mq-src", "syscon";
+                               reg = <0x30390000 0x10000>;
+                               #reset-cells = <1>;
+                       };
+
                        gpc: gpc@303a0000 {
                                compatible = "fsl,imx8mq-gpc";
                                reg = <0x303a0000 0x10000>;
                                                reg = <IMX8M_POWER_DOMAIN_MIPI>;
                                        };
 
-                                       pgc_pcie1: power-domain@1 {
+                                       /*
+                                        * As per comment in ATF source code:
+                                        *
+                                        * PCIE1 and PCIE2 share the
+                                        * same reset signal, if we
+                                        * power down PCIE2, PCIE1
+                                        * will be held in reset too.
+                                        *
+                                        * So instead of creating two
+                                        * separate power domains for
+                                        * PCIE1 and PCIE2 we create a
+                                        * link between both and use
+                                        * it as a shared PCIE power
+                                        * domain.
+                                        */
+                                       pgc_pcie: power-domain@1 {
                                                #power-domain-cells = <0>;
                                                reg = <IMX8M_POWER_DOMAIN_PCIE1>;
+                                               power-domains = <&pgc_pcie2>;
                                        };
 
                                        pgc_otg1: power-domain@2 {
                                status = "disabled";
                        };
 
+                       sai2: sai@308b0000 {
+                               #sound-dai-cells = <0>;
+                               compatible = "fsl,imx8mq-sai",
+                                            "fsl,imx6sx-sai";
+                               reg = <0x308b0000 0x10000>;
+                               interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MQ_CLK_SAI2_IPG>,
+                                        <&clk IMX8MQ_CLK_SAI2_ROOT>,
+                                        <&clk IMX8MQ_CLK_DUMMY>, <&clk IMX8MQ_CLK_DUMMY>;
+                               clock-names = "bus", "mclk1", "mclk2", "mclk3";
+                               dmas = <&sdma1 10 24 0>, <&sdma1 11 24 0>;
+                               dma-names = "rx", "tx";
+                               status = "disabled";
+                       };
+
                        i2c1: i2c@30a20000 {
                                compatible = "fsl,imx8mq-i2c", "fsl,imx21-i2c";
                                reg = <0x30a20000 0x10000>;
                                status = "disabled";
                        };
 
+                       sdma1: sdma@30bd0000 {
+                               compatible = "fsl,imx8mq-sdma","fsl,imx7d-sdma";
+                               reg = <0x30bd0000 0x10000>;
+                               interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX8MQ_CLK_SDMA1_ROOT>,
+                                        <&clk IMX8MQ_CLK_AHB>;
+                               clock-names = "ipg", "ahb";
+                               #dma-cells = <3>;
+                               fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin";
+                       };
+
                        fec1: ethernet@30be0000 {
                                compatible = "fsl,imx8mq-fec", "fsl,imx6sx-fec";
                                reg = <0x30be0000 0x10000>;
                        };
                };
 
+               gpu: gpu@38000000 {
+                       compatible = "vivante,gc";
+                       reg = <0x38000000 0x40000>;
+                       interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clk IMX8MQ_CLK_GPU_ROOT>,
+                                <&clk IMX8MQ_CLK_GPU_SHADER_DIV>,
+                                <&clk IMX8MQ_CLK_GPU_AXI>,
+                                <&clk IMX8MQ_CLK_GPU_AHB>;
+                       clock-names = "core", "shader", "bus", "reg";
+                       assigned-clocks = <&clk IMX8MQ_CLK_GPU_CORE_SRC>,
+                                         <&clk IMX8MQ_CLK_GPU_SHADER_SRC>,
+                                         <&clk IMX8MQ_CLK_GPU_AXI>,
+                                         <&clk IMX8MQ_CLK_GPU_AHB>,
+                                         <&clk IMX8MQ_GPU_PLL_BYPASS>;
+                       assigned-clock-parents = <&clk IMX8MQ_GPU_PLL_OUT>,
+                                                <&clk IMX8MQ_GPU_PLL_OUT>,
+                                                <&clk IMX8MQ_GPU_PLL_OUT>,
+                                                <&clk IMX8MQ_GPU_PLL_OUT>,
+                                                <&clk IMX8MQ_GPU_PLL>;
+                       assigned-clock-rates = <800000000>, <800000000>,
+                                              <800000000>, <800000000>, <0>;
+                       power-domains = <&pgc_gpu>;
+               };
+
                usb_dwc3_0: usb@38100000 {
                        compatible = "fsl,imx8mq-dwc3", "snps,dwc3";
                        reg = <0x38100000 0x10000>;
                        status = "disabled";
                };
 
+
+               pcie0: pcie@33800000 {
+                       compatible = "fsl,imx8mq-pcie";
+                       reg = <0x33800000 0x400000>,
+                             <0x1ff00000 0x80000>;
+                       reg-names = "dbi", "config";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       bus-range = <0x00 0xff>;
+                       ranges = <0x81000000 0 0x00000000 0x1ff80000 0 0x00010000 /* downstream I/O 64KB */
+                                 0x82000000 0 0x18000000 0x18000000 0 0x07f00000>; /* non-prefetchable memory */
+                       num-lanes = <1>;
+                       num-viewport = <4>;
+                       interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi";
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0x7>;
+                       interrupt-map = <0 0 0 1 &gic GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 2 &gic GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 3 &gic GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 4 &gic GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+                       fsl,max-link-speed = <2>;
+                       power-domains = <&pgc_pcie>;
+                       resets = <&src IMX8MQ_RESET_PCIEPHY>,
+                                <&src IMX8MQ_RESET_PCIE_CTRL_APPS_EN>,
+                                <&src IMX8MQ_RESET_PCIE_CTRL_APPS_TURNOFF>;
+                       reset-names = "pciephy", "apps", "turnoff";
+                       status = "disabled";
+               };
+
+               pcie1: pcie@33c00000 {
+                       compatible = "fsl,imx8mq-pcie";
+                       reg = <0x33c00000 0x400000>,
+                             <0x27f00000 0x80000>;
+                       reg-names = "dbi", "config";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       ranges =  <0x81000000 0 0x00000000 0x27f80000 0 0x00010000 /* downstream I/O 64KB */
+                                  0x82000000 0 0x20000000 0x20000000 0 0x07f00000>; /* non-prefetchable memory */
+                       num-lanes = <1>;
+                       num-viewport = <4>;
+                       interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi";
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0x7>;
+                       interrupt-map = <0 0 0 1 &gic GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 2 &gic GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 3 &gic GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 4 &gic GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+                       fsl,max-link-speed = <2>;
+                       power-domains = <&pgc_pcie>;
+                       resets = <&src IMX8MQ_RESET_PCIEPHY2>,
+                                <&src IMX8MQ_RESET_PCIE2_CTRL_APPS_EN>,
+                                <&src IMX8MQ_RESET_PCIE2_CTRL_APPS_TURNOFF>;
+                       reset-names = "pciephy", "apps", "turnoff";
+                       status = "disabled";
+               };
+
                gic: interrupt-controller@38800000 {
                        compatible = "arm,gic-v3";
                        reg = <0x38800000 0x10000>,     /* GIC Dist */
index 03aad66545c5bb57fc634fe3ba3b5f068bf0da0f..bfdada2db176ca07cbb392a67aa55272e6a6d717 100644 (file)
        };
 };
 
+&adma_i2c1 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_lpi2c1 &pinctrl_ioexp_rst>;
+       status = "okay";
+
+       i2c-switch@71 {
+               compatible = "nxp,pca9646", "nxp,pca9546";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x71>;
+               reset-gpios = <&lsio_gpio1 1 GPIO_ACTIVE_LOW>;
+
+               i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0>;
+
+                       max7322: gpio@68 {
+                               compatible = "maxim,max7322";
+                               reg = <0x68>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                       };
+               };
+
+               i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <1>;
+               };
+
+               i2c@2 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <2>;
+
+                       pressure-sensor@60 {
+                               compatible = "fsl,mpl3115";
+                               reg = <0x60>;
+                       };
+               };
+
+               i2c@3 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <3>;
+
+                       pca9557_a: gpio@1a {
+                               compatible = "nxp,pca9557";
+                               reg = <0x1a>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                       };
+
+                       pca9557_b: gpio@1d {
+                               compatible = "nxp,pca9557";
+                               reg = <0x1d>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                       };
+
+                       light-sensor@44 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_isl29023>;
+                               compatible = "isil,isl29023";
+                               reg = <0x44>;
+                               interrupt-parent = <&lsio_gpio1>;
+                               interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
+                       };
+               };
+       };
+};
+
 &usdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc1>;
                >;
        };
 
+       pinctrl_ioexp_rst: ioexp_rst_grp {
+               fsl,pins = <
+                       IMX8QXP_SPI2_SDO_LSIO_GPIO1_IO01                        0x06000021
+               >;
+       };
+
+       pinctrl_isl29023: isl29023grp {
+               fsl,pins = <
+                       IMX8QXP_SPI2_SDI_LSIO_GPIO1_IO02                        0x00000021
+               >;
+       };
+
+       pinctrl_lpi2c1: lpi2c1grp {
+               fsl,pins = <
+                       IMX8QXP_USB_SS3_TC1_ADMA_I2C1_SCL                       0x06000021
+                       IMX8QXP_USB_SS3_TC3_ADMA_I2C1_SDA                       0x06000021
+               >;
+       };
+
        pinctrl_lpuart0: lpuart0grp {
                fsl,pins = <
                        IMX8QXP_UART0_RX_ADMA_UART0_RX                          0x06000020
index 4c3dd95ed488485ccdee84da788e318149a252b3..0683ee2a48ae5a8584fff3e2b136c7d4b112db65 100644 (file)
@@ -21,6 +21,7 @@
                mmc1 = &usdhc2;
                mmc2 = &usdhc3;
                serial0 = &adma_lpuart0;
+               mu1 = &lsio_mu1;
        };
 
        cpus {
@@ -34,6 +35,9 @@
                        reg = <0x0 0x0>;
                        enable-method = "psci";
                        next-level-cache = <&A35_L2>;
+                       clocks = <&clk IMX_A35_CLK>;
+                       operating-points-v2 = <&a35_opp_table>;
+                       #cooling-cells = <2>;
                };
 
                A35_1: cpu@1 {
@@ -42,6 +46,9 @@
                        reg = <0x0 0x1>;
                        enable-method = "psci";
                        next-level-cache = <&A35_L2>;
+                       clocks = <&clk IMX_A35_CLK>;
+                       operating-points-v2 = <&a35_opp_table>;
+                       #cooling-cells = <2>;
                };
 
                A35_2: cpu@2 {
@@ -50,6 +57,9 @@
                        reg = <0x0 0x2>;
                        enable-method = "psci";
                        next-level-cache = <&A35_L2>;
+                       clocks = <&clk IMX_A35_CLK>;
+                       operating-points-v2 = <&a35_opp_table>;
+                       #cooling-cells = <2>;
                };
 
                A35_3: cpu@3 {
@@ -58,6 +68,9 @@
                        reg = <0x0 0x3>;
                        enable-method = "psci";
                        next-level-cache = <&A35_L2>;
+                       clocks = <&clk IMX_A35_CLK>;
+                       operating-points-v2 = <&a35_opp_table>;
+                       #cooling-cells = <2>;
                };
 
                A35_L2: l2-cache0 {
                };
        };
 
+       a35_opp_table: opp-table {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-900000000 {
+                       opp-hz = /bits/ 64 <900000000>;
+                       opp-microvolt = <1000000>;
+                       clock-latency-ns = <150000>;
+               };
+
+               opp-1200000000 {
+                       opp-hz = /bits/ 64 <1200000000>;
+                       opp-microvolt = <1100000>;
+                       clock-latency-ns = <150000>;
+                       opp-suspend;
+               };
+       };
+
        gic: interrupt-controller@51a00000 {
                compatible = "arm,gic-v3";
                reg = <0x0 0x51a00000 0 0x10000>, /* GIC Dist */
        scu {
                compatible = "fsl,imx-scu";
                mbox-names = "tx0", "tx1", "tx2", "tx3",
-                            "rx0", "rx1", "rx2", "rx3";
+                            "rx0", "rx1", "rx2", "rx3",
+                            "gip3";
                mboxes = <&lsio_mu1 0 0
                          &lsio_mu1 0 1
                          &lsio_mu1 0 2
                          &lsio_mu1 1 0
                          &lsio_mu1 1 1
                          &lsio_mu1 1 2
-                         &lsio_mu1 1 3>;
+                         &lsio_mu1 1 3
+                         &lsio_mu1 3 3>;
 
                clk: clock-controller {
                        compatible = "fsl,imx8qxp-clk";
                        status = "disabled";
                };
 
+               adma_lpuart1: serial@5a070000 {
+                       compatible = "fsl,imx8qxp-lpuart", "fsl,imx7ulp-lpuart";
+                       reg = <0x5a070000 0x1000>;
+                       interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-parent = <&gic>;
+                       clocks = <&adma_lpcg IMX_ADMA_LPCG_UART1_BAUD_CLK>;
+                       clock-names = "ipg";
+                       power-domains = <&pd IMX_SC_R_UART_1>;
+                       status = "disabled";
+               };
+
+               adma_lpuart2: serial@5a080000 {
+                       compatible = "fsl,imx8qxp-lpuart", "fsl,imx7ulp-lpuart";
+                       reg = <0x5a080000 0x1000>;
+                       interrupts = <GIC_SPI 227 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-parent = <&gic>;
+                       clocks = <&adma_lpcg IMX_ADMA_LPCG_UART2_BAUD_CLK>;
+                       clock-names = "ipg";
+                       power-domains = <&pd IMX_SC_R_UART_2>;
+                       status = "disabled";
+               };
+
+               adma_lpuart3: serial@5a090000 {
+                       compatible = "fsl,imx8qxp-lpuart", "fsl,imx7ulp-lpuart";
+                       reg = <0x5a090000 0x1000>;
+                       interrupts = <GIC_SPI 228 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-parent = <&gic>;
+                       clocks = <&adma_lpcg IMX_ADMA_LPCG_UART3_BAUD_CLK>;
+                       clock-names = "ipg";
+                       power-domains = <&pd IMX_SC_R_UART_3>;
+                       status = "disabled";
+               };
+
                adma_i2c0: i2c@5a800000 {
                        compatible = "fsl,imx8qxp-lpi2c", "fsl,imx7ulp-lpi2c";
                        reg = <0x5a800000 0x4000>;
                        compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
                        reg = <0x5d1b0000 0x10000>;
                        interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
-                       #mbox-cells = <0>;
+                       #mbox-cells = <2>;
                        status = "disabled";
                };
 
                        #mbox-cells = <2>;
                };
 
+               lsio_mu2: mailbox@5d1d0000 {
+                       compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
+                       reg = <0x5d1d0000 0x10000>;
+                       interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
+                       #mbox-cells = <2>;
+                       status = "disabled";
+               };
+
                lsio_mu3: mailbox@5d1e0000 {
                        compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
                        reg = <0x5d1e0000 0x10000>;
                        interrupts = <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>;
-                       #mbox-cells = <0>;
+                       #mbox-cells = <2>;
                        status = "disabled";
                };
 
                        compatible = "fsl,imx8qxp-mu", "fsl,imx6sx-mu";
                        reg = <0x5d1f0000 0x10000>;
                        interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
-                       #mbox-cells = <0>;
+                       #mbox-cells = <2>;
                        status = "disabled";
                };
 
                        power-domains = <&pd IMX_SC_R_GPIO_7>;
                };
        };
+
+       watchdog {
+               compatible = "fsl,imx8qxp-sc-wdt", "fsl,imx-sc-wdt";
+               timeout-sec = <60>;
+       };
 };
index 2f19e0e5b7cfc4feecc4ae67ed0d1755b31a017e..aa6a8ad31be2fc1f45ecad2f57c06b74b9d4767f 100644 (file)
                        compatible = "arm,pl011", "arm,primecell";
                        reg = <0x0 0xfdf00000 0x0 0x1000>;
                        interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+                       dma-names = "rx", "tx";
+                       dmas =  <&dma0 2 &dma0 3>;
                        clocks = <&crg_ctrl HI3660_CLK_GATE_UART1>,
                                 <&crg_ctrl HI3660_CLK_GATE_UART1>;
                        clock-names = "uartclk", "apb_pclk";
                        compatible = "arm,pl011", "arm,primecell";
                        reg = <0x0 0xfdf03000 0x0 0x1000>;
                        interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+                       dma-names = "rx", "tx";
+                       dmas =  <&dma0 4 &dma0 5>;
                        clocks = <&crg_ctrl HI3660_CLK_GATE_UART2>,
                                 <&crg_ctrl HI3660_PCLK>;
                        clock-names = "uartclk", "apb_pclk";
                        compatible = "arm,pl011", "arm,primecell";
                        reg = <0x0 0xfdf01000 0x0 0x1000>;
                        interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+                       dma-names = "rx", "tx";
+                       dmas =  <&dma0 6 &dma0 7>;
                        clocks = <&crg_ctrl HI3660_CLK_GATE_UART4>,
                                 <&crg_ctrl HI3660_CLK_GATE_UART4>;
                        clock-names = "uartclk", "apb_pclk";
                        compatible = "arm,pl011", "arm,primecell";
                        reg = <0x0 0xfdf05000 0x0 0x1000>;
                        interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+                       dma-names = "rx", "tx";
+                       dmas =  <&dma0 8 &dma0 9>;
                        clocks = <&crg_ctrl HI3660_CLK_GATE_UART5>,
                                 <&crg_ctrl HI3660_CLK_GATE_UART5>;
                        clock-names = "uartclk", "apb_pclk";
                        #dma-cells = <1>;
                        dma-channels = <16>;
                        dma-requests = <32>;
-                       dma-min-chan = <1>;
+                       dma-channel-mask = <0xfffe>;
                        interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&crg_ctrl HI3660_CLK_GATE_DMAC>;
                        dma-no-cci;
                        dma-type = "hi3660_dma";
                };
 
+               asp_dmac: dma-controller@e804b000 {
+                       compatible = "hisilicon,hisi-pcm-asp-dma-1.0";
+                       reg = <0x0 0xe804b000 0x0 0x1000>;
+                       #dma-cells = <1>;
+                       dma-channels = <16>;
+                       dma-requests = <32>;
+                       interrupts = <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "asp_dma_irq";
+               };
+
                rtc0: rtc@fff04000 {
                        compatible = "arm,pl031", "arm,primecell";
                        reg = <0x0 0Xfff04000 0x0 0x1000>;
index c9775b66629f9dedffbf6d1cb48c84d746118098..7dac33d4fd5c67aa16617c761cb879fe1fe58292 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
 
 #include "hi3670.dtsi"
 #include "hikey970-pinctrl.dtsi"
@@ -17,6 +18,8 @@
        compatible = "hisilicon,hi3670-hikey970", "hisilicon,hi3670";
 
        aliases {
+               mshc1 = &dwmmc1;
+               mshc2 = &dwmmc2;
                serial0 = &uart0;
                serial1 = &uart1;
                serial2 = &uart2;
                /* expect bootloader to fill in this region */
                reg = <0x0 0x0 0x0 0x0>;
        };
+
+       sd_1v8: regulator-1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "fixed-1.8V";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+       };
+
+       sd_3v3: regulator-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "fixed-3.3V";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       wlan_en: wlan-en-1-8v {
+               compatible = "regulator-fixed";
+               regulator-name = "wlan-en-regulator";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+
+               /* GPIO_051_WIFI_EN */
+               gpio = <&gpio6 3 0>;
+
+               /* WLAN card specific delay */
+               startup-delay-us = <70000>;
+               enable-active-high;
+       };
 };
 
 /*
                "GPIO_231_HDMI_INT";
 };
 
+&dwmmc1 {
+       bus-width = <0x4>;
+       sd-uhs-sdr12;
+       sd-uhs-sdr25;
+       sd-uhs-sdr50;
+       sd-uhs-sdr104;
+       cap-sd-highspeed;
+       disable-wp;
+       cd-inverted;
+       cd-gpios = <&gpio25 5 GPIO_ACTIVE_HIGH>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sd_pmx_func
+                    &sd_clk_cfg_func
+                    &sd_cfg_func>;
+       vmmc-supply = <&sd_3v3>;
+       vqmmc-supply = <&sd_1v8>;
+       status = "okay";
+};
+
+&dwmmc2 { /* WIFI */
+       bus-width = <0x4>;
+       non-removable;
+       broken-cd;
+       cap-power-off-card;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdio_pmx_func
+                    &sdio_clk_cfg_func
+                    &sdio_cfg_func>;
+       /* WL_EN */
+       vmmc-supply = <&wlan_en>;
+       status = "ok";
+
+       wlcore: wlcore@2 {
+               compatible = "ti,wl1837";
+               reg = <2>;      /* sdio func num */
+               /* WL_IRQ, GPIO_177_WL_WAKEUP_AP */
+               interrupt-parent = <&gpio22>;
+               interrupts = <1 IRQ_TYPE_EDGE_RISING>;
+       };
+};
+
 &uart0 {
        /* On High speed expansion header */
        label = "HS-UART0";
index 2ed06e4588b8db8b8fd6736000d2490df22fdb5b..2dcffa3ed2189eb5538ebf72c37ac4924f5d3629 100644 (file)
                        #clock-cells = <1>;
                };
 
+               crg_rst: crg_rst_controller {
+                       compatible = "hisilicon,hi3670-reset",
+                                    "hisilicon,hi3660-reset";
+                       #reset-cells = <2>;
+                       hisi,rst-syscon = <&crg_ctrl>;
+               };
+
                pctrl: pctrl@e8a09000 {
                        compatible = "hisilicon,hi3670-pctrl", "syscon";
                        reg = <0x0 0xe8a09000 0x0 0x1000>;
                        clocks = <&sctrl HI3670_PCLK_AO_GPIO6>;
                        clock-names = "apb_pclk";
                };
+
+               /* UFS */
+               ufs: ufs@ff3c0000 {
+                       compatible = "hisilicon,hi3670-ufs", "jedec,ufs-2.1";
+                       /* 0: HCI standard */
+                       /* 1: UFS SYS CTRL */
+                       reg = <0x0 0xff3c0000 0x0 0x1000>,
+                               <0x0 0xff3e0000 0x0 0x1000>;
+                       interrupt-parent = <&gic>;
+                       interrupts = <GIC_SPI 278 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&crg_ctrl HI3670_CLK_GATE_UFSIO_REF>,
+                               <&crg_ctrl HI3670_CLK_GATE_UFS_SUBSYS>;
+                       clock-names = "ref_clk", "phy_clk";
+                       freq-table-hz = <0 0>, <0 0>;
+                       /* offset: 0x84; bit: 12 */
+                       resets = <&crg_rst 0x84 12>;
+                       reset-names = "rst";
+               };
+
+               /* SD */
+               dwmmc1: dwmmc1@ff37f000 {
+                       compatible = "hisilicon,hi3670-dw-mshc",
+                                    "hisilicon,hi3660-dw-mshc";
+                       reg = <0x0 0xff37f000 0x0 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&crg_ctrl HI3670_CLK_GATE_SD>,
+                               <&crg_ctrl HI3670_HCLK_GATE_SD>;
+                       clock-names = "ciu", "biu";
+                       clock-frequency = <3200000>;
+                       resets = <&crg_rst 0x94 18>;
+                       reset-names = "reset";
+                       hisilicon,peripheral-syscon = <&sctrl>;
+                       card-detect-delay = <200>;
+                       status = "disabled";
+               };
+
+               /* SDIO */
+               dwmmc2: dwmmc2@fc183000 {
+                       compatible = "hisilicon,hi3670-dw-mshc",
+                                    "hisilicon,hi3660-dw-mshc";
+                       reg = <0x0 0xfc183000 0x0 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&crg_ctrl HI3670_CLK_GATE_SDIO>,
+                               <&crg_ctrl HI3670_HCLK_GATE_SDIO>;
+                       clock-names = "ciu", "biu";
+                       clock-frequency = <3200000>;
+                       resets = <&crg_rst 0x94 20>;
+                       reset-names = "reset";
+                       card-detect-delay = <200>;
+                       status = "disabled";
+               };
        };
 };
index 67bb52d43619d139839e3744f4850bf7d57cc22a..d456b0aa6f58ca81760fdbc3c7243b285d4ea4ee 100644 (file)
                        /* pin base, nr pins & gpio function */
                        pinctrl-single,gpio-range = <&range 0 10 0>;
 
+                       sdio_pmx_func: sdio_pmx_func {
+                               pinctrl-single,pins = <
+                                       0x000 MUX_M1 /* SDIO_CLK */
+                                       0x004 MUX_M1 /* SDIO_CMD */
+                                       0x008 MUX_M1 /* SDIO_DATA0 */
+                                       0x00c MUX_M1 /* SDIO_DATA1 */
+                                       0x010 MUX_M1 /* SDIO_DATA2 */
+                                       0x014 MUX_M1 /* SDIO_DATA3 */
+                               >;
+                       };
                };
 
                pmx6: pinmux@fc182800 {
                        reg = <0x0 0xfc182800 0x0 0x028>;
                        #pinctrl-cells = <1>;
                        pinctrl-single,register-width = <0x20>;
+
+                       sdio_clk_cfg_func: sdio_clk_cfg_func {
+                               pinctrl-single,pins = <
+                                       0x000 0x0 /* SDIO_CLK */
+                               >;
+                               pinctrl-single,bias-pulldown = <
+                                       PULL_DIS
+                                       PULL_DOWN
+                                       PULL_DIS
+                                       PULL_DOWN
+                               >;
+                               pinctrl-single,bias-pullup = <
+                                       PULL_DIS
+                                       PULL_UP
+                                       PULL_DIS
+                                       PULL_UP
+                               >;
+                               pinctrl-single,drive-strength = <
+                                       DRIVE6_32MA DRIVE6_MASK
+                               >;
+                       };
+
+                       sdio_cfg_func: sdio_cfg_func {
+                               pinctrl-single,pins = <
+                                       0x004 0x0 /* SDIO_CMD */
+                                       0x008 0x0 /* SDIO_DATA0 */
+                                       0x00c 0x0 /* SDIO_DATA1 */
+                                       0x010 0x0 /* SDIO_DATA2 */
+                                       0x014 0x0 /* SDIO_DATA3 */
+                               >;
+                               pinctrl-single,bias-pulldown = <
+                                       PULL_DIS
+                                       PULL_DOWN
+                                       PULL_DIS
+                                       PULL_DOWN
+                               >;
+                               pinctrl-single,bias-pullup = <
+                                       PULL_UP
+                                       PULL_UP
+                                       PULL_DIS
+                                       PULL_UP
+                               >;
+                               pinctrl-single,drive-strength = <
+                                       DRIVE6_19MA DRIVE6_MASK
+                               >;
+                       };
                };
 
                pmx7: pinmux@ff37e000 {
                        pinctrl-single,function-mask = <7>;
                        /* pin base, nr pins & gpio function */
                        pinctrl-single,gpio-range = <&range 0 12 0>;
+
+                       sd_pmx_func: sd_pmx_func {
+                               pinctrl-single,pins = <
+                                       0x000 MUX_M1 /* SD_CLK */
+                                       0x004 MUX_M1 /* SD_CMD */
+                                       0x008 MUX_M1 /* SD_DATA0 */
+                                       0x00c MUX_M1 /* SD_DATA1 */
+                                       0x010 MUX_M1 /* SD_DATA2 */
+                                       0x014 MUX_M1 /* SD_DATA3 */
+                               >;
+                       };
                };
 
                pmx8: pinmux@ff37e800 {
                        reg = <0x0 0xff37e800 0x0 0x030>;
                        #pinctrl-cells = <1>;
                        pinctrl-single,register-width = <0x20>;
+
+                       sd_clk_cfg_func: sd_clk_cfg_func {
+                               pinctrl-single,pins = <
+                                       0x000 0x0 /* SD_CLK */
+                               >;
+                               pinctrl-single,bias-pulldown = <
+                                       PULL_DIS
+                                       PULL_DOWN
+                                       PULL_DIS
+                                       PULL_DOWN
+                               >;
+                               pinctrl-single,bias-pullup = <
+                                       PULL_DIS
+                                       PULL_UP
+                                       PULL_DIS
+                                       PULL_UP
+                               >;
+                               pinctrl-single,drive-strength = <
+                                       DRIVE6_32MA
+                                       DRIVE6_MASK
+                               >;
+                       };
+
+                       sd_cfg_func: sd_cfg_func {
+                               pinctrl-single,pins = <
+                                       0x004 0x0 /* SD_CMD */
+                                       0x008 0x0 /* SD_DATA0 */
+                                       0x00c 0x0 /* SD_DATA1 */
+                                       0x010 0x0 /* SD_DATA2 */
+                                       0x014 0x0 /* SD_DATA3 */
+                               >;
+                               pinctrl-single,bias-pulldown = <
+                                       PULL_DIS
+                                       PULL_DOWN
+                                       PULL_DIS
+                                       PULL_DOWN
+                               >;
+                               pinctrl-single,bias-pullup = <
+                                       PULL_UP
+                                       PULL_UP
+                                       PULL_DIS
+                                       PULL_UP
+                               >;
+                               pinctrl-single,drive-strength = <
+                                       DRIVE6_19MA
+                                       DRIVE6_MASK
+                               >;
+                       };
                };
 
                pmx1: pinmux@fff11000 {
diff --git a/arch/arm64/boot/dts/intel/Makefile b/arch/arm64/boot/dts/intel/Makefile
new file mode 100644 (file)
index 0000000..9606ac8
--- /dev/null
@@ -0,0 +1 @@
+dtb-$(CONFIG_ARCH_AGILEX) += socfpga_agilex_socdk.dtb
diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi b/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi
new file mode 100644 (file)
index 0000000..e4ceb3a
--- /dev/null
@@ -0,0 +1,444 @@
+// SPDX-License-Identifier:     GPL-2.0
+/*
+ * Copyright (C) 2019, Intel Corporation
+ */
+
+/dts-v1/;
+#include <dt-bindings/reset/altr,rst-mgr-s10.h>
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       compatible = "intel,socfpga-agilex";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       compatible = "arm,cortex-a53";
+                       device_type = "cpu";
+                       enable-method = "psci";
+                       reg = <0x0>;
+               };
+
+               cpu1: cpu@1 {
+                       compatible = "arm,cortex-a53";
+                       device_type = "cpu";
+                       enable-method = "psci";
+                       reg = <0x1>;
+               };
+
+               cpu2: cpu@2 {
+                       compatible = "arm,cortex-a53";
+                       device_type = "cpu";
+                       enable-method = "psci";
+                       reg = <0x2>;
+               };
+
+               cpu3: cpu@3 {
+                       compatible = "arm,cortex-a53";
+                       device_type = "cpu";
+                       enable-method = "psci";
+                       reg = <0x3>;
+               };
+       };
+
+       pmu {
+               compatible = "arm,armv8-pmuv3";
+               interrupts = <0 120 8>,
+                            <0 121 8>,
+                            <0 122 8>,
+                            <0 123 8>;
+               interrupt-affinity = <&cpu0>,
+                                    <&cpu1>,
+                                    <&cpu2>,
+                                    <&cpu3>;
+               interrupt-parent = <&intc>;
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       intc: intc@fffc1000 {
+               compatible = "arm,gic-400", "arm,cortex-a15-gic";
+               #interrupt-cells = <3>;
+               interrupt-controller;
+               reg = <0x0 0xfffc1000 0x0 0x1000>,
+                     <0x0 0xfffc2000 0x0 0x2000>,
+                     <0x0 0xfffc4000 0x0 0x2000>,
+                     <0x0 0xfffc6000 0x0 0x2000>;
+       };
+
+       soc {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "simple-bus";
+               device_type = "soc";
+               interrupt-parent = <&intc>;
+               ranges = <0 0 0 0xffffffff>;
+
+               gmac0: ethernet@ff800000 {
+                       compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+                       reg = <0xff800000 0x2000>;
+                       interrupts = <0 90 4>;
+                       interrupt-names = "macirq";
+                       mac-address = [00 00 00 00 00 00];
+                       resets = <&rst EMAC0_RESET>, <&rst EMAC0_OCP_RESET>;
+                       reset-names = "stmmaceth", "stmmaceth-ocp";
+                       tx-fifo-depth = <16384>;
+                       rx-fifo-depth = <16384>;
+                       snps,multicast-filter-bins = <256>;
+                       iommus = <&smmu 1>;
+                       status = "disabled";
+               };
+
+               gmac1: ethernet@ff802000 {
+                       compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+                       reg = <0xff802000 0x2000>;
+                       interrupts = <0 91 4>;
+                       interrupt-names = "macirq";
+                       mac-address = [00 00 00 00 00 00];
+                       resets = <&rst EMAC1_RESET>, <&rst EMAC1_OCP_RESET>;
+                       reset-names = "stmmaceth", "stmmaceth-ocp";
+                       tx-fifo-depth = <16384>;
+                       rx-fifo-depth = <16384>;
+                       snps,multicast-filter-bins = <256>;
+                       iommus = <&smmu 2>;
+                       status = "disabled";
+               };
+
+               gmac2: ethernet@ff804000 {
+                       compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+                       reg = <0xff804000 0x2000>;
+                       interrupts = <0 92 4>;
+                       interrupt-names = "macirq";
+                       mac-address = [00 00 00 00 00 00];
+                       resets = <&rst EMAC2_RESET>, <&rst EMAC2_OCP_RESET>;
+                       reset-names = "stmmaceth", "stmmaceth-ocp";
+                       tx-fifo-depth = <16384>;
+                       rx-fifo-depth = <16384>;
+                       snps,multicast-filter-bins = <256>;
+                       iommus = <&smmu 3>;
+                       status = "disabled";
+               };
+
+               gpio0: gpio@ffc03200 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "snps,dw-apb-gpio";
+                       reg = <0xffc03200 0x100>;
+                       resets = <&rst GPIO0_RESET>;
+                       status = "disabled";
+
+                       porta: gpio-controller@0 {
+                               compatible = "snps,dw-apb-gpio-port";
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               snps,nr-gpios = <24>;
+                               reg = <0>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                               interrupts = <0 110 4>;
+                       };
+               };
+
+               gpio1: gpio@ffc03300 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "snps,dw-apb-gpio";
+                       reg = <0xffc03300 0x100>;
+                       resets = <&rst GPIO1_RESET>;
+                       status = "disabled";
+
+                       portb: gpio-controller@0 {
+                               compatible = "snps,dw-apb-gpio-port";
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               snps,nr-gpios = <24>;
+                               reg = <0>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                               interrupts = <0 111 4>;
+                       };
+               };
+
+               i2c0: i2c@ffc02800 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "snps,designware-i2c";
+                       reg = <0xffc02800 0x100>;
+                       interrupts = <0 103 4>;
+                       resets = <&rst I2C0_RESET>;
+                       status = "disabled";
+               };
+
+               i2c1: i2c@ffc02900 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "snps,designware-i2c";
+                       reg = <0xffc02900 0x100>;
+                       interrupts = <0 104 4>;
+                       resets = <&rst I2C1_RESET>;
+                       status = "disabled";
+               };
+
+               i2c2: i2c@ffc02a00 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "snps,designware-i2c";
+                       reg = <0xffc02a00 0x100>;
+                       interrupts = <0 105 4>;
+                       resets = <&rst I2C2_RESET>;
+                       status = "disabled";
+               };
+
+               i2c3: i2c@ffc02b00 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "snps,designware-i2c";
+                       reg = <0xffc02b00 0x100>;
+                       interrupts = <0 106 4>;
+                       resets = <&rst I2C3_RESET>;
+                       status = "disabled";
+               };
+
+               i2c4: i2c@ffc02c00 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "snps,designware-i2c";
+                       reg = <0xffc02c00 0x100>;
+                       interrupts = <0 107 4>;
+                       resets = <&rst I2C4_RESET>;
+                       status = "disabled";
+               };
+
+               mmc: dwmmc0@ff808000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "altr,socfpga-dw-mshc";
+                       reg = <0xff808000 0x1000>;
+                       interrupts = <0 96 4>;
+                       fifo-depth = <0x400>;
+                       resets = <&rst SDMMC_RESET>;
+                       reset-names = "reset";
+                       iommus = <&smmu 5>;
+                       status = "disabled";
+               };
+
+               ocram: sram@ffe00000 {
+                       compatible = "mmio-sram";
+                       reg = <0xffe00000 0x40000>;
+               };
+
+               pdma: pdma@ffda0000 {
+                       compatible = "arm,pl330", "arm,primecell";
+                       reg = <0xffda0000 0x1000>;
+                       interrupts = <0 81 4>,
+                                    <0 82 4>,
+                                    <0 83 4>,
+                                    <0 84 4>,
+                                    <0 85 4>,
+                                    <0 86 4>,
+                                    <0 87 4>,
+                                    <0 88 4>,
+                                    <0 89 4>;
+                       #dma-cells = <1>;
+                       #dma-channels = <8>;
+                       #dma-requests = <32>;
+               };
+
+               rst: rstmgr@ffd11000 {
+                       #reset-cells = <1>;
+                       compatible = "altr,stratix10-rst-mgr";
+                       reg = <0xffd11000 0x100>;
+               };
+
+               smmu: iommu@fa000000 {
+                       compatible = "arm,mmu-500", "arm,smmu-v2";
+                       reg = <0xfa000000 0x40000>;
+                       #global-interrupts = <2>;
+                       #iommu-cells = <1>;
+                       interrupt-parent = <&intc>;
+                       interrupts = <0 128 4>, /* Global Secure Fault */
+                               <0 129 4>, /* Global Non-secure Fault */
+                               /* Non-secure Context Interrupts (32) */
+                               <0 138 4>, <0 139 4>, <0 140 4>, <0 141 4>,
+                               <0 142 4>, <0 143 4>, <0 144 4>, <0 145 4>,
+                               <0 146 4>, <0 147 4>, <0 148 4>, <0 149 4>,
+                               <0 150 4>, <0 151 4>, <0 152 4>, <0 153 4>,
+                               <0 154 4>, <0 155 4>, <0 156 4>, <0 157 4>,
+                               <0 158 4>, <0 159 4>, <0 160 4>, <0 161 4>,
+                               <0 162 4>, <0 163 4>, <0 164 4>, <0 165 4>,
+                               <0 166 4>, <0 167 4>, <0 168 4>, <0 169 4>;
+                       stream-match-mask = <0x7ff0>;
+                       status = "disabled";
+               };
+
+               spi0: spi@ffda4000 {
+                       compatible = "snps,dw-apb-ssi";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0xffda4000 0x1000>;
+                       interrupts = <0 99 4>;
+                       resets = <&rst SPIM0_RESET>;
+                       reg-io-width = <4>;
+                       num-cs = <4>;
+                       status = "disabled";
+               };
+
+               spi1: spi@ffda5000 {
+                       compatible = "snps,dw-apb-ssi";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0xffda5000 0x1000>;
+                       interrupts = <0 100 4>;
+                       resets = <&rst SPIM1_RESET>;
+                       reg-io-width = <4>;
+                       num-cs = <4>;
+                       status = "disabled";
+               };
+
+               sysmgr: sysmgr@ffd12000 {
+                       compatible = "altr,sys-mgr", "syscon";
+                       reg = <0xffd12000 0x500>;
+               };
+
+               /* Local timer */
+               timer {
+                       compatible = "arm,armv8-timer";
+                       interrupts = <1 13 0xf08>,
+                                    <1 14 0xf08>,
+                                    <1 11 0xf08>,
+                                    <1 10 0xf08>;
+               };
+
+               timer0: timer0@ffc03000 {
+                       compatible = "snps,dw-apb-timer";
+                       interrupts = <0 113 4>;
+                       reg = <0xffc03000 0x100>;
+               };
+
+               timer1: timer1@ffc03100 {
+                       compatible = "snps,dw-apb-timer";
+                       interrupts = <0 114 4>;
+                       reg = <0xffc03100 0x100>;
+               };
+
+               timer2: timer2@ffd00000 {
+                       compatible = "snps,dw-apb-timer";
+                       interrupts = <0 115 4>;
+                       reg = <0xffd00000 0x100>;
+               };
+
+               timer3: timer3@ffd00100 {
+                       compatible = "snps,dw-apb-timer";
+                       interrupts = <0 116 4>;
+                       reg = <0xffd00100 0x100>;
+               };
+
+               uart0: serial0@ffc02000 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0xffc02000 0x100>;
+                       interrupts = <0 108 4>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       resets = <&rst UART0_RESET>;
+                       status = "disabled";
+               };
+
+               uart1: serial1@ffc02100 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0xffc02100 0x100>;
+                       interrupts = <0 109 4>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       resets = <&rst UART1_RESET>;
+                       status = "disabled";
+               };
+
+               usbphy0: usbphy@0 {
+                       #phy-cells = <0>;
+                       compatible = "usb-nop-xceiv";
+                       status = "okay";
+               };
+
+               usb0: usb@ffb00000 {
+                       compatible = "snps,dwc2";
+                       reg = <0xffb00000 0x40000>;
+                       interrupts = <0 93 4>;
+                       phys = <&usbphy0>;
+                       phy-names = "usb2-phy";
+                       resets = <&rst USB0_RESET>, <&rst USB0_OCP_RESET>;
+                       reset-names = "dwc2", "dwc2-ecc";
+                       iommus = <&smmu 6>;
+                       status = "disabled";
+               };
+
+               usb1: usb@ffb40000 {
+                       compatible = "snps,dwc2";
+                       reg = <0xffb40000 0x40000>;
+                       interrupts = <0 94 4>;
+                       phys = <&usbphy0>;
+                       phy-names = "usb2-phy";
+                       resets = <&rst USB1_RESET>, <&rst USB1_OCP_RESET>;
+                       reset-names = "dwc2", "dwc2-ecc";
+                       iommus = <&smmu 7>;
+                       status = "disabled";
+               };
+
+               watchdog0: watchdog@ffd00200 {
+                       compatible = "snps,dw-wdt";
+                       reg = <0xffd00200 0x100>;
+                       interrupts = <0 117 4>;
+                       resets = <&rst WATCHDOG0_RESET>;
+                       status = "disabled";
+               };
+
+               watchdog1: watchdog@ffd00300 {
+                       compatible = "snps,dw-wdt";
+                       reg = <0xffd00300 0x100>;
+                       interrupts = <0 118 4>;
+                       resets = <&rst WATCHDOG1_RESET>;
+                       status = "disabled";
+               };
+
+               watchdog2: watchdog@ffd00400 {
+                       compatible = "snps,dw-wdt";
+                       reg = <0xffd00400 0x100>;
+                       interrupts = <0 125 4>;
+                       resets = <&rst WATCHDOG2_RESET>;
+                       status = "disabled";
+               };
+
+               watchdog3: watchdog@ffd00500 {
+                       compatible = "snps,dw-wdt";
+                       reg = <0xffd00500 0x100>;
+                       interrupts = <0 126 4>;
+                       resets = <&rst WATCHDOG3_RESET>;
+                       status = "disabled";
+               };
+
+               sdr: sdr@f8011100 {
+                       compatible = "altr,sdr-ctl", "syscon";
+                       reg = <0xf8011100 0xc0>;
+               };
+
+               qspi: spi@ff8d2000 {
+                       compatible = "cdns,qspi-nor";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0xff8d2000 0x100>,
+                             <0xff900000 0x100000>;
+                       interrupts = <0 3 4>;
+                       cdns,fifo-depth = <128>;
+                       cdns,fifo-width = <4>;
+                       cdns,trigger-address = <0x00000000>;
+
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts b/arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts
new file mode 100644 (file)
index 0000000..7814a9e
--- /dev/null
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier:     GPL-2.0
+/*
+ * Copyright (C) 2019, Intel Corporation
+ */
+#include "socfpga_agilex.dtsi"
+
+/ {
+       model = "SoCFPGA Agilex SoCDK";
+
+       aliases {
+               serial0 = &uart0;
+               ethernet0 = &gmac0;
+               ethernet1 = &gmac1;
+               ethernet2 = &gmac2;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory {
+               device_type = "memory";
+               /* We expect the bootloader to fill in the reg */
+               reg = <0 0 0 0>;
+       };
+};
+
+&gpio1 {
+       status = "okay";
+};
+
+&gmac0 {
+       status = "okay";
+       phy-mode = "rgmii";
+       phy-handle = <&phy0>;
+
+       max-frame-size = <9000>;
+
+       mdio0 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "snps,dwmac-mdio";
+               phy0: ethernet-phy@0 {
+                       reg = <4>;
+
+                       txd0-skew-ps = <0>; /* -420ps */
+                       txd1-skew-ps = <0>; /* -420ps */
+                       txd2-skew-ps = <0>; /* -420ps */
+                       txd3-skew-ps = <0>; /* -420ps */
+                       rxd0-skew-ps = <420>; /* 0ps */
+                       rxd1-skew-ps = <420>; /* 0ps */
+                       rxd2-skew-ps = <420>; /* 0ps */
+                       rxd3-skew-ps = <420>; /* 0ps */
+                       txen-skew-ps = <0>; /* -420ps */
+                       txc-skew-ps = <900>; /* 0ps */
+                       rxdv-skew-ps = <420>; /* 0ps */
+                       rxc-skew-ps = <1680>; /* 780ps */
+               };
+       };
+};
+
+&mmc {
+       status = "okay";
+       cap-sd-highspeed;
+       broken-cd;
+       bus-width = <4>;
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&watchdog0 {
+       status = "okay";
+};
index 2468762283a5c295213ef797407fdae4135c1dab..9143aa13ceb1180e8c2563ac186fcfe7216b94a2 100644 (file)
                marvell,function = "gpio";
        };
 
+       cp0_wlan_disable_pins: wlan-disable-pins {
+               marvell,pins = "mpp51";
+               marvell,function = "gpio";
+       };
+
        cp0_sdhci_pins: sdhci-pins {
                marvell,pins = "mpp55", "mpp56", "mpp57", "mpp58", "mpp59",
                               "mpp60", "mpp61";
 
 &cp0_pcie0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&cp0_pci0_reset_pins>;
+       pinctrl-0 = <&cp0_pci0_reset_pins &cp0_wlan_disable_pins>;
        reset-gpios = <&cp0_gpio2 0 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
                output-low;
        };
 
+       wlan_disable {
+               gpio-hog;
+               gpios = <19 GPIO_ACTIVE_LOW>;
+               output-low;
+       };
+
        lte_disable {
                gpio-hog;
                gpios = <21 GPIO_ACTIVE_LOW>;
index 976d92a9473889f4d3dfa4b4d0bd1473205b1c36..43307bad3f0d66908111921f75ef44c3ef7e90f6 100644 (file)
                        #size-cells = <2>;
                        #interrupt-cells = <1>;
                        ranges;
-                       num-lanes = <1>;
                        interrupt-map-mask = <0 0 0 7>;
                        interrupt-map = <0 0 0 1 &pcie_intc0 0>,
                                        <0 0 0 2 &pcie_intc0 1>,
                        #size-cells = <2>;
                        #interrupt-cells = <1>;
                        ranges;
-                       num-lanes = <1>;
                        interrupt-map-mask = <0 0 0 7>;
                        interrupt-map = <0 0 0 1 &pcie_intc1 0>,
                                        <0 0 0 2 &pcie_intc1 1>,
index c3c360161c5da4333d1007c9fd2bb49a3c630246..15f1842f6df3e4d2126b0449aac8cdf2e3cea9ec 100644 (file)
 
                cpu2: cpu@100 {
                        device_type = "cpu";
-                       compatible = "arm,cortex-a57";
+                       compatible = "arm,cortex-a72";
                        reg = <0x100>;
                        enable-method = "psci";
                        cpu-idle-states = <&CPU_SLEEP_0>;
                        #cooling-cells = <2>;
-                       clocks = <&infracfg CLK_INFRA_CA57SEL>,
+                       clocks = <&infracfg CLK_INFRA_CA72SEL>,
                                 <&apmixedsys CLK_APMIXED_MAINPLL>;
                        clock-names = "cpu", "intermediate";
                        operating-points-v2 = <&cluster1_opp>;
 
                cpu3: cpu@101 {
                        device_type = "cpu";
-                       compatible = "arm,cortex-a57";
+                       compatible = "arm,cortex-a72";
                        reg = <0x101>;
                        enable-method = "psci";
                        cpu-idle-states = <&CPU_SLEEP_0>;
                        #cooling-cells = <2>;
-                       clocks = <&infracfg CLK_INFRA_CA57SEL>,
+                       clocks = <&infracfg CLK_INFRA_CA72SEL>,
                                 <&apmixedsys CLK_APMIXED_MAINPLL>;
                        clock-names = "cpu", "intermediate";
                        operating-points-v2 = <&cluster1_opp>;
                };
        };
 
+       pmu_a53 {
+               compatible = "arm,cortex-a53-pmu";
+               interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 9 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-affinity = <&cpu0>, <&cpu1>;
+       };
+
+       pmu_a72 {
+               compatible = "arm,cortex-a72-pmu";
+               interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 13 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-affinity = <&cpu2>, <&cpu3>;
+       };
+
        psci {
                compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
                method = "smc";
                                      "vencpll",
                                      "venc_lt_sel",
                                      "vdec_bus_clk_src";
+                       assigned-clocks = <&topckgen CLK_TOP_VENC_LT_SEL>,
+                                         <&topckgen CLK_TOP_CCI400_SEL>,
+                                         <&topckgen CLK_TOP_VDEC_SEL>,
+                                         <&apmixedsys CLK_APMIXED_VCODECPLL>,
+                                         <&apmixedsys CLK_APMIXED_VENCPLL>;
+                       assigned-clock-parents = <&topckgen CLK_TOP_VCODECPLL_370P5>,
+                                                <&topckgen CLK_TOP_UNIVPLL_D2>,
+                                                <&topckgen CLK_TOP_VCODECPLL>;
+                       assigned-clock-rates = <0>, <0>, <0>, <1482000000>, <800000000>;
                };
 
                larb1: larb@16010000 {
                                      "venc_sel",
                                      "venc_lt_sel_src",
                                      "venc_lt_sel";
+                       assigned-clocks = <&topckgen CLK_TOP_VENC_SEL>,
+                                         <&topckgen CLK_TOP_VENC_LT_SEL>;
+                       assigned-clock-parents = <&topckgen CLK_TOP_VENCPLL_D2>,
+                                                <&topckgen CLK_TOP_UNIVPLL1_D2>;
                };
 
                vencltsys: clock-controller@19000000 {
diff --git a/arch/arm64/boot/dts/mediatek/mt8183-pinfunc.h b/arch/arm64/boot/dts/mediatek/mt8183-pinfunc.h
new file mode 100644 (file)
index 0000000..6221cd7
--- /dev/null
@@ -0,0 +1,1120 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Zhiyong Tao <zhiyong.tao@mediatek.com>
+ *
+ */
+
+#ifndef __MT8183_PINFUNC_H
+#define __MT8183_PINFUNC_H
+
+#include <dt-bindings/pinctrl/mt65xx.h>
+
+#define PINMUX_GPIO0__FUNC_GPIO0 (MTK_PIN_NO(0) | 0)
+#define PINMUX_GPIO0__FUNC_MRG_SYNC (MTK_PIN_NO(0) | 1)
+#define PINMUX_GPIO0__FUNC_PCM0_SYNC (MTK_PIN_NO(0) | 2)
+#define PINMUX_GPIO0__FUNC_TP_GPIO0_AO (MTK_PIN_NO(0) | 3)
+#define PINMUX_GPIO0__FUNC_SRCLKENAI0 (MTK_PIN_NO(0) | 4)
+#define PINMUX_GPIO0__FUNC_SCP_SPI2_CS (MTK_PIN_NO(0) | 5)
+#define PINMUX_GPIO0__FUNC_I2S3_MCK (MTK_PIN_NO(0) | 6)
+#define PINMUX_GPIO0__FUNC_SPI2_CSB (MTK_PIN_NO(0) | 7)
+
+#define PINMUX_GPIO1__FUNC_GPIO1 (MTK_PIN_NO(1) | 0)
+#define PINMUX_GPIO1__FUNC_MRG_CLK (MTK_PIN_NO(1) | 1)
+#define PINMUX_GPIO1__FUNC_PCM0_CLK (MTK_PIN_NO(1) | 2)
+#define PINMUX_GPIO1__FUNC_TP_GPIO1_AO (MTK_PIN_NO(1) | 3)
+#define PINMUX_GPIO1__FUNC_CLKM3 (MTK_PIN_NO(1) | 4)
+#define PINMUX_GPIO1__FUNC_SCP_SPI2_MO (MTK_PIN_NO(1) | 5)
+#define PINMUX_GPIO1__FUNC_I2S3_BCK (MTK_PIN_NO(1) | 6)
+#define PINMUX_GPIO1__FUNC_SPI2_MO (MTK_PIN_NO(1) | 7)
+
+#define PINMUX_GPIO2__FUNC_GPIO2 (MTK_PIN_NO(2) | 0)
+#define PINMUX_GPIO2__FUNC_MRG_DO (MTK_PIN_NO(2) | 1)
+#define PINMUX_GPIO2__FUNC_PCM0_DO (MTK_PIN_NO(2) | 2)
+#define PINMUX_GPIO2__FUNC_TP_GPIO2_AO (MTK_PIN_NO(2) | 3)
+#define PINMUX_GPIO2__FUNC_SCL6 (MTK_PIN_NO(2) | 4)
+#define PINMUX_GPIO2__FUNC_SCP_SPI2_CK (MTK_PIN_NO(2) | 5)
+#define PINMUX_GPIO2__FUNC_I2S3_LRCK (MTK_PIN_NO(2) | 6)
+#define PINMUX_GPIO2__FUNC_SPI2_CLK (MTK_PIN_NO(2) | 7)
+
+#define PINMUX_GPIO3__FUNC_GPIO3 (MTK_PIN_NO(3) | 0)
+#define PINMUX_GPIO3__FUNC_MRG_DI (MTK_PIN_NO(3) | 1)
+#define PINMUX_GPIO3__FUNC_PCM0_DI (MTK_PIN_NO(3) | 2)
+#define PINMUX_GPIO3__FUNC_TP_GPIO3_AO (MTK_PIN_NO(3) | 3)
+#define PINMUX_GPIO3__FUNC_SDA6 (MTK_PIN_NO(3) | 4)
+#define PINMUX_GPIO3__FUNC_TDM_MCK (MTK_PIN_NO(3) | 5)
+#define PINMUX_GPIO3__FUNC_I2S3_DO (MTK_PIN_NO(3) | 6)
+#define PINMUX_GPIO3__FUNC_SCP_VREQ_VAO (MTK_PIN_NO(3) | 7)
+
+#define PINMUX_GPIO4__FUNC_GPIO4 (MTK_PIN_NO(4) | 0)
+#define PINMUX_GPIO4__FUNC_PWM_B (MTK_PIN_NO(4) | 1)
+#define PINMUX_GPIO4__FUNC_I2S0_MCK (MTK_PIN_NO(4) | 2)
+#define PINMUX_GPIO4__FUNC_SSPM_UTXD_AO (MTK_PIN_NO(4) | 3)
+#define PINMUX_GPIO4__FUNC_MD_URXD1 (MTK_PIN_NO(4) | 4)
+#define PINMUX_GPIO4__FUNC_TDM_BCK (MTK_PIN_NO(4) | 5)
+#define PINMUX_GPIO4__FUNC_TP_GPIO4_AO (MTK_PIN_NO(4) | 6)
+#define PINMUX_GPIO4__FUNC_DAP_MD32_SWD (MTK_PIN_NO(4) | 7)
+
+#define PINMUX_GPIO5__FUNC_GPIO5 (MTK_PIN_NO(5) | 0)
+#define PINMUX_GPIO5__FUNC_PWM_C (MTK_PIN_NO(5) | 1)
+#define PINMUX_GPIO5__FUNC_I2S0_BCK (MTK_PIN_NO(5) | 2)
+#define PINMUX_GPIO5__FUNC_SSPM_URXD_AO (MTK_PIN_NO(5) | 3)
+#define PINMUX_GPIO5__FUNC_MD_UTXD1 (MTK_PIN_NO(5) | 4)
+#define PINMUX_GPIO5__FUNC_TDM_LRCK (MTK_PIN_NO(5) | 5)
+#define PINMUX_GPIO5__FUNC_TP_GPIO5_AO (MTK_PIN_NO(5) | 6)
+#define PINMUX_GPIO5__FUNC_DAP_MD32_SWCK (MTK_PIN_NO(5) | 7)
+
+#define PINMUX_GPIO6__FUNC_GPIO6 (MTK_PIN_NO(6) | 0)
+#define PINMUX_GPIO6__FUNC_PWM_A (MTK_PIN_NO(6) | 1)
+#define PINMUX_GPIO6__FUNC_I2S0_LRCK (MTK_PIN_NO(6) | 2)
+#define PINMUX_GPIO6__FUNC_IDDIG (MTK_PIN_NO(6) | 3)
+#define PINMUX_GPIO6__FUNC_MD_URXD0 (MTK_PIN_NO(6) | 4)
+#define PINMUX_GPIO6__FUNC_TDM_DATA0 (MTK_PIN_NO(6) | 5)
+#define PINMUX_GPIO6__FUNC_TP_GPIO6_AO (MTK_PIN_NO(6) | 6)
+#define PINMUX_GPIO6__FUNC_CMFLASH (MTK_PIN_NO(6) | 7)
+
+#define PINMUX_GPIO7__FUNC_GPIO7 (MTK_PIN_NO(7) | 0)
+#define PINMUX_GPIO7__FUNC_SPI1_B_MI (MTK_PIN_NO(7) | 1)
+#define PINMUX_GPIO7__FUNC_I2S0_DI (MTK_PIN_NO(7) | 2)
+#define PINMUX_GPIO7__FUNC_USB_DRVVBUS (MTK_PIN_NO(7) | 3)
+#define PINMUX_GPIO7__FUNC_MD_UTXD0 (MTK_PIN_NO(7) | 4)
+#define PINMUX_GPIO7__FUNC_TDM_DATA1 (MTK_PIN_NO(7) | 5)
+#define PINMUX_GPIO7__FUNC_TP_GPIO7_AO (MTK_PIN_NO(7) | 6)
+#define PINMUX_GPIO7__FUNC_DVFSRC_EXT_REQ (MTK_PIN_NO(7) | 7)
+
+#define PINMUX_GPIO8__FUNC_GPIO8 (MTK_PIN_NO(8) | 0)
+#define PINMUX_GPIO8__FUNC_SPI1_B_CSB (MTK_PIN_NO(8) | 1)
+#define PINMUX_GPIO8__FUNC_ANT_SEL3 (MTK_PIN_NO(8) | 2)
+#define PINMUX_GPIO8__FUNC_SCL7 (MTK_PIN_NO(8) | 3)
+#define PINMUX_GPIO8__FUNC_CONN_MCU_TRST_B (MTK_PIN_NO(8) | 4)
+#define PINMUX_GPIO8__FUNC_TDM_DATA2 (MTK_PIN_NO(8) | 5)
+#define PINMUX_GPIO8__FUNC_MD_INT0 (MTK_PIN_NO(8) | 6)
+#define PINMUX_GPIO8__FUNC_JTRSTN_SEL1 (MTK_PIN_NO(8) | 7)
+
+#define PINMUX_GPIO9__FUNC_GPIO9 (MTK_PIN_NO(9) | 0)
+#define PINMUX_GPIO9__FUNC_SPI1_B_MO (MTK_PIN_NO(9) | 1)
+#define PINMUX_GPIO9__FUNC_ANT_SEL4 (MTK_PIN_NO(9) | 2)
+#define PINMUX_GPIO9__FUNC_CMMCLK2 (MTK_PIN_NO(9) | 3)
+#define PINMUX_GPIO9__FUNC_CONN_MCU_DBGACK_N (MTK_PIN_NO(9) | 4)
+#define PINMUX_GPIO9__FUNC_SSPM_JTAG_TRSTN (MTK_PIN_NO(9) | 5)
+#define PINMUX_GPIO9__FUNC_IO_JTAG_TRSTN (MTK_PIN_NO(9) | 6)
+#define PINMUX_GPIO9__FUNC_DBG_MON_B10 (MTK_PIN_NO(9) | 7)
+
+#define PINMUX_GPIO10__FUNC_GPIO10 (MTK_PIN_NO(10) | 0)
+#define PINMUX_GPIO10__FUNC_SPI1_B_CLK (MTK_PIN_NO(10) | 1)
+#define PINMUX_GPIO10__FUNC_ANT_SEL5 (MTK_PIN_NO(10) | 2)
+#define PINMUX_GPIO10__FUNC_CMMCLK3 (MTK_PIN_NO(10) | 3)
+#define PINMUX_GPIO10__FUNC_CONN_MCU_DBGI_N (MTK_PIN_NO(10) | 4)
+#define PINMUX_GPIO10__FUNC_TDM_DATA3 (MTK_PIN_NO(10) | 5)
+#define PINMUX_GPIO10__FUNC_EXT_FRAME_SYNC (MTK_PIN_NO(10) | 6)
+#define PINMUX_GPIO10__FUNC_DBG_MON_B11 (MTK_PIN_NO(10) | 7)
+
+#define PINMUX_GPIO11__FUNC_GPIO11 (MTK_PIN_NO(11) | 0)
+#define PINMUX_GPIO11__FUNC_TP_URXD1_AO (MTK_PIN_NO(11) | 1)
+#define PINMUX_GPIO11__FUNC_IDDIG (MTK_PIN_NO(11) | 2)
+#define PINMUX_GPIO11__FUNC_SCL6 (MTK_PIN_NO(11) | 3)
+#define PINMUX_GPIO11__FUNC_UCTS1 (MTK_PIN_NO(11) | 4)
+#define PINMUX_GPIO11__FUNC_UCTS0 (MTK_PIN_NO(11) | 5)
+#define PINMUX_GPIO11__FUNC_SRCLKENAI1 (MTK_PIN_NO(11) | 6)
+#define PINMUX_GPIO11__FUNC_I2S5_MCK (MTK_PIN_NO(11) | 7)
+
+#define PINMUX_GPIO12__FUNC_GPIO12 (MTK_PIN_NO(12) | 0)
+#define PINMUX_GPIO12__FUNC_TP_UTXD1_AO (MTK_PIN_NO(12) | 1)
+#define PINMUX_GPIO12__FUNC_USB_DRVVBUS (MTK_PIN_NO(12) | 2)
+#define PINMUX_GPIO12__FUNC_SDA6 (MTK_PIN_NO(12) | 3)
+#define PINMUX_GPIO12__FUNC_URTS1 (MTK_PIN_NO(12) | 4)
+#define PINMUX_GPIO12__FUNC_URTS0 (MTK_PIN_NO(12) | 5)
+#define PINMUX_GPIO12__FUNC_I2S2_DI2 (MTK_PIN_NO(12) | 6)
+#define PINMUX_GPIO12__FUNC_I2S5_BCK (MTK_PIN_NO(12) | 7)
+
+#define PINMUX_GPIO13__FUNC_GPIO13 (MTK_PIN_NO(13) | 0)
+#define PINMUX_GPIO13__FUNC_DBPI_D0 (MTK_PIN_NO(13) | 1)
+#define PINMUX_GPIO13__FUNC_SPI5_MI (MTK_PIN_NO(13) | 2)
+#define PINMUX_GPIO13__FUNC_PCM0_SYNC (MTK_PIN_NO(13) | 3)
+#define PINMUX_GPIO13__FUNC_MD_URXD0 (MTK_PIN_NO(13) | 4)
+#define PINMUX_GPIO13__FUNC_ANT_SEL3 (MTK_PIN_NO(13) | 5)
+#define PINMUX_GPIO13__FUNC_I2S0_MCK (MTK_PIN_NO(13) | 6)
+#define PINMUX_GPIO13__FUNC_DBG_MON_B15 (MTK_PIN_NO(13) | 7)
+
+#define PINMUX_GPIO14__FUNC_GPIO14 (MTK_PIN_NO(14) | 0)
+#define PINMUX_GPIO14__FUNC_DBPI_D1 (MTK_PIN_NO(14) | 1)
+#define PINMUX_GPIO14__FUNC_SPI5_CSB (MTK_PIN_NO(14) | 2)
+#define PINMUX_GPIO14__FUNC_PCM0_CLK (MTK_PIN_NO(14) | 3)
+#define PINMUX_GPIO14__FUNC_MD_UTXD0 (MTK_PIN_NO(14) | 4)
+#define PINMUX_GPIO14__FUNC_ANT_SEL4 (MTK_PIN_NO(14) | 5)
+#define PINMUX_GPIO14__FUNC_I2S0_BCK (MTK_PIN_NO(14) | 6)
+#define PINMUX_GPIO14__FUNC_DBG_MON_B16 (MTK_PIN_NO(14) | 7)
+
+#define PINMUX_GPIO15__FUNC_GPIO15 (MTK_PIN_NO(15) | 0)
+#define PINMUX_GPIO15__FUNC_DBPI_D2 (MTK_PIN_NO(15) | 1)
+#define PINMUX_GPIO15__FUNC_SPI5_MO (MTK_PIN_NO(15) | 2)
+#define PINMUX_GPIO15__FUNC_PCM0_DO (MTK_PIN_NO(15) | 3)
+#define PINMUX_GPIO15__FUNC_MD_URXD1 (MTK_PIN_NO(15) | 4)
+#define PINMUX_GPIO15__FUNC_ANT_SEL5 (MTK_PIN_NO(15) | 5)
+#define PINMUX_GPIO15__FUNC_I2S0_LRCK (MTK_PIN_NO(15) | 6)
+#define PINMUX_GPIO15__FUNC_DBG_MON_B17 (MTK_PIN_NO(15) | 7)
+
+#define PINMUX_GPIO16__FUNC_GPIO16 (MTK_PIN_NO(16) | 0)
+#define PINMUX_GPIO16__FUNC_DBPI_D3 (MTK_PIN_NO(16) | 1)
+#define PINMUX_GPIO16__FUNC_SPI5_CLK (MTK_PIN_NO(16) | 2)
+#define PINMUX_GPIO16__FUNC_PCM0_DI (MTK_PIN_NO(16) | 3)
+#define PINMUX_GPIO16__FUNC_MD_UTXD1 (MTK_PIN_NO(16) | 4)
+#define PINMUX_GPIO16__FUNC_ANT_SEL6 (MTK_PIN_NO(16) | 5)
+#define PINMUX_GPIO16__FUNC_I2S0_DI (MTK_PIN_NO(16) | 6)
+#define PINMUX_GPIO16__FUNC_DBG_MON_B23 (MTK_PIN_NO(16) | 7)
+
+#define PINMUX_GPIO17__FUNC_GPIO17 (MTK_PIN_NO(17) | 0)
+#define PINMUX_GPIO17__FUNC_DBPI_D4 (MTK_PIN_NO(17) | 1)
+#define PINMUX_GPIO17__FUNC_SPI4_MI (MTK_PIN_NO(17) | 2)
+#define PINMUX_GPIO17__FUNC_CONN_MCU_TRST_B (MTK_PIN_NO(17) | 3)
+#define PINMUX_GPIO17__FUNC_MD_INT0 (MTK_PIN_NO(17) | 4)
+#define PINMUX_GPIO17__FUNC_ANT_SEL7 (MTK_PIN_NO(17) | 5)
+#define PINMUX_GPIO17__FUNC_I2S3_MCK (MTK_PIN_NO(17) | 6)
+#define PINMUX_GPIO17__FUNC_DBG_MON_A1 (MTK_PIN_NO(17) | 7)
+
+#define PINMUX_GPIO18__FUNC_GPIO18 (MTK_PIN_NO(18) | 0)
+#define PINMUX_GPIO18__FUNC_DBPI_D5 (MTK_PIN_NO(18) | 1)
+#define PINMUX_GPIO18__FUNC_SPI4_CSB (MTK_PIN_NO(18) | 2)
+#define PINMUX_GPIO18__FUNC_CONN_MCU_DBGI_N (MTK_PIN_NO(18) | 3)
+#define PINMUX_GPIO18__FUNC_MD_INT0 (MTK_PIN_NO(18) | 4)
+#define PINMUX_GPIO18__FUNC_SCP_VREQ_VAO (MTK_PIN_NO(18) | 5)
+#define PINMUX_GPIO18__FUNC_I2S3_BCK (MTK_PIN_NO(18) | 6)
+#define PINMUX_GPIO18__FUNC_DBG_MON_A2 (MTK_PIN_NO(18) | 7)
+
+#define PINMUX_GPIO19__FUNC_GPIO19 (MTK_PIN_NO(19) | 0)
+#define PINMUX_GPIO19__FUNC_DBPI_D6 (MTK_PIN_NO(19) | 1)
+#define PINMUX_GPIO19__FUNC_SPI4_MO (MTK_PIN_NO(19) | 2)
+#define PINMUX_GPIO19__FUNC_CONN_MCU_TDO (MTK_PIN_NO(19) | 3)
+#define PINMUX_GPIO19__FUNC_MD_INT2_C2K_UIM1_HOT_PLUG (MTK_PIN_NO(19) | 4)
+#define PINMUX_GPIO19__FUNC_URXD1 (MTK_PIN_NO(19) | 5)
+#define PINMUX_GPIO19__FUNC_I2S3_LRCK (MTK_PIN_NO(19) | 6)
+#define PINMUX_GPIO19__FUNC_DBG_MON_A3 (MTK_PIN_NO(19) | 7)
+
+#define PINMUX_GPIO20__FUNC_GPIO20 (MTK_PIN_NO(20) | 0)
+#define PINMUX_GPIO20__FUNC_DBPI_D7 (MTK_PIN_NO(20) | 1)
+#define PINMUX_GPIO20__FUNC_SPI4_CLK (MTK_PIN_NO(20) | 2)
+#define PINMUX_GPIO20__FUNC_CONN_MCU_DBGACK_N (MTK_PIN_NO(20) | 3)
+#define PINMUX_GPIO20__FUNC_MD_INT1_C2K_UIM0_HOT_PLUG (MTK_PIN_NO(20) | 4)
+#define PINMUX_GPIO20__FUNC_UTXD1 (MTK_PIN_NO(20) | 5)
+#define PINMUX_GPIO20__FUNC_I2S3_DO (MTK_PIN_NO(20) | 6)
+#define PINMUX_GPIO20__FUNC_DBG_MON_A19 (MTK_PIN_NO(20) | 7)
+
+#define PINMUX_GPIO21__FUNC_GPIO21 (MTK_PIN_NO(21) | 0)
+#define PINMUX_GPIO21__FUNC_DBPI_D8 (MTK_PIN_NO(21) | 1)
+#define PINMUX_GPIO21__FUNC_SPI3_MI (MTK_PIN_NO(21) | 2)
+#define PINMUX_GPIO21__FUNC_CONN_MCU_TMS (MTK_PIN_NO(21) | 3)
+#define PINMUX_GPIO21__FUNC_DAP_MD32_SWD (MTK_PIN_NO(21) | 4)
+#define PINMUX_GPIO21__FUNC_CONN_MCU_AICE_TMSC (MTK_PIN_NO(21) | 5)
+#define PINMUX_GPIO21__FUNC_I2S2_MCK (MTK_PIN_NO(21) | 6)
+#define PINMUX_GPIO21__FUNC_DBG_MON_B5 (MTK_PIN_NO(21) | 7)
+
+#define PINMUX_GPIO22__FUNC_GPIO22 (MTK_PIN_NO(22) | 0)
+#define PINMUX_GPIO22__FUNC_DBPI_D9 (MTK_PIN_NO(22) | 1)
+#define PINMUX_GPIO22__FUNC_SPI3_CSB (MTK_PIN_NO(22) | 2)
+#define PINMUX_GPIO22__FUNC_CONN_MCU_TCK (MTK_PIN_NO(22) | 3)
+#define PINMUX_GPIO22__FUNC_DAP_MD32_SWCK (MTK_PIN_NO(22) | 4)
+#define PINMUX_GPIO22__FUNC_CONN_MCU_AICE_TCKC (MTK_PIN_NO(22) | 5)
+#define PINMUX_GPIO22__FUNC_I2S2_BCK (MTK_PIN_NO(22) | 6)
+#define PINMUX_GPIO22__FUNC_DBG_MON_B6 (MTK_PIN_NO(22) | 7)
+
+#define PINMUX_GPIO23__FUNC_GPIO23 (MTK_PIN_NO(23) | 0)
+#define PINMUX_GPIO23__FUNC_DBPI_D10 (MTK_PIN_NO(23) | 1)
+#define PINMUX_GPIO23__FUNC_SPI3_MO (MTK_PIN_NO(23) | 2)
+#define PINMUX_GPIO23__FUNC_CONN_MCU_TDI (MTK_PIN_NO(23) | 3)
+#define PINMUX_GPIO23__FUNC_UCTS1 (MTK_PIN_NO(23) | 4)
+#define PINMUX_GPIO23__FUNC_EXT_FRAME_SYNC (MTK_PIN_NO(23) | 5)
+#define PINMUX_GPIO23__FUNC_I2S2_LRCK (MTK_PIN_NO(23) | 6)
+#define PINMUX_GPIO23__FUNC_DBG_MON_B7 (MTK_PIN_NO(23) | 7)
+
+#define PINMUX_GPIO24__FUNC_GPIO24 (MTK_PIN_NO(24) | 0)
+#define PINMUX_GPIO24__FUNC_DBPI_D11 (MTK_PIN_NO(24) | 1)
+#define PINMUX_GPIO24__FUNC_SPI3_CLK (MTK_PIN_NO(24) | 2)
+#define PINMUX_GPIO24__FUNC_SRCLKENAI0 (MTK_PIN_NO(24) | 3)
+#define PINMUX_GPIO24__FUNC_URTS1 (MTK_PIN_NO(24) | 4)
+#define PINMUX_GPIO24__FUNC_IO_JTAG_TCK (MTK_PIN_NO(24) | 5)
+#define PINMUX_GPIO24__FUNC_I2S2_DI (MTK_PIN_NO(24) | 6)
+#define PINMUX_GPIO24__FUNC_DBG_MON_B31 (MTK_PIN_NO(24) | 7)
+
+#define PINMUX_GPIO25__FUNC_GPIO25 (MTK_PIN_NO(25) | 0)
+#define PINMUX_GPIO25__FUNC_DBPI_HSYNC (MTK_PIN_NO(25) | 1)
+#define PINMUX_GPIO25__FUNC_ANT_SEL0 (MTK_PIN_NO(25) | 2)
+#define PINMUX_GPIO25__FUNC_SCL6 (MTK_PIN_NO(25) | 3)
+#define PINMUX_GPIO25__FUNC_KPCOL2 (MTK_PIN_NO(25) | 4)
+#define PINMUX_GPIO25__FUNC_IO_JTAG_TMS (MTK_PIN_NO(25) | 5)
+#define PINMUX_GPIO25__FUNC_I2S1_MCK (MTK_PIN_NO(25) | 6)
+#define PINMUX_GPIO25__FUNC_DBG_MON_B0 (MTK_PIN_NO(25) | 7)
+
+#define PINMUX_GPIO26__FUNC_GPIO26 (MTK_PIN_NO(26) | 0)
+#define PINMUX_GPIO26__FUNC_DBPI_VSYNC (MTK_PIN_NO(26) | 1)
+#define PINMUX_GPIO26__FUNC_ANT_SEL1 (MTK_PIN_NO(26) | 2)
+#define PINMUX_GPIO26__FUNC_SDA6 (MTK_PIN_NO(26) | 3)
+#define PINMUX_GPIO26__FUNC_KPROW2 (MTK_PIN_NO(26) | 4)
+#define PINMUX_GPIO26__FUNC_IO_JTAG_TDI (MTK_PIN_NO(26) | 5)
+#define PINMUX_GPIO26__FUNC_I2S1_BCK (MTK_PIN_NO(26) | 6)
+#define PINMUX_GPIO26__FUNC_DBG_MON_B1 (MTK_PIN_NO(26) | 7)
+
+#define PINMUX_GPIO27__FUNC_GPIO27 (MTK_PIN_NO(27) | 0)
+#define PINMUX_GPIO27__FUNC_DBPI_DE (MTK_PIN_NO(27) | 1)
+#define PINMUX_GPIO27__FUNC_ANT_SEL2 (MTK_PIN_NO(27) | 2)
+#define PINMUX_GPIO27__FUNC_SCL7 (MTK_PIN_NO(27) | 3)
+#define PINMUX_GPIO27__FUNC_DMIC_CLK (MTK_PIN_NO(27) | 4)
+#define PINMUX_GPIO27__FUNC_IO_JTAG_TDO (MTK_PIN_NO(27) | 5)
+#define PINMUX_GPIO27__FUNC_I2S1_LRCK (MTK_PIN_NO(27) | 6)
+#define PINMUX_GPIO27__FUNC_DBG_MON_B9 (MTK_PIN_NO(27) | 7)
+
+#define PINMUX_GPIO28__FUNC_GPIO28 (MTK_PIN_NO(28) | 0)
+#define PINMUX_GPIO28__FUNC_DBPI_CK (MTK_PIN_NO(28) | 1)
+#define PINMUX_GPIO28__FUNC_DVFSRC_EXT_REQ (MTK_PIN_NO(28) | 2)
+#define PINMUX_GPIO28__FUNC_SDA7 (MTK_PIN_NO(28) | 3)
+#define PINMUX_GPIO28__FUNC_DMIC_DAT (MTK_PIN_NO(28) | 4)
+#define PINMUX_GPIO28__FUNC_IO_JTAG_TRSTN (MTK_PIN_NO(28) | 5)
+#define PINMUX_GPIO28__FUNC_I2S1_DO (MTK_PIN_NO(28) | 6)
+#define PINMUX_GPIO28__FUNC_DBG_MON_B32 (MTK_PIN_NO(28) | 7)
+
+#define PINMUX_GPIO29__FUNC_GPIO29 (MTK_PIN_NO(29) | 0)
+#define PINMUX_GPIO29__FUNC_MSDC1_CLK (MTK_PIN_NO(29) | 1)
+#define PINMUX_GPIO29__FUNC_IO_JTAG_TCK (MTK_PIN_NO(29) | 2)
+#define PINMUX_GPIO29__FUNC_UDI_TCK (MTK_PIN_NO(29) | 3)
+#define PINMUX_GPIO29__FUNC_CONN_DSP_JCK (MTK_PIN_NO(29) | 4)
+#define PINMUX_GPIO29__FUNC_SSPM_JTAG_TCK (MTK_PIN_NO(29) | 5)
+#define PINMUX_GPIO29__FUNC_PCM1_CLK (MTK_PIN_NO(29) | 6)
+#define PINMUX_GPIO29__FUNC_DBG_MON_A6 (MTK_PIN_NO(29) | 7)
+
+#define PINMUX_GPIO30__FUNC_GPIO30 (MTK_PIN_NO(30) | 0)
+#define PINMUX_GPIO30__FUNC_MSDC1_DAT3 (MTK_PIN_NO(30) | 1)
+#define PINMUX_GPIO30__FUNC_DAP_MD32_SWD (MTK_PIN_NO(30) | 2)
+#define PINMUX_GPIO30__FUNC_CONN_MCU_AICE_TMSC (MTK_PIN_NO(30) | 3)
+#define PINMUX_GPIO30__FUNC_CONN_DSP_JINTP (MTK_PIN_NO(30) | 4)
+#define PINMUX_GPIO30__FUNC_SSPM_JTAG_TRSTN (MTK_PIN_NO(30) | 5)
+#define PINMUX_GPIO30__FUNC_PCM1_DI (MTK_PIN_NO(30) | 6)
+#define PINMUX_GPIO30__FUNC_DBG_MON_A7 (MTK_PIN_NO(30) | 7)
+
+#define PINMUX_GPIO31__FUNC_GPIO31 (MTK_PIN_NO(31) | 0)
+#define PINMUX_GPIO31__FUNC_MSDC1_CMD (MTK_PIN_NO(31) | 1)
+#define PINMUX_GPIO31__FUNC_IO_JTAG_TMS (MTK_PIN_NO(31) | 2)
+#define PINMUX_GPIO31__FUNC_UDI_TMS (MTK_PIN_NO(31) | 3)
+#define PINMUX_GPIO31__FUNC_CONN_DSP_JMS (MTK_PIN_NO(31) | 4)
+#define PINMUX_GPIO31__FUNC_SSPM_JTAG_TMS (MTK_PIN_NO(31) | 5)
+#define PINMUX_GPIO31__FUNC_PCM1_SYNC (MTK_PIN_NO(31) | 6)
+#define PINMUX_GPIO31__FUNC_DBG_MON_A8 (MTK_PIN_NO(31) | 7)
+
+#define PINMUX_GPIO32__FUNC_GPIO32 (MTK_PIN_NO(32) | 0)
+#define PINMUX_GPIO32__FUNC_MSDC1_DAT0 (MTK_PIN_NO(32) | 1)
+#define PINMUX_GPIO32__FUNC_IO_JTAG_TDI (MTK_PIN_NO(32) | 2)
+#define PINMUX_GPIO32__FUNC_UDI_TDI (MTK_PIN_NO(32) | 3)
+#define PINMUX_GPIO32__FUNC_CONN_DSP_JDI (MTK_PIN_NO(32) | 4)
+#define PINMUX_GPIO32__FUNC_SSPM_JTAG_TDI (MTK_PIN_NO(32) | 5)
+#define PINMUX_GPIO32__FUNC_PCM1_DO0 (MTK_PIN_NO(32) | 6)
+#define PINMUX_GPIO32__FUNC_DBG_MON_A9 (MTK_PIN_NO(32) | 7)
+
+#define PINMUX_GPIO33__FUNC_GPIO33 (MTK_PIN_NO(33) | 0)
+#define PINMUX_GPIO33__FUNC_MSDC1_DAT2 (MTK_PIN_NO(33) | 1)
+#define PINMUX_GPIO33__FUNC_IO_JTAG_TRSTN (MTK_PIN_NO(33) | 2)
+#define PINMUX_GPIO33__FUNC_UDI_NTRST (MTK_PIN_NO(33) | 3)
+#define PINMUX_GPIO33__FUNC_DAP_MD32_SWCK (MTK_PIN_NO(33) | 4)
+#define PINMUX_GPIO33__FUNC_CONN_MCU_AICE_TCKC (MTK_PIN_NO(33) | 5)
+#define PINMUX_GPIO33__FUNC_PCM1_DO2 (MTK_PIN_NO(33) | 6)
+#define PINMUX_GPIO33__FUNC_DBG_MON_A10 (MTK_PIN_NO(33) | 7)
+
+#define PINMUX_GPIO34__FUNC_GPIO34 (MTK_PIN_NO(34) | 0)
+#define PINMUX_GPIO34__FUNC_MSDC1_DAT1 (MTK_PIN_NO(34) | 1)
+#define PINMUX_GPIO34__FUNC_IO_JTAG_TDO (MTK_PIN_NO(34) | 2)
+#define PINMUX_GPIO34__FUNC_UDI_TDO (MTK_PIN_NO(34) | 3)
+#define PINMUX_GPIO34__FUNC_CONN_DSP_JDO (MTK_PIN_NO(34) | 4)
+#define PINMUX_GPIO34__FUNC_SSPM_JTAG_TDO (MTK_PIN_NO(34) | 5)
+#define PINMUX_GPIO34__FUNC_PCM1_DO1 (MTK_PIN_NO(34) | 6)
+#define PINMUX_GPIO34__FUNC_DBG_MON_A11 (MTK_PIN_NO(34) | 7)
+
+#define PINMUX_GPIO35__FUNC_GPIO35 (MTK_PIN_NO(35) | 0)
+#define PINMUX_GPIO35__FUNC_MD1_SIM2_SIO (MTK_PIN_NO(35) | 1)
+#define PINMUX_GPIO35__FUNC_CCU_JTAG_TDO (MTK_PIN_NO(35) | 2)
+#define PINMUX_GPIO35__FUNC_MD1_SIM1_SIO (MTK_PIN_NO(35) | 3)
+#define PINMUX_GPIO35__FUNC_SCP_JTAG_TDO (MTK_PIN_NO(35) | 5)
+#define PINMUX_GPIO35__FUNC_CONN_DSP_JMS (MTK_PIN_NO(35) | 6)
+#define PINMUX_GPIO35__FUNC_DBG_MON_A28 (MTK_PIN_NO(35) | 7)
+
+#define PINMUX_GPIO36__FUNC_GPIO36 (MTK_PIN_NO(36) | 0)
+#define PINMUX_GPIO36__FUNC_MD1_SIM2_SRST (MTK_PIN_NO(36) | 1)
+#define PINMUX_GPIO36__FUNC_CCU_JTAG_TMS (MTK_PIN_NO(36) | 2)
+#define PINMUX_GPIO36__FUNC_MD1_SIM1_SRST (MTK_PIN_NO(36) | 3)
+#define PINMUX_GPIO36__FUNC_CONN_MCU_AICE_TMSC (MTK_PIN_NO(36) | 4)
+#define PINMUX_GPIO36__FUNC_SCP_JTAG_TMS (MTK_PIN_NO(36) | 5)
+#define PINMUX_GPIO36__FUNC_CONN_DSP_JINTP (MTK_PIN_NO(36) | 6)
+#define PINMUX_GPIO36__FUNC_DBG_MON_A29 (MTK_PIN_NO(36) | 7)
+
+#define PINMUX_GPIO37__FUNC_GPIO37 (MTK_PIN_NO(37) | 0)
+#define PINMUX_GPIO37__FUNC_MD1_SIM2_SCLK (MTK_PIN_NO(37) | 1)
+#define PINMUX_GPIO37__FUNC_CCU_JTAG_TDI (MTK_PIN_NO(37) | 2)
+#define PINMUX_GPIO37__FUNC_MD1_SIM1_SCLK (MTK_PIN_NO(37) | 3)
+#define PINMUX_GPIO37__FUNC_SCP_JTAG_TDI (MTK_PIN_NO(37) | 5)
+#define PINMUX_GPIO37__FUNC_CONN_DSP_JDO (MTK_PIN_NO(37) | 6)
+#define PINMUX_GPIO37__FUNC_DBG_MON_A30 (MTK_PIN_NO(37) | 7)
+
+#define PINMUX_GPIO38__FUNC_GPIO38 (MTK_PIN_NO(38) | 0)
+#define PINMUX_GPIO38__FUNC_MD1_SIM1_SCLK (MTK_PIN_NO(38) | 1)
+#define PINMUX_GPIO38__FUNC_MD1_SIM2_SCLK (MTK_PIN_NO(38) | 3)
+#define PINMUX_GPIO38__FUNC_CONN_MCU_AICE_TCKC (MTK_PIN_NO(38) | 4)
+#define PINMUX_GPIO38__FUNC_DBG_MON_A20 (MTK_PIN_NO(38) | 7)
+
+#define PINMUX_GPIO39__FUNC_GPIO39 (MTK_PIN_NO(39) | 0)
+#define PINMUX_GPIO39__FUNC_MD1_SIM1_SRST (MTK_PIN_NO(39) | 1)
+#define PINMUX_GPIO39__FUNC_CCU_JTAG_TCK (MTK_PIN_NO(39) | 2)
+#define PINMUX_GPIO39__FUNC_MD1_SIM2_SRST (MTK_PIN_NO(39) | 3)
+#define PINMUX_GPIO39__FUNC_SCP_JTAG_TCK (MTK_PIN_NO(39) | 5)
+#define PINMUX_GPIO39__FUNC_CONN_DSP_JCK (MTK_PIN_NO(39) | 6)
+#define PINMUX_GPIO39__FUNC_DBG_MON_A31 (MTK_PIN_NO(39) | 7)
+
+#define PINMUX_GPIO40__FUNC_GPIO40 (MTK_PIN_NO(40) | 0)
+#define PINMUX_GPIO40__FUNC_MD1_SIM1_SIO (MTK_PIN_NO(40) | 1)
+#define PINMUX_GPIO40__FUNC_CCU_JTAG_TRST (MTK_PIN_NO(40) | 2)
+#define PINMUX_GPIO40__FUNC_MD1_SIM2_SIO (MTK_PIN_NO(40) | 3)
+#define PINMUX_GPIO40__FUNC_SCP_JTAG_TRSTN (MTK_PIN_NO(40) | 5)
+#define PINMUX_GPIO40__FUNC_CONN_DSP_JDI (MTK_PIN_NO(40) | 6)
+#define PINMUX_GPIO40__FUNC_DBG_MON_A32 (MTK_PIN_NO(40) | 7)
+
+#define PINMUX_GPIO41__FUNC_GPIO41 (MTK_PIN_NO(41) | 0)
+#define PINMUX_GPIO41__FUNC_IDDIG (MTK_PIN_NO(41) | 1)
+#define PINMUX_GPIO41__FUNC_URXD1 (MTK_PIN_NO(41) | 2)
+#define PINMUX_GPIO41__FUNC_UCTS0 (MTK_PIN_NO(41) | 3)
+#define PINMUX_GPIO41__FUNC_SSPM_UTXD_AO (MTK_PIN_NO(41) | 4)
+#define PINMUX_GPIO41__FUNC_EXT_FRAME_SYNC (MTK_PIN_NO(41) | 5)
+#define PINMUX_GPIO41__FUNC_DMIC_CLK (MTK_PIN_NO(41) | 6)
+
+#define PINMUX_GPIO42__FUNC_GPIO42 (MTK_PIN_NO(42) | 0)
+#define PINMUX_GPIO42__FUNC_USB_DRVVBUS (MTK_PIN_NO(42) | 1)
+#define PINMUX_GPIO42__FUNC_UTXD1 (MTK_PIN_NO(42) | 2)
+#define PINMUX_GPIO42__FUNC_URTS0 (MTK_PIN_NO(42) | 3)
+#define PINMUX_GPIO42__FUNC_SSPM_URXD_AO (MTK_PIN_NO(42) | 4)
+#define PINMUX_GPIO42__FUNC_EXT_FRAME_SYNC (MTK_PIN_NO(42) | 5)
+#define PINMUX_GPIO42__FUNC_DMIC_DAT (MTK_PIN_NO(42) | 6)
+
+#define PINMUX_GPIO43__FUNC_GPIO43 (MTK_PIN_NO(43) | 0)
+#define PINMUX_GPIO43__FUNC_DISP_PWM (MTK_PIN_NO(43) | 1)
+
+#define PINMUX_GPIO44__FUNC_GPIO44 (MTK_PIN_NO(44) | 0)
+#define PINMUX_GPIO44__FUNC_DSI_TE (MTK_PIN_NO(44) | 1)
+
+#define PINMUX_GPIO45__FUNC_GPIO45 (MTK_PIN_NO(45) | 0)
+#define PINMUX_GPIO45__FUNC_LCM_RST (MTK_PIN_NO(45) | 1)
+
+#define PINMUX_GPIO46__FUNC_GPIO46 (MTK_PIN_NO(46) | 0)
+#define PINMUX_GPIO46__FUNC_MD_INT2_C2K_UIM1_HOT_PLUG (MTK_PIN_NO(46) | 1)
+#define PINMUX_GPIO46__FUNC_URXD1 (MTK_PIN_NO(46) | 2)
+#define PINMUX_GPIO46__FUNC_UCTS1 (MTK_PIN_NO(46) | 3)
+#define PINMUX_GPIO46__FUNC_CCU_UTXD_AO (MTK_PIN_NO(46) | 4)
+#define PINMUX_GPIO46__FUNC_TP_UCTS1_AO (MTK_PIN_NO(46) | 5)
+#define PINMUX_GPIO46__FUNC_IDDIG (MTK_PIN_NO(46) | 6)
+#define PINMUX_GPIO46__FUNC_I2S5_LRCK (MTK_PIN_NO(46) | 7)
+
+#define PINMUX_GPIO47__FUNC_GPIO47 (MTK_PIN_NO(47) | 0)
+#define PINMUX_GPIO47__FUNC_MD_INT1_C2K_UIM0_HOT_PLUG (MTK_PIN_NO(47) | 1)
+#define PINMUX_GPIO47__FUNC_UTXD1 (MTK_PIN_NO(47) | 2)
+#define PINMUX_GPIO47__FUNC_URTS1 (MTK_PIN_NO(47) | 3)
+#define PINMUX_GPIO47__FUNC_CCU_URXD_AO (MTK_PIN_NO(47) | 4)
+#define PINMUX_GPIO47__FUNC_TP_URTS1_AO (MTK_PIN_NO(47) | 5)
+#define PINMUX_GPIO47__FUNC_USB_DRVVBUS (MTK_PIN_NO(47) | 6)
+#define PINMUX_GPIO47__FUNC_I2S5_DO (MTK_PIN_NO(47) | 7)
+
+#define PINMUX_GPIO48__FUNC_GPIO48 (MTK_PIN_NO(48) | 0)
+#define PINMUX_GPIO48__FUNC_SCL5 (MTK_PIN_NO(48) | 1)
+
+#define PINMUX_GPIO49__FUNC_GPIO49 (MTK_PIN_NO(49) | 0)
+#define PINMUX_GPIO49__FUNC_SDA5 (MTK_PIN_NO(49) | 1)
+
+#define PINMUX_GPIO50__FUNC_GPIO50 (MTK_PIN_NO(50) | 0)
+#define PINMUX_GPIO50__FUNC_SCL3 (MTK_PIN_NO(50) | 1)
+
+#define PINMUX_GPIO51__FUNC_GPIO51 (MTK_PIN_NO(51) | 0)
+#define PINMUX_GPIO51__FUNC_SDA3 (MTK_PIN_NO(51) | 1)
+
+#define PINMUX_GPIO52__FUNC_GPIO52 (MTK_PIN_NO(52) | 0)
+#define PINMUX_GPIO52__FUNC_BPI_ANT2 (MTK_PIN_NO(52) | 1)
+
+#define PINMUX_GPIO53__FUNC_GPIO53 (MTK_PIN_NO(53) | 0)
+#define PINMUX_GPIO53__FUNC_BPI_ANT0 (MTK_PIN_NO(53) | 1)
+
+#define PINMUX_GPIO54__FUNC_GPIO54 (MTK_PIN_NO(54) | 0)
+#define PINMUX_GPIO54__FUNC_BPI_OLAT1 (MTK_PIN_NO(54) | 1)
+
+#define PINMUX_GPIO55__FUNC_GPIO55 (MTK_PIN_NO(55) | 0)
+#define PINMUX_GPIO55__FUNC_BPI_BUS8 (MTK_PIN_NO(55) | 1)
+
+#define PINMUX_GPIO56__FUNC_GPIO56 (MTK_PIN_NO(56) | 0)
+#define PINMUX_GPIO56__FUNC_BPI_BUS9 (MTK_PIN_NO(56) | 1)
+#define PINMUX_GPIO56__FUNC_SCL_6306 (MTK_PIN_NO(56) | 2)
+
+#define PINMUX_GPIO57__FUNC_GPIO57 (MTK_PIN_NO(57) | 0)
+#define PINMUX_GPIO57__FUNC_BPI_BUS10 (MTK_PIN_NO(57) | 1)
+#define PINMUX_GPIO57__FUNC_SDA_6306 (MTK_PIN_NO(57) | 2)
+
+#define PINMUX_GPIO58__FUNC_GPIO58 (MTK_PIN_NO(58) | 0)
+#define PINMUX_GPIO58__FUNC_RFIC0_BSI_D2 (MTK_PIN_NO(58) | 1)
+#define PINMUX_GPIO58__FUNC_SPM_BSI_D2 (MTK_PIN_NO(58) | 2)
+#define PINMUX_GPIO58__FUNC_PWM_B (MTK_PIN_NO(58) | 3)
+
+#define PINMUX_GPIO59__FUNC_GPIO59 (MTK_PIN_NO(59) | 0)
+#define PINMUX_GPIO59__FUNC_RFIC0_BSI_D1 (MTK_PIN_NO(59) | 1)
+#define PINMUX_GPIO59__FUNC_SPM_BSI_D1 (MTK_PIN_NO(59) | 2)
+
+#define PINMUX_GPIO60__FUNC_GPIO60 (MTK_PIN_NO(60) | 0)
+#define PINMUX_GPIO60__FUNC_RFIC0_BSI_D0 (MTK_PIN_NO(60) | 1)
+#define PINMUX_GPIO60__FUNC_SPM_BSI_D0 (MTK_PIN_NO(60) | 2)
+
+#define PINMUX_GPIO61__FUNC_GPIO61 (MTK_PIN_NO(61) | 0)
+#define PINMUX_GPIO61__FUNC_MIPI1_SDATA (MTK_PIN_NO(61) | 1)
+
+#define PINMUX_GPIO62__FUNC_GPIO62 (MTK_PIN_NO(62) | 0)
+#define PINMUX_GPIO62__FUNC_MIPI1_SCLK (MTK_PIN_NO(62) | 1)
+
+#define PINMUX_GPIO63__FUNC_GPIO63 (MTK_PIN_NO(63) | 0)
+#define PINMUX_GPIO63__FUNC_MIPI0_SDATA (MTK_PIN_NO(63) | 1)
+
+#define PINMUX_GPIO64__FUNC_GPIO64 (MTK_PIN_NO(64) | 0)
+#define PINMUX_GPIO64__FUNC_MIPI0_SCLK (MTK_PIN_NO(64) | 1)
+
+#define PINMUX_GPIO65__FUNC_GPIO65 (MTK_PIN_NO(65) | 0)
+#define PINMUX_GPIO65__FUNC_MIPI3_SDATA (MTK_PIN_NO(65) | 1)
+#define PINMUX_GPIO65__FUNC_BPI_OLAT2 (MTK_PIN_NO(65) | 2)
+
+#define PINMUX_GPIO66__FUNC_GPIO66 (MTK_PIN_NO(66) | 0)
+#define PINMUX_GPIO66__FUNC_MIPI3_SCLK (MTK_PIN_NO(66) | 1)
+#define PINMUX_GPIO66__FUNC_BPI_OLAT3 (MTK_PIN_NO(66) | 2)
+
+#define PINMUX_GPIO67__FUNC_GPIO67 (MTK_PIN_NO(67) | 0)
+#define PINMUX_GPIO67__FUNC_MIPI2_SDATA (MTK_PIN_NO(67) | 1)
+
+#define PINMUX_GPIO68__FUNC_GPIO68 (MTK_PIN_NO(68) | 0)
+#define PINMUX_GPIO68__FUNC_MIPI2_SCLK (MTK_PIN_NO(68) | 1)
+
+#define PINMUX_GPIO69__FUNC_GPIO69 (MTK_PIN_NO(69) | 0)
+#define PINMUX_GPIO69__FUNC_BPI_BUS7 (MTK_PIN_NO(69) | 1)
+
+#define PINMUX_GPIO70__FUNC_GPIO70 (MTK_PIN_NO(70) | 0)
+#define PINMUX_GPIO70__FUNC_BPI_BUS6 (MTK_PIN_NO(70) | 1)
+
+#define PINMUX_GPIO71__FUNC_GPIO71 (MTK_PIN_NO(71) | 0)
+#define PINMUX_GPIO71__FUNC_BPI_BUS5 (MTK_PIN_NO(71) | 1)
+
+#define PINMUX_GPIO72__FUNC_GPIO72 (MTK_PIN_NO(72) | 0)
+#define PINMUX_GPIO72__FUNC_BPI_BUS4 (MTK_PIN_NO(72) | 1)
+
+#define PINMUX_GPIO73__FUNC_GPIO73 (MTK_PIN_NO(73) | 0)
+#define PINMUX_GPIO73__FUNC_BPI_BUS3 (MTK_PIN_NO(73) | 1)
+
+#define PINMUX_GPIO74__FUNC_GPIO74 (MTK_PIN_NO(74) | 0)
+#define PINMUX_GPIO74__FUNC_BPI_BUS2 (MTK_PIN_NO(74) | 1)
+
+#define PINMUX_GPIO75__FUNC_GPIO75 (MTK_PIN_NO(75) | 0)
+#define PINMUX_GPIO75__FUNC_BPI_BUS1 (MTK_PIN_NO(75) | 1)
+
+#define PINMUX_GPIO76__FUNC_GPIO76 (MTK_PIN_NO(76) | 0)
+#define PINMUX_GPIO76__FUNC_BPI_BUS0 (MTK_PIN_NO(76) | 1)
+
+#define PINMUX_GPIO77__FUNC_GPIO77 (MTK_PIN_NO(77) | 0)
+#define PINMUX_GPIO77__FUNC_BPI_ANT1 (MTK_PIN_NO(77) | 1)
+
+#define PINMUX_GPIO78__FUNC_GPIO78 (MTK_PIN_NO(78) | 0)
+#define PINMUX_GPIO78__FUNC_BPI_OLAT0 (MTK_PIN_NO(78) | 1)
+
+#define PINMUX_GPIO79__FUNC_GPIO79 (MTK_PIN_NO(79) | 0)
+#define PINMUX_GPIO79__FUNC_BPI_PA_VM1 (MTK_PIN_NO(79) | 1)
+#define PINMUX_GPIO79__FUNC_MIPI4_SDATA (MTK_PIN_NO(79) | 2)
+
+#define PINMUX_GPIO80__FUNC_GPIO80 (MTK_PIN_NO(80) | 0)
+#define PINMUX_GPIO80__FUNC_BPI_PA_VM0 (MTK_PIN_NO(80) | 1)
+#define PINMUX_GPIO80__FUNC_MIPI4_SCLK (MTK_PIN_NO(80) | 2)
+
+#define PINMUX_GPIO81__FUNC_GPIO81 (MTK_PIN_NO(81) | 0)
+#define PINMUX_GPIO81__FUNC_SDA1 (MTK_PIN_NO(81) | 1)
+
+#define PINMUX_GPIO82__FUNC_GPIO82 (MTK_PIN_NO(82) | 0)
+#define PINMUX_GPIO82__FUNC_SDA0 (MTK_PIN_NO(82) | 1)
+
+#define PINMUX_GPIO83__FUNC_GPIO83 (MTK_PIN_NO(83) | 0)
+#define PINMUX_GPIO83__FUNC_SCL0 (MTK_PIN_NO(83) | 1)
+
+#define PINMUX_GPIO84__FUNC_GPIO84 (MTK_PIN_NO(84) | 0)
+#define PINMUX_GPIO84__FUNC_SCL1 (MTK_PIN_NO(84) | 1)
+
+#define PINMUX_GPIO85__FUNC_GPIO85 (MTK_PIN_NO(85) | 0)
+#define PINMUX_GPIO85__FUNC_SPI0_MI (MTK_PIN_NO(85) | 1)
+#define PINMUX_GPIO85__FUNC_SCP_SPI0_MI (MTK_PIN_NO(85) | 2)
+#define PINMUX_GPIO85__FUNC_CLKM3 (MTK_PIN_NO(85) | 3)
+#define PINMUX_GPIO85__FUNC_I2S1_BCK (MTK_PIN_NO(85) | 4)
+#define PINMUX_GPIO85__FUNC_MFG_DFD_JTAG_TDO (MTK_PIN_NO(85) | 5)
+#define PINMUX_GPIO85__FUNC_DFD_TDO (MTK_PIN_NO(85) | 6)
+#define PINMUX_GPIO85__FUNC_JTDO_SEL1 (MTK_PIN_NO(85) | 7)
+
+#define PINMUX_GPIO86__FUNC_GPIO86 (MTK_PIN_NO(86) | 0)
+#define PINMUX_GPIO86__FUNC_SPI0_CSB (MTK_PIN_NO(86) | 1)
+#define PINMUX_GPIO86__FUNC_SCP_SPI0_CS (MTK_PIN_NO(86) | 2)
+#define PINMUX_GPIO86__FUNC_CLKM0 (MTK_PIN_NO(86) | 3)
+#define PINMUX_GPIO86__FUNC_I2S1_LRCK (MTK_PIN_NO(86) | 4)
+#define PINMUX_GPIO86__FUNC_MFG_DFD_JTAG_TMS (MTK_PIN_NO(86) | 5)
+#define PINMUX_GPIO86__FUNC_DFD_TMS (MTK_PIN_NO(86) | 6)
+#define PINMUX_GPIO86__FUNC_JTMS_SEL1 (MTK_PIN_NO(86) | 7)
+
+#define PINMUX_GPIO87__FUNC_GPIO87 (MTK_PIN_NO(87) | 0)
+#define PINMUX_GPIO87__FUNC_SPI0_MO (MTK_PIN_NO(87) | 1)
+#define PINMUX_GPIO87__FUNC_SCP_SPI0_MO (MTK_PIN_NO(87) | 2)
+#define PINMUX_GPIO87__FUNC_SDA1 (MTK_PIN_NO(87) | 3)
+#define PINMUX_GPIO87__FUNC_I2S1_DO (MTK_PIN_NO(87) | 4)
+#define PINMUX_GPIO87__FUNC_MFG_DFD_JTAG_TDI (MTK_PIN_NO(87) | 5)
+#define PINMUX_GPIO87__FUNC_DFD_TDI (MTK_PIN_NO(87) | 6)
+#define PINMUX_GPIO87__FUNC_JTDI_SEL1 (MTK_PIN_NO(87) | 7)
+
+#define PINMUX_GPIO88__FUNC_GPIO88 (MTK_PIN_NO(88) | 0)
+#define PINMUX_GPIO88__FUNC_SPI0_CLK (MTK_PIN_NO(88) | 1)
+#define PINMUX_GPIO88__FUNC_SCP_SPI0_CK (MTK_PIN_NO(88) | 2)
+#define PINMUX_GPIO88__FUNC_SCL1 (MTK_PIN_NO(88) | 3)
+#define PINMUX_GPIO88__FUNC_I2S1_MCK (MTK_PIN_NO(88) | 4)
+#define PINMUX_GPIO88__FUNC_MFG_DFD_JTAG_TCK (MTK_PIN_NO(88) | 5)
+#define PINMUX_GPIO88__FUNC_DFD_TCK_XI (MTK_PIN_NO(88) | 6)
+#define PINMUX_GPIO88__FUNC_JTCK_SEL1 (MTK_PIN_NO(88) | 7)
+
+#define PINMUX_GPIO89__FUNC_GPIO89 (MTK_PIN_NO(89) | 0)
+#define PINMUX_GPIO89__FUNC_SRCLKENAI0 (MTK_PIN_NO(89) | 1)
+#define PINMUX_GPIO89__FUNC_PWM_C (MTK_PIN_NO(89) | 2)
+#define PINMUX_GPIO89__FUNC_I2S5_BCK (MTK_PIN_NO(89) | 3)
+#define PINMUX_GPIO89__FUNC_ANT_SEL6 (MTK_PIN_NO(89) | 4)
+#define PINMUX_GPIO89__FUNC_SDA8 (MTK_PIN_NO(89) | 5)
+#define PINMUX_GPIO89__FUNC_CMVREF0 (MTK_PIN_NO(89) | 6)
+#define PINMUX_GPIO89__FUNC_DBG_MON_A21 (MTK_PIN_NO(89) | 7)
+
+#define PINMUX_GPIO90__FUNC_GPIO90 (MTK_PIN_NO(90) | 0)
+#define PINMUX_GPIO90__FUNC_PWM_A (MTK_PIN_NO(90) | 1)
+#define PINMUX_GPIO90__FUNC_CMMCLK2 (MTK_PIN_NO(90) | 2)
+#define PINMUX_GPIO90__FUNC_I2S5_LRCK (MTK_PIN_NO(90) | 3)
+#define PINMUX_GPIO90__FUNC_SCP_VREQ_VAO (MTK_PIN_NO(90) | 4)
+#define PINMUX_GPIO90__FUNC_SCL8 (MTK_PIN_NO(90) | 5)
+#define PINMUX_GPIO90__FUNC_PTA_RXD (MTK_PIN_NO(90) | 6)
+#define PINMUX_GPIO90__FUNC_DBG_MON_A22 (MTK_PIN_NO(90) | 7)
+
+#define PINMUX_GPIO91__FUNC_GPIO91 (MTK_PIN_NO(91) | 0)
+#define PINMUX_GPIO91__FUNC_KPROW1 (MTK_PIN_NO(91) | 1)
+#define PINMUX_GPIO91__FUNC_PWM_B (MTK_PIN_NO(91) | 2)
+#define PINMUX_GPIO91__FUNC_I2S5_DO (MTK_PIN_NO(91) | 3)
+#define PINMUX_GPIO91__FUNC_ANT_SEL7 (MTK_PIN_NO(91) | 4)
+#define PINMUX_GPIO91__FUNC_CMMCLK3 (MTK_PIN_NO(91) | 5)
+#define PINMUX_GPIO91__FUNC_PTA_TXD (MTK_PIN_NO(91) | 6)
+
+#define PINMUX_GPIO92__FUNC_GPIO92 (MTK_PIN_NO(92) | 0)
+#define PINMUX_GPIO92__FUNC_KPROW0 (MTK_PIN_NO(92) | 1)
+
+#define PINMUX_GPIO93__FUNC_GPIO93 (MTK_PIN_NO(93) | 0)
+#define PINMUX_GPIO93__FUNC_KPCOL0 (MTK_PIN_NO(93) | 1)
+#define PINMUX_GPIO93__FUNC_DBG_MON_B27 (MTK_PIN_NO(93) | 7)
+
+#define PINMUX_GPIO94__FUNC_GPIO94 (MTK_PIN_NO(94) | 0)
+#define PINMUX_GPIO94__FUNC_KPCOL1 (MTK_PIN_NO(94) | 1)
+#define PINMUX_GPIO94__FUNC_I2S2_DI2 (MTK_PIN_NO(94) | 2)
+#define PINMUX_GPIO94__FUNC_I2S5_MCK (MTK_PIN_NO(94) | 3)
+#define PINMUX_GPIO94__FUNC_CMMCLK2 (MTK_PIN_NO(94) | 4)
+#define PINMUX_GPIO94__FUNC_SCP_SPI2_MI (MTK_PIN_NO(94) | 5)
+#define PINMUX_GPIO94__FUNC_SRCLKENAI1 (MTK_PIN_NO(94) | 6)
+#define PINMUX_GPIO94__FUNC_SPI2_MI (MTK_PIN_NO(94) | 7)
+
+#define PINMUX_GPIO95__FUNC_GPIO95 (MTK_PIN_NO(95) | 0)
+#define PINMUX_GPIO95__FUNC_URXD0 (MTK_PIN_NO(95) | 1)
+#define PINMUX_GPIO95__FUNC_UTXD0 (MTK_PIN_NO(95) | 2)
+#define PINMUX_GPIO95__FUNC_MD_URXD0 (MTK_PIN_NO(95) | 3)
+#define PINMUX_GPIO95__FUNC_MD_URXD1 (MTK_PIN_NO(95) | 4)
+#define PINMUX_GPIO95__FUNC_SSPM_URXD_AO (MTK_PIN_NO(95) | 5)
+#define PINMUX_GPIO95__FUNC_CCU_URXD_AO (MTK_PIN_NO(95) | 6)
+
+#define PINMUX_GPIO96__FUNC_GPIO96 (MTK_PIN_NO(96) | 0)
+#define PINMUX_GPIO96__FUNC_UTXD0 (MTK_PIN_NO(96) | 1)
+#define PINMUX_GPIO96__FUNC_URXD0 (MTK_PIN_NO(96) | 2)
+#define PINMUX_GPIO96__FUNC_MD_UTXD0 (MTK_PIN_NO(96) | 3)
+#define PINMUX_GPIO96__FUNC_MD_UTXD1 (MTK_PIN_NO(96) | 4)
+#define PINMUX_GPIO96__FUNC_SSPM_UTXD_AO (MTK_PIN_NO(96) | 5)
+#define PINMUX_GPIO96__FUNC_CCU_UTXD_AO (MTK_PIN_NO(96) | 6)
+#define PINMUX_GPIO96__FUNC_DBG_MON_B2 (MTK_PIN_NO(96) | 7)
+
+#define PINMUX_GPIO97__FUNC_GPIO97 (MTK_PIN_NO(97) | 0)
+#define PINMUX_GPIO97__FUNC_UCTS0 (MTK_PIN_NO(97) | 1)
+#define PINMUX_GPIO97__FUNC_I2S2_MCK (MTK_PIN_NO(97) | 2)
+#define PINMUX_GPIO97__FUNC_IDDIG (MTK_PIN_NO(97) | 3)
+#define PINMUX_GPIO97__FUNC_CONN_MCU_TDO (MTK_PIN_NO(97) | 4)
+#define PINMUX_GPIO97__FUNC_SSPM_JTAG_TDO (MTK_PIN_NO(97) | 5)
+#define PINMUX_GPIO97__FUNC_IO_JTAG_TDO (MTK_PIN_NO(97) | 6)
+#define PINMUX_GPIO97__FUNC_DBG_MON_B3 (MTK_PIN_NO(97) | 7)
+
+#define PINMUX_GPIO98__FUNC_GPIO98 (MTK_PIN_NO(98) | 0)
+#define PINMUX_GPIO98__FUNC_URTS0 (MTK_PIN_NO(98) | 1)
+#define PINMUX_GPIO98__FUNC_I2S2_BCK (MTK_PIN_NO(98) | 2)
+#define PINMUX_GPIO98__FUNC_USB_DRVVBUS (MTK_PIN_NO(98) | 3)
+#define PINMUX_GPIO98__FUNC_CONN_MCU_TMS (MTK_PIN_NO(98) | 4)
+#define PINMUX_GPIO98__FUNC_SSPM_JTAG_TMS (MTK_PIN_NO(98) | 5)
+#define PINMUX_GPIO98__FUNC_IO_JTAG_TMS (MTK_PIN_NO(98) | 6)
+#define PINMUX_GPIO98__FUNC_DBG_MON_B4 (MTK_PIN_NO(98) | 7)
+
+#define PINMUX_GPIO99__FUNC_GPIO99 (MTK_PIN_NO(99) | 0)
+#define PINMUX_GPIO99__FUNC_CMMCLK0 (MTK_PIN_NO(99) | 1)
+#define PINMUX_GPIO99__FUNC_CONN_MCU_AICE_TMSC (MTK_PIN_NO(99) | 4)
+#define PINMUX_GPIO99__FUNC_DBG_MON_B28 (MTK_PIN_NO(99) | 7)
+
+#define PINMUX_GPIO100__FUNC_GPIO100 (MTK_PIN_NO(100) | 0)
+#define PINMUX_GPIO100__FUNC_CMMCLK1 (MTK_PIN_NO(100) | 1)
+#define PINMUX_GPIO100__FUNC_PWM_C (MTK_PIN_NO(100) | 2)
+#define PINMUX_GPIO100__FUNC_MD_INT1_C2K_UIM0_HOT_PLUG (MTK_PIN_NO(100) | 3)
+#define PINMUX_GPIO100__FUNC_CONN_MCU_AICE_TCKC (MTK_PIN_NO(100) | 4)
+#define PINMUX_GPIO100__FUNC_DBG_MON_B29 (MTK_PIN_NO(100) | 7)
+
+#define PINMUX_GPIO101__FUNC_GPIO101 (MTK_PIN_NO(101) | 0)
+#define PINMUX_GPIO101__FUNC_CLKM2 (MTK_PIN_NO(101) | 1)
+#define PINMUX_GPIO101__FUNC_I2S2_LRCK (MTK_PIN_NO(101) | 2)
+#define PINMUX_GPIO101__FUNC_CMVREF1 (MTK_PIN_NO(101) | 3)
+#define PINMUX_GPIO101__FUNC_CONN_MCU_TCK (MTK_PIN_NO(101) | 4)
+#define PINMUX_GPIO101__FUNC_SSPM_JTAG_TCK (MTK_PIN_NO(101) | 5)
+#define PINMUX_GPIO101__FUNC_IO_JTAG_TCK (MTK_PIN_NO(101) | 6)
+
+#define PINMUX_GPIO102__FUNC_GPIO102 (MTK_PIN_NO(102) | 0)
+#define PINMUX_GPIO102__FUNC_CLKM1 (MTK_PIN_NO(102) | 1)
+#define PINMUX_GPIO102__FUNC_I2S2_DI (MTK_PIN_NO(102) | 2)
+#define PINMUX_GPIO102__FUNC_DVFSRC_EXT_REQ (MTK_PIN_NO(102) | 3)
+#define PINMUX_GPIO102__FUNC_CONN_MCU_TDI (MTK_PIN_NO(102) | 4)
+#define PINMUX_GPIO102__FUNC_SSPM_JTAG_TDI (MTK_PIN_NO(102) | 5)
+#define PINMUX_GPIO102__FUNC_IO_JTAG_TDI (MTK_PIN_NO(102) | 6)
+#define PINMUX_GPIO102__FUNC_DBG_MON_B8 (MTK_PIN_NO(102) | 7)
+
+#define PINMUX_GPIO103__FUNC_GPIO103 (MTK_PIN_NO(103) | 0)
+#define PINMUX_GPIO103__FUNC_SCL2 (MTK_PIN_NO(103) | 1)
+
+#define PINMUX_GPIO104__FUNC_GPIO104 (MTK_PIN_NO(104) | 0)
+#define PINMUX_GPIO104__FUNC_SDA2 (MTK_PIN_NO(104) | 1)
+
+#define PINMUX_GPIO105__FUNC_GPIO105 (MTK_PIN_NO(105) | 0)
+#define PINMUX_GPIO105__FUNC_SCL4 (MTK_PIN_NO(105) | 1)
+
+#define PINMUX_GPIO106__FUNC_GPIO106 (MTK_PIN_NO(106) | 0)
+#define PINMUX_GPIO106__FUNC_SDA4 (MTK_PIN_NO(106) | 1)
+
+#define PINMUX_GPIO107__FUNC_GPIO107 (MTK_PIN_NO(107) | 0)
+#define PINMUX_GPIO107__FUNC_DMIC_CLK (MTK_PIN_NO(107) | 1)
+#define PINMUX_GPIO107__FUNC_ANT_SEL0 (MTK_PIN_NO(107) | 2)
+#define PINMUX_GPIO107__FUNC_CLKM0 (MTK_PIN_NO(107) | 3)
+#define PINMUX_GPIO107__FUNC_SDA7 (MTK_PIN_NO(107) | 4)
+#define PINMUX_GPIO107__FUNC_EXT_FRAME_SYNC (MTK_PIN_NO(107) | 5)
+#define PINMUX_GPIO107__FUNC_PWM_A (MTK_PIN_NO(107) | 6)
+#define PINMUX_GPIO107__FUNC_DBG_MON_B12 (MTK_PIN_NO(107) | 7)
+
+#define PINMUX_GPIO108__FUNC_GPIO108 (MTK_PIN_NO(108) | 0)
+#define PINMUX_GPIO108__FUNC_CMMCLK2 (MTK_PIN_NO(108) | 1)
+#define PINMUX_GPIO108__FUNC_ANT_SEL1 (MTK_PIN_NO(108) | 2)
+#define PINMUX_GPIO108__FUNC_CLKM1 (MTK_PIN_NO(108) | 3)
+#define PINMUX_GPIO108__FUNC_SCL8 (MTK_PIN_NO(108) | 4)
+#define PINMUX_GPIO108__FUNC_DAP_MD32_SWD (MTK_PIN_NO(108) | 5)
+#define PINMUX_GPIO108__FUNC_PWM_B (MTK_PIN_NO(108) | 6)
+#define PINMUX_GPIO108__FUNC_DBG_MON_B13 (MTK_PIN_NO(108) | 7)
+
+#define PINMUX_GPIO109__FUNC_GPIO109 (MTK_PIN_NO(109) | 0)
+#define PINMUX_GPIO109__FUNC_DMIC_DAT (MTK_PIN_NO(109) | 1)
+#define PINMUX_GPIO109__FUNC_ANT_SEL2 (MTK_PIN_NO(109) | 2)
+#define PINMUX_GPIO109__FUNC_CLKM2 (MTK_PIN_NO(109) | 3)
+#define PINMUX_GPIO109__FUNC_SDA8 (MTK_PIN_NO(109) | 4)
+#define PINMUX_GPIO109__FUNC_DAP_MD32_SWCK (MTK_PIN_NO(109) | 5)
+#define PINMUX_GPIO109__FUNC_PWM_C (MTK_PIN_NO(109) | 6)
+#define PINMUX_GPIO109__FUNC_DBG_MON_B14 (MTK_PIN_NO(109) | 7)
+
+#define PINMUX_GPIO110__FUNC_GPIO110 (MTK_PIN_NO(110) | 0)
+#define PINMUX_GPIO110__FUNC_SCL7 (MTK_PIN_NO(110) | 1)
+#define PINMUX_GPIO110__FUNC_ANT_SEL0 (MTK_PIN_NO(110) | 2)
+#define PINMUX_GPIO110__FUNC_TP_URXD1_AO (MTK_PIN_NO(110) | 3)
+#define PINMUX_GPIO110__FUNC_USB_DRVVBUS (MTK_PIN_NO(110) | 4)
+#define PINMUX_GPIO110__FUNC_SRCLKENAI1 (MTK_PIN_NO(110) | 5)
+#define PINMUX_GPIO110__FUNC_KPCOL2 (MTK_PIN_NO(110) | 6)
+#define PINMUX_GPIO110__FUNC_URXD1 (MTK_PIN_NO(110) | 7)
+
+#define PINMUX_GPIO111__FUNC_GPIO111 (MTK_PIN_NO(111) | 0)
+#define PINMUX_GPIO111__FUNC_CMMCLK3 (MTK_PIN_NO(111) | 1)
+#define PINMUX_GPIO111__FUNC_ANT_SEL1 (MTK_PIN_NO(111) | 2)
+#define PINMUX_GPIO111__FUNC_SRCLKENAI0 (MTK_PIN_NO(111) | 3)
+#define PINMUX_GPIO111__FUNC_SCP_VREQ_VAO (MTK_PIN_NO(111) | 4)
+#define PINMUX_GPIO111__FUNC_MD_INT2_C2K_UIM1_HOT_PLUG (MTK_PIN_NO(111) | 5)
+#define PINMUX_GPIO111__FUNC_DVFSRC_EXT_REQ (MTK_PIN_NO(111) | 7)
+
+#define PINMUX_GPIO112__FUNC_GPIO112 (MTK_PIN_NO(112) | 0)
+#define PINMUX_GPIO112__FUNC_SDA7 (MTK_PIN_NO(112) | 1)
+#define PINMUX_GPIO112__FUNC_ANT_SEL2 (MTK_PIN_NO(112) | 2)
+#define PINMUX_GPIO112__FUNC_TP_UTXD1_AO (MTK_PIN_NO(112) | 3)
+#define PINMUX_GPIO112__FUNC_IDDIG (MTK_PIN_NO(112) | 4)
+#define PINMUX_GPIO112__FUNC_AGPS_SYNC (MTK_PIN_NO(112) | 5)
+#define PINMUX_GPIO112__FUNC_KPROW2 (MTK_PIN_NO(112) | 6)
+#define PINMUX_GPIO112__FUNC_UTXD1 (MTK_PIN_NO(112) | 7)
+
+#define PINMUX_GPIO113__FUNC_GPIO113 (MTK_PIN_NO(113) | 0)
+#define PINMUX_GPIO113__FUNC_CONN_TOP_CLK (MTK_PIN_NO(113) | 1)
+#define PINMUX_GPIO113__FUNC_SCL6 (MTK_PIN_NO(113) | 3)
+#define PINMUX_GPIO113__FUNC_AUXIF_CLK0 (MTK_PIN_NO(113) | 4)
+#define PINMUX_GPIO113__FUNC_TP_UCTS1_AO (MTK_PIN_NO(113) | 6)
+
+#define PINMUX_GPIO114__FUNC_GPIO114 (MTK_PIN_NO(114) | 0)
+#define PINMUX_GPIO114__FUNC_CONN_TOP_DATA (MTK_PIN_NO(114) | 1)
+#define PINMUX_GPIO114__FUNC_SDA6 (MTK_PIN_NO(114) | 3)
+#define PINMUX_GPIO114__FUNC_AUXIF_ST0 (MTK_PIN_NO(114) | 4)
+#define PINMUX_GPIO114__FUNC_TP_URTS1_AO (MTK_PIN_NO(114) | 6)
+
+#define PINMUX_GPIO115__FUNC_GPIO115 (MTK_PIN_NO(115) | 0)
+#define PINMUX_GPIO115__FUNC_CONN_BT_CLK (MTK_PIN_NO(115) | 1)
+#define PINMUX_GPIO115__FUNC_UTXD1 (MTK_PIN_NO(115) | 2)
+#define PINMUX_GPIO115__FUNC_PTA_TXD (MTK_PIN_NO(115) | 3)
+#define PINMUX_GPIO115__FUNC_AUXIF_CLK1 (MTK_PIN_NO(115) | 4)
+#define PINMUX_GPIO115__FUNC_DAP_MD32_SWD (MTK_PIN_NO(115) | 5)
+#define PINMUX_GPIO115__FUNC_TP_UTXD1_AO (MTK_PIN_NO(115) | 6)
+
+#define PINMUX_GPIO116__FUNC_GPIO116 (MTK_PIN_NO(116) | 0)
+#define PINMUX_GPIO116__FUNC_CONN_BT_DATA (MTK_PIN_NO(116) | 1)
+#define PINMUX_GPIO116__FUNC_IPU_JTAG_TRST (MTK_PIN_NO(116) | 2)
+#define PINMUX_GPIO116__FUNC_AUXIF_ST1 (MTK_PIN_NO(116) | 4)
+#define PINMUX_GPIO116__FUNC_DAP_MD32_SWCK (MTK_PIN_NO(116) | 5)
+#define PINMUX_GPIO116__FUNC_TP_URXD2_AO (MTK_PIN_NO(116) | 6)
+#define PINMUX_GPIO116__FUNC_DBG_MON_A0 (MTK_PIN_NO(116) | 7)
+
+#define PINMUX_GPIO117__FUNC_GPIO117 (MTK_PIN_NO(117) | 0)
+#define PINMUX_GPIO117__FUNC_CONN_WF_HB0 (MTK_PIN_NO(117) | 1)
+#define PINMUX_GPIO117__FUNC_IPU_JTAG_TDO (MTK_PIN_NO(117) | 2)
+#define PINMUX_GPIO117__FUNC_TP_UTXD2_AO (MTK_PIN_NO(117) | 6)
+#define PINMUX_GPIO117__FUNC_DBG_MON_A4 (MTK_PIN_NO(117) | 7)
+
+#define PINMUX_GPIO118__FUNC_GPIO118 (MTK_PIN_NO(118) | 0)
+#define PINMUX_GPIO118__FUNC_CONN_WF_HB1 (MTK_PIN_NO(118) | 1)
+#define PINMUX_GPIO118__FUNC_IPU_JTAG_TDI (MTK_PIN_NO(118) | 2)
+#define PINMUX_GPIO118__FUNC_SSPM_URXD_AO (MTK_PIN_NO(118) | 5)
+#define PINMUX_GPIO118__FUNC_TP_UCTS2_AO (MTK_PIN_NO(118) | 6)
+#define PINMUX_GPIO118__FUNC_DBG_MON_A5 (MTK_PIN_NO(118) | 7)
+
+#define PINMUX_GPIO119__FUNC_GPIO119 (MTK_PIN_NO(119) | 0)
+#define PINMUX_GPIO119__FUNC_CONN_WF_HB2 (MTK_PIN_NO(119) | 1)
+#define PINMUX_GPIO119__FUNC_IPU_JTAG_TCK (MTK_PIN_NO(119) | 2)
+#define PINMUX_GPIO119__FUNC_SSPM_UTXD_AO (MTK_PIN_NO(119) | 5)
+#define PINMUX_GPIO119__FUNC_TP_URTS2_AO (MTK_PIN_NO(119) | 6)
+
+#define PINMUX_GPIO120__FUNC_GPIO120 (MTK_PIN_NO(120) | 0)
+#define PINMUX_GPIO120__FUNC_CONN_WB_PTA (MTK_PIN_NO(120) | 1)
+#define PINMUX_GPIO120__FUNC_IPU_JTAG_TMS (MTK_PIN_NO(120) | 2)
+#define PINMUX_GPIO120__FUNC_CCU_URXD_AO (MTK_PIN_NO(120) | 5)
+
+#define PINMUX_GPIO121__FUNC_GPIO121 (MTK_PIN_NO(121) | 0)
+#define PINMUX_GPIO121__FUNC_CONN_HRST_B (MTK_PIN_NO(121) | 1)
+#define PINMUX_GPIO121__FUNC_URXD1 (MTK_PIN_NO(121) | 2)
+#define PINMUX_GPIO121__FUNC_PTA_RXD (MTK_PIN_NO(121) | 3)
+#define PINMUX_GPIO121__FUNC_CCU_UTXD_AO (MTK_PIN_NO(121) | 5)
+#define PINMUX_GPIO121__FUNC_TP_URXD1_AO (MTK_PIN_NO(121) | 6)
+
+#define PINMUX_GPIO122__FUNC_GPIO122 (MTK_PIN_NO(122) | 0)
+#define PINMUX_GPIO122__FUNC_MSDC0_CMD (MTK_PIN_NO(122) | 1)
+#define PINMUX_GPIO122__FUNC_SSPM_URXD2_AO (MTK_PIN_NO(122) | 2)
+#define PINMUX_GPIO122__FUNC_ANT_SEL1 (MTK_PIN_NO(122) | 3)
+#define PINMUX_GPIO122__FUNC_DBG_MON_A12 (MTK_PIN_NO(122) | 7)
+
+#define PINMUX_GPIO123__FUNC_GPIO123 (MTK_PIN_NO(123) | 0)
+#define PINMUX_GPIO123__FUNC_MSDC0_DAT0 (MTK_PIN_NO(123) | 1)
+#define PINMUX_GPIO123__FUNC_ANT_SEL0 (MTK_PIN_NO(123) | 3)
+#define PINMUX_GPIO123__FUNC_DBG_MON_A13 (MTK_PIN_NO(123) | 7)
+
+#define PINMUX_GPIO124__FUNC_GPIO124 (MTK_PIN_NO(124) | 0)
+#define PINMUX_GPIO124__FUNC_MSDC0_CLK (MTK_PIN_NO(124) | 1)
+#define PINMUX_GPIO124__FUNC_DBG_MON_A14 (MTK_PIN_NO(124) | 7)
+
+#define PINMUX_GPIO125__FUNC_GPIO125 (MTK_PIN_NO(125) | 0)
+#define PINMUX_GPIO125__FUNC_MSDC0_DAT2 (MTK_PIN_NO(125) | 1)
+#define PINMUX_GPIO125__FUNC_MRG_CLK (MTK_PIN_NO(125) | 3)
+#define PINMUX_GPIO125__FUNC_DBG_MON_A15 (MTK_PIN_NO(125) | 7)
+
+#define PINMUX_GPIO126__FUNC_GPIO126 (MTK_PIN_NO(126) | 0)
+#define PINMUX_GPIO126__FUNC_MSDC0_DAT4 (MTK_PIN_NO(126) | 1)
+#define PINMUX_GPIO126__FUNC_ANT_SEL5 (MTK_PIN_NO(126) | 3)
+#define PINMUX_GPIO126__FUNC_UFS_MPHY_SCL (MTK_PIN_NO(126) | 6)
+#define PINMUX_GPIO126__FUNC_DBG_MON_A16 (MTK_PIN_NO(126) | 7)
+
+#define PINMUX_GPIO127__FUNC_GPIO127 (MTK_PIN_NO(127) | 0)
+#define PINMUX_GPIO127__FUNC_MSDC0_DAT6 (MTK_PIN_NO(127) | 1)
+#define PINMUX_GPIO127__FUNC_ANT_SEL4 (MTK_PIN_NO(127) | 3)
+#define PINMUX_GPIO127__FUNC_UFS_MPHY_SDA (MTK_PIN_NO(127) | 6)
+#define PINMUX_GPIO127__FUNC_DBG_MON_A17 (MTK_PIN_NO(127) | 7)
+
+#define PINMUX_GPIO128__FUNC_GPIO128 (MTK_PIN_NO(128) | 0)
+#define PINMUX_GPIO128__FUNC_MSDC0_DAT1 (MTK_PIN_NO(128) | 1)
+#define PINMUX_GPIO128__FUNC_ANT_SEL2 (MTK_PIN_NO(128) | 3)
+#define PINMUX_GPIO128__FUNC_UFS_UNIPRO_SDA (MTK_PIN_NO(128) | 6)
+#define PINMUX_GPIO128__FUNC_DBG_MON_A18 (MTK_PIN_NO(128) | 7)
+
+#define PINMUX_GPIO129__FUNC_GPIO129 (MTK_PIN_NO(129) | 0)
+#define PINMUX_GPIO129__FUNC_MSDC0_DAT5 (MTK_PIN_NO(129) | 1)
+#define PINMUX_GPIO129__FUNC_ANT_SEL3 (MTK_PIN_NO(129) | 3)
+#define PINMUX_GPIO129__FUNC_UFS_UNIPRO_SCL (MTK_PIN_NO(129) | 6)
+#define PINMUX_GPIO129__FUNC_DBG_MON_A23 (MTK_PIN_NO(129) | 7)
+
+#define PINMUX_GPIO130__FUNC_GPIO130 (MTK_PIN_NO(130) | 0)
+#define PINMUX_GPIO130__FUNC_MSDC0_DAT7 (MTK_PIN_NO(130) | 1)
+#define PINMUX_GPIO130__FUNC_MRG_DO (MTK_PIN_NO(130) | 3)
+#define PINMUX_GPIO130__FUNC_DBG_MON_A24 (MTK_PIN_NO(130) | 7)
+
+#define PINMUX_GPIO131__FUNC_GPIO131 (MTK_PIN_NO(131) | 0)
+#define PINMUX_GPIO131__FUNC_MSDC0_DSL (MTK_PIN_NO(131) | 1)
+#define PINMUX_GPIO131__FUNC_MRG_SYNC (MTK_PIN_NO(131) | 3)
+#define PINMUX_GPIO131__FUNC_DBG_MON_A25 (MTK_PIN_NO(131) | 7)
+
+#define PINMUX_GPIO132__FUNC_GPIO132 (MTK_PIN_NO(132) | 0)
+#define PINMUX_GPIO132__FUNC_MSDC0_DAT3 (MTK_PIN_NO(132) | 1)
+#define PINMUX_GPIO132__FUNC_MRG_DI (MTK_PIN_NO(132) | 3)
+#define PINMUX_GPIO132__FUNC_DBG_MON_A26 (MTK_PIN_NO(132) | 7)
+
+#define PINMUX_GPIO133__FUNC_GPIO133 (MTK_PIN_NO(133) | 0)
+#define PINMUX_GPIO133__FUNC_MSDC0_RSTB (MTK_PIN_NO(133) | 1)
+#define PINMUX_GPIO133__FUNC_AGPS_SYNC (MTK_PIN_NO(133) | 3)
+#define PINMUX_GPIO133__FUNC_DBG_MON_A27 (MTK_PIN_NO(133) | 7)
+
+#define PINMUX_GPIO134__FUNC_GPIO134 (MTK_PIN_NO(134) | 0)
+#define PINMUX_GPIO134__FUNC_RTC32K_CK (MTK_PIN_NO(134) | 1)
+
+#define PINMUX_GPIO135__FUNC_GPIO135 (MTK_PIN_NO(135) | 0)
+#define PINMUX_GPIO135__FUNC_WATCHDOG (MTK_PIN_NO(135) | 1)
+
+#define PINMUX_GPIO136__FUNC_GPIO136 (MTK_PIN_NO(136) | 0)
+#define PINMUX_GPIO136__FUNC_AUD_CLK_MOSI (MTK_PIN_NO(136) | 1)
+#define PINMUX_GPIO136__FUNC_AUD_CLK_MISO (MTK_PIN_NO(136) | 2)
+#define PINMUX_GPIO136__FUNC_I2S1_MCK (MTK_PIN_NO(136) | 3)
+#define PINMUX_GPIO136__FUNC_UFS_UNIPRO_SCL (MTK_PIN_NO(136) | 6)
+
+#define PINMUX_GPIO137__FUNC_GPIO137 (MTK_PIN_NO(137) | 0)
+#define PINMUX_GPIO137__FUNC_AUD_SYNC_MOSI (MTK_PIN_NO(137) | 1)
+#define PINMUX_GPIO137__FUNC_AUD_SYNC_MISO (MTK_PIN_NO(137) | 2)
+#define PINMUX_GPIO137__FUNC_I2S1_BCK (MTK_PIN_NO(137) | 3)
+
+#define PINMUX_GPIO138__FUNC_GPIO138 (MTK_PIN_NO(138) | 0)
+#define PINMUX_GPIO138__FUNC_AUD_DAT_MOSI0 (MTK_PIN_NO(138) | 1)
+#define PINMUX_GPIO138__FUNC_AUD_DAT_MISO0 (MTK_PIN_NO(138) | 2)
+#define PINMUX_GPIO138__FUNC_I2S1_LRCK (MTK_PIN_NO(138) | 3)
+#define PINMUX_GPIO138__FUNC_DBG_MON_B24 (MTK_PIN_NO(138) | 7)
+
+#define PINMUX_GPIO139__FUNC_GPIO139 (MTK_PIN_NO(139) | 0)
+#define PINMUX_GPIO139__FUNC_AUD_DAT_MOSI1 (MTK_PIN_NO(139) | 1)
+#define PINMUX_GPIO139__FUNC_AUD_DAT_MISO1 (MTK_PIN_NO(139) | 2)
+#define PINMUX_GPIO139__FUNC_I2S1_DO (MTK_PIN_NO(139) | 3)
+#define PINMUX_GPIO139__FUNC_UFS_MPHY_SDA (MTK_PIN_NO(139) | 6)
+
+#define PINMUX_GPIO140__FUNC_GPIO140 (MTK_PIN_NO(140) | 0)
+#define PINMUX_GPIO140__FUNC_AUD_CLK_MISO (MTK_PIN_NO(140) | 1)
+#define PINMUX_GPIO140__FUNC_AUD_CLK_MOSI (MTK_PIN_NO(140) | 2)
+#define PINMUX_GPIO140__FUNC_I2S0_MCK (MTK_PIN_NO(140) | 3)
+#define PINMUX_GPIO140__FUNC_UFS_UNIPRO_SDA (MTK_PIN_NO(140) | 6)
+
+#define PINMUX_GPIO141__FUNC_GPIO141 (MTK_PIN_NO(141) | 0)
+#define PINMUX_GPIO141__FUNC_AUD_SYNC_MISO (MTK_PIN_NO(141) | 1)
+#define PINMUX_GPIO141__FUNC_AUD_SYNC_MOSI (MTK_PIN_NO(141) | 2)
+#define PINMUX_GPIO141__FUNC_I2S0_BCK (MTK_PIN_NO(141) | 3)
+
+#define PINMUX_GPIO142__FUNC_GPIO142 (MTK_PIN_NO(142) | 0)
+#define PINMUX_GPIO142__FUNC_AUD_DAT_MISO0 (MTK_PIN_NO(142) | 1)
+#define PINMUX_GPIO142__FUNC_AUD_DAT_MOSI0 (MTK_PIN_NO(142) | 2)
+#define PINMUX_GPIO142__FUNC_I2S0_LRCK (MTK_PIN_NO(142) | 3)
+#define PINMUX_GPIO142__FUNC_VOW_DAT_MISO (MTK_PIN_NO(142) | 4)
+#define PINMUX_GPIO142__FUNC_DBG_MON_B25 (MTK_PIN_NO(142) | 7)
+
+#define PINMUX_GPIO143__FUNC_GPIO143 (MTK_PIN_NO(143) | 0)
+#define PINMUX_GPIO143__FUNC_AUD_DAT_MISO1 (MTK_PIN_NO(143) | 1)
+#define PINMUX_GPIO143__FUNC_AUD_DAT_MOSI1 (MTK_PIN_NO(143) | 2)
+#define PINMUX_GPIO143__FUNC_I2S0_DI (MTK_PIN_NO(143) | 3)
+#define PINMUX_GPIO143__FUNC_VOW_CLK_MISO (MTK_PIN_NO(143) | 4)
+#define PINMUX_GPIO143__FUNC_UFS_MPHY_SCL (MTK_PIN_NO(143) | 6)
+#define PINMUX_GPIO143__FUNC_DBG_MON_B26 (MTK_PIN_NO(143) | 7)
+
+#define PINMUX_GPIO144__FUNC_GPIO144 (MTK_PIN_NO(144) | 0)
+#define PINMUX_GPIO144__FUNC_PWRAP_SPI0_MI (MTK_PIN_NO(144) | 1)
+#define PINMUX_GPIO144__FUNC_PWRAP_SPI0_MO (MTK_PIN_NO(144) | 2)
+
+#define PINMUX_GPIO145__FUNC_GPIO145 (MTK_PIN_NO(145) | 0)
+#define PINMUX_GPIO145__FUNC_PWRAP_SPI0_CSN (MTK_PIN_NO(145) | 1)
+
+#define PINMUX_GPIO146__FUNC_GPIO146 (MTK_PIN_NO(146) | 0)
+#define PINMUX_GPIO146__FUNC_PWRAP_SPI0_MO (MTK_PIN_NO(146) | 1)
+#define PINMUX_GPIO146__FUNC_PWRAP_SPI0_MI (MTK_PIN_NO(146) | 2)
+
+#define PINMUX_GPIO147__FUNC_GPIO147 (MTK_PIN_NO(147) | 0)
+#define PINMUX_GPIO147__FUNC_PWRAP_SPI0_CK (MTK_PIN_NO(147) | 1)
+
+#define PINMUX_GPIO148__FUNC_GPIO148 (MTK_PIN_NO(148) | 0)
+#define PINMUX_GPIO148__FUNC_SRCLKENA0 (MTK_PIN_NO(148) | 1)
+
+#define PINMUX_GPIO149__FUNC_GPIO149 (MTK_PIN_NO(149) | 0)
+#define PINMUX_GPIO149__FUNC_SRCLKENA1 (MTK_PIN_NO(149) | 1)
+
+#define PINMUX_GPIO150__FUNC_GPIO150 (MTK_PIN_NO(150) | 0)
+#define PINMUX_GPIO150__FUNC_PWM_A (MTK_PIN_NO(150) | 1)
+#define PINMUX_GPIO150__FUNC_CMFLASH (MTK_PIN_NO(150) | 2)
+#define PINMUX_GPIO150__FUNC_CLKM0 (MTK_PIN_NO(150) | 3)
+#define PINMUX_GPIO150__FUNC_DBG_MON_B30 (MTK_PIN_NO(150) | 7)
+
+#define PINMUX_GPIO151__FUNC_GPIO151 (MTK_PIN_NO(151) | 0)
+#define PINMUX_GPIO151__FUNC_PWM_B (MTK_PIN_NO(151) | 1)
+#define PINMUX_GPIO151__FUNC_CMVREF0 (MTK_PIN_NO(151) | 2)
+#define PINMUX_GPIO151__FUNC_CLKM1 (MTK_PIN_NO(151) | 3)
+#define PINMUX_GPIO151__FUNC_DBG_MON_B20 (MTK_PIN_NO(151) | 7)
+
+#define PINMUX_GPIO152__FUNC_GPIO152 (MTK_PIN_NO(152) | 0)
+#define PINMUX_GPIO152__FUNC_PWM_C (MTK_PIN_NO(152) | 1)
+#define PINMUX_GPIO152__FUNC_CMFLASH (MTK_PIN_NO(152) | 2)
+#define PINMUX_GPIO152__FUNC_CLKM2 (MTK_PIN_NO(152) | 3)
+#define PINMUX_GPIO152__FUNC_DBG_MON_B21 (MTK_PIN_NO(152) | 7)
+
+#define PINMUX_GPIO153__FUNC_GPIO153 (MTK_PIN_NO(153) | 0)
+#define PINMUX_GPIO153__FUNC_PWM_A (MTK_PIN_NO(153) | 1)
+#define PINMUX_GPIO153__FUNC_CMVREF0 (MTK_PIN_NO(153) | 2)
+#define PINMUX_GPIO153__FUNC_CLKM3 (MTK_PIN_NO(153) | 3)
+#define PINMUX_GPIO153__FUNC_DBG_MON_B22 (MTK_PIN_NO(153) | 7)
+
+#define PINMUX_GPIO154__FUNC_GPIO154 (MTK_PIN_NO(154) | 0)
+#define PINMUX_GPIO154__FUNC_SCP_VREQ_VAO (MTK_PIN_NO(154) | 1)
+#define PINMUX_GPIO154__FUNC_DVFSRC_EXT_REQ (MTK_PIN_NO(154) | 2)
+#define PINMUX_GPIO154__FUNC_DBG_MON_B18 (MTK_PIN_NO(154) | 7)
+
+#define PINMUX_GPIO155__FUNC_GPIO155 (MTK_PIN_NO(155) | 0)
+#define PINMUX_GPIO155__FUNC_ANT_SEL0 (MTK_PIN_NO(155) | 1)
+#define PINMUX_GPIO155__FUNC_DVFSRC_EXT_REQ (MTK_PIN_NO(155) | 2)
+#define PINMUX_GPIO155__FUNC_CMVREF1 (MTK_PIN_NO(155) | 3)
+#define PINMUX_GPIO155__FUNC_SCP_JTAG_TDI (MTK_PIN_NO(155) | 7)
+
+#define PINMUX_GPIO156__FUNC_GPIO156 (MTK_PIN_NO(156) | 0)
+#define PINMUX_GPIO156__FUNC_ANT_SEL1 (MTK_PIN_NO(156) | 1)
+#define PINMUX_GPIO156__FUNC_SRCLKENAI0 (MTK_PIN_NO(156) | 2)
+#define PINMUX_GPIO156__FUNC_SCL6 (MTK_PIN_NO(156) | 3)
+#define PINMUX_GPIO156__FUNC_KPCOL2 (MTK_PIN_NO(156) | 4)
+#define PINMUX_GPIO156__FUNC_IDDIG (MTK_PIN_NO(156) | 5)
+#define PINMUX_GPIO156__FUNC_SCP_JTAG_TCK (MTK_PIN_NO(156) | 7)
+
+#define PINMUX_GPIO157__FUNC_GPIO157 (MTK_PIN_NO(157) | 0)
+#define PINMUX_GPIO157__FUNC_ANT_SEL2 (MTK_PIN_NO(157) | 1)
+#define PINMUX_GPIO157__FUNC_SRCLKENAI1 (MTK_PIN_NO(157) | 2)
+#define PINMUX_GPIO157__FUNC_SDA6 (MTK_PIN_NO(157) | 3)
+#define PINMUX_GPIO157__FUNC_KPROW2 (MTK_PIN_NO(157) | 4)
+#define PINMUX_GPIO157__FUNC_USB_DRVVBUS (MTK_PIN_NO(157) | 5)
+#define PINMUX_GPIO157__FUNC_SCP_JTAG_TRSTN (MTK_PIN_NO(157) | 7)
+
+#define PINMUX_GPIO158__FUNC_GPIO158 (MTK_PIN_NO(158) | 0)
+#define PINMUX_GPIO158__FUNC_ANT_SEL3 (MTK_PIN_NO(158) | 1)
+
+#define PINMUX_GPIO159__FUNC_GPIO159 (MTK_PIN_NO(159) | 0)
+#define PINMUX_GPIO159__FUNC_ANT_SEL4 (MTK_PIN_NO(159) | 1)
+
+#define PINMUX_GPIO160__FUNC_GPIO160 (MTK_PIN_NO(160) | 0)
+#define PINMUX_GPIO160__FUNC_ANT_SEL5 (MTK_PIN_NO(160) | 1)
+
+#define PINMUX_GPIO161__FUNC_GPIO161 (MTK_PIN_NO(161) | 0)
+#define PINMUX_GPIO161__FUNC_SPI1_A_MI (MTK_PIN_NO(161) | 1)
+#define PINMUX_GPIO161__FUNC_SCP_SPI1_MI (MTK_PIN_NO(161) | 2)
+#define PINMUX_GPIO161__FUNC_IDDIG (MTK_PIN_NO(161) | 3)
+#define PINMUX_GPIO161__FUNC_ANT_SEL6 (MTK_PIN_NO(161) | 4)
+#define PINMUX_GPIO161__FUNC_KPCOL2 (MTK_PIN_NO(161) | 5)
+#define PINMUX_GPIO161__FUNC_PTA_RXD (MTK_PIN_NO(161) | 6)
+#define PINMUX_GPIO161__FUNC_DBG_MON_B19 (MTK_PIN_NO(161) | 7)
+
+#define PINMUX_GPIO162__FUNC_GPIO162 (MTK_PIN_NO(162) | 0)
+#define PINMUX_GPIO162__FUNC_SPI1_A_CSB (MTK_PIN_NO(162) | 1)
+#define PINMUX_GPIO162__FUNC_SCP_SPI1_CS (MTK_PIN_NO(162) | 2)
+#define PINMUX_GPIO162__FUNC_USB_DRVVBUS (MTK_PIN_NO(162) | 3)
+#define PINMUX_GPIO162__FUNC_ANT_SEL5 (MTK_PIN_NO(162) | 4)
+#define PINMUX_GPIO162__FUNC_KPROW2 (MTK_PIN_NO(162) | 5)
+#define PINMUX_GPIO162__FUNC_PTA_TXD (MTK_PIN_NO(162) | 6)
+
+#define PINMUX_GPIO163__FUNC_GPIO163 (MTK_PIN_NO(163) | 0)
+#define PINMUX_GPIO163__FUNC_SPI1_A_MO (MTK_PIN_NO(163) | 1)
+#define PINMUX_GPIO163__FUNC_SCP_SPI1_MO (MTK_PIN_NO(163) | 2)
+#define PINMUX_GPIO163__FUNC_SDA1 (MTK_PIN_NO(163) | 3)
+#define PINMUX_GPIO163__FUNC_ANT_SEL4 (MTK_PIN_NO(163) | 4)
+#define PINMUX_GPIO163__FUNC_CMMCLK2 (MTK_PIN_NO(163) | 5)
+#define PINMUX_GPIO163__FUNC_DMIC_CLK (MTK_PIN_NO(163) | 6)
+
+#define PINMUX_GPIO164__FUNC_GPIO164 (MTK_PIN_NO(164) | 0)
+#define PINMUX_GPIO164__FUNC_SPI1_A_CLK (MTK_PIN_NO(164) | 1)
+#define PINMUX_GPIO164__FUNC_SCP_SPI1_CK (MTK_PIN_NO(164) | 2)
+#define PINMUX_GPIO164__FUNC_SCL1 (MTK_PIN_NO(164) | 3)
+#define PINMUX_GPIO164__FUNC_ANT_SEL3 (MTK_PIN_NO(164) | 4)
+#define PINMUX_GPIO164__FUNC_CMMCLK3 (MTK_PIN_NO(164) | 5)
+#define PINMUX_GPIO164__FUNC_DMIC_DAT (MTK_PIN_NO(164) | 6)
+
+#define PINMUX_GPIO165__FUNC_GPIO165 (MTK_PIN_NO(165) | 0)
+#define PINMUX_GPIO165__FUNC_PWM_B (MTK_PIN_NO(165) | 1)
+#define PINMUX_GPIO165__FUNC_CMMCLK2 (MTK_PIN_NO(165) | 2)
+#define PINMUX_GPIO165__FUNC_SCP_VREQ_VAO (MTK_PIN_NO(165) | 3)
+#define PINMUX_GPIO165__FUNC_TDM_MCK_2ND (MTK_PIN_NO(165) | 6)
+#define PINMUX_GPIO165__FUNC_SCP_JTAG_TDO (MTK_PIN_NO(165) | 7)
+
+#define PINMUX_GPIO166__FUNC_GPIO166 (MTK_PIN_NO(166) | 0)
+#define PINMUX_GPIO166__FUNC_ANT_SEL6 (MTK_PIN_NO(166) | 1)
+
+#define PINMUX_GPIO167__FUNC_GPIO167 (MTK_PIN_NO(167) | 0)
+#define PINMUX_GPIO167__FUNC_RFIC0_BSI_EN (MTK_PIN_NO(167) | 1)
+#define PINMUX_GPIO167__FUNC_SPM_BSI_EN (MTK_PIN_NO(167) | 2)
+
+#define PINMUX_GPIO168__FUNC_GPIO168 (MTK_PIN_NO(168) | 0)
+#define PINMUX_GPIO168__FUNC_RFIC0_BSI_CK (MTK_PIN_NO(168) | 1)
+#define PINMUX_GPIO168__FUNC_SPM_BSI_CK (MTK_PIN_NO(168) | 2)
+
+#define PINMUX_GPIO169__FUNC_GPIO169 (MTK_PIN_NO(169) | 0)
+#define PINMUX_GPIO169__FUNC_PWM_C (MTK_PIN_NO(169) | 1)
+#define PINMUX_GPIO169__FUNC_CMMCLK3 (MTK_PIN_NO(169) | 2)
+#define PINMUX_GPIO169__FUNC_CMVREF1 (MTK_PIN_NO(169) | 3)
+#define PINMUX_GPIO169__FUNC_ANT_SEL7 (MTK_PIN_NO(169) | 4)
+#define PINMUX_GPIO169__FUNC_AGPS_SYNC (MTK_PIN_NO(169) | 5)
+#define PINMUX_GPIO169__FUNC_TDM_BCK_2ND (MTK_PIN_NO(169) | 6)
+#define PINMUX_GPIO169__FUNC_SCP_JTAG_TMS (MTK_PIN_NO(169) | 7)
+
+#define PINMUX_GPIO170__FUNC_GPIO170 (MTK_PIN_NO(170) | 0)
+#define PINMUX_GPIO170__FUNC_I2S1_BCK (MTK_PIN_NO(170) | 1)
+#define PINMUX_GPIO170__FUNC_I2S3_BCK (MTK_PIN_NO(170) | 2)
+#define PINMUX_GPIO170__FUNC_SCL7 (MTK_PIN_NO(170) | 3)
+#define PINMUX_GPIO170__FUNC_I2S5_BCK (MTK_PIN_NO(170) | 4)
+#define PINMUX_GPIO170__FUNC_EXT_FRAME_SYNC (MTK_PIN_NO(170) | 5)
+#define PINMUX_GPIO170__FUNC_TDM_LRCK_2ND (MTK_PIN_NO(170) | 6)
+#define PINMUX_GPIO170__FUNC_ANT_SEL3 (MTK_PIN_NO(170) | 7)
+
+#define PINMUX_GPIO171__FUNC_GPIO171 (MTK_PIN_NO(171) | 0)
+#define PINMUX_GPIO171__FUNC_I2S1_LRCK (MTK_PIN_NO(171) | 1)
+#define PINMUX_GPIO171__FUNC_I2S3_LRCK (MTK_PIN_NO(171) | 2)
+#define PINMUX_GPIO171__FUNC_SDA7 (MTK_PIN_NO(171) | 3)
+#define PINMUX_GPIO171__FUNC_I2S5_LRCK (MTK_PIN_NO(171) | 4)
+#define PINMUX_GPIO171__FUNC_URXD1 (MTK_PIN_NO(171) | 5)
+#define PINMUX_GPIO171__FUNC_TDM_DATA0_2ND (MTK_PIN_NO(171) | 6)
+#define PINMUX_GPIO171__FUNC_ANT_SEL4 (MTK_PIN_NO(171) | 7)
+
+#define PINMUX_GPIO172__FUNC_GPIO172 (MTK_PIN_NO(172) | 0)
+#define PINMUX_GPIO172__FUNC_I2S1_DO (MTK_PIN_NO(172) | 1)
+#define PINMUX_GPIO172__FUNC_I2S3_DO (MTK_PIN_NO(172) | 2)
+#define PINMUX_GPIO172__FUNC_SCL8 (MTK_PIN_NO(172) | 3)
+#define PINMUX_GPIO172__FUNC_I2S5_DO (MTK_PIN_NO(172) | 4)
+#define PINMUX_GPIO172__FUNC_UTXD1 (MTK_PIN_NO(172) | 5)
+#define PINMUX_GPIO172__FUNC_TDM_DATA1_2ND (MTK_PIN_NO(172) | 6)
+#define PINMUX_GPIO172__FUNC_ANT_SEL5 (MTK_PIN_NO(172) | 7)
+
+#define PINMUX_GPIO173__FUNC_GPIO173 (MTK_PIN_NO(173) | 0)
+#define PINMUX_GPIO173__FUNC_I2S1_MCK (MTK_PIN_NO(173) | 1)
+#define PINMUX_GPIO173__FUNC_I2S3_MCK (MTK_PIN_NO(173) | 2)
+#define PINMUX_GPIO173__FUNC_SDA8 (MTK_PIN_NO(173) | 3)
+#define PINMUX_GPIO173__FUNC_I2S5_MCK (MTK_PIN_NO(173) | 4)
+#define PINMUX_GPIO173__FUNC_UCTS0 (MTK_PIN_NO(173) | 5)
+#define PINMUX_GPIO173__FUNC_TDM_DATA2_2ND (MTK_PIN_NO(173) | 6)
+#define PINMUX_GPIO173__FUNC_ANT_SEL6 (MTK_PIN_NO(173) | 7)
+
+#define PINMUX_GPIO174__FUNC_GPIO174 (MTK_PIN_NO(174) | 0)
+#define PINMUX_GPIO174__FUNC_I2S2_DI (MTK_PIN_NO(174) | 1)
+#define PINMUX_GPIO174__FUNC_I2S0_DI (MTK_PIN_NO(174) | 2)
+#define PINMUX_GPIO174__FUNC_DVFSRC_EXT_REQ (MTK_PIN_NO(174) | 3)
+#define PINMUX_GPIO174__FUNC_I2S2_DI2 (MTK_PIN_NO(174) | 4)
+#define PINMUX_GPIO174__FUNC_URTS0 (MTK_PIN_NO(174) | 5)
+#define PINMUX_GPIO174__FUNC_TDM_DATA3_2ND (MTK_PIN_NO(174) | 6)
+#define PINMUX_GPIO174__FUNC_ANT_SEL7 (MTK_PIN_NO(174) | 7)
+
+#define PINMUX_GPIO175__FUNC_GPIO175 (MTK_PIN_NO(175) | 0)
+#define PINMUX_GPIO175__FUNC_ANT_SEL7 (MTK_PIN_NO(175) | 1)
+
+#define PINMUX_GPIO176__FUNC_GPIO176 (MTK_PIN_NO(176) | 0)
+
+#define PINMUX_GPIO177__FUNC_GPIO177 (MTK_PIN_NO(177) | 0)
+
+#define PINMUX_GPIO178__FUNC_GPIO178 (MTK_PIN_NO(178) | 0)
+
+#define PINMUX_GPIO179__FUNC_GPIO179 (MTK_PIN_NO(179) | 0)
+
+#endif /* __MT8183-PINFUNC_H */
index 6b8ab556848107edbcc8fbeeb0e66a83d65d8bd1..bcd018c3162b19b4bc98c62313e17010ccd2db56 100644 (file)
@@ -3,6 +3,7 @@ dtb-$(CONFIG_ARCH_TEGRA_132_SOC) += tegra132-norrin.dtb
 dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210-p2371-0000.dtb
 dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210-p2371-2180.dtb
 dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210-p2571.dtb
+dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210-p3450-0000.dtb
 dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210-smaug.dtb
 dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210-p2894-0050-a08.dtb
 dtb-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186-p2771-0000.dtb
index 31457f32e4d08aaafffabf15bc17520070af3090..75ee6cf1e1b4ceafca6eb67905a3de08791d3d31 100644 (file)
                status = "okay";
        };
 
+       padctl@3520000 {
+               status = "okay";
+
+               avdd-pll-erefeut-supply = <&vdd_1v8_pll>;
+               avdd-usb-supply = <&vdd_3v3_sys>;
+               dvdd-pex-supply = <&vdd_pex>;
+               dvdd-pex-pll-supply = <&vdd_pex>;
+               hvdd-pex-supply = <&vdd_1v8>;
+               hvdd-pex-pll-supply = <&vdd_1v8>;
+               vclamp-usb-supply = <&vdd_1v8>;
+               vddio-hsic-supply = <&gnd>;
+
+               pads {
+                       usb2 {
+                               status = "okay";
+
+                               lanes {
+                                       usb2-0 {
+                                               nvidia,function = "xusb";
+                                               status = "okay";
+                                       };
+
+                                       usb2-1 {
+                                               nvidia,function = "xusb";
+                                               status = "okay";
+                                       };
+
+                                       usb2-2 {
+                                               nvidia,function = "xusb";
+                                               status = "okay";
+                                       };
+                               };
+                       };
+
+                       usb3 {
+                               status = "okay";
+
+                               lanes {
+                                       usb3-0 {
+                                               nvidia,function = "xusb";
+                                               status = "okay";
+                                       };
+
+                                       usb3-1 {
+                                               nvidia,function = "xusb";
+                                               status = "okay";
+                                       };
+
+                                       usb3-2 {
+                                               nvidia,function = "xusb";
+                                               status = "okay";
+                                       };
+                               };
+                       };
+               };
+
+               ports {
+                       usb2-0 {
+                               status = "okay";
+                               mode = "otg";
+
+                               vbus-supply = <&vdd_usb0>;
+                       };
+
+                       usb2-1 {
+                               status = "okay";
+                               mode = "host";
+
+                               vbus-supply = <&vdd_usb1>;
+                       };
+
+                       usb3-0 {
+                               nvidia,usb2-companion = <1>;
+                               status = "okay";
+                       };
+               };
+       };
+
+       usb@3530000 {
+               status = "okay";
+
+               phys = <&{/padctl@3520000/pads/usb2/lanes/usb2-0}>,
+                      <&{/padctl@3520000/pads/usb2/lanes/usb2-1}>,
+                      <&{/padctl@3520000/pads/usb3/lanes/usb3-0}>;
+               phy-names = "usb2-0", "usb2-1", "usb3-0";
+       };
+
        pcie@10003000 {
                status = "okay";
 
 
                        vin-supply = <&vdd_5v0_sys>;
                };
+
+               vdd_usb0: regulator@102 {
+                       compatible = "regulator-fixed";
+                       reg = <102>;
+
+                       regulator-name = "VDD_USB0";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+
+                       gpio = <&gpio TEGRA_MAIN_GPIO(L, 4) GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+
+                       vin-supply = <&vdd_5v0_sys>;
+               };
+
+               vdd_usb1: regulator@103 {
+                       compatible = "regulator-fixed";
+                       reg = <103>;
+
+                       regulator-name = "VDD_USB1";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+
+                       gpio = <&gpio TEGRA_MAIN_GPIO(L, 5) GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+
+                       vin-supply = <&vdd_5v0_sys>;
+               };
        };
 };
index 89a2da46efae8c60b99ddac7a2b74112718ea19c..64686b033c3885902b2cc3d0ce5e61a459ce2fb1 100644 (file)
                                                regulator-name = "AVDD_DSI_CSI_1V2";
                                                regulator-min-microvolt = <1200000>;
                                                regulator-max-microvolt = <1200000>;
-                                               /* XXX */
-                                               regulator-always-on;
-                                               regulator-boot-on;
                                        };
 
                                        vdd_1v8: sd2 {
                                                regulator-name = "VDD_1V8";
                                                regulator-min-microvolt = <1800000>;
                                                regulator-max-microvolt = <1800000>;
-                                               /* XXX */
-                                               regulator-always-on;
-                                               regulator-boot-on;
                                        };
 
                                        vdd_3v3_sys: sd3 {
                                                regulator-name = "VDD_3V3_SYS";
                                                regulator-min-microvolt = <3300000>;
                                                regulator-max-microvolt = <3300000>;
-                                               /* XXX */
-                                               regulator-always-on;
-                                               regulator-boot-on;
                                        };
 
-                                       ldo0 {
+                                       vdd_1v8_pll: ldo0 {
                                                regulator-name = "VDD_1V8_AP_PLL";
                                                regulator-min-microvolt = <1800000>;
                                                regulator-max-microvolt = <1800000>;
-                                               /* XXX */
-                                               regulator-always-on;
-                                               regulator-boot-on;
                                        };
 
                                        ldo2 {
                                                regulator-name = "VDDIO_3V3_AOHV";
                                                regulator-min-microvolt = <3300000>;
                                                regulator-max-microvolt = <3300000>;
-                                               /* XXX */
                                                regulator-always-on;
                                                regulator-boot-on;
                                        };
                                                regulator-name = "VDD_HDMI_1V05";
                                                regulator-min-microvolt = <1050000>;
                                                regulator-max-microvolt = <1050000>;
-                                               /* XXX */
-                                               regulator-always-on;
-                                               regulator-boot-on;
                                        };
 
                                        vdd_pex: ldo8 {
                                                regulator-name = "VDD_PEX_1V05";
                                                regulator-min-microvolt = <1050000>;
                                                regulator-max-microvolt = <1050000>;
-                                               /* XXX */
-                                               regulator-always-on;
-                                               regulator-boot-on;
                                        };
                                };
                        };
                #address-cells = <1>;
                #size-cells = <0>;
 
-               vdd_5v0_sys: regulator@0 {
+               gnd: regulator@0 {
                        compatible = "regulator-fixed";
                        reg = <0>;
 
+                       regulator-name = "GND";
+                       regulator-min-microvolt = <0>;
+                       regulator-max-microvolt = <0>;
+                       regulator-always-on;
+                       regulator-boot-on;
+               };
+
+               vdd_5v0_sys: regulator@1 {
+                       compatible = "regulator-fixed";
+                       reg = <1>;
+
                        regulator-name = "VDD_5V0_SYS";
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
                        regulator-boot-on;
                };
 
-               vdd_1v8_ap: regulator@1 {
+               vdd_1v8_ap: regulator@2 {
                        compatible = "regulator-fixed";
-                       reg = <1>;
+                       reg = <2>;
 
                        regulator-name = "VDD_1V8_AP";
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
 
-                       /* XXX */
-                       regulator-always-on;
-                       regulator-boot-on;
-
                        gpio = <&pmic 1 GPIO_ACTIVE_HIGH>;
                        enable-active-high;
 
index 97aeb946ed5e7473639ec94a498512d48a12ca8b..f0bb6ced49765761293d185e80238a794f18cbb8 100644 (file)
                nvidia,pad-autocal-pull-down-offset-1v8-timeout = <0x0a>;
                nvidia,pad-autocal-pull-up-offset-3v3-timeout = <0x0a>;
                nvidia,pad-autocal-pull-down-offset-3v3-timeout = <0x0a>;
-               nvidia,default-tap = <0x5>;
-               nvidia,default-trim = <0x9>;
+               nvidia,default-tap = <0x9>;
+               nvidia,default-trim = <0x5>;
                nvidia,dqs-trim = <63>;
                mmc-hs400-1_8v;
+               supports-cqe;
                status = "disabled";
        };
 
                status = "disabled";
        };
 
+       padctl: padctl@3520000 {
+               compatible = "nvidia,tegra186-xusb-padctl";
+               reg = <0x0 0x03520000 0x0 0x1000>,
+                     <0x0 0x03540000 0x0 0x1000>;
+               reg-names = "padctl", "ao";
+
+               resets = <&bpmp TEGRA186_RESET_XUSB_PADCTL>;
+               reset-names = "padctl";
+
+               status = "disabled";
+
+               pads {
+                       usb2 {
+                               clocks = <&bpmp TEGRA186_CLK_USB2_TRK>;
+                               clock-names = "trk";
+                               status = "disabled";
+
+                               lanes {
+                                       usb2-0 {
+                                               status = "disabled";
+                                               #phy-cells = <0>;
+                                       };
+
+                                       usb2-1 {
+                                               status = "disabled";
+                                               #phy-cells = <0>;
+                                       };
+
+                                       usb2-2 {
+                                               status = "disabled";
+                                               #phy-cells = <0>;
+                                       };
+                               };
+                       };
+
+                       hsic {
+                               clocks = <&bpmp TEGRA186_CLK_HSIC_TRK>;
+                               clock-names = "trk";
+                               status = "disabled";
+
+                               lanes {
+                                       hsic-0 {
+                                               status = "disabled";
+                                               #phy-cells = <0>;
+                                       };
+                               };
+                       };
+
+                       usb3 {
+                               status = "disabled";
+
+                               lanes {
+                                       usb3-0 {
+                                               status = "disabled";
+                                               #phy-cells = <0>;
+                                       };
+
+                                       usb3-1 {
+                                               status = "disabled";
+                                               #phy-cells = <0>;
+                                       };
+
+                                       usb3-2 {
+                                               status = "disabled";
+                                               #phy-cells = <0>;
+                                       };
+                               };
+                       };
+               };
+
+               ports {
+                       usb2-0 {
+                               status = "disabled";
+                       };
+
+                       usb2-1 {
+                               status = "disabled";
+                       };
+
+                       usb2-2 {
+                               status = "disabled";
+                       };
+
+                       hsic-0 {
+                               status = "disabled";
+                       };
+
+                       usb3-0 {
+                               status = "disabled";
+                       };
+
+                       usb3-1 {
+                               status = "disabled";
+                       };
+
+                       usb3-2 {
+                               status = "disabled";
+                       };
+               };
+       };
+
+       usb@3530000 {
+               compatible = "nvidia,tegra186-xusb";
+               reg = <0x0 0x03530000 0x0 0x8000>,
+                     <0x0 0x03538000 0x0 0x1000>;
+               reg-names = "hcd", "fpci";
+
+               interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
+
+               clocks = <&bpmp TEGRA186_CLK_XUSB_HOST>,
+                        <&bpmp TEGRA186_CLK_XUSB_FALCON>,
+                        <&bpmp TEGRA186_CLK_XUSB_SS>,
+                        <&bpmp TEGRA186_CLK_XUSB_CORE_SS>,
+                        <&bpmp TEGRA186_CLK_CLK_M>,
+                        <&bpmp TEGRA186_CLK_XUSB_FS>,
+                        <&bpmp TEGRA186_CLK_PLLU>,
+                        <&bpmp TEGRA186_CLK_CLK_M>,
+                        <&bpmp TEGRA186_CLK_PLLE>;
+               clock-names = "xusb_host", "xusb_falcon_src", "xusb_ss",
+                             "xusb_ss_src", "xusb_hs_src", "xusb_fs_src",
+                             "pll_u_480m", "clk_m", "pll_e";
+
+               power-domains = <&bpmp TEGRA186_POWER_DOMAIN_XUSBC>,
+                               <&bpmp TEGRA186_POWER_DOMAIN_XUSBA>;
+               power-domain-names = "xusb_host", "xusb_ss";
+               nvidia,xusb-padctl = <&padctl>;
+
+               status = "disabled";
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
        fuse@3820000 {
                compatible = "nvidia,tegra186-efuse";
                reg = <0x0 0x03820000 0x0 0x10000>;
index 246c1ebbd0558450a5723f40361548f097211bbe..0fd5bd29fbf938295301d17b678e77759b89fb61 100644 (file)
                                interrupt-parent = <&gpio>;
                                interrupts = <TEGRA194_MAIN_GPIO(H, 2)
                                              IRQ_TYPE_LEVEL_LOW>;
+                               vcc-supply = <&vdd_1v8ls>;
 
                                #thermal-sensor-cells = <1>;
                        };
index b62e969458464e562cf04099b13455273b6b8183..73801b48d1d8b79209b0d7d924befebb3be6b7fc 100644 (file)
@@ -57,8 +57,6 @@
                pwms = <&pwm4 0 45334>;
 
                cooling-levels = <0 64 128 255>;
-               cooling-min-state = <0>;
-               cooling-max-state = <3>;
                #cooling-cells = <2>;
        };
 
index 053458a5db55bef47ae3223af38eefc00828367a..4dcd0d36189a46d4239c77807595cf8c7e150d16 100644 (file)
                cpu@3 {
                        enable-method = "psci";
                };
+
+               idle-states {
+                       cpu-sleep {
+                               status = "okay";
+                       };
+               };
        };
 
        psci {
index 9fad0d27278e9075cc3ef0d0090f833df96698e2..5a57396b5948924c2364e1ac2be542e1f04348c2 100644 (file)
                pinctrl-0 = <&dvfs_pwm_active_state>;
                pinctrl-1 = <&dvfs_pwm_inactive_state>;
        };
+
+       aconnect@702c0000 {
+               status = "okay";
+
+               dma@702e2000 {
+                       status = "okay";
+               };
+
+               agic@702f9000 {
+                       status = "okay";
+               };
+       };
 };
index 95e890d8a1192ec0f3f546029df15bb1b6c81edf..a7dc319214a4db1bb98d614ac0fa822186846472 100644 (file)
        padctl@7009f000 {
                status = "okay";
 
+               avdd-pll-utmip-supply = <&vdd_1v8>;
+               avdd-pll-uerefe-supply = <&avdd_1v05_pll>;
+               dvdd-pex-pll-supply = <&vdd_pex_1v05>;
+               hvdd-pex-pll-e-supply = <&vdd_1v8>;
+
                pads {
                        usb2 {
                                status = "okay";
index 3ddf173ccc18ed917aaf8fddc145420738a76a15..88a4b9333d84fee4561125e58bc82bfb9b290233 100644 (file)
                cpu@3 {
                        enable-method = "psci";
                };
+
+               idle-states {
+                       cpu-sleep {
+                               status = "okay";
+                       };
+               };
        };
 
        psci {
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
new file mode 100644 (file)
index 0000000..5d01819
--- /dev/null
@@ -0,0 +1,650 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+
+#include <dt-bindings/input/gpio-keys.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/mfd/max77620.h>
+
+#include "tegra210.dtsi"
+
+/ {
+       model = "NVIDIA Jetson Nano Developer Kit";
+       compatible = "nvidia,p3450-0000", "nvidia,tegra210";
+
+       aliases {
+               ethernet = "/pcie@1003000/pci@2,0/ethernet@0,0";
+               rtc0 = "/i2c@7000d000/pmic@3c";
+               rtc1 = "/rtc@7000e000";
+               serial0 = &uarta;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x0 0x80000000 0x1 0x0>;
+       };
+
+       pcie@1003000 {
+               status = "okay";
+
+               avdd-pll-uerefe-supply = <&vdd_pex_1v05>;
+               hvddio-pex-supply = <&vdd_1v8>;
+               dvddio-pex-supply = <&vdd_pex_1v05>;
+               dvdd-pex-pll-supply = <&vdd_pex_1v05>;
+               hvdd-pex-pll-e-supply = <&vdd_1v8>;
+               vddio-pex-ctl-supply = <&vdd_1v8>;
+
+               pci@1,0 {
+                       phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-1}>,
+                              <&{/padctl@7009f000/pads/pcie/lanes/pcie-2}>,
+                              <&{/padctl@7009f000/pads/pcie/lanes/pcie-3}>,
+                              <&{/padctl@7009f000/pads/pcie/lanes/pcie-4}>;
+                       phy-names = "pcie-0", "pcie-1", "pcie-2", "pcie-3";
+                       nvidia,num-lanes = <4>;
+                       status = "okay";
+               };
+
+               pci@2,0 {
+                       phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-0}>;
+                       phy-names = "pcie-0";
+                       status = "okay";
+
+                       ethernet@0,0 {
+                               reg = <0x000000 0 0 0 0>;
+                               local-mac-address = [ 00 00 00 00 00 00 ];
+                       };
+               };
+       };
+
+       host1x@50000000 {
+               dpaux@54040000 {
+                       status = "okay";
+               };
+
+               sor@54580000 {
+                       status = "okay";
+
+                       avdd-io-supply = <&avdd_1v05>;
+                       vdd-pll-supply = <&vdd_1v8>;
+                       hdmi-supply = <&vdd_hdmi>;
+
+                       nvidia,ddc-i2c-bus = <&hdmi_ddc>;
+                       nvidia,hpd-gpio = <&gpio TEGRA_GPIO(CC, 1)
+                                          GPIO_ACTIVE_LOW>;
+                       nvidia,xbar-cfg = <0 1 2 3 4>;
+               };
+       };
+
+       gpu@57000000 {
+               vdd-supply = <&vdd_gpu>;
+               status = "okay";
+       };
+
+       /* debug port */
+       serial@70006000 {
+               status = "okay";
+       };
+
+       hdmi_ddc: i2c@7000c700 {
+               status = "okay";
+               clock-frequency = <100000>;
+       };
+
+       i2c@7000d000 {
+               status = "okay";
+               clock-frequency = <400000>;
+
+               pmic: pmic@3c {
+                       compatible = "maxim,max77620";
+                       reg = <0x3c>;
+                       interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+
+                       #gpio-cells = <2>;
+                       gpio-controller;
+
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&max77620_default>;
+
+                       max77620_default: pinmux {
+                               gpio0 {
+                                       pins = "gpio0";
+                                       function = "gpio";
+                               };
+
+                               gpio1 {
+                                       pins = "gpio1";
+                                       function = "fps-out";
+                                       drive-push-pull = <1>;
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
+                                       maxim,active-fps-power-up-slot = <0>;
+                                       maxim,active-fps-power-down-slot = <7>;
+                               };
+
+                               gpio2 {
+                                       pins = "gpio2";
+                                       function = "fps-out";
+                                       drive-open-drain = <1>;
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
+                                       maxim,active-fps-power-up-slot = <0>;
+                                       maxim,active-fps-power-down-slot = <7>;
+                               };
+
+                               gpio3 {
+                                       pins = "gpio3";
+                                       function = "fps-out";
+                                       drive-open-drain = <1>;
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
+                                       maxim,active-fps-power-up-slot = <4>;
+                                       maxim,active-fps-power-down-slot = <3>;
+                               };
+
+                               gpio4 {
+                                       pins = "gpio4";
+                                       function = "32k-out1";
+                               };
+
+                               gpio5_6_7 {
+                                       pins = "gpio5", "gpio6", "gpio7";
+                                       function = "gpio";
+                                       drive-push-pull = <1>;
+                               };
+                       };
+
+                       fps {
+                               fps0 {
+                                       maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_EN0>;
+                                       maxim,suspend-fps-time-period-us = <5120>;
+                               };
+
+                               fps1 {
+                                       maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_EN1>;
+                                       maxim,suspend-fps-time-period-us = <5120>;
+                               };
+
+                               fps2 {
+                                       maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_EN0>;
+                               };
+                       };
+
+                       regulators {
+                               in-ldo0-1-supply = <&vdd_pre>;
+                               in-ldo2-supply = <&vdd_3v3_sys>;
+                               in-ldo3-5-supply = <&vdd_1v8>;
+                               in-ldo4-6-supply = <&vdd_5v0_sys>;
+                               in-ldo7-8-supply = <&vdd_pre>;
+                               in-sd0-supply = <&vdd_5v0_sys>;
+                               in-sd1-supply = <&vdd_5v0_sys>;
+                               in-sd2-supply = <&vdd_5v0_sys>;
+                               in-sd3-supply = <&vdd_5v0_sys>;
+
+                               vdd_soc: sd0 {
+                                       regulator-name = "VDD_SOC";
+                                       regulator-min-microvolt = <1000000>;
+                                       regulator-max-microvolt = <1170000>;
+                                       regulator-enable-ramp-delay = <146>;
+                                       regulator-disable-ramp-delay = <4080>;
+                                       regulator-ramp-delay = <27500>;
+                                       regulator-ramp-delay-scale = <300>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_1>;
+                                       maxim,active-fps-power-up-slot = <1>;
+                                       maxim,active-fps-power-down-slot = <6>;
+                               };
+
+                               vdd_ddr: sd1 {
+                                       regulator-name = "VDD_DDR_1V1_PMIC";
+                                       regulator-min-microvolt = <1150000>;
+                                       regulator-max-microvolt = <1150000>;
+                                       regulator-enable-ramp-delay = <176>;
+                                       regulator-disable-ramp-delay = <145800>;
+                                       regulator-ramp-delay = <27500>;
+                                       regulator-ramp-delay-scale = <300>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
+                                       maxim,active-fps-power-up-slot = <5>;
+                                       maxim,active-fps-power-down-slot = <2>;
+                               };
+
+                               vdd_pre: sd2 {
+                                       regulator-name = "VDD_PRE_REG_1V35";
+                                       regulator-min-microvolt = <1350000>;
+                                       regulator-max-microvolt = <1350000>;
+                                       regulator-enable-ramp-delay = <176>;
+                                       regulator-disable-ramp-delay = <32000>;
+                                       regulator-ramp-delay = <27500>;
+                                       regulator-ramp-delay-scale = <350>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_1>;
+                                       maxim,active-fps-power-up-slot = <2>;
+                                       maxim,active-fps-power-down-slot = <5>;
+                               };
+
+                               vdd_1v8: sd3 {
+                                       regulator-name = "VDD_1V8";
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <1800000>;
+                                       regulator-enable-ramp-delay = <242>;
+                                       regulator-disable-ramp-delay = <118000>;
+                                       regulator-ramp-delay = <27500>;
+                                       regulator-ramp-delay-scale = <360>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
+                                       maxim,active-fps-power-up-slot = <3>;
+                                       maxim,active-fps-power-down-slot = <4>;
+                               };
+
+                               vdd_sys_1v2: ldo0 {
+                                       regulator-name = "AVDD_SYS_1V2";
+                                       regulator-min-microvolt = <1200000>;
+                                       regulator-max-microvolt = <1200000>;
+                                       regulator-enable-ramp-delay = <26>;
+                                       regulator-disable-ramp-delay = <626>;
+                                       regulator-ramp-delay = <100000>;
+                                       regulator-ramp-delay-scale = <200>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
+                                       maxim,active-fps-power-up-slot = <0>;
+                                       maxim,active-fps-power-down-slot = <7>;
+                               };
+
+                               vdd_pex_1v05: ldo1 {
+                                       regulator-name = "VDD_PEX_1V05";
+                                       regulator-min-microvolt = <1050000>;
+                                       regulator-max-microvolt = <1050000>;
+                                       regulator-enable-ramp-delay = <22>;
+                                       regulator-disable-ramp-delay = <650>;
+                                       regulator-ramp-delay = <100000>;
+                                       regulator-ramp-delay-scale = <200>;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
+                                       maxim,active-fps-power-up-slot = <0>;
+                                       maxim,active-fps-power-down-slot = <7>;
+                               };
+
+                               vddio_sdmmc: ldo2 {
+                                       regulator-name = "VDDIO_SDMMC";
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <3300000>;
+                                       regulator-enable-ramp-delay = <62>;
+                                       regulator-disable-ramp-delay = <650>;
+                                       regulator-ramp-delay = <100000>;
+                                       regulator-ramp-delay-scale = <200>;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
+                                       maxim,active-fps-power-up-slot = <0>;
+                                       maxim,active-fps-power-down-slot = <7>;
+                               };
+
+                               ldo3 {
+                                       status = "disabled";
+                               };
+
+                               vdd_rtc: ldo4 {
+                                       regulator-name = "VDD_RTC";
+                                       regulator-min-microvolt = <850000>;
+                                       regulator-max-microvolt = <1100000>;
+                                       regulator-enable-ramp-delay = <22>;
+                                       regulator-disable-ramp-delay = <610>;
+                                       regulator-ramp-delay = <100000>;
+                                       regulator-ramp-delay-scale = <200>;
+                                       regulator-disable-active-discharge;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
+                                       maxim,active-fps-power-up-slot = <1>;
+                                       maxim,active-fps-power-down-slot = <6>;
+                               };
+
+                               ldo5 {
+                                       status = "disabled";
+                               };
+
+                               ldo6 {
+                                       status = "disabled";
+                               };
+
+                               avdd_1v05_pll: ldo7 {
+                                       regulator-name = "AVDD_1V05_PLL";
+                                       regulator-min-microvolt = <1050000>;
+                                       regulator-max-microvolt = <1050000>;
+                                       regulator-enable-ramp-delay = <24>;
+                                       regulator-disable-ramp-delay = <2768>;
+                                       regulator-ramp-delay = <100000>;
+                                       regulator-ramp-delay-scale = <200>;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_1>;
+                                       maxim,active-fps-power-up-slot = <3>;
+                                       maxim,active-fps-power-down-slot = <4>;
+                               };
+
+                               avdd_1v05: ldo8 {
+                                       regulator-name = "AVDD_SATA_HDMI_DP_1V05";
+                                       regulator-min-microvolt = <1050000>;
+                                       regulator-max-microvolt = <1050000>;
+                                       regulator-enable-ramp-delay = <22>;
+                                       regulator-disable-ramp-delay = <1160>;
+                                       regulator-ramp-delay = <100000>;
+                                       regulator-ramp-delay-scale = <200>;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_1>;
+                                       maxim,active-fps-power-up-slot = <6>;
+                                       maxim,active-fps-power-down-slot = <1>;
+                               };
+                       };
+               };
+       };
+
+       pmc@7000e400 {
+               nvidia,invert-interrupt;
+       };
+
+       hda@70030000 {
+               nvidia,model = "jetson-nano-hda";
+
+               status = "okay";
+       };
+
+       usb@70090000 {
+               phys = <&{/padctl@7009f000/pads/usb2/lanes/usb2-0}>,
+                      <&{/padctl@7009f000/pads/usb2/lanes/usb2-1}>,
+                      <&{/padctl@7009f000/pads/usb2/lanes/usb2-2}>,
+                      <&{/padctl@7009f000/pads/pcie/lanes/pcie-6}>;
+               phy-names = "usb2-0", "usb2-1", "usb2-2", "usb3-0";
+
+               avdd-usb-supply = <&vdd_3v3_sys>;
+               dvddio-pex-supply = <&vdd_pex_1v05>;
+               hvddio-pex-supply = <&vdd_1v8>;
+               /* these really belong to the XUSB pad controller */
+               avdd-pll-utmip-supply = <&vdd_1v8>;
+               avdd-pll-uerefe-supply = <&vdd_pex_1v05>;
+               dvdd-usb-ss-pll-supply = <&vdd_pex_1v05>;
+               hvdd-usb-ss-pll-e-supply = <&vdd_1v8>;
+
+               status = "okay";
+       };
+
+       padctl@7009f000 {
+               status = "okay";
+
+               avdd-pll-utmip-supply = <&vdd_1v8>;
+               avdd-pll-uerefe-supply = <&vdd_pex_1v05>;
+               dvdd-pex-pll-supply = <&vdd_pex_1v05>;
+               hvdd-pex-pll-e-supply = <&vdd_1v8>;
+
+               pads {
+                       usb2 {
+                               status = "okay";
+
+                               lanes {
+                                       usb2-0 {
+                                               nvidia,function = "xusb";
+                                               status = "okay";
+                                       };
+
+                                       usb2-1 {
+                                               nvidia,function = "xusb";
+                                               status = "okay";
+                                       };
+
+                                       usb2-2 {
+                                               nvidia,function = "xusb";
+                                               status = "okay";
+                                       };
+                               };
+                       };
+
+                       pcie {
+                               status = "okay";
+
+                               lanes {
+                                       pcie-0 {
+                                               nvidia,function = "pcie-x1";
+                                               status = "okay";
+                                       };
+
+                                       pcie-1 {
+                                               nvidia,function = "pcie-x4";
+                                               status = "okay";
+                                       };
+
+                                       pcie-2 {
+                                               nvidia,function = "pcie-x4";
+                                               status = "okay";
+                                       };
+
+                                       pcie-3 {
+                                               nvidia,function = "pcie-x4";
+                                               status = "okay";
+                                       };
+
+                                       pcie-4 {
+                                               nvidia,function = "pcie-x4";
+                                               status = "okay";
+                                       };
+
+                                       pcie-5 {
+                                               nvidia,function = "usb3-ss";
+                                               status = "okay";
+                                       };
+
+                                       pcie-6 {
+                                               nvidia,function = "usb3-ss";
+                                               status = "okay";
+                                       };
+                               };
+                       };
+               };
+
+               ports {
+                       usb2-0 {
+                               status = "okay";
+                               mode = "otg";
+                       };
+
+                       usb2-1 {
+                               status = "okay";
+                               mode = "host";
+                       };
+
+                       usb2-2 {
+                               status = "okay";
+                               mode = "host";
+                       };
+
+                       usb3-0 {
+                               status = "okay";
+                               nvidia,usb2-companion = <1>;
+                               vbus-supply = <&vdd_hub_3v3>;
+                       };
+               };
+       };
+
+       sdhci@700b0000 {
+               status = "okay";
+               bus-width = <4>;
+
+               cd-gpios = <&gpio TEGRA_GPIO(Z, 1) GPIO_ACTIVE_LOW>;
+
+               vqmmc-supply = <&vddio_sdmmc>;
+               vmmc-supply = <&vdd_3v3_sd>;
+       };
+
+       clocks {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               clk32k_in: clock@0 {
+                       compatible = "fixed-clock";
+                       reg = <0>;
+                       #clock-cells = <0>;
+                       clock-frequency = <32768>;
+               };
+       };
+
+       cpus {
+               cpu@0 {
+                       enable-method = "psci";
+               };
+
+               cpu@1 {
+                       enable-method = "psci";
+               };
+
+               cpu@2 {
+                       enable-method = "psci";
+               };
+
+               cpu@3 {
+                       enable-method = "psci";
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               power {
+                       label = "Power";
+                       gpios = <&gpio TEGRA_GPIO(X, 5) GPIO_ACTIVE_LOW>;
+                       linux,input-type = <EV_KEY>;
+                       linux,code = <KEY_POWER>;
+                       debounce-interval = <30>;
+                       wakeup-event-action = <EV_ACT_ASSERTED>;
+                       wakeup-source;
+               };
+
+               force-recovery {
+                       label = "Force Recovery";
+                       gpios = <&gpio TEGRA_GPIO(X, 6) GPIO_ACTIVE_LOW>;
+                       linux,input-type = <EV_KEY>;
+                       linux,code = <BTN_1>;
+                       debounce-interval = <30>;
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-1.0";
+               method = "smc";
+       };
+
+       regulators {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               vdd_5v0_sys: regulator@0 {
+                       compatible = "regulator-fixed";
+                       reg = <0>;
+
+                       regulator-name = "VDD_5V0_SYS";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       regulator-always-on;
+                       regulator-boot-on;
+               };
+
+               vdd_3v3_sys: regulator@1 {
+                       compatible = "regulator-fixed";
+                       reg = <1>;
+                       regulator-name = "VDD_3V3_SYS";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-enable-ramp-delay = <240>;
+                       regulator-disable-ramp-delay = <11340>;
+                       regulator-always-on;
+                       regulator-boot-on;
+
+                       gpio = <&pmic 3 GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+
+                       vin-supply = <&vdd_5v0_sys>;
+               };
+
+               vdd_3v3_sd: regulator@2 {
+                       compatible = "regulator-fixed";
+                       reg = <2>;
+
+                       regulator-name = "VDD_3V3_SD";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+
+                       gpio = <&gpio TEGRA_GPIO(Z, 3) GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+
+                       vin-supply = <&vdd_3v3_sys>;
+               };
+
+               vdd_hdmi: regulator@3 {
+                       compatible = "regulator-fixed";
+                       reg = <3>;
+
+                       regulator-name = "VDD_HDMI_5V0";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+
+                       vin-supply = <&vdd_5v0_sys>;
+               };
+
+               vdd_hub_3v3: regulator@4 {
+                       compatible = "regulator-fixed";
+                       reg = <4>;
+
+                       regulator-name = "VDD_HUB_3V3";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+
+                       gpio = <&gpio TEGRA_GPIO(A, 6) GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+
+                       vin-supply = <&vdd_5v0_sys>;
+               };
+
+               vdd_cpu: regulator@5 {
+                       compatible = "regulator-fixed";
+                       reg = <5>;
+
+                       regulator-name = "VDD_CPU";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       regulator-always-on;
+                       regulator-boot-on;
+
+                       gpio = <&pmic 5 GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+
+                       vin-supply = <&vdd_5v0_sys>;
+               };
+
+               vdd_gpu: regulator@6 {
+                       compatible = "regulator-fixed";
+                       reg = <6>;
+
+                       regulator-name = "VDD_GPU";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       regulator-enable-ramp-delay = <250>;
+
+                       gpio = <&pmic 6 GPIO_ACTIVE_HIGH>;
+                       enable-active-high;
+
+                       vin-supply = <&vdd_5v0_sys>;
+               };
+       };
+};
index a4b8f668a6d44564f28e8009cb629124c01267fa..72c7a04ac1dff2ad7d6c72da180597a1a5071b5c 100644 (file)
        padctl@7009f000 {
                status = "okay";
 
+               avdd-pll-utmip-supply = <&pp1800>;
+               avdd-pll-uerefe-supply = <&pp1050_avdd>;
+               dvdd-pex-pll-supply = <&avddio_1v05>;
+               hvdd-pex-pll-e-supply = <&pp1800>;
+
                pads {
                        usb2 {
                                status = "okay";
                cpu@3 {
                        enable-method = "psci";
                };
+
+               idle-states {
+                       cpu-sleep {
+                               arm,psci-suspend-param = <0x00010007>;
+                               status = "okay";
+                       };
+               };
        };
 
        gpio-keys {
index 6574396d22579feee6c3f4ff3336972565b86a4b..a550c0a4d572fd7360e33c1bb64518c2939965e8 100644 (file)
        };
 
        timer@60005000 {
-               compatible = "nvidia,tegra210-timer", "nvidia,tegra20-timer";
+               compatible = "nvidia,tegra210-timer";
                reg = <0x0 0x60005000 0x0 0x400>;
-               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+               interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+                            <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&tegra_car TEGRA210_CLK_TIMER>;
                clock-names = "timer";
        };
                                 <&dfll>;
                        clock-names = "cpu_g", "pll_x", "pll_p", "dfll";
                        clock-latency = <300000>;
+                       cpu-idle-states = <&CPU_SLEEP>;
+                       next-level-cache = <&L2>;
                };
 
                cpu@1 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a57";
                        reg = <1>;
+                       cpu-idle-states = <&CPU_SLEEP>;
+                       next-level-cache = <&L2>;
                };
 
                cpu@2 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a57";
                        reg = <2>;
+                       cpu-idle-states = <&CPU_SLEEP>;
+                       next-level-cache = <&L2>;
                };
 
                cpu@3 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a57";
                        reg = <3>;
+                       cpu-idle-states = <&CPU_SLEEP>;
+                       next-level-cache = <&L2>;
+               };
+
+               idle-states {
+                       entry-method = "psci";
+
+                       CPU_SLEEP: cpu-sleep {
+                               compatible = "arm,idle-state";
+                               arm,psci-suspend-param = <0x40000007>;
+                               entry-latency-us = <100>;
+                               exit-latency-us = <30>;
+                               min-residency-us = <1000>;
+                               wakeup-latency-us = <130>;
+                               idle-state-name = "cpu-sleep";
+                               status = "disabled";
+                       };
+               };
+
+               L2: l2-cache {
+                       compatible = "cache";
                };
        };
 
index 6a573875d45ace01ddf3f916234cd5487870230b..1c0d06f59d00cf06b3d5157054557ca0eb97b856 100644 (file)
                        bias-disable;
                };
        };
+
+       hdmi_hpd_active: hdmi_hpd_active {
+               mux {
+                       pins = "gpio34";
+                       function = "hdmi_hot";
+               };
+
+               config {
+                       pins = "gpio34";
+                       bias-pull-down;
+                       drive-strength = <16>;
+               };
+       };
+
+       hdmi_hpd_suspend: hdmi_hpd_suspend {
+               mux {
+                       pins = "gpio34";
+                       function = "hdmi_hot";
+               };
+
+               config {
+                       pins = "gpio34";
+                       bias-pull-down;
+                       drive-strength = <2>;
+               };
+       };
+
+       hdmi_ddc_active: hdmi_ddc_active {
+               mux {
+                       pins = "gpio32", "gpio33";
+                       function = "hdmi_ddc";
+               };
+
+               config {
+                       pins = "gpio32", "gpio33";
+                       drive-strength = <2>;
+                       bias-pull-up;
+               };
+       };
+
+       hdmi_ddc_suspend: hdmi_ddc_suspend {
+               mux {
+                       pins = "gpio32", "gpio33";
+                       function = "hdmi_ddc";
+               };
+
+               config {
+                       pins = "gpio32", "gpio33";
+                       drive-strength = <2>;
+                       bias-pull-down;
+               };
+       };
 };
index a6ad3d7fe655bb3dbd976b1e7ddcc2541535b597..31a3e3311ad57a7182e8ff60a72e839fdb9d422c 100644 (file)
                };
        };
 
+       audio_mclk: clk_div1 {
+               pinconf {
+                       pins = "gpio15";
+                       function = "func1";
+                       power-source = <PM8994_GPIO_S4>; // 1.8V
+               };
+       };
+
        volume_up_gpio: pm8996_gpio2 {
                pinconf {
                        pins = "gpio2";
index 6d50449fbcdf0cc8cca4d44fcda6d09f38e376f2..943f69912074d476c6152ec6d7eee71e1e344685 100644 (file)
@@ -18,6 +18,8 @@
 #include "apq8096-db820c-pmic-pins.dtsi"
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/sound/qcom,q6afe.h>
+#include <dt-bindings/sound/qcom,q6asm.h>
 
 /*
  * GPIO name legend: proper name = the GPIO line is used as GPIO
@@ -63,6 +65,7 @@
        };
 
        clocks {
+               compatible = "simple-bus";
                divclk4: divclk4 {
                        compatible = "fixed-clock";
                        #clock-cells = <0>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&divclk4_pin_a>;
                };
+
+               div1_mclk: divclk1 {
+                       compatible = "gpio-gate-clock";
+                       pinctrl-0 = <&audio_mclk>;
+                       pinctrl-names = "default";
+                       clocks = <&rpmcc RPM_SMD_DIV_CLK1>;
+                       #clock-cells = <0>;
+                       enable-gpios = <&pm8994_gpios 15 0>;
+               };
        };
 
        soc {
                                perst-gpio = <&msmgpio 114 GPIO_ACTIVE_LOW>;
                        };
                };
+
+               slim_msm: slim@91c0000 {
+                       ngd@1 {
+                               wcd9335: codec@1{
+                                       clock-names = "mclk", "slimbus";
+                                       clocks = <&div1_mclk>,
+                                                <&rpmcc RPM_SMD_BB_CLK1>;
+                               };
+                       };
+               };
+
+               mdss@900000 {
+                       status = "okay";
+
+                       mdp@901000 {
+                               status = "okay";
+                       };
+
+                       hdmi-phy@9a0600 {
+                               status = "okay";
+
+                               vddio-supply = <&pm8994_l12>;
+                               vcca-supply = <&pm8994_l28>;
+                               #phy-cells = <0>;
+                       };
+
+                       hdmi-tx@9a0000 {
+                               status = "okay";
+
+                               pinctrl-names = "default", "sleep";
+                               pinctrl-0 = <&hdmi_hpd_active &hdmi_ddc_active>;
+                               pinctrl-1 = <&hdmi_hpd_suspend &hdmi_ddc_suspend>;
+
+                               core-vdda-supply = <&pm8994_l12>;
+                               core-vcc-supply = <&pm8994_s4>;
+                       };
+               };
        };
 
 
                };
        };
 };
+
+&sound {
+       compatible = "qcom,apq8096-sndcard";
+       model = "DB820c";
+       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>;
+               };
+       };
+
+       hdmi-dai-link {
+               link-name = "HDMI";
+               cpu {
+                       sound-dai = <&q6afedai HDMI_RX>;
+               };
+
+               platform {
+                       sound-dai = <&q6routing>;
+               };
+
+               codec {
+                       sound-dai = <&hdmi 0>;
+               };
+       };
+
+       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>;
+               };
+       };
+};
index 0803ca8c02da371dbd4670757988453eabee82ec..423dda996b5dcce3b9b0bc9cdc622e181e9e013c 100644 (file)
        };
 
        thermal-zones {
-               cpu-thermal0 {
+               cpu0_1-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
                        thermal-sensors = <&tsens 4>;
 
                        trips {
-                               cpu_alert0: trip0 {
+                               cpu0_1_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
-                               cpu_crit0: trip1 {
+                               cpu0_1_crit: cpu_crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
 
                        cooling-maps {
                                map0 {
-                                       trip = <&cpu_alert0>;
+                                       trip = <&cpu0_1_alert0>;
                                        cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
                                                         <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
                                                         <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
                        };
                };
 
-               cpu-thermal1 {
+               cpu2_3-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
                        thermal-sensors = <&tsens 3>;
 
                        trips {
-                               cpu_alert1: trip0 {
+                               cpu2_3_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
-                               cpu_crit1: trip1 {
+                               cpu2_3_crit: cpu_crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
 
                        cooling-maps {
                                map0 {
-                                       trip = <&cpu_alert1>;
+                                       trip = <&cpu2_3_alert0>;
                                        cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
                                                         <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
                                                         <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
                        thermal-sensors = <&tsens 2>;
 
                        trips {
-                               gpu_alert: trip0 {
+                               gpu_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
-                               gpu_crit: trip1 {
+                               gpu_crit: gpu_crit {
                                        temperature = <95000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                        thermal-sensors = <&tsens 1>;
 
                        trips {
-                               cam_alert: trip0 {
+                               cam_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
-                                       type = "passive";
+                                       type = "hot";
                                };
-                               cam_crit: trip1 {
-                                       temperature = <95000>;
+                       };
+               };
+
+               modem-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens 0>;
+
+                       trips {
+                               modem_alert0: trip-point@0 {
+                                       temperature = <85000>;
                                        hysteresis = <2000>;
-                                       type = "critical";
+                                       type = "hot";
                                };
                        };
-
                };
 
        };
                                #clock-cells = <1>;
                                #phy-cells = <0>;
 
-                               clocks = <&gcc GCC_MDSS_AHB_CLK>;
-                               clock-names = "iface";
+                               clocks = <&gcc GCC_MDSS_AHB_CLK>,
+                                        <&xo_board>;
+                               clock-names = "iface", "ref";
                        };
                };
 
index 131878db9852983ad754e6194cc88c21433aa63e..fba2229b623695032cfddaa481939c49bfa2048d 100644 (file)
 
 &msmgpio {
 
+       wcd9xxx_intr {
+               wcd_intr_default: wcd_intr_default{
+                       mux {
+                               pins = "gpio54";
+                               function = "gpio";
+                       };
+
+                       config {
+                               pins = "gpio54";
+                               drive-strength = <2>; /* 2 mA */
+                               bias-pull-down; /* pull down */
+                               input-enable;
+                       };
+               };
+       };
+
+       cdc_reset_ctrl {
+               cdc_reset_sleep: cdc_reset_sleep {
+                       mux {
+                               pins = "gpio64";
+                               function = "gpio";
+                       };
+                       config {
+                               pins = "gpio64";
+                               drive-strength = <16>;
+                               bias-disable;
+                               output-low;
+                       };
+               };
+               cdc_reset_active:cdc_reset_active {
+                       mux {
+                               pins = "gpio64";
+                               function = "gpio";
+                       };
+                       config {
+                               pins = "gpio64";
+                               drive-strength = <16>;
+                               bias-pull-down;
+                               output-high;
+                       };
+               };
+       };
+
        blsp1_spi0_default: blsp1_spi0_default {
                pinmux {
                        function = "blsp_spi1";
index c761269caf809d8b4961f49eb12c8107ab63df9d..c4e7fde9d88ed9e5393564cdae323589400fd52a 100644 (file)
@@ -14,6 +14,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/soc/qcom,apr.h>
 
 / {
        interrupt-parent = <&intc>;
                        qcom,client-id = <1>;
                        qcom,vmid = <15>;
                };
+
+               zap_shader_region: gpu@8f200000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0x0 0x90b00000 0x0 0xa00000>;
+                       no-map;
+               };
        };
 
        cpus {
        };
 
        thermal-zones {
-               cpu-thermal0 {
+               cpu0-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
                        thermal-sensors = <&tsens0 3>;
 
                        trips {
-                               cpu_alert0: trip0 {
+                               cpu0_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
 
-                               cpu_crit0: trip1 {
+                               cpu0_crit: cpu_crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                        };
                };
 
-               cpu-thermal1 {
+               cpu1-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
                        thermal-sensors = <&tsens0 5>;
 
                        trips {
-                               cpu_alert1: trip0 {
+                               cpu1_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
 
-                               cpu_crit1: trip1 {
+                               cpu1_crit: cpu_crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                        };
                };
 
-               cpu-thermal2 {
+               cpu2-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
                        thermal-sensors = <&tsens0 8>;
 
                        trips {
-                               cpu_alert2: trip0 {
+                               cpu2_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
 
-                               cpu_crit2: trip1 {
+                               cpu2_crit: cpu_crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                        };
                };
 
-               cpu-thermal3 {
+               cpu3-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
                        thermal-sensors = <&tsens0 10>;
 
                        trips {
-                               cpu_alert3: trip0 {
+                               cpu3_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
 
-                               cpu_crit3: trip1 {
+                               cpu3_crit: cpu_crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                                };
                        };
                };
+
+               gpu-thermal-top {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 6>;
+
+                       trips {
+                               gpu1_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               gpu-thermal-bottom {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 7>;
+
+                       trips {
+                               gpu2_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               m4m-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 1>;
+
+                       trips {
+                               m4m_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               l3-or-venus-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 2>;
+
+                       trips {
+                               l3_or_venus_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               cluster0-l2-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 7>;
+
+                       trips {
+                               cluster0_l2_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               cluster1-l2-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 12>;
+
+                       trips {
+                               cluster1_l2_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               camera-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 1>;
+
+                       trips {
+                               camera_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               q6-dsp-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 2>;
+
+                       trips {
+                               q6_dsp_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               mem-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 3>;
+
+                       trips {
+                               mem_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               modemtx-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 4>;
+
+                       trips {
+                               modemtx_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
        };
 
        timer {
                                reg = <0x24f 0x1>;
                                bits = <1 4>;
                        };
+
+                       gpu_speed_bin: gpu_speed_bin@133 {
+                               reg = <0x133 0x1>;
+                               bits = <5 3>;
+                       };
                };
 
                phy@34000 {
                        };
                };
 
+               adreno_smmu: arm,smmu@b40000 {
+                       compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2";
+                       reg = <0xb40000 0x10000>;
+
+                       #global-interrupts = <1>;
+                       interrupts = <GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>;
+                       #iommu-cells = <1>;
+
+                       clocks = <&mmcc GPU_AHB_CLK>,
+                                <&gcc GCC_MMSS_BIMC_GFX_CLK>;
+                       clock-names = "iface", "bus";
+
+                       power-domains = <&mmcc GPU_GDSC>;
+
+                       status = "disabled";
+               };
+
+               mdp_smmu: arm,smmu@d00000 {
+                       compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2";
+                       reg = <0xd00000 0x10000>;
+
+                       #global-interrupts = <1>;
+                       interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH>;
+                       #iommu-cells = <1>;
+                       clocks = <&mmcc SMMU_MDP_AHB_CLK>,
+                                <&mmcc SMMU_MDP_AXI_CLK>;
+                       clock-names = "iface", "bus";
+
+                       power-domains = <&mmcc MDSS_GDSC>;
+
+                       status = "disabled";
+               };
+
+               lpass_q6_smmu: arm,smmu-lpass_q6@1600000 {
+                       compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2";
+                       reg = <0x1600000 0x20000>;
+                       #iommu-cells = <1>;
+                       power-domains = <&gcc HLOS1_VOTE_LPASS_CORE_GDSC>;
+
+                       #global-interrupts = <1>;
+                       interrupts = <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 393 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 394 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>,
+                               <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>;
+
+                       clocks = <&gcc GCC_HLOS1_VOTE_LPASS_CORE_SMMU_CLK>,
+                                <&gcc GCC_HLOS1_VOTE_LPASS_ADSP_SMMU_CLK>;
+                       clock-names = "iface", "bus";
+                       status = "disabled";
+               };
+
                agnoc@0 {
                        power-domains = <&gcc AGGRE0_NOC_GDSC>;
                        compatible = "simple-pm-bus";
                                                "bus_slave";
                        };
                };
+
+               slimbam:dma@9184000
+               {
+                       compatible = "qcom,bam-v1.7.0";
+                       qcom,controlled-remotely;
+                       reg = <0x9184000 0x32000>;
+                       num-channels  = <31>;
+                       interrupts = <0 164 IRQ_TYPE_LEVEL_HIGH>;
+                       #dma-cells = <1>;
+                       qcom,ee = <1>;
+                       qcom,num-ees = <2>;
+               };
+
+               slim_msm: slim@91c0000 {
+                       compatible = "qcom,slim-ngd-v1.5.0";
+                       reg = <0x91c0000 0x2C000>;
+                       reg-names = "ctrl";
+                       interrupts = <0 163 IRQ_TYPE_LEVEL_HIGH>;
+                       dmas =  <&slimbam 3>, <&slimbam 4>,
+                               <&slimbam 5>, <&slimbam 6>;
+                       dma-names = "rx", "tx", "tx2", "rx2";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       ngd@1 {
+                               reg = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+
+                               tasha_ifd: tas-ifd {
+                                       compatible = "slim217,1a0";
+                                       reg  = <0 0>;
+                               };
+
+                               wcd9335: codec@1{
+                                       pinctrl-0 = <&cdc_reset_active &wcd_intr_default>;
+                                       pinctrl-names = "default";
+
+                                       compatible = "slim217,1a0";
+                                       reg  = <1 0>;
+
+                                       interrupt-parent = <&msmgpio>;
+                                       interrupts = <54 IRQ_TYPE_LEVEL_HIGH>,
+                                                    <53 IRQ_TYPE_LEVEL_HIGH>;
+                                       interrupt-names  = "intr1", "intr2";
+                                       interrupt-controller;
+                                       #interrupt-cells = <1>;
+                                       reset-gpios = <&msmgpio 64 0>;
+
+                                       slim-ifc-dev  = <&tasha_ifd>;
+
+                                       vdd-buck-supply = <&pm8994_s4>;
+                                       vdd-buck-sido-supply = <&pm8994_s4>;
+                                       vdd-tx-supply = <&pm8994_s4>;
+                                       vdd-rx-supply = <&pm8994_s4>;
+                                       vdd-io-supply = <&pm8994_s4>;
+
+                                       #sound-dai-cells = <1>;
+                               };
+                       };
+               };
+
+               gpu@b00000 {
+                       compatible = "qcom,adreno-530.2", "qcom,adreno";
+                       #stream-id-cells = <16>;
+
+                       reg = <0xb00000 0x3f000>;
+                       reg-names = "kgsl_3d0_reg_memory";
+
+                       interrupts = <0 300 IRQ_TYPE_LEVEL_HIGH>;
+
+                       clocks = <&mmcc GPU_GX_GFX3D_CLK>,
+                               <&mmcc GPU_AHB_CLK>,
+                               <&mmcc GPU_GX_RBBMTIMER_CLK>,
+                               <&gcc GCC_BIMC_GFX_CLK>,
+                               <&gcc GCC_MMSS_BIMC_GFX_CLK>;
+
+                       clock-names = "core",
+                               "iface",
+                               "rbbmtimer",
+                               "mem",
+                               "mem_iface";
+
+                       power-domains = <&mmcc GPU_GDSC>;
+                       iommus = <&adreno_smmu 0>;
+
+                       nvmem-cells = <&gpu_speed_bin>;
+                       nvmem-cell-names = "speed_bin";
+
+                       qcom,gpu-quirk-two-pass-use-wfi;
+                       qcom,gpu-quirk-fault-detect-mask;
+
+                       operating-points-v2 = <&gpu_opp_table>;
+
+                       gpu_opp_table: opp-table {
+                               compatible  ="operating-points-v2";
+
+                               /*
+                                * 624Mhz and 560Mhz are only available on speed
+                                * bin (1 << 0). All the rest are available on
+                                * all bins of the hardware
+                                */
+                               opp-624000000 {
+                                       opp-hz = /bits/ 64 <624000000>;
+                                       opp-supported-hw = <0x01>;
+                               };
+                               opp-560000000 {
+                                       opp-hz = /bits/ 64 <560000000>;
+                                       opp-supported-hw = <0x01>;
+                               };
+                               opp-510000000 {
+                                       opp-hz = /bits/ 64 <510000000>;
+                                       opp-supported-hw = <0xFF>;
+                               };
+                               opp-401800000 {
+                                       opp-hz = /bits/ 64 <401800000>;
+                                       opp-supported-hw = <0xFF>;
+                               };
+                               opp-315000000 {
+                                       opp-hz = /bits/ 64 <315000000>;
+                                       opp-supported-hw = <0xFF>;
+                               };
+                               opp-214000000 {
+                                       opp-hz = /bits/ 64 <214000000>;
+                                       opp-supported-hw = <0xFF>;
+                               };
+                               opp-133000000 {
+                                       opp-hz = /bits/ 64 <133000000>;
+                                       opp-supported-hw = <0xFF>;
+                               };
+                       };
+
+                       zap-shader {
+                               memory-region = <&zap_shader_region>;
+                       };
+               };
+
+               mdss: mdss@900000 {
+                       compatible = "qcom,mdss";
+
+                       reg = <0x900000 0x1000>,
+                             <0x9b0000 0x1040>,
+                             <0x9b8000 0x1040>;
+                       reg-names = "mdss_phys",
+                                   "vbif_phys",
+                                   "vbif_nrt_phys";
+
+                       power-domains = <&mmcc MDSS_GDSC>;
+                       interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+
+                       clocks = <&mmcc MDSS_AHB_CLK>;
+                       clock-names = "iface_clk";
+
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       mdp: mdp@901000 {
+                               compatible = "qcom,mdp5";
+                               reg = <0x901000 0x90000>;
+                               reg-names = "mdp_phys";
+
+                               interrupt-parent = <&mdss>;
+                               interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+
+                               clocks = <&mmcc MDSS_AHB_CLK>,
+                                        <&mmcc MDSS_AXI_CLK>,
+                                        <&mmcc MDSS_MDP_CLK>,
+                                        <&mmcc SMMU_MDP_AXI_CLK>,
+                                        <&mmcc MDSS_VSYNC_CLK>;
+                               clock-names = "iface_clk",
+                                             "bus_clk",
+                                             "core_clk",
+                                             "iommu_clk",
+                                             "vsync_clk";
+
+                               iommus = <&mdp_smmu 0>;
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0>;
+                                               mdp5_intf3_out: endpoint {
+                                                       remote-endpoint = <&hdmi_in>;
+                                               };
+                                       };
+                               };
+                       };
+
+                       hdmi: hdmi-tx@9a0000 {
+                               compatible = "qcom,hdmi-tx-8996";
+                               reg =   <0x009a0000 0x50c>,
+                                       <0x00070000 0x6158>,
+                                       <0x009e0000 0xfff>;
+                               reg-names = "core_physical",
+                                           "qfprom_physical",
+                                           "hdcp_physical";
+
+                               interrupt-parent = <&mdss>;
+                               interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
+
+                               clocks = <&mmcc MDSS_MDP_CLK>,
+                                        <&mmcc MDSS_AHB_CLK>,
+                                        <&mmcc MDSS_HDMI_CLK>,
+                                        <&mmcc MDSS_HDMI_AHB_CLK>,
+                                        <&mmcc MDSS_EXTPCLK_CLK>;
+                               clock-names =
+                                       "mdp_core_clk",
+                                       "iface_clk",
+                                       "core_clk",
+                                       "alt_iface_clk",
+                                       "extp_clk";
+
+                               phys = <&hdmi_phy>;
+                               phy-names = "hdmi_phy";
+                               #sound-dai-cells = <1>;
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0>;
+                                               hdmi_in: endpoint {
+                                                       remote-endpoint = <&mdp5_intf3_out>;
+                                               };
+                                       };
+                               };
+                       };
+
+                       hdmi_phy: hdmi-phy@9a0600 {
+                               #phy-cells = <0>;
+                               compatible = "qcom,hdmi-phy-8996";
+                               reg = <0x9a0600 0x1c4>,
+                                     <0x9a0a00 0x124>,
+                                     <0x9a0c00 0x124>,
+                                     <0x9a0e00 0x124>,
+                                     <0x9a1000 0x124>,
+                                     <0x9a1200 0x0c8>;
+                               reg-names = "hdmi_pll",
+                                           "hdmi_tx_l0",
+                                           "hdmi_tx_l1",
+                                           "hdmi_tx_l2",
+                                           "hdmi_tx_l3",
+                                           "hdmi_phy";
+
+                               clocks = <&mmcc MDSS_AHB_CLK>,
+                                        <&gcc GCC_HDMI_CLKREF_CLK>;
+                               clock-names = "iface_clk",
+                                             "ref_clk";
+                       };
+               };
+       };
+
+       sound: sound {
        };
 
        adsp-pil {
                        mboxes = <&apcs_glb 8>;
                        qcom,smd-edge = <1>;
                        qcom,remote-pid = <2>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       apr {
+                               power-domains = <&gcc HLOS1_VOTE_LPASS_ADSP_GDSC>;
+                               compatible = "qcom,apr-v2";
+                               qcom,smd-channels = "apr_audio_svc";
+                               reg = <APR_DOMAIN_ADSP>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               q6core {
+                                       reg = <APR_SVC_ADSP_CORE>;
+                                       compatible = "qcom,q6core";
+                               };
+
+                               q6afe: q6afe {
+                                       compatible = "qcom,q6afe";
+                                       reg = <APR_SVC_AFE>;
+                                       q6afedai: dais {
+                                               compatible = "qcom,q6afe-dais";
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+                                               #sound-dai-cells = <1>;
+                                               hdmi@1 {
+                                                       reg = <1>;
+                                               };
+                                       };
+                               };
+
+                               q6asm: q6asm {
+                                       compatible = "qcom,q6asm";
+                                       reg = <APR_SVC_ASM>;
+                                       q6asmdai: dais {
+                                               compatible = "qcom,q6asm-dais";
+                                               #sound-dai-cells = <1>;
+                                               iommus = <&lpass_q6_smmu 1>;
+                                       };
+                               };
+
+                               q6adm: q6adm {
+                                       compatible = "qcom,q6adm";
+                                       reg = <APR_SVC_ADM>;
+                                       q6routing: routing {
+                                               compatible = "qcom,q6adm-routing";
+                                               #sound-dai-cells = <0>;
+                                       };
+                               };
+                       };
+
                };
        };
 
index f0901067b0430275382d4f417c62f10a94095a8e..f09f3e03f708bdf6b6797297a89aa31cec950777 100644 (file)
                stdout-path = "serial0:115200n8";
        };
 
-       thermal-zones {
-               battery-thermal {
-                       polling-delay-passive = <250>;
-                       polling-delay = <1000>;
-
-                       thermal-sensors = <&tsens0 0>;
-
-                       trips {
-                               battery_crit: trip0 {
-                                       temperature = <60000>;
-                                       hysteresis = <2000>;
-                                       type = "critical";
-                               };
-                       };
-               };
-
-               skin-thermal {
-                       polling-delay-passive = <250>;
-                       polling-delay = <1000>;
-
-                       thermal-sensors = <&tsens1 5>;
-
-                       trips {
-                               skin_alert: trip0 {
-                                       temperature = <44000>;
-                                       hysteresis = <2000>;
-                                       type = "passive";
-                               };
-
-                               skip_crit: trip1 {
-                                       temperature = <70000>;
-                                       hysteresis = <2000>;
-                                       type = "critical";
-                               };
-                       };
-               };
-       };
-
        vph_pwr: vph-pwr-regulator {
                compatible = "regulator-fixed";
                regulator-name = "vph_pwr";
                vreg_s4a_1p8: s4 {
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
+                       regulator-allow-set-load;
                };
                vreg_s5a_2p04: s5 {
                        regulator-min-microvolt = <1904000>;
                vreg_l20a_2p95: l20 {
                        regulator-min-microvolt = <2960000>;
                        regulator-max-microvolt = <2960000>;
+                       regulator-allow-set-load;
                };
                vreg_l21a_2p95: l21 {
                        regulator-min-microvolt = <2960000>;
                vreg_l26a_1p2: l26 {
                        regulator-min-microvolt = <1200000>;
                        regulator-max-microvolt = <1200000>;
+                       regulator-allow-set-load;
                };
                vreg_l28_3p0: l28 {
                        regulator-min-microvolt = <3008000>;
        pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
 };
 
+&ufshc {
+       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 {
+       vdda-phy-supply = <&vreg_l1a_0p875>;
+       vdda-pll-supply = <&vreg_l2a_1p2>;
+       vddp-ref-clk-supply = <&vreg_l26a_1p2>;
+       vdda-phy-max-microamp = <51400>;
+       vdda-pll-max-microamp = <14600>;
+       vddp-ref-clk-max-microamp = <100>;
+       vddp-ref-clk-always-on;
+};
+
 &usb3 {
        status = "okay";
 };
index 3fd0769fe648323aa2208e55252d0b279fb60ba9..574be78a936e223f13bb6329b6699ad7a0623b53 100644 (file)
@@ -78,7 +78,6 @@
                        compatible = "arm,armv8";
                        reg = <0x0 0x0>;
                        enable-method = "psci";
-                       efficiency = <1024>;
                        next-level-cache = <&L2_0>;
                        L2_0: l2-cache {
                                compatible = "arm,arch-cache";
@@ -97,7 +96,6 @@
                        compatible = "arm,armv8";
                        reg = <0x0 0x1>;
                        enable-method = "psci";
-                       efficiency = <1024>;
                        next-level-cache = <&L2_0>;
                        L1_I_1: l1-icache {
                                compatible = "arm,arch-cache";
                        compatible = "arm,armv8";
                        reg = <0x0 0x2>;
                        enable-method = "psci";
-                       efficiency = <1024>;
                        next-level-cache = <&L2_0>;
                        L1_I_2: l1-icache {
                                compatible = "arm,arch-cache";
                        compatible = "arm,armv8";
                        reg = <0x0 0x3>;
                        enable-method = "psci";
-                       efficiency = <1024>;
                        next-level-cache = <&L2_0>;
                        L1_I_3: l1-icache {
                                compatible = "arm,arch-cache";
                        compatible = "arm,armv8";
                        reg = <0x0 0x100>;
                        enable-method = "psci";
-                       efficiency = <1536>;
                        next-level-cache = <&L2_1>;
                        L2_1: l2-cache {
                                compatible = "arm,arch-cache";
                        compatible = "arm,armv8";
                        reg = <0x0 0x101>;
                        enable-method = "psci";
-                       efficiency = <1536>;
                        next-level-cache = <&L2_1>;
                        L1_I_101: l1-icache {
                                compatible = "arm,arch-cache";
                        compatible = "arm,armv8";
                        reg = <0x0 0x102>;
                        enable-method = "psci";
-                       efficiency = <1536>;
                        next-level-cache = <&L2_1>;
                        L1_I_102: l1-icache {
                                compatible = "arm,arch-cache";
                        compatible = "arm,armv8";
                        reg = <0x0 0x103>;
                        enable-method = "psci";
-                       efficiency = <1536>;
                        next-level-cache = <&L2_1>;
                        L1_I_103: l1-icache {
                                compatible = "arm,arch-cache";
        };
 
        thermal-zones {
-               cpu-thermal0 {
+               cpu0-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&tsens0 6>;
+                       thermal-sensors = <&tsens0 1>;
 
                        trips {
-                               cpu_alert0: trip0 {
+                               cpu0_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
 
-                               cpu_crit0: trip1 {
+                               cpu0_crit: cpu_crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                        };
                };
 
-               cpu-thermal1 {
+               cpu1-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&tsens0 7>;
+                       thermal-sensors = <&tsens0 2>;
 
                        trips {
-                               cpu_alert1: trip0 {
+                               cpu1_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
 
-                               cpu_crit1: trip1 {
+                               cpu1_crit: cpu_crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                        };
                };
 
-               cpu-thermal2 {
+               cpu2-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&tsens0 8>;
+                       thermal-sensors = <&tsens0 3>;
 
                        trips {
-                               cpu_alert2: trip0 {
+                               cpu2_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
 
-                               cpu_crit2: trip1 {
+                               cpu2_crit: cpu_crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                        };
                };
 
-               cpu-thermal3 {
+               cpu3-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&tsens0 9>;
+                       thermal-sensors = <&tsens0 4>;
 
                        trips {
-                               cpu_alert3: trip0 {
+                               cpu3_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
 
-                               cpu_crit3: trip1 {
+                               cpu3_crit: cpu_crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                        };
                };
 
-               cpu-thermal4 {
+               cpu4-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&tsens0 10>;
+                       thermal-sensors = <&tsens0 7>;
 
                        trips {
-                               cpu_alert4: trip0 {
+                               cpu4_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
 
-                               cpu_crit4: trip1 {
+                               cpu4_crit: cpu_crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                        };
                };
 
-               cpu-thermal5 {
+               cpu5-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&tsens0 11>;
+                       thermal-sensors = <&tsens0 8>;
 
                        trips {
-                               cpu_alert5: trip0 {
+                               cpu5_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
 
-                               cpu_crit5: trip1 {
+                               cpu5_crit: cpu_crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                        };
                };
 
-               cpu-thermal6 {
+               cpu6-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&tsens1 0>;
+                       thermal-sensors = <&tsens0 9>;
 
                        trips {
-                               cpu_alert6: trip0 {
+                               cpu6_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
 
-                               cpu_crit6: trip1 {
+                               cpu6_crit: cpu_crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                        };
                };
 
-               cpu-thermal7 {
+               cpu7-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&tsens1 1>;
+                       thermal-sensors = <&tsens0 10>;
 
                        trips {
-                               cpu_alert7: trip0 {
+                               cpu7_alert0: trip-point@0 {
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
 
-                               cpu_crit7: trip1 {
+                               cpu7_crit: cpu_crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                        };
                };
 
-               gpu-thermal {
+               gpu-thermal-bottom {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 12>;
+
+                       trips {
+                               gpu1_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               gpu-thermal-top {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 13>;
+
+                       trips {
+                               gpu2_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               clust0-mhm-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 5>;
+
+                       trips {
+                               cluster0_mhm_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               clust1-mhm-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 6>;
+
+                       trips {
+                               cluster1_mhm_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               cluster1-l2-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 11>;
+
+                       trips {
+                               cluster1_l2_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               modem-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 1>;
+
+                       trips {
+                               modem_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               mem-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 2>;
+
+                       trips {
+                               mem_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               wlan-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
                        thermal-sensors = <&tsens1 3>;
+
+                       trips {
+                               wlan_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               q6-dsp-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 4>;
+
+                       trips {
+                               q6_dsp_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               camera-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 5>;
+
+                       trips {
+                               camera_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               multimedia-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 6>;
+
+                       trips {
+                               multimedia_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
                };
        };
 
                        cell-index = <0>;
                };
 
-               tsens0: thermal@10aa000 {
+               tsens0: thermal@10ab000 {
                        compatible = "qcom,msm8998-tsens", "qcom,tsens-v2";
-                       reg = <0x10aa000 0x2000>;
+                       reg = <0x10ab000 0x1000>, /* TM */
+                             <0x10aa000 0x1000>; /* SROT */
 
-                       #qcom,sensors = <12>;
+                       #qcom,sensors = <14>;
                        #thermal-sensor-cells = <1>;
                };
 
-               tsens1: thermal@10ad000 {
+               tsens1: thermal@10ae000 {
                        compatible = "qcom,msm8998-tsens", "qcom,tsens-v2";
-                       reg = <0x10ad000 0x2000>;
+                       reg = <0x10ae000 0x1000>, /* TM */
+                             <0x10ad000 0x1000>; /* SROT */
 
                        #qcom,sensors = <8>;
                        #thermal-sensor-cells = <1>;
 
                blsp2_i2c5: i2c@c1ba000 {
                        compatible = "qcom,i2c-qup-v2.2.1";
-                       reg = <0x0c175000 0x600>;
+                       reg = <0x0c1ba000 0x600>;
                        interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
 
                        clocks = <&gcc GCC_BLSP2_QUP6_I2C_APPS_CLK>,
                        redistributor-stride = <0x0 0x20000>;
                        interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
                };
+
+               ufshc: ufshc@1da4000 {
+                       compatible = "qcom,msm8998-ufshc", "qcom,ufshc", "jedec,ufs-2.0";
+                       reg = <0x01da4000 0x2500>;
+                       interrupts = <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>;
+                       phys = <&ufsphy_lanes>;
+                       phy-names = "ufsphy";
+                       lanes-per-direction = <2>;
+                       power-domains = <&gcc UFS_GDSC>;
+                       #reset-cells = <1>;
+
+                       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";
+                       clocks =
+                               <&gcc GCC_UFS_AXI_CLK>,
+                               <&gcc GCC_AGGRE1_UFS_AXI_CLK>,
+                               <&gcc GCC_UFS_AHB_CLK>,
+                               <&gcc GCC_UFS_UNIPRO_CORE_CLK>,
+                               <&rpmcc RPM_SMD_LN_BB_CLK1>,
+                               <&gcc GCC_UFS_TX_SYMBOL_0_CLK>,
+                               <&gcc GCC_UFS_RX_SYMBOL_0_CLK>,
+                               <&gcc GCC_UFS_RX_SYMBOL_1_CLK>;
+                       freq-table-hz =
+                               <50000000 200000000>,
+                               <0 0>,
+                               <0 0>,
+                               <37500000 150000000>,
+                               <0 0>,
+                               <0 0>,
+                               <0 0>,
+                               <0 0>;
+
+                       resets = <&gcc GCC_UFS_BCR>;
+                       reset-names = "rst";
+               };
+
+               ufsphy: phy@1da7000 {
+                       compatible = "qcom,msm8998-qmp-ufs-phy";
+                       reg = <0x01da7000 0x18c>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       clock-names =
+                               "ref",
+                               "ref_aux";
+                       clocks =
+                               <&gcc GCC_UFS_CLKREF_CLK>,
+                               <&gcc GCC_UFS_PHY_AUX_CLK>;
+
+                       reset-names = "ufsphy";
+                       resets = <&ufshc 0>;
+
+                       ufsphy_lanes: lanes@1da7400 {
+                               reg = <0x01da7400 0x128>,
+                                     <0x01da7600 0x1fc>,
+                                     <0x01da7c00 0x1dc>,
+                                     <0x01da7800 0x128>,
+                                     <0x01da7a00 0x1fc>;
+                               #phy-cells = <0>;
+                       };
+               };
        };
 };
 
index c0ddf128136cc9ab34e99201fb0cf5abd807088e..3f97607d8baa89ab1e16a0044c4feacf187bde46 100644 (file)
@@ -15,6 +15,7 @@
                        compatible = "qcom,pm8005-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
+                       gpio-ranges = <&pm8005_gpio 0 0 4>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index 43cb5ea14089d55d45fe670ac037f96e28d1e377..d3ca35a940fb68a7c254533f9cf96db36be8e408 100644 (file)
@@ -58,6 +58,8 @@
                        compatible = "qcom,spmi-temp-alarm";
                        reg = <0x2400>;
                        interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
+                       io-channels = <&pm8998_adc ADC5_DIE_TEMP>;
+                       io-channel-names = "thermal";
                        #thermal-sensor-cells = <0>;
                };
 
@@ -93,6 +95,7 @@
                        compatible = "qcom,pm8998-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
+                       gpio-ranges = <&pm8998_gpio 0 0 26>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index 3aee10e3f92110cbfb18ea9401bbe3e62d4a2d7b..21e05215abe46aade346b98deaf75379df635d16 100644 (file)
@@ -14,6 +14,7 @@
                        compatible = "qcom,pmi8994-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
+                       gpio-ranges = <&pmi8994_gpios 0 0 10>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index 051f57e7d6ac3798f4f815c79f8885cb54005ecb..23f9146a161e539b64a1e8efe3a5cb773698f7a6 100644 (file)
@@ -13,6 +13,7 @@
                        compatible = "qcom,pmi8998-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
+                       gpio-ranges = <&pmi8998_gpio 0 0 14>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index 1bb836d1e8aac8eb7f1e69a94261b6600e7a1e23..e8e186bc1ea790e066a5351746356574c75e6a93 100644 (file)
                        interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>;
                };
        };
+
+       pms405_1: pms405@1 {
+               compatible = "qcom,spmi-pmic";
+               reg = <0x1 SPMI_USID>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               pms405_spmi_regulators: regulators {
+                       compatible = "qcom,pms405-regulators";
+               };
+       };
 };
index 2c14903d808ee191027280d3ff826ed15e73ece0..937eb4555ffe700a0c52453733f965533ac9da6a 100644 (file)
@@ -7,5 +7,6 @@
 
 / {
        model = "Qualcomm Technologies, Inc. QCS404 EVB 1000";
-       compatible = "qcom,qcs404-evb";
+       compatible = "qcom,qcs404-evb-1000", "qcom,qcs404-evb",
+                    "qcom,qcs404";
 };
index 11269ad3de0d432616e88e5784e0279faa6c024c..479ad3ac6c28f31422bd2e07a902275d4c66d72e 100644 (file)
@@ -3,9 +3,92 @@
 
 /dts-v1/;
 
+#include <dt-bindings/gpio/gpio.h>
 #include "qcs404-evb.dtsi"
 
 / {
        model = "Qualcomm Technologies, Inc. QCS404 EVB 4000";
-       compatible = "qcom,qcs404-evb";
+       compatible = "qcom,qcs404-evb-4000", "qcom,qcs404-evb",
+                    "qcom,qcs404";
+};
+
+&ethernet {
+       status = "ok";
+
+       snps,reset-gpio = <&tlmm 60 GPIO_ACTIVE_LOW>;
+       snps,reset-active-low;
+       snps,reset-delays-us = <0 10000 10000>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&ethernet_defaults>;
+
+       phy-handle = <&phy1>;
+       phy-mode = "rgmii";
+       mdio {
+               #address-cells = <0x1>;
+               #size-cells = <0x0>;
+               compatible = "snps,dwmac-mdio";
+               phy1: phy@4 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       device_type = "ethernet-phy";
+                       reg = <0x4>;
+               };
+       };
+};
+
+&tlmm {
+       ethernet_defaults: ethernet-defaults {
+               int {
+                       pins = "gpio61";
+                       function = "rgmii_int";
+                       bias-disable;
+                       drive-strength = <2>;
+               };
+               mdc {
+                       pins = "gpio76";
+                       function = "rgmii_mdc";
+                       bias-pull-up;
+               };
+               mdio {
+                       pins = "gpio75";
+                       function = "rgmii_mdio";
+                       bias-pull-up;
+               };
+               tx {
+                       pins = "gpio67", "gpio66", "gpio65", "gpio64";
+                       function = "rgmii_tx";
+                       bias-pull-up;
+                       drive-strength = <16>;
+               };
+               rx {
+                       pins = "gpio73", "gpio72", "gpio71", "gpio70";
+                       function = "rgmii_rx";
+                       bias-disable;
+                       drive-strength = <2>;
+               };
+               tx-ctl {
+                       pins = "gpio68";
+                       function = "rgmii_ctl";
+                       bias-pull-up;
+                       drive-strength = <16>;
+               };
+               rx-ctl {
+                       pins = "gpio74";
+                       function = "rgmii_ctl";
+                       bias-disable;
+                       drive-strength = <2>;
+               };
+               tx-ck {
+                       pins = "gpio63";
+                       function = "rgmii_ck";
+                       bias-pull-up;
+                       drive-strength = <16>;
+               };
+               rx-ck {
+                       pins = "gpio69";
+                       function = "rgmii_ck";
+                       bias-disable;
+                       drive-strength = <2>;
+               };
+       };
 };
index 50b3589c7f1594e96c9384007d547389b1ffc6bd..2c3127167e3c247d51ce3f52f96b314672ede8d3 100644 (file)
@@ -7,6 +7,7 @@
 / {
        aliases {
                serial0 = &blsp1_uart2;
+               serial1 = &blsp1_uart3;
        };
 
        chosen {
                regulator-always-on;
                regulator-boot-on;
        };
+
+       vdd_ch0_3p3:
+       vdd_esmps3_3p3: vdd-esmps3-3p3-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "eSMPS3_3P3";
+
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+};
+
+&blsp1_uart3 {
+       status = "okay";
+
+       bluetooth {
+               compatible = "qcom,wcn3990-bt";
+               vddio-supply = <&vreg_l6_1p8>;
+               vddxo-supply = <&vreg_l5_1p8>;
+               vddrf-supply = <&vreg_l1_1p3>;
+               vddch0-supply = <&vdd_ch0_3p3>;
+
+               local-bd-address = [ 02 00 00 00 5a ad ];
+
+               max-speed = <3200000>;
+       };
+};
+
+&blsp1_dma {
+       qcom,controlled-remotely;
+};
+
+&blsp2_dma {
+       qcom,controlled-remotely;
+};
+
+&pms405_spmi_regulators {
+       vdd_s3-supply = <&pms405_s3>;
+
+       pms405_s3: s3 {
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-name = "vdd_apc";
+               regulator-min-microvolt = <1048000>;
+               regulator-max-microvolt = <1352000>;
+       };
 };
 
 &remoteproc_adsp {
        pms405-regulators {
                compatible = "qcom,rpm-pms405-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-l1-l2-supply = <&vreg_s5_1p35>;
-               vdd-l3-l8-supply = <&vreg_s5_1p35>;
-               vdd-l4-supply = <&vreg_s5_1p35>;
-               vdd-l5-l6-supply = <&vreg_s4_1p8>;
-               vdd-l7-supply = <&vph_pwr>;
-               vdd-l9-supply = <&vreg_s5_1p35>;
-               vdd-l10-l11-l12-l13-supply = <&vph_pwr>;
+               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_l1_l2-supply = <&vreg_s5_1p35>;
+               vdd_l3_l8-supply = <&vreg_s5_1p35>;
+               vdd_l4-supply = <&vreg_s5_1p35>;
+               vdd_l5_l6-supply = <&vreg_s4_1p8>;
+               vdd_l7-supply = <&vph_pwr>;
+               vdd_l9-supply = <&vreg_s5_1p35>;
+               vdd_l10_l11_l12_l13-supply = <&vph_pwr>;
 
                vreg_s4_1p8: s4 {
                        regulator-min-microvolt = <1728000>;
                };
 
                vreg_s5_1p35: s5 {
-                       regulator-min-microvolt = <>;
-                       regulator-max-microvolt = <>;
+                       regulator-min-microvolt = <1352000>;
+                       regulator-max-microvolt = <1352000>;
                };
 
                vreg_l1_1p3: l1 {
                };
 
                vreg_l3_1p05: l3 {
-                       regulator-min-microvolt = <976000>;
+                       regulator-min-microvolt = <1050000>;
                        regulator-max-microvolt = <1160000>;
                };
 
                bias-disable;
        };
 };
+
+&blsp1_uart3_default {
+       cts {
+               pins = "gpio84";
+               bias-disable;
+       };
+
+       rts-tx {
+               pins = "gpio85", "gpio82";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       rx {
+               pins = "gpio83";
+               bias-pull-up;
+       };
+};
index e8fd26633d5767b01325f31ae3d9d35799cc8dc4..ffedf9640af7dd081e307a36e3e01db09f81116d 100644 (file)
                        clocks = <&gcc GCC_BLSP1_AHB_CLK>;
                        clock-names = "bam_clk";
                        #dma-cells = <1>;
-                       qcom,controlled-remotely = <1>;
                        qcom,ee = <0>;
                        status = "okay";
                };
                        status = "okay";
                };
 
+               ethernet: ethernet@7a80000 {
+                       compatible = "qcom,qcs404-ethqos";
+                       reg = <0x07a80000 0x10000>,
+                               <0x07a96000 0x100>;
+                       reg-names = "stmmaceth", "rgmii";
+                       clock-names = "stmmaceth", "pclk", "ptp_ref", "rgmii";
+                       clocks = <&gcc GCC_ETH_AXI_CLK>,
+                               <&gcc GCC_ETH_SLAVE_AHB_CLK>,
+                               <&gcc GCC_ETH_PTP_CLK>,
+                               <&gcc GCC_ETH_RGMII_CLK>;
+                       interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
+                                       <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "macirq", "eth_lpi";
+
+                       snps,tso;
+                       rx-fifo-depth = <4096>;
+                       tx-fifo-depth = <4096>;
+
+                       status = "disabled";
+               };
+
                wifi: wifi@a000000 {
                        compatible = "qcom,wcn3990-wifi";
                        reg = <0xa000000 0x800000>;
                        clocks = <&gcc GCC_BLSP2_AHB_CLK>;
                        clock-names = "bam_clk";
                        #dma-cells = <1>;
-                       qcom,controlled-remotely = <1>;
                        qcom,ee = <0>;
                        status = "disabled";
                };
index af8c6a2445a2b2908c31b4235d91705ca5eb2d30..02b8357c8ce81ed7290eb2c25e80e13de2dd48cb 100644 (file)
        };
 };
 
+&adsp_pas {
+       status = "okay";
+};
+
 &apps_rsc {
        pm8998-rpmh-regulators {
                compatible = "qcom,pm8998-rpmh-regulators";
        };
 };
 
+&cdsp_pas {
+       status = "okay";
+};
+
 &gcc {
        protected-clocks = <GCC_QSPI_CORE_CLK>,
                           <GCC_QSPI_CORE_CLK_SRC>,
index 5308f16718244951ebbb55bbec4248b4647ab4d7..fcb93300ca628067f87e2a011dfc070fcc28d867 100644 (file)
 #include <dt-bindings/clock/qcom,lpass-sdm845.h>
 #include <dt-bindings/clock/qcom,rpmh.h>
 #include <dt-bindings/clock/qcom,videocc-sdm845.h>
+#include <dt-bindings/interconnect/qcom,sdm845.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/phy/phy-qcom-qusb2.h>
+#include <dt-bindings/power/qcom-rpmpd.h>
 #include <dt-bindings/reset/qcom,sdm845-aoss.h>
 #include <dt-bindings/reset/qcom,sdm845-pdc.h>
 #include <dt-bindings/soc/qcom,rpmh-rsc.h>
                #size-cells = <2>;
                ranges;
 
-               memory@85fc0000 {
+               hyp_mem: memory@85700000 {
+                       reg = <0 0x85700000 0 0x600000>;
+                       no-map;
+               };
+
+               xbl_mem: memory@85e00000 {
+                       reg = <0 0x85e00000 0 0x100000>;
+                       no-map;
+               };
+
+               aop_mem: memory@85fc0000 {
                        reg = <0 0x85fc0000 0 0x20000>;
                        no-map;
                };
 
-               memory@85fe0000 {
+               aop_cmd_db_mem: memory@85fe0000 {
                        compatible = "qcom,cmd-db";
-                       reg = <0x0 0x85fe0000 0x0 0x20000>;
+                       reg = <0x0 0x85fe0000 0 0x20000>;
                        no-map;
                };
 
                smem_mem: memory@86000000 {
-                       reg = <0x0 0x86000000 0x0 0x200000>;
+                       reg = <0x0 0x86000000 0 0x200000>;
                        no-map;
                };
 
-               memory@86200000 {
+               tz_mem: memory@86200000 {
                        reg = <0 0x86200000 0 0x2d00000>;
                        no-map;
                };
 
-               wlan_msa_mem: memory@96700000 {
-                       reg = <0 0x96700000 0 0x100000>;
+               rmtfs_mem: memory@88f00000 {
+                       compatible = "qcom,rmtfs-mem";
+                       reg = <0 0x88f00000 0 0x200000>;
+                       no-map;
+
+                       qcom,client-id = <1>;
+                       qcom,vmid = <15>;
+               };
+
+               qseecom_mem: memory@8ab00000 {
+                       reg = <0 0x8ab00000 0 0x1400000>;
+                       no-map;
+               };
+
+               camera_mem: memory@8bf00000 {
+                       reg = <0 0x8bf00000 0 0x500000>;
+                       no-map;
+               };
+
+               ipa_fw_mem: memory@8c400000 {
+                       reg = <0 0x8c400000 0 0x10000>;
+                       no-map;
+               };
+
+               ipa_gsi_mem: memory@8c410000 {
+                       reg = <0 0x8c410000 0 0x5000>;
+                       no-map;
+               };
+
+               gpu_mem: memory@8c415000 {
+                       reg = <0 0x8c415000 0 0x2000>;
+                       no-map;
+               };
+
+               adsp_mem: memory@8c500000 {
+                       reg = <0 0x8c500000 0 0x1a00000>;
+                       no-map;
+               };
+
+               wlan_msa_mem: memory@8df00000 {
+                       reg = <0 0x8df00000 0 0x100000>;
                        no-map;
                };
 
                        no-map;
                };
 
+               venus_mem: memory@95800000 {
+                       reg = <0 0x95800000 0 0x500000>;
+                       no-map;
+               };
+
+               cdsp_mem: memory@95d00000 {
+                       reg = <0 0x95d00000 0 0x800000>;
+                       no-map;
+               };
+
                mba_region: memory@96500000 {
                        reg = <0 0x96500000 0 0x200000>;
                        no-map;
                };
+
+               slpi_mem: memory@96700000 {
+                       reg = <0 0x96700000 0 0x1400000>;
+                       no-map;
+               };
+
+               spss_mem: memory@97b00000 {
+                       reg = <0 0x97b00000 0 0x100000>;
+                       no-map;
+               };
        };
 
        cpus {
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x0>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <607>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_0>;
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x100>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <607>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_100>;
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x200>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <607>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_200>;
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x300>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <607>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_300>;
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x400>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_400>;
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x500>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_500>;
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x600>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_600>;
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x700>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_700>;
                                next-level-cache = <&L3_0>;
                        };
                };
+
+               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>;
+                               };
+                       };
+               };
        };
 
        pmu {
                };
        };
 
+       adsp_pas: remoteproc-adsp {
+               compatible = "qcom,sdm845-adsp-pas";
+
+               interrupts-extended = <&intc GIC_SPI 162 IRQ_TYPE_EDGE_RISING>,
+                                     <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+                                     <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+                                     <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+                                     <&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "wdog", "fatal", "ready",
+                                 "handover", "stop-ack";
+
+               clocks = <&rpmhcc RPMH_CXO_CLK>;
+               clock-names = "xo";
+
+               memory-region = <&adsp_mem>;
+
+               qcom,smem-states = <&adsp_smp2p_out 0>;
+               qcom,smem-state-names = "stop";
+
+               status = "disabled";
+
+               glink-edge {
+                       interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
+                       label = "lpass";
+                       qcom,remote-pid = <2>;
+                       mboxes = <&apss_shared 8>;
+               };
+       };
+
+       cdsp_pas: remoteproc-cdsp {
+               compatible = "qcom,sdm845-cdsp-pas";
+
+               interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_EDGE_RISING>,
+                                     <&cdsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+                                     <&cdsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+                                     <&cdsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+                                     <&cdsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
+               interrupt-names = "wdog", "fatal", "ready",
+                                 "handover", "stop-ack";
+
+               clocks = <&rpmhcc RPMH_CXO_CLK>;
+               clock-names = "xo";
+
+               memory-region = <&cdsp_mem>;
+
+               qcom,smem-states = <&cdsp_smp2p_out 0>;
+               qcom,smem-state-names = "stop";
+
+               status = "disabled";
+
+               glink-edge {
+                       interrupts = <GIC_SPI 574 IRQ_TYPE_EDGE_RISING>;
+                       label = "turing";
+                       qcom,remote-pid = <5>;
+                       mboxes = <&apss_shared 4>;
+               };
+       };
+
        tcsr_mutex: hwlock {
                compatible = "qcom,tcsr-mutex";
                syscon = <&tcsr_mutex_regs 0 0x1000>;
                        phy-names = "ufsphy";
                        lanes-per-direction = <2>;
                        power-domains = <&gcc UFS_PHY_GDSC>;
+                       #reset-cells = <1>;
 
                        iommus = <&apps_smmu 0x100 0xf>;
 
                        clocks = <&gcc GCC_UFS_MEM_CLKREF_CLK>,
                                 <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
 
+                       resets = <&ufs_mem_hc 0>;
+                       reset-names = "ufsphy";
                        status = "disabled";
 
                        ufs_mem_phy_lanes: lanes@1d87400 {
                                #clock-cells = <1>;
                                #phy-cells = <0>;
 
-                               clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>;
-                               clock-names = "iface";
+                               clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+                                        <&rpmhcc RPMH_CXO_CLK>;
+                               clock-names = "iface", "ref";
 
                                status = "disabled";
                        };
                                #clock-cells = <1>;
                                #phy-cells = <0>;
 
-                               clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>;
-                               clock-names = "iface";
+                               clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+                                        <&rpmhcc RPMH_CXO_CLK>;
+                               clock-names = "iface", "ref";
 
                                status = "disabled";
                        };
                                        compatible = "operating-points-v2";
 
                                        rpmhpd_opp_ret: opp1 {
-                                               opp-level = <16>;
+                                               opp-level = <RPMH_REGULATOR_LEVEL_RETENTION>;
                                        };
 
                                        rpmhpd_opp_min_svs: opp2 {
-                                               opp-level = <48>;
+                                               opp-level = <RPMH_REGULATOR_LEVEL_MIN_SVS>;
                                        };
 
                                        rpmhpd_opp_low_svs: opp3 {
-                                               opp-level = <64>;
+                                               opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>;
                                        };
 
                                        rpmhpd_opp_svs: opp4 {
-                                               opp-level = <128>;
+                                               opp-level = <RPMH_REGULATOR_LEVEL_SVS>;
                                        };
 
                                        rpmhpd_opp_svs_l1: opp5 {
-                                               opp-level = <192>;
+                                               opp-level = <RPMH_REGULATOR_LEVEL_SVS_L1>;
                                        };
 
                                        rpmhpd_opp_nom: opp6 {
-                                               opp-level = <256>;
+                                               opp-level = <RPMH_REGULATOR_LEVEL_NOM>;
                                        };
 
                                        rpmhpd_opp_nom_l1: opp7 {
-                                               opp-level = <320>;
+                                               opp-level = <RPMH_REGULATOR_LEVEL_NOM_L1>;
                                        };
 
                                        rpmhpd_opp_nom_l2: opp8 {
-                                               opp-level = <336>;
+                                               opp-level = <RPMH_REGULATOR_LEVEL_NOM_L2>;
                                        };
 
                                        rpmhpd_opp_turbo: opp9 {
-                                               opp-level = <384>;
+                                               opp-level = <RPMH_REGULATOR_LEVEL_TURBO>;
                                        };
 
                                        rpmhpd_opp_turbo_l1: opp10 {
-                                               opp-level = <416>;
+                                               opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L1>;
                                        };
                                };
                        };
                                };
                        };
                };
+
+               aoss0-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 0>;
+
+                       trips {
+                               aoss0_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               cluster0-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 5>;
+
+                       trips {
+                               cluster0_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                               cluster0_crit: cluster0_crit {
+                                       temperature = <110000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cluster1-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 6>;
+
+                       trips {
+                               cluster1_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                               cluster1_crit: cluster1_crit {
+                                       temperature = <110000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               gpu-thermal-top {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 11>;
+
+                       trips {
+                               gpu1_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               gpu-thermal-bottom {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 12>;
+
+                       trips {
+                               gpu2_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               aoss1-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 0>;
+
+                       trips {
+                               aoss1_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               q6-modem-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 1>;
+
+                       trips {
+                               q6_modem_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               mem-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 2>;
+
+                       trips {
+                               mem_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               wlan-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 3>;
+
+                       trips {
+                               wlan_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               q6-hvx-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 4>;
+
+                       trips {
+                               q6_hvx_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               camera-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 5>;
+
+                       trips {
+                               camera_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               video-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 6>;
+
+                       trips {
+                               video_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+
+               modem-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 7>;
+
+                       trips {
+                               modem_alert0: trip-point@0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
        };
 };
index 14db66755a894efe7195331850833991c7892a17..aaefc3ae56d509604f10cd95d12b87637d3d7ae8 100644 (file)
        };
 };
 
+&can0 {
+       pinctrl-0 = <&can0_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&can1 {
+       pinctrl-0 = <&can1_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
 &pciec0 {
        status = "okay";
 };
                        function = "avb";
                };
        };
+
+       can0_pins: can0 {
+               groups = "can0_data";
+               function = "can0";
+       };
+
+       can1_pins: can1 {
+               groups = "can1_data";
+               function = "can1";
+       };
 };
index ef3cff2dd1b64b717e008f3e71c7caf828862247..de282c4794ed93cf505d642e51f965e0de316049 100644 (file)
                                     "renesas,rcar-gen3-can";
                        reg = <0 0xe6c30000 0 0x1000>;
                        interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&cpg CPG_MOD 916>, <&can_clk>;
-                       clock-names = "clkp1", "can_clk";
+                       clocks = <&cpg CPG_MOD 916>,
+                                <&cpg CPG_CORE R8A774A1_CLK_CANFD>,
+                                <&can_clk>;
+                       clock-names = "clkp1", "clkp2", "can_clk";
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
                        resets = <&cpg 916>;
                        status = "disabled";
                                     "renesas,rcar-gen3-can";
                        reg = <0 0xe6c38000 0 0x1000>;
                        interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&cpg CPG_MOD 915>, <&can_clk>;
-                       clock-names = "clkp1", "can_clk";
+                       clocks = <&cpg CPG_MOD 915>,
+                                <&cpg CPG_CORE R8A774A1_CLK_CANFD>,
+                                <&can_clk>;
+                       clock-names = "clkp1", "clkp2", "can_clk";
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
                        resets = <&cpg 915>;
                        status = "disabled";
index 96ee0d2c6357c6c80cbbcc53cb2d2e67eb55639c..013a48c012113b15c9eea443f784e2792839a49f 100644 (file)
                stdout-path = "serial0:115200n8";
        };
 
+       leds {
+               compatible = "gpio-leds";
+
+               led0 {
+                       gpios = <&gpio5 19 GPIO_ACTIVE_HIGH>;
+                       label = "LED0";
+               };
+
+               led1 {
+                       gpios = <&gpio3 14 GPIO_ACTIVE_HIGH>;
+                       label = "LED1";
+               };
+
+               led2 {
+                       gpios = <&gpio4 10 GPIO_ACTIVE_HIGH>;
+                       label = "LED2";
+               };
+
+               led3 {
+                       gpios = <&gpio6 4 GPIO_ACTIVE_HIGH>;
+                       label = "LED3";
+               };
+       };
+
        memory@48000000 {
                device_type = "memory";
                /* first 128MB is reserved for secure area. */
        };
 };
 
+&ehci0 {
+       dr_mode = "host";
+       status = "okay";
+};
+
 &extal_clk {
        clock-frequency = <48000000>;
 };
 
+&i2c1 {
+       pinctrl-0 = <&i2c1_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+       clock-frequency = <400000>;
+
+       rtc@32 {
+               compatible = "epson,rx8571";
+               reg = <0x32>;
+       };
+};
+
+&ohci0 {
+       dr_mode = "host";
+       status = "okay";
+};
+
 &pcie_bus_clk {
        clock-frequency = <100000000>;
 };
 };
 
 &pfc {
+       i2c1_pins: i2c1 {
+               groups = "i2c1_b";
+               function = "i2c1";
+       };
+
        scif2_pins: scif2 {
                groups = "scif2_data_a";
                function = "scif2";
        };
 };
 
+&rwdt {
+       timeout-sec = <60>;
+       status = "okay";
+};
+
 &scif2 {
        pinctrl-0 = <&scif2_pins>;
        pinctrl-names = "default";
        sd-uhs-sdr104;
        status = "okay";
 };
+
+&usb2_phy0 {
+       renesas,no-otg-pins;
+       status = "okay";
+};
index 1ea684af99c4a19b674f2ab90e38680584b09cf4..3f86db199dbf9fc3889b8eb58c0d12dc86c33024 100644 (file)
@@ -76,7 +76,7 @@
                        power-domains = <&sysc R8A774C0_PD_CA53_CPU0>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
-                       clocks =<&cpg CPG_CORE R8A774C0_CLK_Z2>;
+                       clocks = <&cpg CPG_CORE R8A774C0_CLK_Z2>;
                        operating-points-v2 = <&cluster1_opp>;
                };
 
@@ -87,7 +87,7 @@
                        power-domains = <&sysc R8A774C0_PD_CA53_CPU1>;
                        next-level-cache = <&L2_CA53>;
                        enable-method = "psci";
-                       clocks =<&cpg CPG_CORE R8A774C0_CLK_Z2>;
+                       clocks = <&cpg CPG_CORE R8A774C0_CLK_Z2>;
                        operating-points-v2 = <&cluster1_opp>;
                };
 
                                     "renesas,rcar-gen3-can";
                        reg = <0 0xe6c30000 0 0x1000>;
                        interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&cpg CPG_MOD 916>, <&can_clk>;
-                       clock-names = "clkp1", "can_clk";
+                       clocks = <&cpg CPG_MOD 916>,
+                                <&cpg CPG_CORE R8A774C0_CLK_CANFD>,
+                                <&can_clk>;
+                       clock-names = "clkp1", "clkp2", "can_clk";
                        power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
                        resets = <&cpg 916>;
                        status = "disabled";
                                     "renesas,rcar-gen3-can";
                        reg = <0 0xe6c38000 0 0x1000>;
                        interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&cpg CPG_MOD 915>, <&can_clk>;
-                       clock-names = "clkp1", "can_clk";
+                       clocks = <&cpg CPG_MOD 915>,
+                                <&cpg CPG_CORE R8A774C0_CLK_CANFD>,
+                                <&can_clk>;
+                       clock-names = "clkp1", "clkp2", "can_clk";
                        power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
                        resets = <&cpg 915>;
                        status = "disabled";
                };
 
+               canfd: can@e66c0000 {
+                       compatible = "renesas,r8a774c0-canfd",
+                                    "renesas,rcar-gen3-canfd";
+                       reg = <0 0xe66c0000 0 0x8000>;
+                       interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 914>,
+                                <&cpg CPG_CORE R8A774C0_CLK_CANFD>,
+                                <&can_clk>;
+                       clock-names = "fck", "canfd", "can_clk";
+                       assigned-clocks = <&cpg CPG_CORE R8A774C0_CLK_CANFD>;
+                       assigned-clock-rates = <40000000>;
+                       power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+                       resets = <&cpg 914>;
+                       status = "disabled";
+
+                       channel0 {
+                               status = "disabled";
+                       };
+
+                       channel1 {
+                               status = "disabled";
+                       };
+               };
+
                pwm0: pwm@e6e30000 {
                        compatible = "renesas,pwm-r8a774c0", "renesas,pwm-rcar";
                        reg = <0 0xe6e30000 0 0x8>;
                };
 
                csi40: csi2@feaa0000 {
-                       compatible = "renesas,r8a774c0-csi2",
-                                    "renesas,rcar-gen3-csi2";
+                       compatible = "renesas,r8a774c0-csi2";
                        reg = <0 0xfeaa0000 0 0x10000>;
                        interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 716>;
index abeac3059383969c1329406b3cbbf6bc582e7936..097538cc4b1f179afaafd20b9e04504e46ed1f63 100644 (file)
                        reg = <0 0xe6060000 0 0x50c>;
                };
 
+               cmt0: timer@e60f0000 {
+                       compatible = "renesas,r8a7795-cmt0",
+                                    "renesas,rcar-gen3-cmt0";
+                       reg = <0 0xe60f0000 0 0x1004>;
+                       interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 303>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+                       resets = <&cpg 303>;
+                       status = "disabled";
+               };
+
+               cmt1: timer@e6130000 {
+                       compatible = "renesas,r8a7795-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6130000 0 0x1004>;
+                       interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 302>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+                       resets = <&cpg 302>;
+                       status = "disabled";
+               };
+
+               cmt2: timer@e6140000 {
+                       compatible = "renesas,r8a7795-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6140000 0 0x1004>;
+                       interrupts = <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>;
+                       clocks = <&cpg CPG_MOD 301>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+                       resets = <&cpg 301>;
+                       status = "disabled";
+               };
+
+               cmt3: timer@e6148000 {
+                       compatible = "renesas,r8a7795-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6148000 0 0x1004>;
+                       interrupts = <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>,
+                                    <GIC_SPI 476 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 477 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 300>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+                       resets = <&cpg 300>;
+                       status = "disabled";
+               };
+
                cpg: clock-controller@e6150000 {
                        compatible = "renesas,r8a7795-cpg-mssr";
                        reg = <0 0xe6150000 0 0x1000>;
                                <0 0xec5a0000 0 0x100>,  /* ADG */
                                <0 0xec540000 0 0x1000>, /* SSIU */
                                <0 0xec541000 0 0x280>,  /* SSI */
-                               <0 0xec740000 0 0x200>;  /* Audio DMAC peri peri*/
+                               <0 0xec760000 0 0x200>;  /* Audio DMAC peri peri*/
                        reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
 
                        clocks = <&cpg CPG_MOD 1005>,
index b4f9567cb9f86312164fd4d2302a926974df75a6..2aefa53cb16b8cf18a06951e49ea76a3d289e81b 100644 (file)
@@ -68,6 +68,7 @@
        ports {
                /* rsnd_port0 is on salvator-common */
                rsnd_port1: port@1 {
+                       reg = <1>;
                        rsnd_endpoint1: endpoint {
                                remote-endpoint = <&dw_hdmi0_snd_in>;
 
index 31f12059355ee02b1a1787f563eac2940d0dafb7..d58ede18108d1accbd7d5b538dd719cec34ee305 100644 (file)
@@ -68,6 +68,7 @@
        ports {
                /* rsnd_port0 is on salvator-common */
                rsnd_port1: port@1 {
+                       reg = <1>;
                        rsnd_endpoint1: endpoint {
                                remote-endpoint = <&dw_hdmi0_snd_in>;
 
index cdf784899cf8c06876888c5cfcd510bf645085ea..d5e2f4af83a49a2ab5db4765cee5646fff617ac5 100644 (file)
                                <0 0xec5a0000 0 0x100>,  /* ADG */
                                <0 0xec540000 0 0x1000>, /* SSIU */
                                <0 0xec541000 0 0x280>,  /* SSI */
-                               <0 0xec740000 0 0x200>;  /* Audio DMAC peri peri*/
+                               <0 0xec760000 0 0x200>;  /* Audio DMAC peri peri*/
                        reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
 
                        clocks = <&cpg CPG_MOD 1005>,
                                        dma-names = "rx", "tx";
                                };
                        };
-
-                       ports {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-                               port@0 {
-                                       reg = <0>;
-                               };
-                               port@1 {
-                                       reg = <1>;
-                               };
-                       };
                };
 
                audma0: dma-controller@ec700000 {
index 9763d108e183b13d1067eac9c8d08af1f3ed24a4..2554b1742dbf2316c126cf3e3cf54a218c099fda 100644 (file)
                        reg = <0 0xe6060000 0 0x50c>;
                };
 
+               cmt0: timer@e60f0000 {
+                       compatible = "renesas,r8a77965-cmt0",
+                                    "renesas,rcar-gen3-cmt0";
+                       reg = <0 0xe60f0000 0 0x1004>;
+                       interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 303>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
+                       resets = <&cpg 303>;
+                       status = "disabled";
+               };
+
+               cmt1: timer@e6130000 {
+                       compatible = "renesas,r8a77965-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6130000 0 0x1004>;
+                       interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 302>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
+                       resets = <&cpg 302>;
+                       status = "disabled";
+               };
+
+               cmt2: timer@e6140000 {
+                       compatible = "renesas,r8a77965-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6140000 0 0x1004>;
+                       interrupts = <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>;
+                       clocks = <&cpg CPG_MOD 301>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
+                       resets = <&cpg 301>;
+                       status = "disabled";
+               };
+
+               cmt3: timer@e6148000 {
+                       compatible = "renesas,r8a77965-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6148000 0 0x1004>;
+                       interrupts = <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>,
+                                    <GIC_SPI 476 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 477 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 300>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
+                       resets = <&cpg 300>;
+                       status = "disabled";
+               };
+
                cpg: clock-controller@e6150000 {
                        compatible = "renesas,r8a77965-cpg-mssr";
                        reg = <0 0xe6150000 0 0x1000>;
                                <0 0xec5a0000 0 0x100>,  /* ADG */
                                <0 0xec540000 0 0x1000>, /* SSIU */
                                <0 0xec541000 0 0x280>,  /* SSI */
-                               <0 0xec740000 0 0x200>;  /* Audio DMAC peri peri*/
+                               <0 0xec760000 0 0x200>;  /* Audio DMAC peri peri*/
                        reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
 
                        clocks = <&cpg CPG_MOD 1005>,
                                };
                        };
 
+                       rcar_sound,ssiu {
+                               ssiu00: ssiu-0 {
+                                       dmas = <&audma0 0x15>, <&audma1 0x16>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu01: ssiu-1 {
+                                       dmas = <&audma0 0x35>, <&audma1 0x36>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu02: ssiu-2 {
+                                       dmas = <&audma0 0x37>, <&audma1 0x38>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu03: ssiu-3 {
+                                       dmas = <&audma0 0x47>, <&audma1 0x48>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu04: ssiu-4 {
+                                       dmas = <&audma0 0x3F>, <&audma1 0x40>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu05: ssiu-5 {
+                                       dmas = <&audma0 0x43>, <&audma1 0x44>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu06: ssiu-6 {
+                                       dmas = <&audma0 0x4F>, <&audma1 0x50>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu07: ssiu-7 {
+                                       dmas = <&audma0 0x53>, <&audma1 0x54>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu10: ssiu-8 {
+                                       dmas = <&audma0 0x49>, <&audma1 0x4a>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu11: ssiu-9 {
+                                       dmas = <&audma0 0x4B>, <&audma1 0x4C>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu12: ssiu-10 {
+                                       dmas = <&audma0 0x57>, <&audma1 0x58>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu13: ssiu-11 {
+                                       dmas = <&audma0 0x59>, <&audma1 0x5A>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu14: ssiu-12 {
+                                       dmas = <&audma0 0x5F>, <&audma1 0x60>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu15: ssiu-13 {
+                                       dmas = <&audma0 0xC3>, <&audma1 0xC4>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu16: ssiu-14 {
+                                       dmas = <&audma0 0xC7>, <&audma1 0xC8>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu17: ssiu-15 {
+                                       dmas = <&audma0 0xCB>, <&audma1 0xCC>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu20: ssiu-16 {
+                                       dmas = <&audma0 0x63>, <&audma1 0x64>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu21: ssiu-17 {
+                                       dmas = <&audma0 0x67>, <&audma1 0x68>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu22: ssiu-18 {
+                                       dmas = <&audma0 0x6B>, <&audma1 0x6C>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu23: ssiu-19 {
+                                       dmas = <&audma0 0x6D>, <&audma1 0x6E>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu24: ssiu-20 {
+                                       dmas = <&audma0 0xCF>, <&audma1 0xCE>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu25: ssiu-21 {
+                                       dmas = <&audma0 0xEB>, <&audma1 0xEC>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu26: ssiu-22 {
+                                       dmas = <&audma0 0xED>, <&audma1 0xEE>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu27: ssiu-23 {
+                                       dmas = <&audma0 0xEF>, <&audma1 0xF0>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu30: ssiu-24 {
+                                       dmas = <&audma0 0x6f>, <&audma1 0x70>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu31: ssiu-25 {
+                                       dmas = <&audma0 0x21>, <&audma1 0x22>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu32: ssiu-26 {
+                                       dmas = <&audma0 0x23>, <&audma1 0x24>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu33: ssiu-27 {
+                                       dmas = <&audma0 0x25>, <&audma1 0x26>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu34: ssiu-28 {
+                                       dmas = <&audma0 0x27>, <&audma1 0x28>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu35: ssiu-29 {
+                                       dmas = <&audma0 0x29>, <&audma1 0x2A>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu36: ssiu-30 {
+                                       dmas = <&audma0 0x2B>, <&audma1 0x2C>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu37: ssiu-31 {
+                                       dmas = <&audma0 0x2D>, <&audma1 0x2E>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu40: ssiu-32 {
+                                       dmas =  <&audma0 0x71>, <&audma1 0x72>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu41: ssiu-33 {
+                                       dmas = <&audma0 0x17>, <&audma1 0x18>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu42: ssiu-34 {
+                                       dmas = <&audma0 0x19>, <&audma1 0x1A>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu43: ssiu-35 {
+                                       dmas = <&audma0 0x1B>, <&audma1 0x1C>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu44: ssiu-36 {
+                                       dmas = <&audma0 0x1D>, <&audma1 0x1E>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu45: ssiu-37 {
+                                       dmas = <&audma0 0x1F>, <&audma1 0x20>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu46: ssiu-38 {
+                                       dmas = <&audma0 0x31>, <&audma1 0x32>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu47: ssiu-39 {
+                                       dmas = <&audma0 0x33>, <&audma1 0x34>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu50: ssiu-40 {
+                                       dmas = <&audma0 0x73>, <&audma1 0x74>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu60: ssiu-41 {
+                                       dmas = <&audma0 0x75>, <&audma1 0x76>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu70: ssiu-42 {
+                                       dmas = <&audma0 0x79>, <&audma1 0x7a>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu80: ssiu-43 {
+                                       dmas = <&audma0 0x7b>, <&audma1 0x7c>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu90: ssiu-44 {
+                                       dmas = <&audma0 0x7d>, <&audma1 0x7e>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu91: ssiu-45 {
+                                       dmas = <&audma0 0x7F>, <&audma1 0x80>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu92: ssiu-46 {
+                                       dmas = <&audma0 0x81>, <&audma1 0x82>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu93: ssiu-47 {
+                                       dmas = <&audma0 0x83>, <&audma1 0x84>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu94: ssiu-48 {
+                                       dmas = <&audma0 0xA3>, <&audma1 0xA4>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu95: ssiu-49 {
+                                       dmas = <&audma0 0xA5>, <&audma1 0xA6>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu96: ssiu-50 {
+                                       dmas = <&audma0 0xA7>, <&audma1 0xA8>;
+                                       dma-names = "rx", "tx";
+                               };
+                               ssiu97: ssiu-51 {
+                                       dmas = <&audma0 0xA9>, <&audma1 0xAA>;
+                                       dma-names = "rx", "tx";
+                               };
+                       };
+
                        rcar_sound,ssi {
                                ssi0: ssi-0 {
                                        interrupts = <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>;
-                                       dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>;
-                                       dma-names = "rx", "tx", "rxu", "txu";
+                                       dmas = <&audma0 0x01>, <&audma1 0x02>;
+                                       dma-names = "rx", "tx";
                                };
                                ssi1: ssi-1 {
                                        interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
-                                       dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>;
-                                       dma-names = "rx", "tx", "rxu", "txu";
+                                       dmas = <&audma0 0x03>, <&audma1 0x04>;
+                                       dma-names = "rx", "tx";
                                };
                                ssi2: ssi-2 {
                                        interrupts = <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>;
-                                       dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>;
-                                       dma-names = "rx", "tx", "rxu", "txu";
+                                       dmas = <&audma0 0x05>, <&audma1 0x06>;
+                                       dma-names = "rx", "tx";
                                };
                                ssi3: ssi-3 {
                                        interrupts = <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>;
-                                       dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>;
-                                       dma-names = "rx", "tx", "rxu", "txu";
+                                       dmas = <&audma0 0x07>, <&audma1 0x08>;
+                                       dma-names = "rx", "tx";
                                };
                                ssi4: ssi-4 {
                                        interrupts = <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>;
-                                       dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>;
-                                       dma-names = "rx", "tx", "rxu", "txu";
+                                       dmas = <&audma0 0x09>, <&audma1 0x0a>;
+                                       dma-names = "rx", "tx";
                                };
                                ssi5: ssi-5 {
                                        interrupts = <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
-                                       dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>;
-                                       dma-names = "rx", "tx", "rxu", "txu";
+                                       dmas = <&audma0 0x0b>, <&audma1 0x0c>;
+                                       dma-names = "rx", "tx";
                                };
                                ssi6: ssi-6 {
                                        interrupts = <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>;
-                                       dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>;
-                                       dma-names = "rx", "tx", "rxu", "txu";
+                                       dmas = <&audma0 0x0d>, <&audma1 0x0e>;
+                                       dma-names = "rx", "tx";
                                };
                                ssi7: ssi-7 {
                                        interrupts = <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>;
-                                       dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>;
-                                       dma-names = "rx", "tx", "rxu", "txu";
+                                       dmas = <&audma0 0x0f>, <&audma1 0x10>;
+                                       dma-names = "rx", "tx";
                                };
                                ssi8: ssi-8 {
                                        interrupts = <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>;
-                                       dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>;
-                                       dma-names = "rx", "tx", "rxu", "txu";
+                                       dmas = <&audma0 0x11>, <&audma1 0x12>;
+                                       dma-names = "rx", "tx";
                                };
                                ssi9: ssi-9 {
                                        interrupts = <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>;
-                                       dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>;
-                                       dma-names = "rx", "tx", "rxu", "txu";
+                                       dmas = <&audma0 0x13>, <&audma1 0x14>;
+                                       dma-names = "rx", "tx";
                                };
                        };
                };
                du: display@feb00000 {
                        compatible = "renesas,du-r8a77965";
                        reg = <0 0xfeb00000 0 0x80000>;
-                       reg-names = "du";
                        interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
index 4081622d548a6b8e49151775fd7e22ce2c9228c4..a901a341dcf71981a435ad5e098fd3d4a8cefea6 100644 (file)
                        clocks = <&cpg CPG_MOD 811>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 811>;
+                       renesas,id = <0>;
                        status = "disabled";
 
                        ports {
                        clocks = <&cpg CPG_MOD 810>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        status = "disabled";
+                       renesas,id = <1>;
                        resets = <&cpg 810>;
 
                        ports {
                        clocks = <&cpg CPG_MOD 809>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 809>;
+                       renesas,id = <2>;
                        status = "disabled";
 
                        ports {
                        clocks = <&cpg CPG_MOD 808>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 808>;
+                       renesas,id = <3>;
                        status = "disabled";
 
                        ports {
                        clocks = <&cpg CPG_MOD 807>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 807>;
+                       renesas,id = <4>;
                        status = "disabled";
 
                        ports {
                        clocks = <&cpg CPG_MOD 806>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 806>;
+                       renesas,id = <5>;
                        status = "disabled";
 
                        ports {
                        clocks = <&cpg CPG_MOD 805>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 805>;
+                       renesas,id = <6>;
                        status = "disabled";
 
                        ports {
                        clocks = <&cpg CPG_MOD 804>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 804>;
+                       renesas,id = <7>;
                        status = "disabled";
 
                        ports {
                        clocks = <&cpg CPG_MOD 628>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 628>;
+                       renesas,id = <8>;
                        status = "disabled";
                };
 
                        clocks = <&cpg CPG_MOD 627>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 627>;
+                       renesas,id = <9>;
                        status = "disabled";
                };
 
                        clocks = <&cpg CPG_MOD 625>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 625>;
+                       renesas,id = <10>;
                        status = "disabled";
                };
 
                        clocks = <&cpg CPG_MOD 618>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 618>;
+                       renesas,id = <11>;
                        status = "disabled";
                };
 
                        clocks = <&cpg CPG_MOD 612>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 612>;
+                       renesas,id = <12>;
                        status = "disabled";
                };
 
                        clocks = <&cpg CPG_MOD 608>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 608>;
+                       renesas,id = <13>;
                        status = "disabled";
                };
 
                        clocks = <&cpg CPG_MOD 605>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 605>;
+                       renesas,id = <14>;
                        status = "disabled";
                };
 
                        clocks = <&cpg CPG_MOD 604>;
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        resets = <&cpg 604>;
+                       renesas,id = <15>;
                        status = "disabled";
                };
 
index 144c0820cf60c73178b43279ca73772c341b7554..c72772589953d04732207639c2cf24ded3a72a6b 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Device Tree Source for the ebisu board
  *
@@ -19,7 +19,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
                stdout-path = "serial0:115200n8";
        };
 
 &i2c0 {
        status = "okay";
 
+       io_expander: gpio@20 {
+               compatible = "onnn,pca9654";
+               reg = <0x20>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               interrupt-parent = <&gpio2>;
+               interrupts = <22 IRQ_TYPE_LEVEL_LOW>;
+       };
+
        hdmi-encoder@39 {
                compatible = "adi,adv7511w";
                reg = <0x39>;
                };
 
                port@a {
-                       reg = <0xa>;
+                       reg = <10>;
 
                        adv7482_txa: endpoint {
                                clock-lanes = <0>;
        };
 };
 
+&i2c_dvfs {
+       status = "okay";
+
+       clock-frequency = <400000>;
+
+       pmic: pmic@30 {
+               pinctrl-0 = <&irq0_pins>;
+               pinctrl-names = "default";
+
+               compatible = "rohm,bd9571mwv";
+               reg = <0x30>;
+               interrupt-parent = <&intc_ex>;
+               interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               rohm,ddr-backup-power = <0x1>;
+               rohm,rstbmode-level;
+       };
+};
+
 &lvds0 {
        status = "okay";
 
 };
 
 &lvds1 {
+       /*
+        * Even though the LVDS1 output is not connected, the encoder must be
+        * enabled to supply a pixel clock to the DU for the DPAD output when
+        * LVDS0 is in use.
+        */
+       status = "okay";
+
        clocks = <&cpg CPG_MOD 727>,
                 <&x13_clk>,
                 <&extal_clk>;
                function = "du";
        };
 
+       irq0_pins: irq0 {
+               groups = "intc_ex_irq0";
+               function = "intc_ex";
+       };
+
        pwm3_pins: pwm3 {
                groups = "pwm3_b";
                function = "pwm3";
        status = "okay";
 };
 
+&vin5 {
+       status = "okay";
+};
+
 &xhci0 {
        pinctrl-0 = <&usb30_pins>;
        pinctrl-names = "default";
index d2ad665fe2d925db040e50d2d9341b5535ddd167..56cb566ffa097d24d980f1b7e989c61963882d40 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Device Tree Source for the R-Car E3 (R8A77990) SoC
  *
                        status = "disabled";
                };
 
+               cmt0: timer@e60f0000 {
+                       compatible = "renesas,r8a77990-cmt0",
+                                    "renesas,rcar-gen3-cmt0";
+                       reg = <0 0xe60f0000 0 0x1004>;
+                       interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 303>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
+                       resets = <&cpg 303>;
+                       status = "disabled";
+               };
+
+               cmt1: timer@e6130000 {
+                       compatible = "renesas,r8a77990-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6130000 0 0x1004>;
+                       interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 302>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
+                       resets = <&cpg 302>;
+                       status = "disabled";
+               };
+
+               cmt2: timer@e6140000 {
+                       compatible = "renesas,r8a77990-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6140000 0 0x1004>;
+                       interrupts = <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>;
+                       clocks = <&cpg CPG_MOD 301>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
+                       resets = <&cpg 301>;
+                       status = "disabled";
+               };
+
+               cmt3: timer@e6148000 {
+                       compatible = "renesas,r8a77990-cmt1",
+                                    "renesas,rcar-gen3-cmt1";
+                       reg = <0 0xe6148000 0 0x1004>;
+                       interrupts = <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>,
+                                    <GIC_SPI 476 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 477 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 300>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
+                       resets = <&cpg 300>;
+                       status = "disabled";
+               };
+
                cpg: clock-controller@e6150000 {
                        compatible = "renesas,r8a77990-cpg-mssr";
                        reg = <0 0xe6150000 0 0x1000>;
                };
 
                csi40: csi2@feaa0000 {
-                       compatible = "renesas,r8a77990-csi2", "renesas,rcar-gen3-csi2";
+                       compatible = "renesas,r8a77990-csi2";
                        reg = <0 0xfeaa0000 0 0x10000>;
                        interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 716>;
index db2bed1751b8d308c814fc25c4e96000a819a6f1..a7dc11e36fd9d0cf9093f378d28c104486ac9b99 100644 (file)
@@ -20,7 +20,7 @@
        };
 
        chosen {
-               bootargs = "ignore_loglevel";
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
                stdout-path = "serial0:115200n8";
        };
 
        pinctrl-names = "default";
        renesas,no-ether-link;
        phy-handle = <&phy0>;
-       phy-mode = "rgmii-txid";
        status = "okay";
 
        phy0: ethernet-phy@0 {
        };
 };
 
+&can0 {
+       pinctrl-0 = <&can0_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&can1 {
+       pinctrl-0 = <&can1_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
 &du {
        pinctrl-0 = <&du_pins>;
        pinctrl-names = "default";
 };
 
 &lvds1 {
+       /*
+        * Even though the LVDS1 output is not connected, the encoder must be
+        * enabled to supply a pixel clock to the DU for the DPAD output when
+        * LVDS0 is in use.
+        */
+       status = "okay";
+
        clocks = <&cpg CPG_MOD 727>,
                 <&x12_clk>,
                 <&extal_clk>;
                };
        };
 
+       can0_pins: can0 {
+               groups = "can0_data_a";
+               function = "can0";
+       };
+
+       can1_pins: can1 {
+               groups = "can1_data_a";
+               function = "can1";
+       };
+
        du_pins: du {
                groups = "du_rgb888", "du_sync", "du_disp", "du_clk_out_0";
                function = "du";
index a225c2457274763fd558ad3aa72153c228afa51a..2dba1328acfaa9dd997f57f87a28cb59b8ce9bb9 100644 (file)
@@ -29,6 +29,7 @@
  */
 
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 
 / {
        aliases {
                };
        };
 
+       keys {
+               compatible = "gpio-keys";
+
+               pinctrl-0 = <&keys_pins>;
+               pinctrl-names = "default";
+
+               key-1 {
+                       gpios = <&gpio5 17 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_1>;
+                       label = "SW4-1";
+                       wakeup-source;
+                       debounce-interval = <20>;
+               };
+               key-2 {
+                       gpios = <&gpio5 20 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_2>;
+                       label = "SW4-2";
+                       wakeup-source;
+                       debounce-interval = <20>;
+               };
+               key-3 {
+                       gpios = <&gpio5 22 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_3>;
+                       label = "SW4-3";
+                       wakeup-source;
+                       debounce-interval = <20>;
+               };
+               key-4 {
+                       gpios = <&gpio5 23 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_4>;
+                       label = "SW4-4";
+                       wakeup-source;
+                       debounce-interval = <20>;
+               };
+               key-a {
+                       gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_A>;
+                       label = "TSW0";
+                       wakeup-source;
+                       debounce-interval = <20>;
+               };
+               key-b {
+                       gpios = <&gpio6 12 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_B>;
+                       label = "TSW1";
+                       wakeup-source;
+                       debounce-interval = <20>;
+               };
+               key-c {
+                       gpios = <&gpio6 13 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_C>;
+                       label = "TSW2";
+                       wakeup-source;
+                       debounce-interval = <20>;
+               };
+       };
+
        reg_1p8v: regulator0 {
                compatible = "regulator-fixed";
                regulator-name = "fixed-1.8V";
                function = "intc_ex";
        };
 
+       keys_pins: keys {
+               pins = "GP_5_17", "GP_5_20", "GP_5_22";
+               bias-pull-up;
+       };
+
        pwm1_pins: pwm1 {
                groups = "pwm1_a";
                function = "pwm1";
        };
 };
 
+&rwdt {
+       timeout-sec = <60>;
+       status = "okay";
+};
+
 &scif1 {
        pinctrl-0 = <&scif1_pins>;
        pinctrl-names = "default";
        status = "okay";
 };
 
-&rwdt {
-       timeout-sec = <60>;
-       status = "okay";
-};
-
 &xhci0 {
        pinctrl-0 = <&usb30_pins>;
        pinctrl-names = "default";
index 1b28fa72ea0b2e962ac15d3c3f9dc4f1e6a5fbc9..5f2687acbf9433b4f291987f814ede0634f5d314 100644 (file)
@@ -18,6 +18,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-gru-scarlet-inx.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-gru-scarlet-kd.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopc-t4.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-m4.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-neo4.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-orangepi.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-puma-haikou.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-roc-pc.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-rock-pi-4.dtb
index 263d7f3dbc443fe86fca28aab8d48bbd86b32a55..6eb7407a84aac0f15c296cf173a24ee5f8eb274d 100644 (file)
 
                soc_slppin_slp: soc_slppin_slp {
                        rockchip,pins =
-                               <0 RK_PA4 RK_FUNC_1 &pcfg_pull_none>;
+                               <0 RK_PA4 1 &pcfg_pull_none>;
                };
 
                soc_slppin_rst: soc_slppin_rst {
                        rockchip,pins =
-                               <0 RK_PA4 RK_FUNC_2 &pcfg_pull_none>;
+                               <0 RK_PA4 2 &pcfg_pull_none>;
                };
        };
 
index 8302d86d35c4a77704dfb9d3b3f3209c124b7b89..49c4b96da3d4038799871db0cb208ef654d24c14 100644 (file)
        sdio-pwrseq {
                wifi_enable_h: wifi-enable-h {
                rockchip,pins =
-                       <1 18 RK_FUNC_GPIO &pcfg_pull_none>;
+                       <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 0e34354b20927698482fddaf6814483394a18b93..5d499c9086fbddc79bf763d839d05fa8855d4706 100644 (file)
                regulator-always-on;
                regulator-boot-on;
        };
+
+       leds {
+               compatible = "gpio-leds";
+
+               power {
+                       label = "firefly:blue:power";
+                       linux,default-trigger = "heartbeat";
+                       gpios = <&rk805 1 GPIO_ACTIVE_LOW>;
+                       default-state = "on";
+                       mode = <0x23>;
+               };
+
+               user {
+                       label = "firefly:yellow:user";
+                       linux,default-trigger = "mmc1";
+                       gpios = <&rk805 0 GPIO_ACTIVE_LOW>;
+                       default-state = "off";
+                       mode = <0x05>;
+               };
+       };
 };
 
 &cpu0 {
        cpu-supply = <&vdd_arm>;
 };
 
+&cpu1 {
+       cpu-supply = <&vdd_arm>;
+};
+
+&cpu2 {
+       cpu-supply = <&vdd_arm>;
+};
+
+&cpu3 {
+       cpu-supply = <&vdd_arm>;
+};
+
 &emmc {
        bus-width = <8>;
        cap-mmc-highspeed;
+       max-frequency = <150000000>;
+       mmc-ddr-1_8v;
+       mmc-hs200-1_8v;
        non-removable;
        pinctrl-names = "default";
        pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>;
+       vmmc-supply = <&vcc_io>;
+       vqmmc-supply = <&vcc18_emmc>;
        status = "okay";
 };
 
        status = "okay";
 };
 
+&hdmi {
+       status = "okay";
+};
+
+&hdmiphy {
+       status = "okay";
+};
+
 &i2c1 {
        status = "okay";
 
 &usb_host0_ohci {
        status = "okay";
 };
+
+&vop {
+       status = "okay";
+};
+
+&vop_mmu {
+       status = "okay";
+};
index 79b4d1d4b5d6b67672dcbab1de19d274cecd5c5b..7cfd5ca6cc858259cc37142e459ea38c49b56335 100644 (file)
                regulator-max-microvolt = <5000000>;
        };
 
+       ir-receiver {
+               compatible = "gpio-ir-receiver";
+               gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>;
+               pinctrl-0 = <&ir_int>;
+               pinctrl-names = "default";
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               power {
+                       gpios = <&rk805 1 GPIO_ACTIVE_LOW>;
+                       linux,default-trigger = "mmc0";
+               };
+
+               standby {
+                       gpios = <&rk805 0 GPIO_ACTIVE_LOW>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
        sound {
                compatible = "audio-graph-card";
                label = "rockchip,rk3328";
                interrupts = <6 IRQ_TYPE_LEVEL_LOW>;
                #clock-cells = <1>;
                clock-output-names = "xin32k", "rk805-clkout2";
+               gpio-controller;
+               #gpio-cells = <2>;
                pinctrl-names = "default";
                pinctrl-0 = <&pmic_int_l>;
                rockchip,system-power-controller;
                        };
 
                        vcc_18: LDO_REG1 {
-                               regulator-name = "vdd_18";
+                               regulator-name = "vcc_18";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
                        };
 
                        vcc18_emmc: LDO_REG2 {
-                               regulator-name = "vcc_18emmc";
+                               regulator-name = "vcc18_emmc";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
 };
 
 &pinctrl {
+       ir {
+               ir_int: ir-int {
+                       rockchip,pins = <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
        pmic {
                pmic_int_l: pmic-int-l {
                        rockchip,pins = <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
index dabef1a21649ba44ee4b880d83d9b24591ac1d9d..994468671b19dd3c3895f20734c1308874888a90 100644 (file)
                interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru PCLK_HDMI>,
-                        <&cru SCLK_HDMI_SFC>;
+                        <&cru SCLK_HDMI_SFC>,
+                        <&cru SCLK_RTC32K>;
                clock-names = "iahb",
-                             "isfr";
+                             "isfr",
+                             "cec";
                phys = <&hdmiphy>;
                phy-names = "hdmi";
                pinctrl-names = "default";
                pinctrl-0 = <&hdmi_cec &hdmii2c_xfer &hdmi_hpd>;
                rockchip,grf = <&grf>;
+               #sound-dai-cells = <0>;
                status = "disabled";
 
                ports {
index e96eb62f362ba3c3cdd1fae15dfac4ec3f7606b9..1c52f47c43a68d5ade56d994ba228069d0b875fd 100644 (file)
 
        backlight {
                bl_en: bl-en {
-                       rockchip,pins = <0 20 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        emmc {
                emmc_bus8: emmc-bus8 {
-                       rockchip,pins = <1 18 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 19 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 20 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 21 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 22 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 23 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 24 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 25 RK_FUNC_2 &pcfg_pull_up_drv_8ma>;
+                       rockchip,pins = <1 RK_PC2 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC3 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC4 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC5 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC6 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC7 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PD0 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PD1 2 &pcfg_pull_up_drv_8ma>;
                };
 
                emmc-clk {
-                       rockchip,pins = <2 4 RK_FUNC_2 &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <2 RK_PA4 2 &pcfg_pull_none_drv_8ma>;
                };
 
                emmc-cmd {
-                       rockchip,pins = <1 26 RK_FUNC_2 &pcfg_pull_up_drv_8ma>;
+                       rockchip,pins = <1 RK_PD2 2 &pcfg_pull_up_drv_8ma>;
                };
 
                emmc_reset: emmc-reset {
-                       rockchip,pins = <2 3 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        keys {
                pwr_key: pwr-key {
-                       rockchip,pins = <0 2 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        pmic {
                pmic_int: pmic-int {
-                       rockchip,pins = <0 1 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        sdio {
                wifi_reg_on: wifi-reg-on {
-                       rockchip,pins = <3 4 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                bt_rst: bt-rst {
-                       rockchip,pins = <3 5 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        usb {
                host_vbus_drv: host-vbus-drv {
-                       rockchip,pins = <0 4 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 8fa550cbd1a4a5498008da976deffee2b6d9230b..1d0778ff217c118f092d0d5c2c7de3ff5d21e0a0 100644 (file)
 &pinctrl {
        ir {
                ir_int: ir-int {
-                       rockchip,pins = <3 30 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <3 RK_PD6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        keys {
                pwr_key: pwr-key {
-                       rockchip,pins = <0 2 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        pmic {
                pmic_sleep: pmic-sleep {
-                       rockchip,pins = <0 0 RK_FUNC_2 &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PA0 2 &pcfg_pull_none>;
                };
 
                pmic_int: pmic-int {
-                       rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 };
index fca8e87d8f52626fff2ecedaff2a4f3e931b4cd5..8251f3c0d0a8edb68c8eb07d4cf95e575da095f1 100644 (file)
                haikou_pin_hog: haikou-pin-hog {
                        rockchip,pins =
                                /* LID_BTN */
-                               <RK_GPIO3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>,
+                               <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>,
                                /* BATLOW# */
-                               <RK_GPIO0 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>,
+                               <0 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>,
                                /* SLP_BTN# */
-                               <RK_GPIO3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>,
+                               <3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>,
                                /* BIOS_DISABLE# */
-                               <RK_GPIO3 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
+                               <3 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        leds {
                led_sd_haikou: led-sd-gpio {
                        rockchip,pins =
-                               <RK_GPIO0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        sdmmc {
                sdmmc_cd_gpio: sdmmc-cd-gpio {
                        rockchip,pins =
-                               <RK_GPIO2 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <2 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        usb_otg {
                otg_vbus_drv: otg-vbus-drv {
                        rockchip,pins =
-                               <RK_GPIO0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 1b35d612b66053ed96043f0837e894c2d8b333d5..e17311e090826abf9b2ca73cebbc500d17a2aa7c 100644 (file)
@@ -56,8 +56,6 @@
                        fan: fan@18 {
                                compatible = "ti,amc6821";
                                reg = <0x18>;
-                               cooling-min-state = <0>;
-                               cooling-max-state = <9>;
                                #cooling-cells = <2>;
                        };
 
        leds {
                led_pins_module: led-module-gpio {
                        rockchip,pins =
-                               <RK_GPIO2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>,
-                               <RK_GPIO3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>,
+                               <3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
        pmic {
                pmic_int_l: pmic-int-l {
-                       rockchip,pins = <RK_GPIO0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                pmic_sleep: pmic-sleep {
-                       rockchip,pins = <RK_GPIO0 RK_PA0 RK_FUNC_2 &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PA0 2 &pcfg_pull_none>;
                };
        };
 };
index f5aa3cad67c5c22b826009930368fff37dba25f7..6cc310255da876311d8c434c93f1fced22e9474e 100644 (file)
 
        emmc {
                emmc_bus8: emmc-bus8 {
-                       rockchip,pins = <1 18 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 19 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 20 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 21 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 22 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 23 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 24 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 25 RK_FUNC_2 &pcfg_pull_up_drv_8ma>;
+                       rockchip,pins = <1 RK_PC2 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC3 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC4 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC5 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC6 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC7 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PD0 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PD1 2 &pcfg_pull_up_drv_8ma>;
                };
 
                emmc-clk {
-                       rockchip,pins = <2 4 RK_FUNC_2 &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <2 RK_PA4 2 &pcfg_pull_none_drv_8ma>;
                };
 
                emmc-cmd {
-                       rockchip,pins = <1 26 RK_FUNC_2 &pcfg_pull_up_drv_8ma>;
+                       rockchip,pins = <1 RK_PD2 2 &pcfg_pull_up_drv_8ma>;
                };
 
                emmc_reset: emmc-reset {
-                       rockchip,pins = <2 3 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        keys {
                pwr_key: pwr-key {
-                       rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>;
                };
        };
 
        leds {
                stby_pwren: stby-pwren {
-                       rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                led_ctl: led-ctl {
-                       rockchip,pins = <3 29 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <3 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        sdmmc {
                sdmmc_clk: sdmmc-clk {
-                       rockchip,pins = <2 9 RK_FUNC_1 &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <2 RK_PB1 1 &pcfg_pull_none_drv_8ma>;
                };
 
                sdmmc_cmd: sdmmc-cmd {
-                       rockchip,pins = <2 10 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
+                       rockchip,pins = <2 RK_PB2 1 &pcfg_pull_up_drv_8ma>;
                };
 
                sdmmc_cd: sdmmc-cd {
-                       rockchip,pins = <2 11 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
+                       rockchip,pins = <2 RK_PB3 1 &pcfg_pull_up_drv_8ma>;
                };
 
                sdmmc_bus1: sdmmc-bus1 {
-                       rockchip,pins = <2 5 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
+                       rockchip,pins = <2 RK_PA5 1 &pcfg_pull_up_drv_8ma>;
                };
 
                sdmmc_bus4: sdmmc-bus4 {
-                       rockchip,pins = <2 5 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
-                                       <2 6 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
-                                       <2 7 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
-                                       <2 8 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
+                       rockchip,pins = <2 RK_PA5 1 &pcfg_pull_up_drv_8ma>,
+                                       <2 RK_PA6 1 &pcfg_pull_up_drv_8ma>,
+                                       <2 RK_PA7 1 &pcfg_pull_up_drv_8ma>,
+                                       <2 RK_PB0 1 &pcfg_pull_up_drv_8ma>;
                };
        };
 
        usb {
                host_vbus_drv: host-vbus-drv {
-                       rockchip,pins = <0 4 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 41edcfd531843b4cfa8de248c55fa5801fbde34b..231db0305a03759696d2edb650c7f41332224384 100644 (file)
 &pinctrl {
        keys {
                pwr_key: pwr-key {
-                       rockchip,pins = <0 2 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        pmic {
                pmic_sleep: pmic-sleep {
-                       rockchip,pins = <0 0 RK_FUNC_2 &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PA0 2 &pcfg_pull_none>;
                };
 
                pmic_int: pmic-int {
-                       rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 };
index d34064c65f10721115925108cc827315e3b412c3..006a1fb6a816522c590ebf119546cefce2c8be86 100644 (file)
 
        emmc {
                emmc_bus8: emmc-bus8 {
-                       rockchip,pins = <1 18 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 19 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 20 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 21 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 22 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 23 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 24 RK_FUNC_2 &pcfg_pull_up_drv_8ma>,
-                                       <1 25 RK_FUNC_2 &pcfg_pull_up_drv_8ma>;
+                       rockchip,pins = <1 RK_PC2 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC3 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC4 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC5 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC6 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PC7 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PD0 2 &pcfg_pull_up_drv_8ma>,
+                                       <1 RK_PD1 2 &pcfg_pull_up_drv_8ma>;
                };
 
                emmc-clk {
-                       rockchip,pins = <2 4 RK_FUNC_2 &pcfg_pull_none_drv_8ma>;
+                       rockchip,pins = <2 RK_PA4 2 &pcfg_pull_none_drv_8ma>;
                };
 
                emmc-cmd {
-                       rockchip,pins = <1 26 RK_FUNC_2 &pcfg_pull_up_drv_8ma>;
+                       rockchip,pins = <1 RK_PD2 2 &pcfg_pull_up_drv_8ma>;
                };
 
                emmc_reset: emmc-reset {
-                       rockchip,pins = <2 3 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        ir {
                ir_int: ir-int {
-                       rockchip,pins = <3 30 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <3 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        keys {
                pwr_key: pwr-key {
-                       rockchip,pins = <0 2 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        leds {
                stby_pwren: stby-pwren {
-                       rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                led_ctl: led-ctl {
-                       rockchip,pins = <3 29 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <3 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        sdio {
                wifi_reg_on: wifi-reg-on {
-                       rockchip,pins = <3 4 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                bt_rst: bt-rst {
-                       rockchip,pins = <3 5 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        usb {
                host_vbus_drv: host-vbus-drv {
-                       rockchip,pins = <0 4 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 06e7c31d7d07a9965dcb6fbab59c0c736f787e36..fd86188010b292c98aa5a40ba5784a9db1633e3f 100644 (file)
 
                emmc {
                        emmc_clk: emmc-clk {
-                               rockchip,pins = <2 4 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PA4 2 &pcfg_pull_none>;
                        };
 
                        emmc_cmd: emmc-cmd {
-                               rockchip,pins = <1 26 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PD2 2 &pcfg_pull_up>;
                        };
 
                        emmc_pwr: emmc-pwr {
-                               rockchip,pins = <1 27 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PD3 2 &pcfg_pull_up>;
                        };
 
                        emmc_bus1: emmc-bus1 {
-                               rockchip,pins = <1 18 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PC2 2 &pcfg_pull_up>;
                        };
 
                        emmc_bus4: emmc-bus4 {
-                               rockchip,pins = <1 18 RK_FUNC_2 &pcfg_pull_up>,
-                                               <1 19 RK_FUNC_2 &pcfg_pull_up>,
-                                               <1 20 RK_FUNC_2 &pcfg_pull_up>,
-                                               <1 21 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PC2 2 &pcfg_pull_up>,
+                                               <1 RK_PC3 2 &pcfg_pull_up>,
+                                               <1 RK_PC4 2 &pcfg_pull_up>,
+                                               <1 RK_PC5 2 &pcfg_pull_up>;
                        };
 
                        emmc_bus8: emmc-bus8 {
-                               rockchip,pins = <1 18 RK_FUNC_2 &pcfg_pull_up>,
-                                               <1 19 RK_FUNC_2 &pcfg_pull_up>,
-                                               <1 20 RK_FUNC_2 &pcfg_pull_up>,
-                                               <1 21 RK_FUNC_2 &pcfg_pull_up>,
-                                               <1 22 RK_FUNC_2 &pcfg_pull_up>,
-                                               <1 23 RK_FUNC_2 &pcfg_pull_up>,
-                                               <1 24 RK_FUNC_2 &pcfg_pull_up>,
-                                               <1 25 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PC2 2 &pcfg_pull_up>,
+                                               <1 RK_PC3 2 &pcfg_pull_up>,
+                                               <1 RK_PC4 2 &pcfg_pull_up>,
+                                               <1 RK_PC5 2 &pcfg_pull_up>,
+                                               <1 RK_PC6 2 &pcfg_pull_up>,
+                                               <1 RK_PC7 2 &pcfg_pull_up>,
+                                               <1 RK_PD0 2 &pcfg_pull_up>,
+                                               <1 RK_PD1 2 &pcfg_pull_up>;
                        };
                };
 
                gmac {
                        rgmii_pins: rgmii-pins {
-                               rockchip,pins = <3 22 RK_FUNC_1 &pcfg_pull_none>,
-                                               <3 24 RK_FUNC_1 &pcfg_pull_none>,
-                                               <3 19 RK_FUNC_1 &pcfg_pull_none>,
-                                               <3 8 RK_FUNC_1 &pcfg_pull_none_12ma>,
-                                               <3 9 RK_FUNC_1 &pcfg_pull_none_12ma>,
-                                               <3 10 RK_FUNC_1 &pcfg_pull_none_12ma>,
-                                               <3 14 RK_FUNC_1 &pcfg_pull_none_12ma>,
-                                               <3 28 RK_FUNC_1 &pcfg_pull_none_12ma>,
-                                               <3 13 RK_FUNC_1 &pcfg_pull_none_12ma>,
-                                               <3 15 RK_FUNC_1 &pcfg_pull_none>,
-                                               <3 16 RK_FUNC_1 &pcfg_pull_none>,
-                                               <3 17 RK_FUNC_1 &pcfg_pull_none>,
-                                               <3 18 RK_FUNC_1 &pcfg_pull_none>,
-                                               <3 25 RK_FUNC_1 &pcfg_pull_none>,
-                                               <3 20 RK_FUNC_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>,
+                                               <3 RK_PB1 1 &pcfg_pull_none_12ma>,
+                                               <3 RK_PB2 1 &pcfg_pull_none_12ma>,
+                                               <3 RK_PB6 1 &pcfg_pull_none_12ma>,
+                                               <3 RK_PD4 1 &pcfg_pull_none_12ma>,
+                                               <3 RK_PB5 1 &pcfg_pull_none_12ma>,
+                                               <3 RK_PB7 1 &pcfg_pull_none>,
+                                               <3 RK_PC0 1 &pcfg_pull_none>,
+                                               <3 RK_PC1 1 &pcfg_pull_none>,
+                                               <3 RK_PC2 1 &pcfg_pull_none>,
+                                               <3 RK_PD1 1 &pcfg_pull_none>,
+                                               <3 RK_PC4 1 &pcfg_pull_none>;
                        };
 
                        rmii_pins: rmii-pins {
-                               rockchip,pins = <3 22 RK_FUNC_1 &pcfg_pull_none>,
-                                               <3 24 RK_FUNC_1 &pcfg_pull_none>,
-                                               <3 19 RK_FUNC_1 &pcfg_pull_none>,
-                                               <3 8 RK_FUNC_1 &pcfg_pull_none_12ma>,
-                                               <3 9 RK_FUNC_1 &pcfg_pull_none_12ma>,
-                                               <3 13 RK_FUNC_1 &pcfg_pull_none_12ma>,
-                                               <3 15 RK_FUNC_1 &pcfg_pull_none>,
-                                               <3 16 RK_FUNC_1 &pcfg_pull_none>,
-                                               <3 20 RK_FUNC_1 &pcfg_pull_none>,
-                                               <3 21 RK_FUNC_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>,
+                                               <3 RK_PB1 1 &pcfg_pull_none_12ma>,
+                                               <3 RK_PB5 1 &pcfg_pull_none_12ma>,
+                                               <3 RK_PB7 1 &pcfg_pull_none>,
+                                               <3 RK_PC0 1 &pcfg_pull_none>,
+                                               <3 RK_PC4 1 &pcfg_pull_none>,
+                                               <3 RK_PC5 1 &pcfg_pull_none>;
                        };
                };
 
                i2c0 {
                        i2c0_xfer: i2c0-xfer {
-                               rockchip,pins = <0 6 RK_FUNC_1 &pcfg_pull_none>,
-                                               <0 7 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA6 1 &pcfg_pull_none>,
+                                               <0 RK_PA7 1 &pcfg_pull_none>;
                        };
                };
 
                i2c1 {
                        i2c1_xfer: i2c1-xfer {
-                               rockchip,pins = <2 21 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 22 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PC5 1 &pcfg_pull_none>,
+                                               <2 RK_PC6 1 &pcfg_pull_none>;
                        };
                };
 
                i2c2 {
                        i2c2_xfer: i2c2-xfer {
-                               rockchip,pins = <0 9 RK_FUNC_2 &pcfg_pull_none>,
-                                               <3 31 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PB1 2 &pcfg_pull_none>,
+                                               <3 RK_PD7 2 &pcfg_pull_none>;
                        };
                };
 
                i2c3 {
                        i2c3_xfer: i2c3-xfer {
-                               rockchip,pins = <1 16 RK_FUNC_1 &pcfg_pull_none>,
-                                               <1 17 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PC0 1 &pcfg_pull_none>,
+                                               <1 RK_PC1 1 &pcfg_pull_none>;
                        };
                };
 
                i2c4 {
                        i2c4_xfer: i2c4-xfer {
-                               rockchip,pins = <3 24 RK_FUNC_2 &pcfg_pull_none>,
-                                               <3 25 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PD0 2 &pcfg_pull_none>,
+                                               <3 RK_PD1 2 &pcfg_pull_none>;
                        };
                };
 
                i2c5 {
                        i2c5_xfer: i2c5-xfer {
-                               rockchip,pins = <3 26 RK_FUNC_2 &pcfg_pull_none>,
-                                               <3 27 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PD2 2 &pcfg_pull_none>,
+                                               <3 RK_PD3 2 &pcfg_pull_none>;
                        };
                };
 
                i2s {
                        i2s_8ch_bus: i2s-8ch-bus {
-                               rockchip,pins = <2 12 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 13 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 14 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 15 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 16 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 17 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 18 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 19 RK_FUNC_1 &pcfg_pull_none>,
-                                               <2 20 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PB4 1 &pcfg_pull_none>,
+                                               <2 RK_PB5 1 &pcfg_pull_none>,
+                                               <2 RK_PB6 1 &pcfg_pull_none>,
+                                               <2 RK_PB7 1 &pcfg_pull_none>,
+                                               <2 RK_PC0 1 &pcfg_pull_none>,
+                                               <2 RK_PC1 1 &pcfg_pull_none>,
+                                               <2 RK_PC2 1 &pcfg_pull_none>,
+                                               <2 RK_PC3 1 &pcfg_pull_none>,
+                                               <2 RK_PC4 1 &pcfg_pull_none>;
                        };
                };
 
                pwm0 {
                        pwm0_pin: pwm0-pin {
-                               rockchip,pins = <3 8 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PB0 2 &pcfg_pull_none>;
                        };
                };
 
                pwm1 {
                        pwm1_pin: pwm1-pin {
-                               rockchip,pins = <0 8 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PB0 2 &pcfg_pull_none>;
                        };
                };
 
                pwm3 {
                        pwm3_pin: pwm3-pin {
-                               rockchip,pins = <3 29 RK_FUNC_3 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PD5 3 &pcfg_pull_none>;
                        };
                };
 
                sdio0 {
                        sdio0_bus1: sdio0-bus1 {
-                               rockchip,pins = <2 28 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <2 RK_PD4 1 &pcfg_pull_up>;
                        };
 
                        sdio0_bus4: sdio0-bus4 {
-                               rockchip,pins = <2 28 RK_FUNC_1 &pcfg_pull_up>,
-                                               <2 29 RK_FUNC_1 &pcfg_pull_up>,
-                                               <2 30 RK_FUNC_1 &pcfg_pull_up>,
-                                               <2 31 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <2 RK_PD4 1 &pcfg_pull_up>,
+                                               <2 RK_PD5 1 &pcfg_pull_up>,
+                                               <2 RK_PD6 1 &pcfg_pull_up>,
+                                               <2 RK_PD7 1 &pcfg_pull_up>;
                        };
 
                        sdio0_cmd: sdio0-cmd {
-                               rockchip,pins = <3 0 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PA0 1 &pcfg_pull_up>;
                        };
 
                        sdio0_clk: sdio0-clk {
-                               rockchip,pins = <3 1 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PA1 1 &pcfg_pull_none>;
                        };
 
                        sdio0_cd: sdio0-cd {
-                               rockchip,pins = <3 2 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PA2 1 &pcfg_pull_up>;
                        };
 
                        sdio0_wp: sdio0-wp {
-                               rockchip,pins = <3 3 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PA3 1 &pcfg_pull_up>;
                        };
 
                        sdio0_pwr: sdio0-pwr {
-                               rockchip,pins = <3 4 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PA4 1 &pcfg_pull_up>;
                        };
 
                        sdio0_bkpwr: sdio0-bkpwr {
-                               rockchip,pins = <3 5 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PA5 1 &pcfg_pull_up>;
                        };
 
                        sdio0_int: sdio0-int {
-                               rockchip,pins = <3 6 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PA6 1 &pcfg_pull_up>;
                        };
                };
 
                sdmmc {
                        sdmmc_clk: sdmmc-clk {
-                               rockchip,pins = <2 9 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PB1 1 &pcfg_pull_none>;
                        };
 
                        sdmmc_cmd: sdmmc-cmd {
-                               rockchip,pins = <2 10 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <2 RK_PB2 1 &pcfg_pull_up>;
                        };
 
                        sdmmc_cd: sdmmc-cd {
-                               rockchip,pins = <2 11 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <2 RK_PB3 1 &pcfg_pull_up>;
                        };
 
                        sdmmc_bus1: sdmmc-bus1 {
-                               rockchip,pins = <2 5 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <2 RK_PA5 1 &pcfg_pull_up>;
                        };
 
                        sdmmc_bus4: sdmmc-bus4 {
-                               rockchip,pins = <2 5 RK_FUNC_1 &pcfg_pull_up>,
-                                               <2 6 RK_FUNC_1 &pcfg_pull_up>,
-                                               <2 7 RK_FUNC_1 &pcfg_pull_up>,
-                                               <2 8 RK_FUNC_1 &pcfg_pull_up>;
+                               rockchip,pins = <2 RK_PA5 1 &pcfg_pull_up>,
+                                               <2 RK_PA6 1 &pcfg_pull_up>,
+                                               <2 RK_PA7 1 &pcfg_pull_up>,
+                                               <2 RK_PB0 1 &pcfg_pull_up>;
                        };
                };
 
                spdif {
                        spdif_tx: spdif-tx {
-                               rockchip,pins = <2 RK_PC7 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PC7 1 &pcfg_pull_none>;
                        };
                };
 
                spi0 {
                        spi0_clk: spi0-clk {
-                               rockchip,pins = <1 29 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PD5 2 &pcfg_pull_up>;
                        };
                        spi0_cs0: spi0-cs0 {
-                               rockchip,pins = <1 24 RK_FUNC_3 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PD0 3 &pcfg_pull_up>;
                        };
                        spi0_cs1: spi0-cs1 {
-                               rockchip,pins = <1 25 RK_FUNC_3 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PD1 3 &pcfg_pull_up>;
                        };
                        spi0_tx: spi0-tx {
-                               rockchip,pins = <1 23 RK_FUNC_3 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PC7 3 &pcfg_pull_up>;
                        };
                        spi0_rx: spi0-rx {
-                               rockchip,pins = <1 22 RK_FUNC_3 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PC6 3 &pcfg_pull_up>;
                        };
                };
 
                spi1 {
                        spi1_clk: spi1-clk {
-                               rockchip,pins = <1 14 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PB6 2 &pcfg_pull_up>;
                        };
                        spi1_cs0: spi1-cs0 {
-                               rockchip,pins = <1 15 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PB7 2 &pcfg_pull_up>;
                        };
                        spi1_cs1: spi1-cs1 {
-                               rockchip,pins = <3 28 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <3 RK_PD4 2 &pcfg_pull_up>;
                        };
                        spi1_rx: spi1-rx {
-                               rockchip,pins = <1 16 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PC0 2 &pcfg_pull_up>;
                        };
                        spi1_tx: spi1-tx {
-                               rockchip,pins = <1 17 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <1 RK_PC1 2 &pcfg_pull_up>;
                        };
                };
 
                spi2 {
                        spi2_clk: spi2-clk {
-                               rockchip,pins = <0 12 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PB4 2 &pcfg_pull_up>;
                        };
                        spi2_cs0: spi2-cs0 {
-                               rockchip,pins = <0 13 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PB5 2 &pcfg_pull_up>;
                        };
                        spi2_rx: spi2-rx {
-                               rockchip,pins = <0 10 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PB2 2 &pcfg_pull_up>;
                        };
                        spi2_tx: spi2-tx {
-                               rockchip,pins = <0 11 RK_FUNC_2 &pcfg_pull_up>;
+                               rockchip,pins = <0 RK_PB3 2 &pcfg_pull_up>;
                        };
                };
 
                tsadc {
                        otp_gpio: otp-gpio {
-                               rockchip,pins = <0 3 RK_FUNC_GPIO &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
                        };
 
                        otp_out: otp-out {
-                               rockchip,pins = <0 3 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA3 1 &pcfg_pull_none>;
                        };
                };
 
                uart0 {
                        uart0_xfer: uart0-xfer {
-                               rockchip,pins = <2 24 RK_FUNC_1 &pcfg_pull_up>,
-                                               <2 25 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PD0 1 &pcfg_pull_up>,
+                                               <2 RK_PD1 1 &pcfg_pull_none>;
                        };
 
                        uart0_cts: uart0-cts {
-                               rockchip,pins = <2 26 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PD2 1 &pcfg_pull_none>;
                        };
 
                        uart0_rts: uart0-rts {
-                               rockchip,pins = <2 27 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PD3 1 &pcfg_pull_none>;
                        };
                };
 
                uart1 {
                        uart1_xfer: uart1-xfer {
-                               rockchip,pins = <0 20 RK_FUNC_3 &pcfg_pull_up>,
-                                               <0 21 RK_FUNC_3 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PC4 3 &pcfg_pull_up>,
+                                               <0 RK_PC5 3 &pcfg_pull_none>;
                        };
 
                        uart1_cts: uart1-cts {
-                               rockchip,pins = <0 22 RK_FUNC_3 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PC6 3 &pcfg_pull_none>;
                        };
 
                        uart1_rts: uart1-rts {
-                               rockchip,pins = <0 23 RK_FUNC_3 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PC7 3 &pcfg_pull_none>;
                        };
                };
 
                uart2 {
                        uart2_xfer: uart2-xfer {
-                               rockchip,pins = <2 6 RK_FUNC_2 &pcfg_pull_up>,
-                                               <2 5 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PA6 2 &pcfg_pull_up>,
+                                               <2 RK_PA5 2 &pcfg_pull_none>;
                        };
                        /* no rts / cts for uart2 */
                };
 
                uart3 {
                        uart3_xfer: uart3-xfer {
-                               rockchip,pins = <3 29 RK_FUNC_2 &pcfg_pull_up>,
-                                               <3 30 RK_FUNC_3 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PD5 2 &pcfg_pull_up>,
+                                               <3 RK_PD6 3 &pcfg_pull_none>;
                        };
 
                        uart3_cts: uart3-cts {
-                               rockchip,pins = <3 16 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PC0 2 &pcfg_pull_none>;
                        };
 
                        uart3_rts: uart3-rts {
-                               rockchip,pins = <3 17 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <3 RK_PC1 2 &pcfg_pull_none>;
                        };
                };
 
                uart4 {
                        uart4_xfer: uart4-xfer {
-                               rockchip,pins = <0 27 RK_FUNC_3 &pcfg_pull_up>,
-                                               <0 26 RK_FUNC_3 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PD3 3 &pcfg_pull_up>,
+                                               <0 RK_PD2 3 &pcfg_pull_none>;
                        };
 
                        uart4_cts: uart4-cts {
-                               rockchip,pins = <0 24 RK_FUNC_3 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PD0 3 &pcfg_pull_none>;
                        };
 
                        uart4_rts: uart4-rts {
-                               rockchip,pins = <0 25 RK_FUNC_3 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PD1 3 &pcfg_pull_none>;
                        };
                };
        };
index 959ddc3c7df52bde81d64a9bbf924c397d44c9f7..77008dca45bcddf4bb47224a284eacf0361b7681 100644 (file)
        pmic {
                pmic_int_l: pmic-int-l {
                        rockchip,pins =
-                               <1 21 RK_FUNC_GPIO &pcfg_pull_up>;
+                               <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                pmic_dvs2: pmic-dvs2 {
                        rockchip,pins =
-                               <1 18 RK_FUNC_GPIO &pcfg_pull_down>;
+                               <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>;
                };
        };
 
        usb2 {
                vcc5v0_host_en: vcc5v0-host-en {
                        rockchip,pins =
-                               <4 25 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <4 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 027d428917b8a3a1a2c2c7232dcd9dbb20c15b09..6b059bd7a04fe2ee2acbb7c67507064ad64c0155 100644 (file)
        gmac {
                rgmii_sleep_pins: rgmii-sleep-pins {
                        rockchip,pins =
-                               <3 15 RK_FUNC_GPIO &pcfg_output_low>;
+                               <3 RK_PB7 RK_FUNC_GPIO &pcfg_output_low>;
                };
        };
 
        pcie {
                pcie_drv: pcie-drv {
                        rockchip,pins =
-                               <1 24 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
                        };
        };
 
        usb2 {
                host_vbus_drv: host-vbus-drv {
                        rockchip,pins =
-                               <4 27 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <4 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        leds {
                user_led1: user_led1 {
                        rockchip,pins =
-                               <4 25 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <4 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                user_led2: user_led2 {
                        rockchip,pins =
-                               <4 26 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                user_led3: user_led3 {
                        rockchip,pins =
-                               <4 30 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <4 RK_PD6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                user_led4: user_led4 {
                        rockchip,pins =
-                               <1 0 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                wlan_led: wlan_led {
                        rockchip,pins =
-                               <1 1 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                bt_led: bt_led {
                        rockchip,pins =
-                               <1 4 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index d1cf404b87084a00b18d55b26d50681b68ce48d5..a9f4d6d7d2b754888c753664e775f2c0f611492d 100644 (file)
@@ -73,7 +73,7 @@
 &pinctrl {
        tpm {
                h1_int_od_l: h1-int-od-l {
-                       rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 };
index 931640e9aed4207f407c12fc7202b75e14eab46a..7cd6d470c1cbdb657e5c54b015ac012e07c2d085 100644 (file)
@@ -365,27 +365,27 @@ ap_i2c_tp: &i2c5 {
 &pinctrl {
        discrete-regulators {
                pp1500_en: pp1500-en {
-                       rockchip,pins = <RK_GPIO0 10 RK_FUNC_GPIO
+                       rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO
                                         &pcfg_pull_none>;
                };
 
                pp1800_audio_en: pp1800-audio-en {
-                       rockchip,pins = <RK_GPIO0 2 RK_FUNC_GPIO
+                       rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO
                                         &pcfg_pull_down>;
                };
 
                pp3000_en: pp3000-en {
-                       rockchip,pins = <RK_GPIO0 12 RK_FUNC_GPIO
+                       rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO
                                         &pcfg_pull_none>;
                };
 
                pp3300_disp_en: pp3300-disp-en {
-                       rockchip,pins = <RK_GPIO4 27 RK_FUNC_GPIO
+                       rockchip,pins = <4 RK_PD3 RK_FUNC_GPIO
                                         &pcfg_pull_none>;
                };
 
                wlan_module_pd_l: wlan-module-pd-l {
-                       rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO
                                         &pcfg_pull_down>;
                };
        };
@@ -393,10 +393,10 @@ ap_i2c_tp: &i2c5 {
 
 &wifi {
        wifi_perst_l: wifi-perst-l {
-               rockchip,pins = <2 27 RK_FUNC_GPIO &pcfg_pull_none>;
+               rockchip,pins = <2 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
        };
 
        wlan_host_wake_l: wlan-host-wake-l {
-               rockchip,pins = <0 8 RK_FUNC_GPIO &pcfg_pull_none>;
+               rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
        };
 };
index 15e254a7739120592c1905253ab8ffe4f9c40cc1..3e2272b56eb7cd652c0894e1fd1f9a22ea90e632 100644 (file)
@@ -290,24 +290,24 @@ ap_i2c_dig: &i2c2 {
        digitizer {
                /* Has external pullup */
                cpu1_dig_irq_l: cpu1-dig-irq-l {
-                       rockchip,pins = <2 4 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                /* Has external pullup */
                cpu1_dig_pdct_l: cpu1-dig-pdct-l {
-                       rockchip,pins = <2 5 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        discrete-regulators {
                cpu3_pen_pwr_en: cpu3-pen-pwr-en {
-                       rockchip,pins = <4 30 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <4 RK_PD6 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        pen {
                cpu1_pen_eject: cpu1-pen-eject {
-                       rockchip,pins = <0 13 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 };
index 62ea7d6a7d4a91745a8733cd758e03b1522a69e9..50dfab51f1757bee6ca8ad6e7e6b127af0c23821 100644 (file)
@@ -455,58 +455,58 @@ camera: &i2c7 {
 
 /* PINCTRL OVERRIDES */
 &ec_ap_int_l {
-       rockchip,pins = <1 18 RK_FUNC_GPIO &pcfg_pull_up>;
+       rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>;
 };
 
 &ap_fw_wp {
-       rockchip,pins = <0 13 RK_FUNC_GPIO &pcfg_pull_none>;
+       rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
 };
 
 &bl_en {
-       rockchip,pins = <4 21 RK_FUNC_GPIO &pcfg_pull_none>;
+       rockchip,pins = <4 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
 };
 
 &bt_host_wake_l {
-       rockchip,pins = <1 2 RK_FUNC_GPIO &pcfg_pull_none>;
+       rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
 };
 
 &ec_ap_int_l {
-       rockchip,pins = <1 18 RK_FUNC_GPIO &pcfg_pull_up>;
+       rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>;
 };
 
 &headset_int_l {
-       rockchip,pins = <1 23 RK_FUNC_GPIO &pcfg_pull_up>;
+       rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_up>;
 };
 
 &i2s0_8ch_bus {
        rockchip,pins =
-               <3 24 RK_FUNC_1 &pcfg_pull_none_6ma>,
-               <3 25 RK_FUNC_1 &pcfg_pull_none_6ma>,
-               <3 26 RK_FUNC_1 &pcfg_pull_none_6ma>,
-               <3 27 RK_FUNC_1 &pcfg_pull_none_6ma>,
-               <3 31 RK_FUNC_1 &pcfg_pull_none_6ma>,
-               <4 0 RK_FUNC_1 &pcfg_pull_none_6ma>;
+               <3 RK_PD0 1 &pcfg_pull_none_6ma>,
+               <3 RK_PD1 1 &pcfg_pull_none_6ma>,
+               <3 RK_PD2 1 &pcfg_pull_none_6ma>,
+               <3 RK_PD3 1 &pcfg_pull_none_6ma>,
+               <3 RK_PD7 1 &pcfg_pull_none_6ma>,
+               <4 RK_PA0 1 &pcfg_pull_none_6ma>;
 };
 
 /* there is no external pull up, so need to set this pin pull up */
 &sdmmc_cd_gpio {
-       rockchip,pins = <1 11 RK_FUNC_GPIO &pcfg_pull_up>;
+       rockchip,pins = <1 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>;
 };
 
 &sd_pwr_1800_sel {
-       rockchip,pins = <2 28 RK_FUNC_GPIO &pcfg_pull_up>;
+       rockchip,pins = <2 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up>;
 };
 
 &sdmode_en {
-       rockchip,pins = <0 2 RK_FUNC_GPIO &pcfg_pull_down>;
+       rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>;
 };
 
 &touch_reset_l {
-       rockchip,pins = <0 10 RK_FUNC_GPIO &pcfg_pull_down>;
+       rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_down>;
 };
 
 &touch_int_l {
-       rockchip,pins = <1 4 RK_FUNC_GPIO &pcfg_pull_down>;
+       rockchip,pins = <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>;
 };
 
 &pinctrl {
@@ -523,84 +523,84 @@ camera: &i2c7 {
 
        camera {
                pp1250_cam_en: pp1250-dvdd {
-                       rockchip,pins = <2 4 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                pp2800_cam_en: pp2800-avdd {
-                       rockchip,pins = <2 24 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                ucam_rst: ucam_rst {
-                       rockchip,pins = <2 3 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                wcam_rst: wcam_rst {
-                       rockchip,pins = <2 5 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        digitizer {
                pen_int_odl: pen-int-odl {
-                       rockchip,pins = <1 0 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                pen_reset_l: pen-reset-l {
-                       rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        discrete-regulators {
                display_rst_l: display-rst-l {
-                       rockchip,pins = <4 25 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <4 RK_PD1 RK_FUNC_GPIO &pcfg_pull_down>;
                };
 
                ppvarp_lcd_en: ppvarp-lcd-en {
-                       rockchip,pins = <4 27 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <4 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                ppvarn_lcd_en: ppvarn-lcd-en {
-                       rockchip,pins = <4 28 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <4 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        dmic {
                dmic_en: dmic-en {
-                       rockchip,pins = <4 3 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <4 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        pen {
                pen_eject_odl: pen-eject-odl {
-                       rockchip,pins = <1 1 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        tpm {
                h1_int_od_l: h1-int-od-l {
-                       rockchip,pins = <1 17 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 };
 
 &wifi {
        bt_en_1v8_l: bt-en-1v8-l {
-               rockchip,pins = <0 8 RK_FUNC_GPIO &pcfg_pull_none>;
+               rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
        };
 
        wlan_pd_1v8_l: wlan-pd-1v8-l {
-               rockchip,pins = <0 4 RK_FUNC_GPIO &pcfg_pull_none>;
+               rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
        };
 
        /* Default pull-up, but just to be clear */
        wlan_rf_kill_1v8_l: wlan-rf-kill-1v8-l {
-               rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+               rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
        };
 
        wifi_perst_l: wifi-perst-l {
-               rockchip,pins = <0 3 RK_FUNC_GPIO &pcfg_pull_none>;
+               rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
        };
 
        wlan_host_wake_l: wlan-host-wake-l {
-               rockchip,pins = <1 3 RK_FUNC_GPIO &pcfg_pull_up>;
+               rockchip,pins = <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>;
        };
 };
index da03fa9c56621237db8dc296b7a894930a461954..dd5624975c9b40e4614b60bf175d169ffd530511 100644 (file)
@@ -676,29 +676,29 @@ ap_i2c_audio: &i2c8 {
 
        backlight-enable {
                bl_en: bl-en {
-                       rockchip,pins = <1 17 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        cros-ec {
                ec_ap_int_l: ec-ap-int-l {
-                       rockchip,pins = <RK_GPIO0 1 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        discrete-regulators {
                sd_io_pwr_en: sd-io-pwr-en {
-                       rockchip,pins = <RK_GPIO2 2 RK_FUNC_GPIO
+                       rockchip,pins = <2 RK_PA2 RK_FUNC_GPIO
                                         &pcfg_pull_none>;
                };
 
                sd_pwr_1800_sel: sd-pwr-1800-sel {
-                       rockchip,pins = <RK_GPIO2 28 RK_FUNC_GPIO
+                       rockchip,pins = <2 RK_PD4 RK_FUNC_GPIO
                                         &pcfg_pull_none>;
                };
 
                sd_slot_pwr_en: sd-slot-pwr-en {
-                       rockchip,pins = <RK_GPIO4 29 RK_FUNC_GPIO
+                       rockchip,pins = <4 RK_PD5 RK_FUNC_GPIO
                                         &pcfg_pull_none>;
                };
        };
@@ -706,17 +706,17 @@ ap_i2c_audio: &i2c8 {
        codec {
                /* Has external pullup */
                headset_int_l: headset-int-l {
-                       rockchip,pins = <1 23 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                mic_int: mic-int {
-                       rockchip,pins = <1 13 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_down>;
                };
        };
 
        max98357a {
                sdmode_en: sdmode-en {
-                       rockchip,pins = <1 2 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>;
                };
        };
 
@@ -727,7 +727,7 @@ ap_i2c_audio: &i2c8 {
                         * to hack this as gpio, so the EP could be able to
                         * de-assert it along and make ClockPM(CPM) work.
                         */
-                       rockchip,pins = <2 26 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
@@ -738,20 +738,20 @@ ap_i2c_audio: &i2c8 {
                 */
                sdmmc_bus4: sdmmc-bus4 {
                        rockchip,pins =
-                               <4 8 RK_FUNC_1 &pcfg_pull_none_8ma>,
-                               <4 9 RK_FUNC_1 &pcfg_pull_none_8ma>,
-                               <4 10 RK_FUNC_1 &pcfg_pull_none_8ma>,
-                               <4 11 RK_FUNC_1 &pcfg_pull_none_8ma>;
+                               <4 RK_PB0 1 &pcfg_pull_none_8ma>,
+                               <4 RK_PB1 1 &pcfg_pull_none_8ma>,
+                               <4 RK_PB2 1 &pcfg_pull_none_8ma>,
+                               <4 RK_PB3 1 &pcfg_pull_none_8ma>;
                };
 
                sdmmc_clk: sdmmc-clk {
                        rockchip,pins =
-                               <4 12 RK_FUNC_1 &pcfg_pull_none_8ma>;
+                               <4 RK_PB4 1 &pcfg_pull_none_8ma>;
                };
 
                sdmmc_cmd: sdmmc-cmd {
                        rockchip,pins =
-                               <4 13 RK_FUNC_1 &pcfg_pull_none_8ma>;
+                               <4 RK_PB5 1 &pcfg_pull_none_8ma>;
                };
 
                /*
@@ -765,12 +765,12 @@ ap_i2c_audio: &i2c8 {
                 */
                sdmmc_cd: sdmmc-cd {
                        rockchip,pins =
-                               <0 7 RK_FUNC_1 &pcfg_pull_none>;
+                               <0 RK_PA7 1 &pcfg_pull_none>;
                };
 
                /* This is where we actually hook up CD; has external pull */
                sdmmc_cd_gpio: sdmmc-cd-gpio {
-                       rockchip,pins = <4 24 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <4 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
@@ -780,47 +780,47 @@ ap_i2c_audio: &i2c8 {
                         * Pull down SPI1 CLK/CS/RX/TX during suspend, to
                         * prevent leakage.
                         */
-                       rockchip,pins = <1 9 RK_FUNC_GPIO &pcfg_pull_down>,
-                                       <1 10 RK_FUNC_GPIO &pcfg_pull_down>,
-                                       <1 7 RK_FUNC_GPIO &pcfg_pull_down>,
-                                       <1 8 RK_FUNC_GPIO &pcfg_pull_down>;
+                       rockchip,pins = <1 RK_PB1 RK_FUNC_GPIO &pcfg_pull_down>,
+                                       <1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_down>,
+                                       <1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_down>,
+                                       <1 RK_PB0 RK_FUNC_GPIO &pcfg_pull_down>;
                };
        };
 
        touchscreen {
                touch_int_l: touch-int-l {
-                       rockchip,pins = <3 13 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <3 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                touch_reset_l: touch-reset-l {
-                       rockchip,pins = <4 26 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        trackpad {
                ap_i2c_tp_pu_en: ap-i2c-tp-pu-en {
-                       rockchip,pins = <3 12 RK_FUNC_GPIO &pcfg_output_high>;
+                       rockchip,pins = <3 RK_PB4 RK_FUNC_GPIO &pcfg_output_high>;
                };
 
                trackpad_int_l: trackpad-int-l {
-                       rockchip,pins = <1 4 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        wifi: wifi {
                wlan_module_reset_l: wlan-module-reset-l {
-                       rockchip,pins = <1 11 RK_FUNC_GPIO &pcfg_pull_none>;
+                       rockchip,pins = <1 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                bt_host_wake_l: bt-host-wake-l {
                        /* Kevin has an external pull up, but Gru does not */
-                       rockchip,pins = <0 3 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        write-protect {
                ap_fw_wp: ap-fw-wp {
-                       rockchip,pins = <1 18 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 };
index 84433cf02be98c75d5e6d378cac6dc5860a614f5..2a127985ab171c6ffb2c6e0ad1a71225b3eaa72d 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&ir_rx>;
        };
+
+       fan: pwm-fan {
+               compatible = "pwm-fan";
+               /*
+                * With 20KHz PWM and an EVERCOOL EC4007H12SA fan, these levels
+                * work out to 0, ~1200, ~3000, and 5000RPM respectively.
+                */
+               cooling-levels = <0 12 18 255>;
+               #cooling-cells = <2>;
+               fan-supply = <&vcc12v0_sys>;
+               pwms = <&pwm1 0 50000 0>;
+       };
+};
+
+&cpu_thermal {
+       trips {
+               cpu_warm: cpu_warm {
+                       temperature = <55000>;
+                       hysteresis = <2000>;
+                       type = "active";
+               };
+
+               cpu_hot: cpu_hot {
+                       temperature = <65000>;
+                       hysteresis = <2000>;
+                       type = "active";
+               };
+       };
+
+       cooling-maps {
+               map2 {
+                       trip = <&cpu_warm>;
+                       cooling-device = <&fan THERMAL_NO_LIMIT 1>;
+               };
+
+               map3 {
+                       trip = <&cpu_hot>;
+                       cooling-device = <&fan 2 THERMAL_NO_LIMIT>;
+               };
+       };
+};
+
+&gpu_thermal {
+       trips {
+               gpu_warm: gpu_warm {
+                       temperature = <55000>;
+                       hysteresis = <2000>;
+                       type = "active";
+               };
+
+               gpu_hot: gpu_hot {
+                       temperature = <65000>;
+                       hysteresis = <2000>;
+                       type = "active";
+               };
+       };
+       cooling-maps {
+               map1 {
+                       trip = <&gpu_warm>;
+                       cooling-device = <&fan THERMAL_NO_LIMIT 1>;
+               };
+
+               map2 {
+                       trip = <&gpu_hot>;
+                       cooling-device = <&fan 2 THERMAL_NO_LIMIT>;
+               };
+       };
 };
 
 &pinctrl {
        ir {
                ir_rx: ir-rx {
                        /* external pullup to VCC3V3_SYS, despite being 1.8V :/ */
-                       rockchip,pins = <0 RK_PA6 RK_FUNC_1 &pcfg_pull_none>;
+                       rockchip,pins = <0 RK_PA6 1 &pcfg_pull_none>;
                };
        };
 };
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-neo4.dts b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-neo4.dts
new file mode 100644 (file)
index 0000000..195410b
--- /dev/null
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2019 Amarula Solutions B.V.
+ * Author: Jagan Teki <jagan@amarulasolutions.com>
+ */
+
+/dts-v1/;
+
+#include "rk3399-nanopi4.dtsi"
+
+/ {
+       model = "FriendlyARM NanoPi NEO4";
+       compatible = "friendlyarm,nanopi-neo4", "rockchip,rk3399";
+
+       vdd_5v: vdd-5v {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd_5v";
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       vcc5v0_core: vcc5v0-core {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_core";
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vdd_5v>;
+       };
+
+       vcc5v0_usb1: vcc5v0-usb1 {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_usb1";
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc5v0_sys>;
+       };
+};
+
+&vcc3v3_sys {
+       vin-supply = <&vcc5v0_core>;
+};
+
+&u2phy0_host {
+       phy-supply = <&vcc5v0_usb1>;
+};
+
+&vbus_typec {
+       regulator-always-on;
+       vin-supply = <&vdd_5v>;
+};
index d325e117287ba38d5c2b6a6e731fbce7bf11543c..dd16c80d923eeb7490d0fb048700bc522c42226e 100644 (file)
        assigned-clocks = <&cru SCLK_RMII_SRC>;
        clock_in_out = "input";
        pinctrl-names = "default";
-       pinctrl-0 = <&rgmii_pins>;
+       pinctrl-0 = <&rgmii_pins>, <&phy_intb>, <&phy_rstb>;
+       phy-handle = <&rtl8211e>;
        phy-mode = "rgmii";
        phy-supply = <&vcc3v3_s3>;
        snps,reset-active-low;
-       snps,reset-delays-us = <0 10000 50000>;
+       snps,reset-delays-us = <0 10000 30000>;
        snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
        tx_delay = <0x28>;
        rx_delay = <0x11>;
        status = "okay";
+
+       mdio {
+               compatible = "snps,dwmac-mdio";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               rtl8211e: phy@1 {
+                       reg = <1>;
+                       interrupt-parent = <&gpio3>;
+                       interrupts = <RK_PB2 IRQ_TYPE_LEVEL_LOW>;
+               };
+       };
 };
 
 &gpu {
                };
        };
 
+       phy {
+               phy_intb: phy-intb {
+                       rockchip,pins = <3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+
+               phy_rstb: phy-rstb {
+                       rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
        pmic {
                cpu_b_sleep: cpu-b-sleep {
                        rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts b/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts
new file mode 100644 (file)
index 0000000..0541dfc
--- /dev/null
@@ -0,0 +1,790 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd.
+ */
+
+/dts-v1/;
+
+#include "dt-bindings/pwm/pwm.h"
+#include "dt-bindings/input/input.h"
+#include "rk3399.dtsi"
+#include "rk3399-opp.dtsi"
+
+/ {
+       model = "Orange Pi RK3399 Board";
+       compatible = "rockchip,rk3399-orangepi", "rockchip,rk3399";
+
+       chosen {
+               stdout-path = "serial2:1500000n8";
+       };
+
+       clkin_gmac: external-gmac-clock {
+               compatible = "fixed-clock";
+               clock-frequency = <125000000>;
+               clock-output-names = "clkin_gmac";
+               #clock-cells = <0>;
+       };
+
+       adc-keys {
+               compatible = "adc-keys";
+               io-channels = <&saradc 1>;
+               io-channel-names = "buttons";
+               keyup-threshold-microvolt = <1800000>;
+               poll-interval = <100>;
+
+               button-up {
+                       label = "Volume Up";
+                       linux,code = <KEY_VOLUMEUP>;
+                       press-threshold-microvolt = <100000>;
+               };
+
+               button-down {
+                       label = "Volume Down";
+                       linux,code = <KEY_VOLUMEDOWN>;
+                       press-threshold-microvolt = <300000>;
+               };
+
+               back {
+                       label = "Back";
+                       linux,code = <KEY_BACK>;
+                       press-threshold-microvolt = <985000>;
+               };
+
+               menu {
+                       label = "Menu";
+                       linux,code = <KEY_MENU>;
+                       press-threshold-microvolt = <1314000>;
+               };
+       };
+
+       dc_12v: dc-12v {
+               compatible = "regulator-fixed";
+               regulator-name = "dc_12v";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+       };
+
+       keys: gpio-keys {
+               compatible = "gpio-keys";
+               autorepeat;
+
+               power {
+                       debounce-interval = <100>;
+                       gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
+                       label = "GPIO Power";
+                       linux,code = <KEY_POWER>;
+                       linux,input-type = <1>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pwr_btn>;
+                       wakeup-source;
+               };
+       };
+
+       sdio_pwrseq: sdio-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               clocks = <&rk808 1>;
+               clock-names = "ext_clock";
+               pinctrl-names = "default";
+               pinctrl-0 = <&wifi_reg_on_h>;
+               reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
+       };
+
+       /* switched by pmic_sleep */
+       vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc1v8_s3";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vcc_1v8>;
+       };
+
+       vcc3v0_sd: vcc3v0-sd {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&sdmmc0_pwr_h>;
+               regulator-boot-on;
+               regulator-max-microvolt = <3000000>;
+               regulator-min-microvolt = <3000000>;
+               regulator-name = "vcc3v0_sd";
+               vin-supply = <&vcc3v3_sys>;
+       };
+
+       vcc3v3_sys: vcc3v3-sys {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc3v3_sys";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vcc_sys>;
+       };
+
+       vcc5v0_host: vcc5v0-host-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio4 RK_PD1 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vcc5v0_host_en>;
+               regulator-name = "vcc5v0_host";
+               regulator-always-on;
+               vin-supply = <&vcc_sys>;
+       };
+
+       vbus_typec: vbus-typec-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vcc5v0_typec_en>;
+               regulator-name = "vbus_typec";
+               vin-supply = <&vcc_sys>;
+       };
+
+       vcc_sys: vcc-sys {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_sys";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&dc_12v>;
+       };
+
+       vdd_log: vdd-log {
+               compatible = "pwm-regulator";
+               pwms = <&pwm2 0 25000 1>;
+               regulator-name = "vdd_log";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <800000>;
+               regulator-max-microvolt = <1400000>;
+               vin-supply = <&vcc_sys>;
+       };
+};
+
+&cpu_l0 {
+       cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l1 {
+       cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l2 {
+       cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l3 {
+       cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_b0 {
+       cpu-supply = <&vdd_cpu_b>;
+};
+
+&cpu_b1 {
+       cpu-supply = <&vdd_cpu_b>;
+};
+
+&emmc_phy {
+       status = "okay";
+};
+
+&gmac {
+       assigned-clocks = <&cru SCLK_RMII_SRC>;
+       assigned-clock-parents = <&clkin_gmac>;
+       clock_in_out = "input";
+       phy-supply = <&vcc3v3_s3>;
+       phy-mode = "rgmii";
+       pinctrl-names = "default";
+       pinctrl-0 = <&rgmii_pins>;
+       snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+       snps,reset-active-low;
+       snps,reset-delays-us = <0 10000 50000>;
+       tx_delay = <0x28>;
+       rx_delay = <0x11>;
+       status = "okay";
+};
+
+&gpu {
+       mali-supply = <&vdd_gpu>;
+       status = "okay";
+};
+
+&hdmi {
+       ddc-i2c-bus = <&i2c3>;
+       status = "okay";
+};
+
+&hdmi_sound {
+       status = "okay";
+};
+
+&i2c0 {
+       clock-frequency = <400000>;
+       i2c-scl-rising-time-ns = <168>;
+       i2c-scl-falling-time-ns = <4>;
+       status = "okay";
+
+       rk808: pmic@1b {
+               compatible = "rockchip,rk808";
+               reg = <0x1b>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <21 IRQ_TYPE_LEVEL_LOW>;
+               #clock-cells = <1>;
+               clock-output-names = "rtc_clko_soc", "rtc_clko_wifi";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pmic_int_l>;
+               rockchip,system-power-controller;
+               wakeup-source;
+
+               vcc1-supply = <&vcc3v3_sys>;
+               vcc2-supply = <&vcc3v3_sys>;
+               vcc3-supply = <&vcc3v3_sys>;
+               vcc4-supply = <&vcc3v3_sys>;
+               vcc6-supply = <&vcc3v3_sys>;
+               vcc7-supply = <&vcc3v3_sys>;
+               vcc8-supply = <&vcc3v3_sys>;
+               vcc9-supply = <&vcc3v3_sys>;
+               vcc10-supply = <&vcc3v3_sys>;
+               vcc11-supply = <&vcc3v3_sys>;
+               vcc12-supply = <&vcc3v3_sys>;
+               vddio-supply = <&vcc_3v0>;
+
+               regulators {
+                       vdd_center: DCDC_REG1 {
+                               regulator-name = "vdd_center";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1500000>;
+                               regulator-ramp-delay = <6001>;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_cpu_l: DCDC_REG2 {
+                               regulator-name = "vdd_cpu_l";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <1500000>;
+                               regulator-ramp-delay = <6001>;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_ddr: DCDC_REG3 {
+                               regulator-name = "vcc_ddr";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vcc_1v8: DCDC_REG4 {
+                               regulator-name = "vcc_1v8";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vcc1v8_dvp: LDO_REG1 {
+                               regulator-name = "vcc1v8_dvp";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3400000>;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc3v0_tp: LDO_REG2 {
+                               regulator-name = "vcc3v0_tp";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3400000>;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc1v8_pmupll: LDO_REG3 {
+                               regulator-name = "vcc1v8_pmupll";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <2500000>;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vcc_sdio: LDO_REG4 {
+                               regulator-name = "vcc_sdio";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3400000>;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3000000>;
+                               };
+                       };
+
+                       vcca3v0_codec: LDO_REG5 {
+                               regulator-name = "vcca3v0_codec";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3400000>;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_1v5: LDO_REG6 {
+                               regulator-name = "vcc_1v5";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <2500000>;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1500000>;
+                               };
+                       };
+
+                       vcca1v8_codec: LDO_REG7 {
+                               regulator-name = "vcca1v8_codec";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <2500000>;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_3v0: LDO_REG8 {
+                               regulator-name = "vcc_3v0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3400000>;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3000000>;
+                               };
+                       };
+
+                       vcc3v3_s3: SWITCH_REG1 {
+                               regulator-name = "vcc3v3_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc3v3_s0: SWITCH_REG2 {
+                               regulator-name = "vcc3v3_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+               };
+       };
+
+       vdd_cpu_b: regulator@40 {
+               compatible = "silergy,syr827";
+               reg = <0x40>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-name = "vdd_cpu_b";
+               regulator-min-microvolt = <712500>;
+               regulator-max-microvolt = <1500000>;
+               regulator-ramp-delay = <1000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc3v3_sys>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+
+       vdd_gpu: regulator@41 {
+               compatible = "silergy,syr828";
+               reg = <0x41>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-name = "vdd_gpu";
+               regulator-min-microvolt = <712500>;
+               regulator-max-microvolt = <1500000>;
+               regulator-ramp-delay = <1000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc3v3_sys>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+};
+
+&i2c1 {
+       i2c-scl-rising-time-ns = <450>;
+       i2c-scl-falling-time-ns = <15>;
+       status = "okay";
+};
+
+&i2c3 {
+       i2c-scl-rising-time-ns = <450>;
+       i2c-scl-falling-time-ns = <15>;
+       status = "okay";
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+       i2c-scl-rising-time-ns = <450>;
+       i2c-scl-falling-time-ns = <15>;
+       status = "okay";
+
+       ak09911@c {
+               compatible = "asahi-kasei,ak09911";
+               reg = <0x0c>;
+               vdd-supply = <&vcc3v3_s3>;
+               vid-supply = <&vcc3v3_s3>;
+       };
+
+       mpu6500@68 {
+               compatible = "invensense,mpu6500";
+               reg = <0x68>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <RK_PC6 IRQ_TYPE_EDGE_RISING>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&gsensor_int_l>;
+               vddio-supply = <&vcc3v3_s3>;
+       };
+
+       lsm6ds3@6a {
+               compatible = "st,lsm6ds3";
+               reg = <0x6a>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <RK_PD0 IRQ_TYPE_EDGE_RISING>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&gyr_int_l>;
+               vdd-supply = <&vcc3v3_s3>;
+               vddio-supply = <&vcc3v3_s3>;
+       };
+
+       cm32181@10 {
+               compatible = "capella,cm32181";
+               reg = <0x10>;
+               interrupt-parent = <&gpio4>;
+               interrupts = <RK_PD0 IRQ_TYPE_EDGE_RISING>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&light_int_l>;
+               vdd-supply = <&vcc3v3_s3>;
+       };
+
+       fusb302@22 {
+               compatible = "fcs,fusb302";
+               reg = <0x22>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <RK_PA2 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&chg_cc_int_l>;
+               vbus-supply = <&vbus_typec>;
+       };
+};
+
+&io_domains {
+       status = "okay";
+       bt656-supply = <&vcc_3v0>;
+       audio-supply = <&vcca1v8_codec>;
+       sdmmc-supply = <&vcc_sdio>;
+       gpio1830-supply = <&vcc_3v0>;
+};
+
+&pmu_io_domains {
+       status = "okay";
+       pmu1830-supply = <&vcc_3v0>;
+};
+
+&pinctrl {
+       buttons {
+               pwr_btn: pwr-btn {
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       pmic {
+               pmic_int_l: pmic-int-l {
+                       rockchip,pins =
+                               <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       sd {
+               sdmmc0_pwr_h: sdmmc0-pwr-h {
+                       rockchip,pins =
+                               <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       usb2 {
+               vcc5v0_host_en: vcc5v0-host-en {
+                       rockchip,pins =
+                               <4 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               vcc5v0_typec_en: vcc5v0-typec-en {
+                       rockchip,pins =
+                               <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       sdio-pwrseq {
+               wifi_reg_on_h: wifi-reg-on-h {
+                       rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       wifi {
+               wifi_host_wake_l: wifi-host-wake-l {
+                       rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       bluetooth {
+               bt_reg_on_h: bt-enable-h {
+                       rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               bt_host_wake_l: bt-host-wake-l {
+                       rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               bt_wake_l: bt-wake-l {
+                       rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       mpu6500 {
+               gsensor_int_l: gsensor-int-l {
+                       rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       lsm6ds3 {
+               gyr_int_l: gyr-int-l {
+                       rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       cm32181 {
+               light_int_l: light-int-l {
+                       rockchip,pins = <4 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       fusb302 {
+               chg_cc_int_l: chg-cc-int-l {
+                       rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+};
+
+&pwm0 {
+       status = "okay";
+};
+
+&pwm2 {
+       status = "okay";
+};
+
+&saradc {
+       vref-supply = <&vcca1v8_s3>;
+       status = "okay";
+};
+
+&sdhci {
+       bus-width = <8>;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       non-removable;
+       status = "okay";
+};
+
+&sdio0 {
+       bus-width = <4>;
+       cap-sd-highspeed;
+       cap-sdio-irq;
+       clock-frequency = <50000000>;
+       disable-wp;
+       keep-power-in-suspend;
+       max-frequency = <50000000>;
+       mmc-pwrseq = <&sdio_pwrseq>;
+       non-removable;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>;
+       sd-uhs-sdr104;
+       status = "okay";
+
+       brcmf: wifi@1 {
+               compatible = "brcm,bcm4329-fmac";
+               interrupt-parent = <&gpio0>;
+               interrupts = <RK_PA3 GPIO_ACTIVE_HIGH>;
+               interrupt-names = "host-wake";
+               pinctrl-names = "default";
+               pinctrl-0 = <&wifi_host_wake_l>;
+       };
+};
+
+&sdmmc {
+       bus-width = <4>;
+       cap-mmc-highspeed;
+       cap-sd-highspeed;
+       cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>;
+       clock-frequency = <150000000>;
+       disable-wp;
+       max-frequency = <150000000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>;
+       vmmc-supply = <&vcc3v0_sd>;
+       vqmmc-supply = <&vcc_sdio>;
+       status = "okay";
+};
+
+&tcphy0 {
+       status = "okay";
+};
+
+&tcphy1 {
+       status = "okay";
+};
+
+&tsadc {
+       rockchip,hw-tshut-mode = <1>;
+       rockchip,hw-tshut-polarity = <1>;
+       status = "okay";
+};
+
+&u2phy0 {
+       status = "okay";
+
+       u2phy0_otg: otg-port {
+               phy-supply = <&vbus_typec>;
+               status = "okay";
+       };
+
+       u2phy0_host: host-port {
+               phy-supply = <&vcc5v0_host>;
+               status = "okay";
+       };
+};
+
+&u2phy1 {
+       status = "okay";
+
+       u2phy1_otg: otg-port {
+               status = "okay";
+       };
+
+       u2phy1_host: host-port {
+               phy-supply = <&vcc5v0_host>;
+               status = "okay";
+       };
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
+       status = "okay";
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               clocks = <&rk808 1>;
+               clock-names = "lpo";
+               device-wakeup-gpios = <&gpio2 RK_PD2 GPIO_ACTIVE_HIGH>;
+               host-wakeup-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>;
+               shutdown-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_reg_on_h>;
+               vbat-supply = <&vcc3v3_sys>;
+               vddio-supply = <&vcc_1v8>;
+       };
+};
+
+&uart2 {
+       status = "okay";
+};
+
+&usb_host0_ehci {
+       status = "okay";
+};
+
+&usb_host0_ohci {
+       status = "okay";
+};
+
+&usb_host1_ehci {
+       status = "okay";
+};
+
+&usb_host1_ohci {
+       status = "okay";
+};
+
+&usbdrd3_0 {
+       status = "okay";
+};
+
+&usbdrd_dwc3_0 {
+       status = "okay";
+       dr_mode = "otg";
+};
+
+&usbdrd3_1 {
+       status = "okay";
+};
+
+&usbdrd_dwc3_1 {
+       status = "okay";
+       dr_mode = "host";
+};
+
+&vopb {
+       status = "okay";
+};
+
+&vopb_mmu {
+       status = "okay";
+};
+
+&vopl {
+       status = "okay";
+};
+
+&vopl_mmu {
+       status = "okay";
+};
index 1e6a71066c163fd7bd2493b286e83a0596942930..d80d6b72682068fc6ad4f51d1a039db915518ba7 100644 (file)
                haikou_pin_hog: haikou-pin-hog {
                        rockchip,pins =
                          /* LID_BTN */
-                         <RK_GPIO0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>,
+                         <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>,
                          /* BATLOW# */
-                         <RK_GPIO0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>,
+                         <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>,
                          /* SLP_BTN# */
-                         <RK_GPIO0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>,
+                         <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>,
                          /* BIOS_DISABLE# */
-                         <RK_GPIO0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>;
+                         <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        leds {
                led_sd_haikou: led-sd-gpio {
                        rockchip,pins =
-                         <RK_GPIO1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
+                         <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        usb2 {
                otg_vbus_drv: otg-vbus-drv {
                        rockchip,pins =
-                         <RK_GPIO0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
+                         <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 0130b9f98c9deefca654794f941e7dec85e655c0..62ea288a1a70bc8ed90184635e43083f0aa031fd 100644 (file)
 
 &emmc_phy {
        status = "okay";
+       drive-impedance-ohm = <33>;
 };
 
 &gmac {
        fan: fan@18 {
                compatible = "ti,amc6821";
                reg = <0x18>;
-               cooling-min-state = <0>;
-               cooling-max-state = <9>;
                #cooling-cells = <2>;
        };
 
  */
 &i2s0_2ch_bus {
        rockchip,pins =
-               <RK_GPIO3 RK_PD0 RK_FUNC_1 &pcfg_pull_none>,
-               <RK_GPIO3 RK_PD2 RK_FUNC_1 &pcfg_pull_none>,
-               <RK_GPIO3 RK_PD3 RK_FUNC_1 &pcfg_pull_none>,
-               <RK_GPIO3 RK_PD7 RK_FUNC_1 &pcfg_pull_none>;
+               <3 RK_PD0 1 &pcfg_pull_none>,
+               <3 RK_PD2 1 &pcfg_pull_none>,
+               <3 RK_PD3 1 &pcfg_pull_none>,
+               <3 RK_PD7 1 &pcfg_pull_none>;
 };
 
 &io_domains {
        i2c8 {
                i2c8_xfer_a: i2c8-xfer {
                        rockchip,pins =
-                         <RK_GPIO1 RK_PC4 RK_FUNC_1 &pcfg_pull_up>,
-                         <RK_GPIO1 RK_PC5 RK_FUNC_1 &pcfg_pull_up>;
+                         <1 RK_PC4 1 &pcfg_pull_up>,
+                         <1 RK_PC5 1 &pcfg_pull_up>;
                };
        };
 
        leds {
                led_pin_module: led-module-gpio {
                        rockchip,pins =
-                         <RK_GPIO2 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
+                         <2 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        pmic {
                pmic_int_l: pmic-int-l {
                        rockchip,pins =
-                         <RK_GPIO1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>;
+                         <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
        usb2 {
                vcc5v0_host_en: vcc5v0-host-en {
                        rockchip,pins =
-                         <RK_GPIO4 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
+                         <4 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 };
index 844eac939a97c58f9aea4a2e681b39dd6648f4f1..e030627159c6bc012b44f80180033f0a5a516929 100644 (file)
        status = "okay";
 };
 
+&gpu {
+       mali-supply = <&vdd_gpu>;
+       status = "okay";
+};
+
 &hdmi {
        ddc-i2c-bus = <&i2c3>;
        pinctrl-names = "default";
index 2927db4dda9d33234b1895cf4e839a8ee4976879..c7d48d41e184ee6f00dc82875a6178d894e22752 100644 (file)
                reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
        };
 
+       vcc12v_dcin: vcc12v-dcin {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc12v_dcin";
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
        vcc1v8_s0: vcc1v8-s0 {
                compatible = "regulator-fixed";
                regulator-name = "vcc1v8_s0";
                regulator-always-on;
        };
 
-       vcc_sys: vcc-sys {
+       vcc5v0_sys: vcc5v0-sys {
                compatible = "regulator-fixed";
-               regulator-name = "vcc_sys";
+               regulator-name = "vcc5v0_sys";
                regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
                regulator-always-on;
+               vin-supply = <&vcc12v_dcin>;
        };
 
        vcc3v3_sys: vcc3v3-sys {
@@ -40,7 +50,7 @@
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
                regulator-always-on;
-               vin-supply = <&vcc_sys>;
+               vin-supply = <&vcc5v0_sys>;
        };
 
        vcc3v3_pcie: vcc3v3-pcie-regulator {
@@ -64,7 +74,7 @@
                regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
                regulator-always-on;
-               vin-supply = <&vcc_sys>;
+               vin-supply = <&vcc5v0_sys>;
        };
 };
 
        status = "okay";
 };
 
+&gpu {
+       mali-supply = <&vdd_gpu>;
+       status = "okay";
+};
+
 &hdmi {
        ddc-i2c-bus = <&i2c3>;
        pinctrl-names = "default";
                regulator-ramp-delay = <1000>;
                regulator-always-on;
                regulator-boot-on;
-               vin-supply = <&vcc_sys>;
+               vin-supply = <&vcc5v0_sys>;
                status = "okay";
 
                regulator-state-mem {
                regulator-ramp-delay = <1000>;
                regulator-always-on;
                regulator-boot-on;
-               vin-supply = <&vcc_sys>;
+               vin-supply = <&vcc5v0_sys>;
                regulator-state-mem {
                        regulator-off-in-suspend;
                };
                #clock-cells = <1>;
                clock-output-names = "xin32k", "rk808-clkout2";
 
-               vcc1-supply = <&vcc_sys>;
-               vcc2-supply = <&vcc_sys>;
-               vcc3-supply = <&vcc_sys>;
-               vcc4-supply = <&vcc_sys>;
-               vcc6-supply = <&vcc_sys>;
-               vcc7-supply = <&vcc_sys>;
+               vcc1-supply = <&vcc5v0_sys>;
+               vcc2-supply = <&vcc5v0_sys>;
+               vcc3-supply = <&vcc5v0_sys>;
+               vcc4-supply = <&vcc5v0_sys>;
+               vcc6-supply = <&vcc5v0_sys>;
+               vcc7-supply = <&vcc5v0_sys>;
                vcc8-supply = <&vcc3v3_sys>;
-               vcc9-supply = <&vcc_sys>;
-               vcc10-supply = <&vcc_sys>;
-               vcc11-supply = <&vcc_sys>;
+               vcc9-supply = <&vcc5v0_sys>;
+               vcc10-supply = <&vcc5v0_sys>;
+               vcc11-supply = <&vcc5v0_sys>;
                vcc12-supply = <&vcc3v3_sys>;
                vddio-supply = <&vcc_1v8>;
 
        sdmmc {
                sdmmc_bus1: sdmmc-bus1 {
                        rockchip,pins =
-                               <4 8 RK_FUNC_1 &pcfg_pull_up_8ma>;
+                               <4 RK_PB0 1 &pcfg_pull_up_8ma>;
                };
 
                sdmmc_bus4: sdmmc-bus4 {
                        rockchip,pins =
-                               <4 8 RK_FUNC_1 &pcfg_pull_up_8ma>,
-                               <4 9 RK_FUNC_1 &pcfg_pull_up_8ma>,
-                               <4 10 RK_FUNC_1 &pcfg_pull_up_8ma>,
-                               <4 11 RK_FUNC_1 &pcfg_pull_up_8ma>;
+                               <4 RK_PB0 1 &pcfg_pull_up_8ma>,
+                               <4 RK_PB1 1 &pcfg_pull_up_8ma>,
+                               <4 RK_PB2 1 &pcfg_pull_up_8ma>,
+                               <4 RK_PB3 1 &pcfg_pull_up_8ma>;
                };
 
                sdmmc_clk: sdmmc-clk {
                        rockchip,pins =
-                               <4 12 RK_FUNC_1 &pcfg_pull_none_18ma>;
+                               <4 RK_PB4 1 &pcfg_pull_none_18ma>;
                };
 
                sdmmc_cmd: sdmmc-cmd {
                        rockchip,pins =
-                               <4 13 RK_FUNC_1 &pcfg_pull_up_8ma>;
+                               <4 RK_PB5 1 &pcfg_pull_up_8ma>;
                };
        };
 
        sdio0 {
                sdio0_bus4: sdio0-bus4 {
                        rockchip,pins =
-                               <2 20 RK_FUNC_1 &pcfg_pull_up_20ma>,
-                               <2 21 RK_FUNC_1 &pcfg_pull_up_20ma>,
-                               <2 22 RK_FUNC_1 &pcfg_pull_up_20ma>,
-                               <2 23 RK_FUNC_1 &pcfg_pull_up_20ma>;
+                               <2 RK_PC4 1 &pcfg_pull_up_20ma>,
+                               <2 RK_PC5 1 &pcfg_pull_up_20ma>,
+                               <2 RK_PC6 1 &pcfg_pull_up_20ma>,
+                               <2 RK_PC7 1 &pcfg_pull_up_20ma>;
                };
 
                sdio0_cmd: sdio0-cmd {
                        rockchip,pins =
-                               <2 24 RK_FUNC_1 &pcfg_pull_up_20ma>;
+                               <2 RK_PD0 1 &pcfg_pull_up_20ma>;
                };
 
                sdio0_clk: sdio0-clk {
                        rockchip,pins =
-                               <2 25 RK_FUNC_1 &pcfg_pull_none_20ma>;
+                               <2 RK_PD1 1 &pcfg_pull_none_20ma>;
                };
        };
 
        pmic {
                pmic_int_l: pmic-int-l {
                        rockchip,pins =
-                               <1 21 RK_FUNC_GPIO &pcfg_pull_up>;
+                               <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
                };
 
                vsel1_gpio: vsel1-gpio {
                        rockchip,pins =
-                               <1 17 RK_FUNC_GPIO &pcfg_pull_down>;
+                               <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>;
                };
 
                vsel2_gpio: vsel2-gpio {
                        rockchip,pins =
-                               <1 14 RK_FUNC_GPIO &pcfg_pull_down>;
+                               <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
                };
        };
 
index 1f2394e0587db4f4a7d6c065bd3f868a45ecd654..20ec7d1c25d71cf53198f58e94faa877339a3884 100644 (file)
        status = "okay";
 };
 
+&hdmi_sound {
+       status = "okay";
+};
+
 &gpu {
        mali-supply = <&vdd_gpu>;
        status = "okay";
        status = "okay";
 
        bt656-supply = <&vcc1v8_dvp>;
-       audio-supply = <&vcca1v8_codec>;
+       audio-supply = <&vcc_3v0>;
        sdmmc-supply = <&vcc_sdio>;
        gpio1830-supply = <&vcc_3v0>;
 };
index 946d3589575acadfe51627d20b63c04746a93f52..04623e52ac5db568adfdeefaacd132ac1b7d026c 100644 (file)
        fan {
                motor_pwr: motor-pwr {
                        rockchip,pins =
-                               <RK_GPIO1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
        sd {
                sdmmc0_pwr_h: sdmmc0-pwr-h {
                        rockchip,pins =
-                               <RK_GPIO0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
+                               <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
index db9d948c0b03233fd8dbe42dda36329046d0b8b5..196ac9b780768b53f25f832452cfe30a8fd11f80 100644 (file)
@@ -71,6 +71,7 @@
                        compatible = "arm,cortex-a53";
                        reg = <0x0 0x0>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <485>;
                        clocks = <&cru ARMCLKL>;
                        #cooling-cells = <2>; /* min followed by max */
                        dynamic-power-coefficient = <100>;
@@ -82,6 +83,7 @@
                        compatible = "arm,cortex-a53";
                        reg = <0x0 0x1>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <485>;
                        clocks = <&cru ARMCLKL>;
                        #cooling-cells = <2>; /* min followed by max */
                        dynamic-power-coefficient = <100>;
@@ -93,6 +95,7 @@
                        compatible = "arm,cortex-a53";
                        reg = <0x0 0x2>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <485>;
                        clocks = <&cru ARMCLKL>;
                        #cooling-cells = <2>; /* min followed by max */
                        dynamic-power-coefficient = <100>;
                        compatible = "arm,cortex-a53";
                        reg = <0x0 0x3>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <485>;
                        clocks = <&cru ARMCLKL>;
                        #cooling-cells = <2>; /* min followed by max */
                        dynamic-power-coefficient = <100>;
                        compatible = "arm,cortex-a72";
                        reg = <0x0 0x100>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
                        clocks = <&cru ARMCLKB>;
                        #cooling-cells = <2>; /* min followed by max */
                        dynamic-power-coefficient = <436>;
                        compatible = "arm,cortex-a72";
                        reg = <0x0 0x101>;
                        enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
                        clocks = <&cru ARMCLKB>;
                        #cooling-cells = <2>; /* min followed by max */
                        dynamic-power-coefficient = <436>;
                phys = <&emmc_phy>;
                phy-names = "phy_arasan";
                power-domains = <&power RK3399_PD_EMMC>;
+               disable-cqe-dcmd;
                status = "disabled";
        };
 
                        clock-names = "refclk";
                        #phy-cells = <1>;
                        resets = <&cru SRST_PCIEPHY>;
+                       drive-impedance-ohm = <50>;
                        reset-names = "phy";
                        status = "disabled";
                };
 
                clock {
                        clk_32k: clk-32k {
-                               rockchip,pins = <0 0 RK_FUNC_2 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA0 2 &pcfg_pull_none>;
                        };
                };
 
                edp {
                        edp_hpd: edp-hpd {
                                rockchip,pins =
-                                       <4 23 RK_FUNC_2 &pcfg_pull_none>;
+                                       <4 RK_PC7 2 &pcfg_pull_none>;
                        };
                };
 
                        rgmii_pins: rgmii-pins {
                                rockchip,pins =
                                        /* mac_txclk */
-                                       <3 17 RK_FUNC_1 &pcfg_pull_none_13ma>,
+                                       <3 RK_PC1 1 &pcfg_pull_none_13ma>,
                                        /* mac_rxclk */
-                                       <3 14 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PB6 1 &pcfg_pull_none>,
                                        /* mac_mdio */
-                                       <3 13 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PB5 1 &pcfg_pull_none>,
                                        /* mac_txen */
-                                       <3 12 RK_FUNC_1 &pcfg_pull_none_13ma>,
+                                       <3 RK_PB4 1 &pcfg_pull_none_13ma>,
                                        /* mac_clk */
-                                       <3 11 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PB3 1 &pcfg_pull_none>,
                                        /* mac_rxdv */
-                                       <3 9 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PB1 1 &pcfg_pull_none>,
                                        /* mac_mdc */
-                                       <3 8 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PB0 1 &pcfg_pull_none>,
                                        /* mac_rxd1 */
-                                       <3 7 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PA7 1 &pcfg_pull_none>,
                                        /* mac_rxd0 */
-                                       <3 6 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PA6 1 &pcfg_pull_none>,
                                        /* mac_txd1 */
-                                       <3 5 RK_FUNC_1 &pcfg_pull_none_13ma>,
+                                       <3 RK_PA5 1 &pcfg_pull_none_13ma>,
                                        /* mac_txd0 */
-                                       <3 4 RK_FUNC_1 &pcfg_pull_none_13ma>,
+                                       <3 RK_PA4 1 &pcfg_pull_none_13ma>,
                                        /* mac_rxd3 */
-                                       <3 3 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PA3 1 &pcfg_pull_none>,
                                        /* mac_rxd2 */
-                                       <3 2 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PA2 1 &pcfg_pull_none>,
                                        /* mac_txd3 */
-                                       <3 1 RK_FUNC_1 &pcfg_pull_none_13ma>,
+                                       <3 RK_PA1 1 &pcfg_pull_none_13ma>,
                                        /* mac_txd2 */
-                                       <3 0 RK_FUNC_1 &pcfg_pull_none_13ma>;
+                                       <3 RK_PA0 1 &pcfg_pull_none_13ma>;
                        };
 
                        rmii_pins: rmii-pins {
                                rockchip,pins =
                                        /* mac_mdio */
-                                       <3 13 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PB5 1 &pcfg_pull_none>,
                                        /* mac_txen */
-                                       <3 12 RK_FUNC_1 &pcfg_pull_none_13ma>,
+                                       <3 RK_PB4 1 &pcfg_pull_none_13ma>,
                                        /* mac_clk */
-                                       <3 11 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PB3 1 &pcfg_pull_none>,
                                        /* mac_rxer */
-                                       <3 10 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PB2 1 &pcfg_pull_none>,
                                        /* mac_rxdv */
-                                       <3 9 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PB1 1 &pcfg_pull_none>,
                                        /* mac_mdc */
-                                       <3 8 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PB0 1 &pcfg_pull_none>,
                                        /* mac_rxd1 */
-                                       <3 7 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PA7 1 &pcfg_pull_none>,
                                        /* mac_rxd0 */
-                                       <3 6 RK_FUNC_1 &pcfg_pull_none>,
+                                       <3 RK_PA6 1 &pcfg_pull_none>,
                                        /* mac_txd1 */
-                                       <3 5 RK_FUNC_1 &pcfg_pull_none_13ma>,
+                                       <3 RK_PA5 1 &pcfg_pull_none_13ma>,
                                        /* mac_txd0 */
-                                       <3 4 RK_FUNC_1 &pcfg_pull_none_13ma>;
+                                       <3 RK_PA4 1 &pcfg_pull_none_13ma>;
                        };
                };
 
                i2c0 {
                        i2c0_xfer: i2c0-xfer {
                                rockchip,pins =
-                                       <1 15 RK_FUNC_2 &pcfg_pull_none>,
-                                       <1 16 RK_FUNC_2 &pcfg_pull_none>;
+                                       <1 RK_PB7 2 &pcfg_pull_none>,
+                                       <1 RK_PC0 2 &pcfg_pull_none>;
                        };
                };
 
                i2c1 {
                        i2c1_xfer: i2c1-xfer {
                                rockchip,pins =
-                                       <4 2 RK_FUNC_1 &pcfg_pull_none>,
-                                       <4 1 RK_FUNC_1 &pcfg_pull_none>;
+                                       <4 RK_PA2 1 &pcfg_pull_none>,
+                                       <4 RK_PA1 1 &pcfg_pull_none>;
                        };
                };
 
                i2c2 {
                        i2c2_xfer: i2c2-xfer {
                                rockchip,pins =
-                                       <2 1 RK_FUNC_2 &pcfg_pull_none_12ma>,
-                                       <2 0 RK_FUNC_2 &pcfg_pull_none_12ma>;
+                                       <2 RK_PA1 2 &pcfg_pull_none_12ma>,
+                                       <2 RK_PA0 2 &pcfg_pull_none_12ma>;
                        };
                };
 
                i2c3 {
                        i2c3_xfer: i2c3-xfer {
                                rockchip,pins =
-                                       <4 17 RK_FUNC_1 &pcfg_pull_none>,
-                                       <4 16 RK_FUNC_1 &pcfg_pull_none>;
+                                       <4 RK_PC1 1 &pcfg_pull_none>,
+                                       <4 RK_PC0 1 &pcfg_pull_none>;
                        };
                };
 
                i2c4 {
                        i2c4_xfer: i2c4-xfer {
                                rockchip,pins =
-                                       <1 12 RK_FUNC_1 &pcfg_pull_none>,
-                                       <1 11 RK_FUNC_1 &pcfg_pull_none>;
+                                       <1 RK_PB4 1 &pcfg_pull_none>,
+                                       <1 RK_PB3 1 &pcfg_pull_none>;
                        };
                };
 
                i2c5 {
                        i2c5_xfer: i2c5-xfer {
                                rockchip,pins =
-                                       <3 11 RK_FUNC_2 &pcfg_pull_none>,
-                                       <3 10 RK_FUNC_2 &pcfg_pull_none>;
+                                       <3 RK_PB3 2 &pcfg_pull_none>,
+                                       <3 RK_PB2 2 &pcfg_pull_none>;
                        };
                };
 
                i2c6 {
                        i2c6_xfer: i2c6-xfer {
                                rockchip,pins =
-                                       <2 10 RK_FUNC_2 &pcfg_pull_none>,
-                                       <2 9 RK_FUNC_2 &pcfg_pull_none>;
+                                       <2 RK_PB2 2 &pcfg_pull_none>,
+                                       <2 RK_PB1 2 &pcfg_pull_none>;
                        };
                };
 
                i2c7 {
                        i2c7_xfer: i2c7-xfer {
                                rockchip,pins =
-                                       <2 8 RK_FUNC_2 &pcfg_pull_none>,
-                                       <2 7 RK_FUNC_2 &pcfg_pull_none>;
+                                       <2 RK_PB0 2 &pcfg_pull_none>,
+                                       <2 RK_PA7 2 &pcfg_pull_none>;
                        };
                };
 
                i2c8 {
                        i2c8_xfer: i2c8-xfer {
                                rockchip,pins =
-                                       <1 21 RK_FUNC_1 &pcfg_pull_none>,
-                                       <1 20 RK_FUNC_1 &pcfg_pull_none>;
+                                       <1 RK_PC5 1 &pcfg_pull_none>,
+                                       <1 RK_PC4 1 &pcfg_pull_none>;
                        };
                };
 
                i2s0 {
                        i2s0_2ch_bus: i2s0-2ch-bus {
                                rockchip,pins =
-                                       <3 24 RK_FUNC_1 &pcfg_pull_none>,
-                                       <3 25 RK_FUNC_1 &pcfg_pull_none>,
-                                       <3 26 RK_FUNC_1 &pcfg_pull_none>,
-                                       <3 27 RK_FUNC_1 &pcfg_pull_none>,
-                                       <3 31 RK_FUNC_1 &pcfg_pull_none>,
-                                       <4 0 RK_FUNC_1 &pcfg_pull_none>;
+                                       <3 RK_PD0 1 &pcfg_pull_none>,
+                                       <3 RK_PD1 1 &pcfg_pull_none>,
+                                       <3 RK_PD2 1 &pcfg_pull_none>,
+                                       <3 RK_PD3 1 &pcfg_pull_none>,
+                                       <3 RK_PD7 1 &pcfg_pull_none>,
+                                       <4 RK_PA0 1 &pcfg_pull_none>;
                        };
 
                        i2s0_8ch_bus: i2s0-8ch-bus {
                                rockchip,pins =
-                                       <3 24 RK_FUNC_1 &pcfg_pull_none>,
-                                       <3 25 RK_FUNC_1 &pcfg_pull_none>,
-                                       <3 26 RK_FUNC_1 &pcfg_pull_none>,
-                                       <3 27 RK_FUNC_1 &pcfg_pull_none>,
-                                       <3 28 RK_FUNC_1 &pcfg_pull_none>,
-                                       <3 29 RK_FUNC_1 &pcfg_pull_none>,
-                                       <3 30 RK_FUNC_1 &pcfg_pull_none>,
-                                       <3 31 RK_FUNC_1 &pcfg_pull_none>,
-                                       <4 0 RK_FUNC_1 &pcfg_pull_none>;
+                                       <3 RK_PD0 1 &pcfg_pull_none>,
+                                       <3 RK_PD1 1 &pcfg_pull_none>,
+                                       <3 RK_PD2 1 &pcfg_pull_none>,
+                                       <3 RK_PD3 1 &pcfg_pull_none>,
+                                       <3 RK_PD4 1 &pcfg_pull_none>,
+                                       <3 RK_PD5 1 &pcfg_pull_none>,
+                                       <3 RK_PD6 1 &pcfg_pull_none>,
+                                       <3 RK_PD7 1 &pcfg_pull_none>,
+                                       <4 RK_PA0 1 &pcfg_pull_none>;
                        };
                };
 
                i2s1 {
                        i2s1_2ch_bus: i2s1-2ch-bus {
                                rockchip,pins =
-                                       <4 3 RK_FUNC_1 &pcfg_pull_none>,
-                                       <4 4 RK_FUNC_1 &pcfg_pull_none>,
-                                       <4 5 RK_FUNC_1 &pcfg_pull_none>,
-                                       <4 6 RK_FUNC_1 &pcfg_pull_none>,
-                                       <4 7 RK_FUNC_1 &pcfg_pull_none>;
+                                       <4 RK_PA3 1 &pcfg_pull_none>,
+                                       <4 RK_PA4 1 &pcfg_pull_none>,
+                                       <4 RK_PA5 1 &pcfg_pull_none>,
+                                       <4 RK_PA6 1 &pcfg_pull_none>,
+                                       <4 RK_PA7 1 &pcfg_pull_none>;
                        };
                };
 
                sdio0 {
                        sdio0_bus1: sdio0-bus1 {
                                rockchip,pins =
-                                       <2 RK_PC4 RK_FUNC_1 &pcfg_pull_up>;
+                                       <2 RK_PC4 1 &pcfg_pull_up>;
                        };
 
                        sdio0_bus4: sdio0-bus4 {
                                rockchip,pins =
-                                       <2 RK_PC4 RK_FUNC_1 &pcfg_pull_up>,
-                                       <2 RK_PC5 RK_FUNC_1 &pcfg_pull_up>,
-                                       <2 RK_PC6 RK_FUNC_1 &pcfg_pull_up>,
-                                       <2 RK_PC7 RK_FUNC_1 &pcfg_pull_up>;
+                                       <2 RK_PC4 1 &pcfg_pull_up>,
+                                       <2 RK_PC5 1 &pcfg_pull_up>,
+                                       <2 RK_PC6 1 &pcfg_pull_up>,
+                                       <2 RK_PC7 1 &pcfg_pull_up>;
                        };
 
                        sdio0_cmd: sdio0-cmd {
                                rockchip,pins =
-                                       <2 RK_PD0 RK_FUNC_1 &pcfg_pull_up>;
+                                       <2 RK_PD0 1 &pcfg_pull_up>;
                        };
 
                        sdio0_clk: sdio0-clk {
                                rockchip,pins =
-                                       <2 RK_PD1 RK_FUNC_1 &pcfg_pull_none>;
+                                       <2 RK_PD1 1 &pcfg_pull_none>;
                        };
 
                        sdio0_cd: sdio0-cd {
                                rockchip,pins =
-                                       <2 RK_PD2 RK_FUNC_1 &pcfg_pull_up>;
+                                       <2 RK_PD2 1 &pcfg_pull_up>;
                        };
 
                        sdio0_pwr: sdio0-pwr {
                                rockchip,pins =
-                                       <2 RK_PD3 RK_FUNC_1 &pcfg_pull_up>;
+                                       <2 RK_PD3 1 &pcfg_pull_up>;
                        };
 
                        sdio0_bkpwr: sdio0-bkpwr {
                                rockchip,pins =
-                                       <2 RK_PD4 RK_FUNC_1 &pcfg_pull_up>;
+                                       <2 RK_PD4 1 &pcfg_pull_up>;
                        };
 
                        sdio0_wp: sdio0-wp {
                                rockchip,pins =
-                                       <0 RK_PA3 RK_FUNC_1 &pcfg_pull_up>;
+                                       <0 RK_PA3 1 &pcfg_pull_up>;
                        };
 
                        sdio0_int: sdio0-int {
                                rockchip,pins =
-                                       <0 RK_PA4 RK_FUNC_1 &pcfg_pull_up>;
+                                       <0 RK_PA4 1 &pcfg_pull_up>;
                        };
                };
 
                sdmmc {
                        sdmmc_bus1: sdmmc-bus1 {
                                rockchip,pins =
-                                       <4 RK_PB0 RK_FUNC_1 &pcfg_pull_up>;
+                                       <4 RK_PB0 1 &pcfg_pull_up>;
                        };
 
                        sdmmc_bus4: sdmmc-bus4 {
                                rockchip,pins =
-                                       <4 RK_PB0 RK_FUNC_1 &pcfg_pull_up>,
-                                       <4 RK_PB1 RK_FUNC_1 &pcfg_pull_up>,
-                                       <4 RK_PB2 RK_FUNC_1 &pcfg_pull_up>,
-                                       <4 RK_PB3 RK_FUNC_1 &pcfg_pull_up>;
+                                       <4 RK_PB0 1 &pcfg_pull_up>,
+                                       <4 RK_PB1 1 &pcfg_pull_up>,
+                                       <4 RK_PB2 1 &pcfg_pull_up>,
+                                       <4 RK_PB3 1 &pcfg_pull_up>;
                        };
 
                        sdmmc_clk: sdmmc-clk {
                                rockchip,pins =
-                                       <4 RK_PB4 RK_FUNC_1 &pcfg_pull_none>;
+                                       <4 RK_PB4 1 &pcfg_pull_none>;
                        };
 
                        sdmmc_cmd: sdmmc-cmd {
                                rockchip,pins =
-                                       <4 RK_PB5 RK_FUNC_1 &pcfg_pull_up>;
+                                       <4 RK_PB5 1 &pcfg_pull_up>;
                        };
 
                        sdmmc_cd: sdmmc-cd {
                                rockchip,pins =
-                                       <0 RK_PA7 RK_FUNC_1 &pcfg_pull_up>;
+                                       <0 RK_PA7 1 &pcfg_pull_up>;
                        };
 
                        sdmmc_wp: sdmmc-wp {
                                rockchip,pins =
-                                       <0 RK_PB0 RK_FUNC_1 &pcfg_pull_up>;
+                                       <0 RK_PB0 1 &pcfg_pull_up>;
                        };
                };
 
                sleep {
                        ap_pwroff: ap-pwroff {
-                               rockchip,pins = <1 5 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PA5 1 &pcfg_pull_none>;
                        };
 
                        ddrio_pwroff: ddrio-pwroff {
-                               rockchip,pins = <0 1 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <0 RK_PA1 1 &pcfg_pull_none>;
                        };
                };
 
                spdif {
                        spdif_bus: spdif-bus {
                                rockchip,pins =
-                                       <4 21 RK_FUNC_1 &pcfg_pull_none>;
+                                       <4 RK_PC5 1 &pcfg_pull_none>;
                        };
 
                        spdif_bus_1: spdif-bus-1 {
                                rockchip,pins =
-                                       <3 RK_PC0 RK_FUNC_3 &pcfg_pull_none>;
+                                       <3 RK_PC0 3 &pcfg_pull_none>;
                        };
                };
 
                spi0 {
                        spi0_clk: spi0-clk {
                                rockchip,pins =
-                                       <3 6 RK_FUNC_2 &pcfg_pull_up>;
+                                       <3 RK_PA6 2 &pcfg_pull_up>;
                        };
                        spi0_cs0: spi0-cs0 {
                                rockchip,pins =
-                                       <3 7 RK_FUNC_2 &pcfg_pull_up>;
+                                       <3 RK_PA7 2 &pcfg_pull_up>;
                        };
                        spi0_cs1: spi0-cs1 {
                                rockchip,pins =
-                                       <3 8 RK_FUNC_2 &pcfg_pull_up>;
+                                       <3 RK_PB0 2 &pcfg_pull_up>;
                        };
                        spi0_tx: spi0-tx {
                                rockchip,pins =
-                                       <3 5 RK_FUNC_2 &pcfg_pull_up>;
+                                       <3 RK_PA5 2 &pcfg_pull_up>;
                        };
                        spi0_rx: spi0-rx {
                                rockchip,pins =
-                                       <3 4 RK_FUNC_2 &pcfg_pull_up>;
+                                       <3 RK_PA4 2 &pcfg_pull_up>;
                        };
                };
 
                spi1 {
                        spi1_clk: spi1-clk {
                                rockchip,pins =
-                                       <1 9 RK_FUNC_2 &pcfg_pull_up>;
+                                       <1 RK_PB1 2 &pcfg_pull_up>;
                        };
                        spi1_cs0: spi1-cs0 {
                                rockchip,pins =
-                                       <1 10 RK_FUNC_2 &pcfg_pull_up>;
+                                       <1 RK_PB2 2 &pcfg_pull_up>;
                        };
                        spi1_rx: spi1-rx {
                                rockchip,pins =
-                                       <1 7 RK_FUNC_2 &pcfg_pull_up>;
+                                       <1 RK_PA7 2 &pcfg_pull_up>;
                        };
                        spi1_tx: spi1-tx {
                                rockchip,pins =
-                                       <1 8 RK_FUNC_2 &pcfg_pull_up>;
+                                       <1 RK_PB0 2 &pcfg_pull_up>;
                        };
                };
 
                spi2 {
                        spi2_clk: spi2-clk {
                                rockchip,pins =
-                                       <2 11 RK_FUNC_1 &pcfg_pull_up>;
+                                       <2 RK_PB3 1 &pcfg_pull_up>;
                        };
                        spi2_cs0: spi2-cs0 {
                                rockchip,pins =
-                                       <2 12 RK_FUNC_1 &pcfg_pull_up>;
+                                       <2 RK_PB4 1 &pcfg_pull_up>;
                        };
                        spi2_rx: spi2-rx {
                                rockchip,pins =
-                                       <2 9 RK_FUNC_1 &pcfg_pull_up>;
+                                       <2 RK_PB1 1 &pcfg_pull_up>;
                        };
                        spi2_tx: spi2-tx {
                                rockchip,pins =
-                                       <2 10 RK_FUNC_1 &pcfg_pull_up>;
+                                       <2 RK_PB2 1 &pcfg_pull_up>;
                        };
                };
 
                spi3 {
                        spi3_clk: spi3-clk {
                                rockchip,pins =
-                                       <1 17 RK_FUNC_1 &pcfg_pull_up>;
+                                       <1 RK_PC1 1 &pcfg_pull_up>;
                        };
                        spi3_cs0: spi3-cs0 {
                                rockchip,pins =
-                                       <1 18 RK_FUNC_1 &pcfg_pull_up>;
+                                       <1 RK_PC2 1 &pcfg_pull_up>;
                        };
                        spi3_rx: spi3-rx {
                                rockchip,pins =
-                                       <1 15 RK_FUNC_1 &pcfg_pull_up>;
+                                       <1 RK_PB7 1 &pcfg_pull_up>;
                        };
                        spi3_tx: spi3-tx {
                                rockchip,pins =
-                                       <1 16 RK_FUNC_1 &pcfg_pull_up>;
+                                       <1 RK_PC0 1 &pcfg_pull_up>;
                        };
                };
 
                spi4 {
                        spi4_clk: spi4-clk {
                                rockchip,pins =
-                                       <3 2 RK_FUNC_2 &pcfg_pull_up>;
+                                       <3 RK_PA2 2 &pcfg_pull_up>;
                        };
                        spi4_cs0: spi4-cs0 {
                                rockchip,pins =
-                                       <3 3 RK_FUNC_2 &pcfg_pull_up>;
+                                       <3 RK_PA3 2 &pcfg_pull_up>;
                        };
                        spi4_rx: spi4-rx {
                                rockchip,pins =
-                                       <3 0 RK_FUNC_2 &pcfg_pull_up>;
+                                       <3 RK_PA0 2 &pcfg_pull_up>;
                        };
                        spi4_tx: spi4-tx {
                                rockchip,pins =
-                                       <3 1 RK_FUNC_2 &pcfg_pull_up>;
+                                       <3 RK_PA1 2 &pcfg_pull_up>;
                        };
                };
 
                spi5 {
                        spi5_clk: spi5-clk {
                                rockchip,pins =
-                                       <2 22 RK_FUNC_2 &pcfg_pull_up>;
+                                       <2 RK_PC6 2 &pcfg_pull_up>;
                        };
                        spi5_cs0: spi5-cs0 {
                                rockchip,pins =
-                                       <2 23 RK_FUNC_2 &pcfg_pull_up>;
+                                       <2 RK_PC7 2 &pcfg_pull_up>;
                        };
                        spi5_rx: spi5-rx {
                                rockchip,pins =
-                                       <2 20 RK_FUNC_2 &pcfg_pull_up>;
+                                       <2 RK_PC4 2 &pcfg_pull_up>;
                        };
                        spi5_tx: spi5-tx {
                                rockchip,pins =
-                                       <2 21 RK_FUNC_2 &pcfg_pull_up>;
+                                       <2 RK_PC5 2 &pcfg_pull_up>;
                        };
                };
 
                testclk {
                        test_clkout0: test-clkout0 {
                                rockchip,pins =
-                                       <0 0 RK_FUNC_1 &pcfg_pull_none>;
+                                       <0 RK_PA0 1 &pcfg_pull_none>;
                        };
 
                        test_clkout1: test-clkout1 {
                                rockchip,pins =
-                                       <2 25 RK_FUNC_2 &pcfg_pull_none>;
+                                       <2 RK_PD1 2 &pcfg_pull_none>;
                        };
 
                        test_clkout2: test-clkout2 {
                                rockchip,pins =
-                                       <0 8 RK_FUNC_3 &pcfg_pull_none>;
+                                       <0 RK_PB0 3 &pcfg_pull_none>;
                        };
                };
 
                tsadc {
                        otp_gpio: otp-gpio {
-                               rockchip,pins = <1 6 RK_FUNC_GPIO &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
                        };
 
                        otp_out: otp-out {
-                               rockchip,pins = <1 6 RK_FUNC_1 &pcfg_pull_none>;
+                               rockchip,pins = <1 RK_PA6 1 &pcfg_pull_none>;
                        };
                };
 
                uart0 {
                        uart0_xfer: uart0-xfer {
                                rockchip,pins =
-                                       <2 16 RK_FUNC_1 &pcfg_pull_up>,
-                                       <2 17 RK_FUNC_1 &pcfg_pull_none>;
+                                       <2 RK_PC0 1 &pcfg_pull_up>,
+                                       <2 RK_PC1 1 &pcfg_pull_none>;
                        };
 
                        uart0_cts: uart0-cts {
                                rockchip,pins =
-                                       <2 18 RK_FUNC_1 &pcfg_pull_none>;
+                                       <2 RK_PC2 1 &pcfg_pull_none>;
                        };
 
                        uart0_rts: uart0-rts {
                                rockchip,pins =
-                                       <2 19 RK_FUNC_1 &pcfg_pull_none>;
+                                       <2 RK_PC3 1 &pcfg_pull_none>;
                        };
                };
 
                uart1 {
                        uart1_xfer: uart1-xfer {
                                rockchip,pins =
-                                       <3 12 RK_FUNC_2 &pcfg_pull_up>,
-                                       <3 13 RK_FUNC_2 &pcfg_pull_none>;
+                                       <3 RK_PB4 2 &pcfg_pull_up>,
+                                       <3 RK_PB5 2 &pcfg_pull_none>;
                        };
                };
 
                uart2a {
                        uart2a_xfer: uart2a-xfer {
                                rockchip,pins =
-                                       <4 8 RK_FUNC_2 &pcfg_pull_up>,
-                                       <4 9 RK_FUNC_2 &pcfg_pull_none>;
+                                       <4 RK_PB0 2 &pcfg_pull_up>,
+                                       <4 RK_PB1 2 &pcfg_pull_none>;
                        };
                };
 
                uart2b {
                        uart2b_xfer: uart2b-xfer {
                                rockchip,pins =
-                                       <4 16 RK_FUNC_2 &pcfg_pull_up>,
-                                       <4 17 RK_FUNC_2 &pcfg_pull_none>;
+                                       <4 RK_PC0 2 &pcfg_pull_up>,
+                                       <4 RK_PC1 2 &pcfg_pull_none>;
                        };
                };
 
                uart2c {
                        uart2c_xfer: uart2c-xfer {
                                rockchip,pins =
-                                       <4 19 RK_FUNC_1 &pcfg_pull_up>,
-                                       <4 20 RK_FUNC_1 &pcfg_pull_none>;
+                                       <4 RK_PC3 1 &pcfg_pull_up>,
+                                       <4 RK_PC4 1 &pcfg_pull_none>;
                        };
                };
 
                uart3 {
                        uart3_xfer: uart3-xfer {
                                rockchip,pins =
-                                       <3 14 RK_FUNC_2 &pcfg_pull_up>,
-                                       <3 15 RK_FUNC_2 &pcfg_pull_none>;
+                                       <3 RK_PB6 2 &pcfg_pull_up>,
+                                       <3 RK_PB7 2 &pcfg_pull_none>;
                        };
 
                        uart3_cts: uart3-cts {
                                rockchip,pins =
-                                       <3 18 RK_FUNC_2 &pcfg_pull_none>;
+                                       <3 RK_PC0 2 &pcfg_pull_none>;
                        };
 
                        uart3_rts: uart3-rts {
                                rockchip,pins =
-                                       <3 19 RK_FUNC_2 &pcfg_pull_none>;
+                                       <3 RK_PC1 2 &pcfg_pull_none>;
                        };
                };
 
                uart4 {
                        uart4_xfer: uart4-xfer {
                                rockchip,pins =
-                                       <1 7 RK_FUNC_1 &pcfg_pull_up>,
-                                       <1 8 RK_FUNC_1 &pcfg_pull_none>;
+                                       <1 RK_PA7 1 &pcfg_pull_up>,
+                                       <1 RK_PB0 1 &pcfg_pull_none>;
                        };
                };
 
                uarthdcp {
                        uarthdcp_xfer: uarthdcp-xfer {
                                rockchip,pins =
-                                       <4 21 RK_FUNC_2 &pcfg_pull_up>,
-                                       <4 22 RK_FUNC_2 &pcfg_pull_none>;
+                                       <4 RK_PC5 2 &pcfg_pull_up>,
+                                       <4 RK_PC6 2 &pcfg_pull_none>;
                        };
                };
 
                pwm0 {
                        pwm0_pin: pwm0-pin {
                                rockchip,pins =
-                                       <4 RK_PC2 RK_FUNC_1 &pcfg_pull_none>;
+                                       <4 RK_PC2 1 &pcfg_pull_none>;
                        };
 
                        pwm0_pin_pull_down: pwm0-pin-pull-down {
                                rockchip,pins =
-                                       <4 RK_PC2 RK_FUNC_1 &pcfg_pull_down>;
+                                       <4 RK_PC2 1 &pcfg_pull_down>;
                        };
 
                        vop0_pwm_pin: vop0-pwm-pin {
                                rockchip,pins =
-                                       <4 RK_PC2 RK_FUNC_2 &pcfg_pull_none>;
+                                       <4 RK_PC2 2 &pcfg_pull_none>;
                        };
 
                        vop1_pwm_pin: vop1-pwm-pin {
                                rockchip,pins =
-                                       <4 RK_PC2 RK_FUNC_3 &pcfg_pull_none>;
+                                       <4 RK_PC2 3 &pcfg_pull_none>;
                        };
                };
 
                pwm1 {
                        pwm1_pin: pwm1-pin {
                                rockchip,pins =
-                                       <4 RK_PC6 RK_FUNC_1 &pcfg_pull_none>;
+                                       <4 RK_PC6 1 &pcfg_pull_none>;
                        };
 
                        pwm1_pin_pull_down: pwm1-pin-pull-down {
                                rockchip,pins =
-                                       <4 RK_PC6 RK_FUNC_1 &pcfg_pull_down>;
+                                       <4 RK_PC6 1 &pcfg_pull_down>;
                        };
                };
 
                pwm2 {
                        pwm2_pin: pwm2-pin {
                                rockchip,pins =
-                                       <1 RK_PC3 RK_FUNC_1 &pcfg_pull_none>;
+                                       <1 RK_PC3 1 &pcfg_pull_none>;
                        };
 
                        pwm2_pin_pull_down: pwm2-pin-pull-down {
                                rockchip,pins =
-                                       <1 RK_PC3 RK_FUNC_1 &pcfg_pull_down>;
+                                       <1 RK_PC3 1 &pcfg_pull_down>;
                        };
                };
 
                pwm3a {
                        pwm3a_pin: pwm3a-pin {
                                rockchip,pins =
-                                       <0 RK_PA6 RK_FUNC_1 &pcfg_pull_none>;
+                                       <0 RK_PA6 1 &pcfg_pull_none>;
                        };
                };
 
                pwm3b {
                        pwm3b_pin: pwm3b-pin {
                                rockchip,pins =
-                                       <1 RK_PB6 RK_FUNC_1 &pcfg_pull_none>;
+                                       <1 RK_PB6 1 &pcfg_pull_none>;
                        };
                };
 
                hdmi {
                        hdmi_i2c_xfer: hdmi-i2c-xfer {
                                rockchip,pins =
-                                       <4 RK_PC1 RK_FUNC_3 &pcfg_pull_none>,
-                                       <4 RK_PC0 RK_FUNC_3 &pcfg_pull_none>;
+                                       <4 RK_PC1 3 &pcfg_pull_none>,
+                                       <4 RK_PC0 3 &pcfg_pull_none>;
                        };
 
                        hdmi_cec: hdmi-cec {
                                rockchip,pins =
-                                       <4 RK_PC7 RK_FUNC_1 &pcfg_pull_none>;
+                                       <4 RK_PC7 1 &pcfg_pull_none>;
                        };
                };
 
index 11cc67184fa9ffb832a9d02a1b66454dbd82a5d0..2421ec71a201c2b696ad2d329538e80acd42c1af 100644 (file)
@@ -89,6 +89,7 @@
                ti,rx-internal-delay = <0x8>;
                ti,tx-internal-delay = <0xa>;
                ti,fifo-depth = <0x1>;
+               ti,dp83867-rxctrl-strap-quirk;
        };
 };
 
index cef81671f3ab4e369b1847b5df03f507c2bd5ec3..2a3b66547c6d93a2331b2f799334d08c361535e9 100644 (file)
                ti,rx-internal-delay = <0x8>;
                ti,tx-internal-delay = <0xa>;
                ti,fifo-depth = <0x1>;
+               ti,dp83867-rxctrl-strap-quirk;
        };
 };
 
index af4d86882a5c30611b116abbaa8e4257efc40fbf..1780ed237daf2e60e92249b0db4d52c6157efd45 100644 (file)
@@ -21,6 +21,7 @@
                ti,rx-internal-delay = <0x8>;
                ti,tx-internal-delay = <0xa>;
                ti,fifo-depth = <0x1>;
+               ti,dp83867-rxctrl-strap-quirk;
        };
        /* Cleanup from RevA */
        /delete-node/ phy@21;
index d4ad19a38c936238f7db6199ff35073772a73aec..8f456146409fcc20b7c78d6846988fa5f0d19ad0 100644 (file)
@@ -55,6 +55,7 @@
                ti,rx-internal-delay = <0x8>;
                ti,tx-internal-delay = <0xa>;
                ti,fifo-depth = <0x1>;
+               ti,dp83867-rxctrl-strap-quirk;
        };
 };
 
index 94cf5094df648a8652f855db3a70a91fdba23b44..93ce7eb81498d15178ae755918e0382aa08af5c7 100644 (file)
                ti,rx-internal-delay = <0x8>;
                ti,tx-internal-delay = <0xa>;
                ti,fifo-depth = <0x1>;
+               ti,dp83867-rxctrl-strap-quirk;
        };
 };
 
index 460adc3782958257f91ad3e331a771d9f7ee958f..8bb0001a026fcc12f43a66b236437870f1ec8d6c 100644 (file)
                ti,rx-internal-delay = <0x8>;
                ti,tx-internal-delay = <0xa>;
                ti,fifo-depth = <0x1>;
+               ti,dp83867-rxctrl-strap-quirk;
        };
 };
 
index 2d9c39033c1aa91cff516457aed405d5de1dc2c2..4d583514258ce57b1edcde391aba9ce0d4211b3e 100644 (file)
@@ -29,6 +29,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
+CONFIG_ARCH_AGILEX=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_ARCH_ALPINE=y
 CONFIG_ARCH_BCM2835=y
@@ -46,15 +47,6 @@ CONFIG_ARCH_MVEBU=y
 CONFIG_ARCH_MXC=y
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_RENESAS=y
-CONFIG_ARCH_R8A774A1=y
-CONFIG_ARCH_R8A774C0=y
-CONFIG_ARCH_R8A7795=y
-CONFIG_ARCH_R8A7796=y
-CONFIG_ARCH_R8A77965=y
-CONFIG_ARCH_R8A77970=y
-CONFIG_ARCH_R8A77980=y
-CONFIG_ARCH_R8A77990=y
-CONFIG_ARCH_R8A77995=y
 CONFIG_ARCH_ROCKCHIP=y
 CONFIG_ARCH_SEATTLE=y
 CONFIG_ARCH_STRATIX10=y
@@ -68,25 +60,6 @@ CONFIG_ARCH_VEXPRESS=y
 CONFIG_ARCH_XGENE=y
 CONFIG_ARCH_ZX=y
 CONFIG_ARCH_ZYNQMP=y
-CONFIG_PCI=y
-CONFIG_PCIEPORTBUS=y
-CONFIG_PCI_IOV=y
-CONFIG_HOTPLUG_PCI=y
-CONFIG_HOTPLUG_PCI_ACPI=y
-CONFIG_PCI_AARDVARK=y
-CONFIG_PCI_TEGRA=y
-CONFIG_PCIE_RCAR=y
-CONFIG_PCI_HOST_GENERIC=y
-CONFIG_PCI_XGENE=y
-CONFIG_PCI_HOST_THUNDER_PEM=y
-CONFIG_PCI_HOST_THUNDER_ECAM=y
-CONFIG_PCIE_ROCKCHIP_HOST=m
-CONFIG_PCI_LAYERSCAPE=y
-CONFIG_PCI_HISI=y
-CONFIG_PCIE_QCOM=y
-CONFIG_PCIE_ARMADA_8K=y
-CONFIG_PCIE_KIRIN=y
-CONFIG_PCIE_HISI_STB=y
 CONFIG_ARM64_VA_BITS_48=y
 CONFIG_SCHED_MC=y
 CONFIG_NUMA=y
@@ -112,6 +85,7 @@ CONFIG_ARM_SCPI_CPUFREQ=y
 CONFIG_ARM_TEGRA186_CPUFREQ=y
 CONFIG_ARM_SCPI_PROTOCOL=y
 CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_INTEL_STRATIX10_SERVICE=y
 CONFIG_TI_SCI_PROTOCOL=y
 CONFIG_EFI_CAPSULE_LOADER=y
 CONFIG_IMX_SCU=y
@@ -196,17 +170,36 @@ CONFIG_MAC80211_LEDS=y
 CONFIG_RFKILL=m
 CONFIG_NET_9P=y
 CONFIG_NET_9P_VIRTIO=y
+CONFIG_PCI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCI_IOV=y
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_ACPI=y
+CONFIG_PCI_AARDVARK=y
+CONFIG_PCI_TEGRA=y
+CONFIG_PCIE_RCAR=y
+CONFIG_PCI_HOST_GENERIC=y
+CONFIG_PCI_XGENE=y
+CONFIG_PCIE_ALTERA=y
+CONFIG_PCIE_ALTERA_MSI=y
+CONFIG_PCI_HOST_THUNDER_PEM=y
+CONFIG_PCI_HOST_THUNDER_ECAM=y
+CONFIG_PCIE_ROCKCHIP_HOST=m
+CONFIG_PCI_LAYERSCAPE=y
+CONFIG_PCI_HISI=y
+CONFIG_PCIE_QCOM=y
+CONFIG_PCIE_ARMADA_8K=y
+CONFIG_PCIE_KIRIN=y
+CONFIG_PCIE_HISI_STB=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_DMA_CMA=y
-CONFIG_CMA_SIZE_MBYTES=32
 CONFIG_HISILICON_LPC=y
 CONFIG_SIMPLE_PM_BUS=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_M25P80=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_DENALI_DT=y
 CONFIG_MTD_NAND_MARVELL=y
 CONFIG_MTD_NAND_QCOM=y
@@ -222,10 +215,10 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_SCSI_SAS_ATA=y
 CONFIG_SCSI_HISI_SAS=y
 CONFIG_SCSI_HISI_SAS_PCI=y
-CONFIG_SCSI_UFSHCD=m
-CONFIG_SCSI_UFSHCD_PLATFORM=m
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
 CONFIG_SCSI_UFS_QCOM=m
-CONFIG_SCSI_UFS_HISI=m
+CONFIG_SCSI_UFS_HISI=y
 CONFIG_ATA=y
 CONFIG_SATA_AHCI=y
 CONFIG_SATA_AHCI_PLATFORM=y
@@ -364,6 +357,7 @@ CONFIG_SPI=y
 CONFIG_SPI_ARMADA_3700=y
 CONFIG_SPI_BCM2835=m
 CONFIG_SPI_BCM2835AUX=m
+CONFIG_SPI_NXP_FLEXSPI=y
 CONFIG_SPI_MESON_SPICC=m
 CONFIG_SPI_MESON_SPIFC=m
 CONFIG_SPI_ORION=y
@@ -372,7 +366,7 @@ CONFIG_SPI_ROCKCHIP=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_S3C64XX=y
 CONFIG_SPI_SPIDEV=m
-CONFIG_SPI_NXP_FLEXSPI=y
+CONFIG_SPI_SUN6I=y
 CONFIG_SPMI=y
 CONFIG_PINCTRL_SINGLE=y
 CONFIG_PINCTRL_MAX77620=y
@@ -387,7 +381,6 @@ CONFIG_PINCTRL_QCS404=y
 CONFIG_PINCTRL_QDF2XXX=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_PINCTRL_SDM845=y
-CONFIG_PINCTRL_MTK_MOORE=y
 CONFIG_GPIO_DWAPB=y
 CONFIG_GPIO_MB86S7X=y
 CONFIG_GPIO_PL061=y
@@ -408,6 +401,7 @@ CONFIG_BATTERY_SBS=m
 CONFIG_BATTERY_BQ27XXX=y
 CONFIG_SENSORS_ARM_SCPI=y
 CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_PWM_FAN=m
 CONFIG_SENSORS_RASPBERRYPI_HWMON=m
 CONFIG_SENSORS_INA2XX=m
 CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
@@ -432,6 +426,7 @@ CONFIG_MESON_WATCHDOG=m
 CONFIG_RENESAS_WDT=y
 CONFIG_UNIPHIER_WATCHDOG=y
 CONFIG_BCM2835_WDT=y
+CONFIG_MFD_ALTERA_SYSMGR=y
 CONFIG_MFD_BD9571MWV=y
 CONFIG_MFD_AXP20X_I2C=y
 CONFIG_MFD_AXP20X_RSB=y
@@ -472,14 +467,14 @@ CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 # CONFIG_DVB_NET is not set
-CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_MEDIA_USB_SUPPORT=y
 CONFIG_USB_VIDEO_CLASS=m
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_SUN6I_CSI=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_SUN6I_CSI=m
 CONFIG_VIDEO_RENESAS_FCP=m
 CONFIG_VIDEO_RENESAS_VSP1=m
 CONFIG_DRM=m
@@ -498,7 +493,6 @@ CONFIG_ROCKCHIP_DW_HDMI=y
 CONFIG_ROCKCHIP_DW_MIPI_DSI=y
 CONFIG_ROCKCHIP_INNO_HDMI=y
 CONFIG_DRM_RCAR_DU=m
-CONFIG_DRM_RCAR_LVDS=m
 CONFIG_DRM_SUN4I=m
 CONFIG_DRM_SUN8I_DW_HDMI=m
 CONFIG_DRM_SUN8I_MIXER=m
@@ -513,7 +507,6 @@ CONFIG_DRM_MESON=m
 CONFIG_DRM_PL111=m
 CONFIG_FB=y
 CONFIG_FB_MODE_HELPERS=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_GENERIC=m
 CONFIG_BACKLIGHT_PWM=m
 CONFIG_BACKLIGHT_LP855X=m
@@ -522,22 +515,24 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_VGA16 is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
+CONFIG_SND_HDA_TEGRA=m
+CONFIG_SND_HDA_CODEC_HDMI=m
 CONFIG_SND_SOC=y
 CONFIG_SND_BCM2835_SOC_I2S=m
+CONFIG_SND_MESON_AXG_SOUND_CARD=m
 CONFIG_SND_SOC_ROCKCHIP=m
 CONFIG_SND_SOC_ROCKCHIP_SPDIF=m
 CONFIG_SND_SOC_ROCKCHIP_RT5645=m
 CONFIG_SND_SOC_RK3399_GRU_SOUND=m
-CONFIG_SND_MESON_AXG_SOUND_CARD=m
 CONFIG_SND_SOC_SAMSUNG=y
 CONFIG_SND_SOC_RCAR=m
 CONFIG_SND_SOC_AK4613=m
-CONFIG_SND_SOC_PCM3168A_I2C=m
-CONFIG_SND_SIMPLE_CARD=m
-CONFIG_SND_AUDIO_GRAPH_CARD=m
 CONFIG_SND_SOC_ES7134=m
 CONFIG_SND_SOC_ES7241=m
+CONFIG_SND_SOC_PCM3168A_I2C=m
 CONFIG_SND_SOC_TAS571X=m
+CONFIG_SND_SIMPLE_CARD=m
+CONFIG_SND_AUDIO_GRAPH_CARD=m
 CONFIG_I2C_HID=m
 CONFIG_USB=y
 CONFIG_USB_OTG=y
@@ -605,6 +600,7 @@ CONFIG_EDAC_GHES=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_MAX77686=y
 CONFIG_RTC_DRV_RK808=m
+CONFIG_RTC_DRV_RX8581=m
 CONFIG_RTC_DRV_S5M=y
 CONFIG_RTC_DRV_DS3232=y
 CONFIG_RTC_DRV_EFI=y
@@ -619,6 +615,7 @@ CONFIG_RTC_DRV_XGENE=y
 CONFIG_DMADEVICES=y
 CONFIG_DMA_BCM2835=m
 CONFIG_K3_DMA=y
+CONFIG_MV_XOR=y
 CONFIG_MV_XOR_V2=y
 CONFIG_PL330_DMA=y
 CONFIG_TEGRA20_APB_DMA=y
@@ -676,7 +673,6 @@ CONFIG_RPMSG_QCOM_GLINK_RPM=y
 CONFIG_RPMSG_QCOM_GLINK_SMEM=m
 CONFIG_RPMSG_QCOM_SMD=y
 CONFIG_RASPBERRYPI_POWER=y
-CONFIG_IMX_GPCV2_PM_DOMAINS=y
 CONFIG_QCOM_COMMAND_DB=y
 CONFIG_QCOM_GENI_SE=y
 CONFIG_QCOM_GLINK_SSR=m
@@ -685,6 +681,15 @@ CONFIG_QCOM_SMEM=y
 CONFIG_QCOM_SMD_RPM=y
 CONFIG_QCOM_SMP2P=y
 CONFIG_QCOM_SMSM=y
+CONFIG_ARCH_R8A774A1=y
+CONFIG_ARCH_R8A774C0=y
+CONFIG_ARCH_R8A7795=y
+CONFIG_ARCH_R8A7796=y
+CONFIG_ARCH_R8A77965=y
+CONFIG_ARCH_R8A77970=y
+CONFIG_ARCH_R8A77980=y
+CONFIG_ARCH_R8A77990=y
+CONFIG_ARCH_R8A77995=y
 CONFIG_ROCKCHIP_PM_DOMAINS=y
 CONFIG_ARCH_TEGRA_132_SOC=y
 CONFIG_ARCH_TEGRA_210_SOC=y
@@ -740,6 +745,12 @@ CONFIG_QCOM_QFPROM=y
 CONFIG_ROCKCHIP_EFUSE=y
 CONFIG_UNIPHIER_EFUSE=y
 CONFIG_MESON_EFUSE=m
+CONFIG_FPGA=y
+CONFIG_FPGA_MGR_STRATIX10_SOC=m
+CONFIG_FPGA_BRIDGE=m
+CONFIG_ALTERA_FREEZE_BRIDGE=m
+CONFIG_FPGA_REGION=m
+CONFIG_OF_FPGA_REGION=m
 CONFIG_TEE=y
 CONFIG_OPTEE=y
 CONFIG_EXT2_FS=y
@@ -770,6 +781,8 @@ CONFIG_NLS_ISO8859_1=y
 CONFIG_SECURITY=y
 CONFIG_CRYPTO_ECHAINIV=y
 CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=32
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_FS=y
index eb0df239a759fcaa7ffb8db7b092b5246b446092..1de6e05ce48b2a079c4ed3a31eebca91f294a87b 100644 (file)
@@ -17,10 +17,8 @@ generic-y += mmiowb.h
 generic-y += msi.h
 generic-y += qrwlock.h
 generic-y += qspinlock.h
-generic-y += segment.h
 generic-y += serial.h
 generic-y += set_memory.h
-generic-y += sizes.h
 generic-y += switch_to.h
 generic-y += trace_clock.h
 generic-y += unaligned.h
index 355e552a9175a0b81d4c51e89d62faf3f1584819..c7f67da13cd99ae677db63f5f19f5e118c64a202 100644 (file)
@@ -3,7 +3,7 @@
 #ifndef __ASM_BOOT_H
 #define __ASM_BOOT_H
 
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 /*
  * arm64 requires the DTB to be 8 byte aligned and
index f210bcf096f76543aca975aa34b9228ae8ef6487..bc895c869892ce7ae8f82faae98c17d05c654850 100644 (file)
@@ -401,7 +401,7 @@ unsigned long cpu_get_elf_hwcap2(void);
 #define cpu_have_named_feature(name) cpu_have_feature(cpu_feature(name))
 
 /* System capability check for constant caps */
-static inline bool __cpus_have_const_cap(int num)
+static __always_inline bool __cpus_have_const_cap(int num)
 {
        if (num >= ARM64_NCAPS)
                return false;
@@ -415,7 +415,7 @@ static inline bool cpus_have_cap(unsigned int num)
        return test_bit(num, cpu_hwcaps);
 }
 
-static inline bool cpus_have_const_cap(int num)
+static __always_inline bool cpus_have_const_cap(int num)
 {
        if (static_branch_likely(&arm64_const_caps_ready))
                return __cpus_have_const_cap(num);
index dd1ad3950ef5dfbe270768d27da0aca82d534c8c..df62bbd33a9a62592e9bf80f7dd1b7e66ed6708b 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+#include <linux/bitmap.h>
 #include <linux/build_bug.h>
+#include <linux/bug.h>
 #include <linux/cache.h>
 #include <linux/init.h>
 #include <linux/stddef.h>
+#include <linux/types.h>
 
 #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
 /* Masks for extracting the FPSR and FPCR from the FPSCR */
@@ -56,7 +59,8 @@ extern void fpsimd_restore_current_state(void);
 extern void fpsimd_update_current_state(struct user_fpsimd_state const *state);
 
 extern void fpsimd_bind_task_to_cpu(void);
-extern void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *state);
+extern void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *state,
+                                    void *sve_state, unsigned int sve_vl);
 
 extern void fpsimd_flush_task_state(struct task_struct *target);
 extern void fpsimd_flush_cpu_state(void);
@@ -87,6 +91,29 @@ extern void sve_kernel_enable(const struct arm64_cpu_capabilities *__unused);
 extern u64 read_zcr_features(void);
 
 extern int __ro_after_init sve_max_vl;
+extern int __ro_after_init sve_max_virtualisable_vl;
+extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
+
+/*
+ * Helpers to translate bit indices in sve_vq_map to VQ values (and
+ * vice versa).  This allows find_next_bit() to be used to find the
+ * _maximum_ VQ not exceeding a certain value.
+ */
+static inline unsigned int __vq_to_bit(unsigned int vq)
+{
+       return SVE_VQ_MAX - vq;
+}
+
+static inline unsigned int __bit_to_vq(unsigned int bit)
+{
+       return SVE_VQ_MAX - bit;
+}
+
+/* Ensure vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX before calling this function */
+static inline bool sve_vq_available(unsigned int vq)
+{
+       return test_bit(__vq_to_bit(vq), sve_vq_map);
+}
 
 #ifdef CONFIG_ARM64_SVE
 
index c6a07a3b433e3d09b9b0ff08ed53a881470b6508..4aad6382f6319198f9df0e24df297e5c7b0a61bf 100644 (file)
@@ -70,8 +70,4 @@ extern void set_huge_swap_pte_at(struct mm_struct *mm, unsigned long addr,
 
 #include <asm-generic/hugetlb.h>
 
-#ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE
-static inline bool gigantic_page_supported(void) { return true; }
-#endif
-
 #endif /* __ASM_HUGETLB_H */
index f5b79e995f406051ebf4942da7199155843641ef..ff73f5462aca512a8f19acca00ab41b07bf2e34c 100644 (file)
@@ -108,7 +108,8 @@ extern u32 __kvm_get_mdcr_el2(void);
 .endm
 
 .macro get_host_ctxt reg, tmp
-       hyp_adr_this_cpu \reg, kvm_host_cpu_state, \tmp
+       hyp_adr_this_cpu \reg, kvm_host_data, \tmp
+       add     \reg, \reg, #HOST_DATA_CONTEXT
 .endm
 
 .macro get_vcpu_ptr vcpu, ctxt
index d3842791e1c42a2a9bc8b62238b1658c1e650193..613427fafff978c6654fc5815a04ee3059fc3e65 100644 (file)
@@ -98,6 +98,22 @@ static inline void vcpu_set_wfe_traps(struct kvm_vcpu *vcpu)
        vcpu->arch.hcr_el2 |= HCR_TWE;
 }
 
+static inline void vcpu_ptrauth_enable(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.hcr_el2 |= (HCR_API | HCR_APK);
+}
+
+static inline void vcpu_ptrauth_disable(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.hcr_el2 &= ~(HCR_API | HCR_APK);
+}
+
+static inline void vcpu_ptrauth_setup_lazy(struct kvm_vcpu *vcpu)
+{
+       if (vcpu_has_ptrauth(vcpu))
+               vcpu_ptrauth_disable(vcpu);
+}
+
 static inline unsigned long vcpu_get_vsesr(struct kvm_vcpu *vcpu)
 {
        return vcpu->arch.vsesr_el2;
index a01fe087e022882d63f50e6fb766b13217a38208..2a8d3f8ca22c38c0a747115b07b97131536611c4 100644 (file)
 #ifndef __ARM64_KVM_HOST_H__
 #define __ARM64_KVM_HOST_H__
 
+#include <linux/bitmap.h>
 #include <linux/types.h>
+#include <linux/jump_label.h>
 #include <linux/kvm_types.h>
+#include <linux/percpu.h>
 #include <asm/arch_gicv3.h>
+#include <asm/barrier.h>
 #include <asm/cpufeature.h>
 #include <asm/daifflags.h>
 #include <asm/fpsimd.h>
@@ -45,7 +49,7 @@
 
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
-#define KVM_VCPU_MAX_FEATURES 4
+#define KVM_VCPU_MAX_FEATURES 7
 
 #define KVM_REQ_SLEEP \
        KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
 
 DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
 
+extern unsigned int kvm_sve_max_vl;
+int kvm_arm_init_sve(void);
+
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
+void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu);
 int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
 void __extended_idmap_trampoline(phys_addr_t boot_pgd, phys_addr_t idmap_start);
 
@@ -117,6 +125,7 @@ enum vcpu_sysreg {
        SCTLR_EL1,      /* System Control Register */
        ACTLR_EL1,      /* Auxiliary Control Register */
        CPACR_EL1,      /* Coprocessor Access Control */
+       ZCR_EL1,        /* SVE Control */
        TTBR0_EL1,      /* Translation Table Base Register 0 */
        TTBR1_EL1,      /* Translation Table Base Register 1 */
        TCR_EL1,        /* Translation Control Register */
@@ -152,6 +161,18 @@ enum vcpu_sysreg {
        PMSWINC_EL0,    /* Software Increment Register */
        PMUSERENR_EL0,  /* User Enable Register */
 
+       /* Pointer Authentication Registers in a strict increasing order. */
+       APIAKEYLO_EL1,
+       APIAKEYHI_EL1,
+       APIBKEYLO_EL1,
+       APIBKEYHI_EL1,
+       APDAKEYLO_EL1,
+       APDAKEYHI_EL1,
+       APDBKEYLO_EL1,
+       APDBKEYHI_EL1,
+       APGAKEYLO_EL1,
+       APGAKEYHI_EL1,
+
        /* 32bit specific registers. Keep them at the end of the range */
        DACR32_EL2,     /* Domain Access Control Register */
        IFSR32_EL2,     /* Instruction Fault Status Register */
@@ -212,7 +233,17 @@ struct kvm_cpu_context {
        struct kvm_vcpu *__hyp_running_vcpu;
 };
 
-typedef struct kvm_cpu_context kvm_cpu_context_t;
+struct kvm_pmu_events {
+       u32 events_host;
+       u32 events_guest;
+};
+
+struct kvm_host_data {
+       struct kvm_cpu_context host_ctxt;
+       struct kvm_pmu_events pmu_events;
+};
+
+typedef struct kvm_host_data kvm_host_data_t;
 
 struct vcpu_reset_state {
        unsigned long   pc;
@@ -223,6 +254,8 @@ struct vcpu_reset_state {
 
 struct kvm_vcpu_arch {
        struct kvm_cpu_context ctxt;
+       void *sve_state;
+       unsigned int sve_max_vl;
 
        /* HYP configuration */
        u64 hcr_el2;
@@ -255,7 +288,7 @@ struct kvm_vcpu_arch {
        struct kvm_guest_debug_arch external_debug_state;
 
        /* Pointer to host CPU context */
-       kvm_cpu_context_t *host_cpu_context;
+       struct kvm_cpu_context *host_cpu_context;
 
        struct thread_info *host_thread_info;   /* hyp VA */
        struct user_fpsimd_state *host_fpsimd_state;    /* hyp VA */
@@ -318,12 +351,40 @@ struct kvm_vcpu_arch {
        bool sysregs_loaded_on_cpu;
 };
 
+/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
+#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
+                                     sve_ffr_offset((vcpu)->arch.sve_max_vl)))
+
+#define vcpu_sve_state_size(vcpu) ({                                   \
+       size_t __size_ret;                                              \
+       unsigned int __vcpu_vq;                                         \
+                                                                       \
+       if (WARN_ON(!sve_vl_valid((vcpu)->arch.sve_max_vl))) {          \
+               __size_ret = 0;                                         \
+       } else {                                                        \
+               __vcpu_vq = sve_vq_from_vl((vcpu)->arch.sve_max_vl);    \
+               __size_ret = SVE_SIG_REGS_SIZE(__vcpu_vq);              \
+       }                                                               \
+                                                                       \
+       __size_ret;                                                     \
+})
+
 /* vcpu_arch flags field values: */
 #define KVM_ARM64_DEBUG_DIRTY          (1 << 0)
 #define KVM_ARM64_FP_ENABLED           (1 << 1) /* guest FP regs loaded */
 #define KVM_ARM64_FP_HOST              (1 << 2) /* host FP regs loaded */
 #define KVM_ARM64_HOST_SVE_IN_USE      (1 << 3) /* backup for host TIF_SVE */
 #define KVM_ARM64_HOST_SVE_ENABLED     (1 << 4) /* SVE enabled for EL0 */
+#define KVM_ARM64_GUEST_HAS_SVE                (1 << 5) /* SVE exposed to guest */
+#define KVM_ARM64_VCPU_SVE_FINALIZED   (1 << 6) /* SVE config completed */
+#define KVM_ARM64_GUEST_HAS_PTRAUTH    (1 << 7) /* PTRAUTH exposed to guest */
+
+#define vcpu_has_sve(vcpu) (system_supports_sve() && \
+                           ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
+
+#define vcpu_has_ptrauth(vcpu) ((system_supports_address_auth() || \
+                                 system_supports_generic_auth()) && \
+                                ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_PTRAUTH))
 
 #define vcpu_gp_regs(v)                (&(v)->arch.ctxt.gp_regs)
 
@@ -432,9 +493,9 @@ void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 syndrome);
 
 struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
 
-DECLARE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state);
+DECLARE_PER_CPU(kvm_host_data_t, kvm_host_data);
 
-static inline void kvm_init_host_cpu_context(kvm_cpu_context_t *cpu_ctxt,
+static inline void kvm_init_host_cpu_context(struct kvm_cpu_context *cpu_ctxt,
                                             int cpu)
 {
        /* The host's MPIDR is immutable, so let's set it up at boot time */
@@ -452,8 +513,8 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
         * kernel's mapping to the linear mapping, and store it in tpidr_el2
         * so that we can use adr_l to access per-cpu variables in EL2.
         */
-       u64 tpidr_el2 = ((u64)this_cpu_ptr(&kvm_host_cpu_state) -
-                        (u64)kvm_ksym_ref(kvm_host_cpu_state));
+       u64 tpidr_el2 = ((u64)this_cpu_ptr(&kvm_host_data) -
+                        (u64)kvm_ksym_ref(kvm_host_data));
 
        /*
         * Call initialization code, and switch to the full blown HYP code.
@@ -491,9 +552,10 @@ static inline bool kvm_arch_requires_vhe(void)
        return false;
 }
 
+void kvm_arm_vcpu_ptrauth_trap(struct kvm_vcpu *vcpu);
+
 static inline void kvm_arch_hardware_unsetup(void) {}
 static inline void kvm_arch_sync_events(struct kvm *kvm) {}
-static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
 static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
 static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
 
@@ -516,11 +578,28 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu);
 void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu);
 void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu);
 
+static inline bool kvm_pmu_counter_deferred(struct perf_event_attr *attr)
+{
+       return (!has_vhe() && attr->exclude_host);
+}
+
 #ifdef CONFIG_KVM /* Avoid conflicts with core headers if CONFIG_KVM=n */
 static inline int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
 {
        return kvm_arch_vcpu_run_map_fp(vcpu);
 }
+
+void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr);
+void kvm_clr_pmu_events(u32 clr);
+
+void __pmu_switch_to_host(struct kvm_cpu_context *host_ctxt);
+bool __pmu_switch_to_guest(struct kvm_cpu_context *host_ctxt);
+
+void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu);
+void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu);
+#else
+static inline void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr) {}
+static inline void kvm_clr_pmu_events(u32 clr) {}
 #endif
 
 static inline void kvm_arm_vhe_guest_enter(void)
@@ -594,4 +673,10 @@ void kvm_arch_free_vm(struct kvm *kvm);
 
 int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
 
+int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature);
+bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
+
+#define kvm_arm_vcpu_sve_finalized(vcpu) \
+       ((vcpu)->arch.flags & KVM_ARM64_VCPU_SVE_FINALIZED)
+
 #endif /* __ARM64_KVM_HOST_H__ */
index c3060833b7a5aae918bd902963b1dff2843beae1..09fe8bd15f6e763f9c8711e9943f6c09a3f486f4 100644 (file)
@@ -149,7 +149,6 @@ void __debug_switch_to_host(struct kvm_vcpu *vcpu);
 
 void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
 void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
-bool __fpsimd_enabled(void);
 
 void activate_traps_vhe_load(struct kvm_vcpu *vcpu);
 void deactivate_traps_vhe_put(void);
diff --git a/arch/arm64/include/asm/kvm_ptrauth.h b/arch/arm64/include/asm/kvm_ptrauth.h
new file mode 100644 (file)
index 0000000..6301813
--- /dev/null
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* arch/arm64/include/asm/kvm_ptrauth.h: Guest/host ptrauth save/restore
+ * Copyright 2019 Arm Limited
+ * Authors: Mark Rutland <mark.rutland@arm.com>
+ *         Amit Daniel Kachhap <amit.kachhap@arm.com>
+ */
+
+#ifndef __ASM_KVM_PTRAUTH_H
+#define __ASM_KVM_PTRAUTH_H
+
+#ifdef __ASSEMBLY__
+
+#include <asm/sysreg.h>
+
+#ifdef CONFIG_ARM64_PTR_AUTH
+
+#define PTRAUTH_REG_OFFSET(x)  (x - CPU_APIAKEYLO_EL1)
+
+/*
+ * CPU_AP*_EL1 values exceed immediate offset range (512) for stp
+ * instruction so below macros takes CPU_APIAKEYLO_EL1 as base and
+ * calculates the offset of the keys from this base to avoid an extra add
+ * instruction. These macros assumes the keys offsets follow the order of
+ * the sysreg enum in kvm_host.h.
+ */
+.macro ptrauth_save_state base, reg1, reg2
+       mrs_s   \reg1, SYS_APIAKEYLO_EL1
+       mrs_s   \reg2, SYS_APIAKEYHI_EL1
+       stp     \reg1, \reg2, [\base, #PTRAUTH_REG_OFFSET(CPU_APIAKEYLO_EL1)]
+       mrs_s   \reg1, SYS_APIBKEYLO_EL1
+       mrs_s   \reg2, SYS_APIBKEYHI_EL1
+       stp     \reg1, \reg2, [\base, #PTRAUTH_REG_OFFSET(CPU_APIBKEYLO_EL1)]
+       mrs_s   \reg1, SYS_APDAKEYLO_EL1
+       mrs_s   \reg2, SYS_APDAKEYHI_EL1
+       stp     \reg1, \reg2, [\base, #PTRAUTH_REG_OFFSET(CPU_APDAKEYLO_EL1)]
+       mrs_s   \reg1, SYS_APDBKEYLO_EL1
+       mrs_s   \reg2, SYS_APDBKEYHI_EL1
+       stp     \reg1, \reg2, [\base, #PTRAUTH_REG_OFFSET(CPU_APDBKEYLO_EL1)]
+       mrs_s   \reg1, SYS_APGAKEYLO_EL1
+       mrs_s   \reg2, SYS_APGAKEYHI_EL1
+       stp     \reg1, \reg2, [\base, #PTRAUTH_REG_OFFSET(CPU_APGAKEYLO_EL1)]
+.endm
+
+.macro ptrauth_restore_state base, reg1, reg2
+       ldp     \reg1, \reg2, [\base, #PTRAUTH_REG_OFFSET(CPU_APIAKEYLO_EL1)]
+       msr_s   SYS_APIAKEYLO_EL1, \reg1
+       msr_s   SYS_APIAKEYHI_EL1, \reg2
+       ldp     \reg1, \reg2, [\base, #PTRAUTH_REG_OFFSET(CPU_APIBKEYLO_EL1)]
+       msr_s   SYS_APIBKEYLO_EL1, \reg1
+       msr_s   SYS_APIBKEYHI_EL1, \reg2
+       ldp     \reg1, \reg2, [\base, #PTRAUTH_REG_OFFSET(CPU_APDAKEYLO_EL1)]
+       msr_s   SYS_APDAKEYLO_EL1, \reg1
+       msr_s   SYS_APDAKEYHI_EL1, \reg2
+       ldp     \reg1, \reg2, [\base, #PTRAUTH_REG_OFFSET(CPU_APDBKEYLO_EL1)]
+       msr_s   SYS_APDBKEYLO_EL1, \reg1
+       msr_s   SYS_APDBKEYHI_EL1, \reg2
+       ldp     \reg1, \reg2, [\base, #PTRAUTH_REG_OFFSET(CPU_APGAKEYLO_EL1)]
+       msr_s   SYS_APGAKEYLO_EL1, \reg1
+       msr_s   SYS_APGAKEYHI_EL1, \reg2
+.endm
+
+/*
+ * Both ptrauth_switch_to_guest and ptrauth_switch_to_host macros will
+ * check for the presence of one of the cpufeature flag
+ * ARM64_HAS_ADDRESS_AUTH_ARCH or ARM64_HAS_ADDRESS_AUTH_IMP_DEF and
+ * then proceed ahead with the save/restore of Pointer Authentication
+ * key registers.
+ */
+.macro ptrauth_switch_to_guest g_ctxt, reg1, reg2, reg3
+alternative_if ARM64_HAS_ADDRESS_AUTH_ARCH
+       b       1000f
+alternative_else_nop_endif
+alternative_if_not ARM64_HAS_ADDRESS_AUTH_IMP_DEF
+       b       1001f
+alternative_else_nop_endif
+1000:
+       ldr     \reg1, [\g_ctxt, #(VCPU_HCR_EL2 - VCPU_CONTEXT)]
+       and     \reg1, \reg1, #(HCR_API | HCR_APK)
+       cbz     \reg1, 1001f
+       add     \reg1, \g_ctxt, #CPU_APIAKEYLO_EL1
+       ptrauth_restore_state   \reg1, \reg2, \reg3
+1001:
+.endm
+
+.macro ptrauth_switch_to_host g_ctxt, h_ctxt, reg1, reg2, reg3
+alternative_if ARM64_HAS_ADDRESS_AUTH_ARCH
+       b       2000f
+alternative_else_nop_endif
+alternative_if_not ARM64_HAS_ADDRESS_AUTH_IMP_DEF
+       b       2001f
+alternative_else_nop_endif
+2000:
+       ldr     \reg1, [\g_ctxt, #(VCPU_HCR_EL2 - VCPU_CONTEXT)]
+       and     \reg1, \reg1, #(HCR_API | HCR_APK)
+       cbz     \reg1, 2001f
+       add     \reg1, \g_ctxt, #CPU_APIAKEYLO_EL1
+       ptrauth_save_state      \reg1, \reg2, \reg3
+       add     \reg1, \h_ctxt, #CPU_APIAKEYLO_EL1
+       ptrauth_restore_state   \reg1, \reg2, \reg3
+       isb
+2001:
+.endm
+
+#else /* !CONFIG_ARM64_PTR_AUTH */
+.macro ptrauth_switch_to_guest g_ctxt, reg1, reg2, reg3
+.endm
+.macro ptrauth_switch_to_host g_ctxt, h_ctxt, reg1, reg2, reg3
+.endm
+#endif /* CONFIG_ARM64_PTR_AUTH */
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_KVM_PTRAUTH_H */
index 2cb8248fa2c893debb6b70cecd60dabbe2884531..8ffcf5a512bbcc3e3a50cafd9b54e3c6b73531be 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/types.h>
 #include <asm/bug.h>
 #include <asm/page-def.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 /*
  * Size of the PCI I/O space. This must remain a power of two so that
index 3f7b917e8f3a76aef3787aa7cd3c356e9f04b1b5..902d75b6091477a822f9883a0766efa77815bed8 100644 (file)
 #define SYS_ICH_LR14_EL2               __SYS__LR8_EL2(6)
 #define SYS_ICH_LR15_EL2               __SYS__LR8_EL2(7)
 
+/* VHE encodings for architectural EL0/1 system registers */
+#define SYS_ZCR_EL12                   sys_reg(3, 5, 1, 2, 0)
+
 /* Common SCTLR_ELx flags. */
 #define SCTLR_ELx_DSSBS        (_BITUL(44))
 #define SCTLR_ELx_ENIA (_BITUL(31))
index f2a83ff6b73c2414110c02dc14aa24686d6ada9c..70e6882853c09ae639da932a70507895c5f8ba18 100644 (file)
@@ -44,7 +44,7 @@
 #define __ARM_NR_compat_set_tls                (__ARM_NR_COMPAT_BASE + 5)
 #define __ARM_NR_COMPAT_END            (__ARM_NR_COMPAT_BASE + 0x800)
 
-#define __NR_compat_syscalls           428
+#define __NR_compat_syscalls           434
 #endif
 
 #define __ARCH_WANT_SYS_CLONE
index 23f1a44acada413fb4e2ad5411624d2925c71835..c39e90600bb31000eef7d78c7e4e46d6ea152b13 100644 (file)
@@ -874,6 +874,18 @@ __SYSCALL(__NR_io_uring_setup, sys_io_uring_setup)
 __SYSCALL(__NR_io_uring_enter, sys_io_uring_enter)
 #define __NR_io_uring_register 427
 __SYSCALL(__NR_io_uring_register, sys_io_uring_register)
+#define __NR_open_tree 428
+__SYSCALL(__NR_open_tree, sys_open_tree)
+#define __NR_move_mount 429
+__SYSCALL(__NR_move_mount, sys_move_mount)
+#define __NR_fsopen 430
+__SYSCALL(__NR_fsopen, sys_fsopen)
+#define __NR_fsconfig 431
+__SYSCALL(__NR_fsconfig, sys_fsconfig)
+#define __NR_fsmount 432
+__SYSCALL(__NR_fsmount, sys_fsmount)
+#define __NR_fspick 433
+__SYSCALL(__NR_fspick, sys_fspick)
 
 /*
  * Please add new compat syscalls above this comment and update
index 97c3478ee6e718c8ac2de4c01edee6a0dd4cd27e..7b7ac0f6cec9e87c93abbaa2ddffea565c3302b0 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/psci.h>
 #include <linux/types.h>
 #include <asm/ptrace.h>
+#include <asm/sve_context.h>
 
 #define __KVM_HAVE_GUEST_DEBUG
 #define __KVM_HAVE_IRQ_LINE
@@ -102,6 +103,9 @@ struct kvm_regs {
 #define KVM_ARM_VCPU_EL1_32BIT         1 /* CPU running a 32bit VM */
 #define KVM_ARM_VCPU_PSCI_0_2          2 /* CPU uses PSCI v0.2 */
 #define KVM_ARM_VCPU_PMU_V3            3 /* Support guest PMUv3 */
+#define KVM_ARM_VCPU_SVE               4 /* enable SVE for this CPU */
+#define KVM_ARM_VCPU_PTRAUTH_ADDRESS   5 /* VCPU uses address authentication */
+#define KVM_ARM_VCPU_PTRAUTH_GENERIC   6 /* VCPU uses generic authentication */
 
 struct kvm_vcpu_init {
        __u32 target;
@@ -226,6 +230,45 @@ struct kvm_vcpu_events {
                                         KVM_REG_ARM_FW | ((r) & 0xffff))
 #define KVM_REG_ARM_PSCI_VERSION       KVM_REG_ARM_FW_REG(0)
 
+/* SVE registers */
+#define KVM_REG_ARM64_SVE              (0x15 << KVM_REG_ARM_COPROC_SHIFT)
+
+/* Z- and P-regs occupy blocks at the following offsets within this range: */
+#define KVM_REG_ARM64_SVE_ZREG_BASE    0
+#define KVM_REG_ARM64_SVE_PREG_BASE    0x400
+#define KVM_REG_ARM64_SVE_FFR_BASE     0x600
+
+#define KVM_ARM64_SVE_NUM_ZREGS                __SVE_NUM_ZREGS
+#define KVM_ARM64_SVE_NUM_PREGS                __SVE_NUM_PREGS
+
+#define KVM_ARM64_SVE_MAX_SLICES       32
+
+#define KVM_REG_ARM64_SVE_ZREG(n, i)                                   \
+       (KVM_REG_ARM64 | KVM_REG_ARM64_SVE | KVM_REG_ARM64_SVE_ZREG_BASE | \
+        KVM_REG_SIZE_U2048 |                                           \
+        (((n) & (KVM_ARM64_SVE_NUM_ZREGS - 1)) << 5) |                 \
+        ((i) & (KVM_ARM64_SVE_MAX_SLICES - 1)))
+
+#define KVM_REG_ARM64_SVE_PREG(n, i)                                   \
+       (KVM_REG_ARM64 | KVM_REG_ARM64_SVE | KVM_REG_ARM64_SVE_PREG_BASE | \
+        KVM_REG_SIZE_U256 |                                            \
+        (((n) & (KVM_ARM64_SVE_NUM_PREGS - 1)) << 5) |                 \
+        ((i) & (KVM_ARM64_SVE_MAX_SLICES - 1)))
+
+#define KVM_REG_ARM64_SVE_FFR(i)                                       \
+       (KVM_REG_ARM64 | KVM_REG_ARM64_SVE | KVM_REG_ARM64_SVE_FFR_BASE | \
+        KVM_REG_SIZE_U256 |                                            \
+        ((i) & (KVM_ARM64_SVE_MAX_SLICES - 1)))
+
+#define KVM_ARM64_SVE_VQ_MIN __SVE_VQ_MIN
+#define KVM_ARM64_SVE_VQ_MAX __SVE_VQ_MAX
+
+/* Vector lengths pseudo-register: */
+#define KVM_REG_ARM64_SVE_VLS          (KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
+                                        KVM_REG_SIZE_U512 | 0xffff)
+#define KVM_ARM64_SVE_VLS_WORDS        \
+       ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
+
 /* Device Control API: ARM VGIC */
 #define KVM_DEV_ARM_VGIC_GRP_ADDR      0
 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
index e10e2a5d9ddcf2ca1f60d55e7a02b5baff6bf509..947e39896e289b0feb6f1a93f523e7be3f38f064 100644 (file)
@@ -125,9 +125,16 @@ int main(void)
   DEFINE(VCPU_CONTEXT,         offsetof(struct kvm_vcpu, arch.ctxt));
   DEFINE(VCPU_FAULT_DISR,      offsetof(struct kvm_vcpu, arch.fault.disr_el1));
   DEFINE(VCPU_WORKAROUND_FLAGS,        offsetof(struct kvm_vcpu, arch.workaround_flags));
+  DEFINE(VCPU_HCR_EL2,         offsetof(struct kvm_vcpu, arch.hcr_el2));
   DEFINE(CPU_GP_REGS,          offsetof(struct kvm_cpu_context, gp_regs));
+  DEFINE(CPU_APIAKEYLO_EL1,    offsetof(struct kvm_cpu_context, sys_regs[APIAKEYLO_EL1]));
+  DEFINE(CPU_APIBKEYLO_EL1,    offsetof(struct kvm_cpu_context, sys_regs[APIBKEYLO_EL1]));
+  DEFINE(CPU_APDAKEYLO_EL1,    offsetof(struct kvm_cpu_context, sys_regs[APDAKEYLO_EL1]));
+  DEFINE(CPU_APDBKEYLO_EL1,    offsetof(struct kvm_cpu_context, sys_regs[APDBKEYLO_EL1]));
+  DEFINE(CPU_APGAKEYLO_EL1,    offsetof(struct kvm_cpu_context, sys_regs[APGAKEYLO_EL1]));
   DEFINE(CPU_USER_PT_REGS,     offsetof(struct kvm_regs, regs));
   DEFINE(HOST_CONTEXT_VCPU,    offsetof(struct kvm_cpu_context, __hyp_running_vcpu));
+  DEFINE(HOST_DATA_CONTEXT,    offsetof(struct kvm_host_data, host_ctxt));
 #endif
 #ifdef CONFIG_CPU_PM
   DEFINE(CPU_CTX_SP,           offsetof(struct cpu_suspend_ctx, sp));
index 2b807f129e602bd3644e8be50c77b75452d637b3..ca27e08e3d8a7ea96fd209064e02efd05add7827 100644 (file)
@@ -1913,7 +1913,7 @@ static void verify_sve_features(void)
        unsigned int len = zcr & ZCR_ELx_LEN_MASK;
 
        if (len < safe_len || sve_verify_vq_map()) {
-               pr_crit("CPU%d: SVE: required vector length(s) missing\n",
+               pr_crit("CPU%d: SVE: vector length support mismatch\n",
                        smp_processor_id());
                cpu_die_early();
        }
index 735cf1f8b109c730a48df5099fc3128f5c4905fb..a38bf74bcca8c5c1732cf161718b497e59160853 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/bitmap.h>
+#include <linux/bitops.h>
 #include <linux/bottom_half.h>
 #include <linux/bug.h>
 #include <linux/cache.h>
@@ -48,6 +49,7 @@
 #include <asm/sigcontext.h>
 #include <asm/sysreg.h>
 #include <asm/traps.h>
+#include <asm/virt.h>
 
 #define FPEXC_IOF      (1 << 0)
 #define FPEXC_DZF      (1 << 1)
  */
 struct fpsimd_last_state_struct {
        struct user_fpsimd_state *st;
+       void *sve_state;
+       unsigned int sve_vl;
 };
 
 static DEFINE_PER_CPU(struct fpsimd_last_state_struct, fpsimd_last_state);
@@ -130,14 +134,23 @@ static int sve_default_vl = -1;
 
 /* Maximum supported vector length across all CPUs (initially poisoned) */
 int __ro_after_init sve_max_vl = SVE_VL_MIN;
-/* Set of available vector lengths, as vq_to_bit(vq): */
-static __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
+int __ro_after_init sve_max_virtualisable_vl = SVE_VL_MIN;
+
+/*
+ * Set of available vector lengths,
+ * where length vq encoded as bit __vq_to_bit(vq):
+ */
+__ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
+/* Set of vector lengths present on at least one cpu: */
+static __ro_after_init DECLARE_BITMAP(sve_vq_partial_map, SVE_VQ_MAX);
+
 static void __percpu *efi_sve_state;
 
 #else /* ! CONFIG_ARM64_SVE */
 
 /* Dummy declaration for code that will be optimised out: */
 extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
+extern __ro_after_init DECLARE_BITMAP(sve_vq_partial_map, SVE_VQ_MAX);
 extern void __percpu *efi_sve_state;
 
 #endif /* ! CONFIG_ARM64_SVE */
@@ -235,14 +248,15 @@ static void task_fpsimd_load(void)
  */
 void fpsimd_save(void)
 {
-       struct user_fpsimd_state *st = __this_cpu_read(fpsimd_last_state.st);
+       struct fpsimd_last_state_struct const *last =
+               this_cpu_ptr(&fpsimd_last_state);
        /* set by fpsimd_bind_task_to_cpu() or fpsimd_bind_state_to_cpu() */
 
        WARN_ON(!in_softirq() && !irqs_disabled());
 
        if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) {
                if (system_supports_sve() && test_thread_flag(TIF_SVE)) {
-                       if (WARN_ON(sve_get_vl() != current->thread.sve_vl)) {
+                       if (WARN_ON(sve_get_vl() != last->sve_vl)) {
                                /*
                                 * Can't save the user regs, so current would
                                 * re-enter user with corrupt state.
@@ -252,31 +266,14 @@ void fpsimd_save(void)
                                return;
                        }
 
-                       sve_save_state(sve_pffr(&current->thread), &st->fpsr);
+                       sve_save_state((char *)last->sve_state +
+                                               sve_ffr_offset(last->sve_vl),
+                                      &last->st->fpsr);
                } else
-                       fpsimd_save_state(st);
+                       fpsimd_save_state(last->st);
        }
 }
 
-/*
- * Helpers to translate bit indices in sve_vq_map to VQ values (and
- * vice versa).  This allows find_next_bit() to be used to find the
- * _maximum_ VQ not exceeding a certain value.
- */
-
-static unsigned int vq_to_bit(unsigned int vq)
-{
-       return SVE_VQ_MAX - vq;
-}
-
-static unsigned int bit_to_vq(unsigned int bit)
-{
-       if (WARN_ON(bit >= SVE_VQ_MAX))
-               bit = SVE_VQ_MAX - 1;
-
-       return SVE_VQ_MAX - bit;
-}
-
 /*
  * All vector length selection from userspace comes through here.
  * We're on a slow path, so some sanity-checks are included.
@@ -298,8 +295,8 @@ static unsigned int find_supported_vector_length(unsigned int vl)
                vl = max_vl;
 
        bit = find_next_bit(sve_vq_map, SVE_VQ_MAX,
-                           vq_to_bit(sve_vq_from_vl(vl)));
-       return sve_vl_from_vq(bit_to_vq(bit));
+                           __vq_to_bit(sve_vq_from_vl(vl)));
+       return sve_vl_from_vq(__bit_to_vq(bit));
 }
 
 #ifdef CONFIG_SYSCTL
@@ -550,7 +547,6 @@ int sve_set_vector_length(struct task_struct *task,
                local_bh_disable();
 
                fpsimd_save();
-               set_thread_flag(TIF_FOREIGN_FPSTATE);
        }
 
        fpsimd_flush_task_state(task);
@@ -624,12 +620,6 @@ int sve_get_current_vl(void)
        return sve_prctl_status(0);
 }
 
-/*
- * Bitmap for temporary storage of the per-CPU set of supported vector lengths
- * during secondary boot.
- */
-static DECLARE_BITMAP(sve_secondary_vq_map, SVE_VQ_MAX);
-
 static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
 {
        unsigned int vq, vl;
@@ -644,40 +634,82 @@ static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
                write_sysreg_s(zcr | (vq - 1), SYS_ZCR_EL1); /* self-syncing */
                vl = sve_get_vl();
                vq = sve_vq_from_vl(vl); /* skip intervening lengths */
-               set_bit(vq_to_bit(vq), map);
+               set_bit(__vq_to_bit(vq), map);
        }
 }
 
+/*
+ * Initialise the set of known supported VQs for the boot CPU.
+ * This is called during kernel boot, before secondary CPUs are brought up.
+ */
 void __init sve_init_vq_map(void)
 {
        sve_probe_vqs(sve_vq_map);
+       bitmap_copy(sve_vq_partial_map, sve_vq_map, SVE_VQ_MAX);
 }
 
 /*
  * If we haven't committed to the set of supported VQs yet, filter out
  * those not supported by the current CPU.
+ * This function is called during the bring-up of early secondary CPUs only.
  */
 void sve_update_vq_map(void)
 {
-       sve_probe_vqs(sve_secondary_vq_map);
-       bitmap_and(sve_vq_map, sve_vq_map, sve_secondary_vq_map, SVE_VQ_MAX);
+       DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
+
+       sve_probe_vqs(tmp_map);
+       bitmap_and(sve_vq_map, sve_vq_map, tmp_map, SVE_VQ_MAX);
+       bitmap_or(sve_vq_partial_map, sve_vq_partial_map, tmp_map, SVE_VQ_MAX);
 }
 
-/* Check whether the current CPU supports all VQs in the committed set */
+/*
+ * Check whether the current CPU supports all VQs in the committed set.
+ * This function is called during the bring-up of late secondary CPUs only.
+ */
 int sve_verify_vq_map(void)
 {
-       int ret = 0;
+       DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
+       unsigned long b;
 
-       sve_probe_vqs(sve_secondary_vq_map);
-       bitmap_andnot(sve_secondary_vq_map, sve_vq_map, sve_secondary_vq_map,
-                     SVE_VQ_MAX);
-       if (!bitmap_empty(sve_secondary_vq_map, SVE_VQ_MAX)) {
+       sve_probe_vqs(tmp_map);
+
+       bitmap_complement(tmp_map, tmp_map, SVE_VQ_MAX);
+       if (bitmap_intersects(tmp_map, sve_vq_map, SVE_VQ_MAX)) {
                pr_warn("SVE: cpu%d: Required vector length(s) missing\n",
                        smp_processor_id());
-               ret = -EINVAL;
+               return -EINVAL;
        }
 
-       return ret;
+       if (!IS_ENABLED(CONFIG_KVM) || !is_hyp_mode_available())
+               return 0;
+
+       /*
+        * For KVM, it is necessary to ensure that this CPU doesn't
+        * support any vector length that guests may have probed as
+        * unsupported.
+        */
+
+       /* Recover the set of supported VQs: */
+       bitmap_complement(tmp_map, tmp_map, SVE_VQ_MAX);
+       /* Find VQs supported that are not globally supported: */
+       bitmap_andnot(tmp_map, tmp_map, sve_vq_map, SVE_VQ_MAX);
+
+       /* Find the lowest such VQ, if any: */
+       b = find_last_bit(tmp_map, SVE_VQ_MAX);
+       if (b >= SVE_VQ_MAX)
+               return 0; /* no mismatches */
+
+       /*
+        * Mismatches above sve_max_virtualisable_vl are fine, since
+        * no guest is allowed to configure ZCR_EL2.LEN to exceed this:
+        */
+       if (sve_vl_from_vq(__bit_to_vq(b)) <= sve_max_virtualisable_vl) {
+               pr_warn("SVE: cpu%d: Unsupported vector length(s) present\n",
+                       smp_processor_id());
+               return -EINVAL;
+       }
+
+       return 0;
 }
 
 static void __init sve_efi_setup(void)
@@ -744,6 +776,8 @@ u64 read_zcr_features(void)
 void __init sve_setup(void)
 {
        u64 zcr;
+       DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
+       unsigned long b;
 
        if (!system_supports_sve())
                return;
@@ -753,8 +787,8 @@ void __init sve_setup(void)
         * so sve_vq_map must have at least SVE_VQ_MIN set.
         * If something went wrong, at least try to patch it up:
         */
-       if (WARN_ON(!test_bit(vq_to_bit(SVE_VQ_MIN), sve_vq_map)))
-               set_bit(vq_to_bit(SVE_VQ_MIN), sve_vq_map);
+       if (WARN_ON(!test_bit(__vq_to_bit(SVE_VQ_MIN), sve_vq_map)))
+               set_bit(__vq_to_bit(SVE_VQ_MIN), sve_vq_map);
 
        zcr = read_sanitised_ftr_reg(SYS_ZCR_EL1);
        sve_max_vl = sve_vl_from_vq((zcr & ZCR_ELx_LEN_MASK) + 1);
@@ -772,11 +806,31 @@ void __init sve_setup(void)
         */
        sve_default_vl = find_supported_vector_length(64);
 
+       bitmap_andnot(tmp_map, sve_vq_partial_map, sve_vq_map,
+                     SVE_VQ_MAX);
+
+       b = find_last_bit(tmp_map, SVE_VQ_MAX);
+       if (b >= SVE_VQ_MAX)
+               /* No non-virtualisable VLs found */
+               sve_max_virtualisable_vl = SVE_VQ_MAX;
+       else if (WARN_ON(b == SVE_VQ_MAX - 1))
+               /* No virtualisable VLs?  This is architecturally forbidden. */
+               sve_max_virtualisable_vl = SVE_VQ_MIN;
+       else /* b + 1 < SVE_VQ_MAX */
+               sve_max_virtualisable_vl = sve_vl_from_vq(__bit_to_vq(b + 1));
+
+       if (sve_max_virtualisable_vl > sve_max_vl)
+               sve_max_virtualisable_vl = sve_max_vl;
+
        pr_info("SVE: maximum available vector length %u bytes per vector\n",
                sve_max_vl);
        pr_info("SVE: default vector length %u bytes per vector\n",
                sve_default_vl);
 
+       /* KVM decides whether to support mismatched systems. Just warn here: */
+       if (sve_max_virtualisable_vl < sve_max_vl)
+               pr_warn("SVE: unvirtualisable vector lengths present\n");
+
        sve_efi_setup();
 }
 
@@ -816,12 +870,11 @@ asmlinkage void do_sve_acc(unsigned int esr, struct pt_regs *regs)
        local_bh_disable();
 
        fpsimd_save();
-       fpsimd_to_sve(current);
 
        /* Force ret_to_user to reload the registers: */
        fpsimd_flush_task_state(current);
-       set_thread_flag(TIF_FOREIGN_FPSTATE);
 
+       fpsimd_to_sve(current);
        if (test_and_set_thread_flag(TIF_SVE))
                WARN_ON(1); /* SVE access shouldn't have trapped */
 
@@ -894,9 +947,9 @@ void fpsimd_flush_thread(void)
 
        local_bh_disable();
 
+       fpsimd_flush_task_state(current);
        memset(&current->thread.uw.fpsimd_state, 0,
               sizeof(current->thread.uw.fpsimd_state));
-       fpsimd_flush_task_state(current);
 
        if (system_supports_sve()) {
                clear_thread_flag(TIF_SVE);
@@ -933,8 +986,6 @@ void fpsimd_flush_thread(void)
                        current->thread.sve_vl_onexec = 0;
        }
 
-       set_thread_flag(TIF_FOREIGN_FPSTATE);
-
        local_bh_enable();
 }
 
@@ -974,6 +1025,8 @@ void fpsimd_bind_task_to_cpu(void)
                this_cpu_ptr(&fpsimd_last_state);
 
        last->st = &current->thread.uw.fpsimd_state;
+       last->sve_state = current->thread.sve_state;
+       last->sve_vl = current->thread.sve_vl;
        current->thread.fpsimd_cpu = smp_processor_id();
 
        if (system_supports_sve()) {
@@ -987,7 +1040,8 @@ void fpsimd_bind_task_to_cpu(void)
        }
 }
 
-void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st)
+void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st, void *sve_state,
+                             unsigned int sve_vl)
 {
        struct fpsimd_last_state_struct *last =
                this_cpu_ptr(&fpsimd_last_state);
@@ -995,6 +1049,8 @@ void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st)
        WARN_ON(!in_softirq() && !irqs_disabled());
 
        last->st = st;
+       last->sve_state = sve_state;
+       last->sve_vl = sve_vl;
 }
 
 /*
@@ -1043,12 +1099,29 @@ void fpsimd_update_current_state(struct user_fpsimd_state const *state)
 
 /*
  * Invalidate live CPU copies of task t's FPSIMD state
+ *
+ * This function may be called with preemption enabled.  The barrier()
+ * ensures that the assignment to fpsimd_cpu is visible to any
+ * preemption/softirq that could race with set_tsk_thread_flag(), so
+ * that TIF_FOREIGN_FPSTATE cannot be spuriously re-cleared.
+ *
+ * The final barrier ensures that TIF_FOREIGN_FPSTATE is seen set by any
+ * subsequent code.
  */
 void fpsimd_flush_task_state(struct task_struct *t)
 {
        t->thread.fpsimd_cpu = NR_CPUS;
+
+       barrier();
+       set_tsk_thread_flag(t, TIF_FOREIGN_FPSTATE);
+
+       barrier();
 }
 
+/*
+ * Invalidate any task's FPSIMD state that is present on this cpu.
+ * This function must be called with softirqs disabled.
+ */
 void fpsimd_flush_cpu_state(void)
 {
        __this_cpu_write(fpsimd_last_state.st, NULL);
index 6164d389eed6065867eae5e55e4f8b459d9d9b42..348d12eec566c63ffd2c6472b789af50e1d9df4a 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <linux/acpi.h>
 #include <linux/clocksource.h>
+#include <linux/kvm_host.h>
 #include <linux/of.h>
 #include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
@@ -528,12 +529,21 @@ static inline int armv8pmu_enable_counter(int idx)
 
 static inline void armv8pmu_enable_event_counter(struct perf_event *event)
 {
+       struct perf_event_attr *attr = &event->attr;
        int idx = event->hw.idx;
+       u32 counter_bits = BIT(ARMV8_IDX_TO_COUNTER(idx));
 
-       armv8pmu_enable_counter(idx);
        if (armv8pmu_event_is_chained(event))
-               armv8pmu_enable_counter(idx - 1);
-       isb();
+               counter_bits |= BIT(ARMV8_IDX_TO_COUNTER(idx - 1));
+
+       kvm_set_pmu_events(counter_bits, attr);
+
+       /* We rely on the hypervisor switch code to enable guest counters */
+       if (!kvm_pmu_counter_deferred(attr)) {
+               armv8pmu_enable_counter(idx);
+               if (armv8pmu_event_is_chained(event))
+                       armv8pmu_enable_counter(idx - 1);
+       }
 }
 
 static inline int armv8pmu_disable_counter(int idx)
@@ -546,11 +556,21 @@ static inline int armv8pmu_disable_counter(int idx)
 static inline void armv8pmu_disable_event_counter(struct perf_event *event)
 {
        struct hw_perf_event *hwc = &event->hw;
+       struct perf_event_attr *attr = &event->attr;
        int idx = hwc->idx;
+       u32 counter_bits = BIT(ARMV8_IDX_TO_COUNTER(idx));
 
        if (armv8pmu_event_is_chained(event))
-               armv8pmu_disable_counter(idx - 1);
-       armv8pmu_disable_counter(idx);
+               counter_bits |= BIT(ARMV8_IDX_TO_COUNTER(idx - 1));
+
+       kvm_clr_pmu_events(counter_bits);
+
+       /* We rely on the hypervisor switch code to disable guest counters */
+       if (!kvm_pmu_counter_deferred(attr)) {
+               if (armv8pmu_event_is_chained(event))
+                       armv8pmu_disable_counter(idx - 1);
+               armv8pmu_disable_counter(idx);
+       }
 }
 
 static inline int armv8pmu_enable_intens(int idx)
@@ -827,14 +847,23 @@ static int armv8pmu_set_event_filter(struct hw_perf_event *event,
         * with other architectures (x86 and Power).
         */
        if (is_kernel_in_hyp_mode()) {
-               if (!attr->exclude_kernel)
+               if (!attr->exclude_kernel && !attr->exclude_host)
                        config_base |= ARMV8_PMU_INCLUDE_EL2;
-       } else {
-               if (attr->exclude_kernel)
+               if (attr->exclude_guest)
                        config_base |= ARMV8_PMU_EXCLUDE_EL1;
-               if (!attr->exclude_hv)
+               if (attr->exclude_host)
+                       config_base |= ARMV8_PMU_EXCLUDE_EL0;
+       } else {
+               if (!attr->exclude_hv && !attr->exclude_host)
                        config_base |= ARMV8_PMU_INCLUDE_EL2;
        }
+
+       /*
+        * Filter out !VHE kernels and guest kernels
+        */
+       if (attr->exclude_kernel)
+               config_base |= ARMV8_PMU_EXCLUDE_EL1;
+
        if (attr->exclude_user)
                config_base |= ARMV8_PMU_EXCLUDE_EL0;
 
@@ -864,6 +893,9 @@ static void armv8pmu_reset(void *info)
                armv8pmu_disable_intens(idx);
        }
 
+       /* Clear the counters we flip at guest entry/exit */
+       kvm_clr_pmu_events(U32_MAX);
+
        /*
         * Initialize & Reset PMNC. Request overflow interrupt for
         * 64 bit cycle counter but cheat in armv8pmu_write_counter().
index 867a7cea70e52efe753cc7e40b8815fa2b76e6d5..a9b0485df074293812e0b2996cf1d65e79041ebe 100644 (file)
@@ -296,11 +296,6 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
         */
 
        fpsimd_flush_task_state(current);
-       barrier();
-       /* From now, fpsimd_thread_switch() won't clear TIF_FOREIGN_FPSTATE */
-
-       set_thread_flag(TIF_FOREIGN_FPSTATE);
-       barrier();
        /* From now, fpsimd_thread_switch() won't touch thread.sve_state */
 
        sve_alloc(current);
index 690e033a91c000513281a45f38ce39e680720e8b..3ac1a64d2fb9d736e5c2a2bfa778f450a13bee0b 100644 (file)
@@ -17,7 +17,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/psci.o $(KVM)/arm/perf.o
 kvm-$(CONFIG_KVM_ARM_HOST) += inject_fault.o regmap.o va_layout.o
 kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
 kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generic_v8.o
-kvm-$(CONFIG_KVM_ARM_HOST) += vgic-sys-reg-v3.o fpsimd.o
+kvm-$(CONFIG_KVM_ARM_HOST) += vgic-sys-reg-v3.o fpsimd.o pmu.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/aarch32.o
 
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic.o
index aac7808ce2162a9d2bdcdcc938b649655663912e..6e3c9c8b2df94d954c6ef87bb945f9bcf47751a2 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/sched.h>
 #include <linux/thread_info.h>
 #include <linux/kvm_host.h>
+#include <asm/fpsimd.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_host.h>
 #include <asm/kvm_mmu.h>
@@ -85,9 +86,12 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
        WARN_ON_ONCE(!irqs_disabled());
 
        if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
-               fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.gp_regs.fp_regs);
+               fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.gp_regs.fp_regs,
+                                        vcpu->arch.sve_state,
+                                        vcpu->arch.sve_max_vl);
+
                clear_thread_flag(TIF_FOREIGN_FPSTATE);
-               clear_thread_flag(TIF_SVE);
+               update_thread_flag(TIF_SVE, vcpu_has_sve(vcpu));
        }
 }
 
@@ -100,14 +104,21 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
 void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
 {
        unsigned long flags;
+       bool host_has_sve = system_supports_sve();
+       bool guest_has_sve = vcpu_has_sve(vcpu);
 
        local_irq_save(flags);
 
        if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
+               u64 *guest_zcr = &vcpu->arch.ctxt.sys_regs[ZCR_EL1];
+
                /* Clean guest FP state to memory and invalidate cpu view */
                fpsimd_save();
                fpsimd_flush_cpu_state();
-       } else if (system_supports_sve()) {
+
+               if (guest_has_sve)
+                       *guest_zcr = read_sysreg_s(SYS_ZCR_EL12);
+       } else if (host_has_sve) {
                /*
                 * The FPSIMD/SVE state in the CPU has not been touched, and we
                 * have SVE (and VHE): CPACR_EL1 (alias CPTR_EL2) has been
index dd436a50fce7b13fa1c1af79ce15495323ca142d..3ae2f82fca469eb0922e556e018647beebc46294 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/bits.h>
 #include <linux/errno.h>
 #include <linux/err.h>
+#include <linux/nospec.h>
 #include <linux/kvm_host.h>
 #include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
 #include <kvm/arm_psci.h>
 #include <asm/cputype.h>
 #include <linux/uaccess.h>
+#include <asm/fpsimd.h>
 #include <asm/kvm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_coproc.h>
+#include <asm/kvm_host.h>
+#include <asm/sigcontext.h>
 
 #include "trace.h"
 
@@ -52,12 +59,19 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+static bool core_reg_offset_is_vreg(u64 off)
+{
+       return off >= KVM_REG_ARM_CORE_REG(fp_regs.vregs) &&
+               off < KVM_REG_ARM_CORE_REG(fp_regs.fpsr);
+}
+
 static u64 core_reg_offset_from_id(u64 id)
 {
        return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
 }
 
-static int validate_core_offset(const struct kvm_one_reg *reg)
+static int validate_core_offset(const struct kvm_vcpu *vcpu,
+                               const struct kvm_one_reg *reg)
 {
        u64 off = core_reg_offset_from_id(reg->id);
        int size;
@@ -89,11 +103,19 @@ static int validate_core_offset(const struct kvm_one_reg *reg)
                return -EINVAL;
        }
 
-       if (KVM_REG_SIZE(reg->id) == size &&
-           IS_ALIGNED(off, size / sizeof(__u32)))
-               return 0;
+       if (KVM_REG_SIZE(reg->id) != size ||
+           !IS_ALIGNED(off, size / sizeof(__u32)))
+               return -EINVAL;
 
-       return -EINVAL;
+       /*
+        * The KVM_REG_ARM64_SVE regs must be used instead of
+        * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
+        * SVE-enabled vcpus:
+        */
+       if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(off))
+               return -EINVAL;
+
+       return 0;
 }
 
 static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
@@ -115,7 +137,7 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
            (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
                return -ENOENT;
 
-       if (validate_core_offset(reg))
+       if (validate_core_offset(vcpu, reg))
                return -EINVAL;
 
        if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id)))
@@ -140,7 +162,7 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
            (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
                return -ENOENT;
 
-       if (validate_core_offset(reg))
+       if (validate_core_offset(vcpu, reg))
                return -EINVAL;
 
        if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
@@ -183,6 +205,239 @@ out:
        return err;
 }
 
+#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
+#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
+
+static bool vq_present(
+       const u64 (*const vqs)[KVM_ARM64_SVE_VLS_WORDS],
+       unsigned int vq)
+{
+       return (*vqs)[vq_word(vq)] & vq_mask(vq);
+}
+
+static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+       unsigned int max_vq, vq;
+       u64 vqs[KVM_ARM64_SVE_VLS_WORDS];
+
+       if (!vcpu_has_sve(vcpu))
+               return -ENOENT;
+
+       if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
+               return -EINVAL;
+
+       memset(vqs, 0, sizeof(vqs));
+
+       max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
+       for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
+               if (sve_vq_available(vq))
+                       vqs[vq_word(vq)] |= vq_mask(vq);
+
+       if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+       unsigned int max_vq, vq;
+       u64 vqs[KVM_ARM64_SVE_VLS_WORDS];
+
+       if (!vcpu_has_sve(vcpu))
+               return -ENOENT;
+
+       if (kvm_arm_vcpu_sve_finalized(vcpu))
+               return -EPERM; /* too late! */
+
+       if (WARN_ON(vcpu->arch.sve_state))
+               return -EINVAL;
+
+       if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
+               return -EFAULT;
+
+       max_vq = 0;
+       for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
+               if (vq_present(&vqs, vq))
+                       max_vq = vq;
+
+       if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
+               return -EINVAL;
+
+       /*
+        * Vector lengths supported by the host can't currently be
+        * hidden from the guest individually: instead we can only set a
+        * maxmium via ZCR_EL2.LEN.  So, make sure the available vector
+        * lengths match the set requested exactly up to the requested
+        * maximum:
+        */
+       for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
+               if (vq_present(&vqs, vq) != sve_vq_available(vq))
+                       return -EINVAL;
+
+       /* Can't run with no vector lengths at all: */
+       if (max_vq < SVE_VQ_MIN)
+               return -EINVAL;
+
+       /* vcpu->arch.sve_state will be alloc'd by kvm_vcpu_finalize_sve() */
+       vcpu->arch.sve_max_vl = sve_vl_from_vq(max_vq);
+
+       return 0;
+}
+
+#define SVE_REG_SLICE_SHIFT    0
+#define SVE_REG_SLICE_BITS     5
+#define SVE_REG_ID_SHIFT       (SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
+#define SVE_REG_ID_BITS                5
+
+#define SVE_REG_SLICE_MASK                                     \
+       GENMASK(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS - 1,   \
+               SVE_REG_SLICE_SHIFT)
+#define SVE_REG_ID_MASK                                                        \
+       GENMASK(SVE_REG_ID_SHIFT + SVE_REG_ID_BITS - 1, SVE_REG_ID_SHIFT)
+
+#define SVE_NUM_SLICES (1 << SVE_REG_SLICE_BITS)
+
+#define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
+#define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
+
+/*
+ * Number of register slices required to cover each whole SVE register.
+ * NOTE: Only the first slice every exists, for now.
+ * If you are tempted to modify this, you must also rework sve_reg_to_region()
+ * to match:
+ */
+#define vcpu_sve_slices(vcpu) 1
+
+/* Bounds of a single SVE register slice within vcpu->arch.sve_state */
+struct sve_state_reg_region {
+       unsigned int koffset;   /* offset into sve_state in kernel memory */
+       unsigned int klen;      /* length in kernel memory */
+       unsigned int upad;      /* extra trailing padding in user memory */
+};
+
+/*
+ * Validate SVE register ID and get sanitised bounds for user/kernel SVE
+ * register copy
+ */
+static int sve_reg_to_region(struct sve_state_reg_region *region,
+                            struct kvm_vcpu *vcpu,
+                            const struct kvm_one_reg *reg)
+{
+       /* reg ID ranges for Z- registers */
+       const u64 zreg_id_min = KVM_REG_ARM64_SVE_ZREG(0, 0);
+       const u64 zreg_id_max = KVM_REG_ARM64_SVE_ZREG(SVE_NUM_ZREGS - 1,
+                                                      SVE_NUM_SLICES - 1);
+
+       /* reg ID ranges for P- registers and FFR (which are contiguous) */
+       const u64 preg_id_min = KVM_REG_ARM64_SVE_PREG(0, 0);
+       const u64 preg_id_max = KVM_REG_ARM64_SVE_FFR(SVE_NUM_SLICES - 1);
+
+       unsigned int vq;
+       unsigned int reg_num;
+
+       unsigned int reqoffset, reqlen; /* User-requested offset and length */
+       unsigned int maxlen; /* Maxmimum permitted length */
+
+       size_t sve_state_size;
+
+       const u64 last_preg_id = KVM_REG_ARM64_SVE_PREG(SVE_NUM_PREGS - 1,
+                                                       SVE_NUM_SLICES - 1);
+
+       /* Verify that the P-regs and FFR really do have contiguous IDs: */
+       BUILD_BUG_ON(KVM_REG_ARM64_SVE_FFR(0) != last_preg_id + 1);
+
+       /* Verify that we match the UAPI header: */
+       BUILD_BUG_ON(SVE_NUM_SLICES != KVM_ARM64_SVE_MAX_SLICES);
+
+       reg_num = (reg->id & SVE_REG_ID_MASK) >> SVE_REG_ID_SHIFT;
+
+       if (reg->id >= zreg_id_min && reg->id <= zreg_id_max) {
+               if (!vcpu_has_sve(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0)
+                       return -ENOENT;
+
+               vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
+
+               reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) -
+                               SVE_SIG_REGS_OFFSET;
+               reqlen = KVM_SVE_ZREG_SIZE;
+               maxlen = SVE_SIG_ZREG_SIZE(vq);
+       } else if (reg->id >= preg_id_min && reg->id <= preg_id_max) {
+               if (!vcpu_has_sve(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0)
+                       return -ENOENT;
+
+               vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
+
+               reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) -
+                               SVE_SIG_REGS_OFFSET;
+               reqlen = KVM_SVE_PREG_SIZE;
+               maxlen = SVE_SIG_PREG_SIZE(vq);
+       } else {
+               return -EINVAL;
+       }
+
+       sve_state_size = vcpu_sve_state_size(vcpu);
+       if (WARN_ON(!sve_state_size))
+               return -EINVAL;
+
+       region->koffset = array_index_nospec(reqoffset, sve_state_size);
+       region->klen = min(maxlen, reqlen);
+       region->upad = reqlen - region->klen;
+
+       return 0;
+}
+
+static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+       int ret;
+       struct sve_state_reg_region region;
+       char __user *uptr = (char __user *)reg->addr;
+
+       /* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
+       if (reg->id == KVM_REG_ARM64_SVE_VLS)
+               return get_sve_vls(vcpu, reg);
+
+       /* Try to interpret reg ID as an architectural SVE register... */
+       ret = sve_reg_to_region(&region, vcpu, reg);
+       if (ret)
+               return ret;
+
+       if (!kvm_arm_vcpu_sve_finalized(vcpu))
+               return -EPERM;
+
+       if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
+                        region.klen) ||
+           clear_user(uptr + region.klen, region.upad))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+       int ret;
+       struct sve_state_reg_region region;
+       const char __user *uptr = (const char __user *)reg->addr;
+
+       /* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
+       if (reg->id == KVM_REG_ARM64_SVE_VLS)
+               return set_sve_vls(vcpu, reg);
+
+       /* Try to interpret reg ID as an architectural SVE register... */
+       ret = sve_reg_to_region(&region, vcpu, reg);
+       if (ret)
+               return ret;
+
+       if (!kvm_arm_vcpu_sve_finalized(vcpu))
+               return -EPERM;
+
+       if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
+                          region.klen))
+               return -EFAULT;
+
+       return 0;
+}
+
 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
        return -EINVAL;
@@ -193,9 +448,37 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        return -EINVAL;
 }
 
-static unsigned long num_core_regs(void)
+static int copy_core_reg_indices(const struct kvm_vcpu *vcpu,
+                                u64 __user *uindices)
+{
+       unsigned int i;
+       int n = 0;
+       const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
+
+       for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
+               /*
+                * The KVM_REG_ARM64_SVE regs must be used instead of
+                * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
+                * SVE-enabled vcpus:
+                */
+               if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(i))
+                       continue;
+
+               if (uindices) {
+                       if (put_user(core_reg | i, uindices))
+                               return -EFAULT;
+                       uindices++;
+               }
+
+               n++;
+       }
+
+       return n;
+}
+
+static unsigned long num_core_regs(const struct kvm_vcpu *vcpu)
 {
-       return sizeof(struct kvm_regs) / sizeof(__u32);
+       return copy_core_reg_indices(vcpu, NULL);
 }
 
 /**
@@ -251,6 +534,67 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
        return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
 }
 
+static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
+{
+       const unsigned int slices = vcpu_sve_slices(vcpu);
+
+       if (!vcpu_has_sve(vcpu))
+               return 0;
+
+       /* Policed by KVM_GET_REG_LIST: */
+       WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
+
+       return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */)
+               + 1; /* KVM_REG_ARM64_SVE_VLS */
+}
+
+static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
+                               u64 __user *uindices)
+{
+       const unsigned int slices = vcpu_sve_slices(vcpu);
+       u64 reg;
+       unsigned int i, n;
+       int num_regs = 0;
+
+       if (!vcpu_has_sve(vcpu))
+               return 0;
+
+       /* Policed by KVM_GET_REG_LIST: */
+       WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
+
+       /*
+        * Enumerate this first, so that userspace can save/restore in
+        * the order reported by KVM_GET_REG_LIST:
+        */
+       reg = KVM_REG_ARM64_SVE_VLS;
+       if (put_user(reg, uindices++))
+               return -EFAULT;
+       ++num_regs;
+
+       for (i = 0; i < slices; i++) {
+               for (n = 0; n < SVE_NUM_ZREGS; n++) {
+                       reg = KVM_REG_ARM64_SVE_ZREG(n, i);
+                       if (put_user(reg, uindices++))
+                               return -EFAULT;
+                       num_regs++;
+               }
+
+               for (n = 0; n < SVE_NUM_PREGS; n++) {
+                       reg = KVM_REG_ARM64_SVE_PREG(n, i);
+                       if (put_user(reg, uindices++))
+                               return -EFAULT;
+                       num_regs++;
+               }
+
+               reg = KVM_REG_ARM64_SVE_FFR(i);
+               if (put_user(reg, uindices++))
+                       return -EFAULT;
+               num_regs++;
+       }
+
+       return num_regs;
+}
+
 /**
  * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
  *
@@ -258,8 +602,15 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
  */
 unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 {
-       return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu)
-               + kvm_arm_get_fw_num_regs(vcpu) + NUM_TIMER_REGS;
+       unsigned long res = 0;
+
+       res += num_core_regs(vcpu);
+       res += num_sve_regs(vcpu);
+       res += kvm_arm_num_sys_reg_descs(vcpu);
+       res += kvm_arm_get_fw_num_regs(vcpu);
+       res += NUM_TIMER_REGS;
+
+       return res;
 }
 
 /**
@@ -269,23 +620,25 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
  */
 int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 {
-       unsigned int i;
-       const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
        int ret;
 
-       for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
-               if (put_user(core_reg | i, uindices))
-                       return -EFAULT;
-               uindices++;
-       }
+       ret = copy_core_reg_indices(vcpu, uindices);
+       if (ret < 0)
+               return ret;
+       uindices += ret;
+
+       ret = copy_sve_reg_indices(vcpu, uindices);
+       if (ret < 0)
+               return ret;
+       uindices += ret;
 
        ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
-       if (ret)
+       if (ret < 0)
                return ret;
        uindices += kvm_arm_get_fw_num_regs(vcpu);
 
        ret = copy_timer_indices(vcpu, uindices);
-       if (ret)
+       if (ret < 0)
                return ret;
        uindices += NUM_TIMER_REGS;
 
@@ -298,12 +651,11 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
        if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
                return -EINVAL;
 
-       /* Register group 16 means we want a core register. */
-       if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
-               return get_core_reg(vcpu, reg);
-
-       if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
-               return kvm_arm_get_fw_reg(vcpu, reg);
+       switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
+       case KVM_REG_ARM_CORE:  return get_core_reg(vcpu, reg);
+       case KVM_REG_ARM_FW:    return kvm_arm_get_fw_reg(vcpu, reg);
+       case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
+       }
 
        if (is_timer_reg(reg->id))
                return get_timer_reg(vcpu, reg);
@@ -317,12 +669,11 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
        if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
                return -EINVAL;
 
-       /* Register group 16 means we set a core register. */
-       if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
-               return set_core_reg(vcpu, reg);
-
-       if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
-               return kvm_arm_set_fw_reg(vcpu, reg);
+       switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
+       case KVM_REG_ARM_CORE:  return set_core_reg(vcpu, reg);
+       case KVM_REG_ARM_FW:    return kvm_arm_set_fw_reg(vcpu, reg);
+       case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
+       }
 
        if (is_timer_reg(reg->id))
                return set_timer_reg(vcpu, reg);
index 0b79834420719a24fa6bb8b4f149f43352173c5c..516aead3c2a99363461ec72ca120a2c7c07563b5 100644 (file)
@@ -173,20 +173,40 @@ static int handle_sve(struct kvm_vcpu *vcpu, struct kvm_run *run)
        return 1;
 }
 
+#define __ptrauth_save_key(regs, key)                                          \
+({                                                                             \
+       regs[key ## KEYLO_EL1] = read_sysreg_s(SYS_ ## key ## KEYLO_EL1);       \
+       regs[key ## KEYHI_EL1] = read_sysreg_s(SYS_ ## key ## KEYHI_EL1);       \
+})
+
+/*
+ * Handle the guest trying to use a ptrauth instruction, or trying to access a
+ * ptrauth register.
+ */
+void kvm_arm_vcpu_ptrauth_trap(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpu_context *ctxt;
+
+       if (vcpu_has_ptrauth(vcpu)) {
+               vcpu_ptrauth_enable(vcpu);
+               ctxt = vcpu->arch.host_cpu_context;
+               __ptrauth_save_key(ctxt->sys_regs, APIA);
+               __ptrauth_save_key(ctxt->sys_regs, APIB);
+               __ptrauth_save_key(ctxt->sys_regs, APDA);
+               __ptrauth_save_key(ctxt->sys_regs, APDB);
+               __ptrauth_save_key(ctxt->sys_regs, APGA);
+       } else {
+               kvm_inject_undefined(vcpu);
+       }
+}
+
 /*
  * Guest usage of a ptrauth instruction (which the guest EL1 did not turn into
  * a NOP).
  */
 static int kvm_handle_ptrauth(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-       /*
-        * We don't currently support ptrauth in a guest, and we mask the ID
-        * registers to prevent well-behaved guests from trying to make use of
-        * it.
-        *
-        * Inject an UNDEF, as if the feature really isn't present.
-        */
-       kvm_inject_undefined(vcpu);
+       kvm_arm_vcpu_ptrauth_trap(vcpu);
        return 1;
 }
 
index 675fdc186e3ba3153602b3c6ebec4432df1c6793..93ba3d7ef027f472fdb81e80163033eb51f60e74 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/kvm_arm.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmu.h>
+#include <asm/kvm_ptrauth.h>
 
 #define CPU_GP_REG_OFFSET(x)   (CPU_GP_REGS + x)
 #define CPU_XREG_OFFSET(x)     CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
@@ -64,6 +65,13 @@ ENTRY(__guest_enter)
 
        add     x18, x0, #VCPU_CONTEXT
 
+       // Macro ptrauth_switch_to_guest format:
+       //      ptrauth_switch_to_guest(guest cxt, tmp1, tmp2, tmp3)
+       // The below macro to restore guest keys is not implemented in C code
+       // as it may cause Pointer Authentication key signing mismatch errors
+       // when this feature is enabled for kernel code.
+       ptrauth_switch_to_guest x18, x0, x1, x2
+
        // Restore guest regs x0-x17
        ldp     x0, x1,   [x18, #CPU_XREG_OFFSET(0)]
        ldp     x2, x3,   [x18, #CPU_XREG_OFFSET(2)]
@@ -118,6 +126,13 @@ ENTRY(__guest_exit)
 
        get_host_ctxt   x2, x3
 
+       // Macro ptrauth_switch_to_guest format:
+       //      ptrauth_switch_to_host(guest cxt, host cxt, tmp1, tmp2, tmp3)
+       // The below macro to save/restore keys is not implemented in C code
+       // as it may cause Pointer Authentication key signing mismatch errors
+       // when this feature is enabled for kernel code.
+       ptrauth_switch_to_host x1, x2, x3, x4, x5
+
        // Now restore the host regs
        restore_callee_saved_regs x2
 
index 3563fe655cd53f366ddc5897606b0db5c9c27f73..22b4c335e0b265207b904121d4d4e2ecbfd326d9 100644 (file)
@@ -100,7 +100,10 @@ static void activate_traps_vhe(struct kvm_vcpu *vcpu)
        val = read_sysreg(cpacr_el1);
        val |= CPACR_EL1_TTA;
        val &= ~CPACR_EL1_ZEN;
-       if (!update_fp_enabled(vcpu)) {
+       if (update_fp_enabled(vcpu)) {
+               if (vcpu_has_sve(vcpu))
+                       val |= CPACR_EL1_ZEN;
+       } else {
                val &= ~CPACR_EL1_FPEN;
                __activate_traps_fpsimd32(vcpu);
        }
@@ -317,16 +320,48 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
        return true;
 }
 
-static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
+/* Check for an FPSIMD/SVE trap and handle as appropriate */
+static bool __hyp_text __hyp_handle_fpsimd(struct kvm_vcpu *vcpu)
 {
-       struct user_fpsimd_state *host_fpsimd = vcpu->arch.host_fpsimd_state;
+       bool vhe, sve_guest, sve_host;
+       u8 hsr_ec;
 
-       if (has_vhe())
-               write_sysreg(read_sysreg(cpacr_el1) | CPACR_EL1_FPEN,
-                            cpacr_el1);
-       else
+       if (!system_supports_fpsimd())
+               return false;
+
+       if (system_supports_sve()) {
+               sve_guest = vcpu_has_sve(vcpu);
+               sve_host = vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE;
+               vhe = true;
+       } else {
+               sve_guest = false;
+               sve_host = false;
+               vhe = has_vhe();
+       }
+
+       hsr_ec = kvm_vcpu_trap_get_class(vcpu);
+       if (hsr_ec != ESR_ELx_EC_FP_ASIMD &&
+           hsr_ec != ESR_ELx_EC_SVE)
+               return false;
+
+       /* Don't handle SVE traps for non-SVE vcpus here: */
+       if (!sve_guest)
+               if (hsr_ec != ESR_ELx_EC_FP_ASIMD)
+                       return false;
+
+       /* Valid trap.  Switch the context: */
+
+       if (vhe) {
+               u64 reg = read_sysreg(cpacr_el1) | CPACR_EL1_FPEN;
+
+               if (sve_guest)
+                       reg |= CPACR_EL1_ZEN;
+
+               write_sysreg(reg, cpacr_el1);
+       } else {
                write_sysreg(read_sysreg(cptr_el2) & ~(u64)CPTR_EL2_TFP,
                             cptr_el2);
+       }
 
        isb();
 
@@ -335,21 +370,28 @@ static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
                 * In the SVE case, VHE is assumed: it is enforced by
                 * Kconfig and kvm_arch_init().
                 */
-               if (system_supports_sve() &&
-                   (vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE)) {
+               if (sve_host) {
                        struct thread_struct *thread = container_of(
-                               host_fpsimd,
+                               vcpu->arch.host_fpsimd_state,
                                struct thread_struct, uw.fpsimd_state);
 
-                       sve_save_state(sve_pffr(thread), &host_fpsimd->fpsr);
+                       sve_save_state(sve_pffr(thread),
+                                      &vcpu->arch.host_fpsimd_state->fpsr);
                } else {
-                       __fpsimd_save_state(host_fpsimd);
+                       __fpsimd_save_state(vcpu->arch.host_fpsimd_state);
                }
 
                vcpu->arch.flags &= ~KVM_ARM64_FP_HOST;
        }
 
-       __fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
+       if (sve_guest) {
+               sve_load_state(vcpu_sve_pffr(vcpu),
+                              &vcpu->arch.ctxt.gp_regs.fp_regs.fpsr,
+                              sve_vq_from_vl(vcpu->arch.sve_max_vl) - 1);
+               write_sysreg_s(vcpu->arch.ctxt.sys_regs[ZCR_EL1], SYS_ZCR_EL12);
+       } else {
+               __fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
+       }
 
        /* Skip restoring fpexc32 for AArch64 guests */
        if (!(read_sysreg(hcr_el2) & HCR_RW))
@@ -385,10 +427,10 @@ static bool __hyp_text fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
         * and restore the guest context lazily.
         * If FP/SIMD is not implemented, handle the trap and inject an
         * undefined instruction exception to the guest.
+        * Similarly for trapped SVE accesses.
         */
-       if (system_supports_fpsimd() &&
-           kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_FP_ASIMD)
-               return __hyp_switch_fpsimd(vcpu);
+       if (__hyp_handle_fpsimd(vcpu))
+               return true;
 
        if (!__populate_fault_info(vcpu))
                return true;
@@ -524,6 +566,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpu_context *host_ctxt;
        struct kvm_cpu_context *guest_ctxt;
+       bool pmu_switch_needed;
        u64 exit_code;
 
        /*
@@ -543,6 +586,8 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
        host_ctxt->__hyp_running_vcpu = vcpu;
        guest_ctxt = &vcpu->arch.ctxt;
 
+       pmu_switch_needed = __pmu_switch_to_guest(host_ctxt);
+
        __sysreg_save_state_nvhe(host_ctxt);
 
        __activate_vm(kern_hyp_va(vcpu->kvm));
@@ -589,6 +634,9 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
         */
        __debug_switch_to_host(vcpu);
 
+       if (pmu_switch_needed)
+               __pmu_switch_to_host(host_ctxt);
+
        /* Returning to host will clear PSR.I, remask PMR if needed */
        if (system_uses_irq_prio_masking())
                gic_write_pmr(GIC_PRIO_IRQOFF);
diff --git a/arch/arm64/kvm/pmu.c b/arch/arm64/kvm/pmu.c
new file mode 100644 (file)
index 0000000..3da94a5
--- /dev/null
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Arm Limited
+ * Author: Andrew Murray <Andrew.Murray@arm.com>
+ */
+#include <linux/kvm_host.h>
+#include <linux/perf_event.h>
+#include <asm/kvm_hyp.h>
+
+/*
+ * Given the perf event attributes and system type, determine
+ * if we are going to need to switch counters at guest entry/exit.
+ */
+static bool kvm_pmu_switch_needed(struct perf_event_attr *attr)
+{
+       /**
+        * With VHE the guest kernel runs at EL1 and the host at EL2,
+        * where user (EL0) is excluded then we have no reason to switch
+        * counters.
+        */
+       if (has_vhe() && attr->exclude_user)
+               return false;
+
+       /* Only switch if attributes are different */
+       return (attr->exclude_host != attr->exclude_guest);
+}
+
+/*
+ * Add events to track that we may want to switch at guest entry/exit
+ * time.
+ */
+void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr)
+{
+       struct kvm_host_data *ctx = this_cpu_ptr(&kvm_host_data);
+
+       if (!kvm_pmu_switch_needed(attr))
+               return;
+
+       if (!attr->exclude_host)
+               ctx->pmu_events.events_host |= set;
+       if (!attr->exclude_guest)
+               ctx->pmu_events.events_guest |= set;
+}
+
+/*
+ * Stop tracking events
+ */
+void kvm_clr_pmu_events(u32 clr)
+{
+       struct kvm_host_data *ctx = this_cpu_ptr(&kvm_host_data);
+
+       ctx->pmu_events.events_host &= ~clr;
+       ctx->pmu_events.events_guest &= ~clr;
+}
+
+/**
+ * Disable host events, enable guest events
+ */
+bool __hyp_text __pmu_switch_to_guest(struct kvm_cpu_context *host_ctxt)
+{
+       struct kvm_host_data *host;
+       struct kvm_pmu_events *pmu;
+
+       host = container_of(host_ctxt, struct kvm_host_data, host_ctxt);
+       pmu = &host->pmu_events;
+
+       if (pmu->events_host)
+               write_sysreg(pmu->events_host, pmcntenclr_el0);
+
+       if (pmu->events_guest)
+               write_sysreg(pmu->events_guest, pmcntenset_el0);
+
+       return (pmu->events_host || pmu->events_guest);
+}
+
+/**
+ * Disable guest events, enable host events
+ */
+void __hyp_text __pmu_switch_to_host(struct kvm_cpu_context *host_ctxt)
+{
+       struct kvm_host_data *host;
+       struct kvm_pmu_events *pmu;
+
+       host = container_of(host_ctxt, struct kvm_host_data, host_ctxt);
+       pmu = &host->pmu_events;
+
+       if (pmu->events_guest)
+               write_sysreg(pmu->events_guest, pmcntenclr_el0);
+
+       if (pmu->events_host)
+               write_sysreg(pmu->events_host, pmcntenset_el0);
+}
+
+#define PMEVTYPER_READ_CASE(idx)                               \
+       case idx:                                               \
+               return read_sysreg(pmevtyper##idx##_el0)
+
+#define PMEVTYPER_WRITE_CASE(idx)                              \
+       case idx:                                               \
+               write_sysreg(val, pmevtyper##idx##_el0);        \
+               break
+
+#define PMEVTYPER_CASES(readwrite)                             \
+       PMEVTYPER_##readwrite##_CASE(0);                        \
+       PMEVTYPER_##readwrite##_CASE(1);                        \
+       PMEVTYPER_##readwrite##_CASE(2);                        \
+       PMEVTYPER_##readwrite##_CASE(3);                        \
+       PMEVTYPER_##readwrite##_CASE(4);                        \
+       PMEVTYPER_##readwrite##_CASE(5);                        \
+       PMEVTYPER_##readwrite##_CASE(6);                        \
+       PMEVTYPER_##readwrite##_CASE(7);                        \
+       PMEVTYPER_##readwrite##_CASE(8);                        \
+       PMEVTYPER_##readwrite##_CASE(9);                        \
+       PMEVTYPER_##readwrite##_CASE(10);                       \
+       PMEVTYPER_##readwrite##_CASE(11);                       \
+       PMEVTYPER_##readwrite##_CASE(12);                       \
+       PMEVTYPER_##readwrite##_CASE(13);                       \
+       PMEVTYPER_##readwrite##_CASE(14);                       \
+       PMEVTYPER_##readwrite##_CASE(15);                       \
+       PMEVTYPER_##readwrite##_CASE(16);                       \
+       PMEVTYPER_##readwrite##_CASE(17);                       \
+       PMEVTYPER_##readwrite##_CASE(18);                       \
+       PMEVTYPER_##readwrite##_CASE(19);                       \
+       PMEVTYPER_##readwrite##_CASE(20);                       \
+       PMEVTYPER_##readwrite##_CASE(21);                       \
+       PMEVTYPER_##readwrite##_CASE(22);                       \
+       PMEVTYPER_##readwrite##_CASE(23);                       \
+       PMEVTYPER_##readwrite##_CASE(24);                       \
+       PMEVTYPER_##readwrite##_CASE(25);                       \
+       PMEVTYPER_##readwrite##_CASE(26);                       \
+       PMEVTYPER_##readwrite##_CASE(27);                       \
+       PMEVTYPER_##readwrite##_CASE(28);                       \
+       PMEVTYPER_##readwrite##_CASE(29);                       \
+       PMEVTYPER_##readwrite##_CASE(30)
+
+/*
+ * Read a value direct from PMEVTYPER<idx> where idx is 0-30
+ * or PMCCFILTR_EL0 where idx is ARMV8_PMU_CYCLE_IDX (31).
+ */
+static u64 kvm_vcpu_pmu_read_evtype_direct(int idx)
+{
+       switch (idx) {
+       PMEVTYPER_CASES(READ);
+       case ARMV8_PMU_CYCLE_IDX:
+               return read_sysreg(pmccfiltr_el0);
+       default:
+               WARN_ON(1);
+       }
+
+       return 0;
+}
+
+/*
+ * Write a value direct to PMEVTYPER<idx> where idx is 0-30
+ * or PMCCFILTR_EL0 where idx is ARMV8_PMU_CYCLE_IDX (31).
+ */
+static void kvm_vcpu_pmu_write_evtype_direct(int idx, u32 val)
+{
+       switch (idx) {
+       PMEVTYPER_CASES(WRITE);
+       case ARMV8_PMU_CYCLE_IDX:
+               write_sysreg(val, pmccfiltr_el0);
+               break;
+       default:
+               WARN_ON(1);
+       }
+}
+
+/*
+ * Modify ARMv8 PMU events to include EL0 counting
+ */
+static void kvm_vcpu_pmu_enable_el0(unsigned long events)
+{
+       u64 typer;
+       u32 counter;
+
+       for_each_set_bit(counter, &events, 32) {
+               typer = kvm_vcpu_pmu_read_evtype_direct(counter);
+               typer &= ~ARMV8_PMU_EXCLUDE_EL0;
+               kvm_vcpu_pmu_write_evtype_direct(counter, typer);
+       }
+}
+
+/*
+ * Modify ARMv8 PMU events to exclude EL0 counting
+ */
+static void kvm_vcpu_pmu_disable_el0(unsigned long events)
+{
+       u64 typer;
+       u32 counter;
+
+       for_each_set_bit(counter, &events, 32) {
+               typer = kvm_vcpu_pmu_read_evtype_direct(counter);
+               typer |= ARMV8_PMU_EXCLUDE_EL0;
+               kvm_vcpu_pmu_write_evtype_direct(counter, typer);
+       }
+}
+
+/*
+ * On VHE ensure that only guest events have EL0 counting enabled
+ */
+void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpu_context *host_ctxt;
+       struct kvm_host_data *host;
+       u32 events_guest, events_host;
+
+       if (!has_vhe())
+               return;
+
+       host_ctxt = vcpu->arch.host_cpu_context;
+       host = container_of(host_ctxt, struct kvm_host_data, host_ctxt);
+       events_guest = host->pmu_events.events_guest;
+       events_host = host->pmu_events.events_host;
+
+       kvm_vcpu_pmu_enable_el0(events_guest);
+       kvm_vcpu_pmu_disable_el0(events_host);
+}
+
+/*
+ * On VHE ensure that only host events have EL0 counting enabled
+ */
+void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpu_context *host_ctxt;
+       struct kvm_host_data *host;
+       u32 events_guest, events_host;
+
+       if (!has_vhe())
+               return;
+
+       host_ctxt = vcpu->arch.host_cpu_context;
+       host = container_of(host_ctxt, struct kvm_host_data, host_ctxt);
+       events_guest = host->pmu_events.events_guest;
+       events_host = host->pmu_events.events_host;
+
+       kvm_vcpu_pmu_enable_el0(events_host);
+       kvm_vcpu_pmu_disable_el0(events_guest);
+}
index e2a0500cd7a27c9ecc5326dd2380f23917309f91..1140b4485575d6cf6d84318d32a9cbf6727210bd 100644 (file)
  */
 
 #include <linux/errno.h>
+#include <linux/kernel.h>
 #include <linux/kvm_host.h>
 #include <linux/kvm.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
 
 #include <kvm/arm_arch_timer.h>
 
 #include <asm/cpufeature.h>
 #include <asm/cputype.h>
+#include <asm/fpsimd.h>
 #include <asm/ptrace.h>
 #include <asm/kvm_arm.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_coproc.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
+#include <asm/virt.h>
 
 /* Maximum phys_shift supported for any VM on this host */
 static u32 kvm_ipa_limit;
@@ -92,6 +98,14 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_ARM_VM_IPA_SIZE:
                r = kvm_ipa_limit;
                break;
+       case KVM_CAP_ARM_SVE:
+               r = system_supports_sve();
+               break;
+       case KVM_CAP_ARM_PTRAUTH_ADDRESS:
+       case KVM_CAP_ARM_PTRAUTH_GENERIC:
+               r = has_vhe() && system_supports_address_auth() &&
+                                system_supports_generic_auth();
+               break;
        default:
                r = 0;
        }
@@ -99,13 +113,148 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        return r;
 }
 
+unsigned int kvm_sve_max_vl;
+
+int kvm_arm_init_sve(void)
+{
+       if (system_supports_sve()) {
+               kvm_sve_max_vl = sve_max_virtualisable_vl;
+
+               /*
+                * The get_sve_reg()/set_sve_reg() ioctl interface will need
+                * to be extended with multiple register slice support in
+                * order to support vector lengths greater than
+                * SVE_VL_ARCH_MAX:
+                */
+               if (WARN_ON(kvm_sve_max_vl > SVE_VL_ARCH_MAX))
+                       kvm_sve_max_vl = SVE_VL_ARCH_MAX;
+
+               /*
+                * Don't even try to make use of vector lengths that
+                * aren't available on all CPUs, for now:
+                */
+               if (kvm_sve_max_vl < sve_max_vl)
+                       pr_warn("KVM: SVE vector length for guests limited to %u bytes\n",
+                               kvm_sve_max_vl);
+       }
+
+       return 0;
+}
+
+static int kvm_vcpu_enable_sve(struct kvm_vcpu *vcpu)
+{
+       if (!system_supports_sve())
+               return -EINVAL;
+
+       /* Verify that KVM startup enforced this when SVE was detected: */
+       if (WARN_ON(!has_vhe()))
+               return -EINVAL;
+
+       vcpu->arch.sve_max_vl = kvm_sve_max_vl;
+
+       /*
+        * Userspace can still customize the vector lengths by writing
+        * KVM_REG_ARM64_SVE_VLS.  Allocation is deferred until
+        * kvm_arm_vcpu_finalize(), which freezes the configuration.
+        */
+       vcpu->arch.flags |= KVM_ARM64_GUEST_HAS_SVE;
+
+       return 0;
+}
+
+/*
+ * Finalize vcpu's maximum SVE vector length, allocating
+ * vcpu->arch.sve_state as necessary.
+ */
+static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
+{
+       void *buf;
+       unsigned int vl;
+
+       vl = vcpu->arch.sve_max_vl;
+
+       /*
+        * Resposibility for these properties is shared between
+        * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
+        * set_sve_vls().  Double-check here just to be sure:
+        */
+       if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
+                   vl > SVE_VL_ARCH_MAX))
+               return -EIO;
+
+       buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       vcpu->arch.sve_state = buf;
+       vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
+       return 0;
+}
+
+int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature)
+{
+       switch (feature) {
+       case KVM_ARM_VCPU_SVE:
+               if (!vcpu_has_sve(vcpu))
+                       return -EINVAL;
+
+               if (kvm_arm_vcpu_sve_finalized(vcpu))
+                       return -EPERM;
+
+               return kvm_vcpu_finalize_sve(vcpu);
+       }
+
+       return -EINVAL;
+}
+
+bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
+{
+       if (vcpu_has_sve(vcpu) && !kvm_arm_vcpu_sve_finalized(vcpu))
+               return false;
+
+       return true;
+}
+
+void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+       kfree(vcpu->arch.sve_state);
+}
+
+static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
+{
+       if (vcpu_has_sve(vcpu))
+               memset(vcpu->arch.sve_state, 0, vcpu_sve_state_size(vcpu));
+}
+
+static int kvm_vcpu_enable_ptrauth(struct kvm_vcpu *vcpu)
+{
+       /* Support ptrauth only if the system supports these capabilities. */
+       if (!has_vhe())
+               return -EINVAL;
+
+       if (!system_supports_address_auth() ||
+           !system_supports_generic_auth())
+               return -EINVAL;
+       /*
+        * For now make sure that both address/generic pointer authentication
+        * features are requested by the userspace together.
+        */
+       if (!test_bit(KVM_ARM_VCPU_PTRAUTH_ADDRESS, vcpu->arch.features) ||
+           !test_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, vcpu->arch.features))
+               return -EINVAL;
+
+       vcpu->arch.flags |= KVM_ARM64_GUEST_HAS_PTRAUTH;
+       return 0;
+}
+
 /**
  * kvm_reset_vcpu - sets core registers and sys_regs to reset value
  * @vcpu: The VCPU pointer
  *
  * This function finds the right table above and sets the registers on
  * the virtual CPU struct to their architecturally defined reset
- * values.
+ * values, except for registers whose reset is deferred until
+ * kvm_arm_vcpu_finalize().
  *
  * Note: This function can be called from two paths: The KVM_ARM_VCPU_INIT
  * ioctl or as part of handling a request issued by another VCPU in the PSCI
@@ -131,6 +280,22 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
        if (loaded)
                kvm_arch_vcpu_put(vcpu);
 
+       if (!kvm_arm_vcpu_sve_finalized(vcpu)) {
+               if (test_bit(KVM_ARM_VCPU_SVE, vcpu->arch.features)) {
+                       ret = kvm_vcpu_enable_sve(vcpu);
+                       if (ret)
+                               goto out;
+               }
+       } else {
+               kvm_vcpu_reset_sve(vcpu);
+       }
+
+       if (test_bit(KVM_ARM_VCPU_PTRAUTH_ADDRESS, vcpu->arch.features) ||
+           test_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, vcpu->arch.features)) {
+               if (kvm_vcpu_enable_ptrauth(vcpu))
+                       goto out;
+       }
+
        switch (vcpu->arch.target) {
        default:
                if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) {
index 539feecda5b8123eed039c0dcda7221695f339b5..857b226bcdde34e8e00bf660328777c121c4b1f8 100644 (file)
@@ -695,6 +695,7 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
                val |= p->regval & ARMV8_PMU_PMCR_MASK;
                __vcpu_sys_reg(vcpu, PMCR_EL0) = val;
                kvm_pmu_handle_pmcr(vcpu, val);
+               kvm_vcpu_pmu_restore_guest(vcpu);
        } else {
                /* PMCR.P & PMCR.C are RAZ */
                val = __vcpu_sys_reg(vcpu, PMCR_EL0)
@@ -850,6 +851,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
        if (p->is_write) {
                kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
                __vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
+               kvm_vcpu_pmu_restore_guest(vcpu);
        } else {
                p->regval = __vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
        }
@@ -875,6 +877,7 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
                        /* accessing PMCNTENSET_EL0 */
                        __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
                        kvm_pmu_enable_counter(vcpu, val);
+                       kvm_vcpu_pmu_restore_guest(vcpu);
                } else {
                        /* accessing PMCNTENCLR_EL0 */
                        __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
@@ -1007,6 +1010,37 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
        { SYS_DESC(SYS_PMEVTYPERn_EL0(n)),                                      \
          access_pmu_evtyper, reset_unknown, (PMEVTYPER0_EL0 + n), }
 
+static bool trap_ptrauth(struct kvm_vcpu *vcpu,
+                        struct sys_reg_params *p,
+                        const struct sys_reg_desc *rd)
+{
+       kvm_arm_vcpu_ptrauth_trap(vcpu);
+
+       /*
+        * Return false for both cases as we never skip the trapped
+        * instruction:
+        *
+        * - Either we re-execute the same key register access instruction
+        *   after enabling ptrauth.
+        * - Or an UNDEF is injected as ptrauth is not supported/enabled.
+        */
+       return false;
+}
+
+static unsigned int ptrauth_visibility(const struct kvm_vcpu *vcpu,
+                       const struct sys_reg_desc *rd)
+{
+       return vcpu_has_ptrauth(vcpu) ? 0 : REG_HIDDEN_USER | REG_HIDDEN_GUEST;
+}
+
+#define __PTRAUTH_KEY(k)                                               \
+       { SYS_DESC(SYS_## k), trap_ptrauth, reset_unknown, k,           \
+       .visibility = ptrauth_visibility}
+
+#define PTRAUTH_KEY(k)                                                 \
+       __PTRAUTH_KEY(k ## KEYLO_EL1),                                  \
+       __PTRAUTH_KEY(k ## KEYHI_EL1)
+
 static bool access_arch_timer(struct kvm_vcpu *vcpu,
                              struct sys_reg_params *p,
                              const struct sys_reg_desc *r)
@@ -1044,25 +1078,20 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu,
 }
 
 /* Read a sanitised cpufeature ID register by sys_reg_desc */
-static u64 read_id_reg(struct sys_reg_desc const *r, bool raz)
+static u64 read_id_reg(const struct kvm_vcpu *vcpu,
+               struct sys_reg_desc const *r, bool raz)
 {
        u32 id = sys_reg((u32)r->Op0, (u32)r->Op1,
                         (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
        u64 val = raz ? 0 : read_sanitised_ftr_reg(id);
 
-       if (id == SYS_ID_AA64PFR0_EL1) {
-               if (val & (0xfUL << ID_AA64PFR0_SVE_SHIFT))
-                       kvm_debug("SVE unsupported for guests, suppressing\n");
-
+       if (id == SYS_ID_AA64PFR0_EL1 && !vcpu_has_sve(vcpu)) {
                val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT);
-       } else if (id == SYS_ID_AA64ISAR1_EL1) {
-               const u64 ptrauth_mask = (0xfUL << ID_AA64ISAR1_APA_SHIFT) |
-                                        (0xfUL << ID_AA64ISAR1_API_SHIFT) |
-                                        (0xfUL << ID_AA64ISAR1_GPA_SHIFT) |
-                                        (0xfUL << ID_AA64ISAR1_GPI_SHIFT);
-               if (val & ptrauth_mask)
-                       kvm_debug("ptrauth unsupported for guests, suppressing\n");
-               val &= ~ptrauth_mask;
+       } else if (id == SYS_ID_AA64ISAR1_EL1 && !vcpu_has_ptrauth(vcpu)) {
+               val &= ~((0xfUL << ID_AA64ISAR1_APA_SHIFT) |
+                        (0xfUL << ID_AA64ISAR1_API_SHIFT) |
+                        (0xfUL << ID_AA64ISAR1_GPA_SHIFT) |
+                        (0xfUL << ID_AA64ISAR1_GPI_SHIFT));
        }
 
        return val;
@@ -1078,7 +1107,7 @@ static bool __access_id_reg(struct kvm_vcpu *vcpu,
        if (p->is_write)
                return write_to_read_only(vcpu, p, r);
 
-       p->regval = read_id_reg(r, raz);
+       p->regval = read_id_reg(vcpu, r, raz);
        return true;
 }
 
@@ -1100,6 +1129,81 @@ static int reg_from_user(u64 *val, const void __user *uaddr, u64 id);
 static int reg_to_user(void __user *uaddr, const u64 *val, u64 id);
 static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
 
+/* Visibility overrides for SVE-specific control registers */
+static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
+                                  const struct sys_reg_desc *rd)
+{
+       if (vcpu_has_sve(vcpu))
+               return 0;
+
+       return REG_HIDDEN_USER | REG_HIDDEN_GUEST;
+}
+
+/* Visibility overrides for SVE-specific ID registers */
+static unsigned int sve_id_visibility(const struct kvm_vcpu *vcpu,
+                                     const struct sys_reg_desc *rd)
+{
+       if (vcpu_has_sve(vcpu))
+               return 0;
+
+       return REG_HIDDEN_USER;
+}
+
+/* Generate the emulated ID_AA64ZFR0_EL1 value exposed to the guest */
+static u64 guest_id_aa64zfr0_el1(const struct kvm_vcpu *vcpu)
+{
+       if (!vcpu_has_sve(vcpu))
+               return 0;
+
+       return read_sanitised_ftr_reg(SYS_ID_AA64ZFR0_EL1);
+}
+
+static bool access_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
+                                  struct sys_reg_params *p,
+                                  const struct sys_reg_desc *rd)
+{
+       if (p->is_write)
+               return write_to_read_only(vcpu, p, rd);
+
+       p->regval = guest_id_aa64zfr0_el1(vcpu);
+       return true;
+}
+
+static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
+               const struct sys_reg_desc *rd,
+               const struct kvm_one_reg *reg, void __user *uaddr)
+{
+       u64 val;
+
+       if (WARN_ON(!vcpu_has_sve(vcpu)))
+               return -ENOENT;
+
+       val = guest_id_aa64zfr0_el1(vcpu);
+       return reg_to_user(uaddr, &val, reg->id);
+}
+
+static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
+               const struct sys_reg_desc *rd,
+               const struct kvm_one_reg *reg, void __user *uaddr)
+{
+       const u64 id = sys_reg_to_index(rd);
+       int err;
+       u64 val;
+
+       if (WARN_ON(!vcpu_has_sve(vcpu)))
+               return -ENOENT;
+
+       err = reg_from_user(&val, uaddr, id);
+       if (err)
+               return err;
+
+       /* This is what we mean by invariant: you can't change it. */
+       if (val != guest_id_aa64zfr0_el1(vcpu))
+               return -EINVAL;
+
+       return 0;
+}
+
 /*
  * cpufeature ID register user accessors
  *
@@ -1107,16 +1211,18 @@ static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
  * are stored, and for set_id_reg() we don't allow the effective value
  * to be changed.
  */
-static int __get_id_reg(const struct sys_reg_desc *rd, void __user *uaddr,
+static int __get_id_reg(const struct kvm_vcpu *vcpu,
+                       const struct sys_reg_desc *rd, void __user *uaddr,
                        bool raz)
 {
        const u64 id = sys_reg_to_index(rd);
-       const u64 val = read_id_reg(rd, raz);
+       const u64 val = read_id_reg(vcpu, rd, raz);
 
        return reg_to_user(uaddr, &val, id);
 }
 
-static int __set_id_reg(const struct sys_reg_desc *rd, void __user *uaddr,
+static int __set_id_reg(const struct kvm_vcpu *vcpu,
+                       const struct sys_reg_desc *rd, void __user *uaddr,
                        bool raz)
 {
        const u64 id = sys_reg_to_index(rd);
@@ -1128,7 +1234,7 @@ static int __set_id_reg(const struct sys_reg_desc *rd, void __user *uaddr,
                return err;
 
        /* This is what we mean by invariant: you can't change it. */
-       if (val != read_id_reg(rd, raz))
+       if (val != read_id_reg(vcpu, rd, raz))
                return -EINVAL;
 
        return 0;
@@ -1137,25 +1243,25 @@ static int __set_id_reg(const struct sys_reg_desc *rd, void __user *uaddr,
 static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
                      const struct kvm_one_reg *reg, void __user *uaddr)
 {
-       return __get_id_reg(rd, uaddr, false);
+       return __get_id_reg(vcpu, rd, uaddr, false);
 }
 
 static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
                      const struct kvm_one_reg *reg, void __user *uaddr)
 {
-       return __set_id_reg(rd, uaddr, false);
+       return __set_id_reg(vcpu, rd, uaddr, false);
 }
 
 static int get_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
                          const struct kvm_one_reg *reg, void __user *uaddr)
 {
-       return __get_id_reg(rd, uaddr, true);
+       return __get_id_reg(vcpu, rd, uaddr, true);
 }
 
 static int set_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
                          const struct kvm_one_reg *reg, void __user *uaddr)
 {
-       return __set_id_reg(rd, uaddr, true);
+       return __set_id_reg(vcpu, rd, uaddr, true);
 }
 
 static bool access_ctr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
@@ -1343,7 +1449,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        ID_SANITISED(ID_AA64PFR1_EL1),
        ID_UNALLOCATED(4,2),
        ID_UNALLOCATED(4,3),
-       ID_UNALLOCATED(4,4),
+       { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility },
        ID_UNALLOCATED(4,5),
        ID_UNALLOCATED(4,6),
        ID_UNALLOCATED(4,7),
@@ -1380,10 +1486,17 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
        { SYS_DESC(SYS_SCTLR_EL1), access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 },
        { SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
+       { SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
        { SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
        { SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
        { SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 },
 
+       PTRAUTH_KEY(APIA),
+       PTRAUTH_KEY(APIB),
+       PTRAUTH_KEY(APDA),
+       PTRAUTH_KEY(APDB),
+       PTRAUTH_KEY(APGA),
+
        { SYS_DESC(SYS_AFSR0_EL1), access_vm_reg, reset_unknown, AFSR0_EL1 },
        { SYS_DESC(SYS_AFSR1_EL1), access_vm_reg, reset_unknown, AFSR1_EL1 },
        { SYS_DESC(SYS_ESR_EL1), access_vm_reg, reset_unknown, ESR_EL1 },
@@ -1924,6 +2037,12 @@ static void perform_access(struct kvm_vcpu *vcpu,
 {
        trace_kvm_sys_access(*vcpu_pc(vcpu), params, r);
 
+       /* Check for regs disabled by runtime config */
+       if (sysreg_hidden_from_guest(vcpu, r)) {
+               kvm_inject_undefined(vcpu);
+               return;
+       }
+
        /*
         * Not having an accessor means that we have configured a trap
         * that we don't know how to handle. This certainly qualifies
@@ -2435,6 +2554,10 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
        if (!r)
                return get_invariant_sys_reg(reg->id, uaddr);
 
+       /* Check for regs disabled by runtime config */
+       if (sysreg_hidden_from_user(vcpu, r))
+               return -ENOENT;
+
        if (r->get_user)
                return (r->get_user)(vcpu, r, reg, uaddr);
 
@@ -2456,6 +2579,10 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
        if (!r)
                return set_invariant_sys_reg(reg->id, uaddr);
 
+       /* Check for regs disabled by runtime config */
+       if (sysreg_hidden_from_user(vcpu, r))
+               return -ENOENT;
+
        if (r->set_user)
                return (r->set_user)(vcpu, r, reg, uaddr);
 
@@ -2512,7 +2639,8 @@ static bool copy_reg_to_user(const struct sys_reg_desc *reg, u64 __user **uind)
        return true;
 }
 
-static int walk_one_sys_reg(const struct sys_reg_desc *rd,
+static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
+                           const struct sys_reg_desc *rd,
                            u64 __user **uind,
                            unsigned int *total)
 {
@@ -2523,6 +2651,9 @@ static int walk_one_sys_reg(const struct sys_reg_desc *rd,
        if (!(rd->reg || rd->get_user))
                return 0;
 
+       if (sysreg_hidden_from_user(vcpu, rd))
+               return 0;
+
        if (!copy_reg_to_user(rd, uind))
                return -EFAULT;
 
@@ -2551,9 +2682,9 @@ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind)
                int cmp = cmp_sys_reg(i1, i2);
                /* target-specific overrides generic entry. */
                if (cmp <= 0)
-                       err = walk_one_sys_reg(i1, &uind, &total);
+                       err = walk_one_sys_reg(vcpu, i1, &uind, &total);
                else
-                       err = walk_one_sys_reg(i2, &uind, &total);
+                       err = walk_one_sys_reg(vcpu, i2, &uind, &total);
 
                if (err)
                        return err;
index 3b1bc7f01d0bd284314308898f7aa1448f5e0436..2be99508dcb9a892f943a064ea958d429f645182 100644 (file)
@@ -64,8 +64,15 @@ struct sys_reg_desc {
                        const struct kvm_one_reg *reg, void __user *uaddr);
        int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
                        const struct kvm_one_reg *reg, void __user *uaddr);
+
+       /* Return mask of REG_* runtime visibility overrides */
+       unsigned int (*visibility)(const struct kvm_vcpu *vcpu,
+                                  const struct sys_reg_desc *rd);
 };
 
+#define REG_HIDDEN_USER                (1 << 0) /* hidden from userspace ioctls */
+#define REG_HIDDEN_GUEST       (1 << 1) /* hidden from guest */
+
 static inline void print_sys_reg_instr(const struct sys_reg_params *p)
 {
        /* Look, we even formatted it for you to paste into the table! */
@@ -102,6 +109,24 @@ static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r
        __vcpu_sys_reg(vcpu, r->reg) = r->val;
 }
 
+static inline bool sysreg_hidden_from_guest(const struct kvm_vcpu *vcpu,
+                                           const struct sys_reg_desc *r)
+{
+       if (likely(!r->visibility))
+               return false;
+
+       return r->visibility(vcpu, r) & REG_HIDDEN_GUEST;
+}
+
+static inline bool sysreg_hidden_from_user(const struct kvm_vcpu *vcpu,
+                                          const struct sys_reg_desc *r)
+{
+       if (likely(!r->visibility))
+               return false;
+
+       return r->visibility(vcpu, r) & REG_HIDDEN_USER;
+}
+
 static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
                              const struct sys_reg_desc *i2)
 {
index 40e2d7e5efcb1e10c34b4abf83352ca4ec4c0d99..d2adffb81b5daaaaf607da505959f66ce0c1c3f7 100644 (file)
@@ -48,7 +48,7 @@
 #include <asm/numa.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/tlb.h>
 #include <asm/alternative.h>
 
@@ -578,24 +578,11 @@ void free_initmem(void)
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-
-static int keep_initrd __initdata;
-
 void __init free_initrd_mem(unsigned long start, unsigned long end)
 {
-       if (!keep_initrd) {
-               free_reserved_area((void *)start, (void *)end, 0, "initrd");
-               memblock_free(__virt_to_phys(start), end - start);
-       }
-}
-
-static int __init keepinitrd_setup(char *__unused)
-{
-       keep_initrd = 1;
-       return 1;
+       free_reserved_area((void *)start, (void *)end, 0, "initrd");
+       memblock_free(__virt_to_phys(start), end - start);
 }
-
-__setup("keepinitrd", keepinitrd_setup);
 #endif
 
 /*
index ef82312860ac3ee8e8568b229d1cd92b24c6ddd6..a170c6369a68412cbe3e59ce140a4a834684548f 100644 (file)
@@ -40,7 +40,7 @@
 #include <asm/kernel-pgtable.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/tlb.h>
 #include <asm/mmu_context.h>
 #include <asm/ptdump.h>
@@ -1065,8 +1065,8 @@ int p4d_free_pud_page(p4d_t *p4d, unsigned long addr)
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-int arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap,
-                   bool want_memblock)
+int arch_add_memory(int nid, u64 start, u64 size,
+                       struct mhp_restrictions *restrictions)
 {
        int flags = 0;
 
@@ -1077,6 +1077,6 @@ int arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap,
                             size, PAGE_KERNEL, __pgd_pgtable_alloc, flags);
 
        return __add_pages(nid, start >> PAGE_SHIFT, size >> PAGE_SHIFT,
-                          altmap, want_memblock);
+                          restrictions);
 }
 #endif
index 6b168d32fbffe63a1acf325352d5fc21ad2c4ab2..2162eb32dcec828f89b9eac57a49b0cf864b3676 100644 (file)
@@ -30,7 +30,6 @@ generic-y += pci.h
 generic-y += percpu.h
 generic-y += pgalloc.h
 generic-y += preempt.h
-generic-y += segment.h
 generic-y += serial.h
 generic-y += shmparam.h
 generic-y += tlbflush.h
index fe582c3a1794143baff4a686e85f2b24d526fe4a..573242b160e1abf0d9fd6b0223c0f1b44fe3d933 100644 (file)
@@ -68,15 +68,3 @@ void __init mem_init(void)
 
        mem_init_print_info(NULL);
 }
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void __init free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-#endif
-
-void __init free_initmem(void)
-{
-       free_initmem_default(-1);
-}
index 61c01db6c29230ca8b60ffc64d00179ccc579b24..ecfc4b4b6373cf4a89b8e92ad62b686963fe7000 100644 (file)
@@ -23,6 +23,7 @@ config H8300
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_HASH
        select CPU_NO_EFFICIENT_FFS
+       select UACCESS_MEMCPY
 
 config CPU_BIG_ENDIAN
        def_bool y
index 123d8f54be4a5a5a58ca6fc8b0b4a1145fb157e1..79cd1e605ec4d1823822c1b806713a66fdb0e1b9 100644 (file)
@@ -42,12 +42,12 @@ generic-y += scatterlist.h
 generic-y += sections.h
 generic-y += serial.h
 generic-y += shmparam.h
-generic-y += sizes.h
 generic-y += spinlock.h
 generic-y += timex.h
 generic-y += tlbflush.h
 generic-y += topology.h
 generic-y += trace_clock.h
+generic-y += uaccess.h
 generic-y += unaligned.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
diff --git a/arch/h8300/include/asm/uaccess.h b/arch/h8300/include/asm/uaccess.h
deleted file mode 100644 (file)
index bc80319..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_UACCESS_H
-#define _ASM_UACCESS_H
-
-#include <linux/string.h>
-
-static inline __must_check unsigned long
-raw_copy_from_user(void *to, const void __user * from, unsigned long n)
-{
-       if (__builtin_constant_p(n)) {
-               switch(n) {
-               case 1:
-                       *(u8 *)to = *(u8 __force *)from;
-                       return 0;
-               case 2:
-                       *(u16 *)to = *(u16 __force *)from;
-                       return 0;
-               case 4:
-                       *(u32 *)to = *(u32 __force *)from;
-                       return 0;
-               }
-       }
-
-       memcpy(to, (const void __force *)from, n);
-       return 0;
-}
-
-static inline __must_check unsigned long
-raw_copy_to_user(void __user *to, const void *from, unsigned long n)
-{
-       if (__builtin_constant_p(n)) {
-               switch(n) {
-               case 1:
-                       *(u8 __force *)to = *(u8 *)from;
-                       return 0;
-               case 2:
-                       *(u16 __force *)to = *(u16 *)from;
-                       return 0;
-               case 4:
-                       *(u32 __force *)to = *(u32 *)from;
-                       return 0;
-               default:
-                       break;
-               }
-       }
-
-       memcpy((void __force *)to, from, n);
-       return 0;
-}
-#define INLINE_COPY_FROM_USER
-#define INLINE_COPY_TO_USER
-
-#include <asm-generic/uaccess.h>
-
-#endif
index b32bfa1fe99e5c56aedd9923f2f49c2807d180ce..23a979a85f1428f4e2ca7f6a922eeb2b580162bf 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/console.h>
index 0f04a5e9aa4f393226d7b1c287d2111826d944ec..1eab16b1a0bcfbf688294855f72eb7e1668fef90 100644 (file)
@@ -102,17 +102,3 @@ void __init mem_init(void)
 
        mem_init_print_info(NULL);
 }
-
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-#endif
-
-void
-free_initmem(void)
-{
-       free_initmem_default(-1);
-}
index 3e54a53208d58ad7c7587dcc88920a692c5d2634..b7d404bbaa0fe8a8592e556ade45e17df1172b4c 100644 (file)
@@ -22,7 +22,6 @@ config HEXAGON
        select GENERIC_IRQ_SHOW
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_TRACEHOOK
-       select ARCH_DISCARD_MEMBLOCK
        select NEED_SG_DMA_LENGTH
        select NO_IOPORT_MAP
        select GENERIC_IOMAP
index 6234a303d2a3bb75cb0870aa9e92e82ae06bc108..84bb1ed1b9311078c793f64dd4c9c7abc477bfbf 100644 (file)
@@ -29,10 +29,8 @@ generic-y += pci.h
 generic-y += percpu.h
 generic-y += preempt.h
 generic-y += sections.h
-generic-y += segment.h
 generic-y += serial.h
 generic-y += shmparam.h
-generic-y += sizes.h
 generic-y += topology.h
 generic-y += trace_clock.h
 generic-y += unaligned.h
index a30e58d5f3516cce39fd35caec420603e508a45b..7a34092e8b58fe604ff58fc266e85f07bfe4c647 100644 (file)
@@ -24,7 +24,6 @@
  * User space memory access functions
  */
 #include <linux/mm.h>
-#include <asm/segment.h>
 #include <asm/sections.h>
 
 /*
index 1719ede9e9bde102b66432d66e65bc462d5e6e15..41cf34243ea1b6d06b81b84cad6d0e5d506afc96 100644 (file)
@@ -84,16 +84,6 @@ void __init mem_init(void)
        init_mm.context.ptbase = __pa(init_mm.pgd);
 }
 
-/*
- * free_initmem - frees memory used by stuff declared with __init
- *
- * Todo:  free pages between __init_begin and __init_end; possibly
- * some devtree related stuff as well.
- */
-void __ref free_initmem(void)
-{
-}
-
 /*
  * free_initrd_mem - frees...  initrd memory.
  * @start - start of init memory
index 73a26f04644e3e27a17c1fc1ab4145f22f6d520c..7468d8e504672a711e34a09984f2601f0cad6b1b 100644 (file)
@@ -33,7 +33,6 @@ config IA64
        select ARCH_HAS_DMA_COHERENT_TO_PFN if SWIOTLB
        select ARCH_HAS_SYNC_DMA_FOR_CPU if SWIOTLB
        select VIRT_TO_BUS
-       select ARCH_DISCARD_MEMBLOCK
        select GENERIC_IRQ_PROBE
        select GENERIC_PENDING_IRQ if SMP
        select GENERIC_IRQ_SHOW
diff --git a/arch/ia64/include/asm/segment.h b/arch/ia64/include/asm/segment.h
deleted file mode 100644 (file)
index b89e2b3..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_IA64_SEGMENT_H
-#define _ASM_IA64_SEGMENT_H
-
-/* Only here because we have some old header files that expect it.. */
-
-#endif /* _ASM_IA64_SEGMENT_H */
index 1b604d02250bee2b8b0ea41d3236ac62ac17b6c6..ebd82535f51b7dc29af27a89258a0b683b472475 100644 (file)
@@ -10,7 +10,9 @@
 
 #include <asm/page.h>
 
-struct ia64_machine_vector ia64_mv;
+struct ia64_machine_vector ia64_mv = {
+       .mmiowb = ___ia64_mmiowb
+};
 EXPORT_SYMBOL(ia64_mv);
 
 static struct ia64_machine_vector * __init
index 56e3d0b685e19119afc0a3e244ca64c3752aca4e..e01df3f2f80d3abfa74a207f435396f13caddeaf 100644 (file)
 425    common  io_uring_setup                  sys_io_uring_setup
 426    common  io_uring_enter                  sys_io_uring_enter
 427    common  io_uring_register               sys_io_uring_register
+428    common  open_tree                       sys_open_tree
+429    common  move_mount                      sys_move_mount
+430    common  fsopen                          sys_fsopen
+431    common  fsconfig                        sys_fsconfig
+432    common  fsmount                         sys_fsmount
+433    common  fspick                          sys_fspick
index e49200e31750d1a78a98ab33bb5b8982de6b1cc1..d28e29103bdbab519293b97a455286edac33d6e7 100644 (file)
@@ -666,14 +666,14 @@ mem_init (void)
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-int arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap,
-               bool want_memblock)
+int arch_add_memory(int nid, u64 start, u64 size,
+                       struct mhp_restrictions *restrictions)
 {
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
        int ret;
 
-       ret = __add_pages(nid, start_pfn, nr_pages, altmap, want_memblock);
+       ret = __add_pages(nid, start_pfn, nr_pages, restrictions);
        if (ret)
                printk("%s: Problem encountered in __add_pages() as ret=%d\n",
                       __func__,  ret);
@@ -682,20 +682,15 @@ int arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap,
 }
 
 #ifdef CONFIG_MEMORY_HOTREMOVE
-int arch_remove_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap)
+void arch_remove_memory(int nid, u64 start, u64 size,
+                       struct vmem_altmap *altmap)
 {
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
        struct zone *zone;
-       int ret;
 
        zone = page_zone(pfn_to_page(start_pfn));
-       ret = __remove_pages(zone, start_pfn, nr_pages, altmap);
-       if (ret)
-               pr_warn("%s: Problem encountered in __remove_pages() as"
-                       " ret=%d\n", __func__,  ret);
-
-       return ret;
+       __remove_pages(zone, start_pfn, nr_pages, altmap);
 }
 #endif
 #endif
index fe5cc2da6d108ac0dd74feb5c709a3000eeb2e7b..218e037ef901a68cc0b1caa73a84288ad9205ed6 100644 (file)
@@ -26,7 +26,6 @@ config M68K
        select MODULES_USE_ELF_RELA
        select OLD_SIGSUSPEND3
        select OLD_SIGACTION
-       select ARCH_DISCARD_MEMBLOCK
        select MMU_GATHER_NO_RANGE if MMU
 
 config CPU_BIG_ENDIAN
index df4ec3ec71d1518bfac752044f7a1eae9291535a..7e3d0734b2f377f7cc375d0e21668e4c9198f3db 100644 (file)
 425    common  io_uring_setup                  sys_io_uring_setup
 426    common  io_uring_enter                  sys_io_uring_enter
 427    common  io_uring_register               sys_io_uring_register
+428    common  open_tree                       sys_open_tree
+429    common  move_mount                      sys_move_mount
+430    common  fsopen                          sys_fsopen
+431    common  fsconfig                        sys_fsconfig
+432    common  fsmount                         sys_fsmount
+433    common  fspick                          sys_fspick
index 8868a4c9adaefb3914f0c775a4205504d391ec87..778cacb7d57b3defdf05ef114af4a07423a107c2 100644 (file)
@@ -147,10 +147,3 @@ void __init mem_init(void)
        init_pointer_tables();
        mem_init_print_info(NULL);
 }
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-#endif
index 4964947732af3e37bd5d651aaad9a3f3ccd39056..26339e417695fb7e99560fe507a3cfb9a6c082e4 100644 (file)
 425    common  io_uring_setup                  sys_io_uring_setup
 426    common  io_uring_enter                  sys_io_uring_enter
 427    common  io_uring_register               sys_io_uring_register
+428    common  open_tree                       sys_open_tree
+429    common  move_mount                      sys_move_mount
+430    common  fsopen                          sys_fsopen
+431    common  fsconfig                        sys_fsconfig
+432    common  fsmount                         sys_fsmount
+433    common  fspick                          sys_fspick
index 7e97d44f653801ddd8972320988aa376c8ccc2b3..a015a951c8b78bece064bb3cc5c03a5123fa5b2d 100644 (file)
@@ -186,18 +186,6 @@ void __init setup_memory(void)
        paging_init();
 }
 
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-#endif
-
-void free_initmem(void)
-{
-       free_initmem_default(-1);
-}
-
 void __init mem_init(void)
 {
        high_memory = (void *)__va(memory_start + lowmem_size - 1);
index ff8cff9fcf545bba8d9026aced13af4a804da07a..70d3200476bfebee57f493e2eb70d29696600166 100644 (file)
@@ -5,7 +5,6 @@ config MIPS
        select ARCH_32BIT_OFF_T if !64BIT
        select ARCH_BINFMT_ELF_STATE if MIPS_FP_SUPPORT
        select ARCH_CLOCKSOURCE_DATA
-       select ARCH_DISCARD_MEMBLOCK
        select ARCH_HAS_ELF_RANDOMIZE
        select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
        select ARCH_HAS_UBSAN_SANITIZE_ALL
@@ -675,7 +674,10 @@ config SGI_IP27
        select SYS_HAS_EARLY_PRINTK
        select HAVE_PCI
        select IRQ_MIPS_CPU
+       select IRQ_DOMAIN_HIERARCHY
        select NR_CPUS_DEFAULT_64
+       select PCI_DRIVERS_GENERIC
+       select PCI_XTALK_BRIDGE
        select SYS_HAS_CPU_R10000
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
@@ -1242,6 +1244,9 @@ config IRQ_GT641XX
 config PCI_GT64XXX_PCI0
        bool
 
+config PCI_XTALK_BRIDGE
+       bool
+
 config NO_EXCEPT_FILL
        bool
 
index 1454d9f6ab2d425d7828c6b934e21314e1cb2449..b8f3397c59c92a7cc61563017eb2e97ac71fec5a 100644 (file)
@@ -131,9 +131,7 @@ static void __init alchemy_setup_uarts(int ctype)
 }
 
 
-/* The dmamask must be set for OHCI/EHCI to work */
-static u64 alchemy_ohci_dmamask = DMA_BIT_MASK(32);
-static u64 __maybe_unused alchemy_ehci_dmamask = DMA_BIT_MASK(32);
+static u64 alchemy_all_dmamask = DMA_BIT_MASK(32);
 
 /* Power on callback for the ehci platform driver */
 static int alchemy_ehci_power_on(struct platform_device *pdev)
@@ -231,7 +229,7 @@ static void __init alchemy_setup_usb(int ctype)
        res[1].flags = IORESOURCE_IRQ;
        pdev->name = "ohci-platform";
        pdev->id = 0;
-       pdev->dev.dma_mask = &alchemy_ohci_dmamask;
+       pdev->dev.dma_mask = &alchemy_all_dmamask;
        pdev->dev.platform_data = &alchemy_ohci_pdata;
 
        if (platform_device_register(pdev))
@@ -251,7 +249,7 @@ static void __init alchemy_setup_usb(int ctype)
                res[1].flags = IORESOURCE_IRQ;
                pdev->name = "ehci-platform";
                pdev->id = 0;
-               pdev->dev.dma_mask = &alchemy_ehci_dmamask;
+               pdev->dev.dma_mask = &alchemy_all_dmamask;
                pdev->dev.platform_data = &alchemy_ehci_pdata;
 
                if (platform_device_register(pdev))
@@ -271,7 +269,7 @@ static void __init alchemy_setup_usb(int ctype)
                res[1].flags = IORESOURCE_IRQ;
                pdev->name = "ohci-platform";
                pdev->id = 1;
-               pdev->dev.dma_mask = &alchemy_ohci_dmamask;
+               pdev->dev.dma_mask = &alchemy_all_dmamask;
                pdev->dev.platform_data = &alchemy_ohci_pdata;
 
                if (platform_device_register(pdev))
@@ -338,7 +336,11 @@ static struct platform_device au1xxx_eth0_device = {
        .name           = "au1000-eth",
        .id             = 0,
        .num_resources  = MAC_RES_COUNT,
-       .dev.platform_data = &au1xxx_eth0_platform_data,
+       .dev = {
+               .dma_mask               = &alchemy_all_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &au1xxx_eth0_platform_data,
+       },
 };
 
 static struct resource au1xxx_eth1_resources[][MAC_RES_COUNT] __initdata = {
@@ -370,7 +372,11 @@ static struct platform_device au1xxx_eth1_device = {
        .name           = "au1000-eth",
        .id             = 1,
        .num_resources  = MAC_RES_COUNT,
-       .dev.platform_data = &au1xxx_eth1_platform_data,
+       .dev = {
+               .dma_mask               = &alchemy_all_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &au1xxx_eth1_platform_data,
+       },
 };
 
 void __init au1xxx_override_eth_cfg(unsigned int port,
index d4ca97e2ec6cc6eb9363ea0b5be60e90464960b2..228cdc736db703e1e84dbc808f5d49ea1ce98094 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
index 25a57895a3a359f6f7ded09785bf6e4cc15ea1db..298b46b4e9cb8b8c2ec211812528169b76bf6966 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/memblock.h>
 #include <linux/err.h>
 #include <linux/clk.h>
index 249f5285e343cc7f40c3be3e6fab16ff6556b3d4..91ce75edbfb46da1e52348e2dbb675ada346aa5a 100644 (file)
@@ -41,7 +41,7 @@ CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_BCM47XXSFLASH=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_BCM47XXNFLASH=y
 CONFIG_NETDEVICES=y
 CONFIG_B44=y
index 412800d5d7e0ddbfc7e292632dd0d6d0082dd224..50bebce2850038a4a43904563bbed7c8c09a5376 100644 (file)
@@ -51,7 +51,7 @@ CONFIG_DEVTMPFS=y
 CONFIG_DMA_CMA=y
 CONFIG_CMA_SIZE_MBYTES=32
 CONFIG_MTD=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_JZ4780=y
 CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_FASTMAP=y
index 34633b7611cbcf46b1ca636483c07cc4031258ec..bc9b6ae046b27bf221c26ce92204513798a9a3e7 100644 (file)
@@ -95,8 +95,8 @@ CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_M25P80=y
 CONFIG_MTD_SST25L=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ECC_BCH=y
+CONFIG_MTD_RAW_NAND=y
+CONFIG_MTD_NAND_ECC_SW_BCH=y
 CONFIG_MTD_NAND_AU1550=y
 CONFIG_MTD_NAND_PLATFORM=y
 CONFIG_MTD_SPI_NOR=y
index f72223b366cabc4294a4ec40c9e3eb5987cfb55f..1ed0d3e8715ef63c782a4784a06e6fea765aed2f 100644 (file)
@@ -15,9 +15,9 @@ CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CMDLINE_PARTS=y
 
-CONFIG_MTD_NAND_ECC=y
-CONFIG_MTD_NAND_ECC_BCH=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ECC_SW_HAMMING=y
+CONFIG_MTD_NAND_ECC_SW_BCH=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_GPIO=y
 CONFIG_MTD_NAND_IDS=y
 
index 184eb65a6ba71a5bea1e6b39cbe5d389a9764416..1134fbb99fc2144f9d26aa43929edfdc05dadc1e 100644 (file)
@@ -10,7 +10,7 @@ CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_M25P80=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_PLATFORM=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_MTD_UBI=y
index ff40fbc2f4399dc2a51b76d39b022a993df5a7e8..21a1168ae301f6d1519990afce524d8b365a32de 100644 (file)
@@ -228,7 +228,7 @@ CONFIG_SERIAL_IP22_ZILOG=m
 # CONFIG_HW_RANDOM is not set
 CONFIG_RAW_DRIVER=m
 # CONFIG_HWMON is not set
-CONFIG_THERMAL=m
+CONFIG_THERMAL=y
 CONFIG_WATCHDOG=y
 CONFIG_INDYDOG=m
 # CONFIG_VGA_CONSOLE is not set
index 81c47e18131bd46422143e86d8ef1a12ed7b1260..54db5dedf7764594b473a2312581dde6801b0ee2 100644 (file)
@@ -271,7 +271,7 @@ CONFIG_I2C_PARPORT_LIGHT=m
 CONFIG_I2C_TAOS_EVM=m
 CONFIG_I2C_STUB=m
 # CONFIG_HWMON is not set
-CONFIG_THERMAL=m
+CONFIG_THERMAL=y
 CONFIG_MFD_PCF50633=m
 CONFIG_PCF50633_ADC=m
 CONFIG_PCF50633_GPIO=m
index aa7e98c5f5fc92e4105396ef99b76a8fa31a881a..3d390a7494d6de6f90e9a5459d064bc76ed05953 100644 (file)
@@ -41,7 +41,7 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_SCSI=m
index 520e7ef35383097f84b294175a7fbf88967950ba..247d56e94c0a766bde2807bcc83454cce9bce75c 100644 (file)
@@ -42,7 +42,7 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_SCSI=m
index 7671fe6a804257e5ec68e92e75de74f47505245f..1a0677d04982897092a20e14b98481366b67d3ca 100644 (file)
@@ -44,7 +44,7 @@ CONFIG_TCP_CONG_WESTWOOD=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_JZ4740=y
 CONFIG_MTD_UBI=y
 CONFIG_NETDEVICES=y
index ed1038f62a2c53ba1b8bf128efc7bc3678aa46b2..50632a3103dd837f715fa44bad5272f2291da8e7 100644 (file)
@@ -109,7 +109,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_BLOCK2MTD=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_PLATFORM=y
 CONFIG_ATA=y
 # CONFIG_ATA_VERBOSE_ERROR is not set
index b0f0c5f9ad9d02319c1014efd2beb18717fa557c..5e389db35fa74670a3a180fa4de4515c57363e6e 100644 (file)
@@ -39,7 +39,7 @@ CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_RBTX4939=y
-CONFIG_MTD_NAND=m
+CONFIG_MTD_RAW_NAND=m
 CONFIG_MTD_NAND_TXX9NDFMC=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
index 2bb02ea9fb4ee06c10855ffe9328df25c5153d6f..203db83c3ee9d2158cda51e1856bb9f728db5a65 100644 (file)
@@ -81,7 +81,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_MTD_LANTIQ=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_XWAY=y
 CONFIG_EEPROM_93CX6=m
 CONFIG_SCSI=y
index a106f8113842a35e4c125d741a11992b63d95281..a84475f1924f5189bba767191dc9faef2ddfe939 100644 (file)
@@ -43,14 +43,14 @@ void __init *plat_get_fdt(void)
                /* Already set up */
                return (void *)fdt;
 
-       if ((fw_arg0 == -2) && !fdt_check_header((void *)fw_arg1)) {
+       if ((fw_arg0 == -2) && !fdt_check_header((void *)fw_passed_dtb)) {
                /*
                 * We booted using the UHI boot protocol, so we have been
                 * provided with the appropriate device tree for the board.
                 * Make use of it & search for any machine struct based upon
                 * the root compatible string.
                 */
-               fdt = (void *)fw_arg1;
+               fdt = (void *)fw_passed_dtb;
 
                for_each_mips_machine(check_mach) {
                        match = mips_machine_is_compatible(check_mach, fdt);
index 87b86cdf126a99245d8309263906e20e748edb89..a03cd4e24f3789169978a5818733d377dc7ef4b5 100644 (file)
@@ -19,7 +19,6 @@ generic-y += preempt.h
 generic-y += qrwlock.h
 generic-y += qspinlock.h
 generic-y += sections.h
-generic-y += segment.h
 generic-y += trace_clock.h
 generic-y += unaligned.h
 generic-y += user.h
index 830c93a010c34926b26d3dea33a9f6ac8049ee59..9a466dde9b96a14f9628476c5a65d8bb640d761f 100644 (file)
@@ -482,7 +482,7 @@ static inline void __clear_bit_unlock(unsigned long nr, volatile unsigned long *
  * Return the bit position (0..63) of the most significant 1 bit in a word
  * Returns -1 if no 1 bit exists
  */
-static inline unsigned long __fls(unsigned long word)
+static __always_inline unsigned long __fls(unsigned long word)
 {
        int num;
 
@@ -548,7 +548,7 @@ static inline unsigned long __fls(unsigned long word)
  * Returns 0..SZLONG-1
  * Undefined if no bit exists, so code should check against 0 first.
  */
-static inline unsigned long __ffs(unsigned long word)
+static __always_inline unsigned long __ffs(unsigned long word)
 {
        return __fls(word & -word);
 }
index 42ea1313626c2bff56dc5ebe831cf739ccc0477f..965f0793a5f9144ebbc0c3b8088c2f65941ec3c4 100644 (file)
@@ -7,18 +7,9 @@
 #include <asm/mmzone.h>
 
 struct cpuinfo_ip27 {
-//     cpuid_t         p_cpuid;        /* PROM assigned cpuid */
        cnodeid_t       p_nodeid;       /* my node ID in compact-id-space */
        nasid_t         p_nasid;        /* my node ID in numa-as-id-space */
        unsigned char   p_slice;        /* Physical position on node board */
-#if 0
-       unsigned long           loops_per_sec;
-       unsigned long           ipi_count;
-       unsigned long           irq_attempt[NR_IRQS];
-       unsigned long           smp_local_irq_count;
-       unsigned long           prof_multiplier;
-       unsigned long           prof_counter;
-#endif
 };
 
 extern struct cpuinfo_ip27 sn_cpu_info[NR_CPUS];
@@ -30,7 +21,7 @@ extern struct cpuinfo_ip27 sn_cpu_info[NR_CPUS];
 struct pci_bus;
 extern int pcibus_to_node(struct pci_bus *);
 
-#define cpumask_of_pcibus(bus) (cpu_online_mask)
+#define cpumask_of_pcibus(bus) (cpumask_of_node(pcibus_to_node(bus)))
 
 extern unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
 
index 23574c27eb40f97b40a51d10d2dac960579e3072..a92cd30b48c912b17726384073a03148e44d10c5 100644 (file)
@@ -801,15 +801,13 @@ struct bridge_err_cmdword {
 #define PCI64_ATTR_RMF_SHFT    48
 
 struct bridge_controller {
-       struct pci_controller   pc;
-       struct resource         mem;
-       struct resource         io;
        struct resource         busn;
        struct bridge_regs      *base;
-       nasid_t                 nasid;
-       unsigned int            widget_id;
-       u64                     baddr;
+       unsigned long           baddr;
+       unsigned long           intr_addr;
+       struct irq_domain       *domain;
        unsigned int            pci_int[8];
+       nasid_t                 nasid;
 };
 
 #define BRIDGE_CONTROLLER(bus) \
@@ -822,8 +820,4 @@ struct bridge_controller {
 #define bridge_clr(bc, reg, val)       \
        __raw_writel(__raw_readl(&bc->base->reg) & ~(val), &bc->base->reg)
 
-extern int request_bridge_irq(struct bridge_controller *bc, int pin);
-
-extern struct pci_ops bridge_pci_ops;
-
 #endif /* _ASM_PCI_BRIDGE_H */
diff --git a/arch/mips/include/asm/sn/irq_alloc.h b/arch/mips/include/asm/sn/irq_alloc.h
new file mode 100644 (file)
index 0000000..09b89ce
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_SN_IRQ_ALLOC_H
+#define __ASM_SN_IRQ_ALLOC_H
+
+struct irq_alloc_info {
+       void *ctrl;
+       nasid_t nasid;
+       int pin;
+};
+
+#endif /* __ASM_SN_IRQ_ALLOC_H */
index 26d2ed1fa9176bc8c811673792d7f7d65a8106f7..680e7efebbaf6bd08246ade5a9dd14a8a6640a57 100644 (file)
@@ -47,15 +47,6 @@ typedef struct xtalk_piomap_s *xtalk_piomap_t;
 #define XIO_PORT(x)    ((xwidgetnum_t)(((x)&XIO_PORT_BITS) >> XIO_PORT_SHIFT))
 #define XIO_PACK(p, o) ((((uint64_t)(p))<<XIO_PORT_SHIFT) | ((o)&XIO_ADDR_BITS))
 
-#ifdef CONFIG_PCI
-extern int bridge_probe(nasid_t nasid, int widget, int masterwid);
-#else
-static inline int bridge_probe(nasid_t nasid, int widget, int masterwid)
-{
-       return 0;
-}
-#endif
-
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_XTALK_XTALK_H */
index bada74af7641bcaade341f60c33af4e4dc67c761..c04b97aace4ad991e04490cd4330dacf15c964a0 100644 (file)
@@ -42,8 +42,8 @@ static inline void align_mod(const int align, const int mod)
                : "n"(align), "n"(mod));
 }
 
-static inline void mult_sh_align_mod(long *v1, long *v2, long *w,
-                                    const int align, const int mod)
+static __always_inline void mult_sh_align_mod(long *v1, long *v2, long *w,
+                                             const int align, const int mod)
 {
        unsigned long flags;
        int m1, m2;
index d5e335e6846a9645a96ffb556014d16f32053d38..6126b77d5a62b0a6674e80a9d3628ada18e9d0f1 100644 (file)
@@ -1973,6 +1973,14 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
                panic("Unknown Ingenic Processor ID!");
                break;
        }
+
+       /*
+        * The config0 register in the Xburst CPUs with a processor ID of
+        * PRID_COMP_INGENIC_D0 report themselves as MIPS32r2 compatible,
+        * but they don't actually support this ISA.
+        */
+       if ((c->processor_id & PRID_COMP_MASK) == PRID_COMP_INGENIC_D0)
+               c->isa_level &= ~MIPS_CPU_ISA_M32R2;
 }
 
 static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
index 413863508f6fab1c718a19751fa030b278a506a3..d67fb64e908c4b1157c1672f7fb77899122e0c52 100644 (file)
@@ -64,17 +64,11 @@ struct mips_perf_event {
        #define CNTR_EVEN       0x55555555
        #define CNTR_ODD        0xaaaaaaaa
        #define CNTR_ALL        0xffffffff
-#ifdef CONFIG_MIPS_MT_SMP
        enum {
                T  = 0,
                V  = 1,
                P  = 2,
        } range;
-#else
-       #define T
-       #define V
-       #define P
-#endif
 };
 
 static struct mips_perf_event raw_event;
@@ -325,9 +319,7 @@ static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx)
 {
        struct perf_event *event = container_of(evt, struct perf_event, hw);
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
-#ifdef CONFIG_MIPS_MT_SMP
        unsigned int range = evt->event_base >> 24;
-#endif /* CONFIG_MIPS_MT_SMP */
 
        WARN_ON(idx < 0 || idx >= mipspmu.num_counters);
 
@@ -336,21 +328,15 @@ static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx)
                /* Make sure interrupt enabled. */
                MIPS_PERFCTRL_IE;
 
-#ifdef CONFIG_CPU_BMIPS5000
-       {
+       if (IS_ENABLED(CONFIG_CPU_BMIPS5000)) {
                /* enable the counter for the calling thread */
                cpuc->saved_ctrl[idx] |=
                        (1 << (12 + vpe_id())) | BRCM_PERFCTRL_TC;
-       }
-#else
-#ifdef CONFIG_MIPS_MT_SMP
-       if (range > V) {
+       } else if (IS_ENABLED(CONFIG_MIPS_MT_SMP) && range > V) {
                /* The counter is processor wide. Set it up to count all TCs. */
                pr_debug("Enabling perf counter for all TCs\n");
                cpuc->saved_ctrl[idx] |= M_TC_EN_ALL;
-       } else
-#endif /* CONFIG_MIPS_MT_SMP */
-       {
+       } else {
                unsigned int cpu, ctrl;
 
                /*
@@ -365,7 +351,6 @@ static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx)
                cpuc->saved_ctrl[idx] |= ctrl;
                pr_debug("Enabling perf counter for CPU%d\n", cpu);
        }
-#endif /* CONFIG_CPU_BMIPS5000 */
        /*
         * We do not actually let the counter run. Leave it until start().
         */
index 9392dfe33f97ec48a74014d3bc49940dafdc944d..0e2dd68ade5784004abeebb552bfcf18dfed44f6 100644 (file)
 425    n32     io_uring_setup                  sys_io_uring_setup
 426    n32     io_uring_enter                  sys_io_uring_enter
 427    n32     io_uring_register               sys_io_uring_register
+428    n32     open_tree                       sys_open_tree
+429    n32     move_mount                      sys_move_mount
+430    n32     fsopen                          sys_fsopen
+431    n32     fsconfig                        sys_fsconfig
+432    n32     fsmount                         sys_fsmount
+433    n32     fspick                          sys_fspick
index cd0c8aa21fbacfb7563c39123f0880d2b753a7c2..5eebfa0d155c598354619f326951b15edad4cd54 100644 (file)
 425    n64     io_uring_setup                  sys_io_uring_setup
 426    n64     io_uring_enter                  sys_io_uring_enter
 427    n64     io_uring_register               sys_io_uring_register
+428    n64     open_tree                       sys_open_tree
+429    n64     move_mount                      sys_move_mount
+430    n64     fsopen                          sys_fsopen
+431    n64     fsconfig                        sys_fsconfig
+432    n64     fsmount                         sys_fsmount
+433    n64     fspick                          sys_fspick
index e849e8ffe4a25b4516cdc748abfa96bb2c918ebe..3cc1374e02d079a672be86affdd066cc54c0e326 100644 (file)
 425    o32     io_uring_setup                  sys_io_uring_setup
 426    o32     io_uring_enter                  sys_io_uring_enter
 427    o32     io_uring_register               sys_io_uring_register
+428    o32     open_tree                       sys_open_tree
+429    o32     move_mount                      sys_move_mount
+430    o32     fsopen                          sys_fsopen
+431    o32     fsconfig                        sys_fsconfig
+432    o32     fsmount                         sys_fsmount
+433    o32     fspick                          sys_fspick
index 0d14e0d8eacf058f49e25be97c1347847af6a137..4c2b4483683cd6395bf7c61e805647868060742d 100644 (file)
@@ -235,7 +235,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
  * get_user_pages_fast() - pin user pages in memory
  * @start:     starting user address
  * @nr_pages:  number of pages from start to pin
- * @write:     whether pages will be written to
+ * @gup_flags: flags modifying pin behaviour
  * @pages:     array that receives pointers to the pages pinned.
  *             Should be at least nr_pages long.
  *
@@ -247,8 +247,8 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
  * requested. If nr_pages is 0 or negative, returns 0. If no pages
  * were pinned, returns -errno.
  */
-int get_user_pages_fast(unsigned long start, int nr_pages, int write,
-                       struct page **pages)
+int get_user_pages_fast(unsigned long start, int nr_pages,
+                       unsigned int gup_flags, struct page **pages)
 {
        struct mm_struct *mm = current->mm;
        unsigned long addr, len, end;
@@ -273,7 +273,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                next = pgd_addr_end(addr, end);
                if (pgd_none(pgd))
                        goto slow;
-               if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+               if (!gup_pud_range(pgd, addr, next, gup_flags & FOLL_WRITE,
+                                  pages, &nr))
                        goto slow;
        } while (pgdp++, addr = next, addr != end);
        local_irq_enable();
@@ -289,7 +290,7 @@ slow_irqon:
        pages += nr;
 
        ret = get_user_pages_unlocked(start, (end - start) >> PAGE_SHIFT,
-                                     pages, write ? FOLL_WRITE : 0);
+                                     pages, gup_flags);
 
        /* Have to be a bit careful with return values */
        if (nr > 0) {
index bbb196ad5f26b08e07b7e808dd905e0818f6bef8..8a038b30d3c4981d3e9bd8fdcbee8d40665bae82 100644 (file)
@@ -504,14 +504,6 @@ void free_init_pages(const char *what, unsigned long begin, unsigned long end)
        printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
 }
 
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
-                          "initrd");
-}
-#endif
-
 void (*free_init_pages_eva)(void *begin, void *end) = NULL;
 
 void __ref free_initmem(void)
index c4f976593061f21ee17594a3b68d1dcf19dec84b..d6de4cb2e31cafe13b5435606bad5aad3e9247a0 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_PCI_AR2315)      += pci-ar2315.o
 obj-$(CONFIG_SOC_AR71XX)       += pci-ar71xx.o
 obj-$(CONFIG_PCI_AR724X)       += pci-ar724x.o
 obj-$(CONFIG_MIPS_PCI_VIRTIO)  += pci-virtio-guest.o
+obj-$(CONFIG_PCI_XTALK_BRIDGE) += pci-xtalk-bridge.o
 #
 # These are still pretty much in the old state, watch, go blind.
 #
@@ -39,7 +40,7 @@ obj-$(CONFIG_MIPS_MALTA)      += fixup-malta.o pci-malta.o
 obj-$(CONFIG_PMC_MSP7120_GW)   += fixup-pmcmsp.o ops-pmcmsp.o
 obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o
 obj-$(CONFIG_PMC_MSP7120_FPGA) += fixup-pmcmsp.o ops-pmcmsp.o
-obj-$(CONFIG_SGI_IP27)         += ops-bridge.o pci-ip27.o
+obj-$(CONFIG_SGI_IP27)         += pci-ip27.o
 obj-$(CONFIG_SGI_IP32)         += fixup-ip32.o ops-mace.o pci-ip32.o
 obj-$(CONFIG_SIBYTE_SB1250)    += fixup-sb1250.o pci-sb1250.o
 obj-$(CONFIG_SIBYTE_BCM112X)   += fixup-sb1250.o pci-sb1250.o
diff --git a/arch/mips/pci/ops-bridge.c b/arch/mips/pci/ops-bridge.c
deleted file mode 100644 (file)
index df95b0d..0000000
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1999, 2000, 04, 06 Ralf Baechle (ralf@linux-mips.org)
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- */
-#include <linux/pci.h>
-#include <asm/paccess.h>
-#include <asm/pci/bridge.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/sn0/hub.h>
-
-/*
- * Most of the IOC3 PCI config register aren't present
- * we emulate what is needed for a normal PCI enumeration
- */
-static u32 emulate_ioc3_cfg(int where, int size)
-{
-       if (size == 1 && where == 0x3d)
-               return 0x01;
-       else if (size == 2 && where == 0x3c)
-               return 0x0100;
-       else if (size == 4 && where == 0x3c)
-               return 0x00000100;
-
-       return 0;
-}
-
-/*
- * The Bridge ASIC supports both type 0 and type 1 access.  Type 1 is
- * not really documented, so right now I can't write code which uses it.
- * Therefore we use type 0 accesses for now even though they won't work
- * correctly for PCI-to-PCI bridges.
- *
- * The function is complicated by the ultimate brokenness of the IOC3 chip
- * which is used in SGI systems.  The IOC3 can only handle 32-bit PCI
- * accesses and does only decode parts of it's address space.
- */
-
-static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
-                                int where, int size, u32 * value)
-{
-       struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
-       struct bridge_regs *bridge = bc->base;
-       int slot = PCI_SLOT(devfn);
-       int fn = PCI_FUNC(devfn);
-       volatile void *addr;
-       u32 cf, shift, mask;
-       int res;
-
-       addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID];
-       if (get_dbe(cf, (u32 *) addr))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       /*
-        * IOC3 is broken beyond belief ...  Don't even give the
-        * generic PCI code a chance to look at it for real ...
-        */
-       if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
-               goto is_ioc3;
-
-       addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
-
-       if (size == 1)
-               res = get_dbe(*value, (u8 *) addr);
-       else if (size == 2)
-               res = get_dbe(*value, (u16 *) addr);
-       else
-               res = get_dbe(*value, (u32 *) addr);
-
-       return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-
-is_ioc3:
-
-       /*
-        * IOC3 special handling
-        */
-       if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) {
-               *value = emulate_ioc3_cfg(where, size);
-               return PCIBIOS_SUCCESSFUL;
-       }
-
-       addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
-
-       if (get_dbe(cf, (u32 *) addr))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       shift = ((where & 3) << 3);
-       mask = (0xffffffffU >> ((4 - size) << 3));
-       *value = (cf >> shift) & mask;
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
-                                int where, int size, u32 * value)
-{
-       struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
-       struct bridge_regs *bridge = bc->base;
-       int busno = bus->number;
-       int slot = PCI_SLOT(devfn);
-       int fn = PCI_FUNC(devfn);
-       volatile void *addr;
-       u32 cf, shift, mask;
-       int res;
-
-       bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
-       addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
-       if (get_dbe(cf, (u32 *) addr))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       /*
-        * IOC3 is broken beyond belief ...  Don't even give the
-        * generic PCI code a chance to look at it for real ...
-        */
-       if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
-               goto is_ioc3;
-
-       bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
-       addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
-
-       if (size == 1)
-               res = get_dbe(*value, (u8 *) addr);
-       else if (size == 2)
-               res = get_dbe(*value, (u16 *) addr);
-       else
-               res = get_dbe(*value, (u32 *) addr);
-
-       return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-
-is_ioc3:
-
-       /*
-        * IOC3 special handling
-        */
-       if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) {
-               *value = emulate_ioc3_cfg(where, size);
-               return PCIBIOS_SUCCESSFUL;
-       }
-
-       bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
-       addr = &bridge->b_type1_cfg.c[(fn << 8) | where];
-
-       if (get_dbe(cf, (u32 *) addr))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       shift = ((where & 3) << 3);
-       mask = (0xffffffffU >> ((4 - size) << 3));
-       *value = (cf >> shift) & mask;
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_read_config(struct pci_bus *bus, unsigned int devfn,
-                          int where, int size, u32 * value)
-{
-       if (!pci_is_root_bus(bus))
-               return pci_conf1_read_config(bus, devfn, where, size, value);
-
-       return pci_conf0_read_config(bus, devfn, where, size, value);
-}
-
-static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
-                                 int where, int size, u32 value)
-{
-       struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
-       struct bridge_regs *bridge = bc->base;
-       int slot = PCI_SLOT(devfn);
-       int fn = PCI_FUNC(devfn);
-       volatile void *addr;
-       u32 cf, shift, mask, smask;
-       int res;
-
-       addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID];
-       if (get_dbe(cf, (u32 *) addr))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       /*
-        * IOC3 is broken beyond belief ...  Don't even give the
-        * generic PCI code a chance to look at it for real ...
-        */
-       if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
-               goto is_ioc3;
-
-       addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
-
-       if (size == 1) {
-               res = put_dbe(value, (u8 *) addr);
-       } else if (size == 2) {
-               res = put_dbe(value, (u16 *) addr);
-       } else {
-               res = put_dbe(value, (u32 *) addr);
-       }
-
-       if (res)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       return PCIBIOS_SUCCESSFUL;
-
-is_ioc3:
-
-       /*
-        * IOC3 special handling
-        */
-       if ((where >= 0x14 && where < 0x40) || (where >= 0x48))
-               return PCIBIOS_SUCCESSFUL;
-
-       addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
-
-       if (get_dbe(cf, (u32 *) addr))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       shift = ((where & 3) << 3);
-       mask = (0xffffffffU >> ((4 - size) << 3));
-       smask = mask << shift;
-
-       cf = (cf & ~smask) | ((value & mask) << shift);
-       if (put_dbe(cf, (u32 *) addr))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
-                                 int where, int size, u32 value)
-{
-       struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
-       struct bridge_regs *bridge = bc->base;
-       int slot = PCI_SLOT(devfn);
-       int fn = PCI_FUNC(devfn);
-       int busno = bus->number;
-       volatile void *addr;
-       u32 cf, shift, mask, smask;
-       int res;
-
-       bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
-       addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
-       if (get_dbe(cf, (u32 *) addr))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       /*
-        * IOC3 is broken beyond belief ...  Don't even give the
-        * generic PCI code a chance to look at it for real ...
-        */
-       if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
-               goto is_ioc3;
-
-       addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
-
-       if (size == 1) {
-               res = put_dbe(value, (u8 *) addr);
-       } else if (size == 2) {
-               res = put_dbe(value, (u16 *) addr);
-       } else {
-               res = put_dbe(value, (u32 *) addr);
-       }
-
-       if (res)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       return PCIBIOS_SUCCESSFUL;
-
-is_ioc3:
-
-       /*
-        * IOC3 special handling
-        */
-       if ((where >= 0x14 && where < 0x40) || (where >= 0x48))
-               return PCIBIOS_SUCCESSFUL;
-
-       addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
-
-       if (get_dbe(cf, (u32 *) addr))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       shift = ((where & 3) << 3);
-       mask = (0xffffffffU >> ((4 - size) << 3));
-       smask = mask << shift;
-
-       cf = (cf & ~smask) | ((value & mask) << shift);
-       if (put_dbe(cf, (u32 *) addr))
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_write_config(struct pci_bus *bus, unsigned int devfn,
-       int where, int size, u32 value)
-{
-       if (!pci_is_root_bus(bus))
-               return pci_conf1_write_config(bus, devfn, where, size, value);
-
-       return pci_conf0_write_config(bus, devfn, where, size, value);
-}
-
-struct pci_ops bridge_pci_ops = {
-       .read   = pci_read_config,
-       .write  = pci_write_config,
-};
index 3c177b4d0609154836080b1e4b623f769e0a12c6..441eb9383b20fd8d24d7e9ce4e49751ec67ac7c6 100644 (file)
@@ -7,162 +7,7 @@
  * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org)
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  */
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/pci.h>
-#include <linux/smp.h>
-#include <linux/dma-direct.h>
-#include <asm/sn/arch.h>
 #include <asm/pci/bridge.h>
-#include <asm/paccess.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/sn0/hub.h>
-
-/*
- * Max #PCI busses we can handle; ie, max #PCI bridges.
- */
-#define MAX_PCI_BUSSES         40
-
-/*
- * XXX: No kmalloc available when we do our crosstalk scan,
- *     we should try to move it later in the boot process.
- */
-static struct bridge_controller bridges[MAX_PCI_BUSSES];
-
-extern struct pci_ops bridge_pci_ops;
-
-int bridge_probe(nasid_t nasid, int widget_id, int masterwid)
-{
-       unsigned long offset = NODE_OFFSET(nasid);
-       struct bridge_controller *bc;
-       static int num_bridges = 0;
-       int slot;
-
-       pci_set_flags(PCI_PROBE_ONLY);
-
-       printk("a bridge\n");
-
-       /* XXX: kludge alert.. */
-       if (!num_bridges)
-               ioport_resource.end = ~0UL;
-
-       bc = &bridges[num_bridges];
-
-       bc->pc.pci_ops          = &bridge_pci_ops;
-       bc->pc.mem_resource     = &bc->mem;
-       bc->pc.io_resource      = &bc->io;
-
-       bc->pc.index            = num_bridges;
-
-       bc->mem.name            = "Bridge PCI MEM";
-       bc->pc.mem_offset       = offset;
-       bc->mem.start           = 0;
-       bc->mem.end             = ~0UL;
-       bc->mem.flags           = IORESOURCE_MEM;
-
-       bc->io.name             = "Bridge IO MEM";
-       bc->pc.io_offset        = offset;
-       bc->io.start            = 0UL;
-       bc->io.end              = ~0UL;
-       bc->io.flags            = IORESOURCE_IO;
-
-       bc->widget_id = widget_id;
-       bc->nasid = nasid;
-
-       bc->baddr = (u64)masterwid << 60 | PCI64_ATTR_BAR;
-
-       /*
-        * point to this bridge
-        */
-       bc->base = (struct bridge_regs *)RAW_NODE_SWIN_BASE(nasid, widget_id);
-
-       /*
-        * Clear all pending interrupts.
-        */
-       bridge_write(bc, b_int_rst_stat, BRIDGE_IRR_ALL_CLR);
-
-       /*
-        * Until otherwise set up, assume all interrupts are from slot 0
-        */
-       bridge_write(bc, b_int_device, 0x0);
-
-       /*
-        * swap pio's to pci mem and io space (big windows)
-        */
-       bridge_set(bc, b_wid_control, BRIDGE_CTRL_IO_SWAP |
-                                     BRIDGE_CTRL_MEM_SWAP);
-#ifdef CONFIG_PAGE_SIZE_4KB
-       bridge_clr(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
-#else /* 16kB or larger */
-       bridge_set(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
-#endif
-
-       /*
-        * Hmm...  IRIX sets additional bits in the address which
-        * are documented as reserved in the bridge docs.
-        */
-       bridge_write(bc, b_wid_int_upper, 0x8000 | (masterwid << 16));
-       bridge_write(bc, b_wid_int_lower, 0x01800090); /* PI_INT_PEND_MOD off*/
-       bridge_write(bc, b_dir_map, (masterwid << 20)); /* DMA */
-       bridge_write(bc, b_int_enable, 0);
-
-       for (slot = 0; slot < 8; slot ++) {
-               bridge_set(bc, b_device[slot].reg, BRIDGE_DEV_SWAP_DIR);
-               bc->pci_int[slot] = -1;
-       }
-       bridge_read(bc, b_wid_tflush);    /* wait until Bridge PIO complete */
-
-       register_pci_controller(&bc->pc);
-
-       num_bridges++;
-
-       return 0;
-}
-
-/*
- * All observed requests have pin == 1. We could have a global here, that
- * gets incremented and returned every time - unfortunately, pci_map_irq
- * may be called on the same device over and over, and need to return the
- * same value. On O2000, pin can be 0 or 1, and PCI slots can be [0..7].
- *
- * A given PCI device, in general, should be able to intr any of the cpus
- * on any one of the hubs connected to its xbow.
- */
-int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
-       return 0;
-}
-
-static inline struct pci_dev *bridge_root_dev(struct pci_dev *dev)
-{
-       while (dev->bus->parent) {
-               /* Move up the chain of bridges. */
-               dev = dev->bus->self;
-       }
-
-       return dev;
-}
-
-/* Do platform specific device initialization at pci_enable_device() time */
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
-       struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
-       struct pci_dev *rdev = bridge_root_dev(dev);
-       int slot = PCI_SLOT(rdev->devfn);
-       int irq;
-
-       irq = bc->pci_int[slot];
-       if (irq == -1) {
-               irq = request_bridge_irq(bc, slot);
-               if (irq < 0)
-                       return irq;
-
-               bc->pci_int[slot] = irq;
-       }
-       dev->irq = irq;
-
-       return 0;
-}
 
 dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
 {
@@ -177,29 +22,6 @@ phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t dma_addr)
        return dma_addr & ~(0xffUL << 56);
 }
 
-/*
- * Device might live on a subordinate PCI bus. XXX Walk up the chain of buses
- * to find the slot number in sense of the bridge device register.
- * XXX This also means multiple devices might rely on conflicting bridge
- * settings.
- */
-
-static inline void pci_disable_swapping(struct pci_dev *dev)
-{
-       struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
-       struct bridge_regs *bridge = bc->base;
-       int slot = PCI_SLOT(dev->devfn);
-
-       /* Turn off byte swapping */
-       bridge->b_device[slot].reg &= ~BRIDGE_DEV_SWAP_DIR;
-       bridge->b_widget.w_tflush;      /* Flush */
-}
-
-static void pci_fixup_ioc3(struct pci_dev *d)
-{
-       pci_disable_swapping(d);
-}
-
 #ifdef CONFIG_NUMA
 int pcibus_to_node(struct pci_bus *bus)
 {
@@ -209,6 +31,3 @@ int pcibus_to_node(struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pcibus_to_node);
 #endif /* CONFIG_NUMA */
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
-       pci_fixup_ioc3);
diff --git a/arch/mips/pci/pci-xtalk-bridge.c b/arch/mips/pci/pci-xtalk-bridge.c
new file mode 100644 (file)
index 0000000..bcf7f55
--- /dev/null
@@ -0,0 +1,610 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2003 Christoph Hellwig (hch@lst.de)
+ * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/pci.h>
+#include <linux/smp.h>
+#include <linux/dma-direct.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/xtalk-bridge.h>
+
+#include <asm/pci/bridge.h>
+#include <asm/paccess.h>
+#include <asm/sn/irq_alloc.h>
+
+/*
+ * Most of the IOC3 PCI config register aren't present
+ * we emulate what is needed for a normal PCI enumeration
+ */
+static u32 emulate_ioc3_cfg(int where, int size)
+{
+       if (size == 1 && where == 0x3d)
+               return 0x01;
+       else if (size == 2 && where == 0x3c)
+               return 0x0100;
+       else if (size == 4 && where == 0x3c)
+               return 0x00000100;
+
+       return 0;
+}
+
+static void bridge_disable_swapping(struct pci_dev *dev)
+{
+       struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
+       int slot = PCI_SLOT(dev->devfn);
+
+       /* Turn off byte swapping */
+       bridge_clr(bc, b_device[slot].reg, BRIDGE_DEV_SWAP_DIR);
+       bridge_read(bc, b_widget.w_tflush);     /* Flush */
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+       bridge_disable_swapping);
+
+
+/*
+ * The Bridge ASIC supports both type 0 and type 1 access.  Type 1 is
+ * not really documented, so right now I can't write code which uses it.
+ * Therefore we use type 0 accesses for now even though they won't work
+ * correctly for PCI-to-PCI bridges.
+ *
+ * The function is complicated by the ultimate brokenness of the IOC3 chip
+ * which is used in SGI systems.  The IOC3 can only handle 32-bit PCI
+ * accesses and does only decode parts of it's address space.
+ */
+static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
+                                int where, int size, u32 *value)
+{
+       struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+       struct bridge_regs *bridge = bc->base;
+       int slot = PCI_SLOT(devfn);
+       int fn = PCI_FUNC(devfn);
+       void *addr;
+       u32 cf, shift, mask;
+       int res;
+
+       addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID];
+       if (get_dbe(cf, (u32 *)addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       /*
+        * IOC3 is broken beyond belief ...  Don't even give the
+        * generic PCI code a chance to look at it for real ...
+        */
+       if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
+               goto is_ioc3;
+
+       addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
+
+       if (size == 1)
+               res = get_dbe(*value, (u8 *)addr);
+       else if (size == 2)
+               res = get_dbe(*value, (u16 *)addr);
+       else
+               res = get_dbe(*value, (u32 *)addr);
+
+       return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+
+is_ioc3:
+
+       /*
+        * IOC3 special handling
+        */
+       if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) {
+               *value = emulate_ioc3_cfg(where, size);
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
+       if (get_dbe(cf, (u32 *)addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       shift = ((where & 3) << 3);
+       mask = (0xffffffffU >> ((4 - size) << 3));
+       *value = (cf >> shift) & mask;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
+                                int where, int size, u32 *value)
+{
+       struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+       struct bridge_regs *bridge = bc->base;
+       int busno = bus->number;
+       int slot = PCI_SLOT(devfn);
+       int fn = PCI_FUNC(devfn);
+       void *addr;
+       u32 cf, shift, mask;
+       int res;
+
+       bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
+       addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
+       if (get_dbe(cf, (u32 *)addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       /*
+        * IOC3 is broken beyond belief ...  Don't even give the
+        * generic PCI code a chance to look at it for real ...
+        */
+       if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
+               goto is_ioc3;
+
+       addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
+
+       if (size == 1)
+               res = get_dbe(*value, (u8 *)addr);
+       else if (size == 2)
+               res = get_dbe(*value, (u16 *)addr);
+       else
+               res = get_dbe(*value, (u32 *)addr);
+
+       return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+
+is_ioc3:
+
+       /*
+        * IOC3 special handling
+        */
+       if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) {
+               *value = emulate_ioc3_cfg(where, size);
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       addr = &bridge->b_type1_cfg.c[(fn << 8) | where];
+       if (get_dbe(cf, (u32 *)addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       shift = ((where & 3) << 3);
+       mask = (0xffffffffU >> ((4 - size) << 3));
+       *value = (cf >> shift) & mask;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_read_config(struct pci_bus *bus, unsigned int devfn,
+                          int where, int size, u32 *value)
+{
+       if (!pci_is_root_bus(bus))
+               return pci_conf1_read_config(bus, devfn, where, size, value);
+
+       return pci_conf0_read_config(bus, devfn, where, size, value);
+}
+
+static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
+                                 int where, int size, u32 value)
+{
+       struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+       struct bridge_regs *bridge = bc->base;
+       int slot = PCI_SLOT(devfn);
+       int fn = PCI_FUNC(devfn);
+       void *addr;
+       u32 cf, shift, mask, smask;
+       int res;
+
+       addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID];
+       if (get_dbe(cf, (u32 *)addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       /*
+        * IOC3 is broken beyond belief ...  Don't even give the
+        * generic PCI code a chance to look at it for real ...
+        */
+       if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
+               goto is_ioc3;
+
+       addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
+
+       if (size == 1)
+               res = put_dbe(value, (u8 *)addr);
+       else if (size == 2)
+               res = put_dbe(value, (u16 *)addr);
+       else
+               res = put_dbe(value, (u32 *)addr);
+
+       if (res)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       return PCIBIOS_SUCCESSFUL;
+
+is_ioc3:
+
+       /*
+        * IOC3 special handling
+        */
+       if ((where >= 0x14 && where < 0x40) || (where >= 0x48))
+               return PCIBIOS_SUCCESSFUL;
+
+       addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
+
+       if (get_dbe(cf, (u32 *)addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       shift = ((where & 3) << 3);
+       mask = (0xffffffffU >> ((4 - size) << 3));
+       smask = mask << shift;
+
+       cf = (cf & ~smask) | ((value & mask) << shift);
+       if (put_dbe(cf, (u32 *)addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
+                                 int where, int size, u32 value)
+{
+       struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+       struct bridge_regs *bridge = bc->base;
+       int slot = PCI_SLOT(devfn);
+       int fn = PCI_FUNC(devfn);
+       int busno = bus->number;
+       void *addr;
+       u32 cf, shift, mask, smask;
+       int res;
+
+       bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
+       addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
+       if (get_dbe(cf, (u32 *)addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       /*
+        * IOC3 is broken beyond belief ...  Don't even give the
+        * generic PCI code a chance to look at it for real ...
+        */
+       if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
+               goto is_ioc3;
+
+       addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
+
+       if (size == 1)
+               res = put_dbe(value, (u8 *)addr);
+       else if (size == 2)
+               res = put_dbe(value, (u16 *)addr);
+       else
+               res = put_dbe(value, (u32 *)addr);
+
+       if (res)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       return PCIBIOS_SUCCESSFUL;
+
+is_ioc3:
+
+       /*
+        * IOC3 special handling
+        */
+       if ((where >= 0x14 && where < 0x40) || (where >= 0x48))
+               return PCIBIOS_SUCCESSFUL;
+
+       addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
+       if (get_dbe(cf, (u32 *)addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       shift = ((where & 3) << 3);
+       mask = (0xffffffffU >> ((4 - size) << 3));
+       smask = mask << shift;
+
+       cf = (cf & ~smask) | ((value & mask) << shift);
+       if (put_dbe(cf, (u32 *)addr))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_write_config(struct pci_bus *bus, unsigned int devfn,
+       int where, int size, u32 value)
+{
+       if (!pci_is_root_bus(bus))
+               return pci_conf1_write_config(bus, devfn, where, size, value);
+
+       return pci_conf0_write_config(bus, devfn, where, size, value);
+}
+
+static struct pci_ops bridge_pci_ops = {
+       .read    = pci_read_config,
+       .write   = pci_write_config,
+};
+
+struct bridge_irq_chip_data {
+       struct bridge_controller *bc;
+       nasid_t nasid;
+};
+
+static int bridge_set_affinity(struct irq_data *d, const struct cpumask *mask,
+                              bool force)
+{
+#ifdef CONFIG_NUMA
+       struct bridge_irq_chip_data *data = d->chip_data;
+       int bit = d->parent_data->hwirq;
+       int pin = d->hwirq;
+       nasid_t nasid;
+       int ret, cpu;
+
+       ret = irq_chip_set_affinity_parent(d, mask, force);
+       if (ret >= 0) {
+               cpu = cpumask_first_and(mask, cpu_online_mask);
+               nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
+               bridge_write(data->bc, b_int_addr[pin].addr,
+                            (((data->bc->intr_addr >> 30) & 0x30000) |
+                             bit | (nasid << 8)));
+               bridge_read(data->bc, b_wid_tflush);
+       }
+       return ret;
+#else
+       return irq_chip_set_affinity_parent(d, mask, force);
+#endif
+}
+
+struct irq_chip bridge_irq_chip = {
+       .name             = "BRIDGE",
+       .irq_mask         = irq_chip_mask_parent,
+       .irq_unmask       = irq_chip_unmask_parent,
+       .irq_set_affinity = bridge_set_affinity
+};
+
+static int bridge_domain_alloc(struct irq_domain *domain, unsigned int virq,
+                              unsigned int nr_irqs, void *arg)
+{
+       struct bridge_irq_chip_data *data;
+       struct irq_alloc_info *info = arg;
+       int ret;
+
+       if (nr_irqs > 1 || !info)
+               return -EINVAL;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+       if (ret >= 0) {
+               data->bc = info->ctrl;
+               data->nasid = info->nasid;
+               irq_domain_set_info(domain, virq, info->pin, &bridge_irq_chip,
+                                   data, handle_level_irq, NULL, NULL);
+       } else {
+               kfree(data);
+       }
+
+       return ret;
+}
+
+static void bridge_domain_free(struct irq_domain *domain, unsigned int virq,
+                              unsigned int nr_irqs)
+{
+       struct irq_data *irqd = irq_domain_get_irq_data(domain, virq);
+
+       if (nr_irqs)
+               return;
+
+       kfree(irqd->chip_data);
+       irq_domain_free_irqs_top(domain, virq, nr_irqs);
+}
+
+static int bridge_domain_activate(struct irq_domain *domain,
+                                 struct irq_data *irqd, bool reserve)
+{
+       struct bridge_irq_chip_data *data = irqd->chip_data;
+       struct bridge_controller *bc = data->bc;
+       int bit = irqd->parent_data->hwirq;
+       int pin = irqd->hwirq;
+       u32 device;
+
+       bridge_write(bc, b_int_addr[pin].addr,
+                    (((bc->intr_addr >> 30) & 0x30000) |
+                     bit | (data->nasid << 8)));
+       bridge_set(bc, b_int_enable, (1 << pin));
+       bridge_set(bc, b_int_enable, 0x7ffffe00); /* more stuff in int_enable */
+
+       /*
+        * Enable sending of an interrupt clear packt to the hub on a high to
+        * low transition of the interrupt pin.
+        *
+        * IRIX sets additional bits in the address which are documented as
+        * reserved in the bridge docs.
+        */
+       bridge_set(bc, b_int_mode, (1UL << pin));
+
+       /*
+        * We assume the bridge to have a 1:1 mapping between devices
+        * (slots) and intr pins.
+        */
+       device = bridge_read(bc, b_int_device);
+       device &= ~(7 << (pin*3));
+       device |= (pin << (pin*3));
+       bridge_write(bc, b_int_device, device);
+
+       bridge_read(bc, b_wid_tflush);
+       return 0;
+}
+
+static void bridge_domain_deactivate(struct irq_domain *domain,
+                                    struct irq_data *irqd)
+{
+       struct bridge_irq_chip_data *data = irqd->chip_data;
+
+       bridge_clr(data->bc, b_int_enable, (1 << irqd->hwirq));
+       bridge_read(data->bc, b_wid_tflush);
+}
+
+static const struct irq_domain_ops bridge_domain_ops = {
+       .alloc      = bridge_domain_alloc,
+       .free       = bridge_domain_free,
+       .activate   = bridge_domain_activate,
+       .deactivate = bridge_domain_deactivate
+};
+
+/*
+ * All observed requests have pin == 1. We could have a global here, that
+ * gets incremented and returned every time - unfortunately, pci_map_irq
+ * may be called on the same device over and over, and need to return the
+ * same value. On O2000, pin can be 0 or 1, and PCI slots can be [0..7].
+ *
+ * A given PCI device, in general, should be able to intr any of the cpus
+ * on any one of the hubs connected to its xbow.
+ */
+static int bridge_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+       struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
+       struct irq_alloc_info info;
+       int irq;
+
+       irq = bc->pci_int[slot];
+       if (irq == -1) {
+               info.ctrl = bc;
+               info.nasid = bc->nasid;
+               info.pin = slot;
+
+               irq = irq_domain_alloc_irqs(bc->domain, 1, bc->nasid, &info);
+               if (irq < 0)
+                       return irq;
+
+               bc->pci_int[slot] = irq;
+       }
+       return irq;
+}
+
+static int bridge_probe(struct platform_device *pdev)
+{
+       struct xtalk_bridge_platform_data *bd = dev_get_platdata(&pdev->dev);
+       struct device *dev = &pdev->dev;
+       struct bridge_controller *bc;
+       struct pci_host_bridge *host;
+       struct irq_domain *domain, *parent;
+       struct fwnode_handle *fn;
+       int slot;
+       int err;
+
+       parent = irq_get_default_host();
+       if (!parent)
+               return -ENODEV;
+       fn = irq_domain_alloc_named_fwnode("BRIDGE");
+       if (!fn)
+               return -ENOMEM;
+       domain = irq_domain_create_hierarchy(parent, 0, 8, fn,
+                                            &bridge_domain_ops, NULL);
+       irq_domain_free_fwnode(fn);
+       if (!domain)
+               return -ENOMEM;
+
+       pci_set_flags(PCI_PROBE_ONLY);
+
+       host = devm_pci_alloc_host_bridge(dev, sizeof(*bc));
+       if (!host) {
+               err = -ENOMEM;
+               goto err_remove_domain;
+       }
+
+       bc = pci_host_bridge_priv(host);
+
+       bc->busn.name           = "Bridge PCI busn";
+       bc->busn.start          = 0;
+       bc->busn.end            = 0xff;
+       bc->busn.flags          = IORESOURCE_BUS;
+
+       bc->domain              = domain;
+
+       pci_add_resource_offset(&host->windows, &bd->mem, bd->mem_offset);
+       pci_add_resource_offset(&host->windows, &bd->io, bd->io_offset);
+       pci_add_resource(&host->windows, &bc->busn);
+
+       err = devm_request_pci_bus_resources(dev, &host->windows);
+       if (err < 0)
+               goto err_free_resource;
+
+       bc->nasid = bd->nasid;
+
+       bc->baddr = (u64)bd->masterwid << 60 | PCI64_ATTR_BAR;
+       bc->base = (struct bridge_regs *)bd->bridge_addr;
+       bc->intr_addr = bd->intr_addr;
+
+       /*
+        * Clear all pending interrupts.
+        */
+       bridge_write(bc, b_int_rst_stat, BRIDGE_IRR_ALL_CLR);
+
+       /*
+        * Until otherwise set up, assume all interrupts are from slot 0
+        */
+       bridge_write(bc, b_int_device, 0x0);
+
+       /*
+        * disable swapping for big windows
+        */
+       bridge_clr(bc, b_wid_control,
+                  BRIDGE_CTRL_IO_SWAP | BRIDGE_CTRL_MEM_SWAP);
+#ifdef CONFIG_PAGE_SIZE_4KB
+       bridge_clr(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
+#else /* 16kB or larger */
+       bridge_set(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
+#endif
+
+       /*
+        * Hmm...  IRIX sets additional bits in the address which
+        * are documented as reserved in the bridge docs.
+        */
+       bridge_write(bc, b_wid_int_upper,
+                    ((bc->intr_addr >> 32) & 0xffff) | (bd->masterwid << 16));
+       bridge_write(bc, b_wid_int_lower, bc->intr_addr & 0xffffffff);
+       bridge_write(bc, b_dir_map, (bd->masterwid << 20));     /* DMA */
+       bridge_write(bc, b_int_enable, 0);
+
+       for (slot = 0; slot < 8; slot++) {
+               bridge_set(bc, b_device[slot].reg, BRIDGE_DEV_SWAP_DIR);
+               bc->pci_int[slot] = -1;
+       }
+       bridge_read(bc, b_wid_tflush);    /* wait until Bridge PIO complete */
+
+       host->dev.parent = dev;
+       host->sysdata = bc;
+       host->busnr = 0;
+       host->ops = &bridge_pci_ops;
+       host->map_irq = bridge_map_irq;
+       host->swizzle_irq = pci_common_swizzle;
+
+       err = pci_scan_root_bus_bridge(host);
+       if (err < 0)
+               goto err_free_resource;
+
+       pci_bus_claim_resources(host->bus);
+       pci_bus_add_devices(host->bus);
+
+       platform_set_drvdata(pdev, host->bus);
+
+       return 0;
+
+err_free_resource:
+       pci_free_resource_list(&host->windows);
+err_remove_domain:
+       irq_domain_remove(domain);
+       return err;
+}
+
+static int bridge_remove(struct platform_device *pdev)
+{
+       struct pci_bus *bus = platform_get_drvdata(pdev);
+       struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
+
+       irq_domain_remove(bc->domain);
+       pci_lock_rescan_remove();
+       pci_stop_root_bus(bus);
+       pci_remove_root_bus(bus);
+       pci_unlock_rescan_remove();
+
+       return 0;
+}
+
+static struct platform_driver bridge_driver = {
+       .probe  = bridge_probe,
+       .remove = bridge_remove,
+       .driver = {
+               .name = "xtalk-bridge",
+       }
+};
+
+builtin_platform_driver(bridge_driver);
index 37ad267165790bde93b11d7b4ce2a7f548399fb9..0b2002e02a47735b92727de6a785c0bef704f1b5 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/if_ether.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/paccess.h>
 #include <asm/sgi/ip22.h>
@@ -25,6 +26,8 @@ static struct sgiwd93_platform_data sgiwd93_0_pd = {
        .irq    = SGI_WD93_0_IRQ,
 };
 
+static u64 sgiwd93_0_dma_mask = DMA_BIT_MASK(32);
+
 static struct platform_device sgiwd93_0_device = {
        .name           = "sgiwd93",
        .id             = 0,
@@ -32,6 +35,8 @@ static struct platform_device sgiwd93_0_device = {
        .resource       = sgiwd93_0_resources,
        .dev = {
                .platform_data = &sgiwd93_0_pd,
+               .dma_mask = &sgiwd93_0_dma_mask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
        },
 };
 
@@ -49,6 +54,8 @@ static struct sgiwd93_platform_data sgiwd93_1_pd = {
        .irq    = SGI_WD93_1_IRQ,
 };
 
+static u64 sgiwd93_1_dma_mask = DMA_BIT_MASK(32);
+
 static struct platform_device sgiwd93_1_device = {
        .name           = "sgiwd93",
        .id             = 1,
@@ -56,6 +63,8 @@ static struct platform_device sgiwd93_1_device = {
        .resource       = sgiwd93_1_resources,
        .dev = {
                .platform_data = &sgiwd93_1_pd,
+               .dma_mask = &sgiwd93_1_dma_mask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
        },
 };
 
@@ -96,6 +105,8 @@ static struct resource sgiseeq_0_resources[] = {
 
 static struct sgiseeq_platform_data eth0_pd;
 
+static u64 sgiseeq_dma_mask = DMA_BIT_MASK(32);
+
 static struct platform_device eth0_device = {
        .name           = "sgiseeq",
        .id             = 0,
@@ -103,6 +114,8 @@ static struct platform_device eth0_device = {
        .resource       = sgiseeq_0_resources,
        .dev = {
                .platform_data = &eth0_pd,
+               .dma_mask = &sgiseeq_dma_mask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
        },
 };
 
index 6074efeff894f7f24b91c3b9f9c2d174481c7499..066b33f50bcc4da9649360d2654c80e7a0da5e72 100644 (file)
@@ -184,5 +184,7 @@ void __init plat_mem_setup(void)
 
        ioc3_eth_init();
 
+       ioport_resource.start = 0;
+       ioport_resource.end = ~0UL;
        set_io_port_base(IO_BASE);
 }
index a32f843cdbe02299e34bf7f0897ad61f6e23dce5..37be04975831e34c13fb22b47d73c76207806f33 100644 (file)
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/bitops.h>
+#include <linux/sched.h>
 
 #include <asm/io.h>
 #include <asm/irq_cpu.h>
-#include <asm/pci/bridge.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/agent.h>
 #include <asm/sn/arch.h>
 #include <asm/sn/hub.h>
 #include <asm/sn/intr.h>
+#include <asm/sn/irq_alloc.h>
 
 struct hub_irq_data {
-       struct bridge_controller *bc;
        u64     *irq_mask[2];
        cpuid_t cpu;
-       int     bit;
-       int     pin;
 };
 
 static DECLARE_BITMAP(hub_irq_map, IP27_HUB_IRQ_COUNT);
@@ -54,7 +52,7 @@ static void enable_hub_irq(struct irq_data *d)
        struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
        unsigned long *mask = per_cpu(irq_enable_mask, hd->cpu);
 
-       set_bit(hd->bit, mask);
+       set_bit(d->hwirq, mask);
        __raw_writeq(mask[0], hd->irq_mask[0]);
        __raw_writeq(mask[1], hd->irq_mask[1]);
 }
@@ -64,71 +62,11 @@ static void disable_hub_irq(struct irq_data *d)
        struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
        unsigned long *mask = per_cpu(irq_enable_mask, hd->cpu);
 
-       clear_bit(hd->bit, mask);
+       clear_bit(d->hwirq, mask);
        __raw_writeq(mask[0], hd->irq_mask[0]);
        __raw_writeq(mask[1], hd->irq_mask[1]);
 }
 
-static unsigned int startup_bridge_irq(struct irq_data *d)
-{
-       struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
-       struct bridge_controller *bc;
-       nasid_t nasid;
-       u32 device;
-       int pin;
-
-       if (!hd)
-               return -EINVAL;
-
-       pin = hd->pin;
-       bc = hd->bc;
-
-       nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(hd->cpu));
-       bridge_write(bc, b_int_addr[pin].addr,
-                    (0x20000 | hd->bit | (nasid << 8)));
-       bridge_set(bc, b_int_enable, (1 << pin));
-       bridge_set(bc, b_int_enable, 0x7ffffe00); /* more stuff in int_enable */
-
-       /*
-        * Enable sending of an interrupt clear packt to the hub on a high to
-        * low transition of the interrupt pin.
-        *
-        * IRIX sets additional bits in the address which are documented as
-        * reserved in the bridge docs.
-        */
-       bridge_set(bc, b_int_mode, (1UL << pin));
-
-       /*
-        * We assume the bridge to have a 1:1 mapping between devices
-        * (slots) and intr pins.
-        */
-       device = bridge_read(bc, b_int_device);
-       device &= ~(7 << (pin*3));
-       device |= (pin << (pin*3));
-       bridge_write(bc, b_int_device, device);
-
-       bridge_read(bc, b_wid_tflush);
-
-       enable_hub_irq(d);
-
-       return 0;       /* Never anything pending.  */
-}
-
-static void shutdown_bridge_irq(struct irq_data *d)
-{
-       struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
-       struct bridge_controller *bc;
-
-       if (!hd)
-               return;
-
-       disable_hub_irq(d);
-
-       bc = hd->bc;
-       bridge_clr(bc, b_int_enable, (1 << hd->pin));
-       bridge_read(bc, b_wid_tflush);
-}
-
 static void setup_hub_mask(struct hub_irq_data *hd, const struct cpumask *mask)
 {
        nasid_t nasid;
@@ -144,9 +82,6 @@ static void setup_hub_mask(struct hub_irq_data *hd, const struct cpumask *mask)
                hd->irq_mask[0] = REMOTE_HUB_PTR(nasid, PI_INT_MASK0_B);
                hd->irq_mask[1] = REMOTE_HUB_PTR(nasid, PI_INT_MASK1_B);
        }
-
-       /* Make sure it's not already pending when we connect it. */
-       REMOTE_HUB_CLR_INTR(nasid, hd->bit);
 }
 
 static int set_affinity_hub_irq(struct irq_data *d, const struct cpumask *mask,
@@ -163,7 +98,7 @@ static int set_affinity_hub_irq(struct irq_data *d, const struct cpumask *mask,
        setup_hub_mask(hd, mask);
 
        if (irqd_is_started(d))
-               startup_bridge_irq(d);
+               enable_hub_irq(d);
 
        irq_data_update_effective_affinity(d, cpumask_of(hd->cpu));
 
@@ -172,20 +107,22 @@ static int set_affinity_hub_irq(struct irq_data *d, const struct cpumask *mask,
 
 static struct irq_chip hub_irq_type = {
        .name             = "HUB",
-       .irq_startup      = startup_bridge_irq,
-       .irq_shutdown     = shutdown_bridge_irq,
        .irq_mask         = disable_hub_irq,
        .irq_unmask       = enable_hub_irq,
        .irq_set_affinity = set_affinity_hub_irq,
 };
 
-int request_bridge_irq(struct bridge_controller *bc, int pin)
+static int hub_domain_alloc(struct irq_domain *domain, unsigned int virq,
+                           unsigned int nr_irqs, void *arg)
 {
+       struct irq_alloc_info *info = arg;
        struct hub_irq_data *hd;
        struct hub_data *hub;
        struct irq_desc *desc;
        int swlevel;
-       int irq;
+
+       if (nr_irqs > 1 || !info)
+               return -EINVAL;
 
        hd = kzalloc(sizeof(*hd), GFP_KERNEL);
        if (!hd)
@@ -196,46 +133,41 @@ int request_bridge_irq(struct bridge_controller *bc, int pin)
                kfree(hd);
                return -EAGAIN;
        }
-       irq = swlevel + IP27_HUB_IRQ_BASE;
-
-       hd->bc = bc;
-       hd->bit = swlevel;
-       hd->pin = pin;
-       irq_set_chip_data(irq, hd);
+       irq_domain_set_info(domain, virq, swlevel, &hub_irq_type, hd,
+                           handle_level_irq, NULL, NULL);
 
        /* use CPU connected to nearest hub */
-       hub = hub_data(NASID_TO_COMPACT_NODEID(bc->nasid));
+       hub = hub_data(NASID_TO_COMPACT_NODEID(info->nasid));
        setup_hub_mask(hd, &hub->h_cpus);
 
-       desc = irq_to_desc(irq);
-       desc->irq_common_data.node = bc->nasid;
+       /* Make sure it's not already pending when we connect it. */
+       REMOTE_HUB_CLR_INTR(info->nasid, swlevel);
+
+       desc = irq_to_desc(virq);
+       desc->irq_common_data.node = info->nasid;
        cpumask_copy(desc->irq_common_data.affinity, &hub->h_cpus);
 
-       return irq;
+       return 0;
 }
 
-void ip27_hub_irq_init(void)
+static void hub_domain_free(struct irq_domain *domain,
+                           unsigned int virq, unsigned int nr_irqs)
 {
-       int i;
+       struct irq_data *irqd;
 
-       for (i = IP27_HUB_IRQ_BASE;
-            i < (IP27_HUB_IRQ_BASE + IP27_HUB_IRQ_COUNT); i++)
-               irq_set_chip_and_handler(i, &hub_irq_type, handle_level_irq);
-
-       /*
-        * Some interrupts are reserved by hardware or by software convention.
-        * Mark these as reserved right away so they won't be used accidentally
-        * later.
-        */
-       for (i = 0; i <= BASE_PCI_IRQ; i++)
-               set_bit(i, hub_irq_map);
-
-       set_bit(IP_PEND0_6_63, hub_irq_map);
+       if (nr_irqs > 1)
+               return;
 
-       for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++)
-               set_bit(i, hub_irq_map);
+       irqd = irq_domain_get_irq_data(domain, virq);
+       if (irqd && irqd->chip_data)
+               kfree(irqd->chip_data);
 }
 
+static const struct irq_domain_ops hub_domain_ops = {
+       .alloc = hub_domain_alloc,
+       .free  = hub_domain_free,
+};
+
 /*
  * This code is unnecessarily complex, because we do
  * intr enabling. Basically, once we grab the set of intrs we need
@@ -252,7 +184,9 @@ static void ip27_do_irq_mask0(struct irq_desc *desc)
 {
        cpuid_t cpu = smp_processor_id();
        unsigned long *mask = per_cpu(irq_enable_mask, cpu);
+       struct irq_domain *domain;
        u64 pend0;
+       int irq;
 
        /* copied from Irix intpend0() */
        pend0 = LOCAL_HUB_L(PI_INT_PEND0);
@@ -276,7 +210,14 @@ static void ip27_do_irq_mask0(struct irq_desc *desc)
                generic_smp_call_function_interrupt();
        } else
 #endif
-               generic_handle_irq(__ffs(pend0) + IP27_HUB_IRQ_BASE);
+       {
+               domain = irq_desc_get_handler_data(desc);
+               irq = irq_linear_revmap(domain, __ffs(pend0));
+               if (irq)
+                       generic_handle_irq(irq);
+               else
+                       spurious_interrupt();
+       }
 
        LOCAL_HUB_L(PI_INT_PEND0);
 }
@@ -285,7 +226,9 @@ static void ip27_do_irq_mask1(struct irq_desc *desc)
 {
        cpuid_t cpu = smp_processor_id();
        unsigned long *mask = per_cpu(irq_enable_mask, cpu);
+       struct irq_domain *domain;
        u64 pend1;
+       int irq;
 
        /* copied from Irix intpend0() */
        pend1 = LOCAL_HUB_L(PI_INT_PEND1);
@@ -294,7 +237,12 @@ static void ip27_do_irq_mask1(struct irq_desc *desc)
        if (!pend1)
                return;
 
-       generic_handle_irq(__ffs(pend1) + IP27_HUB_IRQ_BASE + 64);
+       domain = irq_desc_get_handler_data(desc);
+       irq = irq_linear_revmap(domain, __ffs(pend1) + 64);
+       if (irq)
+               generic_handle_irq(irq);
+       else
+               spurious_interrupt();
 
        LOCAL_HUB_L(PI_INT_PEND1);
 }
@@ -325,11 +273,41 @@ void install_ipi(void)
 
 void __init arch_init_irq(void)
 {
+       struct irq_domain *domain;
+       struct fwnode_handle *fn;
+       int i;
+
        mips_cpu_irq_init();
-       ip27_hub_irq_init();
+
+       /*
+        * Some interrupts are reserved by hardware or by software convention.
+        * Mark these as reserved right away so they won't be used accidentally
+        * later.
+        */
+       for (i = 0; i <= BASE_PCI_IRQ; i++)
+               set_bit(i, hub_irq_map);
+
+       set_bit(IP_PEND0_6_63, hub_irq_map);
+
+       for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++)
+               set_bit(i, hub_irq_map);
+
+       fn = irq_domain_alloc_named_fwnode("HUB");
+       WARN_ON(fn == NULL);
+       if (!fn)
+               return;
+       domain = irq_domain_create_linear(fn, IP27_HUB_IRQ_COUNT,
+                                         &hub_domain_ops, NULL);
+       WARN_ON(domain == NULL);
+       if (!domain)
+               return;
+
+       irq_set_default_host(domain);
 
        irq_set_percpu_devid(IP27_HUB_PEND0_IRQ);
-       irq_set_chained_handler(IP27_HUB_PEND0_IRQ, ip27_do_irq_mask0);
+       irq_set_chained_handler_and_data(IP27_HUB_PEND0_IRQ, ip27_do_irq_mask0,
+                                        domain);
        irq_set_percpu_devid(IP27_HUB_PEND1_IRQ);
-       irq_set_chained_handler(IP27_HUB_PEND1_IRQ, ip27_do_irq_mask1);
+       irq_set_chained_handler_and_data(IP27_HUB_PEND1_IRQ, ip27_do_irq_mask1,
+                                        domain);
 }
index ce06aaa115ae33c70538e608196ee956bec01ebd..bd5cb855c6e521f352fe1f2101a4b1f913f891c3 100644 (file)
@@ -9,6 +9,9 @@
 
 #include <linux/kernel.h>
 #include <linux/smp.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/xtalk-bridge.h>
+#include <asm/sn/addrs.h>
 #include <asm/sn/types.h>
 #include <asm/sn/klconfig.h>
 #include <asm/sn/hub.h>
 #define XXBOW_WIDGET_PART_NUM  0xd000  /* Xbow in Xbridge */
 #define BASE_XBOW_PORT         8     /* Lowest external port */
 
-extern int bridge_probe(nasid_t nasid, int widget, int masterwid);
+static void bridge_platform_create(nasid_t nasid, int widget, int masterwid)
+{
+       struct xtalk_bridge_platform_data *bd;
+       struct platform_device *pdev;
+       unsigned long offset;
+
+       bd = kzalloc(sizeof(*bd), GFP_KERNEL);
+       if (!bd)
+               goto no_mem;
+       pdev = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
+       if (!pdev) {
+               kfree(bd);
+               goto no_mem;
+       }
+
+       offset = NODE_OFFSET(nasid);
+
+       bd->bridge_addr = RAW_NODE_SWIN_BASE(nasid, widget);
+       bd->intr_addr   = BIT_ULL(47) + 0x01800000 + PI_INT_PEND_MOD;
+       bd->nasid       = nasid;
+       bd->masterwid   = masterwid;
+
+       bd->mem.name    = "Bridge PCI MEM";
+       bd->mem.start   = offset + (widget << SWIN_SIZE_BITS);
+       bd->mem.end     = bd->mem.start + SWIN_SIZE - 1;
+       bd->mem.flags   = IORESOURCE_MEM;
+       bd->mem_offset  = offset;
+
+       bd->io.name     = "Bridge PCI IO";
+       bd->io.start    = offset + (widget << SWIN_SIZE_BITS);
+       bd->io.end      = bd->io.start + SWIN_SIZE - 1;
+       bd->io.flags    = IORESOURCE_IO;
+       bd->io_offset   = offset;
+
+       platform_device_add_data(pdev, bd, sizeof(*bd));
+       platform_device_add(pdev);
+       pr_info("xtalk:n%d/%x bridge widget\n", nasid, widget);
+       return;
+
+no_mem:
+       pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget);
+}
 
 static int probe_one_port(nasid_t nasid, int widget, int masterwid)
 {
@@ -31,13 +75,10 @@ static int probe_one_port(nasid_t nasid, int widget, int masterwid)
                (RAW_NODE_SWIN_BASE(nasid, widget) + WIDGET_ID);
        partnum = XWIDGET_PART_NUM(widget_id);
 
-       printk(KERN_INFO "Cpu %d, Nasid 0x%x, widget 0x%x (partnum 0x%x) is ",
-                       smp_processor_id(), nasid, widget, partnum);
-
        switch (partnum) {
        case BRIDGE_WIDGET_PART_NUM:
        case XBRIDGE_WIDGET_PART_NUM:
-               bridge_probe(nasid, widget, masterwid);
+               bridge_platform_create(nasid, widget, masterwid);
                break;
        default:
                break;
@@ -52,8 +93,6 @@ static int xbow_probe(nasid_t nasid)
        klxbow_t *xbow_p;
        unsigned masterwid, i;
 
-       printk("is xbow\n");
-
        /*
         * found xbow, so may have multiple bridges
         * need to probe xbow
@@ -117,19 +156,17 @@ static void xtalk_probe_node(cnodeid_t nid)
                       (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
        partnum = XWIDGET_PART_NUM(widget_id);
 
-       printk(KERN_INFO "Cpu %d, Nasid 0x%x: partnum 0x%x is ",
-                       smp_processor_id(), nasid, partnum);
-
        switch (partnum) {
        case BRIDGE_WIDGET_PART_NUM:
-               bridge_probe(nasid, 0x8, 0xa);
+               bridge_platform_create(nasid, 0x8, 0xa);
                break;
        case XBOW_WIDGET_PART_NUM:
        case XXBOW_WIDGET_PART_NUM:
+               pr_info("xtalk:n%d/0 xbow widget\n", nasid);
                xbow_probe(nasid);
                break;
        default:
-               printk(" unknown widget??\n");
+               pr_info("xtalk:n%d/0 unknown widget (0x%x)\n", nasid, partnum);
                break;
        }
 }
index 70a1ab66d252c15f4c305d5901dee16b669f9320..46537c2ca86a2eae46f8da5bf920e507f4fe7504 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/leds.h>
 #include <linux/device.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <linux/irq.h>
 #include <asm/bootinfo.h>
 #include <asm/idle.h>
index 55559ca0efe404ce78d7039f9fa09a72df7c0ad3..2245169c72af0dc5f4d1346e817cb18ee5600cfc 100644 (file)
@@ -4,7 +4,7 @@
 #
 
 config NDS32
-        def_bool y
+       def_bool y
        select ARCH_32BIT_OFF_T
        select ARCH_HAS_SYNC_DMA_FOR_CPU
        select ARCH_HAS_SYNC_DMA_FOR_DEVICE
@@ -51,20 +51,20 @@ config GENERIC_CALIBRATE_DELAY
        def_bool y
 
 config GENERIC_CSUM
-        def_bool y
+       def_bool y
 
 config GENERIC_HWEIGHT
-        def_bool y
+       def_bool y
 
 config GENERIC_LOCKBREAK
-        def_bool y
+       def_bool y
        depends on PREEMPT
 
 config TRACE_IRQFLAGS_SUPPORT
        def_bool y
 
 config STACKTRACE_SUPPORT
-        def_bool y
+       def_bool y
 
 config FIX_EARLYCON_MEM
        def_bool y
@@ -79,11 +79,11 @@ config NR_CPUS
        default 1
 
 config MMU
-        def_bool y
+       def_bool y
 
 config NDS32_BUILTIN_DTB
-        string "Builtin DTB"
-        default ""
+       string "Builtin DTB"
+       default ""
        help
          User can use it to specify the dts of the SoC
 endmenu
index 688b6ed262278e9536e9fc2a18f11a07f68583e0..f43b44d692ca7b606a274c9015d85607f37aa3db 100644 (file)
@@ -6,7 +6,6 @@ generic-y += bugs.h
 generic-y += checksum.h
 generic-y += clkdev.h
 generic-y += cmpxchg.h
-generic-y += cmpxchg-local.h
 generic-y += compat.h
 generic-y += cputime.h
 generic-y += device.h
@@ -37,9 +36,7 @@ generic-y += pci.h
 generic-y += percpu.h
 generic-y += preempt.h
 generic-y += sections.h
-generic-y += segment.h
 generic-y += serial.h
-generic-y += sizes.h
 generic-y += switch_to.h
 generic-y += timex.h
 generic-y += topology.h
index c3855782a541934a747003311b957e61123e3837..5e7c569260494105db01c9e51c87b91668ec9b1e 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __NDS32_ASSEMBLER_H__
index faafc373ea6c5cc4398a45f1079a0d7f027ac606..16413172fd50deefa334a18ef5c833face0e615b 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __NDS32_ASM_BARRIER_H
index 7414fcbbab4e2f51499e42961be12a1ecc16e3be..e75212c76b2044aa17badc5d77f5f5ad61cf8f30 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __NDS32_BITFIELD_H__
index 347db4881c5f8e01a911379a37ea83d92073e74a..fc3c41b591691cf4c2a396e905486defc18facea 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __NDS32_CACHE_H__
index 38ec458ba54310776e80190530af2540949c16de..e89d8078f3a66f2166d8d73e7b669d56d86b86aa 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 struct cache_info {
index 8b26198d51bb78b60a28748248e1e50f89be52ab..d9ac7e6408ef3196253f3c6838d111a51a1f0973 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __NDS32_CACHEFLUSH_H__
index b4dcd22b7bcbe9300a117834a0fd4984d7565a3e..65d30096142bfc601d4afb3640e334b54ce22600 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef _ASM_NDS32_CURRENT_H
index 519ba97acb6eb6f69021a1afb1f032e537389a16..56ea3894f8f80b42ba697e9c72c6970ff857893e 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __NDS32_DELAY_H__
index 02250626b9f0ffa01d2faf551a0b4b428dc2f3f4..1c8e56d7013d9f9c6c56699fec4ac30cf1cc293b 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __ASMNDS32_ELF_H
index 0e60e153a71ae047397ef43361d4be12cecec98c..5a4bf11e58003e6ec8ff39c4c3274b82d22c498e 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __ASM_NDS32_FIXMAP_H
index baf178bf1d0b2aa39ec940bbf833de228adb2882..5213c65c2e0b36e0f28df249061f153aee3a96f6 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __NDS32_FUTEX_H__
index 425d546cb05912d8723bfe85dccc24e5b5bd8b41..b3a82c97ded3a9a7d78c3e190a6b29df34ad7981 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef _ASM_HIGHMEM_H
index 5ef8ae5ba83368af59be986582fb7e5f34a266f9..16f262322b8f7a861d8bcdd6da9373cf6aa78139 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __ASM_NDS32_IO_H
index 2bfd00f8bc48efb3caacd3d5bd70592e79c0dc77..fb45ec46bb1b2e7be861a236a3773c090ca65b1e 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #include <asm/nds32.h>
index 37dd5ef61de8b550b66ea68a9c157221a06d7efd..3ea48e19e6de6106d0f81d80fa0deb8a68399ce2 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef L2_CACHE_H
index e708c8bdb926caa599791ddb966cd78045e21242..a696469abb70c6a3f021f66d855590a5b22784b5 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __ASM_LINKAGE_H
index 60efc726b56ed926524fb480609518d4f1f27a2f..940d328427938dffad6ab8f9aa601dcc841deb0d 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __ASM_NDS32_MEMORY_H
 #define PHYS_OFFSET     (0x0)
 #endif
 
-#ifndef __virt_to_bus
-#define __virt_to_bus  __virt_to_phys
-#endif
-
-#ifndef __bus_to_virt
-#define __bus_to_virt  __phys_to_virt
-#endif
-
 /*
  * TASK_SIZE - the maximum size of a user space task.
  * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
index 88b9ee8c10645f81f9ae052c0ca68c9d16ae3abb..89d63afee455cc788b4b83a43c1b63172501b826 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __NDS32_MMU_H
index fd7d13cefccc115529e1a19fa10bb5ad54eb7666..b8fd3d189fdce8ce699f4c850dc0db67d6e87a56 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __ASM_NDS32_MMU_CONTEXT_H
index 16cf9c7237adfc7d9e39b31ff5247904ab0c264f..a3a08e993c65924cb3537bb3848701a15e4b33b7 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef _ASM_NDS32_MODULE_H
index 68c38151c3e41c24c24081f92449a097bf077f02..4994f6a9e0a0bcb1d518c7890c10fef18fbda739 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef _ASM_NDS32_NDS32_H_
index 947f0491c9a717cefd1b3d0549ae867c333e716c..8feb1fa12f01a879a2e14f3334ce1fccac2d3f00 100644 (file)
@@ -1,5 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
- * SPDX-License-Identifier: GPL-2.0
  * Copyright (C) 2005-2017 Andes Technology Corporation
  */
 
index 3c5fee5b5759539d71dc8b731e448dd7843f6184..3cbc749c79aa26ead2a2b2dc78b9422f69a0df38 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef _ASMNDS32_PGALLOC_H
index 9f52db930c004ecc5c6de013721e06d7b4bf52a3..c70cc56bec09b7501e687e4760676532e65b0a55 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef _ASMNDS32_PGTABLE_H
@@ -6,7 +6,7 @@
 
 #define __PAGETABLE_PMD_FOLDED 1
 #include <asm-generic/4level-fixup.h>
-#include <asm-generic/sizes.h>
+#include <linux/sizes.h>
 
 #include <asm/memory.h>
 #include <asm/nds32.h>
index bedc4f59e064f86354a2016dd42776ac16256dca..27c617fa77afd9a324091aec15e2fa6098b29085 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __NDS32_PROCFNS_H__
index 72024f8bc129035de9367277b35203f09fe40d80..b82369c7659d4dedeeec151859654bad0a789749 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __ASM_NDS32_PROCESSOR_H
index c4538839055cc4c97dfe1e4bec13e8f705330609..919ee223620c95470a27cedccd1ff27b54f91bd8 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __ASM_NDS32_PTRACE_H
index fd1cff64b68e938ec897f857adc256603616ae83..3aeee946973d5ac2be3ca14302d5dc5c321bc26c 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef _ASMNDS32_SHMPARAM_H
index 179272caa5409ce188aae6e03fd33a37ff7808d4..cae8fe16de98b599d42abd51b3e2ccae365abbf4 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __ASM_NDS32_STRING_H
index e01a755a37d2af2af1f6d2007bed342e7ffd95db..362a466f2976a7ebea95ea22f1669027ff37abe8 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __NDS32_SWAB_H__
index 174b8571d362e5600acd5f173e947829111a90b5..899b2fb4b52f7972f3e567aba0d1942ee296f5a2 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2008-2009 Red Hat, Inc.  All rights reserved.
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
index da32101b455d764a125649f3791cc3f4332db15c..f3b16f602cb5389c924a18c57e4d105407faaee4 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __ASM_NDS32_SYSCALLS_H
index bff741ff337baf617c518612120de1cad1750ea8..c135111ec44ebb1519c13b616edbda6d85f4f8d3 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __ASM_NDS32_THREAD_INFO_H
@@ -42,7 +42,6 @@ struct thread_info {
  *  TIF_SIGPENDING     - signal pending
  *  TIF_NEED_RESCHED   - rescheduling necessary
  *  TIF_NOTIFY_RESUME  - callback before returning to user
- *  TIF_USEDFPU                - FPU was used by this task this quantum (SMP)
  *  TIF_POLLING_NRFLAG - true if poll_idle() is polling TIF_NEED_RESCHED
  */
 #define TIF_SIGPENDING         1
@@ -50,7 +49,6 @@ struct thread_info {
 #define TIF_SINGLESTEP         3
 #define TIF_NOTIFY_RESUME      4       /* callback before returning to user */
 #define TIF_SYSCALL_TRACE      8
-#define TIF_USEDFPU             16
 #define TIF_POLLING_NRFLAG     17
 #define TIF_MEMDIE             18
 #define TIF_FREEZE             19
index d5ae571c8d303f4e87350e3a9644df4469ec4da2..a8aff1c8b4f4316070d35fffd191fcac5b8f66a6 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __ASMNDS32_TLB_H
index 38ee769b18d8ad344e09819dff0fb93c24af94bc..97155366ea01852498d2ac7a3d39e126db8ade46 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef _ASMNDS32_TLBFLUSH_H
index 116598b47c4d2b7c19cce39ba9ad98d8c00e51fd..8916ad9f9f139954ce6a8d799dfb3ad807db66f7 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef _ASMANDES_UACCESS_H
index b586a2862beb22994c13af34d31b501e236ee2e5..bf5e2d440913f00051781485a7d9b5a557d8fef3 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #define __ARCH_WANT_SYS_CLONE
index af2c6afc2469253fc6df5c3aadd305de3a44424c..89b113ffc3dc01e24780203d30723620b02b7ea1 100644 (file)
@@ -1,5 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
- * SPDX-License-Identifier: GPL-2.0
  * Copyright (C) 2005-2017 Andes Technology Corporation
  */
 
index 79db5a12ca5eb660d2a3ae7873c4872cd2c415f2..74c68802021ec60d277292e2e86b3043c0535ed2 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2012 ARM Limited
 // Copyright (C) 2005-2017 Andes Technology Corporation
 #ifndef __ASM_VDSO_DATAPAGE_H
@@ -20,6 +20,7 @@ struct vdso_data {
        u32 xtime_clock_sec;    /* CLOCK_REALTIME - seconds */
        u32 cs_mult;            /* clocksource multiplier */
        u32 cs_shift;           /* Cycle to nanosecond divisor (power of two) */
+       u32 hrtimer_res;        /* hrtimer resolution */
 
        u64 cs_cycle_last;      /* last cycle value */
        u64 cs_mask;            /* clocksource mask */
index 50ba117cff12945c98e0e531e43e51426205f63c..328439ce37db7263cc03fb4cc581fe011d96b3d6 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 extern struct timer_info_t timer_info;
index 2d3213f5e59583162babb3b6ad05eafa116828ad..b5d58ea8decbb0a299efeb1c5fc1e4a1c19acff9 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __ASM_AUXVEC_H
index a23f6f3a24689229fa9042dcad413a7aafec0386..511e653c709d54692483508f3ae8a71c03e662cd 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __NDS32_BYTEORDER_H__
index 4cdca9b23974935945a46a2d8c1396a3caae88fe..73793662815c849a4776bfb042e4f9f050dde254 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 1994, 1995, 1996 by Ralf Baechle
 // Copyright (C) 2005-2017 Andes Technology Corporation
 #ifndef        _ASM_CACHECTL
index e3fb723ee362a695f6a1f9ab380c307e7b130ba3..2977534a6bd3129df9a1ec5c17a7e1a46a150def 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __ASM_NDS32_PARAM_H
index 358c99e399d05d22ab6749c2144aaa89ba7ca7aa..1a6e01c00e6f880607d1e5b43ad0432f5c3abc00 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef __UAPI_ASM_NDS32_PTRACE_H
index 58afc416473e578817a23073693dfd87a61251c1..628ff6b75825a18c77562c1285268c3c189846e7 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #ifndef _ASMNDS32_SIGCONTEXT_H
index 4ec8f543103f6c9df303950230469a665bb93827..c691735017ed59724f760b859a2c739780835b10 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 // Copyright (C) 2005-2017 Andes Technology Corporation
 
 #define __ARCH_WANT_STAT64
diff --git a/arch/nds32/kernel/.gitignore b/arch/nds32/kernel/.gitignore
new file mode 100644 (file)
index 0000000..c5f676c
--- /dev/null
@@ -0,0 +1 @@
+vmlinux.lds
index 0a7bc696dd5523961b78f4e2740e9ec4809f5902..aab98e447feb368e742461c02b00b044d56d993f 100644 (file)
@@ -13,7 +13,7 @@ static void ci_leaf_init(struct cacheinfo *this_leaf,
        this_leaf->level = level;
        this_leaf->type = type;
        this_leaf->coherency_line_size = CACHE_LINE_SIZE(cache_type);
-       this_leaf->number_of_sets = CACHE_SET(cache_type);;
+       this_leaf->number_of_sets = CACHE_SET(cache_type);
        this_leaf->ways_of_associativity = CACHE_WAY(cache_type);
        this_leaf->size = this_leaf->number_of_sets *
            this_leaf->coherency_line_size * this_leaf->ways_of_associativity;
index 97ba15cd4180b09bc59aeb7fcdbe2eede8c766dd..1df02a79336417fb7eef1ca34d199f378b514659 100644 (file)
@@ -163,7 +163,7 @@ resume_kernel:
        gie_disable
        lwi     $t0, [tsk+#TSK_TI_PREEMPT]
        bnez    $t0, no_work_pending
-need_resched:
+
        lwi     $t0, [tsk+#TSK_TI_FLAGS]
        andi    $p1, $t0, #_TIF_NEED_RESCHED
        beqz    $p1, no_work_pending
@@ -173,7 +173,7 @@ need_resched:
        beqz    $t0, no_work_pending
 
        jal     preempt_schedule_irq
-       b       need_resched
+       b       no_work_pending
 #endif
 
 /*
index 8a41372551ff3cbca4bcf0a94e1bea400dcb4c01..fd2a54b8cd5733f8ce64455bdf8762bd8a3a8251 100644 (file)
@@ -7,7 +7,6 @@
 #ifndef CONFIG_DYNAMIC_FTRACE
 extern void (*ftrace_trace_function)(unsigned long, unsigned long,
                                     struct ftrace_ops*, struct pt_regs*);
-extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace);
 extern void ftrace_graph_caller(void);
 
 noinline void __naked ftrace_stub(unsigned long ip, unsigned long parent_ip,
index db64b78b1232abcd088c6fea36e39c262902355b..fcefb62606cab118048e9caaef8dcedaa693923d 100644 (file)
@@ -7,7 +7,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/thread_info.h>
 
 #ifdef CONFIG_CPU_BIG_ENDIAN
index 5ecebd0e60cb60244ac97c368c66e931d7c1870c..20719e42ae36842cef799b9756e710e7e4446caf 100644 (file)
@@ -23,9 +23,3 @@ EXPORT_SYMBOL(memzero);
 EXPORT_SYMBOL(__arch_copy_from_user);
 EXPORT_SYMBOL(__arch_copy_to_user);
 EXPORT_SYMBOL(__arch_clear_user);
-
-/* cache handling */
-EXPORT_SYMBOL(cpu_icache_inval_all);
-EXPORT_SYMBOL(cpu_dcache_wbinval_all);
-EXPORT_SYMBOL(cpu_dma_inval_range);
-EXPORT_SYMBOL(cpu_dma_wb_range);
index 016f15891f6d40c22a908a6da6c719c5a3c6503a..90bcae6f855448da7775863d9d172ce0fbaae9b4 100644 (file)
@@ -220,6 +220,7 @@ void update_vsyscall(struct timekeeper *tk)
        vdso_data->xtime_coarse_sec = tk->xtime_sec;
        vdso_data->xtime_coarse_nsec = tk->tkr_mono.xtime_nsec >>
            tk->tkr_mono.shift;
+       vdso_data->hrtimer_res = hrtimer_resolution;
        vdso_write_end(vdso_data);
 }
 
diff --git a/arch/nds32/kernel/vdso/.gitignore b/arch/nds32/kernel/vdso/.gitignore
new file mode 100644 (file)
index 0000000..f8b69d8
--- /dev/null
@@ -0,0 +1 @@
+vdso.lds
index e6c50a70131351fe4d06abdd86553936277d5f3a..8792fda19a64b4a486c1b23b2b1d7ed639768fc1 100644 (file)
@@ -11,10 +11,8 @@ obj-vdso := note.o datapage.o sigreturn.o gettimeofday.o
 targets := $(obj-vdso) vdso.so vdso.so.dbg
 obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
 
-ccflags-y := -shared -fno-common -fno-builtin
-ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \
-               $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
-ccflags-y += -fPIC -Wl,-shared -g
+ccflags-y := -shared -fno-common -fno-builtin -nostdlib -fPIC -Wl,-shared -g \
+       -Wl,-soname=linux-vdso.so.1 -Wl,--hash-style=sysv
 
 # Disable gcov profiling for VDSO code
 GCOV_PROFILE := n
@@ -28,7 +26,7 @@ CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
 $(obj)/vdso.o : $(obj)/vdso.so
 
 # Link rule for the .so file, .lds has to be first
-$(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso)
+$(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE
        $(call if_changed,vdsold)
 
 
@@ -40,9 +38,7 @@ $(obj)/%.so: $(obj)/%.so.dbg FORCE
 # Generate VDSO offsets using helper script
 gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh
 quiet_cmd_vdsosym = VDSOSYM $@
-define cmd_vdsosym
-       $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
-endef
+      cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
 
 include/generated/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE
        $(call if_changed,vdsosym)
@@ -65,7 +61,7 @@ gettimeofday.o : gettimeofday.c FORCE
 
 # Actual build commands
 quiet_cmd_vdsold = VDSOL   $@
-      cmd_vdsold = $(CC) $(c_flags) -Wl,-n -Wl,-T $^ -o $@
+      cmd_vdsold = $(CC) $(c_flags) -Wl,-n -Wl,-T $(real-prereqs) -o $@
 quiet_cmd_vdsoas = VDSOA   $@
       cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $<
 quiet_cmd_vdsocc = VDSOA   $@
index 038721af40e37d91213f8de6bd636b8c03cfeae8..b02581891c33c7288d1db33a58dbeff5eb1ad6cf 100644 (file)
@@ -208,6 +208,8 @@ static notrace int clock_getres_fallback(clockid_t _clk_id,
 
 notrace int __vdso_clock_getres(clockid_t clk_id, struct timespec *res)
 {
+       struct vdso_data *vdata = __get_datapage();
+
        if (res == NULL)
                return 0;
        switch (clk_id) {
@@ -215,7 +217,7 @@ notrace int __vdso_clock_getres(clockid_t clk_id, struct timespec *res)
        case CLOCK_MONOTONIC:
        case CLOCK_MONOTONIC_RAW:
                res->tv_sec = 0;
-               res->tv_nsec = CLOCK_REALTIME_RES;
+               res->tv_nsec = vdata->hrtimer_res;
                break;
        case CLOCK_REALTIME_COARSE:
        case CLOCK_MONOTONIC_COARSE:
index 1d03633f89a9f3e7b953db45001cec2839c25deb..55703b03d17224a10b70895f32a35a4688d3d849 100644 (file)
@@ -252,18 +252,6 @@ void __init mem_init(void)
        return;
 }
 
-void free_initmem(void)
-{
-       free_initmem_default(-1);
-}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-#endif
-
 void __set_fixmap(enum fixed_addresses idx,
                               phys_addr_t phys, pgprot_t flags)
 {
@@ -272,7 +260,7 @@ void __set_fixmap(enum fixed_addresses idx,
 
        BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses);
 
-       pte = (pte_t *)&fixmap_pmd_p[pte_index(addr)];;
+       pte = (pte_t *)&fixmap_pmd_p[pte_index(addr)];
 
        if (pgprot_val(flags)) {
                set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags));
index ea37394ff3eab2ad16cb5d7f1f08fe9626431080..26a9c760a98bbcc36d43f6599326addcfeace594 100644 (file)
@@ -23,7 +23,6 @@ config NIOS2
        select SPARSE_IRQ
        select USB_ARCH_HAS_HCD if USB_SUPPORT
        select CPU_NO_EFFICIENT_FFS
-       select ARCH_DISCARD_MEMBLOCK
        select MMU_GATHER_NO_RANGE if MMU
 
 config GENERIC_CSUM
index d7ef3512504a6be516b7fe81c2a74d49f81e9cbe..a8ffdd007f6ca7b06a349dec829053d261adc4b4 100644 (file)
@@ -33,7 +33,6 @@ generic-y += pci.h
 generic-y += percpu.h
 generic-y += preempt.h
 generic-y += sections.h
-generic-y += segment.h
 generic-y += serial.h
 generic-y += spinlock.h
 generic-y += topology.h
index 16cea5776b87c6aa51101ea690f8a6401df191bb..2c609c2516b29c1a83f402abb2010e28fa62bdd3 100644 (file)
@@ -82,18 +82,6 @@ void __init mmu_init(void)
        flush_tlb_all();
 }
 
-#ifdef CONFIG_BLK_DEV_INITRD
-void __init free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-#endif
-
-void __ref free_initmem(void)
-{
-       free_initmem_default(-1);
-}
-
 #define __page_aligned(order) __aligned(PAGE_SIZE << (order))
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned(PGD_ORDER);
 pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned(PTE_ORDER);
index 1919cc5e0f11d4af523998bf2fac993a4e932547..164be10062bc33d969e5dffbd43d1640b3606f63 100644 (file)
@@ -34,7 +34,6 @@ generic-y += qspinlock.h
 generic-y += qrwlock_types.h
 generic-y += qrwlock.h
 generic-y += sections.h
-generic-y += segment.h
 generic-y += shmparam.h
 generic-y += switch_to.h
 generic-y += topology.h
index eb97a8e7c8aa79d1d1e4ccf3329f7e2281d37e5e..e8fb2a764f4697e1f7a707cb021b883e4a158a5d 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/elf.h>
 
 #include <asm/thread_info.h>
-#include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
index c605bdad1746ad25288b6b2e06de9641704e1f3f..17c00d06d91bbd421c0829c913b4135c93e91902 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/device.h>
 
 #include <asm/sections.h>
-#include <asm/segment.h>
 #include <asm/pgtable.h>
 #include <asm/types.h>
 #include <asm/setup.h>
index d8981cbb852a5f1fc1ea80667df3ed451579d13c..6ed7293ef007f4ae068622ff73ed178aae94c07e 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/kallsyms.h>
 #include <linux/uaccess.h>
 
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/unwinder.h>
index caeb4184e8a6bb030f93b647e0cbd076b8918a48..e63cb4a91a3ea7d4ba591dbe8e14b8af959b578e 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/blkdev.h>      /* for initrd_* */
 #include <linux/pagemap.h>
 
-#include <asm/segment.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/dma.h>
@@ -223,15 +222,3 @@ void __init mem_init(void)
        mem_init_done = 1;
        return;
 }
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-#endif
-
-void free_initmem(void)
-{
-       free_initmem_default(-1);
-}
index 6c253a2e86bc4e1a2cba5e509f09fdbe5c148635..7f9f50161dfedda1dc7809e51da8aed85bef7563 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 
-#include <asm/segment.h>
 #include <asm/tlbflush.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
index ed2d8cc9490969cab10137383d770202ade70a0a..005ee8ad0446a78b6febaa45960eb56c17a337b7 100644 (file)
@@ -19,7 +19,6 @@ generic-y += mmiowb.h
 generic-y += percpu.h
 generic-y += preempt.h
 generic-y += seccomp.h
-generic-y += segment.h
 generic-y += trace_clock.h
 generic-y += user.h
 generic-y += vga.h
index 4016fe1c65a9c31148d677d6678c6dbe0d2c3871..73ca89a47f492702f5326525cd67d85be9f8076e 100644 (file)
@@ -24,9 +24,6 @@
 
 #define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
-/* Read-only memory is marked before mark_rodata_ro() is called. */
-#define __ro_after_init        __read_mostly
-
 void parisc_cache_init(void);  /* initializes cache-flushing */
 void disable_sr_hashing_asm(int); /* low level support for above */
 void disable_sr_hashing(void);   /* turns off space register hashing */
index 0338561968a4f5fa52545d1e34cc073a16c5276a..a82b3eaa539896b986010f63622c7c8321848625 100644 (file)
@@ -29,9 +29,9 @@
 #include <asm/sections.h>
 #include <asm/shmparam.h>
 
-int split_tlb __read_mostly;
-int dcache_stride __read_mostly;
-int icache_stride __read_mostly;
+int split_tlb __ro_after_init;
+int dcache_stride __ro_after_init;
+int icache_stride __ro_after_init;
 EXPORT_SYMBOL(dcache_stride);
 
 void flush_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr);
@@ -51,12 +51,12 @@ DEFINE_SPINLOCK(pa_tlb_flush_lock);
 DEFINE_SPINLOCK(pa_swapper_pg_lock);
 
 #if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
-int pa_serialize_tlb_flushes __read_mostly;
+int pa_serialize_tlb_flushes __ro_after_init;
 #endif
 
-struct pdc_cache_info cache_info __read_mostly;
+struct pdc_cache_info cache_info __ro_after_init;
 #ifndef CONFIG_PA20
-static struct pdc_btlb_info btlb_info __read_mostly;
+static struct pdc_btlb_info btlb_info __ro_after_init;
 #endif
 
 #ifdef CONFIG_SMP
@@ -381,10 +381,10 @@ EXPORT_SYMBOL(flush_data_cache_local);
 EXPORT_SYMBOL(flush_kernel_icache_range_asm);
 
 #define FLUSH_THRESHOLD 0x80000 /* 0.5MB */
-static unsigned long parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD;
+static unsigned long parisc_cache_flush_threshold __ro_after_init = FLUSH_THRESHOLD;
 
 #define FLUSH_TLB_THRESHOLD (16*1024) /* 16 KiB minimum TLB threshold */
-static unsigned long parisc_tlb_flush_threshold __read_mostly = FLUSH_TLB_THRESHOLD;
+static unsigned long parisc_tlb_flush_threshold __ro_after_init = FLUSH_TLB_THRESHOLD;
 
 void __init parisc_setup_cache_timing(void)
 {
index 15e7b3be7b6b163a26272c7c671df8c96c8fcef1..00a181f1ecc6d7a02a01896fdc3fcf526b13f03b 100644 (file)
@@ -41,7 +41,7 @@
 #include <asm/ropes.h>
 
 /* See comments in include/asm-parisc/pci.h */
-const struct dma_map_ops *hppa_dma_ops __read_mostly;
+const struct dma_map_ops *hppa_dma_ops __ro_after_init;
 EXPORT_SYMBOL(hppa_dma_ops);
 
 static struct device root = {
index 7a17551ea31e3f887dd79462c72cd46dea8ef539..f01e102bbfa2b13f8f38a26d7f72a0ca24f0ca95 100644 (file)
@@ -87,7 +87,7 @@ extern unsigned long pdc_result2[NUM_PDC_RESULT];
 
 /* Firmware needs to be initially set to narrow to determine the 
  * actual firmware width. */
-int parisc_narrow_firmware __read_mostly = 1;
+int parisc_narrow_firmware __ro_after_init = 1;
 #endif
 
 /* On most currently-supported platforms, IODC I/O calls are 32-bit calls
index e46a4157a8948862697755439496a16e5acb29f4..a28f915993b1b7b9684ee5761287b1bb6f60ab9b 100644 (file)
@@ -51,7 +51,6 @@ void notrace __hot ftrace_function_trampoline(unsigned long parent,
                                unsigned long org_sp_gr3)
 {
        extern ftrace_func_t ftrace_trace_function;  /* depends on CONFIG_DYNAMIC_FTRACE */
-       extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace);
 
        if (ftrace_trace_function != ftrace_stub) {
                /* struct ftrace_ops *op, struct pt_regs *regs); */
index d12de2a137532562bcac864fbc57f2d70e24d85e..951a339369dd5994bd40dae09e97021b539cf982 100644 (file)
@@ -376,7 +376,7 @@ smp_slave_stext:
 ENDPROC(parisc_kernel_start)
 
 #ifndef CONFIG_64BIT
-       .section .data..read_mostly
+       .section .data..ro_after_init
 
        .align  4
        .export $global$,data
index 6f2d611347a15ee2b56c2a58793195222321b0ff..3f4a91c0b805079bd1ce82c5c914f20a02f8dc12 100644 (file)
 */
 #undef DEBUG_PAT
 
-int pdc_type __read_mostly = PDC_TYPE_ILLEGAL;
+int pdc_type __ro_after_init = PDC_TYPE_ILLEGAL;
 
 /* cell number and location (PAT firmware only) */
-unsigned long parisc_cell_num __read_mostly;
-unsigned long parisc_cell_loc __read_mostly;
-unsigned long parisc_pat_pdc_cap __read_mostly;
+unsigned long parisc_cell_num __ro_after_init;
+unsigned long parisc_cell_loc __ro_after_init;
+unsigned long parisc_pat_pdc_cap __ro_after_init;
 
 
 void __init setup_pdc(void)
index ae684ac6efb6e6d3f5b5284dda279eda54dea311..bc41ca243cfece3f7b9e57e5d8f449ad3a9c28ac 100644 (file)
  * #define pci_post_reset_delay 50
  */
 
-struct pci_port_ops *pci_port __read_mostly;
-struct pci_bios_ops *pci_bios __read_mostly;
+struct pci_port_ops *pci_port __ro_after_init;
+struct pci_bios_ops *pci_bios __ro_after_init;
 
-static int pci_hba_count __read_mostly;
+static int pci_hba_count __ro_after_init;
 
 /* parisc_pci_hba used by pci_port->in/out() ops to lookup bus data.  */
 #define PCI_HBA_MAX 32
-static struct pci_hba_data *parisc_pci_hba[PCI_HBA_MAX] __read_mostly;
+static struct pci_hba_data *parisc_pci_hba[PCI_HBA_MAX] __ro_after_init;
 
 
 /********************************************************************
index 7fef9644df47bd8fd37a42b2cfcd80d23921cee7..c108fee989d982b59c8ff845a18db7d418059538 100644 (file)
@@ -25,7 +25,7 @@
 
 #define PCXU_IMAGE_SIZE 584
 
-static uint32_t onyx_images[][PCXU_IMAGE_SIZE/sizeof(uint32_t)] __read_mostly = {
+static uint32_t onyx_images[][PCXU_IMAGE_SIZE/sizeof(uint32_t)] __ro_after_init = {
 /*
  * CPI:
  *
@@ -2093,7 +2093,7 @@ static uint32_t onyx_images[][PCXU_IMAGE_SIZE/sizeof(uint32_t)] __read_mostly =
 };
 #define PCXW_IMAGE_SIZE 576
 
-static uint32_t cuda_images[][PCXW_IMAGE_SIZE/sizeof(uint32_t)] __read_mostly = {
+static uint32_t cuda_images[][PCXW_IMAGE_SIZE/sizeof(uint32_t)] __ro_after_init = {
 /*
  * CPI:     FROM CPI.IDF (Image 0)
  *
index 97c206734e24f372175c8592703033084d81d0ae..89e4f4497ffb9cc3d3fb0908b68a2b7db5f7c1ec 100644 (file)
@@ -192,7 +192,7 @@ int dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *r)
  * QEMU idle the host too.
  */
 
-int running_on_qemu __read_mostly;
+int running_on_qemu __ro_after_init;
 EXPORT_SYMBOL(running_on_qemu);
 
 void __cpuidle arch_cpu_idle_dead(void)
index e0a81dedc36665ea619298cb3724f693b43690ac..e715871cd4ac046a8745e3b7ea95fbf078a48f7c 100644 (file)
 #include <asm/irq.h>           /* for struct irq_region */
 #include <asm/parisc-device.h>
 
-struct system_cpuinfo_parisc boot_cpu_data __read_mostly;
+struct system_cpuinfo_parisc boot_cpu_data __ro_after_init;
 EXPORT_SYMBOL(boot_cpu_data);
 #ifdef CONFIG_PA8X00
-int _parisc_requires_coherency __read_mostly;
+int _parisc_requires_coherency __ro_after_init;
 EXPORT_SYMBOL(_parisc_requires_coherency);
 #endif
 
index e54d5e4d3489f39eb2cd84eafa6d4d7090dd1d3a..97ac707c6bfff0248e8814b1e6207782e7e61236 100644 (file)
@@ -641,7 +641,8 @@ cas_action:
 2:     stw     %r24, 0(%r26)
        /* Free lock */
 #ifdef CONFIG_SMP
-       LDCW    0(%sr2,%r20), %r1                       /* Barrier */
+98:    LDCW    0(%sr2,%r20), %r1                       /* Barrier */
+99:    ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
 #endif
        stw     %r20, 0(%sr2,%r20)
 #if ENABLE_LWS_DEBUG
@@ -658,7 +659,8 @@ cas_action:
        /* Error occurred on load or store */
        /* Free lock */
 #ifdef CONFIG_SMP
-       LDCW    0(%sr2,%r20), %r1                       /* Barrier */
+98:    LDCW    0(%sr2,%r20), %r1                       /* Barrier */
+99:    ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
 #endif
        stw     %r20, 0(%sr2,%r20)
 #if ENABLE_LWS_DEBUG
@@ -862,7 +864,8 @@ cas2_action:
 cas2_end:
        /* Free lock */
 #ifdef CONFIG_SMP
-       LDCW    0(%sr2,%r20), %r1                       /* Barrier */
+98:    LDCW    0(%sr2,%r20), %r1                       /* Barrier */
+99:    ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
 #endif
        stw     %r20, 0(%sr2,%r20)
        /* Enable interrupts */
@@ -875,7 +878,8 @@ cas2_end:
        /* Error occurred on load or store */
        /* Free lock */
 #ifdef CONFIG_SMP
-       LDCW    0(%sr2,%r20), %r1                       /* Barrier */
+98:    LDCW    0(%sr2,%r20), %r1                       /* Barrier */
+99:    ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
 #endif
        stw     %r20, 0(%sr2,%r20)
        ssm     PSW_SM_I, %r0
index fe8ca623add89a627710b697f7886fc879589ac2..c9e377d59232fd3b8b882c086440131042073e1f 100644 (file)
 425    common  io_uring_setup                  sys_io_uring_setup
 426    common  io_uring_enter                  sys_io_uring_enter
 427    common  io_uring_register               sys_io_uring_register
+428    common  open_tree                       sys_open_tree
+429    common  move_mount                      sys_move_mount
+430    common  fsopen                          sys_fsopen
+431    common  fsconfig                        sys_fsconfig
+432    common  fsmount                         sys_fsmount
+433    common  fspick                          sys_fspick
index a1e772f909cbf4c2f0c1bd361f968221de3cb0a0..04508158815c1342cf40ddf9db41e5b9868d5273 100644 (file)
@@ -40,7 +40,7 @@
 
 #include <linux/timex.h>
 
-static unsigned long clocktick __read_mostly;  /* timer cycles per tick */
+static unsigned long clocktick __ro_after_init;        /* timer cycles per tick */
 
 /*
  * We keep time on PA-RISC Linux by using the Interval Timer which is
index 2d14f17838d23405383e82e28b3dcc2cf5e3afe7..87ae476d1c4f5d17b24d8d088c71ac261bae0998 100644 (file)
@@ -40,7 +40,7 @@ static DEFINE_SPINLOCK(unwind_lock);
  * we can call unwind_init as early in the bootup process as 
  * possible (before the slab allocator is initialized)
  */
-static struct unwind_table kernel_unwind_table __read_mostly;
+static struct unwind_table kernel_unwind_table __ro_after_init;
 static LIST_HEAD(unwind_tables);
 
 static inline const struct unwind_table_entry *
index a8be7a47fcc0f7790ca1f7e8721fdc7f1a2c2356..c3b1b9c24ede70fd9957d646613413dea42398eb 100644 (file)
@@ -18,9 +18,6 @@
                                *(.data..vm0.pgd) \
                                *(.data..vm0.pte)
 
-/* No __ro_after_init data in the .rodata section - which will always be ro */
-#define RO_AFTER_INIT_DATA
-
 #include <asm-generic/vmlinux.lds.h>
 
 /* needed for the processor specific cache alignment size */   
index 3b0f9eab7f2cdcf0259ec6b4def076fea0b87565..ddca8287d43bac22e772854d7100975312146866 100644 (file)
@@ -66,7 +66,7 @@ static struct resource pdcdata_resource = {
        .flags  = IORESOURCE_BUSY | IORESOURCE_MEM,
 };
 
-static struct resource sysram_resources[MAX_PHYSMEM_RANGES] __read_mostly;
+static struct resource sysram_resources[MAX_PHYSMEM_RANGES] __ro_after_init;
 
 /* The following array is initialized from the firmware specific
  * information retrieved in kernel/inventory.c.
@@ -345,16 +345,7 @@ static void __init setup_bootmem(void)
        memblock_dump_all();
 }
 
-static int __init parisc_text_address(unsigned long vaddr)
-{
-       static unsigned long head_ptr __initdata;
-
-       if (!head_ptr)
-               head_ptr = PAGE_MASK & (unsigned long)
-                       dereference_function_descriptor(&parisc_kernel_start);
-
-       return core_kernel_text(vaddr) || vaddr == head_ptr;
-}
+static bool kernel_set_to_readonly;
 
 static void __init map_pages(unsigned long start_vaddr,
                             unsigned long start_paddr, unsigned long size,
@@ -372,10 +363,11 @@ static void __init map_pages(unsigned long start_vaddr,
        unsigned long vaddr;
        unsigned long ro_start;
        unsigned long ro_end;
-       unsigned long kernel_end;
+       unsigned long kernel_start, kernel_end;
 
        ro_start = __pa((unsigned long)_text);
        ro_end   = __pa((unsigned long)&data_start);
+       kernel_start = __pa((unsigned long)&__init_begin);
        kernel_end  = __pa((unsigned long)&_end);
 
        end_paddr = start_paddr + size;
@@ -438,26 +430,30 @@ static void __init map_pages(unsigned long start_vaddr,
                        pg_table = (pte_t *) __va(pg_table) + start_pte;
                        for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++, pg_table++) {
                                pte_t pte;
-
-                               if (force)
-                                       pte =  __mk_pte(address, pgprot);
-                               else if (parisc_text_address(vaddr)) {
-                                       pte = __mk_pte(address, PAGE_KERNEL_EXEC);
-                                       if (address >= ro_start && address < kernel_end)
-                                               pte = pte_mkhuge(pte);
+                               pgprot_t prot;
+                               bool huge = false;
+
+                               if (force) {
+                                       prot = pgprot;
+                               } else if (address < kernel_start || address >= kernel_end) {
+                                       /* outside kernel memory */
+                                       prot = PAGE_KERNEL;
+                               } else if (!kernel_set_to_readonly) {
+                                       /* still initializing, allow writing to RO memory */
+                                       prot = PAGE_KERNEL_RWX;
+                                       huge = true;
+                               } else if (address >= ro_start) {
+                                       /* Code (ro) and Data areas */
+                                       prot = (address < ro_end) ?
+                                               PAGE_KERNEL_EXEC : PAGE_KERNEL;
+                                       huge = true;
+                               } else {
+                                       prot = PAGE_KERNEL;
                                }
-                               else
-#if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
-                               if (address >= ro_start && address < ro_end) {
-                                       pte = __mk_pte(address, PAGE_KERNEL_EXEC);
+
+                               pte = __mk_pte(address, prot);
+                               if (huge)
                                        pte = pte_mkhuge(pte);
-                               } else
-#endif
-                               {
-                                       pte = __mk_pte(address, pgprot);
-                                       if (address >= ro_start && address < kernel_end)
-                                               pte = pte_mkhuge(pte);
-                               }
 
                                if (address >= end_paddr)
                                        break;
@@ -493,6 +489,12 @@ void __ref free_initmem(void)
 {
        unsigned long init_begin = (unsigned long)__init_begin;
        unsigned long init_end = (unsigned long)__init_end;
+       unsigned long kernel_end  = (unsigned long)&_end;
+
+       /* Remap kernel text and data, but do not touch init section yet. */
+       kernel_set_to_readonly = true;
+       map_pages(init_end, __pa(init_end), kernel_end - init_end,
+                 PAGE_KERNEL, 0);
 
        /* The init text pages are marked R-X.  We have to
         * flush the icache and mark them RW-
@@ -509,7 +511,7 @@ void __ref free_initmem(void)
                  PAGE_KERNEL, 1);
 
        /* force the kernel to see the new TLB entries */
-       __flush_tlb_range(0, init_begin, init_end);
+       __flush_tlb_range(0, init_begin, kernel_end);
 
        /* finally dump all the instructions which were cached, since the
         * pages are no-longer executable */
@@ -527,8 +529,9 @@ void mark_rodata_ro(void)
 {
        /* rodata memory was already mapped with KERNEL_RO access rights by
            pagetable_init() and map_pages(). No need to do additional stuff here */
-       printk (KERN_INFO "Write protecting the kernel read-only data: %luk\n",
-               (unsigned long)(__end_rodata - __start_rodata) >> 10);
+       unsigned long roai_size = __end_ro_after_init - __start_ro_after_init;
+
+       pr_info("Write protected read-only-after-init data: %luk\n", roai_size >> 10);
 }
 #endif
 
@@ -554,11 +557,11 @@ void mark_rodata_ro(void)
 #define SET_MAP_OFFSET(x) ((void *)(((unsigned long)(x) + VM_MAP_OFFSET) \
                                     & ~(VM_MAP_OFFSET-1)))
 
-void *parisc_vmalloc_start __read_mostly;
+void *parisc_vmalloc_start __ro_after_init;
 EXPORT_SYMBOL(parisc_vmalloc_start);
 
 #ifdef CONFIG_PA11
-unsigned long pcxl_dma_start __read_mostly;
+unsigned long pcxl_dma_start __ro_after_init;
 #endif
 
 void __init mem_init(void)
@@ -632,7 +635,7 @@ void __init mem_init(void)
 #endif
 }
 
-unsigned long *empty_zero_page __read_mostly;
+unsigned long *empty_zero_page __ro_after_init;
 EXPORT_SYMBOL(empty_zero_page);
 
 /*
@@ -917,10 +920,3 @@ void flush_tlb_all(void)
        spin_unlock(&sid_lock);
 }
 #endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-#endif
index d7996cfacecaee9c007c4c3fe65769906c977e14..8c1c636308c8e6544fc781a3f4cbda6310ba95d1 100644 (file)
@@ -137,6 +137,7 @@ config PPC
        select ARCH_HAS_UBSAN_SANITIZE_ALL
        select ARCH_HAS_ZONE_DEVICE             if PPC_BOOK3S_64
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
+       select ARCH_KEEP_MEMBLOCK
        select ARCH_MIGHT_HAVE_PC_PARPORT
        select ARCH_MIGHT_HAVE_PC_SERIO
        select ARCH_OPTIONAL_KERNEL_RWX         if ARCH_HAS_STRICT_KERNEL_RWX
index b5cc7426c21fd030614cc3696a5efa65eb138ea9..3da091f651d6c542d85799cee7b1b0ffd8242045 100644 (file)
@@ -33,7 +33,7 @@ CONFIG_MTD_CFI=y
 CONFIG_MTD_JEDECPROBE=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_NDFC=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=35000
index aac06d2ad01ae25742ba1163b98b4d5f1154165c..38d3d7769a2f9e60abd13f770e981c2050cc6da1 100644 (file)
@@ -33,7 +33,7 @@ CONFIG_MTD_CFI=y
 CONFIG_MTD_JEDECPROBE=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_NDFC=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=35000
index c8e6f048a1220e679568ebf27fc5f14dc2617601..d427cee027a69f42faa2808b11a2e1d11611a795 100644 (file)
@@ -32,7 +32,7 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_NDFC=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=35000
index f6dc23fef6837689ae3d1e0a1e9fd462b1b5166b..f593258806ad9e38929f3ba4c172be8478cb16ee 100644 (file)
@@ -33,7 +33,7 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_NDFC=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=35000
index 1e04122912f300f5b9cd63bbbf03df1b2f960355..f34fee9464e5b07a70e0b3b6a208f9da254af49a 100644 (file)
@@ -33,7 +33,7 @@ CONFIG_MTD_JEDECPROBE=y
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_NDFC=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=35000
index 6c02f53271cdca814b96f86b20c8c641256da1b9..6ae88d4879bf56c5bc2e219bf28d7fe7e9e1d2f4 100644 (file)
@@ -34,7 +34,7 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_NDFC=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_RAM=y
index 1f69f4edf0748e6ac1fae2e1ee8c5d6bd6dd3473..9dffb2e7f735548b86f3d4030df16073d399ac08 100644 (file)
@@ -31,7 +31,7 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_FSL_ELBC=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
index 797fc3ffddee25749349bbdb2683f317d758c4f5..a42232732c6d2578d91099e4594a63196bb6756c 100644 (file)
@@ -31,7 +31,7 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=32768
index c03d0fb166658720745aafc29af21bfbd22db5f1..9575a38c9155be520c665db41cbfdd2e8afdabb5 100644 (file)
@@ -71,7 +71,7 @@ CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_M25P80=y
 CONFIG_MTD_NAND_FSL_ELBC=y
 CONFIG_MTD_NAND_FSL_IFC=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_PLATRAM=y
index dd98f43b2fb806501dd1454e6fe2fa265ba04d43..d70b60314dad403cd5e6ece06dc370422a7d03f5 100644 (file)
@@ -73,7 +73,7 @@ CONFIG_MTD_JEDECPROBE=y
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_FSL_ELBC=y
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
index 6106fadbbd8ba3fe4ae50c7557ec94dd2a6a4acc..7037a6d8018c6c16a9efc459310a6be5f10e69ca 100644 (file)
@@ -31,7 +31,7 @@ CONFIG_MTD_CFI=y
 CONFIG_MTD_JEDECPROBE=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_SOCRATES=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
index 2697e4e8a761c9995791a93444d315c2e9fb823a..1c63cbdc3211da7c98bfbf2d8dcd88f8330b5a4c 100644 (file)
@@ -35,8 +35,8 @@ CONFIG_MTD=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND_ECC_SMC=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_FSL_UPM=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
index 6531139a8a8d338fd1e0f8444bb89075f334c519..78f5beb2928cce3c7165a03e633cd52496a24e51 100644 (file)
@@ -65,7 +65,7 @@ CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_CFI_STAA=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_FSL_ELBC=y
 CONFIG_MTD_NAND_FSL_UPM=y
 CONFIG_BLK_DEV_LOOP=y
index d3dd6b8865c088cc2c73a2fb968c3cf9d7316e09..151164cf8cb3f5ad095b003c33e14f24d904e734 100644 (file)
@@ -47,7 +47,7 @@ CONFIG_MTD_CFI=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_JEDECPROBE=y
 CONFIG_MTD_NAND_FSL_ELBC=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_NETDEVICES=y
 CONFIG_NET_TULIP=y
index e4bfb1101c0e85dd6c073428ddd4f78475f89146..e4bf8aa87e6027f111471e882d9561859b323fc1 100644 (file)
@@ -46,7 +46,7 @@ CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_ROM=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_MPC5121_NFC=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_RAM=y
index d1b82035d35f9aae54886fe01798e9e5cdea5d91..005d00020fb9bfa4e423811999444dbc31e832ec 100644 (file)
@@ -46,7 +46,7 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_FSL_ELBC=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
index 6daa56f8895cb22bcd37011328c68932abe50074..c0423b2cf7c03e55ebea533a78f892aa9a2755b4 100644 (file)
@@ -51,7 +51,7 @@ CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_SLRAM=y
 CONFIG_MTD_PHRAM=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_PASEMI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
index 66dd6bf45cde3ce7f6d945dbd3b138ee139fb455..db48039e0b1116c5bb370ee86849aef0f95bb4b4 100644 (file)
@@ -44,7 +44,7 @@ CONFIG_MTD_CFI=y
 CONFIG_MTD_JEDECPROBE=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=m
+CONFIG_MTD_RAW_NAND=m
 CONFIG_MTD_NAND_NDFC=m
 CONFIG_MTD_UBI=m
 CONFIG_MTD_UBI_GLUEBI=m
index 56140d19c85fcb21d6265799e290fc553dfcbf6f..12e150e615b7756d040f256bd841bfb60c41e072 100644 (file)
@@ -36,8 +36,8 @@ static inline int hstate_get_psize(struct hstate *hstate)
        }
 }
 
-#ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE
-static inline bool gigantic_page_supported(void)
+#define __HAVE_ARCH_GIGANTIC_PAGE_RUNTIME_SUPPORTED
+static inline bool gigantic_page_runtime_supported(void)
 {
        /*
         * We used gigantic page reservation with hypervisor assist in some case.
@@ -49,7 +49,6 @@ static inline bool gigantic_page_supported(void)
 
        return true;
 }
-#endif
 
 /* hugepd entry valid bit */
 #define HUGEPD_VAL_BITS                (0x8000000000000000UL)
index e6b5bb012ccb962fa5dcf7fdcd2db8962da1a57e..013c76a0a03eba66462c679af353ee1f770cb88c 100644 (file)
@@ -201,6 +201,8 @@ struct kvmppc_spapr_tce_iommu_table {
        struct kref kref;
 };
 
+#define TCES_PER_PAGE  (PAGE_SIZE / sizeof(u64))
+
 struct kvmppc_spapr_tce_table {
        struct list_head list;
        struct kvm *kvm;
@@ -210,6 +212,7 @@ struct kvmppc_spapr_tce_table {
        u64 offset;             /* in pages */
        u64 size;               /* window size in pages */
        struct list_head iommu_tables;
+       struct mutex alloc_lock;
        struct page *pages[0];
 };
 
@@ -222,6 +225,7 @@ extern struct kvm_device_ops kvm_xics_ops;
 struct kvmppc_xive;
 struct kvmppc_xive_vcpu;
 extern struct kvm_device_ops kvm_xive_ops;
+extern struct kvm_device_ops kvm_xive_native_ops;
 
 struct kvmppc_passthru_irqmap;
 
@@ -312,7 +316,11 @@ struct kvm_arch {
 #endif
 #ifdef CONFIG_KVM_XICS
        struct kvmppc_xics *xics;
-       struct kvmppc_xive *xive;
+       struct kvmppc_xive *xive;    /* Current XIVE device in use */
+       struct {
+               struct kvmppc_xive *native;
+               struct kvmppc_xive *xics_on_xive;
+       } xive_devices;
        struct kvmppc_passthru_irqmap *pimap;
 #endif
        struct kvmppc_ops *kvm_ops;
@@ -449,6 +457,7 @@ struct kvmppc_passthru_irqmap {
 #define KVMPPC_IRQ_DEFAULT     0
 #define KVMPPC_IRQ_MPIC                1
 #define KVMPPC_IRQ_XICS                2 /* Includes a XIVE option */
+#define KVMPPC_IRQ_XIVE                3 /* XIVE native exploitation mode */
 
 #define MMIO_HPTE_CACHE_SIZE   4
 
index ac22b28ae78d4bc52223c94b478b83fc1c5ce48e..bc892380e6cd543d5b757690bcc110b77e2c008c 100644 (file)
@@ -197,10 +197,6 @@ extern struct kvmppc_spapr_tce_table *kvmppc_find_table(
                (iommu_tce_check_ioba((stt)->page_shift, (stt)->offset, \
                                (stt)->size, (ioba), (npages)) ?        \
                                H_PARAMETER : H_SUCCESS)
-extern long kvmppc_tce_to_ua(struct kvm *kvm, unsigned long tce,
-               unsigned long *ua, unsigned long **prmap);
-extern void kvmppc_tce_put(struct kvmppc_spapr_tce_table *tt,
-               unsigned long idx, unsigned long tce);
 extern long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
                             unsigned long ioba, unsigned long tce);
 extern long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu,
@@ -273,6 +269,7 @@ union kvmppc_one_reg {
                u64     addr;
                u64     length;
        }       vpaval;
+       u64     xive_timaval[2];
 };
 
 struct kvmppc_ops {
@@ -480,6 +477,9 @@ extern void kvm_hv_vm_activated(void);
 extern void kvm_hv_vm_deactivated(void);
 extern bool kvm_hv_mode_active(void);
 
+extern void kvmppc_check_need_tlb_flush(struct kvm *kvm, int pcpu,
+                                       struct kvm_nested_guest *nested);
+
 #else
 static inline void __init kvm_cma_reserve(void)
 {}
@@ -594,6 +594,22 @@ extern int kvmppc_xive_set_icp(struct kvm_vcpu *vcpu, u64 icpval);
 extern int kvmppc_xive_set_irq(struct kvm *kvm, int irq_source_id, u32 irq,
                               int level, bool line_status);
 extern void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu);
+
+static inline int kvmppc_xive_enabled(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.irq_type == KVMPPC_IRQ_XIVE;
+}
+
+extern int kvmppc_xive_native_connect_vcpu(struct kvm_device *dev,
+                                          struct kvm_vcpu *vcpu, u32 cpu);
+extern void kvmppc_xive_native_cleanup_vcpu(struct kvm_vcpu *vcpu);
+extern void kvmppc_xive_native_init_module(void);
+extern void kvmppc_xive_native_exit_module(void);
+extern int kvmppc_xive_native_get_vp(struct kvm_vcpu *vcpu,
+                                    union kvmppc_one_reg *val);
+extern int kvmppc_xive_native_set_vp(struct kvm_vcpu *vcpu,
+                                    union kvmppc_one_reg *val);
+
 #else
 static inline int kvmppc_xive_set_xive(struct kvm *kvm, u32 irq, u32 server,
                                       u32 priority) { return -1; }
@@ -617,6 +633,21 @@ static inline int kvmppc_xive_set_icp(struct kvm_vcpu *vcpu, u64 icpval) { retur
 static inline int kvmppc_xive_set_irq(struct kvm *kvm, int irq_source_id, u32 irq,
                                      int level, bool line_status) { return -ENODEV; }
 static inline void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu) { }
+
+static inline int kvmppc_xive_enabled(struct kvm_vcpu *vcpu)
+       { return 0; }
+static inline int kvmppc_xive_native_connect_vcpu(struct kvm_device *dev,
+                         struct kvm_vcpu *vcpu, u32 cpu) { return -EBUSY; }
+static inline void kvmppc_xive_native_cleanup_vcpu(struct kvm_vcpu *vcpu) { }
+static inline void kvmppc_xive_native_init_module(void) { }
+static inline void kvmppc_xive_native_exit_module(void) { }
+static inline int kvmppc_xive_native_get_vp(struct kvm_vcpu *vcpu,
+                                           union kvmppc_one_reg *val)
+{ return 0; }
+static inline int kvmppc_xive_native_set_vp(struct kvm_vcpu *vcpu,
+                                           union kvmppc_one_reg *val)
+{ return -ENOENT; }
+
 #endif /* CONFIG_KVM_XIVE */
 
 #if defined(CONFIG_PPC_POWERNV) && defined(CONFIG_KVM_BOOK3S_64_HANDLER)
@@ -665,6 +696,8 @@ long kvmppc_h_clear_ref(struct kvm_vcpu *vcpu, unsigned long flags,
                         unsigned long pte_index);
 long kvmppc_h_clear_mod(struct kvm_vcpu *vcpu, unsigned long flags,
                         unsigned long pte_index);
+long kvmppc_rm_h_page_init(struct kvm_vcpu *vcpu, unsigned long flags,
+                          unsigned long dest, unsigned long src);
 long kvmppc_hpte_hv_fault(struct kvm_vcpu *vcpu, unsigned long addr,
                           unsigned long slb_v, unsigned int status, bool data);
 unsigned long kvmppc_rm_h_xirr(struct kvm_vcpu *vcpu);
index 5070df19d4638e60dc9ede36058f27027e3f9a23..c005aee5ea437f32f22853b4280bb47c2f1e1212 100644 (file)
 #include <linux/sched/task_stack.h>
 
 #ifdef CONFIG_LIVEPATCH
-static inline int klp_check_compiler_support(void)
-{
-       return 0;
-}
-
 static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
 {
        regs->nip = ip;
index b579a943407bbc0a63c34d53fc73662e9e99db7a..eaf76f57023a10b88bf7929a6b6d2ef99ffa3b5b 100644 (file)
@@ -23,6 +23,7 @@
  * same offset regardless of where the code is executing
  */
 extern void __iomem *xive_tima;
+extern unsigned long xive_tima_os;
 
 /*
  * Offset in the TM area of our current execution level (provided by
@@ -73,6 +74,8 @@ struct xive_q {
        u32                     esc_irq;
        atomic_t                count;
        atomic_t                pending_count;
+       u64                     guest_qaddr;
+       u32                     guest_qshift;
 };
 
 /* Global enable flags for the XIVE support */
index 26ca425f4c2c39515bccee31029b3cada4c73639..b0f72dea8b11ac689c990971dbf78c1601ef4e7a 100644 (file)
@@ -482,6 +482,8 @@ struct kvm_ppc_cpu_char {
 #define  KVM_REG_PPC_ICP_PPRI_SHIFT    16      /* pending irq priority */
 #define  KVM_REG_PPC_ICP_PPRI_MASK     0xff
 
+#define KVM_REG_PPC_VP_STATE   (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x8d)
+
 /* Device control API: PPC-specific devices */
 #define KVM_DEV_MPIC_GRP_MISC          1
 #define   KVM_DEV_MPIC_BASE_ADDR       0       /* 64-bit */
@@ -677,4 +679,48 @@ struct kvm_ppc_cpu_char {
 #define  KVM_XICS_PRESENTED            (1ULL << 43)
 #define  KVM_XICS_QUEUED               (1ULL << 44)
 
+/* POWER9 XIVE Native Interrupt Controller */
+#define KVM_DEV_XIVE_GRP_CTRL          1
+#define   KVM_DEV_XIVE_RESET           1
+#define   KVM_DEV_XIVE_EQ_SYNC         2
+#define KVM_DEV_XIVE_GRP_SOURCE                2       /* 64-bit source identifier */
+#define KVM_DEV_XIVE_GRP_SOURCE_CONFIG 3       /* 64-bit source identifier */
+#define KVM_DEV_XIVE_GRP_EQ_CONFIG     4       /* 64-bit EQ identifier */
+#define KVM_DEV_XIVE_GRP_SOURCE_SYNC   5       /* 64-bit source identifier */
+
+/* Layout of 64-bit XIVE source attribute values */
+#define KVM_XIVE_LEVEL_SENSITIVE       (1ULL << 0)
+#define KVM_XIVE_LEVEL_ASSERTED                (1ULL << 1)
+
+/* Layout of 64-bit XIVE source configuration attribute values */
+#define KVM_XIVE_SOURCE_PRIORITY_SHIFT 0
+#define KVM_XIVE_SOURCE_PRIORITY_MASK  0x7
+#define KVM_XIVE_SOURCE_SERVER_SHIFT   3
+#define KVM_XIVE_SOURCE_SERVER_MASK    0xfffffff8ULL
+#define KVM_XIVE_SOURCE_MASKED_SHIFT   32
+#define KVM_XIVE_SOURCE_MASKED_MASK    0x100000000ULL
+#define KVM_XIVE_SOURCE_EISN_SHIFT     33
+#define KVM_XIVE_SOURCE_EISN_MASK      0xfffffffe00000000ULL
+
+/* Layout of 64-bit EQ identifier */
+#define KVM_XIVE_EQ_PRIORITY_SHIFT     0
+#define KVM_XIVE_EQ_PRIORITY_MASK      0x7
+#define KVM_XIVE_EQ_SERVER_SHIFT       3
+#define KVM_XIVE_EQ_SERVER_MASK                0xfffffff8ULL
+
+/* Layout of EQ configuration values (64 bytes) */
+struct kvm_ppc_xive_eq {
+       __u32 flags;
+       __u32 qshift;
+       __u64 qaddr;
+       __u32 qtoggle;
+       __u32 qindex;
+       __u8  pad[40];
+};
+
+#define KVM_XIVE_EQ_ALWAYS_NOTIFY      0x00000001
+
+#define KVM_XIVE_TIMA_PAGE_OFFSET      0
+#define KVM_XIVE_ESB_PAGE_OFFSET       4
+
 #endif /* __LINUX_KVM_POWERPC_H */
index 523bb99d7676a5ccbdb8f88338cb58dd4ae4a4ff..00682b8df3305aa16c5ede61467a33f5207978f9 100644 (file)
@@ -628,14 +628,14 @@ static int __init prom_next_node(phandle *nodep)
        }
 }
 
-static inline int prom_getprop(phandle node, const char *pname,
-                              void *value, size_t valuelen)
+static inline int __init prom_getprop(phandle node, const char *pname,
+                                     void *value, size_t valuelen)
 {
        return call_prom("getprop", 4, 1, node, ADDR(pname),
                         (u32)(unsigned long) value, (u32) valuelen);
 }
 
-static inline int prom_getproplen(phandle node, const char *pname)
+static inline int __init prom_getproplen(phandle node, const char *pname)
 {
        return call_prom("getproplen", 2, 1, node, ADDR(pname));
 }
index 00f5a63c8d9a65aefd60df95b75d9cfae1fe8493..103655d84b4b556891029bfe01d9df8beb89c443 100644 (file)
 425    common  io_uring_setup                  sys_io_uring_setup
 426    common  io_uring_enter                  sys_io_uring_enter
 427    common  io_uring_register               sys_io_uring_register
+428    common  open_tree                       sys_open_tree
+429    common  move_mount                      sys_move_mount
+430    common  fsopen                          sys_fsopen
+431    common  fsconfig                        sys_fsconfig
+432    common  fsmount                         sys_fsmount
+433    common  fspick                          sys_fspick
index e8e93c2c7d031a923bb9e983b122d98bc1c406f7..7a1708875d27d11c2de6ad45e837d1d4dc63cecc 100644 (file)
@@ -610,7 +610,7 @@ SYSFS_PMCSETUP(pa6t_pmc2, SPRN_PA6T_PMC2);
 SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3);
 SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4);
 SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5);
-#ifdef CONFIG_DEBUG_KERNEL
+#ifdef CONFIG_DEBUG_MISC
 SYSFS_SPRSETUP(hid0, SPRN_HID0);
 SYSFS_SPRSETUP(hid1, SPRN_HID1);
 SYSFS_SPRSETUP(hid4, SPRN_HID4);
@@ -639,7 +639,7 @@ SYSFS_SPRSETUP(tsr0, SPRN_PA6T_TSR0);
 SYSFS_SPRSETUP(tsr1, SPRN_PA6T_TSR1);
 SYSFS_SPRSETUP(tsr2, SPRN_PA6T_TSR2);
 SYSFS_SPRSETUP(tsr3, SPRN_PA6T_TSR3);
-#endif /* CONFIG_DEBUG_KERNEL */
+#endif /* CONFIG_DEBUG_MISC */
 #endif /* HAS_PPC_PMC_PA6T */
 
 #ifdef HAS_PPC_PMC_IBM
@@ -680,7 +680,7 @@ static struct device_attribute pa6t_attrs[] = {
        __ATTR(pmc3, 0600, show_pa6t_pmc3, store_pa6t_pmc3),
        __ATTR(pmc4, 0600, show_pa6t_pmc4, store_pa6t_pmc4),
        __ATTR(pmc5, 0600, show_pa6t_pmc5, store_pa6t_pmc5),
-#ifdef CONFIG_DEBUG_KERNEL
+#ifdef CONFIG_DEBUG_MISC
        __ATTR(hid0, 0600, show_hid0, store_hid0),
        __ATTR(hid1, 0600, show_hid1, store_hid1),
        __ATTR(hid4, 0600, show_hid4, store_hid4),
@@ -709,7 +709,7 @@ static struct device_attribute pa6t_attrs[] = {
        __ATTR(tsr1, 0600, show_tsr1, store_tsr1),
        __ATTR(tsr2, 0600, show_tsr2, store_tsr2),
        __ATTR(tsr3, 0600, show_tsr3, store_tsr3),
-#endif /* CONFIG_DEBUG_KERNEL */
+#endif /* CONFIG_DEBUG_MISC */
 };
 #endif /* HAS_PPC_PMC_PA6T */
 #endif /* HAS_PPC_PMC_CLASSIC */
index 3223aec88b2cc314c0f0b0485c1b9049f278d3d7..4c67cc79de7c853dfc81d804a2457a51adf5b72b 100644 (file)
@@ -94,7 +94,7 @@ endif
 kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \
        book3s_xics.o
 
-kvm-book3s_64-objs-$(CONFIG_KVM_XIVE) += book3s_xive.o
+kvm-book3s_64-objs-$(CONFIG_KVM_XIVE) += book3s_xive.o book3s_xive_native.o
 kvm-book3s_64-objs-$(CONFIG_SPAPR_TCE_IOMMU) += book3s_64_vio.o
 
 kvm-book3s_64-module-objs := \
index 10c5579d20cec64152946f2f703a79e2da055154..61a212d0daf023e9c0806f1ef0a101350c2a1a2f 100644 (file)
@@ -651,6 +651,18 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id,
                                *val = get_reg_val(id, kvmppc_xics_get_icp(vcpu));
                        break;
 #endif /* CONFIG_KVM_XICS */
+#ifdef CONFIG_KVM_XIVE
+               case KVM_REG_PPC_VP_STATE:
+                       if (!vcpu->arch.xive_vcpu) {
+                               r = -ENXIO;
+                               break;
+                       }
+                       if (xive_enabled())
+                               r = kvmppc_xive_native_get_vp(vcpu, val);
+                       else
+                               r = -ENXIO;
+                       break;
+#endif /* CONFIG_KVM_XIVE */
                case KVM_REG_PPC_FSCR:
                        *val = get_reg_val(id, vcpu->arch.fscr);
                        break;
@@ -724,6 +736,18 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id,
                                r = kvmppc_xics_set_icp(vcpu, set_reg_val(id, *val));
                        break;
 #endif /* CONFIG_KVM_XICS */
+#ifdef CONFIG_KVM_XIVE
+               case KVM_REG_PPC_VP_STATE:
+                       if (!vcpu->arch.xive_vcpu) {
+                               r = -ENXIO;
+                               break;
+                       }
+                       if (xive_enabled())
+                               r = kvmppc_xive_native_set_vp(vcpu, val);
+                       else
+                               r = -ENXIO;
+                       break;
+#endif /* CONFIG_KVM_XIVE */
                case KVM_REG_PPC_FSCR:
                        vcpu->arch.fscr = set_reg_val(id, *val);
                        break;
@@ -891,6 +915,17 @@ void kvmppc_core_destroy_vm(struct kvm *kvm)
        kvmppc_rtas_tokens_free(kvm);
        WARN_ON(!list_empty(&kvm->arch.spapr_tce_tables));
 #endif
+
+#ifdef CONFIG_KVM_XICS
+       /*
+        * Free the XIVE devices which are not directly freed by the
+        * device 'release' method
+        */
+       kfree(kvm->arch.xive_devices.native);
+       kvm->arch.xive_devices.native = NULL;
+       kfree(kvm->arch.xive_devices.xics_on_xive);
+       kvm->arch.xive_devices.xics_on_xive = NULL;
+#endif /* CONFIG_KVM_XICS */
 }
 
 int kvmppc_h_logical_ci_load(struct kvm_vcpu *vcpu)
@@ -1050,6 +1085,9 @@ static int kvmppc_book3s_init(void)
        if (xics_on_xive()) {
                kvmppc_xive_init_module();
                kvm_register_device_ops(&kvm_xive_ops, KVM_DEV_TYPE_XICS);
+               kvmppc_xive_native_init_module();
+               kvm_register_device_ops(&kvm_xive_native_ops,
+                                       KVM_DEV_TYPE_XIVE);
        } else
 #endif
                kvm_register_device_ops(&kvm_xics_ops, KVM_DEV_TYPE_XICS);
@@ -1060,8 +1098,10 @@ static int kvmppc_book3s_init(void)
 static void kvmppc_book3s_exit(void)
 {
 #ifdef CONFIG_KVM_XICS
-       if (xics_on_xive())
+       if (xics_on_xive()) {
                kvmppc_xive_exit_module();
+               kvmppc_xive_native_exit_module();
+       }
 #endif
 #ifdef CONFIG_KVM_BOOK3S_32_HANDLER
        kvmppc_book3s_exit_pr();
index be7bc070eae5fc701251d7d53ce7979195051f7d..ab3d484c5e2ec0b4647876bacf7d5d49e543efa8 100644 (file)
@@ -600,7 +600,7 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
        /* If writing != 0, then the HPTE must allow writing, if we get here */
        write_ok = writing;
        hva = gfn_to_hva_memslot(memslot, gfn);
-       npages = get_user_pages_fast(hva, 1, writing, pages);
+       npages = get_user_pages_fast(hva, 1, writing ? FOLL_WRITE : 0, pages);
        if (npages < 1) {
                /* Check if it's an I/O mapping */
                down_read(&current->mm->mmap_sem);
@@ -1193,7 +1193,7 @@ void *kvmppc_pin_guest_page(struct kvm *kvm, unsigned long gpa,
        if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID))
                goto err;
        hva = gfn_to_hva_memslot(memslot, gfn);
-       npages = get_user_pages_fast(hva, 1, 1, pages);
+       npages = get_user_pages_fast(hva, 1, FOLL_WRITE, pages);
        if (npages < 1)
                goto err;
        page = pages[0];
index f100e331e69b6ad37f5f6323219ada40fe8c8641..66270e07449adcbd19f0480d5e2f708a7cd5a51d 100644 (file)
@@ -228,11 +228,33 @@ static void release_spapr_tce_table(struct rcu_head *head)
        unsigned long i, npages = kvmppc_tce_pages(stt->size);
 
        for (i = 0; i < npages; i++)
-               __free_page(stt->pages[i]);
+               if (stt->pages[i])
+                       __free_page(stt->pages[i]);
 
        kfree(stt);
 }
 
+static struct page *kvm_spapr_get_tce_page(struct kvmppc_spapr_tce_table *stt,
+               unsigned long sttpage)
+{
+       struct page *page = stt->pages[sttpage];
+
+       if (page)
+               return page;
+
+       mutex_lock(&stt->alloc_lock);
+       page = stt->pages[sttpage];
+       if (!page) {
+               page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+               WARN_ON_ONCE(!page);
+               if (page)
+                       stt->pages[sttpage] = page;
+       }
+       mutex_unlock(&stt->alloc_lock);
+
+       return page;
+}
+
 static vm_fault_t kvm_spapr_tce_fault(struct vm_fault *vmf)
 {
        struct kvmppc_spapr_tce_table *stt = vmf->vma->vm_file->private_data;
@@ -241,7 +263,10 @@ static vm_fault_t kvm_spapr_tce_fault(struct vm_fault *vmf)
        if (vmf->pgoff >= kvmppc_tce_pages(stt->size))
                return VM_FAULT_SIGBUS;
 
-       page = stt->pages[vmf->pgoff];
+       page = kvm_spapr_get_tce_page(stt, vmf->pgoff);
+       if (!page)
+               return VM_FAULT_OOM;
+
        get_page(page);
        vmf->page = page;
        return 0;
@@ -296,7 +321,6 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
        struct kvmppc_spapr_tce_table *siter;
        unsigned long npages, size = args->size;
        int ret = -ENOMEM;
-       int i;
 
        if (!args->size || args->page_shift < 12 || args->page_shift > 34 ||
                (args->offset + args->size > (ULLONG_MAX >> args->page_shift)))
@@ -318,14 +342,9 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
        stt->offset = args->offset;
        stt->size = size;
        stt->kvm = kvm;
+       mutex_init(&stt->alloc_lock);
        INIT_LIST_HEAD_RCU(&stt->iommu_tables);
 
-       for (i = 0; i < npages; i++) {
-               stt->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
-               if (!stt->pages[i])
-                       goto fail;
-       }
-
        mutex_lock(&kvm->lock);
 
        /* Check this LIOBN hasn't been previously allocated */
@@ -352,17 +371,28 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
        if (ret >= 0)
                return ret;
 
- fail:
-       for (i = 0; i < npages; i++)
-               if (stt->pages[i])
-                       __free_page(stt->pages[i]);
-
        kfree(stt);
  fail_acct:
        kvmppc_account_memlimit(kvmppc_stt_pages(npages), false);
        return ret;
 }
 
+static long kvmppc_tce_to_ua(struct kvm *kvm, unsigned long tce,
+               unsigned long *ua)
+{
+       unsigned long gfn = tce >> PAGE_SHIFT;
+       struct kvm_memory_slot *memslot;
+
+       memslot = search_memslots(kvm_memslots(kvm), gfn);
+       if (!memslot)
+               return -EINVAL;
+
+       *ua = __gfn_to_hva_memslot(memslot, gfn) |
+               (tce & ~(PAGE_MASK | TCE_PCI_READ | TCE_PCI_WRITE));
+
+       return 0;
+}
+
 static long kvmppc_tce_validate(struct kvmppc_spapr_tce_table *stt,
                unsigned long tce)
 {
@@ -378,7 +408,7 @@ static long kvmppc_tce_validate(struct kvmppc_spapr_tce_table *stt,
        if (iommu_tce_check_gpa(stt->page_shift, gpa))
                return H_TOO_HARD;
 
-       if (kvmppc_tce_to_ua(stt->kvm, tce, &ua, NULL))
+       if (kvmppc_tce_to_ua(stt->kvm, tce, &ua))
                return H_TOO_HARD;
 
        list_for_each_entry_rcu(stit, &stt->iommu_tables, next) {
@@ -397,6 +427,36 @@ static long kvmppc_tce_validate(struct kvmppc_spapr_tce_table *stt,
        return H_SUCCESS;
 }
 
+/*
+ * Handles TCE requests for emulated devices.
+ * Puts guest TCE values to the table and expects user space to convert them.
+ * Cannot fail so kvmppc_tce_validate must be called before it.
+ */
+static void kvmppc_tce_put(struct kvmppc_spapr_tce_table *stt,
+               unsigned long idx, unsigned long tce)
+{
+       struct page *page;
+       u64 *tbl;
+       unsigned long sttpage;
+
+       idx -= stt->offset;
+       sttpage = idx / TCES_PER_PAGE;
+       page = stt->pages[sttpage];
+
+       if (!page) {
+               /* We allow any TCE, not just with read|write permissions */
+               if (!tce)
+                       return;
+
+               page = kvm_spapr_get_tce_page(stt, sttpage);
+               if (!page)
+                       return;
+       }
+       tbl = page_to_virt(page);
+
+       tbl[idx % TCES_PER_PAGE] = tce;
+}
+
 static void kvmppc_clear_tce(struct mm_struct *mm, struct iommu_table *tbl,
                unsigned long entry)
 {
@@ -551,7 +611,7 @@ long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
 
        dir = iommu_tce_direction(tce);
 
-       if ((dir != DMA_NONE) && kvmppc_tce_to_ua(vcpu->kvm, tce, &ua, NULL)) {
+       if ((dir != DMA_NONE) && kvmppc_tce_to_ua(vcpu->kvm, tce, &ua)) {
                ret = H_PARAMETER;
                goto unlock_exit;
        }
@@ -612,7 +672,7 @@ long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu,
                return ret;
 
        idx = srcu_read_lock(&vcpu->kvm->srcu);
-       if (kvmppc_tce_to_ua(vcpu->kvm, tce_list, &ua, NULL)) {
+       if (kvmppc_tce_to_ua(vcpu->kvm, tce_list, &ua)) {
                ret = H_TOO_HARD;
                goto unlock_exit;
        }
@@ -647,7 +707,7 @@ long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu,
                }
                tce = be64_to_cpu(tce);
 
-               if (kvmppc_tce_to_ua(vcpu->kvm, tce, &ua, NULL))
+               if (kvmppc_tce_to_ua(vcpu->kvm, tce, &ua))
                        return H_PARAMETER;
 
                list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
index 2206bc729b9a07c4c0715af3fbabc916f7e13a72..484b47fa3960b89b9672f9e58a00866b2892b8fe 100644 (file)
@@ -66,8 +66,6 @@
 
 #endif
 
-#define TCES_PER_PAGE  (PAGE_SIZE / sizeof(u64))
-
 /*
  * Finds a TCE table descriptor by LIOBN.
  *
@@ -88,6 +86,25 @@ struct kvmppc_spapr_tce_table *kvmppc_find_table(struct kvm *kvm,
 EXPORT_SYMBOL_GPL(kvmppc_find_table);
 
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+static long kvmppc_rm_tce_to_ua(struct kvm *kvm, unsigned long tce,
+               unsigned long *ua, unsigned long **prmap)
+{
+       unsigned long gfn = tce >> PAGE_SHIFT;
+       struct kvm_memory_slot *memslot;
+
+       memslot = search_memslots(kvm_memslots_raw(kvm), gfn);
+       if (!memslot)
+               return -EINVAL;
+
+       *ua = __gfn_to_hva_memslot(memslot, gfn) |
+               (tce & ~(PAGE_MASK | TCE_PCI_READ | TCE_PCI_WRITE));
+
+       if (prmap)
+               *prmap = &memslot->arch.rmap[gfn - memslot->base_gfn];
+
+       return 0;
+}
+
 /*
  * Validates TCE address.
  * At the moment flags and page mask are validated.
@@ -111,7 +128,7 @@ static long kvmppc_rm_tce_validate(struct kvmppc_spapr_tce_table *stt,
        if (iommu_tce_check_gpa(stt->page_shift, gpa))
                return H_PARAMETER;
 
-       if (kvmppc_tce_to_ua(stt->kvm, tce, &ua, NULL))
+       if (kvmppc_rm_tce_to_ua(stt->kvm, tce, &ua, NULL))
                return H_TOO_HARD;
 
        list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
@@ -129,7 +146,6 @@ static long kvmppc_rm_tce_validate(struct kvmppc_spapr_tce_table *stt,
 
        return H_SUCCESS;
 }
-#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
 
 /* Note on the use of page_address() in real mode,
  *
@@ -161,13 +177,9 @@ static u64 *kvmppc_page_address(struct page *page)
 /*
  * Handles TCE requests for emulated devices.
  * Puts guest TCE values to the table and expects user space to convert them.
- * Called in both real and virtual modes.
- * Cannot fail so kvmppc_tce_validate must be called before it.
- *
- * WARNING: This will be called in real-mode on HV KVM and virtual
- *          mode on PR KVM
+ * Cannot fail so kvmppc_rm_tce_validate must be called before it.
  */
-void kvmppc_tce_put(struct kvmppc_spapr_tce_table *stt,
+static void kvmppc_rm_tce_put(struct kvmppc_spapr_tce_table *stt,
                unsigned long idx, unsigned long tce)
 {
        struct page *page;
@@ -175,35 +187,48 @@ void kvmppc_tce_put(struct kvmppc_spapr_tce_table *stt,
 
        idx -= stt->offset;
        page = stt->pages[idx / TCES_PER_PAGE];
+       /*
+        * page must not be NULL in real mode,
+        * kvmppc_rm_ioba_validate() must have taken care of this.
+        */
+       WARN_ON_ONCE_RM(!page);
        tbl = kvmppc_page_address(page);
 
        tbl[idx % TCES_PER_PAGE] = tce;
 }
-EXPORT_SYMBOL_GPL(kvmppc_tce_put);
 
-long kvmppc_tce_to_ua(struct kvm *kvm, unsigned long tce,
-               unsigned long *ua, unsigned long **prmap)
+/*
+ * TCEs pages are allocated in kvmppc_rm_tce_put() which won't be able to do so
+ * in real mode.
+ * Check if kvmppc_rm_tce_put() can succeed in real mode, i.e. a TCEs page is
+ * allocated or not required (when clearing a tce entry).
+ */
+static long kvmppc_rm_ioba_validate(struct kvmppc_spapr_tce_table *stt,
+               unsigned long ioba, unsigned long npages, bool clearing)
 {
-       unsigned long gfn = tce >> PAGE_SHIFT;
-       struct kvm_memory_slot *memslot;
+       unsigned long i, idx, sttpage, sttpages;
+       unsigned long ret = kvmppc_ioba_validate(stt, ioba, npages);
 
-       memslot = search_memslots(kvm_memslots(kvm), gfn);
-       if (!memslot)
-               return -EINVAL;
-
-       *ua = __gfn_to_hva_memslot(memslot, gfn) |
-               (tce & ~(PAGE_MASK | TCE_PCI_READ | TCE_PCI_WRITE));
+       if (ret)
+               return ret;
+       /*
+        * clearing==true says kvmppc_rm_tce_put won't be allocating pages
+        * for empty tces.
+        */
+       if (clearing)
+               return H_SUCCESS;
 
-#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
-       if (prmap)
-               *prmap = &memslot->arch.rmap[gfn - memslot->base_gfn];
-#endif
+       idx = (ioba >> stt->page_shift) - stt->offset;
+       sttpage = idx / TCES_PER_PAGE;
+       sttpages = _ALIGN_UP(idx % TCES_PER_PAGE + npages, TCES_PER_PAGE) /
+                       TCES_PER_PAGE;
+       for (i = sttpage; i < sttpage + sttpages; ++i)
+               if (!stt->pages[i])
+                       return H_TOO_HARD;
 
-       return 0;
+       return H_SUCCESS;
 }
-EXPORT_SYMBOL_GPL(kvmppc_tce_to_ua);
 
-#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
 static long iommu_tce_xchg_rm(struct mm_struct *mm, struct iommu_table *tbl,
                unsigned long entry, unsigned long *hpa,
                enum dma_data_direction *direction)
@@ -381,7 +406,7 @@ long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
        if (!stt)
                return H_TOO_HARD;
 
-       ret = kvmppc_ioba_validate(stt, ioba, 1);
+       ret = kvmppc_rm_ioba_validate(stt, ioba, 1, tce == 0);
        if (ret != H_SUCCESS)
                return ret;
 
@@ -390,7 +415,7 @@ long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
                return ret;
 
        dir = iommu_tce_direction(tce);
-       if ((dir != DMA_NONE) && kvmppc_tce_to_ua(vcpu->kvm, tce, &ua, NULL))
+       if ((dir != DMA_NONE) && kvmppc_rm_tce_to_ua(vcpu->kvm, tce, &ua, NULL))
                return H_PARAMETER;
 
        entry = ioba >> stt->page_shift;
@@ -409,7 +434,7 @@ long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
                }
        }
 
-       kvmppc_tce_put(stt, entry, tce);
+       kvmppc_rm_tce_put(stt, entry, tce);
 
        return H_SUCCESS;
 }
@@ -480,7 +505,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu,
        if (tce_list & (SZ_4K - 1))
                return H_PARAMETER;
 
-       ret = kvmppc_ioba_validate(stt, ioba, npages);
+       ret = kvmppc_rm_ioba_validate(stt, ioba, npages, false);
        if (ret != H_SUCCESS)
                return ret;
 
@@ -492,7 +517,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu,
                 */
                struct mm_iommu_table_group_mem_t *mem;
 
-               if (kvmppc_tce_to_ua(vcpu->kvm, tce_list, &ua, NULL))
+               if (kvmppc_rm_tce_to_ua(vcpu->kvm, tce_list, &ua, NULL))
                        return H_TOO_HARD;
 
                mem = mm_iommu_lookup_rm(vcpu->kvm->mm, ua, IOMMU_PAGE_SIZE_4K);
@@ -508,7 +533,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu,
                 * We do not require memory to be preregistered in this case
                 * so lock rmap and do __find_linux_pte_or_hugepte().
                 */
-               if (kvmppc_tce_to_ua(vcpu->kvm, tce_list, &ua, &rmap))
+               if (kvmppc_rm_tce_to_ua(vcpu->kvm, tce_list, &ua, &rmap))
                        return H_TOO_HARD;
 
                rmap = (void *) vmalloc_to_phys(rmap);
@@ -542,7 +567,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu,
                unsigned long tce = be64_to_cpu(((u64 *)tces)[i]);
 
                ua = 0;
-               if (kvmppc_tce_to_ua(vcpu->kvm, tce, &ua, NULL))
+               if (kvmppc_rm_tce_to_ua(vcpu->kvm, tce, &ua, NULL))
                        return H_PARAMETER;
 
                list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
@@ -557,7 +582,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu,
                        }
                }
 
-               kvmppc_tce_put(stt, entry + i, tce);
+               kvmppc_rm_tce_put(stt, entry + i, tce);
        }
 
 unlock_exit:
@@ -583,7 +608,7 @@ long kvmppc_rm_h_stuff_tce(struct kvm_vcpu *vcpu,
        if (!stt)
                return H_TOO_HARD;
 
-       ret = kvmppc_ioba_validate(stt, ioba, npages);
+       ret = kvmppc_rm_ioba_validate(stt, ioba, npages, tce_value == 0);
        if (ret != H_SUCCESS)
                return ret;
 
@@ -610,7 +635,7 @@ long kvmppc_rm_h_stuff_tce(struct kvm_vcpu *vcpu,
        }
 
        for (i = 0; i < npages; ++i, ioba += (1ULL << stt->page_shift))
-               kvmppc_tce_put(stt, ioba >> stt->page_shift, tce_value);
+               kvmppc_rm_tce_put(stt, ioba >> stt->page_shift, tce_value);
 
        return H_SUCCESS;
 }
@@ -635,6 +660,10 @@ long kvmppc_h_get_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
 
        idx = (ioba >> stt->page_shift) - stt->offset;
        page = stt->pages[idx / TCES_PER_PAGE];
+       if (!page) {
+               vcpu->arch.regs.gpr[4] = 0;
+               return H_SUCCESS;
+       }
        tbl = (u64 *)page_address(page);
 
        vcpu->arch.regs.gpr[4] = tbl[idx % TCES_PER_PAGE];
index 7bdcd4d7a9f0297c36874cb4bd92edc30f5d777c..d5fc624e0655073d8570869b8f101d536fd21740 100644 (file)
@@ -750,7 +750,7 @@ static bool kvmppc_doorbell_pending(struct kvm_vcpu *vcpu)
        /*
         * Ensure that the read of vcore->dpdes comes after the read
         * of vcpu->doorbell_request.  This barrier matches the
-        * smb_wmb() in kvmppc_guest_entry_inject().
+        * smp_wmb() in kvmppc_guest_entry_inject().
         */
        smp_rmb();
        vc = vcpu->arch.vcore;
@@ -802,6 +802,80 @@ static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags,
        }
 }
 
+/* Copy guest memory in place - must reside within a single memslot */
+static int kvmppc_copy_guest(struct kvm *kvm, gpa_t to, gpa_t from,
+                                 unsigned long len)
+{
+       struct kvm_memory_slot *to_memslot = NULL;
+       struct kvm_memory_slot *from_memslot = NULL;
+       unsigned long to_addr, from_addr;
+       int r;
+
+       /* Get HPA for from address */
+       from_memslot = gfn_to_memslot(kvm, from >> PAGE_SHIFT);
+       if (!from_memslot)
+               return -EFAULT;
+       if ((from + len) >= ((from_memslot->base_gfn + from_memslot->npages)
+                            << PAGE_SHIFT))
+               return -EINVAL;
+       from_addr = gfn_to_hva_memslot(from_memslot, from >> PAGE_SHIFT);
+       if (kvm_is_error_hva(from_addr))
+               return -EFAULT;
+       from_addr |= (from & (PAGE_SIZE - 1));
+
+       /* Get HPA for to address */
+       to_memslot = gfn_to_memslot(kvm, to >> PAGE_SHIFT);
+       if (!to_memslot)
+               return -EFAULT;
+       if ((to + len) >= ((to_memslot->base_gfn + to_memslot->npages)
+                          << PAGE_SHIFT))
+               return -EINVAL;
+       to_addr = gfn_to_hva_memslot(to_memslot, to >> PAGE_SHIFT);
+       if (kvm_is_error_hva(to_addr))
+               return -EFAULT;
+       to_addr |= (to & (PAGE_SIZE - 1));
+
+       /* Perform copy */
+       r = raw_copy_in_user((void __user *)to_addr, (void __user *)from_addr,
+                            len);
+       if (r)
+               return -EFAULT;
+       mark_page_dirty(kvm, to >> PAGE_SHIFT);
+       return 0;
+}
+
+static long kvmppc_h_page_init(struct kvm_vcpu *vcpu, unsigned long flags,
+                              unsigned long dest, unsigned long src)
+{
+       u64 pg_sz = SZ_4K;              /* 4K page size */
+       u64 pg_mask = SZ_4K - 1;
+       int ret;
+
+       /* Check for invalid flags (H_PAGE_SET_LOANED covers all CMO flags) */
+       if (flags & ~(H_ICACHE_INVALIDATE | H_ICACHE_SYNCHRONIZE |
+                     H_ZERO_PAGE | H_COPY_PAGE | H_PAGE_SET_LOANED))
+               return H_PARAMETER;
+
+       /* dest (and src if copy_page flag set) must be page aligned */
+       if ((dest & pg_mask) || ((flags & H_COPY_PAGE) && (src & pg_mask)))
+               return H_PARAMETER;
+
+       /* zero and/or copy the page as determined by the flags */
+       if (flags & H_COPY_PAGE) {
+               ret = kvmppc_copy_guest(vcpu->kvm, dest, src, pg_sz);
+               if (ret < 0)
+                       return H_PARAMETER;
+       } else if (flags & H_ZERO_PAGE) {
+               ret = kvm_clear_guest(vcpu->kvm, dest, pg_sz);
+               if (ret < 0)
+                       return H_PARAMETER;
+       }
+
+       /* We can ignore the remaining flags */
+
+       return H_SUCCESS;
+}
+
 static int kvm_arch_vcpu_yield_to(struct kvm_vcpu *target)
 {
        struct kvmppc_vcore *vcore = target->arch.vcore;
@@ -1004,6 +1078,11 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
                if (nesting_enabled(vcpu->kvm))
                        ret = kvmhv_copy_tofrom_guest_nested(vcpu);
                break;
+       case H_PAGE_INIT:
+               ret = kvmppc_h_page_init(vcpu, kvmppc_get_gpr(vcpu, 4),
+                                        kvmppc_get_gpr(vcpu, 5),
+                                        kvmppc_get_gpr(vcpu, 6));
+               break;
        default:
                return RESUME_HOST;
        }
@@ -1048,6 +1127,7 @@ static int kvmppc_hcall_impl_hv(unsigned long cmd)
        case H_IPOLL:
        case H_XIRR_X:
 #endif
+       case H_PAGE_INIT:
                return 1;
        }
 
@@ -2505,37 +2585,6 @@ static void kvmppc_prepare_radix_vcpu(struct kvm_vcpu *vcpu, int pcpu)
        }
 }
 
-static void kvmppc_radix_check_need_tlb_flush(struct kvm *kvm, int pcpu,
-                                             struct kvm_nested_guest *nested)
-{
-       cpumask_t *need_tlb_flush;
-       int lpid;
-
-       if (!cpu_has_feature(CPU_FTR_HVMODE))
-               return;
-
-       if (cpu_has_feature(CPU_FTR_ARCH_300))
-               pcpu &= ~0x3UL;
-
-       if (nested) {
-               lpid = nested->shadow_lpid;
-               need_tlb_flush = &nested->need_tlb_flush;
-       } else {
-               lpid = kvm->arch.lpid;
-               need_tlb_flush = &kvm->arch.need_tlb_flush;
-       }
-
-       mtspr(SPRN_LPID, lpid);
-       isync();
-       smp_mb();
-
-       if (cpumask_test_cpu(pcpu, need_tlb_flush)) {
-               radix__local_flush_tlb_lpid_guest(lpid);
-               /* Clear the bit after the TLB flush */
-               cpumask_clear_cpu(pcpu, need_tlb_flush);
-       }
-}
-
 static void kvmppc_start_thread(struct kvm_vcpu *vcpu, struct kvmppc_vcore *vc)
 {
        int cpu;
@@ -3229,19 +3278,11 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
        for (sub = 0; sub < core_info.n_subcores; ++sub)
                spin_unlock(&core_info.vc[sub]->lock);
 
-       if (kvm_is_radix(vc->kvm)) {
-               /*
-                * Do we need to flush the process scoped TLB for the LPAR?
-                *
-                * On POWER9, individual threads can come in here, but the
-                * TLB is shared between the 4 threads in a core, hence
-                * invalidating on one thread invalidates for all.
-                * Thus we make all 4 threads use the same bit here.
-                *
-                * Hash must be flushed in realmode in order to use tlbiel.
-                */
-               kvmppc_radix_check_need_tlb_flush(vc->kvm, pcpu, NULL);
-       }
+       guest_enter_irqoff();
+
+       srcu_idx = srcu_read_lock(&vc->kvm->srcu);
+
+       this_cpu_disable_ftrace();
 
        /*
         * Interrupts will be enabled once we get into the guest,
@@ -3249,19 +3290,14 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
         */
        trace_hardirqs_on();
 
-       guest_enter_irqoff();
-
-       srcu_idx = srcu_read_lock(&vc->kvm->srcu);
-
-       this_cpu_disable_ftrace();
-
        trap = __kvmppc_vcore_entry();
 
+       trace_hardirqs_off();
+
        this_cpu_enable_ftrace();
 
        srcu_read_unlock(&vc->kvm->srcu, srcu_idx);
 
-       trace_hardirqs_off();
        set_irq_happened(trap);
 
        spin_lock(&vc->lock);
@@ -3514,6 +3550,7 @@ int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
 #ifdef CONFIG_ALTIVEC
        load_vr_state(&vcpu->arch.vr);
 #endif
+       mtspr(SPRN_VRSAVE, vcpu->arch.vrsave);
 
        mtspr(SPRN_DSCR, vcpu->arch.dscr);
        mtspr(SPRN_IAMR, vcpu->arch.iamr);
@@ -3605,6 +3642,7 @@ int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
 #ifdef CONFIG_ALTIVEC
        store_vr_state(&vcpu->arch.vr);
 #endif
+       vcpu->arch.vrsave = mfspr(SPRN_VRSAVE);
 
        if (cpu_has_feature(CPU_FTR_TM) ||
            cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST))
@@ -3970,7 +4008,7 @@ int kvmhv_run_single_vcpu(struct kvm_run *kvm_run,
                          unsigned long lpcr)
 {
        int trap, r, pcpu;
-       int srcu_idx;
+       int srcu_idx, lpid;
        struct kvmppc_vcore *vc;
        struct kvm *kvm = vcpu->kvm;
        struct kvm_nested_guest *nested = vcpu->arch.nested;
@@ -4046,8 +4084,12 @@ int kvmhv_run_single_vcpu(struct kvm_run *kvm_run,
        vc->vcore_state = VCORE_RUNNING;
        trace_kvmppc_run_core(vc, 0);
 
-       if (cpu_has_feature(CPU_FTR_HVMODE))
-               kvmppc_radix_check_need_tlb_flush(kvm, pcpu, nested);
+       if (cpu_has_feature(CPU_FTR_HVMODE)) {
+               lpid = nested ? nested->shadow_lpid : kvm->arch.lpid;
+               mtspr(SPRN_LPID, lpid);
+               isync();
+               kvmppc_check_need_tlb_flush(kvm, pcpu, nested);
+       }
 
        trace_hardirqs_on();
        guest_enter_irqoff();
index b0cf22477e879b74ce4c0fa771d0deabb6c54af7..6035d24f1d1d45d3711a02fe7fd274d79bd89dc4 100644 (file)
@@ -805,3 +805,60 @@ void kvmppc_guest_entry_inject_int(struct kvm_vcpu *vcpu)
                vcpu->arch.doorbell_request = 0;
        }
 }
+
+static void flush_guest_tlb(struct kvm *kvm)
+{
+       unsigned long rb, set;
+
+       rb = PPC_BIT(52);       /* IS = 2 */
+       if (kvm_is_radix(kvm)) {
+               /* R=1 PRS=1 RIC=2 */
+               asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
+                            : : "r" (rb), "i" (1), "i" (1), "i" (2),
+                              "r" (0) : "memory");
+               for (set = 1; set < kvm->arch.tlb_sets; ++set) {
+                       rb += PPC_BIT(51);      /* increment set number */
+                       /* R=1 PRS=1 RIC=0 */
+                       asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
+                                    : : "r" (rb), "i" (1), "i" (1), "i" (0),
+                                      "r" (0) : "memory");
+               }
+       } else {
+               for (set = 0; set < kvm->arch.tlb_sets; ++set) {
+                       /* R=0 PRS=0 RIC=0 */
+                       asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
+                                    : : "r" (rb), "i" (0), "i" (0), "i" (0),
+                                      "r" (0) : "memory");
+                       rb += PPC_BIT(51);      /* increment set number */
+               }
+       }
+       asm volatile("ptesync": : :"memory");
+}
+
+void kvmppc_check_need_tlb_flush(struct kvm *kvm, int pcpu,
+                                struct kvm_nested_guest *nested)
+{
+       cpumask_t *need_tlb_flush;
+
+       /*
+        * On POWER9, individual threads can come in here, but the
+        * TLB is shared between the 4 threads in a core, hence
+        * invalidating on one thread invalidates for all.
+        * Thus we make all 4 threads use the same bit.
+        */
+       if (cpu_has_feature(CPU_FTR_ARCH_300))
+               pcpu = cpu_first_thread_sibling(pcpu);
+
+       if (nested)
+               need_tlb_flush = &nested->need_tlb_flush;
+       else
+               need_tlb_flush = &kvm->arch.need_tlb_flush;
+
+       if (cpumask_test_cpu(pcpu, need_tlb_flush)) {
+               flush_guest_tlb(kvm);
+
+               /* Clear the bit after the TLB flush */
+               cpumask_clear_cpu(pcpu, need_tlb_flush);
+       }
+}
+EXPORT_SYMBOL_GPL(kvmppc_check_need_tlb_flush);
index 3b3791ed74a6756315080be96f4085f1a9c7cd9b..8431ad1e83919051b315be36834201cbb5c01e96 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/hugetlb.h>
 #include <linux/module.h>
 #include <linux/log2.h>
+#include <linux/sizes.h>
 
 #include <asm/trace.h>
 #include <asm/kvm_ppc.h>
@@ -867,6 +868,149 @@ long kvmppc_h_clear_mod(struct kvm_vcpu *vcpu, unsigned long flags,
        return ret;
 }
 
+static int kvmppc_get_hpa(struct kvm_vcpu *vcpu, unsigned long gpa,
+                         int writing, unsigned long *hpa,
+                         struct kvm_memory_slot **memslot_p)
+{
+       struct kvm *kvm = vcpu->kvm;
+       struct kvm_memory_slot *memslot;
+       unsigned long gfn, hva, pa, psize = PAGE_SHIFT;
+       unsigned int shift;
+       pte_t *ptep, pte;
+
+       /* Find the memslot for this address */
+       gfn = gpa >> PAGE_SHIFT;
+       memslot = __gfn_to_memslot(kvm_memslots_raw(kvm), gfn);
+       if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID))
+               return H_PARAMETER;
+
+       /* Translate to host virtual address */
+       hva = __gfn_to_hva_memslot(memslot, gfn);
+
+       /* Try to find the host pte for that virtual address */
+       ptep = __find_linux_pte(vcpu->arch.pgdir, hva, NULL, &shift);
+       if (!ptep)
+               return H_TOO_HARD;
+       pte = kvmppc_read_update_linux_pte(ptep, writing);
+       if (!pte_present(pte))
+               return H_TOO_HARD;
+
+       /* Convert to a physical address */
+       if (shift)
+               psize = 1UL << shift;
+       pa = pte_pfn(pte) << PAGE_SHIFT;
+       pa |= hva & (psize - 1);
+       pa |= gpa & ~PAGE_MASK;
+
+       if (hpa)
+               *hpa = pa;
+       if (memslot_p)
+               *memslot_p = memslot;
+
+       return H_SUCCESS;
+}
+
+static long kvmppc_do_h_page_init_zero(struct kvm_vcpu *vcpu,
+                                      unsigned long dest)
+{
+       struct kvm_memory_slot *memslot;
+       struct kvm *kvm = vcpu->kvm;
+       unsigned long pa, mmu_seq;
+       long ret = H_SUCCESS;
+       int i;
+
+       /* Used later to detect if we might have been invalidated */
+       mmu_seq = kvm->mmu_notifier_seq;
+       smp_rmb();
+
+       ret = kvmppc_get_hpa(vcpu, dest, 1, &pa, &memslot);
+       if (ret != H_SUCCESS)
+               return ret;
+
+       /* Check if we've been invalidated */
+       raw_spin_lock(&kvm->mmu_lock.rlock);
+       if (mmu_notifier_retry(kvm, mmu_seq)) {
+               ret = H_TOO_HARD;
+               goto out_unlock;
+       }
+
+       /* Zero the page */
+       for (i = 0; i < SZ_4K; i += L1_CACHE_BYTES, pa += L1_CACHE_BYTES)
+               dcbz((void *)pa);
+       kvmppc_update_dirty_map(memslot, dest >> PAGE_SHIFT, PAGE_SIZE);
+
+out_unlock:
+       raw_spin_unlock(&kvm->mmu_lock.rlock);
+       return ret;
+}
+
+static long kvmppc_do_h_page_init_copy(struct kvm_vcpu *vcpu,
+                                      unsigned long dest, unsigned long src)
+{
+       unsigned long dest_pa, src_pa, mmu_seq;
+       struct kvm_memory_slot *dest_memslot;
+       struct kvm *kvm = vcpu->kvm;
+       long ret = H_SUCCESS;
+
+       /* Used later to detect if we might have been invalidated */
+       mmu_seq = kvm->mmu_notifier_seq;
+       smp_rmb();
+
+       ret = kvmppc_get_hpa(vcpu, dest, 1, &dest_pa, &dest_memslot);
+       if (ret != H_SUCCESS)
+               return ret;
+       ret = kvmppc_get_hpa(vcpu, src, 0, &src_pa, NULL);
+       if (ret != H_SUCCESS)
+               return ret;
+
+       /* Check if we've been invalidated */
+       raw_spin_lock(&kvm->mmu_lock.rlock);
+       if (mmu_notifier_retry(kvm, mmu_seq)) {
+               ret = H_TOO_HARD;
+               goto out_unlock;
+       }
+
+       /* Copy the page */
+       memcpy((void *)dest_pa, (void *)src_pa, SZ_4K);
+
+       kvmppc_update_dirty_map(dest_memslot, dest >> PAGE_SHIFT, PAGE_SIZE);
+
+out_unlock:
+       raw_spin_unlock(&kvm->mmu_lock.rlock);
+       return ret;
+}
+
+long kvmppc_rm_h_page_init(struct kvm_vcpu *vcpu, unsigned long flags,
+                          unsigned long dest, unsigned long src)
+{
+       struct kvm *kvm = vcpu->kvm;
+       u64 pg_mask = SZ_4K - 1;        /* 4K page size */
+       long ret = H_SUCCESS;
+
+       /* Don't handle radix mode here, go up to the virtual mode handler */
+       if (kvm_is_radix(kvm))
+               return H_TOO_HARD;
+
+       /* Check for invalid flags (H_PAGE_SET_LOANED covers all CMO flags) */
+       if (flags & ~(H_ICACHE_INVALIDATE | H_ICACHE_SYNCHRONIZE |
+                     H_ZERO_PAGE | H_COPY_PAGE | H_PAGE_SET_LOANED))
+               return H_PARAMETER;
+
+       /* dest (and src if copy_page flag set) must be page aligned */
+       if ((dest & pg_mask) || ((flags & H_COPY_PAGE) && (src & pg_mask)))
+               return H_PARAMETER;
+
+       /* zero and/or copy the page as determined by the flags */
+       if (flags & H_COPY_PAGE)
+               ret = kvmppc_do_h_page_init_copy(vcpu, dest, src);
+       else if (flags & H_ZERO_PAGE)
+               ret = kvmppc_do_h_page_init_zero(vcpu, dest);
+
+       /* We can ignore the other flags */
+
+       return ret;
+}
+
 void kvmppc_invalidate_hpte(struct kvm *kvm, __be64 *hptep,
                        unsigned long pte_index)
 {
index dd014308f06507e7a8cc1fb5229cc82b0ebec554..f9b2620fbecd46f481e2692fbc41db1c7e6bc950 100644 (file)
@@ -589,11 +589,8 @@ kvmppc_hv_entry:
 1:
 #endif
 
-       /* Use cr7 as an indication of radix mode */
        ld      r5, HSTATE_KVM_VCORE(r13)
        ld      r9, VCORE_KVM(r5)       /* pointer to struct kvm */
-       lbz     r0, KVM_RADIX(r9)
-       cmpwi   cr7, r0, 0
 
        /*
         * POWER7/POWER8 host -> guest partition switch code.
@@ -616,9 +613,6 @@ kvmppc_hv_entry:
        cmpwi   r6,0
        bne     10f
 
-       /* Radix has already switched LPID and flushed core TLB */
-       bne     cr7, 22f
-
        lwz     r7,KVM_LPID(r9)
 BEGIN_FTR_SECTION
        ld      r6,KVM_SDR1(r9)
@@ -630,41 +624,13 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
        mtspr   SPRN_LPID,r7
        isync
 
-       /* See if we need to flush the TLB. Hash has to be done in RM */
-       lhz     r6,PACAPACAINDEX(r13)   /* test_bit(cpu, need_tlb_flush) */
-BEGIN_FTR_SECTION
-       /*
-        * On POWER9, individual threads can come in here, but the
-        * TLB is shared between the 4 threads in a core, hence
-        * invalidating on one thread invalidates for all.
-        * Thus we make all 4 threads use the same bit here.
-        */
-       clrrdi  r6,r6,2
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
-       clrldi  r7,r6,64-6              /* extract bit number (6 bits) */
-       srdi    r6,r6,6                 /* doubleword number */
-       sldi    r6,r6,3                 /* address offset */
-       add     r6,r6,r9
-       addi    r6,r6,KVM_NEED_FLUSH    /* dword in kvm->arch.need_tlb_flush */
-       li      r8,1
-       sld     r8,r8,r7
-       ld      r7,0(r6)
-       and.    r7,r7,r8
-       beq     22f
-       /* Flush the TLB of any entries for this LPID */
-       lwz     r0,KVM_TLB_SETS(r9)
-       mtctr   r0
-       li      r7,0x800                /* IS field = 0b10 */
-       ptesync
-       li      r0,0                    /* RS for P9 version of tlbiel */
-28:    tlbiel  r7                      /* On P9, rs=0, RIC=0, PRS=0, R=0 */
-       addi    r7,r7,0x1000
-       bdnz    28b
-       ptesync
-23:    ldarx   r7,0,r6                 /* clear the bit after TLB flushed */
-       andc    r7,r7,r8
-       stdcx.  r7,0,r6
-       bne     23b
+       /* See if we need to flush the TLB. */
+       mr      r3, r9                  /* kvm pointer */
+       lhz     r4, PACAPACAINDEX(r13)  /* physical cpu number */
+       li      r5, 0                   /* nested vcpu pointer */
+       bl      kvmppc_check_need_tlb_flush
+       nop
+       ld      r5, HSTATE_KVM_VCORE(r13)
 
        /* Add timebase offset onto timebase */
 22:    ld      r8,VCORE_TB_OFFSET(r5)
@@ -980,17 +946,27 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_300)
 
 #ifdef CONFIG_KVM_XICS
        /* We are entering the guest on that thread, push VCPU to XIVE */
-       ld      r10, HSTATE_XIVE_TIMA_PHYS(r13)
-       cmpldi  cr0, r10, 0
-       beq     no_xive
        ld      r11, VCPU_XIVE_SAVED_STATE(r4)
        li      r9, TM_QW1_OS
+       lwz     r8, VCPU_XIVE_CAM_WORD(r4)
+       li      r7, TM_QW1_OS + TM_WORD2
+       mfmsr   r0
+       andi.   r0, r0, MSR_DR          /* in real mode? */
+       beq     2f
+       ld      r10, HSTATE_XIVE_TIMA_VIRT(r13)
+       cmpldi  cr1, r10, 0
+       beq     cr1, no_xive
+       eieio
+       stdx    r11,r9,r10
+       stwx    r8,r7,r10
+       b       3f
+2:     ld      r10, HSTATE_XIVE_TIMA_PHYS(r13)
+       cmpldi  cr1, r10, 0
+       beq     cr1, no_xive
        eieio
        stdcix  r11,r9,r10
-       lwz     r11, VCPU_XIVE_CAM_WORD(r4)
-       li      r9, TM_QW1_OS + TM_WORD2
-       stwcix  r11,r9,r10
-       li      r9, 1
+       stwcix  r8,r7,r10
+3:     li      r9, 1
        stb     r9, VCPU_XIVE_PUSHED(r4)
        eieio
 
@@ -1009,12 +985,16 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_300)
         * on, we mask it.
         */
        lbz     r0, VCPU_XIVE_ESC_ON(r4)
-       cmpwi   r0,0
-       beq     1f
-       ld      r10, VCPU_XIVE_ESC_RADDR(r4)
+       cmpwi   cr1, r0,0
+       beq     cr1, 1f
        li      r9, XIVE_ESB_SET_PQ_01
+       beq     4f                      /* in real mode? */
+       ld      r10, VCPU_XIVE_ESC_VADDR(r4)
+       ldx     r0, r10, r9
+       b       5f
+4:     ld      r10, VCPU_XIVE_ESC_RADDR(r4)
        ldcix   r0, r10, r9
-       sync
+5:     sync
 
        /* We have a possible subtle race here: The escalation interrupt might
         * have fired and be on its way to the host queue while we mask it,
@@ -2292,7 +2272,7 @@ hcall_real_table:
 #endif
        .long   0               /* 0x24 - H_SET_SPRG0 */
        .long   DOTSYM(kvmppc_h_set_dabr) - hcall_real_table
-       .long   0               /* 0x2c */
+       .long   DOTSYM(kvmppc_rm_h_page_init) - hcall_real_table
        .long   0               /* 0x30 */
        .long   0               /* 0x34 */
        .long   0               /* 0x38 */
index f78d002f0fe0dce6cc311ae1322dc17c42b7bdd5..4953957333b7812b2c154c5140b6f07776a95f11 100644 (file)
@@ -166,7 +166,8 @@ static irqreturn_t xive_esc_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int xive_attach_escalation(struct kvm_vcpu *vcpu, u8 prio)
+int kvmppc_xive_attach_escalation(struct kvm_vcpu *vcpu, u8 prio,
+                                 bool single_escalation)
 {
        struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
        struct xive_q *q = &xc->queues[prio];
@@ -185,7 +186,7 @@ static int xive_attach_escalation(struct kvm_vcpu *vcpu, u8 prio)
                return -EIO;
        }
 
-       if (xc->xive->single_escalation)
+       if (single_escalation)
                name = kasprintf(GFP_KERNEL, "kvm-%d-%d",
                                 vcpu->kvm->arch.lpid, xc->server_num);
        else
@@ -217,7 +218,7 @@ static int xive_attach_escalation(struct kvm_vcpu *vcpu, u8 prio)
         * interrupt, thus leaving it effectively masked after
         * it fires once.
         */
-       if (xc->xive->single_escalation) {
+       if (single_escalation) {
                struct irq_data *d = irq_get_irq_data(xc->esc_virq[prio]);
                struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
 
@@ -291,7 +292,8 @@ static int xive_check_provisioning(struct kvm *kvm, u8 prio)
                        continue;
                rc = xive_provision_queue(vcpu, prio);
                if (rc == 0 && !xive->single_escalation)
-                       xive_attach_escalation(vcpu, prio);
+                       kvmppc_xive_attach_escalation(vcpu, prio,
+                                                     xive->single_escalation);
                if (rc)
                        return rc;
        }
@@ -342,7 +344,7 @@ static int xive_try_pick_queue(struct kvm_vcpu *vcpu, u8 prio)
        return atomic_add_unless(&q->count, 1, max) ? 0 : -EBUSY;
 }
 
-static int xive_select_target(struct kvm *kvm, u32 *server, u8 prio)
+int kvmppc_xive_select_target(struct kvm *kvm, u32 *server, u8 prio)
 {
        struct kvm_vcpu *vcpu;
        int i, rc;
@@ -380,11 +382,6 @@ static int xive_select_target(struct kvm *kvm, u32 *server, u8 prio)
        return -EBUSY;
 }
 
-static u32 xive_vp(struct kvmppc_xive *xive, u32 server)
-{
-       return xive->vp_base + kvmppc_pack_vcpu_id(xive->kvm, server);
-}
-
 static u8 xive_lock_and_mask(struct kvmppc_xive *xive,
                             struct kvmppc_xive_src_block *sb,
                             struct kvmppc_xive_irq_state *state)
@@ -430,8 +427,8 @@ static u8 xive_lock_and_mask(struct kvmppc_xive *xive,
         */
        if (xd->flags & OPAL_XIVE_IRQ_MASK_VIA_FW) {
                xive_native_configure_irq(hw_num,
-                                         xive_vp(xive, state->act_server),
-                                         MASKED, state->number);
+                               kvmppc_xive_vp(xive, state->act_server),
+                               MASKED, state->number);
                /* set old_p so we can track if an H_EOI was done */
                state->old_p = true;
                state->old_q = false;
@@ -486,8 +483,8 @@ static void xive_finish_unmask(struct kvmppc_xive *xive,
         */
        if (xd->flags & OPAL_XIVE_IRQ_MASK_VIA_FW) {
                xive_native_configure_irq(hw_num,
-                                         xive_vp(xive, state->act_server),
-                                         state->act_priority, state->number);
+                               kvmppc_xive_vp(xive, state->act_server),
+                               state->act_priority, state->number);
                /* If an EOI is needed, do it here */
                if (!state->old_p)
                        xive_vm_source_eoi(hw_num, xd);
@@ -535,7 +532,7 @@ static int xive_target_interrupt(struct kvm *kvm,
         * priority. The count for that new target will have
         * already been incremented.
         */
-       rc = xive_select_target(kvm, &server, prio);
+       rc = kvmppc_xive_select_target(kvm, &server, prio);
 
        /*
         * We failed to find a target ? Not much we can do
@@ -563,7 +560,7 @@ static int xive_target_interrupt(struct kvm *kvm,
        kvmppc_xive_select_irq(state, &hw_num, NULL);
 
        return xive_native_configure_irq(hw_num,
-                                        xive_vp(xive, server),
+                                        kvmppc_xive_vp(xive, server),
                                         prio, state->number);
 }
 
@@ -849,7 +846,8 @@ int kvmppc_xive_set_icp(struct kvm_vcpu *vcpu, u64 icpval)
 
        /*
         * We can't update the state of a "pushed" VCPU, but that
-        * shouldn't happen.
+        * shouldn't happen because the vcpu->mutex makes running a
+        * vcpu mutually exclusive with doing one_reg get/set on it.
         */
        if (WARN_ON(vcpu->arch.xive_pushed))
                return -EIO;
@@ -940,6 +938,13 @@ int kvmppc_xive_set_mapped(struct kvm *kvm, unsigned long guest_irq,
        /* Turn the IPI hard off */
        xive_vm_esb_load(&state->ipi_data, XIVE_ESB_SET_PQ_01);
 
+       /*
+        * Reset ESB guest mapping. Needed when ESB pages are exposed
+        * to the guest in XIVE native mode
+        */
+       if (xive->ops && xive->ops->reset_mapped)
+               xive->ops->reset_mapped(kvm, guest_irq);
+
        /* Grab info about irq */
        state->pt_number = hw_irq;
        state->pt_data = irq_data_get_irq_handler_data(host_data);
@@ -951,7 +956,7 @@ int kvmppc_xive_set_mapped(struct kvm *kvm, unsigned long guest_irq,
         * which is fine for a never started interrupt.
         */
        xive_native_configure_irq(hw_irq,
-                                 xive_vp(xive, state->act_server),
+                                 kvmppc_xive_vp(xive, state->act_server),
                                  state->act_priority, state->number);
 
        /*
@@ -1025,9 +1030,17 @@ int kvmppc_xive_clr_mapped(struct kvm *kvm, unsigned long guest_irq,
        state->pt_number = 0;
        state->pt_data = NULL;
 
+       /*
+        * Reset ESB guest mapping. Needed when ESB pages are exposed
+        * to the guest in XIVE native mode
+        */
+       if (xive->ops && xive->ops->reset_mapped) {
+               xive->ops->reset_mapped(kvm, guest_irq);
+       }
+
        /* Reconfigure the IPI */
        xive_native_configure_irq(state->ipi_number,
-                                 xive_vp(xive, state->act_server),
+                                 kvmppc_xive_vp(xive, state->act_server),
                                  state->act_priority, state->number);
 
        /*
@@ -1049,7 +1062,7 @@ int kvmppc_xive_clr_mapped(struct kvm *kvm, unsigned long guest_irq,
 }
 EXPORT_SYMBOL_GPL(kvmppc_xive_clr_mapped);
 
-static void kvmppc_xive_disable_vcpu_interrupts(struct kvm_vcpu *vcpu)
+void kvmppc_xive_disable_vcpu_interrupts(struct kvm_vcpu *vcpu)
 {
        struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
        struct kvm *kvm = vcpu->kvm;
@@ -1083,14 +1096,35 @@ static void kvmppc_xive_disable_vcpu_interrupts(struct kvm_vcpu *vcpu)
                        arch_spin_unlock(&sb->lock);
                }
        }
+
+       /* Disable vcpu's escalation interrupt */
+       if (vcpu->arch.xive_esc_on) {
+               __raw_readq((void __iomem *)(vcpu->arch.xive_esc_vaddr +
+                                            XIVE_ESB_SET_PQ_01));
+               vcpu->arch.xive_esc_on = false;
+       }
+
+       /*
+        * Clear pointers to escalation interrupt ESB.
+        * This is safe because the vcpu->mutex is held, preventing
+        * any other CPU from concurrently executing a KVM_RUN ioctl.
+        */
+       vcpu->arch.xive_esc_vaddr = 0;
+       vcpu->arch.xive_esc_raddr = 0;
 }
 
 void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu)
 {
        struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
-       struct kvmppc_xive *xive = xc->xive;
+       struct kvmppc_xive *xive = vcpu->kvm->arch.xive;
        int i;
 
+       if (!kvmppc_xics_enabled(vcpu))
+               return;
+
+       if (!xc)
+               return;
+
        pr_devel("cleanup_vcpu(cpu=%d)\n", xc->server_num);
 
        /* Ensure no interrupt is still routed to that VP */
@@ -1129,6 +1163,10 @@ void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu)
        }
        /* Free the VP */
        kfree(xc);
+
+       /* Cleanup the vcpu */
+       vcpu->arch.irq_type = KVMPPC_IRQ_DEFAULT;
+       vcpu->arch.xive_vcpu = NULL;
 }
 
 int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
@@ -1146,7 +1184,7 @@ int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
        }
        if (xive->kvm != vcpu->kvm)
                return -EPERM;
-       if (vcpu->arch.irq_type)
+       if (vcpu->arch.irq_type != KVMPPC_IRQ_DEFAULT)
                return -EBUSY;
        if (kvmppc_xive_find_server(vcpu->kvm, cpu)) {
                pr_devel("Duplicate !\n");
@@ -1166,7 +1204,7 @@ int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
        xc->xive = xive;
        xc->vcpu = vcpu;
        xc->server_num = cpu;
-       xc->vp_id = xive_vp(xive, cpu);
+       xc->vp_id = kvmppc_xive_vp(xive, cpu);
        xc->mfrr = 0xff;
        xc->valid = true;
 
@@ -1219,7 +1257,8 @@ int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
                if (xive->qmap & (1 << i)) {
                        r = xive_provision_queue(vcpu, i);
                        if (r == 0 && !xive->single_escalation)
-                               xive_attach_escalation(vcpu, i);
+                               kvmppc_xive_attach_escalation(
+                                       vcpu, i, xive->single_escalation);
                        if (r)
                                goto bail;
                } else {
@@ -1234,7 +1273,7 @@ int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
        }
 
        /* If not done above, attach priority 0 escalation */
-       r = xive_attach_escalation(vcpu, 0);
+       r = kvmppc_xive_attach_escalation(vcpu, 0, xive->single_escalation);
        if (r)
                goto bail;
 
@@ -1485,8 +1524,8 @@ static int xive_get_source(struct kvmppc_xive *xive, long irq, u64 addr)
        return 0;
 }
 
-static struct kvmppc_xive_src_block *xive_create_src_block(struct kvmppc_xive *xive,
-                                                          int irq)
+struct kvmppc_xive_src_block *kvmppc_xive_create_src_block(
+       struct kvmppc_xive *xive, int irq)
 {
        struct kvm *kvm = xive->kvm;
        struct kvmppc_xive_src_block *sb;
@@ -1509,6 +1548,7 @@ static struct kvmppc_xive_src_block *xive_create_src_block(struct kvmppc_xive *x
 
        for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) {
                sb->irq_state[i].number = (bid << KVMPPC_XICS_ICS_SHIFT) | i;
+               sb->irq_state[i].eisn = 0;
                sb->irq_state[i].guest_priority = MASKED;
                sb->irq_state[i].saved_priority = MASKED;
                sb->irq_state[i].act_priority = MASKED;
@@ -1565,7 +1605,7 @@ static int xive_set_source(struct kvmppc_xive *xive, long irq, u64 addr)
        sb = kvmppc_xive_find_source(xive, irq, &idx);
        if (!sb) {
                pr_devel("No source, creating source block...\n");
-               sb = xive_create_src_block(xive, irq);
+               sb = kvmppc_xive_create_src_block(xive, irq);
                if (!sb) {
                        pr_devel("Failed to create block...\n");
                        return -ENOMEM;
@@ -1789,7 +1829,7 @@ static void kvmppc_xive_cleanup_irq(u32 hw_num, struct xive_irq_data *xd)
        xive_cleanup_irq_data(xd);
 }
 
-static void kvmppc_xive_free_sources(struct kvmppc_xive_src_block *sb)
+void kvmppc_xive_free_sources(struct kvmppc_xive_src_block *sb)
 {
        int i;
 
@@ -1810,16 +1850,55 @@ static void kvmppc_xive_free_sources(struct kvmppc_xive_src_block *sb)
        }
 }
 
-static void kvmppc_xive_free(struct kvm_device *dev)
+/*
+ * Called when device fd is closed.  kvm->lock is held.
+ */
+static void kvmppc_xive_release(struct kvm_device *dev)
 {
        struct kvmppc_xive *xive = dev->private;
        struct kvm *kvm = xive->kvm;
+       struct kvm_vcpu *vcpu;
        int i;
+       int was_ready;
+
+       pr_devel("Releasing xive device\n");
 
        debugfs_remove(xive->dentry);
 
-       if (kvm)
-               kvm->arch.xive = NULL;
+       /*
+        * Clearing mmu_ready temporarily while holding kvm->lock
+        * is a way of ensuring that no vcpus can enter the guest
+        * until we drop kvm->lock.  Doing kick_all_cpus_sync()
+        * ensures that any vcpu executing inside the guest has
+        * exited the guest.  Once kick_all_cpus_sync() has finished,
+        * we know that no vcpu can be executing the XIVE push or
+        * pull code, or executing a XICS hcall.
+        *
+        * Since this is the device release function, we know that
+        * userspace does not have any open fd referring to the
+        * device.  Therefore there can not be any of the device
+        * attribute set/get functions being executed concurrently,
+        * and similarly, the connect_vcpu and set/clr_mapped
+        * functions also cannot be being executed.
+        */
+       was_ready = kvm->arch.mmu_ready;
+       kvm->arch.mmu_ready = 0;
+       kick_all_cpus_sync();
+
+       /*
+        * We should clean up the vCPU interrupt presenters first.
+        */
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               /*
+                * Take vcpu->mutex to ensure that no one_reg get/set ioctl
+                * (i.e. kvmppc_xive_[gs]et_icp) can be done concurrently.
+                */
+               mutex_lock(&vcpu->mutex);
+               kvmppc_xive_cleanup_vcpu(vcpu);
+               mutex_unlock(&vcpu->mutex);
+       }
+
+       kvm->arch.xive = NULL;
 
        /* Mask and free interrupts */
        for (i = 0; i <= xive->max_sbid; i++) {
@@ -1832,11 +1911,47 @@ static void kvmppc_xive_free(struct kvm_device *dev)
        if (xive->vp_base != XIVE_INVALID_VP)
                xive_native_free_vp_block(xive->vp_base);
 
+       kvm->arch.mmu_ready = was_ready;
+
+       /*
+        * A reference of the kvmppc_xive pointer is now kept under
+        * the xive_devices struct of the machine for reuse. It is
+        * freed when the VM is destroyed for now until we fix all the
+        * execution paths.
+        */
 
-       kfree(xive);
        kfree(dev);
 }
 
+/*
+ * When the guest chooses the interrupt mode (XICS legacy or XIVE
+ * native), the VM will switch of KVM device. The previous device will
+ * be "released" before the new one is created.
+ *
+ * Until we are sure all execution paths are well protected, provide a
+ * fail safe (transitional) method for device destruction, in which
+ * the XIVE device pointer is recycled and not directly freed.
+ */
+struct kvmppc_xive *kvmppc_xive_get_device(struct kvm *kvm, u32 type)
+{
+       struct kvmppc_xive **kvm_xive_device = type == KVM_DEV_TYPE_XIVE ?
+               &kvm->arch.xive_devices.native :
+               &kvm->arch.xive_devices.xics_on_xive;
+       struct kvmppc_xive *xive = *kvm_xive_device;
+
+       if (!xive) {
+               xive = kzalloc(sizeof(*xive), GFP_KERNEL);
+               *kvm_xive_device = xive;
+       } else {
+               memset(xive, 0, sizeof(*xive));
+       }
+
+       return xive;
+}
+
+/*
+ * Create a XICS device with XIVE backend.  kvm->lock is held.
+ */
 static int kvmppc_xive_create(struct kvm_device *dev, u32 type)
 {
        struct kvmppc_xive *xive;
@@ -1845,7 +1960,7 @@ static int kvmppc_xive_create(struct kvm_device *dev, u32 type)
 
        pr_devel("Creating xive for partition\n");
 
-       xive = kzalloc(sizeof(*xive), GFP_KERNEL);
+       xive = kvmppc_xive_get_device(kvm, type);
        if (!xive)
                return -ENOMEM;
 
@@ -1883,6 +1998,43 @@ static int kvmppc_xive_create(struct kvm_device *dev, u32 type)
        return 0;
 }
 
+int kvmppc_xive_debug_show_queues(struct seq_file *m, struct kvm_vcpu *vcpu)
+{
+       struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
+       unsigned int i;
+
+       for (i = 0; i < KVMPPC_XIVE_Q_COUNT; i++) {
+               struct xive_q *q = &xc->queues[i];
+               u32 i0, i1, idx;
+
+               if (!q->qpage && !xc->esc_virq[i])
+                       continue;
+
+               seq_printf(m, " [q%d]: ", i);
+
+               if (q->qpage) {
+                       idx = q->idx;
+                       i0 = be32_to_cpup(q->qpage + idx);
+                       idx = (idx + 1) & q->msk;
+                       i1 = be32_to_cpup(q->qpage + idx);
+                       seq_printf(m, "T=%d %08x %08x...\n", q->toggle,
+                                  i0, i1);
+               }
+               if (xc->esc_virq[i]) {
+                       struct irq_data *d = irq_get_irq_data(xc->esc_virq[i]);
+                       struct xive_irq_data *xd =
+                               irq_data_get_irq_handler_data(d);
+                       u64 pq = xive_vm_esb_load(xd, XIVE_ESB_GET);
+
+                       seq_printf(m, "E:%c%c I(%d:%llx:%llx)",
+                                  (pq & XIVE_ESB_VAL_P) ? 'P' : 'p',
+                                  (pq & XIVE_ESB_VAL_Q) ? 'Q' : 'q',
+                                  xc->esc_virq[i], pq, xd->eoi_page);
+                       seq_puts(m, "\n");
+               }
+       }
+       return 0;
+}
 
 static int xive_debug_show(struct seq_file *m, void *private)
 {
@@ -1908,7 +2060,6 @@ static int xive_debug_show(struct seq_file *m, void *private)
 
        kvm_for_each_vcpu(i, vcpu, kvm) {
                struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
-               unsigned int i;
 
                if (!xc)
                        continue;
@@ -1918,33 +2069,8 @@ static int xive_debug_show(struct seq_file *m, void *private)
                           xc->server_num, xc->cppr, xc->hw_cppr,
                           xc->mfrr, xc->pending,
                           xc->stat_rm_h_xirr, xc->stat_vm_h_xirr);
-               for (i = 0; i < KVMPPC_XIVE_Q_COUNT; i++) {
-                       struct xive_q *q = &xc->queues[i];
-                       u32 i0, i1, idx;
-
-                       if (!q->qpage && !xc->esc_virq[i])
-                               continue;
 
-                       seq_printf(m, " [q%d]: ", i);
-
-                       if (q->qpage) {
-                               idx = q->idx;
-                               i0 = be32_to_cpup(q->qpage + idx);
-                               idx = (idx + 1) & q->msk;
-                               i1 = be32_to_cpup(q->qpage + idx);
-                               seq_printf(m, "T=%d %08x %08x... \n", q->toggle, i0, i1);
-                       }
-                       if (xc->esc_virq[i]) {
-                               struct irq_data *d = irq_get_irq_data(xc->esc_virq[i]);
-                               struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
-                               u64 pq = xive_vm_esb_load(xd, XIVE_ESB_GET);
-                               seq_printf(m, "E:%c%c I(%d:%llx:%llx)",
-                                          (pq & XIVE_ESB_VAL_P) ? 'P' : 'p',
-                                          (pq & XIVE_ESB_VAL_Q) ? 'Q' : 'q',
-                                          xc->esc_virq[i], pq, xd->eoi_page);
-                               seq_printf(m, "\n");
-                       }
-               }
+               kvmppc_xive_debug_show_queues(m, vcpu);
 
                t_rm_h_xirr += xc->stat_rm_h_xirr;
                t_rm_h_ipoll += xc->stat_rm_h_ipoll;
@@ -1999,7 +2125,7 @@ struct kvm_device_ops kvm_xive_ops = {
        .name = "kvm-xive",
        .create = kvmppc_xive_create,
        .init = kvmppc_xive_init,
-       .destroy = kvmppc_xive_free,
+       .release = kvmppc_xive_release,
        .set_attr = xive_set_attr,
        .get_attr = xive_get_attr,
        .has_attr = xive_has_attr,
index a08ae6fd4c51fc54b9c79ffe48290b7f86b58956..426146332984c87b5f874df03549a211add985c9 100644 (file)
 #ifdef CONFIG_KVM_XICS
 #include "book3s_xics.h"
 
+/*
+ * The XIVE Interrupt source numbers are within the range 0 to
+ * KVMPPC_XICS_NR_IRQS.
+ */
+#define KVMPPC_XIVE_FIRST_IRQ  0
+#define KVMPPC_XIVE_NR_IRQS    KVMPPC_XICS_NR_IRQS
+
 /*
  * State for one guest irq source.
  *
@@ -54,6 +61,9 @@ struct kvmppc_xive_irq_state {
        bool saved_p;
        bool saved_q;
        u8 saved_scan_prio;
+
+       /* Xive native */
+       u32 eisn;                       /* Guest Effective IRQ number */
 };
 
 /* Select the "right" interrupt (IPI vs. passthrough) */
@@ -84,6 +94,11 @@ struct kvmppc_xive_src_block {
        struct kvmppc_xive_irq_state irq_state[KVMPPC_XICS_IRQ_PER_ICS];
 };
 
+struct kvmppc_xive;
+
+struct kvmppc_xive_ops {
+       int (*reset_mapped)(struct kvm *kvm, unsigned long guest_irq);
+};
 
 struct kvmppc_xive {
        struct kvm *kvm;
@@ -122,6 +137,10 @@ struct kvmppc_xive {
 
        /* Flags */
        u8      single_escalation;
+
+       struct kvmppc_xive_ops *ops;
+       struct address_space   *mapping;
+       struct mutex mapping_lock;
 };
 
 #define KVMPPC_XIVE_Q_COUNT    8
@@ -198,6 +217,11 @@ static inline struct kvmppc_xive_src_block *kvmppc_xive_find_source(struct kvmpp
        return xive->src_blocks[bid];
 }
 
+static inline u32 kvmppc_xive_vp(struct kvmppc_xive *xive, u32 server)
+{
+       return xive->vp_base + kvmppc_pack_vcpu_id(xive->kvm, server);
+}
+
 /*
  * Mapping between guest priorities and host priorities
  * is as follow.
@@ -248,5 +272,18 @@ extern int (*__xive_vm_h_ipi)(struct kvm_vcpu *vcpu, unsigned long server,
 extern int (*__xive_vm_h_cppr)(struct kvm_vcpu *vcpu, unsigned long cppr);
 extern int (*__xive_vm_h_eoi)(struct kvm_vcpu *vcpu, unsigned long xirr);
 
+/*
+ * Common Xive routines for XICS-over-XIVE and XIVE native
+ */
+void kvmppc_xive_disable_vcpu_interrupts(struct kvm_vcpu *vcpu);
+int kvmppc_xive_debug_show_queues(struct seq_file *m, struct kvm_vcpu *vcpu);
+struct kvmppc_xive_src_block *kvmppc_xive_create_src_block(
+       struct kvmppc_xive *xive, int irq);
+void kvmppc_xive_free_sources(struct kvmppc_xive_src_block *sb);
+int kvmppc_xive_select_target(struct kvm *kvm, u32 *server, u8 prio);
+int kvmppc_xive_attach_escalation(struct kvm_vcpu *vcpu, u8 prio,
+                                 bool single_escalation);
+struct kvmppc_xive *kvmppc_xive_get_device(struct kvm *kvm, u32 type);
+
 #endif /* CONFIG_KVM_XICS */
 #endif /* _KVM_PPC_BOOK3S_XICS_H */
diff --git a/arch/powerpc/kvm/book3s_xive_native.c b/arch/powerpc/kvm/book3s_xive_native.c
new file mode 100644 (file)
index 0000000..6a8e698
--- /dev/null
@@ -0,0 +1,1249 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017-2019, IBM Corporation.
+ */
+
+#define pr_fmt(fmt) "xive-kvm: " fmt
+
+#include <linux/kernel.h>
+#include <linux/kvm_host.h>
+#include <linux/err.h>
+#include <linux/gfp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/file.h>
+#include <asm/uaccess.h>
+#include <asm/kvm_book3s.h>
+#include <asm/kvm_ppc.h>
+#include <asm/hvcall.h>
+#include <asm/xive.h>
+#include <asm/xive-regs.h>
+#include <asm/debug.h>
+#include <asm/debugfs.h>
+#include <asm/opal.h>
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include "book3s_xive.h"
+
+static u8 xive_vm_esb_load(struct xive_irq_data *xd, u32 offset)
+{
+       u64 val;
+
+       if (xd->flags & XIVE_IRQ_FLAG_SHIFT_BUG)
+               offset |= offset << 4;
+
+       val = in_be64(xd->eoi_mmio + offset);
+       return (u8)val;
+}
+
+static void kvmppc_xive_native_cleanup_queue(struct kvm_vcpu *vcpu, int prio)
+{
+       struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
+       struct xive_q *q = &xc->queues[prio];
+
+       xive_native_disable_queue(xc->vp_id, q, prio);
+       if (q->qpage) {
+               put_page(virt_to_page(q->qpage));
+               q->qpage = NULL;
+       }
+}
+
+void kvmppc_xive_native_cleanup_vcpu(struct kvm_vcpu *vcpu)
+{
+       struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
+       int i;
+
+       if (!kvmppc_xive_enabled(vcpu))
+               return;
+
+       if (!xc)
+               return;
+
+       pr_devel("native_cleanup_vcpu(cpu=%d)\n", xc->server_num);
+
+       /* Ensure no interrupt is still routed to that VP */
+       xc->valid = false;
+       kvmppc_xive_disable_vcpu_interrupts(vcpu);
+
+       /* Disable the VP */
+       xive_native_disable_vp(xc->vp_id);
+
+       /* Free the queues & associated interrupts */
+       for (i = 0; i < KVMPPC_XIVE_Q_COUNT; i++) {
+               /* Free the escalation irq */
+               if (xc->esc_virq[i]) {
+                       free_irq(xc->esc_virq[i], vcpu);
+                       irq_dispose_mapping(xc->esc_virq[i]);
+                       kfree(xc->esc_virq_names[i]);
+                       xc->esc_virq[i] = 0;
+               }
+
+               /* Free the queue */
+               kvmppc_xive_native_cleanup_queue(vcpu, i);
+       }
+
+       /* Free the VP */
+       kfree(xc);
+
+       /* Cleanup the vcpu */
+       vcpu->arch.irq_type = KVMPPC_IRQ_DEFAULT;
+       vcpu->arch.xive_vcpu = NULL;
+}
+
+int kvmppc_xive_native_connect_vcpu(struct kvm_device *dev,
+                                   struct kvm_vcpu *vcpu, u32 server_num)
+{
+       struct kvmppc_xive *xive = dev->private;
+       struct kvmppc_xive_vcpu *xc = NULL;
+       int rc;
+
+       pr_devel("native_connect_vcpu(server=%d)\n", server_num);
+
+       if (dev->ops != &kvm_xive_native_ops) {
+               pr_devel("Wrong ops !\n");
+               return -EPERM;
+       }
+       if (xive->kvm != vcpu->kvm)
+               return -EPERM;
+       if (vcpu->arch.irq_type != KVMPPC_IRQ_DEFAULT)
+               return -EBUSY;
+       if (server_num >= KVM_MAX_VCPUS) {
+               pr_devel("Out of bounds !\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&vcpu->kvm->lock);
+
+       if (kvmppc_xive_find_server(vcpu->kvm, server_num)) {
+               pr_devel("Duplicate !\n");
+               rc = -EEXIST;
+               goto bail;
+       }
+
+       xc = kzalloc(sizeof(*xc), GFP_KERNEL);
+       if (!xc) {
+               rc = -ENOMEM;
+               goto bail;
+       }
+
+       vcpu->arch.xive_vcpu = xc;
+       xc->xive = xive;
+       xc->vcpu = vcpu;
+       xc->server_num = server_num;
+
+       xc->vp_id = kvmppc_xive_vp(xive, server_num);
+       xc->valid = true;
+       vcpu->arch.irq_type = KVMPPC_IRQ_XIVE;
+
+       rc = xive_native_get_vp_info(xc->vp_id, &xc->vp_cam, &xc->vp_chip_id);
+       if (rc) {
+               pr_err("Failed to get VP info from OPAL: %d\n", rc);
+               goto bail;
+       }
+
+       /*
+        * Enable the VP first as the single escalation mode will
+        * affect escalation interrupts numbering
+        */
+       rc = xive_native_enable_vp(xc->vp_id, xive->single_escalation);
+       if (rc) {
+               pr_err("Failed to enable VP in OPAL: %d\n", rc);
+               goto bail;
+       }
+
+       /* Configure VCPU fields for use by assembly push/pull */
+       vcpu->arch.xive_saved_state.w01 = cpu_to_be64(0xff000000);
+       vcpu->arch.xive_cam_word = cpu_to_be32(xc->vp_cam | TM_QW1W2_VO);
+
+       /* TODO: reset all queues to a clean state ? */
+bail:
+       mutex_unlock(&vcpu->kvm->lock);
+       if (rc)
+               kvmppc_xive_native_cleanup_vcpu(vcpu);
+
+       return rc;
+}
+
+/*
+ * Device passthrough support
+ */
+static int kvmppc_xive_native_reset_mapped(struct kvm *kvm, unsigned long irq)
+{
+       struct kvmppc_xive *xive = kvm->arch.xive;
+
+       if (irq >= KVMPPC_XIVE_NR_IRQS)
+               return -EINVAL;
+
+       /*
+        * Clear the ESB pages of the IRQ number being mapped (or
+        * unmapped) into the guest and let the the VM fault handler
+        * repopulate with the appropriate ESB pages (device or IC)
+        */
+       pr_debug("clearing esb pages for girq 0x%lx\n", irq);
+       mutex_lock(&xive->mapping_lock);
+       if (xive->mapping)
+               unmap_mapping_range(xive->mapping,
+                                   irq * (2ull << PAGE_SHIFT),
+                                   2ull << PAGE_SHIFT, 1);
+       mutex_unlock(&xive->mapping_lock);
+       return 0;
+}
+
+static struct kvmppc_xive_ops kvmppc_xive_native_ops =  {
+       .reset_mapped = kvmppc_xive_native_reset_mapped,
+};
+
+static vm_fault_t xive_native_esb_fault(struct vm_fault *vmf)
+{
+       struct vm_area_struct *vma = vmf->vma;
+       struct kvm_device *dev = vma->vm_file->private_data;
+       struct kvmppc_xive *xive = dev->private;
+       struct kvmppc_xive_src_block *sb;
+       struct kvmppc_xive_irq_state *state;
+       struct xive_irq_data *xd;
+       u32 hw_num;
+       u16 src;
+       u64 page;
+       unsigned long irq;
+       u64 page_offset;
+
+       /*
+        * Linux/KVM uses a two pages ESB setting, one for trigger and
+        * one for EOI
+        */
+       page_offset = vmf->pgoff - vma->vm_pgoff;
+       irq = page_offset / 2;
+
+       sb = kvmppc_xive_find_source(xive, irq, &src);
+       if (!sb) {
+               pr_devel("%s: source %lx not found !\n", __func__, irq);
+               return VM_FAULT_SIGBUS;
+       }
+
+       state = &sb->irq_state[src];
+       kvmppc_xive_select_irq(state, &hw_num, &xd);
+
+       arch_spin_lock(&sb->lock);
+
+       /*
+        * first/even page is for trigger
+        * second/odd page is for EOI and management.
+        */
+       page = page_offset % 2 ? xd->eoi_page : xd->trig_page;
+       arch_spin_unlock(&sb->lock);
+
+       if (WARN_ON(!page)) {
+               pr_err("%s: accessing invalid ESB page for source %lx !\n",
+                      __func__, irq);
+               return VM_FAULT_SIGBUS;
+       }
+
+       vmf_insert_pfn(vma, vmf->address, page >> PAGE_SHIFT);
+       return VM_FAULT_NOPAGE;
+}
+
+static const struct vm_operations_struct xive_native_esb_vmops = {
+       .fault = xive_native_esb_fault,
+};
+
+static vm_fault_t xive_native_tima_fault(struct vm_fault *vmf)
+{
+       struct vm_area_struct *vma = vmf->vma;
+
+       switch (vmf->pgoff - vma->vm_pgoff) {
+       case 0: /* HW - forbid access */
+       case 1: /* HV - forbid access */
+               return VM_FAULT_SIGBUS;
+       case 2: /* OS */
+               vmf_insert_pfn(vma, vmf->address, xive_tima_os >> PAGE_SHIFT);
+               return VM_FAULT_NOPAGE;
+       case 3: /* USER - TODO */
+       default:
+               return VM_FAULT_SIGBUS;
+       }
+}
+
+static const struct vm_operations_struct xive_native_tima_vmops = {
+       .fault = xive_native_tima_fault,
+};
+
+static int kvmppc_xive_native_mmap(struct kvm_device *dev,
+                                  struct vm_area_struct *vma)
+{
+       struct kvmppc_xive *xive = dev->private;
+
+       /* We only allow mappings at fixed offset for now */
+       if (vma->vm_pgoff == KVM_XIVE_TIMA_PAGE_OFFSET) {
+               if (vma_pages(vma) > 4)
+                       return -EINVAL;
+               vma->vm_ops = &xive_native_tima_vmops;
+       } else if (vma->vm_pgoff == KVM_XIVE_ESB_PAGE_OFFSET) {
+               if (vma_pages(vma) > KVMPPC_XIVE_NR_IRQS * 2)
+                       return -EINVAL;
+               vma->vm_ops = &xive_native_esb_vmops;
+       } else {
+               return -EINVAL;
+       }
+
+       vma->vm_flags |= VM_IO | VM_PFNMAP;
+       vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot);
+
+       /*
+        * Grab the KVM device file address_space to be able to clear
+        * the ESB pages mapping when a device is passed-through into
+        * the guest.
+        */
+       xive->mapping = vma->vm_file->f_mapping;
+       return 0;
+}
+
+static int kvmppc_xive_native_set_source(struct kvmppc_xive *xive, long irq,
+                                        u64 addr)
+{
+       struct kvmppc_xive_src_block *sb;
+       struct kvmppc_xive_irq_state *state;
+       u64 __user *ubufp = (u64 __user *) addr;
+       u64 val;
+       u16 idx;
+       int rc;
+
+       pr_devel("%s irq=0x%lx\n", __func__, irq);
+
+       if (irq < KVMPPC_XIVE_FIRST_IRQ || irq >= KVMPPC_XIVE_NR_IRQS)
+               return -E2BIG;
+
+       sb = kvmppc_xive_find_source(xive, irq, &idx);
+       if (!sb) {
+               pr_debug("No source, creating source block...\n");
+               sb = kvmppc_xive_create_src_block(xive, irq);
+               if (!sb) {
+                       pr_err("Failed to create block...\n");
+                       return -ENOMEM;
+               }
+       }
+       state = &sb->irq_state[idx];
+
+       if (get_user(val, ubufp)) {
+               pr_err("fault getting user info !\n");
+               return -EFAULT;
+       }
+
+       arch_spin_lock(&sb->lock);
+
+       /*
+        * If the source doesn't already have an IPI, allocate
+        * one and get the corresponding data
+        */
+       if (!state->ipi_number) {
+               state->ipi_number = xive_native_alloc_irq();
+               if (state->ipi_number == 0) {
+                       pr_err("Failed to allocate IRQ !\n");
+                       rc = -ENXIO;
+                       goto unlock;
+               }
+               xive_native_populate_irq_data(state->ipi_number,
+                                             &state->ipi_data);
+               pr_debug("%s allocated hw_irq=0x%x for irq=0x%lx\n", __func__,
+                        state->ipi_number, irq);
+       }
+
+       /* Restore LSI state */
+       if (val & KVM_XIVE_LEVEL_SENSITIVE) {
+               state->lsi = true;
+               if (val & KVM_XIVE_LEVEL_ASSERTED)
+                       state->asserted = true;
+               pr_devel("  LSI ! Asserted=%d\n", state->asserted);
+       }
+
+       /* Mask IRQ to start with */
+       state->act_server = 0;
+       state->act_priority = MASKED;
+       xive_vm_esb_load(&state->ipi_data, XIVE_ESB_SET_PQ_01);
+       xive_native_configure_irq(state->ipi_number, 0, MASKED, 0);
+
+       /* Increment the number of valid sources and mark this one valid */
+       if (!state->valid)
+               xive->src_count++;
+       state->valid = true;
+
+       rc = 0;
+
+unlock:
+       arch_spin_unlock(&sb->lock);
+
+       return rc;
+}
+
+static int kvmppc_xive_native_update_source_config(struct kvmppc_xive *xive,
+                                       struct kvmppc_xive_src_block *sb,
+                                       struct kvmppc_xive_irq_state *state,
+                                       u32 server, u8 priority, bool masked,
+                                       u32 eisn)
+{
+       struct kvm *kvm = xive->kvm;
+       u32 hw_num;
+       int rc = 0;
+
+       arch_spin_lock(&sb->lock);
+
+       if (state->act_server == server && state->act_priority == priority &&
+           state->eisn == eisn)
+               goto unlock;
+
+       pr_devel("new_act_prio=%d new_act_server=%d mask=%d act_server=%d act_prio=%d\n",
+                priority, server, masked, state->act_server,
+                state->act_priority);
+
+       kvmppc_xive_select_irq(state, &hw_num, NULL);
+
+       if (priority != MASKED && !masked) {
+               rc = kvmppc_xive_select_target(kvm, &server, priority);
+               if (rc)
+                       goto unlock;
+
+               state->act_priority = priority;
+               state->act_server = server;
+               state->eisn = eisn;
+
+               rc = xive_native_configure_irq(hw_num,
+                                              kvmppc_xive_vp(xive, server),
+                                              priority, eisn);
+       } else {
+               state->act_priority = MASKED;
+               state->act_server = 0;
+               state->eisn = 0;
+
+               rc = xive_native_configure_irq(hw_num, 0, MASKED, 0);
+       }
+
+unlock:
+       arch_spin_unlock(&sb->lock);
+       return rc;
+}
+
+static int kvmppc_xive_native_set_source_config(struct kvmppc_xive *xive,
+                                               long irq, u64 addr)
+{
+       struct kvmppc_xive_src_block *sb;
+       struct kvmppc_xive_irq_state *state;
+       u64 __user *ubufp = (u64 __user *) addr;
+       u16 src;
+       u64 kvm_cfg;
+       u32 server;
+       u8 priority;
+       bool masked;
+       u32 eisn;
+
+       sb = kvmppc_xive_find_source(xive, irq, &src);
+       if (!sb)
+               return -ENOENT;
+
+       state = &sb->irq_state[src];
+
+       if (!state->valid)
+               return -EINVAL;
+
+       if (get_user(kvm_cfg, ubufp))
+               return -EFAULT;
+
+       pr_devel("%s irq=0x%lx cfg=%016llx\n", __func__, irq, kvm_cfg);
+
+       priority = (kvm_cfg & KVM_XIVE_SOURCE_PRIORITY_MASK) >>
+               KVM_XIVE_SOURCE_PRIORITY_SHIFT;
+       server = (kvm_cfg & KVM_XIVE_SOURCE_SERVER_MASK) >>
+               KVM_XIVE_SOURCE_SERVER_SHIFT;
+       masked = (kvm_cfg & KVM_XIVE_SOURCE_MASKED_MASK) >>
+               KVM_XIVE_SOURCE_MASKED_SHIFT;
+       eisn = (kvm_cfg & KVM_XIVE_SOURCE_EISN_MASK) >>
+               KVM_XIVE_SOURCE_EISN_SHIFT;
+
+       if (priority != xive_prio_from_guest(priority)) {
+               pr_err("invalid priority for queue %d for VCPU %d\n",
+                      priority, server);
+               return -EINVAL;
+       }
+
+       return kvmppc_xive_native_update_source_config(xive, sb, state, server,
+                                                      priority, masked, eisn);
+}
+
+static int kvmppc_xive_native_sync_source(struct kvmppc_xive *xive,
+                                         long irq, u64 addr)
+{
+       struct kvmppc_xive_src_block *sb;
+       struct kvmppc_xive_irq_state *state;
+       struct xive_irq_data *xd;
+       u32 hw_num;
+       u16 src;
+       int rc = 0;
+
+       pr_devel("%s irq=0x%lx", __func__, irq);
+
+       sb = kvmppc_xive_find_source(xive, irq, &src);
+       if (!sb)
+               return -ENOENT;
+
+       state = &sb->irq_state[src];
+
+       rc = -EINVAL;
+
+       arch_spin_lock(&sb->lock);
+
+       if (state->valid) {
+               kvmppc_xive_select_irq(state, &hw_num, &xd);
+               xive_native_sync_source(hw_num);
+               rc = 0;
+       }
+
+       arch_spin_unlock(&sb->lock);
+       return rc;
+}
+
+static int xive_native_validate_queue_size(u32 qshift)
+{
+       /*
+        * We only support 64K pages for the moment. This is also
+        * advertised in the DT property "ibm,xive-eq-sizes"
+        */
+       switch (qshift) {
+       case 0: /* EQ reset */
+       case 16:
+               return 0;
+       case 12:
+       case 21:
+       case 24:
+       default:
+               return -EINVAL;
+       }
+}
+
+static int kvmppc_xive_native_set_queue_config(struct kvmppc_xive *xive,
+                                              long eq_idx, u64 addr)
+{
+       struct kvm *kvm = xive->kvm;
+       struct kvm_vcpu *vcpu;
+       struct kvmppc_xive_vcpu *xc;
+       void __user *ubufp = (void __user *) addr;
+       u32 server;
+       u8 priority;
+       struct kvm_ppc_xive_eq kvm_eq;
+       int rc;
+       __be32 *qaddr = 0;
+       struct page *page;
+       struct xive_q *q;
+       gfn_t gfn;
+       unsigned long page_size;
+
+       /*
+        * Demangle priority/server tuple from the EQ identifier
+        */
+       priority = (eq_idx & KVM_XIVE_EQ_PRIORITY_MASK) >>
+               KVM_XIVE_EQ_PRIORITY_SHIFT;
+       server = (eq_idx & KVM_XIVE_EQ_SERVER_MASK) >>
+               KVM_XIVE_EQ_SERVER_SHIFT;
+
+       if (copy_from_user(&kvm_eq, ubufp, sizeof(kvm_eq)))
+               return -EFAULT;
+
+       vcpu = kvmppc_xive_find_server(kvm, server);
+       if (!vcpu) {
+               pr_err("Can't find server %d\n", server);
+               return -ENOENT;
+       }
+       xc = vcpu->arch.xive_vcpu;
+
+       if (priority != xive_prio_from_guest(priority)) {
+               pr_err("Trying to restore invalid queue %d for VCPU %d\n",
+                      priority, server);
+               return -EINVAL;
+       }
+       q = &xc->queues[priority];
+
+       pr_devel("%s VCPU %d priority %d fl:%x shift:%d addr:%llx g:%d idx:%d\n",
+                __func__, server, priority, kvm_eq.flags,
+                kvm_eq.qshift, kvm_eq.qaddr, kvm_eq.qtoggle, kvm_eq.qindex);
+
+       /*
+        * sPAPR specifies a "Unconditional Notify (n) flag" for the
+        * H_INT_SET_QUEUE_CONFIG hcall which forces notification
+        * without using the coalescing mechanisms provided by the
+        * XIVE END ESBs. This is required on KVM as notification
+        * using the END ESBs is not supported.
+        */
+       if (kvm_eq.flags != KVM_XIVE_EQ_ALWAYS_NOTIFY) {
+               pr_err("invalid flags %d\n", kvm_eq.flags);
+               return -EINVAL;
+       }
+
+       rc = xive_native_validate_queue_size(kvm_eq.qshift);
+       if (rc) {
+               pr_err("invalid queue size %d\n", kvm_eq.qshift);
+               return rc;
+       }
+
+       /* reset queue and disable queueing */
+       if (!kvm_eq.qshift) {
+               q->guest_qaddr  = 0;
+               q->guest_qshift = 0;
+
+               rc = xive_native_configure_queue(xc->vp_id, q, priority,
+                                                NULL, 0, true);
+               if (rc) {
+                       pr_err("Failed to reset queue %d for VCPU %d: %d\n",
+                              priority, xc->server_num, rc);
+                       return rc;
+               }
+
+               if (q->qpage) {
+                       put_page(virt_to_page(q->qpage));
+                       q->qpage = NULL;
+               }
+
+               return 0;
+       }
+
+       if (kvm_eq.qaddr & ((1ull << kvm_eq.qshift) - 1)) {
+               pr_err("queue page is not aligned %llx/%llx\n", kvm_eq.qaddr,
+                      1ull << kvm_eq.qshift);
+               return -EINVAL;
+       }
+
+       gfn = gpa_to_gfn(kvm_eq.qaddr);
+       page = gfn_to_page(kvm, gfn);
+       if (is_error_page(page)) {
+               pr_err("Couldn't get queue page %llx!\n", kvm_eq.qaddr);
+               return -EINVAL;
+       }
+
+       page_size = kvm_host_page_size(kvm, gfn);
+       if (1ull << kvm_eq.qshift > page_size) {
+               pr_warn("Incompatible host page size %lx!\n", page_size);
+               return -EINVAL;
+       }
+
+       qaddr = page_to_virt(page) + (kvm_eq.qaddr & ~PAGE_MASK);
+
+       /*
+        * Backup the queue page guest address to the mark EQ page
+        * dirty for migration.
+        */
+       q->guest_qaddr  = kvm_eq.qaddr;
+       q->guest_qshift = kvm_eq.qshift;
+
+        /*
+         * Unconditional Notification is forced by default at the
+         * OPAL level because the use of END ESBs is not supported by
+         * Linux.
+         */
+       rc = xive_native_configure_queue(xc->vp_id, q, priority,
+                                        (__be32 *) qaddr, kvm_eq.qshift, true);
+       if (rc) {
+               pr_err("Failed to configure queue %d for VCPU %d: %d\n",
+                      priority, xc->server_num, rc);
+               put_page(page);
+               return rc;
+       }
+
+       /*
+        * Only restore the queue state when needed. When doing the
+        * H_INT_SET_SOURCE_CONFIG hcall, it should not.
+        */
+       if (kvm_eq.qtoggle != 1 || kvm_eq.qindex != 0) {
+               rc = xive_native_set_queue_state(xc->vp_id, priority,
+                                                kvm_eq.qtoggle,
+                                                kvm_eq.qindex);
+               if (rc)
+                       goto error;
+       }
+
+       rc = kvmppc_xive_attach_escalation(vcpu, priority,
+                                          xive->single_escalation);
+error:
+       if (rc)
+               kvmppc_xive_native_cleanup_queue(vcpu, priority);
+       return rc;
+}
+
+static int kvmppc_xive_native_get_queue_config(struct kvmppc_xive *xive,
+                                              long eq_idx, u64 addr)
+{
+       struct kvm *kvm = xive->kvm;
+       struct kvm_vcpu *vcpu;
+       struct kvmppc_xive_vcpu *xc;
+       struct xive_q *q;
+       void __user *ubufp = (u64 __user *) addr;
+       u32 server;
+       u8 priority;
+       struct kvm_ppc_xive_eq kvm_eq;
+       u64 qaddr;
+       u64 qshift;
+       u64 qeoi_page;
+       u32 escalate_irq;
+       u64 qflags;
+       int rc;
+
+       /*
+        * Demangle priority/server tuple from the EQ identifier
+        */
+       priority = (eq_idx & KVM_XIVE_EQ_PRIORITY_MASK) >>
+               KVM_XIVE_EQ_PRIORITY_SHIFT;
+       server = (eq_idx & KVM_XIVE_EQ_SERVER_MASK) >>
+               KVM_XIVE_EQ_SERVER_SHIFT;
+
+       vcpu = kvmppc_xive_find_server(kvm, server);
+       if (!vcpu) {
+               pr_err("Can't find server %d\n", server);
+               return -ENOENT;
+       }
+       xc = vcpu->arch.xive_vcpu;
+
+       if (priority != xive_prio_from_guest(priority)) {
+               pr_err("invalid priority for queue %d for VCPU %d\n",
+                      priority, server);
+               return -EINVAL;
+       }
+       q = &xc->queues[priority];
+
+       memset(&kvm_eq, 0, sizeof(kvm_eq));
+
+       if (!q->qpage)
+               return 0;
+
+       rc = xive_native_get_queue_info(xc->vp_id, priority, &qaddr, &qshift,
+                                       &qeoi_page, &escalate_irq, &qflags);
+       if (rc)
+               return rc;
+
+       kvm_eq.flags = 0;
+       if (qflags & OPAL_XIVE_EQ_ALWAYS_NOTIFY)
+               kvm_eq.flags |= KVM_XIVE_EQ_ALWAYS_NOTIFY;
+
+       kvm_eq.qshift = q->guest_qshift;
+       kvm_eq.qaddr  = q->guest_qaddr;
+
+       rc = xive_native_get_queue_state(xc->vp_id, priority, &kvm_eq.qtoggle,
+                                        &kvm_eq.qindex);
+       if (rc)
+               return rc;
+
+       pr_devel("%s VCPU %d priority %d fl:%x shift:%d addr:%llx g:%d idx:%d\n",
+                __func__, server, priority, kvm_eq.flags,
+                kvm_eq.qshift, kvm_eq.qaddr, kvm_eq.qtoggle, kvm_eq.qindex);
+
+       if (copy_to_user(ubufp, &kvm_eq, sizeof(kvm_eq)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static void kvmppc_xive_reset_sources(struct kvmppc_xive_src_block *sb)
+{
+       int i;
+
+       for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) {
+               struct kvmppc_xive_irq_state *state = &sb->irq_state[i];
+
+               if (!state->valid)
+                       continue;
+
+               if (state->act_priority == MASKED)
+                       continue;
+
+               state->eisn = 0;
+               state->act_server = 0;
+               state->act_priority = MASKED;
+               xive_vm_esb_load(&state->ipi_data, XIVE_ESB_SET_PQ_01);
+               xive_native_configure_irq(state->ipi_number, 0, MASKED, 0);
+               if (state->pt_number) {
+                       xive_vm_esb_load(state->pt_data, XIVE_ESB_SET_PQ_01);
+                       xive_native_configure_irq(state->pt_number,
+                                                 0, MASKED, 0);
+               }
+       }
+}
+
+static int kvmppc_xive_reset(struct kvmppc_xive *xive)
+{
+       struct kvm *kvm = xive->kvm;
+       struct kvm_vcpu *vcpu;
+       unsigned int i;
+
+       pr_devel("%s\n", __func__);
+
+       mutex_lock(&kvm->lock);
+
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
+               unsigned int prio;
+
+               if (!xc)
+                       continue;
+
+               kvmppc_xive_disable_vcpu_interrupts(vcpu);
+
+               for (prio = 0; prio < KVMPPC_XIVE_Q_COUNT; prio++) {
+
+                       /* Single escalation, no queue 7 */
+                       if (prio == 7 && xive->single_escalation)
+                               break;
+
+                       if (xc->esc_virq[prio]) {
+                               free_irq(xc->esc_virq[prio], vcpu);
+                               irq_dispose_mapping(xc->esc_virq[prio]);
+                               kfree(xc->esc_virq_names[prio]);
+                               xc->esc_virq[prio] = 0;
+                       }
+
+                       kvmppc_xive_native_cleanup_queue(vcpu, prio);
+               }
+       }
+
+       for (i = 0; i <= xive->max_sbid; i++) {
+               struct kvmppc_xive_src_block *sb = xive->src_blocks[i];
+
+               if (sb) {
+                       arch_spin_lock(&sb->lock);
+                       kvmppc_xive_reset_sources(sb);
+                       arch_spin_unlock(&sb->lock);
+               }
+       }
+
+       mutex_unlock(&kvm->lock);
+
+       return 0;
+}
+
+static void kvmppc_xive_native_sync_sources(struct kvmppc_xive_src_block *sb)
+{
+       int j;
+
+       for (j = 0; j < KVMPPC_XICS_IRQ_PER_ICS; j++) {
+               struct kvmppc_xive_irq_state *state = &sb->irq_state[j];
+               struct xive_irq_data *xd;
+               u32 hw_num;
+
+               if (!state->valid)
+                       continue;
+
+               /*
+                * The struct kvmppc_xive_irq_state reflects the state
+                * of the EAS configuration and not the state of the
+                * source. The source is masked setting the PQ bits to
+                * '-Q', which is what is being done before calling
+                * the KVM_DEV_XIVE_EQ_SYNC control.
+                *
+                * If a source EAS is configured, OPAL syncs the XIVE
+                * IC of the source and the XIVE IC of the previous
+                * target if any.
+                *
+                * So it should be fine ignoring MASKED sources as
+                * they have been synced already.
+                */
+               if (state->act_priority == MASKED)
+                       continue;
+
+               kvmppc_xive_select_irq(state, &hw_num, &xd);
+               xive_native_sync_source(hw_num);
+               xive_native_sync_queue(hw_num);
+       }
+}
+
+static int kvmppc_xive_native_vcpu_eq_sync(struct kvm_vcpu *vcpu)
+{
+       struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
+       unsigned int prio;
+
+       if (!xc)
+               return -ENOENT;
+
+       for (prio = 0; prio < KVMPPC_XIVE_Q_COUNT; prio++) {
+               struct xive_q *q = &xc->queues[prio];
+
+               if (!q->qpage)
+                       continue;
+
+               /* Mark EQ page dirty for migration */
+               mark_page_dirty(vcpu->kvm, gpa_to_gfn(q->guest_qaddr));
+       }
+       return 0;
+}
+
+static int kvmppc_xive_native_eq_sync(struct kvmppc_xive *xive)
+{
+       struct kvm *kvm = xive->kvm;
+       struct kvm_vcpu *vcpu;
+       unsigned int i;
+
+       pr_devel("%s\n", __func__);
+
+       mutex_lock(&kvm->lock);
+       for (i = 0; i <= xive->max_sbid; i++) {
+               struct kvmppc_xive_src_block *sb = xive->src_blocks[i];
+
+               if (sb) {
+                       arch_spin_lock(&sb->lock);
+                       kvmppc_xive_native_sync_sources(sb);
+                       arch_spin_unlock(&sb->lock);
+               }
+       }
+
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               kvmppc_xive_native_vcpu_eq_sync(vcpu);
+       }
+       mutex_unlock(&kvm->lock);
+
+       return 0;
+}
+
+static int kvmppc_xive_native_set_attr(struct kvm_device *dev,
+                                      struct kvm_device_attr *attr)
+{
+       struct kvmppc_xive *xive = dev->private;
+
+       switch (attr->group) {
+       case KVM_DEV_XIVE_GRP_CTRL:
+               switch (attr->attr) {
+               case KVM_DEV_XIVE_RESET:
+                       return kvmppc_xive_reset(xive);
+               case KVM_DEV_XIVE_EQ_SYNC:
+                       return kvmppc_xive_native_eq_sync(xive);
+               }
+               break;
+       case KVM_DEV_XIVE_GRP_SOURCE:
+               return kvmppc_xive_native_set_source(xive, attr->attr,
+                                                    attr->addr);
+       case KVM_DEV_XIVE_GRP_SOURCE_CONFIG:
+               return kvmppc_xive_native_set_source_config(xive, attr->attr,
+                                                           attr->addr);
+       case KVM_DEV_XIVE_GRP_EQ_CONFIG:
+               return kvmppc_xive_native_set_queue_config(xive, attr->attr,
+                                                          attr->addr);
+       case KVM_DEV_XIVE_GRP_SOURCE_SYNC:
+               return kvmppc_xive_native_sync_source(xive, attr->attr,
+                                                     attr->addr);
+       }
+       return -ENXIO;
+}
+
+static int kvmppc_xive_native_get_attr(struct kvm_device *dev,
+                                      struct kvm_device_attr *attr)
+{
+       struct kvmppc_xive *xive = dev->private;
+
+       switch (attr->group) {
+       case KVM_DEV_XIVE_GRP_EQ_CONFIG:
+               return kvmppc_xive_native_get_queue_config(xive, attr->attr,
+                                                          attr->addr);
+       }
+       return -ENXIO;
+}
+
+static int kvmppc_xive_native_has_attr(struct kvm_device *dev,
+                                      struct kvm_device_attr *attr)
+{
+       switch (attr->group) {
+       case KVM_DEV_XIVE_GRP_CTRL:
+               switch (attr->attr) {
+               case KVM_DEV_XIVE_RESET:
+               case KVM_DEV_XIVE_EQ_SYNC:
+                       return 0;
+               }
+               break;
+       case KVM_DEV_XIVE_GRP_SOURCE:
+       case KVM_DEV_XIVE_GRP_SOURCE_CONFIG:
+       case KVM_DEV_XIVE_GRP_SOURCE_SYNC:
+               if (attr->attr >= KVMPPC_XIVE_FIRST_IRQ &&
+                   attr->attr < KVMPPC_XIVE_NR_IRQS)
+                       return 0;
+               break;
+       case KVM_DEV_XIVE_GRP_EQ_CONFIG:
+               return 0;
+       }
+       return -ENXIO;
+}
+
+/*
+ * Called when device fd is closed
+ */
+static void kvmppc_xive_native_release(struct kvm_device *dev)
+{
+       struct kvmppc_xive *xive = dev->private;
+       struct kvm *kvm = xive->kvm;
+       struct kvm_vcpu *vcpu;
+       int i;
+       int was_ready;
+
+       debugfs_remove(xive->dentry);
+
+       pr_devel("Releasing xive native device\n");
+
+       /*
+        * Clearing mmu_ready temporarily while holding kvm->lock
+        * is a way of ensuring that no vcpus can enter the guest
+        * until we drop kvm->lock.  Doing kick_all_cpus_sync()
+        * ensures that any vcpu executing inside the guest has
+        * exited the guest.  Once kick_all_cpus_sync() has finished,
+        * we know that no vcpu can be executing the XIVE push or
+        * pull code or accessing the XIVE MMIO regions.
+        *
+        * Since this is the device release function, we know that
+        * userspace does not have any open fd or mmap referring to
+        * the device.  Therefore there can not be any of the
+        * device attribute set/get, mmap, or page fault functions
+        * being executed concurrently, and similarly, the
+        * connect_vcpu and set/clr_mapped functions also cannot
+        * be being executed.
+        */
+       was_ready = kvm->arch.mmu_ready;
+       kvm->arch.mmu_ready = 0;
+       kick_all_cpus_sync();
+
+       /*
+        * We should clean up the vCPU interrupt presenters first.
+        */
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               /*
+                * Take vcpu->mutex to ensure that no one_reg get/set ioctl
+                * (i.e. kvmppc_xive_native_[gs]et_vp) can be being done.
+                */
+               mutex_lock(&vcpu->mutex);
+               kvmppc_xive_native_cleanup_vcpu(vcpu);
+               mutex_unlock(&vcpu->mutex);
+       }
+
+       kvm->arch.xive = NULL;
+
+       for (i = 0; i <= xive->max_sbid; i++) {
+               if (xive->src_blocks[i])
+                       kvmppc_xive_free_sources(xive->src_blocks[i]);
+               kfree(xive->src_blocks[i]);
+               xive->src_blocks[i] = NULL;
+       }
+
+       if (xive->vp_base != XIVE_INVALID_VP)
+               xive_native_free_vp_block(xive->vp_base);
+
+       kvm->arch.mmu_ready = was_ready;
+
+       /*
+        * A reference of the kvmppc_xive pointer is now kept under
+        * the xive_devices struct of the machine for reuse. It is
+        * freed when the VM is destroyed for now until we fix all the
+        * execution paths.
+        */
+
+       kfree(dev);
+}
+
+/*
+ * Create a XIVE device.  kvm->lock is held.
+ */
+static int kvmppc_xive_native_create(struct kvm_device *dev, u32 type)
+{
+       struct kvmppc_xive *xive;
+       struct kvm *kvm = dev->kvm;
+       int ret = 0;
+
+       pr_devel("Creating xive native device\n");
+
+       if (kvm->arch.xive)
+               return -EEXIST;
+
+       xive = kvmppc_xive_get_device(kvm, type);
+       if (!xive)
+               return -ENOMEM;
+
+       dev->private = xive;
+       xive->dev = dev;
+       xive->kvm = kvm;
+       kvm->arch.xive = xive;
+       mutex_init(&xive->mapping_lock);
+
+       /*
+        * Allocate a bunch of VPs. KVM_MAX_VCPUS is a large value for
+        * a default. Getting the max number of CPUs the VM was
+        * configured with would improve our usage of the XIVE VP space.
+        */
+       xive->vp_base = xive_native_alloc_vp_block(KVM_MAX_VCPUS);
+       pr_devel("VP_Base=%x\n", xive->vp_base);
+
+       if (xive->vp_base == XIVE_INVALID_VP)
+               ret = -ENXIO;
+
+       xive->single_escalation = xive_native_has_single_escalation();
+       xive->ops = &kvmppc_xive_native_ops;
+
+       if (ret)
+               kfree(xive);
+
+       return ret;
+}
+
+/*
+ * Interrupt Pending Buffer (IPB) offset
+ */
+#define TM_IPB_SHIFT 40
+#define TM_IPB_MASK  (((u64) 0xFF) << TM_IPB_SHIFT)
+
+int kvmppc_xive_native_get_vp(struct kvm_vcpu *vcpu, union kvmppc_one_reg *val)
+{
+       struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
+       u64 opal_state;
+       int rc;
+
+       if (!kvmppc_xive_enabled(vcpu))
+               return -EPERM;
+
+       if (!xc)
+               return -ENOENT;
+
+       /* Thread context registers. We only care about IPB and CPPR */
+       val->xive_timaval[0] = vcpu->arch.xive_saved_state.w01;
+
+       /* Get the VP state from OPAL */
+       rc = xive_native_get_vp_state(xc->vp_id, &opal_state);
+       if (rc)
+               return rc;
+
+       /*
+        * Capture the backup of IPB register in the NVT structure and
+        * merge it in our KVM VP state.
+        */
+       val->xive_timaval[0] |= cpu_to_be64(opal_state & TM_IPB_MASK);
+
+       pr_devel("%s NSR=%02x CPPR=%02x IBP=%02x PIPR=%02x w01=%016llx w2=%08x opal=%016llx\n",
+                __func__,
+                vcpu->arch.xive_saved_state.nsr,
+                vcpu->arch.xive_saved_state.cppr,
+                vcpu->arch.xive_saved_state.ipb,
+                vcpu->arch.xive_saved_state.pipr,
+                vcpu->arch.xive_saved_state.w01,
+                (u32) vcpu->arch.xive_cam_word, opal_state);
+
+       return 0;
+}
+
+int kvmppc_xive_native_set_vp(struct kvm_vcpu *vcpu, union kvmppc_one_reg *val)
+{
+       struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
+       struct kvmppc_xive *xive = vcpu->kvm->arch.xive;
+
+       pr_devel("%s w01=%016llx vp=%016llx\n", __func__,
+                val->xive_timaval[0], val->xive_timaval[1]);
+
+       if (!kvmppc_xive_enabled(vcpu))
+               return -EPERM;
+
+       if (!xc || !xive)
+               return -ENOENT;
+
+       /* We can't update the state of a "pushed" VCPU  */
+       if (WARN_ON(vcpu->arch.xive_pushed))
+               return -EBUSY;
+
+       /*
+        * Restore the thread context registers. IPB and CPPR should
+        * be the only ones that matter.
+        */
+       vcpu->arch.xive_saved_state.w01 = val->xive_timaval[0];
+
+       /*
+        * There is no need to restore the XIVE internal state (IPB
+        * stored in the NVT) as the IPB register was merged in KVM VP
+        * state when captured.
+        */
+       return 0;
+}
+
+static int xive_native_debug_show(struct seq_file *m, void *private)
+{
+       struct kvmppc_xive *xive = m->private;
+       struct kvm *kvm = xive->kvm;
+       struct kvm_vcpu *vcpu;
+       unsigned int i;
+
+       if (!kvm)
+               return 0;
+
+       seq_puts(m, "=========\nVCPU state\n=========\n");
+
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
+
+               if (!xc)
+                       continue;
+
+               seq_printf(m, "cpu server %#x NSR=%02x CPPR=%02x IBP=%02x PIPR=%02x w01=%016llx w2=%08x\n",
+                          xc->server_num,
+                          vcpu->arch.xive_saved_state.nsr,
+                          vcpu->arch.xive_saved_state.cppr,
+                          vcpu->arch.xive_saved_state.ipb,
+                          vcpu->arch.xive_saved_state.pipr,
+                          vcpu->arch.xive_saved_state.w01,
+                          (u32) vcpu->arch.xive_cam_word);
+
+               kvmppc_xive_debug_show_queues(m, vcpu);
+       }
+
+       return 0;
+}
+
+static int xive_native_debug_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, xive_native_debug_show, inode->i_private);
+}
+
+static const struct file_operations xive_native_debug_fops = {
+       .open = xive_native_debug_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static void xive_native_debugfs_init(struct kvmppc_xive *xive)
+{
+       char *name;
+
+       name = kasprintf(GFP_KERNEL, "kvm-xive-%p", xive);
+       if (!name) {
+               pr_err("%s: no memory for name\n", __func__);
+               return;
+       }
+
+       xive->dentry = debugfs_create_file(name, 0444, powerpc_debugfs_root,
+                                          xive, &xive_native_debug_fops);
+
+       pr_debug("%s: created %s\n", __func__, name);
+       kfree(name);
+}
+
+static void kvmppc_xive_native_init(struct kvm_device *dev)
+{
+       struct kvmppc_xive *xive = (struct kvmppc_xive *)dev->private;
+
+       /* Register some debug interfaces */
+       xive_native_debugfs_init(xive);
+}
+
+struct kvm_device_ops kvm_xive_native_ops = {
+       .name = "kvm-xive-native",
+       .create = kvmppc_xive_native_create,
+       .init = kvmppc_xive_native_init,
+       .release = kvmppc_xive_native_release,
+       .set_attr = kvmppc_xive_native_set_attr,
+       .get_attr = kvmppc_xive_native_get_attr,
+       .has_attr = kvmppc_xive_native_has_attr,
+       .mmap = kvmppc_xive_native_mmap,
+};
+
+void kvmppc_xive_native_init_module(void)
+{
+       ;
+}
+
+void kvmppc_xive_native_exit_module(void)
+{
+       ;
+}
index 033363d6e764eac80f260de8f33ba53abda48825..0737acfd17f1ec04433d41bce26aaeae5beeeeed 100644 (file)
@@ -130,24 +130,14 @@ static u32 GLUE(X_PFX,scan_interrupts)(struct kvmppc_xive_vcpu *xc,
                 */
                prio = ffs(pending) - 1;
 
-               /*
-                * If the most favoured prio we found pending is less
-                * favored (or equal) than a pending IPI, we return
-                * the IPI instead.
-                *
-                * Note: If pending was 0 and mfrr is 0xff, we will
-                * not spurriously take an IPI because mfrr cannot
-                * then be smaller than cppr.
-                */
-               if (prio >= xc->mfrr && xc->mfrr < xc->cppr) {
-                       prio = xc->mfrr;
-                       hirq = XICS_IPI;
-                       break;
-               }
-
                /* Don't scan past the guest cppr */
-               if (prio >= xc->cppr || prio > 7)
+               if (prio >= xc->cppr || prio > 7) {
+                       if (xc->mfrr < xc->cppr) {
+                               prio = xc->mfrr;
+                               hirq = XICS_IPI;
+                       }
                        break;
+               }
 
                /* Grab queue and pointers */
                q = &xc->queues[prio];
@@ -184,9 +174,12 @@ skip_ipi:
                 * been set and another occurrence of the IPI will trigger.
                 */
                if (hirq == XICS_IPI || (prio == 0 && !qpage)) {
-                       if (scan_type == scan_fetch)
+                       if (scan_type == scan_fetch) {
                                GLUE(X_PFX,source_eoi)(xc->vp_ipi,
                                                       &xc->vp_ipi_data);
+                               q->idx = idx;
+                               q->toggle = toggle;
+                       }
                        /* Loop back on same queue with updated idx/toggle */
 #ifdef XIVE_RUNTIME_CHECKS
                        WARN_ON(hirq && hirq != XICS_IPI);
@@ -199,32 +192,41 @@ skip_ipi:
                if (hirq == XICS_DUMMY)
                        goto skip_ipi;
 
-               /* If fetching, update queue pointers */
-               if (scan_type == scan_fetch) {
-                       q->idx = idx;
-                       q->toggle = toggle;
-               }
-
-               /* Something found, stop searching */
-               if (hirq)
-                       break;
-
-               /* Clear the pending bit on the now empty queue */
-               pending &= ~(1 << prio);
+               /* Clear the pending bit if the queue is now empty */
+               if (!hirq) {
+                       pending &= ~(1 << prio);
 
-               /*
-                * Check if the queue count needs adjusting due to
-                * interrupts being moved away.
-                */
-               if (atomic_read(&q->pending_count)) {
-                       int p = atomic_xchg(&q->pending_count, 0);
-                       if (p) {
+                       /*
+                        * Check if the queue count needs adjusting due to
+                        * interrupts being moved away.
+                        */
+                       if (atomic_read(&q->pending_count)) {
+                               int p = atomic_xchg(&q->pending_count, 0);
+                               if (p) {
 #ifdef XIVE_RUNTIME_CHECKS
-                               WARN_ON(p > atomic_read(&q->count));
+                                       WARN_ON(p > atomic_read(&q->count));
 #endif
-                               atomic_sub(p, &q->count);
+                                       atomic_sub(p, &q->count);
+                               }
                        }
                }
+
+               /*
+                * If the most favoured prio we found pending is less
+                * favored (or equal) than a pending IPI, we return
+                * the IPI instead.
+                */
+               if (prio >= xc->mfrr && xc->mfrr < xc->cppr) {
+                       prio = xc->mfrr;
+                       hirq = XICS_IPI;
+                       break;
+               }
+
+               /* If fetching, update queue pointers */
+               if (scan_type == scan_fetch) {
+                       q->idx = idx;
+                       q->toggle = toggle;
+               }
        }
 
        /* If we are just taking a "peek", do nothing else */
index 24296f4cadc6c43c529c9d7e9eb81823c8ff963d..e0af53fd78c50fd1408e2dcb4c0e08fbcc45c8db 100644 (file)
@@ -783,7 +783,7 @@ int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu,
        if (!pages)
                return -ENOMEM;
 
-       ret = get_user_pages_fast(cfg->array, num_pages, 1, pages);
+       ret = get_user_pages_fast(cfg->array, num_pages, FOLL_WRITE, pages);
        if (ret < 0)
                goto free_pages;
 
index 8885377ec3e0c611b3ec3f14b8565e2f7ffde4aa..3393b166817a859a371bd95bf5664e1a0788944f 100644 (file)
@@ -570,6 +570,16 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_PPC_GET_CPU_CHAR:
                r = 1;
                break;
+#ifdef CONFIG_KVM_XIVE
+       case KVM_CAP_PPC_IRQ_XIVE:
+               /*
+                * We need XIVE to be enabled on the platform (implies
+                * a POWER9 processor) and the PowerNV platform, as
+                * nested is not yet supported.
+                */
+               r = xive_enabled() && !!cpu_has_feature(CPU_FTR_HVMODE);
+               break;
+#endif
 
        case KVM_CAP_PPC_ALLOC_HTAB:
                r = hv_enabled;
@@ -644,9 +654,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                else
                        r = num_online_cpus();
                break;
-       case KVM_CAP_NR_MEMSLOTS:
-               r = KVM_USER_MEM_SLOTS;
-               break;
        case KVM_CAP_MAX_VCPUS:
                r = KVM_MAX_VCPUS;
                break;
@@ -753,6 +760,9 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
                else
                        kvmppc_xics_free_icp(vcpu);
                break;
+       case KVMPPC_IRQ_XIVE:
+               kvmppc_xive_native_cleanup_vcpu(vcpu);
+               break;
        }
 
        kvmppc_core_vcpu_free(vcpu);
@@ -1941,6 +1951,30 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
                break;
        }
 #endif /* CONFIG_KVM_XICS */
+#ifdef CONFIG_KVM_XIVE
+       case KVM_CAP_PPC_IRQ_XIVE: {
+               struct fd f;
+               struct kvm_device *dev;
+
+               r = -EBADF;
+               f = fdget(cap->args[0]);
+               if (!f.file)
+                       break;
+
+               r = -ENXIO;
+               if (!xive_enabled())
+                       break;
+
+               r = -EPERM;
+               dev = kvm_device_from_filp(f.file);
+               if (dev)
+                       r = kvmppc_xive_native_connect_vcpu(dev, vcpu,
+                                                           cap->args[1]);
+
+               fdput(f);
+               break;
+       }
+#endif /* CONFIG_KVM_XIVE */
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
        case KVM_CAP_PPC_FWNMI:
                r = -EINVAL;
index 8330f135294f48ecfff9bb5d3555f6fa3e3514c3..5c521f3924a54ee35fade6be1136a9153bbb1f45 100644 (file)
@@ -141,8 +141,9 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua,
        for (entry = 0; entry < entries; entry += chunk) {
                unsigned long n = min(entries - entry, chunk);
 
-               ret = get_user_pages_longterm(ua + (entry << PAGE_SHIFT), n,
-                               FOLL_WRITE, mem->hpages + entry, NULL);
+               ret = get_user_pages(ua + (entry << PAGE_SHIFT), n,
+                               FOLL_WRITE | FOLL_LONGTERM,
+                               mem->hpages + entry, NULL);
                if (ret == n) {
                        pinned += n;
                        continue;
index 6a23b9ebd2a14593deddcc922568e4eda7e31057..4d841369399f439915b863241a08a143c8f6f98f 100644 (file)
@@ -90,7 +90,7 @@ void radix__tlbiel_all(unsigned int action)
        asm volatile(PPC_INVALIDATE_ERAT "; isync" : : :"memory");
 }
 
-static inline void __tlbiel_pid(unsigned long pid, int set,
+static __always_inline void __tlbiel_pid(unsigned long pid, int set,
                                unsigned long ric)
 {
        unsigned long rb,rs,prs,r;
@@ -106,7 +106,7 @@ static inline void __tlbiel_pid(unsigned long pid, int set,
        trace_tlbie(0, 1, rb, rs, ric, prs, r);
 }
 
-static inline void __tlbie_pid(unsigned long pid, unsigned long ric)
+static __always_inline void __tlbie_pid(unsigned long pid, unsigned long ric)
 {
        unsigned long rb,rs,prs,r;
 
@@ -120,7 +120,7 @@ static inline void __tlbie_pid(unsigned long pid, unsigned long ric)
        trace_tlbie(0, 0, rb, rs, ric, prs, r);
 }
 
-static inline void __tlbiel_lpid(unsigned long lpid, int set,
+static __always_inline void __tlbiel_lpid(unsigned long lpid, int set,
                                unsigned long ric)
 {
        unsigned long rb,rs,prs,r;
@@ -136,7 +136,7 @@ static inline void __tlbiel_lpid(unsigned long lpid, int set,
        trace_tlbie(lpid, 1, rb, rs, ric, prs, r);
 }
 
-static inline void __tlbie_lpid(unsigned long lpid, unsigned long ric)
+static __always_inline void __tlbie_lpid(unsigned long lpid, unsigned long ric)
 {
        unsigned long rb,rs,prs,r;
 
@@ -928,7 +928,7 @@ void radix__tlb_flush(struct mmu_gather *tlb)
        tlb->need_flush_all = 0;
 }
 
-static inline void __radix__flush_tlb_range_psize(struct mm_struct *mm,
+static __always_inline void __radix__flush_tlb_range_psize(struct mm_struct *mm,
                                unsigned long start, unsigned long end,
                                int psize, bool also_pwc)
 {
index cd525d709072abf95c60c96bde6bd9cbc2deec48..e885fe2aafcc7bd7717baff2b31b14368c082e93 100644 (file)
@@ -109,8 +109,8 @@ int __weak remove_section_mapping(unsigned long start, unsigned long end)
        return -ENODEV;
 }
 
-int __ref arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap,
-                         bool want_memblock)
+int __ref arch_add_memory(int nid, u64 start, u64 size,
+                       struct mhp_restrictions *restrictions)
 {
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
@@ -127,11 +127,11 @@ int __ref arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altm
        }
        flush_inval_dcache_range(start, start + size);
 
-       return __add_pages(nid, start_pfn, nr_pages, altmap, want_memblock);
+       return __add_pages(nid, start_pfn, nr_pages, restrictions);
 }
 
 #ifdef CONFIG_MEMORY_HOTREMOVE
-int __ref arch_remove_memory(int nid, u64 start, u64 size,
+void __ref arch_remove_memory(int nid, u64 start, u64 size,
                             struct vmem_altmap *altmap)
 {
        unsigned long start_pfn = start >> PAGE_SHIFT;
@@ -147,14 +147,13 @@ int __ref arch_remove_memory(int nid, u64 start, u64 size,
        if (altmap)
                page += vmem_altmap_offset(altmap);
 
-       ret = __remove_pages(page_zone(page), start_pfn, nr_pages, altmap);
-       if (ret)
-               return ret;
+       __remove_pages(page_zone(page), start_pfn, nr_pages, altmap);
 
        /* Remove htab bolted mappings for this section of memory */
        start = (unsigned long)__va(start);
        flush_inval_dcache_range(start, start + size);
        ret = remove_section_mapping(start, start + size);
+       WARN_ON_ONCE(ret);
 
        /* Ensure all vmalloc mappings are flushed in case they also
         * hit that section of memory
@@ -163,8 +162,6 @@ int __ref arch_remove_memory(int nid, u64 start, u64 size,
 
        if (resize_hpt_for_hotplug(memblock_phys_mem_size()) == -ENOSPC)
                pr_warn("Hash collision while resizing HPT\n");
-
-       return ret;
 }
 #endif
 #endif /* CONFIG_MEMORY_HOTPLUG */
@@ -338,13 +335,6 @@ void free_initmem(void)
        free_initmem_default(POISON_FREE_INITMEM);
 }
 
-#ifdef CONFIG_BLK_DEV_INITRD
-void __init free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-#endif
-
 /*
  * This is called when a page has been modified by the kernel.
  * It just marks the page as not i-cache clean.  We do the i-cache
index d0e172d4757427203874e95a23c0afabb6f3a853..2794235e9d3eab5e1791210c3a5d810283df36cb 100644 (file)
@@ -331,7 +331,7 @@ config ARCH_ENABLE_SPLIT_PMD_PTLOCK
 config PPC_RADIX_MMU
        bool "Radix MMU Support"
        depends on PPC_BOOK3S_64 && HUGETLB_PAGE
-       select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA
+       select ARCH_HAS_GIGANTIC_PAGE
        select PPC_HAVE_KUEP
        select PPC_HAVE_KUAP
        default y
index dc23d9d2a7d9ae60c9c956dfeadd7e480e243891..495550432f3d62fd50a2aeacdfd902a5f20303b8 100644 (file)
@@ -1213,9 +1213,8 @@ int pnv_npu2_map_lpar_dev(struct pci_dev *gpdev, unsigned int lparid,
         * Currently we only support radix and non-zero LPCR only makes sense
         * for hash tables so skiboot expects the LPCR parameter to be a zero.
         */
-       ret = opal_npu_map_lpar(nphb->opal_id,
-                       PCI_DEVID(gpdev->bus->number, gpdev->devfn), lparid,
-                       0 /* LPCR bits */);
+       ret = opal_npu_map_lpar(nphb->opal_id, pci_dev_id(gpdev), lparid,
+                               0 /* LPCR bits */);
        if (ret) {
                dev_err(&gpdev->dev, "Error %d mapping device to LPAR\n", ret);
                return ret;
@@ -1224,7 +1223,7 @@ int pnv_npu2_map_lpar_dev(struct pci_dev *gpdev, unsigned int lparid,
        dev_dbg(&gpdev->dev, "init context opalid=%llu msr=%lx\n",
                        nphb->opal_id, msr);
        ret = opal_npu_init_context(nphb->opal_id, 0/*__unused*/, msr,
-                       PCI_DEVID(gpdev->bus->number, gpdev->devfn));
+                                   pci_dev_id(gpdev));
        if (ret < 0)
                dev_err(&gpdev->dev, "Failed to init context: %d\n", ret);
        else
@@ -1258,7 +1257,7 @@ int pnv_npu2_unmap_lpar_dev(struct pci_dev *gpdev)
        dev_dbg(&gpdev->dev, "destroy context opalid=%llu\n",
                        nphb->opal_id);
        ret = opal_npu_destroy_context(nphb->opal_id, 0/*__unused*/,
-                       PCI_DEVID(gpdev->bus->number, gpdev->devfn));
+                                      pci_dev_id(gpdev));
        if (ret < 0) {
                dev_err(&gpdev->dev, "Failed to destroy context: %d\n", ret);
                return ret;
@@ -1266,9 +1265,8 @@ int pnv_npu2_unmap_lpar_dev(struct pci_dev *gpdev)
 
        /* Set LPID to 0 anyway, just to be safe */
        dev_dbg(&gpdev->dev, "Map LPAR opalid=%llu lparid=0\n", nphb->opal_id);
-       ret = opal_npu_map_lpar(nphb->opal_id,
-                       PCI_DEVID(gpdev->bus->number, gpdev->devfn), 0 /*LPID*/,
-                       0 /* LPCR bits */);
+       ret = opal_npu_map_lpar(nphb->opal_id, pci_dev_id(gpdev), 0 /*LPID*/,
+                               0 /* LPCR bits */);
        if (ret)
                dev_err(&gpdev->dev, "Error %d mapping device to LPAR\n", ret);
 
index c92dcac85231c6381884199cfec717a08d3e36eb..026619c9a8cbc9f8cfecfd2ba298444792a47c21 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/irq.h>
 #include <linux/export.h>
 #include <linux/device.h>
+#include <linux/etherdevice.h>
 #include <linux/platform_device.h>
 #include <linux/of_net.h>
 #include <asm/tsi108.h>
@@ -106,7 +107,7 @@ static int __init tsi108_eth_of_init(void)
 
                mac_addr = of_get_mac_address(np);
                if (!IS_ERR(mac_addr))
-                       memcpy(tsi_eth_data.mac_addr, mac_addr, 6);
+                       ether_addr_copy(tsi_eth_data.mac_addr, mac_addr);
 
                ph = of_get_property(np, "mdio-handle", NULL);
                mdio = of_find_node_by_phandle(*ph);
index 0c037e933e55967ac75a6b486d52465a89165bae..7782201e5fe8de03f720b867aec1a098a3eda8bb 100644 (file)
@@ -521,6 +521,9 @@ u32 xive_native_default_eq_shift(void)
 }
 EXPORT_SYMBOL_GPL(xive_native_default_eq_shift);
 
+unsigned long xive_tima_os;
+EXPORT_SYMBOL_GPL(xive_tima_os);
+
 bool __init xive_native_init(void)
 {
        struct device_node *np;
@@ -573,6 +576,14 @@ bool __init xive_native_init(void)
        for_each_possible_cpu(cpu)
                kvmppc_set_xive_tima(cpu, r.start, tima);
 
+       /* Resource 2 is OS window */
+       if (of_address_to_resource(np, 2, &r)) {
+               pr_err("Failed to get thread mgmnt area resource\n");
+               return false;
+       }
+
+       xive_tima_os = r.start;
+
        /* Grab size of provisionning pages */
        xive_parse_provisioning(np);
 
index e66745decea1734388b48f3395404e523a9a7888..ee32c66e1af3aca63ff03a69a9c1c7dedb8f6bce 100644 (file)
@@ -27,7 +27,7 @@ config RISCV
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
        select GENERIC_SMP_IDLE_THREAD
-       select GENERIC_ATOMIC64 if !64BIT || !RISCV_ISA_A
+       select GENERIC_ATOMIC64 if !64BIT
        select HAVE_ARCH_AUDITSYSCALL
        select HAVE_MEMBLOCK_NODE_MAP
        select HAVE_DMA_CONTIGUOUS
@@ -35,7 +35,6 @@ config RISCV
        select HAVE_PERF_EVENTS
        select HAVE_SYSCALL_TRACEPOINTS
        select IRQ_DOMAIN
-       select RISCV_ISA_A if SMP
        select SPARSE_IRQ
        select SYSCTL_EXCEPTION_TRACE
        select HAVE_ARCH_TRACEHOOK
@@ -195,9 +194,6 @@ config RISCV_ISA_C
 
           If you don't know what to do here, say Y.
 
-config RISCV_ISA_A
-       def_bool y
-
 menu "supported PMU type"
        depends on PERF_EVENTS
 
index c6342e638ef7cdca40af2960c22f7e38c62ea680..6b0741c9f348729fd6899a721b67aaaa222be15e 100644 (file)
@@ -39,9 +39,8 @@ endif
 KBUILD_CFLAGS += -Wall
 
 # ISA string setting
-riscv-march-$(CONFIG_ARCH_RV32I)       := rv32im
-riscv-march-$(CONFIG_ARCH_RV64I)       := rv64im
-riscv-march-$(CONFIG_RISCV_ISA_A)      := $(riscv-march-y)a
+riscv-march-$(CONFIG_ARCH_RV32I)       := rv32ima
+riscv-march-$(CONFIG_ARCH_RV64I)       := rv64ima
 riscv-march-$(CONFIG_FPU)              := $(riscv-march-y)fd
 riscv-march-$(CONFIG_RISCV_ISA_C)      := $(riscv-march-y)c
 KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y))
index cccd12cf27d44d134f274f49067d294cde3498b0..5a7a19d9aa7fc27a0a0046e62e7ac3e9da19f034 100644 (file)
@@ -4,6 +4,7 @@ generic-y += compat.h
 generic-y += cputime.h
 generic-y += device.h
 generic-y += div64.h
+generic-y += extable.h
 generic-y += dma.h
 generic-y += dma-contiguous.h
 generic-y += dma-mapping.h
index bfc7f099ab1fea28981d2a3a1ffce8aa25e4ea4d..52a1fbdeab3bb2bca2827bdf68a2dc0c79d814a7 100644 (file)
 #include <asm/asm.h>
 
 #ifdef CONFIG_GENERIC_BUG
-#define __BUG_INSN     _AC(0x00100073, UL) /* ebreak */
+#define __INSN_LENGTH_MASK  _UL(0x3)
+#define __INSN_LENGTH_32    _UL(0x3)
+#define __COMPRESSED_INSN_MASK _UL(0xffff)
+
+#define __BUG_INSN_32  _UL(0x00100073) /* ebreak */
+#define __BUG_INSN_16  _UL(0x9002) /* c.ebreak */
 
 #ifndef __ASSEMBLY__
 typedef u32 bug_insn_t;
@@ -38,38 +43,46 @@ typedef u32 bug_insn_t;
 #define __BUG_ENTRY                    \
        __BUG_ENTRY_ADDR "\n\t"         \
        __BUG_ENTRY_FILE "\n\t"         \
-       RISCV_SHORT " %1"
+       RISCV_SHORT " %1\n\t"           \
+       RISCV_SHORT " %2"
 #else
 #define __BUG_ENTRY                    \
-       __BUG_ENTRY_ADDR
+       __BUG_ENTRY_ADDR "\n\t"         \
+       RISCV_SHORT " %2"
 #endif
 
-#define BUG()                                                  \
+#define __BUG_FLAGS(flags)                                     \
 do {                                                           \
        __asm__ __volatile__ (                                  \
                "1:\n\t"                                        \
                        "ebreak\n"                              \
-                       ".pushsection __bug_table,\"a\"\n\t"    \
+                       ".pushsection __bug_table,\"aw\"\n\t"   \
                "2:\n\t"                                        \
                        __BUG_ENTRY "\n\t"                      \
-                       ".org 2b + %2\n\t"                      \
+                       ".org 2b + %3\n\t"                      \
                        ".popsection"                           \
                :                                               \
                : "i" (__FILE__), "i" (__LINE__),               \
-                 "i" (sizeof(struct bug_entry)));              \
-       unreachable();                                          \
+                 "i" (flags),                                  \
+                 "i" (sizeof(struct bug_entry)));              \
 } while (0)
+
 #endif /* !__ASSEMBLY__ */
 #else /* CONFIG_GENERIC_BUG */
 #ifndef __ASSEMBLY__
-#define BUG()                                                  \
-do {                                                           \
+#define __BUG_FLAGS(flags) do {                                        \
        __asm__ __volatile__ ("ebreak\n");                      \
-       unreachable();                                          \
 } while (0)
 #endif /* !__ASSEMBLY__ */
 #endif /* CONFIG_GENERIC_BUG */
 
+#define BUG() do {                                             \
+       __BUG_FLAGS(0);                                         \
+       unreachable();                                          \
+} while (0)
+
+#define __WARN_FLAGS(flags) __BUG_FLAGS(BUGFLAG_WARNING|(flags))
+
 #define HAVE_ARCH_BUG
 
 #include <asm-generic/bug.h>
index 8f13074413a7d652729f7fc4871ac5d2a74eea3e..1f4ba68ab9aa779870a953db9decaa05f948a8c6 100644 (file)
@@ -47,7 +47,7 @@ static inline void flush_dcache_page(struct page *page)
 
 #else /* CONFIG_SMP */
 
-#define flush_icache_all() sbi_remote_fence_i(NULL)
+void flush_icache_all(void);
 void flush_icache_mm(struct mm_struct *mm, bool local);
 
 #endif /* CONFIG_SMP */
index 28a0d1cb374c8c25ce4032da874b974712ca3129..3c3c26c3a1f1e4d3a114de529b3fec7a5e75b0ad 100644 (file)
 #ifndef _ASM_RISCV_CSR_H
 #define _ASM_RISCV_CSR_H
 
+#include <asm/asm.h>
 #include <linux/const.h>
 
 /* Status register flags */
-#define SR_SIE _AC(0x00000002, UL) /* Supervisor Interrupt Enable */
-#define SR_SPIE        _AC(0x00000020, UL) /* Previous Supervisor IE */
-#define SR_SPP _AC(0x00000100, UL) /* Previously Supervisor */
-#define SR_SUM _AC(0x00040000, UL) /* Supervisor may access User Memory */
-
-#define SR_FS           _AC(0x00006000, UL) /* Floating-point Status */
-#define SR_FS_OFF       _AC(0x00000000, UL)
-#define SR_FS_INITIAL   _AC(0x00002000, UL)
-#define SR_FS_CLEAN     _AC(0x00004000, UL)
-#define SR_FS_DIRTY     _AC(0x00006000, UL)
-
-#define SR_XS           _AC(0x00018000, UL) /* Extension Status */
-#define SR_XS_OFF       _AC(0x00000000, UL)
-#define SR_XS_INITIAL   _AC(0x00008000, UL)
-#define SR_XS_CLEAN     _AC(0x00010000, UL)
-#define SR_XS_DIRTY     _AC(0x00018000, UL)
+#define SR_SIE         _AC(0x00000002, UL) /* Supervisor Interrupt Enable */
+#define SR_SPIE                _AC(0x00000020, UL) /* Previous Supervisor IE */
+#define SR_SPP         _AC(0x00000100, UL) /* Previously Supervisor */
+#define SR_SUM         _AC(0x00040000, UL) /* Supervisor User Memory Access */
+
+#define SR_FS          _AC(0x00006000, UL) /* Floating-point Status */
+#define SR_FS_OFF      _AC(0x00000000, UL)
+#define SR_FS_INITIAL  _AC(0x00002000, UL)
+#define SR_FS_CLEAN    _AC(0x00004000, UL)
+#define SR_FS_DIRTY    _AC(0x00006000, UL)
+
+#define SR_XS          _AC(0x00018000, UL) /* Extension Status */
+#define SR_XS_OFF      _AC(0x00000000, UL)
+#define SR_XS_INITIAL  _AC(0x00008000, UL)
+#define SR_XS_CLEAN    _AC(0x00010000, UL)
+#define SR_XS_DIRTY    _AC(0x00018000, UL)
 
 #ifndef CONFIG_64BIT
-#define SR_SD   _AC(0x80000000, UL) /* FS/XS dirty */
+#define SR_SD          _AC(0x80000000, UL) /* FS/XS dirty */
 #else
-#define SR_SD   _AC(0x8000000000000000, UL) /* FS/XS dirty */
+#define SR_SD          _AC(0x8000000000000000, UL) /* FS/XS dirty */
 #endif
 
 /* SATP flags */
-#if __riscv_xlen == 32
-#define SATP_PPN     _AC(0x003FFFFF, UL)
-#define SATP_MODE_32 _AC(0x80000000, UL)
-#define SATP_MODE    SATP_MODE_32
+#ifndef CONFIG_64BIT
+#define SATP_PPN       _AC(0x003FFFFF, UL)
+#define SATP_MODE_32   _AC(0x80000000, UL)
+#define SATP_MODE      SATP_MODE_32
 #else
-#define SATP_PPN     _AC(0x00000FFFFFFFFFFF, UL)
-#define SATP_MODE_39 _AC(0x8000000000000000, UL)
-#define SATP_MODE    SATP_MODE_39
+#define SATP_PPN       _AC(0x00000FFFFFFFFFFF, UL)
+#define SATP_MODE_39   _AC(0x8000000000000000, UL)
+#define SATP_MODE      SATP_MODE_39
 #endif
 
-/* Interrupt Enable and Interrupt Pending flags */
-#define SIE_SSIE _AC(0x00000002, UL) /* Software Interrupt Enable */
-#define SIE_STIE _AC(0x00000020, UL) /* Timer Interrupt Enable */
-#define SIE_SEIE _AC(0x00000200, UL) /* External Interrupt Enable */
-
-#define EXC_INST_MISALIGNED     0
-#define EXC_INST_ACCESS         1
-#define EXC_BREAKPOINT          3
-#define EXC_LOAD_ACCESS         5
-#define EXC_STORE_ACCESS        7
-#define EXC_SYSCALL             8
-#define EXC_INST_PAGE_FAULT     12
-#define EXC_LOAD_PAGE_FAULT     13
-#define EXC_STORE_PAGE_FAULT    15
+/* SCAUSE */
+#define SCAUSE_IRQ_FLAG                (_AC(1, UL) << (__riscv_xlen - 1))
+
+#define IRQ_U_SOFT             0
+#define IRQ_S_SOFT             1
+#define IRQ_M_SOFT             3
+#define IRQ_U_TIMER            4
+#define IRQ_S_TIMER            5
+#define IRQ_M_TIMER            7
+#define IRQ_U_EXT              8
+#define IRQ_S_EXT              9
+#define IRQ_M_EXT              11
+
+#define EXC_INST_MISALIGNED    0
+#define EXC_INST_ACCESS                1
+#define EXC_BREAKPOINT         3
+#define EXC_LOAD_ACCESS                5
+#define EXC_STORE_ACCESS       7
+#define EXC_SYSCALL            8
+#define EXC_INST_PAGE_FAULT    12
+#define EXC_LOAD_PAGE_FAULT    13
+#define EXC_STORE_PAGE_FAULT   15
+
+/* SIE (Interrupt Enable) and SIP (Interrupt Pending) flags */
+#define SIE_SSIE               (_AC(0x1, UL) << IRQ_S_SOFT)
+#define SIE_STIE               (_AC(0x1, UL) << IRQ_S_TIMER)
+#define SIE_SEIE               (_AC(0x1, UL) << IRQ_S_EXT)
+
+#define CSR_CYCLE              0xc00
+#define CSR_TIME               0xc01
+#define CSR_INSTRET            0xc02
+#define CSR_SSTATUS            0x100
+#define CSR_SIE                        0x104
+#define CSR_STVEC              0x105
+#define CSR_SCOUNTEREN         0x106
+#define CSR_SSCRATCH           0x140
+#define CSR_SEPC               0x141
+#define CSR_SCAUSE             0x142
+#define CSR_STVAL              0x143
+#define CSR_SIP                        0x144
+#define CSR_SATP               0x180
+#define CSR_CYCLEH             0xc80
+#define CSR_TIMEH              0xc81
+#define CSR_INSTRETH           0xc82
 
 #ifndef __ASSEMBLY__
 
 #define csr_swap(csr, val)                                     \
 ({                                                             \
        unsigned long __v = (unsigned long)(val);               \
-       __asm__ __volatile__ ("csrrw %0, " #csr ", %1"          \
+       __asm__ __volatile__ ("csrrw %0, " __ASM_STR(csr) ", %1"\
                              : "=r" (__v) : "rK" (__v)         \
                              : "memory");                      \
        __v;                                                    \
 #define csr_read(csr)                                          \
 ({                                                             \
        register unsigned long __v;                             \
-       __asm__ __volatile__ ("csrr %0, " #csr                  \
+       __asm__ __volatile__ ("csrr %0, " __ASM_STR(csr)        \
                              : "=r" (__v) :                    \
                              : "memory");                      \
        __v;                                                    \
 #define csr_write(csr, val)                                    \
 ({                                                             \
        unsigned long __v = (unsigned long)(val);               \
-       __asm__ __volatile__ ("csrw " #csr ", %0"               \
+       __asm__ __volatile__ ("csrw " __ASM_STR(csr) ", %0"     \
                              : : "rK" (__v)                    \
                              : "memory");                      \
 })
 #define csr_read_set(csr, val)                                 \
 ({                                                             \
        unsigned long __v = (unsigned long)(val);               \
-       __asm__ __volatile__ ("csrrs %0, " #csr ", %1"          \
+       __asm__ __volatile__ ("csrrs %0, " __ASM_STR(csr) ", %1"\
                              : "=r" (__v) : "rK" (__v)         \
                              : "memory");                      \
        __v;                                                    \
 #define csr_set(csr, val)                                      \
 ({                                                             \
        unsigned long __v = (unsigned long)(val);               \
-       __asm__ __volatile__ ("csrs " #csr ", %0"               \
+       __asm__ __volatile__ ("csrs " __ASM_STR(csr) ", %0"     \
                              : : "rK" (__v)                    \
                              : "memory");                      \
 })
 #define csr_read_clear(csr, val)                               \
 ({                                                             \
        unsigned long __v = (unsigned long)(val);               \
-       __asm__ __volatile__ ("csrrc %0, " #csr ", %1"          \
+       __asm__ __volatile__ ("csrrc %0, " __ASM_STR(csr) ", %1"\
                              : "=r" (__v) : "rK" (__v)         \
                              : "memory");                      \
        __v;                                                    \
 #define csr_clear(csr, val)                                    \
 ({                                                             \
        unsigned long __v = (unsigned long)(val);               \
-       __asm__ __volatile__ ("csrc " #csr ", %0"               \
+       __asm__ __volatile__ ("csrc " __ASM_STR(csr) ", %0"     \
                              : : "rK" (__v)                    \
                              : "memory");                      \
 })
index 697fc23b0d5ae4f6d6cd508e8d0a2804c277e0ee..ce0cd7d77eb061a33776c04ac65b2898c2c0ce33 100644 (file)
 #define ELF_CLASS      ELFCLASS32
 #endif
 
-#if defined(__LITTLE_ENDIAN)
 #define ELF_DATA       ELFDATA2LSB
-#elif defined(__BIG_ENDIAN)
-#define ELF_DATA       ELFDATA2MSB
-#else
-#error "Unknown endianness"
-#endif
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
index 66641624d8a5e0ff915f04e0461c124a1decddc6..4ad6409c4647db4a4a613817c9abeaf57707f1df 100644 (file)
@@ -7,18 +7,6 @@
 #ifndef _ASM_FUTEX_H
 #define _ASM_FUTEX_H
 
-#ifndef CONFIG_RISCV_ISA_A
-/*
- * Use the generic interrupt disabling versions if the A extension
- * is not supported.
- */
-#ifdef CONFIG_SMP
-#error "Can't support generic futex calls without A extension on SMP"
-#endif
-#include <asm-generic/futex.h>
-
-#else /* CONFIG_RISCV_ISA_A */
-
 #include <linux/futex.h>
 #include <linux/uaccess.h>
 #include <linux/errno.h>
@@ -124,5 +112,4 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
        return ret;
 }
 
-#endif /* CONFIG_RISCV_ISA_A */
 #endif /* _ASM_FUTEX_H */
index 07a3c6d5706ff8fd8f34acbe6c5832fc6e638676..1a69b3bcd3716d4d904f572c93b9e4065c7c2a75 100644 (file)
 /* read interrupt enabled status */
 static inline unsigned long arch_local_save_flags(void)
 {
-       return csr_read(sstatus);
+       return csr_read(CSR_SSTATUS);
 }
 
 /* unconditionally enable interrupts */
 static inline void arch_local_irq_enable(void)
 {
-       csr_set(sstatus, SR_SIE);
+       csr_set(CSR_SSTATUS, SR_SIE);
 }
 
 /* unconditionally disable interrupts */
 static inline void arch_local_irq_disable(void)
 {
-       csr_clear(sstatus, SR_SIE);
+       csr_clear(CSR_SSTATUS, SR_SIE);
 }
 
 /* get status and disable interrupts */
 static inline unsigned long arch_local_irq_save(void)
 {
-       return csr_read_clear(sstatus, SR_SIE);
+       return csr_read_clear(CSR_SSTATUS, SR_SIE);
 }
 
 /* test flags */
@@ -57,7 +57,7 @@ static inline int arch_irqs_disabled(void)
 /* set interrupt enabled status */
 static inline void arch_local_irq_restore(unsigned long flags)
 {
-       csr_set(sstatus, flags & SR_SIE);
+       csr_set(CSR_SSTATUS, flags & SR_SIE);
 }
 
 #endif /* _ASM_RISCV_IRQFLAGS_H */
index 336d60ec56989ca96a351c8fb296b8a6b11c30f5..bf4f097a90511f5a9b715614947e8ee81cd37342 100644 (file)
@@ -20,8 +20,6 @@
 
 #include <linux/mm.h>
 #include <linux/sched.h>
-#include <asm/tlbflush.h>
-#include <asm/cacheflush.h>
 
 static inline void enter_lazy_tlb(struct mm_struct *mm,
        struct task_struct *task)
@@ -39,61 +37,8 @@ static inline void destroy_context(struct mm_struct *mm)
 {
 }
 
-/*
- * When necessary, performs a deferred icache flush for the given MM context,
- * on the local CPU.  RISC-V has no direct mechanism for instruction cache
- * shoot downs, so instead we send an IPI that informs the remote harts they
- * need to flush their local instruction caches.  To avoid pathologically slow
- * behavior in a common case (a bunch of single-hart processes on a many-hart
- * machine, ie 'make -j') we avoid the IPIs for harts that are not currently
- * executing a MM context and instead schedule a deferred local instruction
- * cache flush to be performed before execution resumes on each hart.  This
- * actually performs that local instruction cache flush, which implicitly only
- * refers to the current hart.
- */
-static inline void flush_icache_deferred(struct mm_struct *mm)
-{
-#ifdef CONFIG_SMP
-       unsigned int cpu = smp_processor_id();
-       cpumask_t *mask = &mm->context.icache_stale_mask;
-
-       if (cpumask_test_cpu(cpu, mask)) {
-               cpumask_clear_cpu(cpu, mask);
-               /*
-                * Ensure the remote hart's writes are visible to this hart.
-                * This pairs with a barrier in flush_icache_mm.
-                */
-               smp_mb();
-               local_flush_icache_all();
-       }
-#endif
-}
-
-static inline void switch_mm(struct mm_struct *prev,
-       struct mm_struct *next, struct task_struct *task)
-{
-       if (likely(prev != next)) {
-               /*
-                * Mark the current MM context as inactive, and the next as
-                * active.  This is at least used by the icache flushing
-                * routines in order to determine who should
-                */
-               unsigned int cpu = smp_processor_id();
-
-               cpumask_clear_cpu(cpu, mm_cpumask(prev));
-               cpumask_set_cpu(cpu, mm_cpumask(next));
-
-               /*
-                * Use the old spbtr name instead of using the current satp
-                * name to support binutils 2.29 which doesn't know about the
-                * privileged ISA 1.10 yet.
-                */
-               csr_write(sptbr, virt_to_pfn(next->pgd) | SATP_MODE);
-               local_flush_tlb_all();
-
-               flush_icache_deferred(next);
-       }
-}
+void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+       struct task_struct *task);
 
 static inline void activate_mm(struct mm_struct *prev,
                               struct mm_struct *next)
index d35ec2f413812a9780d7e7d703260c385fee3507..9c867a4bac8371715b7f537efcf3fcb6f591ec59 100644 (file)
@@ -70,47 +70,38 @@ struct pt_regs {
 
 
 /* Helpers for working with the instruction pointer */
-#define GET_IP(regs) ((regs)->sepc)
-#define SET_IP(regs, val) (GET_IP(regs) = (val))
-
 static inline unsigned long instruction_pointer(struct pt_regs *regs)
 {
-       return GET_IP(regs);
+       return regs->sepc;
 }
 static inline void instruction_pointer_set(struct pt_regs *regs,
                                           unsigned long val)
 {
-       SET_IP(regs, val);
+       regs->sepc = val;
 }
 
 #define profile_pc(regs) instruction_pointer(regs)
 
 /* Helpers for working with the user stack pointer */
-#define GET_USP(regs) ((regs)->sp)
-#define SET_USP(regs, val) (GET_USP(regs) = (val))
-
 static inline unsigned long user_stack_pointer(struct pt_regs *regs)
 {
-       return GET_USP(regs);
+       return regs->sp;
 }
 static inline void user_stack_pointer_set(struct pt_regs *regs,
                                          unsigned long val)
 {
-       SET_USP(regs, val);
+       regs->sp =  val;
 }
 
 /* Helpers for working with the frame pointer */
-#define GET_FP(regs) ((regs)->s0)
-#define SET_FP(regs, val) (GET_FP(regs) = (val))
-
 static inline unsigned long frame_pointer(struct pt_regs *regs)
 {
-       return GET_FP(regs);
+       return regs->s0;
 }
 static inline void frame_pointer_set(struct pt_regs *regs,
                                     unsigned long val)
 {
-       SET_FP(regs, val);
+       regs->s0 = val;
 }
 
 static inline unsigned long regs_return_value(struct pt_regs *regs)
index b6bb10b92fe24e902c47f68dd377a0af9cd793fc..19f231615510085af6bec7e690e56f0109c11522 100644 (file)
 #define SBI_REMOTE_SFENCE_VMA_ASID 7
 #define SBI_SHUTDOWN 8
 
-#define SBI_CALL(which, arg0, arg1, arg2) ({                   \
+#define SBI_CALL(which, arg0, arg1, arg2, arg3) ({             \
        register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);   \
        register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);   \
        register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);   \
+       register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);   \
        register uintptr_t a7 asm ("a7") = (uintptr_t)(which);  \
        asm volatile ("ecall"                                   \
                      : "+r" (a0)                               \
-                     : "r" (a1), "r" (a2), "r" (a7)            \
+                     : "r" (a1), "r" (a2), "r" (a3), "r" (a7)  \
                      : "memory");                              \
        a0;                                                     \
 })
 
 /* Lazy implementations until SBI is finalized */
-#define SBI_CALL_0(which) SBI_CALL(which, 0, 0, 0)
-#define SBI_CALL_1(which, arg0) SBI_CALL(which, arg0, 0, 0)
-#define SBI_CALL_2(which, arg0, arg1) SBI_CALL(which, arg0, arg1, 0)
+#define SBI_CALL_0(which) SBI_CALL(which, 0, 0, 0, 0)
+#define SBI_CALL_1(which, arg0) SBI_CALL(which, arg0, 0, 0, 0)
+#define SBI_CALL_2(which, arg0, arg1) SBI_CALL(which, arg0, arg1, 0, 0)
+#define SBI_CALL_3(which, arg0, arg1, arg2) \
+               SBI_CALL(which, arg0, arg1, arg2, 0)
+#define SBI_CALL_4(which, arg0, arg1, arg2, arg3) \
+               SBI_CALL(which, arg0, arg1, arg2, arg3)
 
 static inline void sbi_console_putchar(int ch)
 {
@@ -86,7 +91,7 @@ static inline void sbi_remote_sfence_vma(const unsigned long *hart_mask,
                                         unsigned long start,
                                         unsigned long size)
 {
-       SBI_CALL_1(SBI_REMOTE_SFENCE_VMA, hart_mask);
+       SBI_CALL_3(SBI_REMOTE_SFENCE_VMA, hart_mask, start, size);
 }
 
 static inline void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
@@ -94,7 +99,7 @@ static inline void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
                                              unsigned long size,
                                              unsigned long asid)
 {
-       SBI_CALL_1(SBI_REMOTE_SFENCE_VMA_ASID, hart_mask);
+       SBI_CALL_4(SBI_REMOTE_SFENCE_VMA_ASID, hart_mask, start, size, asid);
 }
 
 #endif
diff --git a/arch/riscv/include/asm/sifive_l2_cache.h b/arch/riscv/include/asm/sifive_l2_cache.h
new file mode 100644 (file)
index 0000000..04f6748
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SiFive L2 Cache Controller header file
+ *
+ */
+
+#ifndef _ASM_RISCV_SIFIVE_L2_CACHE_H
+#define _ASM_RISCV_SIFIVE_L2_CACHE_H
+
+extern int register_sifive_l2_error_notifier(struct notifier_block *nb);
+extern int unregister_sifive_l2_error_notifier(struct notifier_block *nb);
+
+#define SIFIVE_L2_ERR_TYPE_CE 0
+#define SIFIVE_L2_ERR_TYPE_UE 1
+
+#endif /* _ASM_RISCV_SIFIVE_L2_CACHE_H */
index 1c9cc8389928824096dea7564f7ef828af76b37c..9c039870019b6962656997048c520ecee9aa5604 100644 (file)
@@ -28,7 +28,9 @@
 #include <asm/processor.h>
 #include <asm/csr.h>
 
-typedef unsigned long mm_segment_t;
+typedef struct {
+       unsigned long seg;
+} mm_segment_t;
 
 /*
  * low level task data that entry.S needs immediate access to
index fb53a8089e769473434493d59bc408079dcbb519..b26f407be5c8d7a2bb3a353128a6a022b7c82ea8 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/compiler.h>
 #include <linux/thread_info.h>
 #include <asm/byteorder.h>
+#include <asm/extable.h>
 #include <asm/asm.h>
 
 #define __enable_user_access()                                                 \
  * For historical reasons, these macros are grossly misnamed.
  */
 
-#define KERNEL_DS      (~0UL)
-#define USER_DS                (TASK_SIZE)
+#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
+
+#define KERNEL_DS      MAKE_MM_SEG(~0UL)
+#define USER_DS                MAKE_MM_SEG(TASK_SIZE)
 
 #define get_fs()       (current_thread_info()->addr_limit)
 
@@ -48,9 +51,9 @@ static inline void set_fs(mm_segment_t fs)
        current_thread_info()->addr_limit = fs;
 }
 
-#define segment_eq(a, b) ((a) == (b))
+#define segment_eq(a, b) ((a).seg == (b).seg)
 
-#define user_addr_max()        (get_fs())
+#define user_addr_max()        (get_fs().seg)
 
 
 /**
@@ -82,7 +85,7 @@ static inline int __access_ok(unsigned long addr, unsigned long size)
 {
        const mm_segment_t fs = get_fs();
 
-       return (size <= fs) && (addr <= (fs - size));
+       return size <= fs.seg && addr <= fs.seg - size;
 }
 
 /*
@@ -98,21 +101,8 @@ static inline int __access_ok(unsigned long addr, unsigned long size)
  * on our cache or tlb entries.
  */
 
-struct exception_table_entry {
-       unsigned long insn, fixup;
-};
-
-extern int fixup_exception(struct pt_regs *state);
-
-#if defined(__LITTLE_ENDIAN)
-#define __MSW  1
 #define __LSW  0
-#elif defined(__BIG_ENDIAN)
-#define __MSW  0
-#define        __LSW   1
-#else
-#error "Unknown endianness"
-#endif
+#define __MSW  1
 
 /*
  * The "__xxx" versions of the user access functions do not verify the address
index dac98348c6a34a362ffa92fa34829d37d7ea26c9..578bb5efc085cbeddce97d6257f78f59f6c517da 100644 (file)
@@ -312,9 +312,6 @@ void asm_offsets(void)
                - offsetof(struct task_struct, thread.fstate.f[0])
        );
 
-       /* The assembler needs access to THREAD_SIZE as well. */
-       DEFINE(ASM_THREAD_SIZE, THREAD_SIZE);
-
        /*
         * We allocate a pt_regs on the stack when entering the kernel.  This
         * ensures the alignment is sane.
index cf2fca12414a4501a35037ffa020fc6a46e47277..c8d2a322309949d2079662a955b24725ef95344d 100644 (file)
@@ -136,8 +136,7 @@ static void c_stop(struct seq_file *m, void *v)
 static int c_show(struct seq_file *m, void *v)
 {
        unsigned long cpu_id = (unsigned long)v - 1;
-       struct device_node *node = of_get_cpu_node(cpuid_to_hartid_map(cpu_id),
-                                                  NULL);
+       struct device_node *node = of_get_cpu_node(cpu_id, NULL);
        const char *compat, *isa, *mmu;
 
        seq_printf(m, "processor\t: %lu\n", cpu_id);
index fd9b57c8b4cef412091fddd8326f7d64e35544d4..1c1ecc238cfab9092b5dd2d43d1273906276b87d 100644 (file)
         * the kernel thread pointer.  If we came from the kernel, sscratch
         * will contain 0, and we should continue on the current TP.
         */
-       csrrw tp, sscratch, tp
+       csrrw tp, CSR_SSCRATCH, tp
        bnez tp, _save_context
 
 _restore_kernel_tpsp:
-       csrr tp, sscratch
+       csrr tp, CSR_SSCRATCH
        REG_S sp, TASK_TI_KERNEL_SP(tp)
 _save_context:
        REG_S sp, TASK_TI_USER_SP(tp)
@@ -87,11 +87,11 @@ _save_context:
        li t0, SR_SUM | SR_FS
 
        REG_L s0, TASK_TI_USER_SP(tp)
-       csrrc s1, sstatus, t0
-       csrr s2, sepc
-       csrr s3, sbadaddr
-       csrr s4, scause
-       csrr s5, sscratch
+       csrrc s1, CSR_SSTATUS, t0
+       csrr s2, CSR_SEPC
+       csrr s3, CSR_STVAL
+       csrr s4, CSR_SCAUSE
+       csrr s5, CSR_SSCRATCH
        REG_S s0, PT_SP(sp)
        REG_S s1, PT_SSTATUS(sp)
        REG_S s2, PT_SEPC(sp)
@@ -107,8 +107,8 @@ _save_context:
        .macro RESTORE_ALL
        REG_L a0, PT_SSTATUS(sp)
        REG_L a2, PT_SEPC(sp)
-       csrw sstatus, a0
-       csrw sepc, a2
+       csrw CSR_SSTATUS, a0
+       csrw CSR_SEPC, a2
 
        REG_L x1,  PT_RA(sp)
        REG_L x3,  PT_GP(sp)
@@ -155,7 +155,7 @@ ENTRY(handle_exception)
         * Set sscratch register to 0, so that if a recursive exception
         * occurs, the exception vector knows it came from the kernel
         */
-       csrw sscratch, x0
+       csrw CSR_SSCRATCH, x0
 
        /* Load the global pointer */
 .option push
@@ -248,7 +248,7 @@ resume_userspace:
         * Save TP into sscratch, so we can find the kernel data structures
         * again.
         */
-       csrw sscratch, tp
+       csrw CSR_SSCRATCH, tp
 
 restore_all:
        RESTORE_ALL
index fe884cd69abd8f0d7b3fe3a9e20b781937a32502..370c66ce187a8e9225f5ece5dca9043f56d729f6 100644 (file)
@@ -23,7 +23,8 @@
 __INIT
 ENTRY(_start)
        /* Mask all interrupts */
-       csrw sie, zero
+       csrw CSR_SIE, zero
+       csrw CSR_SIP, zero
 
        /* Load the global pointer */
 .option push
@@ -68,14 +69,10 @@ clear_bss_done:
        /* Restore C environment */
        la tp, init_task
        sw zero, TASK_TI_CPU(tp)
-
-       la sp, init_thread_union
-       li a0, ASM_THREAD_SIZE
-       add sp, sp, a0
+       la sp, init_thread_union + THREAD_SIZE
 
        /* Start the kernel */
-       mv a0, s0
-       mv a1, s1
+       mv a0, s1
        call parse_dtb
        tail start_kernel
 
@@ -89,7 +86,7 @@ relocate:
        /* Point stvec to virtual address of intruction after satp write */
        la a0, 1f
        add a0, a0, a1
-       csrw stvec, a0
+       csrw CSR_STVEC, a0
 
        /* Compute satp for kernel page tables, but don't load it yet */
        la a2, swapper_pg_dir
@@ -99,18 +96,20 @@ relocate:
 
        /*
         * Load trampoline page directory, which will cause us to trap to
-        * stvec if VA != PA, or simply fall through if VA == PA
+        * stvec if VA != PA, or simply fall through if VA == PA.  We need a
+        * full fence here because setup_vm() just wrote these PTEs and we need
+        * to ensure the new translations are in use.
         */
        la a0, trampoline_pg_dir
        srl a0, a0, PAGE_SHIFT
        or a0, a0, a1
        sfence.vma
-       csrw sptbr, a0
+       csrw CSR_SATP, a0
 .align 2
 1:
        /* Set trap vector to spin forever to help debug */
        la a0, .Lsecondary_park
-       csrw stvec, a0
+       csrw CSR_STVEC, a0
 
        /* Reload the global pointer */
 .option push
@@ -118,8 +117,14 @@ relocate:
        la gp, __global_pointer$
 .option pop
 
-       /* Switch to kernel page tables */
-       csrw sptbr, a2
+       /*
+        * Switch to kernel page tables.  A full fence is necessary in order to
+        * avoid using the trampoline translations, which are only correct for
+        * the first superpage.  Fetching the fence is guarnteed to work
+        * because that first superpage is translated the same way.
+        */
+       csrw CSR_SATP, a2
+       sfence.vma
 
        ret
 
@@ -130,7 +135,7 @@ relocate:
 
        /* Set trap vector to spin forever to help debug */
        la a3, .Lsecondary_park
-       csrw stvec, a3
+       csrw CSR_STVEC, a3
 
        slli a3, a0, LGREG
        la a1, __cpu_up_stack_pointer
index 48e6b7db83a1d17db763e362a15500602b1711e7..6d8659388c4922e1bb4bf5f67121e3407f570129 100644 (file)
 /*
  * Possible interrupt causes:
  */
-#define INTERRUPT_CAUSE_SOFTWARE    1
-#define INTERRUPT_CAUSE_TIMER       5
-#define INTERRUPT_CAUSE_EXTERNAL    9
-
-/*
- * The high order bit of the trap cause register is always set for
- * interrupts, which allows us to differentiate them from exceptions
- * quickly.  The INTERRUPT_CAUSE_* macros don't contain that bit, so we
- * need to mask it off.
- */
-#define INTERRUPT_CAUSE_FLAG   (1UL << (__riscv_xlen - 1))
+#define INTERRUPT_CAUSE_SOFTWARE       IRQ_S_SOFT
+#define INTERRUPT_CAUSE_TIMER          IRQ_S_TIMER
+#define INTERRUPT_CAUSE_EXTERNAL       IRQ_S_EXT
 
 int arch_show_interrupts(struct seq_file *p, int prec)
 {
@@ -37,7 +29,7 @@ asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs)
        struct pt_regs *old_regs = set_irq_regs(regs);
 
        irq_enter();
-       switch (regs->scause & ~INTERRUPT_CAUSE_FLAG) {
+       switch (regs->scause & ~SCAUSE_IRQ_FLAG) {
        case INTERRUPT_CAUSE_TIMER:
                riscv_timer_interrupt();
                break;
@@ -54,7 +46,8 @@ asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs)
                handle_arch_irq(regs);
                break;
        default:
-               panic("unexpected interrupt cause");
+               pr_alert("unexpected interrupt cause 0x%lx", regs->scause);
+               BUG();
        }
        irq_exit();
 
index 667ee70defea163ee92eb7cfcb12fffeefa019dd..91626d9ae5f23d5304d3eabd289c01b09a559991 100644 (file)
@@ -185,10 +185,10 @@ static inline u64 read_counter(int idx)
 
        switch (idx) {
        case RISCV_PMU_CYCLE:
-               val = csr_read(cycle);
+               val = csr_read(CSR_CYCLE);
                break;
        case RISCV_PMU_INSTRET:
-               val = csr_read(instret);
+               val = csr_read(CSR_INSTRET);
                break;
        default:
                WARN_ON_ONCE(idx < 0 || idx > RISCV_MAX_COUNTERS);
index 2a53d26ffdd67f7062de4e0efbdc0a209cdf3597..ed637aee514b3a711c77201ba5f843ac90a7bc1c 100644 (file)
  */
 
 #include <linux/reboot.h>
-#include <linux/export.h>
 #include <asm/sbi.h>
 
-void (*pm_power_off)(void) = machine_power_off;
-EXPORT_SYMBOL(pm_power_off);
+static void default_power_off(void)
+{
+       sbi_shutdown();
+       while (1);
+}
+
+void (*pm_power_off)(void) = default_power_off;
 
 void machine_restart(char *cmd)
 {
@@ -26,11 +30,10 @@ void machine_restart(char *cmd)
 
 void machine_halt(void)
 {
-       machine_power_off();
+       pm_power_off();
 }
 
 void machine_power_off(void)
 {
-       sbi_shutdown();
-       while (1);
+       pm_power_off();
 }
index 540a331d1376922c62ba17bf0d9c786714d89948..d93bcce004e3e5bda58040294fb102095a405bfe 100644 (file)
@@ -52,9 +52,11 @@ struct screen_info screen_info = {
 atomic_t hart_lottery;
 unsigned long boot_cpu_hartid;
 
-void __init parse_dtb(unsigned int hartid, void *dtb)
+void __init parse_dtb(phys_addr_t dtb_phys)
 {
-       if (early_init_dt_scan(__va(dtb)))
+       void *dtb = __va(dtb_phys);
+
+       if (early_init_dt_scan(dtb))
                return;
 
        pr_err("No DTB passed to the kernel\n");
index 837e1646091a83ecb81feda8ddefb4b5914cdce8..804d6ee4f3c5b3b743bdf5ff3c82e61fe016f329 100644 (file)
@@ -234,6 +234,9 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 
        /* Are we from a system call? */
        if (regs->scause == EXC_SYSCALL) {
+               /* Avoid additional syscall restarting via ret_from_exception */
+               regs->scause = -1UL;
+
                /* If so, check system call restarting.. */
                switch (regs->a0) {
                case -ERESTART_RESTARTBLOCK:
@@ -272,6 +275,9 @@ static void do_signal(struct pt_regs *regs)
 
        /* Did we come from a system call? */
        if (regs->scause == EXC_SYSCALL) {
+               /* Avoid additional syscall restarting via ret_from_exception */
+               regs->scause = -1UL;
+
                /* Restart the system call - no handlers present */
                switch (regs->a0) {
                case -ERESTARTNOHAND:
index 0c41d07ec281e4a6c94e7a53b975c66ac2c44e49..b2537ffa855c4d812ab5ab6d8de06783b65b63a7 100644 (file)
@@ -42,7 +42,7 @@ unsigned long __cpuid_to_hartid_map[NR_CPUS] = {
 
 void __init smp_setup_processor_id(void)
 {
-       cpuid_to_hartid_map(0) = boot_cpu_hartid;
+       cpuid_to_hartid_map(0) = boot_cpu_hartid;
 }
 
 /* A collection of single bit ipi messages.  */
@@ -53,7 +53,7 @@ static struct {
 
 int riscv_hartid_to_cpuid(int hartid)
 {
-       int i = -1;
+       int i;
 
        for (i = 0; i < NR_CPUS; i++)
                if (cpuid_to_hartid_map(i) == hartid)
@@ -70,6 +70,12 @@ void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out)
        for_each_cpu(cpu, in)
                cpumask_set_cpu(cpuid_to_hartid_map(cpu), out);
 }
+
+bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
+{
+       return phys_id == cpuid_to_hartid_map(cpu);
+}
+
 /* Unsupported */
 int setup_profiling_timer(unsigned int multiplier)
 {
@@ -89,7 +95,7 @@ void riscv_software_interrupt(void)
        unsigned long *stats = ipi_data[smp_processor_id()].stats;
 
        /* Clear pending IPI */
-       csr_clear(sip, SIE_SSIE);
+       csr_clear(CSR_SIP, SIE_SSIE);
 
        while (true) {
                unsigned long ops;
@@ -199,52 +205,3 @@ void smp_send_reschedule(int cpu)
        send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
 }
 
-/*
- * Performs an icache flush for the given MM context.  RISC-V has no direct
- * mechanism for instruction cache shoot downs, so instead we send an IPI that
- * informs the remote harts they need to flush their local instruction caches.
- * To avoid pathologically slow behavior in a common case (a bunch of
- * single-hart processes on a many-hart machine, ie 'make -j') we avoid the
- * IPIs for harts that are not currently executing a MM context and instead
- * schedule a deferred local instruction cache flush to be performed before
- * execution resumes on each hart.
- */
-void flush_icache_mm(struct mm_struct *mm, bool local)
-{
-       unsigned int cpu;
-       cpumask_t others, hmask, *mask;
-
-       preempt_disable();
-
-       /* Mark every hart's icache as needing a flush for this MM. */
-       mask = &mm->context.icache_stale_mask;
-       cpumask_setall(mask);
-       /* Flush this hart's I$ now, and mark it as flushed. */
-       cpu = smp_processor_id();
-       cpumask_clear_cpu(cpu, mask);
-       local_flush_icache_all();
-
-       /*
-        * Flush the I$ of other harts concurrently executing, and mark them as
-        * flushed.
-        */
-       cpumask_andnot(&others, mm_cpumask(mm), cpumask_of(cpu));
-       local |= cpumask_empty(&others);
-       if (mm != current->active_mm || !local) {
-               cpumask_clear(&hmask);
-               riscv_cpuid_to_hartid_mask(&others, &hmask);
-               sbi_remote_fence_i(hmask.bits);
-       } else {
-               /*
-                * It's assumed that at least one strongly ordered operation is
-                * performed on this hart between setting a hart's cpumask bit
-                * and scheduling this MM context on that hart.  Sending an SBI
-                * remote message will do this, but in the case where no
-                * messages are sent we still need to order this hart's writes
-                * with flush_icache_deferred().
-                */
-               smp_mb();
-       }
-
-       preempt_enable();
-}
index eb533b5c2c8c04d6552664439602fcd204748b0c..7a0b62252524547780407e219ff0fb418be00dea 100644 (file)
@@ -47,6 +47,17 @@ void __init smp_prepare_boot_cpu(void)
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
+       int cpuid;
+
+       /* This covers non-smp usecase mandated by "nosmp" option */
+       if (max_cpus == 0)
+               return;
+
+       for_each_possible_cpu(cpuid) {
+               if (cpuid == smp_processor_id())
+                       continue;
+               set_cpu_present(cpuid, true);
+       }
 }
 
 void __init setup_smp(void)
@@ -73,12 +84,19 @@ void __init setup_smp(void)
                }
 
                cpuid_to_hartid_map(cpuid) = hart;
-               set_cpu_possible(cpuid, true);
-               set_cpu_present(cpuid, true);
                cpuid++;
        }
 
        BUG_ON(!found_boot_cpu);
+
+       if (cpuid > nr_cpu_ids)
+               pr_warn("Total number of cpus [%d] is greater than nr_cpus option value [%d]\n",
+                       cpuid, nr_cpu_ids);
+
+       for (cpuid = 1; cpuid < nr_cpu_ids; cpuid++) {
+               if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID)
+                       set_cpu_possible(cpuid, true);
+       }
 }
 
 int __cpu_up(unsigned int cpu, struct task_struct *tidle)
index 4d403274c2e8d0436f2c74e3719cbc75fc057db8..e80a5e8da119bd4381e252cc3654c2ba971c8f40 100644 (file)
@@ -33,9 +33,9 @@ static void notrace walk_stackframe(struct task_struct *task,
        unsigned long fp, sp, pc;
 
        if (regs) {
-               fp = GET_FP(regs);
-               sp = GET_USP(regs);
-               pc = GET_IP(regs);
+               fp = frame_pointer(regs);
+               sp = user_stack_pointer(regs);
+               pc = instruction_pointer(regs);
        } else if (task == NULL || task == current) {
                const register unsigned long current_sp __asm__ ("sp");
                fp = (unsigned long)__builtin_frame_address(0);
@@ -64,12 +64,8 @@ static void notrace walk_stackframe(struct task_struct *task,
                frame = (struct stackframe *)fp - 1;
                sp = fp;
                fp = frame->fp;
-#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
                pc = ftrace_graph_ret_addr(current, NULL, frame->ra,
                                           (unsigned long *)(fp - 8));
-#else
-               pc = frame->ra - 0x4;
-#endif
        }
 }
 
@@ -82,8 +78,8 @@ static void notrace walk_stackframe(struct task_struct *task,
        unsigned long *ksp;
 
        if (regs) {
-               sp = GET_USP(regs);
-               pc = GET_IP(regs);
+               sp = user_stack_pointer(regs);
+               pc = instruction_pointer(regs);
        } else if (task == NULL || task == current) {
                const register unsigned long current_sp __asm__ ("sp");
                sp = current_sp;
index 24a9333dda2cb9bb407d3c4ee1f3954714d30f01..3d1a651dc54c71638fa3435ad6d66dee33dff6e7 100644 (file)
@@ -70,7 +70,7 @@ void do_trap(struct pt_regs *regs, int signo, int code,
            && printk_ratelimit()) {
                pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x" REG_FMT,
                        tsk->comm, task_pid_nr(tsk), signo, code, addr);
-               print_vma_addr(KERN_CONT " in ", GET_IP(regs));
+               print_vma_addr(KERN_CONT " in ", instruction_pointer(regs));
                pr_cont("\n");
                show_regs(regs);
        }
@@ -118,6 +118,17 @@ DO_ERROR_INFO(do_trap_ecall_s,
 DO_ERROR_INFO(do_trap_ecall_m,
        SIGILL, ILL_ILLTRP, "environment call from M-mode");
 
+#ifdef CONFIG_GENERIC_BUG
+static inline unsigned long get_break_insn_length(unsigned long pc)
+{
+       bug_insn_t insn;
+
+       if (probe_kernel_address((bug_insn_t *)pc, insn))
+               return 0;
+       return (((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32) ? 4UL : 2UL);
+}
+#endif /* CONFIG_GENERIC_BUG */
+
 asmlinkage void do_trap_break(struct pt_regs *regs)
 {
 #ifdef CONFIG_GENERIC_BUG
@@ -129,8 +140,8 @@ asmlinkage void do_trap_break(struct pt_regs *regs)
                case BUG_TRAP_TYPE_NONE:
                        break;
                case BUG_TRAP_TYPE_WARN:
-                       regs->sepc += sizeof(bug_insn_t);
-                       return;
+                       regs->sepc += get_break_insn_length(regs->sepc);
+                       break;
                case BUG_TRAP_TYPE_BUG:
                        die(regs, "Kernel BUG");
                }
@@ -145,11 +156,14 @@ int is_valid_bugaddr(unsigned long pc)
 {
        bug_insn_t insn;
 
-       if (pc < PAGE_OFFSET)
+       if (pc < VMALLOC_START)
                return 0;
        if (probe_kernel_address((bug_insn_t *)pc, insn))
                return 0;
-       return (insn == __BUG_INSN);
+       if ((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32)
+               return (insn == __BUG_INSN_32);
+       else
+               return ((insn & __COMPRESSED_INSN_MASK) == __BUG_INSN_16);
 }
 #endif /* CONFIG_GENERIC_BUG */
 
@@ -159,9 +173,9 @@ void __init trap_init(void)
         * Set sup0 scratch register to 0, indicating to exception vector
         * that we are presently executing in the kernel
         */
-       csr_write(sscratch, 0);
+       csr_write(CSR_SSCRATCH, 0);
        /* Set the exception vector address */
-       csr_write(stvec, &handle_exception);
+       csr_write(CSR_STVEC, &handle_exception);
        /* Enable all interrupts */
-       csr_write(sie, -1);
+       csr_write(CSR_SIE, -1);
 }
index fec62b24df8960bfd77a3c669eb65f6741a3dd67..b07b765f312a1e376f361de8dc254f78a7333dfc 100644 (file)
@@ -36,7 +36,7 @@ $(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso) FORCE
 # these symbols in the kernel code rather than hand-coded addresses.
 
 SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \
-                            $(call cc-ldoption, -Wl$(comma)--hash-style=both)
+       -Wl,--hash-style=both
 $(obj)/vdso-dummy.o: $(src)/vdso.lds $(obj)/rt_sigreturn.o FORCE
        $(call if_changed,vdsold)
 
index b68aac7018031cd5afe4ebb293051cbcc814969e..8db5691414850a0731118d8b502823aeee190d8c 100644 (file)
@@ -9,3 +9,5 @@ obj-y += fault.o
 obj-y += extable.o
 obj-y += ioremap.o
 obj-y += cacheflush.o
+obj-y += context.o
+obj-y += sifive_l2_cache.o
index 498c0a0814fe3fa2ddaa59cd0de0831aa94eba87..497b7d07af0c3967feef76a86dde90025b2edea0 100644 (file)
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
 
+#ifdef CONFIG_SMP
+
+#include <asm/sbi.h>
+
+void flush_icache_all(void)
+{
+       sbi_remote_fence_i(NULL);
+}
+
+/*
+ * Performs an icache flush for the given MM context.  RISC-V has no direct
+ * mechanism for instruction cache shoot downs, so instead we send an IPI that
+ * informs the remote harts they need to flush their local instruction caches.
+ * To avoid pathologically slow behavior in a common case (a bunch of
+ * single-hart processes on a many-hart machine, ie 'make -j') we avoid the
+ * IPIs for harts that are not currently executing a MM context and instead
+ * schedule a deferred local instruction cache flush to be performed before
+ * execution resumes on each hart.
+ */
+void flush_icache_mm(struct mm_struct *mm, bool local)
+{
+       unsigned int cpu;
+       cpumask_t others, hmask, *mask;
+
+       preempt_disable();
+
+       /* Mark every hart's icache as needing a flush for this MM. */
+       mask = &mm->context.icache_stale_mask;
+       cpumask_setall(mask);
+       /* Flush this hart's I$ now, and mark it as flushed. */
+       cpu = smp_processor_id();
+       cpumask_clear_cpu(cpu, mask);
+       local_flush_icache_all();
+
+       /*
+        * Flush the I$ of other harts concurrently executing, and mark them as
+        * flushed.
+        */
+       cpumask_andnot(&others, mm_cpumask(mm), cpumask_of(cpu));
+       local |= cpumask_empty(&others);
+       if (mm != current->active_mm || !local) {
+               cpumask_clear(&hmask);
+               riscv_cpuid_to_hartid_mask(&others, &hmask);
+               sbi_remote_fence_i(hmask.bits);
+       } else {
+               /*
+                * It's assumed that at least one strongly ordered operation is
+                * performed on this hart between setting a hart's cpumask bit
+                * and scheduling this MM context on that hart.  Sending an SBI
+                * remote message will do this, but in the case where no
+                * messages are sent we still need to order this hart's writes
+                * with flush_icache_deferred().
+                */
+               smp_mb();
+       }
+
+       preempt_enable();
+}
+
+#endif /* CONFIG_SMP */
+
 void flush_icache_pte(pte_t pte)
 {
        struct page *page = pte_page(pte);
diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c
new file mode 100644 (file)
index 0000000..89ceb3c
--- /dev/null
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2012 Regents of the University of California
+ * Copyright (C) 2017 SiFive
+ */
+
+#include <linux/mm.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+
+/*
+ * When necessary, performs a deferred icache flush for the given MM context,
+ * on the local CPU.  RISC-V has no direct mechanism for instruction cache
+ * shoot downs, so instead we send an IPI that informs the remote harts they
+ * need to flush their local instruction caches.  To avoid pathologically slow
+ * behavior in a common case (a bunch of single-hart processes on a many-hart
+ * machine, ie 'make -j') we avoid the IPIs for harts that are not currently
+ * executing a MM context and instead schedule a deferred local instruction
+ * cache flush to be performed before execution resumes on each hart.  This
+ * actually performs that local instruction cache flush, which implicitly only
+ * refers to the current hart.
+ */
+static inline void flush_icache_deferred(struct mm_struct *mm)
+{
+#ifdef CONFIG_SMP
+       unsigned int cpu = smp_processor_id();
+       cpumask_t *mask = &mm->context.icache_stale_mask;
+
+       if (cpumask_test_cpu(cpu, mask)) {
+               cpumask_clear_cpu(cpu, mask);
+               /*
+                * Ensure the remote hart's writes are visible to this hart.
+                * This pairs with a barrier in flush_icache_mm.
+                */
+               smp_mb();
+               local_flush_icache_all();
+       }
+
+#endif
+}
+
+void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+       struct task_struct *task)
+{
+       unsigned int cpu;
+
+       if (unlikely(prev == next))
+               return;
+
+       /*
+        * Mark the current MM context as inactive, and the next as
+        * active.  This is at least used by the icache flushing
+        * routines in order to determine who should be flushed.
+        */
+       cpu = smp_processor_id();
+
+       cpumask_clear_cpu(cpu, mm_cpumask(prev));
+       cpumask_set_cpu(cpu, mm_cpumask(next));
+
+       /*
+        * Use the old spbtr name instead of using the current satp
+        * name to support binutils 2.29 which doesn't know about the
+        * privileged ISA 1.10 yet.
+        */
+       csr_write(sptbr, virt_to_pfn(next->pgd) | SATP_MODE);
+       local_flush_tlb_all();
+
+       flush_icache_deferred(next);
+}
index 88401d5125bcc0b354833eb5205b7b995f033752..cec8be9e2d6aca1049945fc0a4200f0ef36071b0 100644 (file)
@@ -229,8 +229,9 @@ vmalloc_fault:
                pte_t *pte_k;
                int index;
 
+               /* User mode accesses just cause a SIGSEGV */
                if (user_mode(regs))
-                       goto bad_area;
+                       return do_trap(regs, SIGSEGV, code, addr, tsk);
 
                /*
                 * Synchronize this task's top level page-table
@@ -239,13 +240,9 @@ vmalloc_fault:
                 * Do _not_ use "tsk->active_mm->pgd" here.
                 * We might be inside an interrupt in the middle
                 * of a task switch.
-                *
-                * Note: Use the old spbtr name instead of using the current
-                * satp name to support binutils 2.29 which doesn't know about
-                * the privileged ISA 1.10 yet.
                 */
                index = pgd_index(addr);
-               pgd = (pgd_t *)pfn_to_virt(csr_read(sptbr)) + index;
+               pgd = (pgd_t *)pfn_to_virt(csr_read(CSR_SATP)) + index;
                pgd_k = init_mm.pgd + index;
 
                if (!pgd_present(*pgd_k))
index bc7b77e34d0920f2190c7e8c4edd18658c526703..8bf6f9c2d48c4fcc05230c10dc0e6faf9435ee04 100644 (file)
@@ -66,11 +66,6 @@ void __init mem_init(void)
        mem_init_print_info(NULL);
 }
 
-void free_initmem(void)
-{
-       free_initmem_default(0);
-}
-
 #ifdef CONFIG_BLK_DEV_INITRD
 static void __init setup_initrd(void)
 {
diff --git a/arch/riscv/mm/sifive_l2_cache.c b/arch/riscv/mm/sifive_l2_cache.c
new file mode 100644 (file)
index 0000000..4eb6461
--- /dev/null
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SiFive L2 cache controller Driver
+ *
+ * Copyright (C) 2018-2019 SiFive, Inc.
+ *
+ */
+#include <linux/debugfs.h>
+#include <linux/interrupt.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <asm/sifive_l2_cache.h>
+
+#define SIFIVE_L2_DIRECCFIX_LOW 0x100
+#define SIFIVE_L2_DIRECCFIX_HIGH 0x104
+#define SIFIVE_L2_DIRECCFIX_COUNT 0x108
+
+#define SIFIVE_L2_DATECCFIX_LOW 0x140
+#define SIFIVE_L2_DATECCFIX_HIGH 0x144
+#define SIFIVE_L2_DATECCFIX_COUNT 0x148
+
+#define SIFIVE_L2_DATECCFAIL_LOW 0x160
+#define SIFIVE_L2_DATECCFAIL_HIGH 0x164
+#define SIFIVE_L2_DATECCFAIL_COUNT 0x168
+
+#define SIFIVE_L2_CONFIG 0x00
+#define SIFIVE_L2_WAYENABLE 0x08
+#define SIFIVE_L2_ECCINJECTERR 0x40
+
+#define SIFIVE_L2_MAX_ECCINTR 3
+
+static void __iomem *l2_base;
+static int g_irq[SIFIVE_L2_MAX_ECCINTR];
+
+enum {
+       DIR_CORR = 0,
+       DATA_CORR,
+       DATA_UNCORR,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *sifive_test;
+
+static ssize_t l2_write(struct file *file, const char __user *data,
+                       size_t count, loff_t *ppos)
+{
+       unsigned int val;
+
+       if (kstrtouint_from_user(data, count, 0, &val))
+               return -EINVAL;
+       if ((val >= 0 && val < 0xFF) || (val >= 0x10000 && val < 0x100FF))
+               writel(val, l2_base + SIFIVE_L2_ECCINJECTERR);
+       else
+               return -EINVAL;
+       return count;
+}
+
+static const struct file_operations l2_fops = {
+       .owner = THIS_MODULE,
+       .open = simple_open,
+       .write = l2_write
+};
+
+static void setup_sifive_debug(void)
+{
+       sifive_test = debugfs_create_dir("sifive_l2_cache", NULL);
+
+       debugfs_create_file("sifive_debug_inject_error", 0200,
+                           sifive_test, NULL, &l2_fops);
+}
+#endif
+
+static void l2_config_read(void)
+{
+       u32 regval, val;
+
+       regval = readl(l2_base + SIFIVE_L2_CONFIG);
+       val = regval & 0xFF;
+       pr_info("L2CACHE: No. of Banks in the cache: %d\n", val);
+       val = (regval & 0xFF00) >> 8;
+       pr_info("L2CACHE: No. of ways per bank: %d\n", val);
+       val = (regval & 0xFF0000) >> 16;
+       pr_info("L2CACHE: Sets per bank: %llu\n", (uint64_t)1 << val);
+       val = (regval & 0xFF000000) >> 24;
+       pr_info("L2CACHE: Bytes per cache block: %llu\n", (uint64_t)1 << val);
+
+       regval = readl(l2_base + SIFIVE_L2_WAYENABLE);
+       pr_info("L2CACHE: Index of the largest way enabled: %d\n", regval);
+}
+
+static const struct of_device_id sifive_l2_ids[] = {
+       { .compatible = "sifive,fu540-c000-ccache" },
+       { /* end of table */ },
+};
+
+static ATOMIC_NOTIFIER_HEAD(l2_err_chain);
+
+int register_sifive_l2_error_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(&l2_err_chain, nb);
+}
+EXPORT_SYMBOL_GPL(register_sifive_l2_error_notifier);
+
+int unregister_sifive_l2_error_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_unregister(&l2_err_chain, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_sifive_l2_error_notifier);
+
+static irqreturn_t l2_int_handler(int irq, void *device)
+{
+       unsigned int regval, add_h, add_l;
+
+       if (irq == g_irq[DIR_CORR]) {
+               add_h = readl(l2_base + SIFIVE_L2_DIRECCFIX_HIGH);
+               add_l = readl(l2_base + SIFIVE_L2_DIRECCFIX_LOW);
+               pr_err("L2CACHE: DirError @ 0x%08X.%08X\n", add_h, add_l);
+               regval = readl(l2_base + SIFIVE_L2_DIRECCFIX_COUNT);
+               atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE,
+                                          "DirECCFix");
+       }
+       if (irq == g_irq[DATA_CORR]) {
+               add_h = readl(l2_base + SIFIVE_L2_DATECCFIX_HIGH);
+               add_l = readl(l2_base + SIFIVE_L2_DATECCFIX_LOW);
+               pr_err("L2CACHE: DataError @ 0x%08X.%08X\n", add_h, add_l);
+               regval = readl(l2_base + SIFIVE_L2_DATECCFIX_COUNT);
+               atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE,
+                                          "DatECCFix");
+       }
+       if (irq == g_irq[DATA_UNCORR]) {
+               add_h = readl(l2_base + SIFIVE_L2_DATECCFAIL_HIGH);
+               add_l = readl(l2_base + SIFIVE_L2_DATECCFAIL_LOW);
+               pr_err("L2CACHE: DataFail @ 0x%08X.%08X\n", add_h, add_l);
+               regval = readl(l2_base + SIFIVE_L2_DATECCFAIL_COUNT);
+               atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_UE,
+                                          "DatECCFail");
+       }
+
+       return IRQ_HANDLED;
+}
+
+int __init sifive_l2_init(void)
+{
+       struct device_node *np;
+       struct resource res;
+       int i, rc;
+
+       np = of_find_matching_node(NULL, sifive_l2_ids);
+       if (!np)
+               return -ENODEV;
+
+       if (of_address_to_resource(np, 0, &res))
+               return -ENODEV;
+
+       l2_base = ioremap(res.start, resource_size(&res));
+       if (!l2_base)
+               return -ENOMEM;
+
+       for (i = 0; i < SIFIVE_L2_MAX_ECCINTR; i++) {
+               g_irq[i] = irq_of_parse_and_map(np, i);
+               rc = request_irq(g_irq[i], l2_int_handler, 0, "l2_ecc", NULL);
+               if (rc) {
+                       pr_err("L2CACHE: Could not request IRQ %d\n", g_irq[i]);
+                       return rc;
+               }
+       }
+
+       l2_config_read();
+
+#ifdef CONFIG_DEBUG_FS
+       setup_sifive_debug();
+#endif
+       return 0;
+}
+device_initcall(sifive_l2_init);
index 07485582d0272a610b74e59f24bc4770bde20c5f..109243fdb6ec96d04349072329db3367e233e724 100644 (file)
@@ -63,7 +63,7 @@ config S390
        select ARCH_HAS_ELF_RANDOMIZE
        select ARCH_HAS_FORTIFY_SOURCE
        select ARCH_HAS_GCOV_PROFILE_ALL
-       select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA
+       select ARCH_HAS_GIGANTIC_PAGE
        select ARCH_HAS_KCOV
        select ARCH_HAS_PTE_SPECIAL
        select ARCH_HAS_SET_MEMORY
@@ -100,6 +100,7 @@ config S390
        select ARCH_INLINE_WRITE_UNLOCK_BH
        select ARCH_INLINE_WRITE_UNLOCK_IRQ
        select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE
+       select ARCH_KEEP_MEMBLOCK
        select ARCH_SAVE_PAGE_KEYS if HIBERNATION
        select ARCH_SUPPORTS_ATOMIC_RMW
        select ARCH_SUPPORTS_NUMA_BALANCING
index df1d6a150f3007a0cc6cfab410c9637ea0221170..de8521fc9de58da66c68ac15f795834914bf83ee 100644 (file)
@@ -10,6 +10,8 @@
 # Copyright (C) 1994 by Linus Torvalds
 #
 
+KBUILD_DEFCONFIG := defconfig
+
 LD_BFD         := elf64-s390
 KBUILD_LDFLAGS := -m elf64_s390
 KBUILD_AFLAGS_MODULE += -fPIC
index c51496bbac1906c721485be0b2abac71106f6631..7cba96e7587bca0d3d523483884a6c5f5ee48071 100644 (file)
@@ -58,7 +58,6 @@ define cmd_section_cmp
        touch $@
 endef
 
-OBJCOPYFLAGS_bzImage := --pad-to $$(readelf -s $(obj)/compressed/vmlinux | awk '/\<_end\>/ {print or(strtonum("0x"$$2),4095)+1}')
 $(obj)/bzImage: $(obj)/compressed/vmlinux $(obj)/section_cmp.boot.data $(obj)/section_cmp.boot.preserved.data FORCE
        $(call if_changed,objcopy)
 
index 112b8d9f1e4cd9752e70eff11d3a164f5ac72c31..635217eb3d91b2326b05edb0a4c0fc9c87d8027a 100644 (file)
@@ -77,6 +77,8 @@ SECTIONS
                _compressed_start = .;
                *(.vmlinux.bin.compressed)
                _compressed_end = .;
+               FILL(0xff);
+               . = ALIGN(4096);
        }
        . = ALIGN(256);
        .bss : {
diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig
new file mode 100644 (file)
index 0000000..c59b922
--- /dev/null
@@ -0,0 +1,254 @@
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_USELIB=y
+CONFIG_AUDIT=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+# CONFIG_CPU_ISOLATION is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_HUGETLB=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_PERF=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_CHECKPOINT_RESTORE=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EXPERT=y
+# CONFIG_SYSFS_SYSCALL is not set
+CONFIG_BPF_SYSCALL=y
+CONFIG_USERFAULTFD=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_LIVEPATCH=y
+CONFIG_NR_CPUS=256
+CONFIG_NUMA=y
+CONFIG_HZ_100=y
+CONFIG_KEXEC_FILE=y
+CONFIG_KEXEC_VERIFY_SIG=y
+CONFIG_CRASH_DUMP=y
+CONFIG_HIBERNATION=y
+CONFIG_PM_DEBUG=y
+CONFIG_CMM=m
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_JUMP_LABEL=y
+CONFIG_STATIC_KEYS_SELFTEST=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_IBM_PARTITION=y
+CONFIG_DEFAULT_DEADLINE=y
+CONFIG_BINFMT_MISC=m
+CONFIG_MEMORY_HOTPLUG=y
+CONFIG_MEMORY_HOTREMOVE=y
+CONFIG_KSM=y
+CONFIG_TRANSPARENT_HUGEPAGE=y
+CONFIG_CLEANCACHE=y
+CONFIG_FRONTSWAP=y
+CONFIG_ZSWAP=y
+CONFIG_ZBUD=m
+CONFIG_ZSMALLOC=m
+CONFIG_ZSMALLOC_STAT=y
+CONFIG_IDLE_PAGE_TRACKING=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_L2TP=m
+CONFIG_L2TP_DEBUGFS=m
+CONFIG_VLAN_8021Q=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_BPF_JIT=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_SCSI=y
+# CONFIG_SCSI_MQ_DEFAULT is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_FC_ATTRS=y
+CONFIG_ZFCP=y
+CONFIG_SCSI_VIRTIO=y
+CONFIG_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_QL=m
+CONFIG_DM_MULTIPATH_ST=m
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=m
+CONFIG_DM_SWITCH=m
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+CONFIG_VIRTIO_NET=y
+# CONFIG_NET_VENDOR_ALACRITECH is not set
+# CONFIG_NET_VENDOR_AURORA is not set
+# CONFIG_NET_VENDOR_CORTINA is not set
+# CONFIG_NET_VENDOR_SOLARFLARE is not set
+# CONFIG_NET_VENDOR_SOCIONEXT is not set
+# CONFIG_NET_VENDOR_SYNOPSYS is not set
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+CONFIG_RAW_DRIVER=m
+CONFIG_VIRTIO_BALLOON=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_XFS_FS=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_BTRFS_FS=y
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_FANOTIFY=y
+CONFIG_FUSE_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_HUGETLBFS=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_CMAC=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_CRC32=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SALSA20=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_LZ4=m
+CONFIG_CRYPTO_LZ4HC=m
+CONFIG_CRYPTO_ANSI_CPRNG=m
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_ZCRYPT=m
+CONFIG_PKEY=m
+CONFIG_CRYPTO_PAES_S390=m
+CONFIG_CRYPTO_SHA1_S390=m
+CONFIG_CRYPTO_SHA256_S390=m
+CONFIG_CRYPTO_SHA512_S390=m
+CONFIG_CRYPTO_DES_S390=m
+CONFIG_CRYPTO_AES_S390=m
+CONFIG_CRYPTO_CRC32_S390=y
+CONFIG_CRC7=m
+# CONFIG_XZ_DEC_X86 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_SPARC is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF4=y
+CONFIG_GDB_SCRIPTS=y
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_PANIC_ON_OOPS=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_LOCK_STAT=y
+CONFIG_DEBUG_LOCKDEP=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_LIST=y
+CONFIG_DEBUG_SG=y
+CONFIG_DEBUG_NOTIFIERS=y
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+CONFIG_LATENCYTOP=y
+CONFIG_SCHED_TRACER=y
+CONFIG_FTRACE_SYSCALLS=y
+CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y
+CONFIG_STACK_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_FUNCTION_PROFILER=y
+# CONFIG_RUNTIME_TESTING_MENU is not set
+CONFIG_S390_PTDUMP=y
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
deleted file mode 100644 (file)
index c59b922..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_USELIB=y
-CONFIG_AUDIT=y
-CONFIG_NO_HZ_IDLE=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_TASKSTATS=y
-CONFIG_TASK_DELAY_ACCT=y
-CONFIG_TASK_XACCT=y
-CONFIG_TASK_IO_ACCOUNTING=y
-# CONFIG_CPU_ISOLATION is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_CGROUPS=y
-CONFIG_MEMCG=y
-CONFIG_MEMCG_SWAP=y
-CONFIG_BLK_CGROUP=y
-CONFIG_CGROUP_SCHED=y
-CONFIG_RT_GROUP_SCHED=y
-CONFIG_CGROUP_PIDS=y
-CONFIG_CGROUP_FREEZER=y
-CONFIG_CGROUP_HUGETLB=y
-CONFIG_CPUSETS=y
-CONFIG_CGROUP_DEVICE=y
-CONFIG_CGROUP_CPUACCT=y
-CONFIG_CGROUP_PERF=y
-CONFIG_NAMESPACES=y
-CONFIG_USER_NS=y
-CONFIG_CHECKPOINT_RESTORE=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EXPERT=y
-# CONFIG_SYSFS_SYSCALL is not set
-CONFIG_BPF_SYSCALL=y
-CONFIG_USERFAULTFD=y
-# CONFIG_COMPAT_BRK is not set
-CONFIG_PROFILING=y
-CONFIG_LIVEPATCH=y
-CONFIG_NR_CPUS=256
-CONFIG_NUMA=y
-CONFIG_HZ_100=y
-CONFIG_KEXEC_FILE=y
-CONFIG_KEXEC_VERIFY_SIG=y
-CONFIG_CRASH_DUMP=y
-CONFIG_HIBERNATION=y
-CONFIG_PM_DEBUG=y
-CONFIG_CMM=m
-CONFIG_OPROFILE=y
-CONFIG_KPROBES=y
-CONFIG_JUMP_LABEL=y
-CONFIG_STATIC_KEYS_SELFTEST=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_BLK_DEV_INTEGRITY=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_IBM_PARTITION=y
-CONFIG_DEFAULT_DEADLINE=y
-CONFIG_BINFMT_MISC=m
-CONFIG_MEMORY_HOTPLUG=y
-CONFIG_MEMORY_HOTREMOVE=y
-CONFIG_KSM=y
-CONFIG_TRANSPARENT_HUGEPAGE=y
-CONFIG_CLEANCACHE=y
-CONFIG_FRONTSWAP=y
-CONFIG_ZSWAP=y
-CONFIG_ZBUD=m
-CONFIG_ZSMALLOC=m
-CONFIG_ZSMALLOC_STAT=y
-CONFIG_IDLE_PAGE_TRACKING=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_L2TP=m
-CONFIG_L2TP_DEBUGFS=m
-CONFIG_VLAN_8021Q=y
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_CBQ=m
-CONFIG_NET_SCH_PRIO=m
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-CONFIG_NET_SCH_TEQL=m
-CONFIG_NET_SCH_TBF=m
-CONFIG_NET_SCH_GRED=m
-CONFIG_NET_SCH_DSMARK=m
-CONFIG_NET_CLS_TCINDEX=m
-CONFIG_NET_CLS_ROUTE4=m
-CONFIG_NET_CLS_FW=m
-CONFIG_NET_CLS_U32=m
-CONFIG_CLS_U32_MARK=y
-CONFIG_NET_CLS_RSVP=m
-CONFIG_NET_CLS_RSVP6=m
-CONFIG_NET_CLS_ACT=y
-CONFIG_NET_ACT_POLICE=y
-CONFIG_BPF_JIT=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_DEVTMPFS=y
-CONFIG_BLK_DEV_LOOP=m
-CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_RAM=y
-CONFIG_VIRTIO_BLK=y
-CONFIG_SCSI=y
-# CONFIG_SCSI_MQ_DEFAULT is not set
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_FC_ATTRS=y
-CONFIG_ZFCP=y
-CONFIG_SCSI_VIRTIO=y
-CONFIG_MD=y
-CONFIG_MD_LINEAR=m
-CONFIG_MD_MULTIPATH=m
-CONFIG_BLK_DEV_DM=y
-CONFIG_DM_CRYPT=m
-CONFIG_DM_SNAPSHOT=m
-CONFIG_DM_MIRROR=m
-CONFIG_DM_LOG_USERSPACE=m
-CONFIG_DM_RAID=m
-CONFIG_DM_ZERO=m
-CONFIG_DM_MULTIPATH=m
-CONFIG_DM_MULTIPATH_QL=m
-CONFIG_DM_MULTIPATH_ST=m
-CONFIG_DM_UEVENT=y
-CONFIG_DM_VERITY=m
-CONFIG_DM_SWITCH=m
-CONFIG_NETDEVICES=y
-CONFIG_BONDING=m
-CONFIG_DUMMY=m
-CONFIG_EQUALIZER=m
-CONFIG_TUN=m
-CONFIG_VIRTIO_NET=y
-# CONFIG_NET_VENDOR_ALACRITECH is not set
-# CONFIG_NET_VENDOR_AURORA is not set
-# CONFIG_NET_VENDOR_CORTINA is not set
-# CONFIG_NET_VENDOR_SOLARFLARE is not set
-# CONFIG_NET_VENDOR_SOCIONEXT is not set
-# CONFIG_NET_VENDOR_SYNOPSYS is not set
-# CONFIG_INPUT is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_DEVKMEM=y
-CONFIG_RAW_DRIVER=m
-CONFIG_VIRTIO_BALLOON=y
-CONFIG_EXT4_FS=y
-CONFIG_EXT4_FS_POSIX_ACL=y
-CONFIG_EXT4_FS_SECURITY=y
-CONFIG_XFS_FS=y
-CONFIG_XFS_QUOTA=y
-CONFIG_XFS_POSIX_ACL=y
-CONFIG_XFS_RT=y
-CONFIG_BTRFS_FS=y
-CONFIG_BTRFS_FS_POSIX_ACL=y
-CONFIG_FANOTIFY=y
-CONFIG_FUSE_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_HUGETLBFS=y
-# CONFIG_NETWORK_FILESYSTEMS is not set
-CONFIG_CRYPTO_CRYPTD=m
-CONFIG_CRYPTO_AUTHENC=m
-CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
-CONFIG_CRYPTO_GCM=m
-CONFIG_CRYPTO_CBC=y
-CONFIG_CRYPTO_CFB=m
-CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_CMAC=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_VMAC=m
-CONFIG_CRYPTO_CRC32=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD128=m
-CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_RMD256=m
-CONFIG_CRYPTO_RMD320=m
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_TGR192=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_CAMELLIA=m
-CONFIG_CRYPTO_CAST5=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_FCRYPT=m
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_SALSA20=m
-CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_DEFLATE=m
-CONFIG_CRYPTO_LZ4=m
-CONFIG_CRYPTO_LZ4HC=m
-CONFIG_CRYPTO_ANSI_CPRNG=m
-CONFIG_CRYPTO_USER_API_HASH=m
-CONFIG_CRYPTO_USER_API_SKCIPHER=m
-CONFIG_CRYPTO_USER_API_RNG=m
-CONFIG_ZCRYPT=m
-CONFIG_PKEY=m
-CONFIG_CRYPTO_PAES_S390=m
-CONFIG_CRYPTO_SHA1_S390=m
-CONFIG_CRYPTO_SHA256_S390=m
-CONFIG_CRYPTO_SHA512_S390=m
-CONFIG_CRYPTO_DES_S390=m
-CONFIG_CRYPTO_AES_S390=m
-CONFIG_CRYPTO_CRC32_S390=y
-CONFIG_CRC7=m
-# CONFIG_XZ_DEC_X86 is not set
-# CONFIG_XZ_DEC_POWERPC is not set
-# CONFIG_XZ_DEC_IA64 is not set
-# CONFIG_XZ_DEC_ARM is not set
-# CONFIG_XZ_DEC_ARMTHUMB is not set
-# CONFIG_XZ_DEC_SPARC is not set
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_INFO_DWARF4=y
-CONFIG_GDB_SCRIPTS=y
-CONFIG_UNUSED_SYMBOLS=y
-CONFIG_DEBUG_SECTION_MISMATCH=y
-CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_PAGEALLOC=y
-CONFIG_DETECT_HUNG_TASK=y
-CONFIG_PANIC_ON_OOPS=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_LOCK_STAT=y
-CONFIG_DEBUG_LOCKDEP=y
-CONFIG_DEBUG_ATOMIC_SLEEP=y
-CONFIG_DEBUG_LIST=y
-CONFIG_DEBUG_SG=y
-CONFIG_DEBUG_NOTIFIERS=y
-CONFIG_RCU_CPU_STALL_TIMEOUT=60
-CONFIG_LATENCYTOP=y
-CONFIG_SCHED_TRACER=y
-CONFIG_FTRACE_SYSCALLS=y
-CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y
-CONFIG_STACK_TRACER=y
-CONFIG_BLK_DEV_IO_TRACE=y
-CONFIG_FUNCTION_PROFILER=y
-# CONFIG_RUNTIME_TESTING_MENU is not set
-CONFIG_S390_PTDUMP=y
index 3cc52e37b4b2a6c4f209b4df3e153d05729d3d59..27696755daa9096d429d36a4c7f90967e16371a0 100644 (file)
@@ -28,6 +28,7 @@
 #define CPACF_KMCTR            0xb92d          /* MSA4 */
 #define CPACF_PRNO             0xb93c          /* MSA5 */
 #define CPACF_KMA              0xb929          /* MSA8 */
+#define CPACF_KDSA             0xb93a          /* MSA9 */
 
 /*
  * En/decryption modifier bits
@@ -202,7 +203,7 @@ static inline int __cpacf_check_opcode(unsigned int opcode)
        }
 }
 
-static inline int cpacf_query(unsigned int opcode, cpacf_mask_t *mask)
+static __always_inline int cpacf_query(unsigned int opcode, cpacf_mask_t *mask)
 {
        if (__cpacf_check_opcode(opcode)) {
                __cpacf_query(opcode, mask);
index 2d1afa58a4b6bf92c9fab01c021f7923dc199bc3..bb59dd9645909207351edc8d3577985f1aead9fb 100644 (file)
@@ -116,7 +116,9 @@ static inline pte_t huge_pte_modify(pte_t pte, pgprot_t newprot)
        return pte_modify(pte, newprot);
 }
 
-#ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE
-static inline bool gigantic_page_supported(void) { return true; }
-#endif
+static inline bool gigantic_page_runtime_supported(void)
+{
+       return true;
+}
+
 #endif /* _ASM_S390_HUGETLB_H */
index c47e22bba87fac58b08ecf28c498fe54074ede5d..bdbc81b5bc914bea9526a530625a360fb7a1cf26 100644 (file)
@@ -278,6 +278,7 @@ struct kvm_s390_sie_block {
 #define ECD_HOSTREGMGMT        0x20000000
 #define ECD_MEF                0x08000000
 #define ECD_ETOKENF    0x02000000
+#define ECD_ECC                0x00200000
        __u32   ecd;                    /* 0x01c8 */
        __u8    reserved1cc[18];        /* 0x01cc */
        __u64   pp;                     /* 0x01de */
@@ -312,6 +313,7 @@ struct kvm_vcpu_stat {
        u64 halt_successful_poll;
        u64 halt_attempted_poll;
        u64 halt_poll_invalid;
+       u64 halt_no_poll_steal;
        u64 halt_wakeup;
        u64 instruction_lctl;
        u64 instruction_lctlg;
index 672f95b12d4065b4fa023444dbd5575ca71d767e..818612b784cda2a77960461d1eb0c720c29f925d 100644 (file)
 
 #include <asm/ptrace.h>
 
-static inline int klp_check_compiler_support(void)
-{
-       return 0;
-}
-
 static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
 {
        regs->psw.addr = ip;
diff --git a/arch/s390/include/asm/segment.h b/arch/s390/include/asm/segment.h
deleted file mode 100644 (file)
index 97a0582..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_SEGMENT_H
-#define _ASM_SEGMENT_H
-
-#endif
index 16511d97e8dc037c8c0b9a60b09a0adf409e6d20..47104e5b47fd47b7941e3631e8e8eea4798e3d21 100644 (file)
@@ -152,7 +152,10 @@ struct kvm_s390_vm_cpu_subfunc {
        __u8 pcc[16];           /* with MSA4 */
        __u8 ppno[16];          /* with MSA5 */
        __u8 kma[16];           /* with MSA8 */
-       __u8 reserved[1808];
+       __u8 kdsa[16];          /* with MSA9 */
+       __u8 sortl[32];         /* with STFLE.150 */
+       __u8 dfltcc[32];        /* with STFLE.151 */
+       __u8 reserved[1728];
 };
 
 /* kvm attributes for crypto */
index cd3df5514552cc262dee1d1b99260d0ee089668b..ad71132374f0c7eecb9efe9c923e82d2e67b9872 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/seccomp.h>
 #include <linux/compat.h>
 #include <trace/syscall.h>
-#include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
index 061418f787c3712f4091cfeb94b8dfb5d2b1eb03..e822b2964a833b07e89fafe241920a53674bf948 100644 (file)
 425  common    io_uring_setup          sys_io_uring_setup              sys_io_uring_setup
 426  common    io_uring_enter          sys_io_uring_enter              sys_io_uring_enter
 427  common    io_uring_register       sys_io_uring_register           sys_io_uring_register
+428  common    open_tree               sys_open_tree                   sys_open_tree
+429  common    move_mount              sys_move_mount                  sys_move_mount
+430  common    fsopen                  sys_fsopen                      sys_fsopen
+431  common    fsconfig                sys_fsconfig                    sys_fsconfig
+432  common    fsmount                 sys_fsmount                     sys_fsmount
+433  common    fspick                  sys_fspick                      sys_fspick
index 1816ee48eadd6e80baf170a1985d9c7e545e3916..d3db3d7ed077207fc39aac003c33ea117254b20f 100644 (file)
@@ -30,6 +30,7 @@ config KVM
        select HAVE_KVM_IRQFD
        select HAVE_KVM_IRQ_ROUTING
        select HAVE_KVM_INVALID_WAKEUPS
+       select HAVE_KVM_NO_POLL
        select SRCU
        select KVM_VFIO
        ---help---
index 37503ae62486cab04b418afeb488a93919313d9b..9dde4d7d870455d5fc36bdb07257b05af1dd75dc 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/kvm_host.h>
 #include <linux/hrtimer.h>
 #include <linux/mmu_context.h>
+#include <linux/nospec.h>
 #include <linux/signal.h>
 #include <linux/slab.h>
 #include <linux/bitmap.h>
@@ -2307,6 +2308,7 @@ static struct s390_io_adapter *get_io_adapter(struct kvm *kvm, unsigned int id)
 {
        if (id >= MAX_S390_IO_ADAPTERS)
                return NULL;
+       id = array_index_nospec(id, MAX_S390_IO_ADAPTERS);
        return kvm->arch.adapters[id];
 }
 
@@ -2320,8 +2322,13 @@ static int register_io_adapter(struct kvm_device *dev,
                           (void __user *)attr->addr, sizeof(adapter_info)))
                return -EFAULT;
 
-       if ((adapter_info.id >= MAX_S390_IO_ADAPTERS) ||
-           (dev->kvm->arch.adapters[adapter_info.id] != NULL))
+       if (adapter_info.id >= MAX_S390_IO_ADAPTERS)
+               return -EINVAL;
+
+       adapter_info.id = array_index_nospec(adapter_info.id,
+                                            MAX_S390_IO_ADAPTERS);
+
+       if (dev->kvm->arch.adapters[adapter_info.id] != NULL)
                return -EINVAL;
 
        adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
@@ -2376,7 +2383,7 @@ static int kvm_s390_adapter_map(struct kvm *kvm, unsigned int id, __u64 addr)
                ret = -EFAULT;
                goto out;
        }
-       ret = get_user_pages_fast(map->addr, 1, 1, &map->page);
+       ret = get_user_pages_fast(map->addr, 1, FOLL_WRITE, &map->page);
        if (ret < 0)
                goto out;
        BUG_ON(ret != 1);
index 4638303ba6a858793eded0e331b67aeea67db5d0..8d6d75db8de65bbd044eb17df59379136e5f956c 100644 (file)
@@ -75,6 +75,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "halt_successful_poll", VCPU_STAT(halt_successful_poll) },
        { "halt_attempted_poll", VCPU_STAT(halt_attempted_poll) },
        { "halt_poll_invalid", VCPU_STAT(halt_poll_invalid) },
+       { "halt_no_poll_steal", VCPU_STAT(halt_no_poll_steal) },
        { "halt_wakeup", VCPU_STAT(halt_wakeup) },
        { "instruction_lctlg", VCPU_STAT(instruction_lctlg) },
        { "instruction_lctl", VCPU_STAT(instruction_lctl) },
@@ -177,6 +178,11 @@ static int hpage;
 module_param(hpage, int, 0444);
 MODULE_PARM_DESC(hpage, "1m huge page backing support");
 
+/* maximum percentage of steal time for polling.  >100 is treated like 100 */
+static u8 halt_poll_max_steal = 10;
+module_param(halt_poll_max_steal, byte, 0644);
+MODULE_PARM_DESC(hpage, "Maximum percentage of steal time to allow polling");
+
 /*
  * For now we handle at most 16 double words as this is what the s390 base
  * kernel handles and stores in the prefix page. If we ever need to go beyond
@@ -321,6 +327,22 @@ static inline int plo_test_bit(unsigned char nr)
        return cc == 0;
 }
 
+static inline void __insn32_query(unsigned int opcode, u8 query[32])
+{
+       register unsigned long r0 asm("0") = 0; /* query function */
+       register unsigned long r1 asm("1") = (unsigned long) query;
+
+       asm volatile(
+               /* Parameter regs are ignored */
+               "       .insn   rrf,%[opc] << 16,2,4,6,0\n"
+               : "=m" (*query)
+               : "d" (r0), "a" (r1), [opc] "i" (opcode)
+               : "cc");
+}
+
+#define INSN_SORTL 0xb938
+#define INSN_DFLTCC 0xb939
+
 static void kvm_s390_cpu_feat_init(void)
 {
        int i;
@@ -368,6 +390,16 @@ static void kvm_s390_cpu_feat_init(void)
                __cpacf_query(CPACF_KMA, (cpacf_mask_t *)
                              kvm_s390_available_subfunc.kma);
 
+       if (test_facility(155)) /* MSA9 */
+               __cpacf_query(CPACF_KDSA, (cpacf_mask_t *)
+                             kvm_s390_available_subfunc.kdsa);
+
+       if (test_facility(150)) /* SORTL */
+               __insn32_query(INSN_SORTL, kvm_s390_available_subfunc.sortl);
+
+       if (test_facility(151)) /* DFLTCC */
+               __insn32_query(INSN_DFLTCC, kvm_s390_available_subfunc.dfltcc);
+
        if (MACHINE_HAS_ESOP)
                allow_cpu_feat(KVM_S390_VM_CPU_FEAT_ESOP);
        /*
@@ -513,9 +545,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                else if (sclp.has_esca && sclp.has_64bscao)
                        r = KVM_S390_ESCA_CPU_SLOTS;
                break;
-       case KVM_CAP_NR_MEMSLOTS:
-               r = KVM_USER_MEM_SLOTS;
-               break;
        case KVM_CAP_S390_COW:
                r = MACHINE_HAS_ESOP;
                break;
@@ -657,6 +686,14 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
                                set_kvm_facility(kvm->arch.model.fac_mask, 135);
                                set_kvm_facility(kvm->arch.model.fac_list, 135);
                        }
+                       if (test_facility(148)) {
+                               set_kvm_facility(kvm->arch.model.fac_mask, 148);
+                               set_kvm_facility(kvm->arch.model.fac_list, 148);
+                       }
+                       if (test_facility(152)) {
+                               set_kvm_facility(kvm->arch.model.fac_mask, 152);
+                               set_kvm_facility(kvm->arch.model.fac_list, 152);
+                       }
                        r = 0;
                } else
                        r = -EINVAL;
@@ -1323,6 +1360,19 @@ static int kvm_s390_set_processor_subfunc(struct kvm *kvm,
        VM_EVENT(kvm, 3, "SET: guest KMA    subfunc 0x%16.16lx.%16.16lx",
                 ((unsigned long *) &kvm->arch.model.subfuncs.kma)[0],
                 ((unsigned long *) &kvm->arch.model.subfuncs.kma)[1]);
+       VM_EVENT(kvm, 3, "SET: guest KDSA   subfunc 0x%16.16lx.%16.16lx",
+                ((unsigned long *) &kvm->arch.model.subfuncs.kdsa)[0],
+                ((unsigned long *) &kvm->arch.model.subfuncs.kdsa)[1]);
+       VM_EVENT(kvm, 3, "SET: guest SORTL  subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
+                ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[0],
+                ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[1],
+                ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[2],
+                ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[3]);
+       VM_EVENT(kvm, 3, "SET: guest DFLTCC subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
+                ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[0],
+                ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[1],
+                ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[2],
+                ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[3]);
 
        return 0;
 }
@@ -1491,6 +1541,19 @@ static int kvm_s390_get_processor_subfunc(struct kvm *kvm,
        VM_EVENT(kvm, 3, "GET: guest KMA    subfunc 0x%16.16lx.%16.16lx",
                 ((unsigned long *) &kvm->arch.model.subfuncs.kma)[0],
                 ((unsigned long *) &kvm->arch.model.subfuncs.kma)[1]);
+       VM_EVENT(kvm, 3, "GET: guest KDSA   subfunc 0x%16.16lx.%16.16lx",
+                ((unsigned long *) &kvm->arch.model.subfuncs.kdsa)[0],
+                ((unsigned long *) &kvm->arch.model.subfuncs.kdsa)[1]);
+       VM_EVENT(kvm, 3, "GET: guest SORTL  subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
+                ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[0],
+                ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[1],
+                ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[2],
+                ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[3]);
+       VM_EVENT(kvm, 3, "GET: guest DFLTCC subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
+                ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[0],
+                ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[1],
+                ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[2],
+                ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[3]);
 
        return 0;
 }
@@ -1546,6 +1609,19 @@ static int kvm_s390_get_machine_subfunc(struct kvm *kvm,
        VM_EVENT(kvm, 3, "GET: host  KMA    subfunc 0x%16.16lx.%16.16lx",
                 ((unsigned long *) &kvm_s390_available_subfunc.kma)[0],
                 ((unsigned long *) &kvm_s390_available_subfunc.kma)[1]);
+       VM_EVENT(kvm, 3, "GET: host  KDSA   subfunc 0x%16.16lx.%16.16lx",
+                ((unsigned long *) &kvm_s390_available_subfunc.kdsa)[0],
+                ((unsigned long *) &kvm_s390_available_subfunc.kdsa)[1]);
+       VM_EVENT(kvm, 3, "GET: host  SORTL  subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
+                ((unsigned long *) &kvm_s390_available_subfunc.sortl)[0],
+                ((unsigned long *) &kvm_s390_available_subfunc.sortl)[1],
+                ((unsigned long *) &kvm_s390_available_subfunc.sortl)[2],
+                ((unsigned long *) &kvm_s390_available_subfunc.sortl)[3]);
+       VM_EVENT(kvm, 3, "GET: host  DFLTCC subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
+                ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[0],
+                ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[1],
+                ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[2],
+                ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[3]);
 
        return 0;
 }
@@ -2817,6 +2893,25 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
        vcpu->arch.enabled_gmap = vcpu->arch.gmap;
 }
 
+static bool kvm_has_pckmo_subfunc(struct kvm *kvm, unsigned long nr)
+{
+       if (test_bit_inv(nr, (unsigned long *)&kvm->arch.model.subfuncs.pckmo) &&
+           test_bit_inv(nr, (unsigned long *)&kvm_s390_available_subfunc.pckmo))
+               return true;
+       return false;
+}
+
+static bool kvm_has_pckmo_ecc(struct kvm *kvm)
+{
+       /* At least one ECC subfunction must be present */
+       return kvm_has_pckmo_subfunc(kvm, 32) ||
+              kvm_has_pckmo_subfunc(kvm, 33) ||
+              kvm_has_pckmo_subfunc(kvm, 34) ||
+              kvm_has_pckmo_subfunc(kvm, 40) ||
+              kvm_has_pckmo_subfunc(kvm, 41);
+
+}
+
 static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu)
 {
        /*
@@ -2829,13 +2924,19 @@ static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu)
        vcpu->arch.sie_block->crycbd = vcpu->kvm->arch.crypto.crycbd;
        vcpu->arch.sie_block->ecb3 &= ~(ECB3_AES | ECB3_DEA);
        vcpu->arch.sie_block->eca &= ~ECA_APIE;
+       vcpu->arch.sie_block->ecd &= ~ECD_ECC;
 
        if (vcpu->kvm->arch.crypto.apie)
                vcpu->arch.sie_block->eca |= ECA_APIE;
 
        /* Set up protected key support */
-       if (vcpu->kvm->arch.crypto.aes_kw)
+       if (vcpu->kvm->arch.crypto.aes_kw) {
                vcpu->arch.sie_block->ecb3 |= ECB3_AES;
+               /* ecc is also wrapped with AES key */
+               if (kvm_has_pckmo_ecc(vcpu->kvm))
+                       vcpu->arch.sie_block->ecd |= ECD_ECC;
+       }
+
        if (vcpu->kvm->arch.crypto.dea_kw)
                vcpu->arch.sie_block->ecb3 |= ECB3_DEA;
 }
@@ -3068,6 +3169,17 @@ static void kvm_gmap_notifier(struct gmap *gmap, unsigned long start,
        }
 }
 
+bool kvm_arch_no_poll(struct kvm_vcpu *vcpu)
+{
+       /* do not poll with more than halt_poll_max_steal percent of steal time */
+       if (S390_lowcore.avg_steal_timer * 100 / (TICK_USEC << 12) >=
+           halt_poll_max_steal) {
+               vcpu->stat.halt_no_poll_steal++;
+               return true;
+       }
+       return false;
+}
+
 int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
 {
        /* kvm common code refers to this, but never calls it */
index d62fa148558b99dccab51d3cdf8ea3cef06e31fa..076090f9e666c56139c70f02e59d41b598ef4773 100644 (file)
@@ -288,7 +288,9 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
        const u32 crycb_addr = crycbd_o & 0x7ffffff8U;
        unsigned long *b1, *b2;
        u8 ecb3_flags;
+       u32 ecd_flags;
        int apie_h;
+       int apie_s;
        int key_msk = test_kvm_facility(vcpu->kvm, 76);
        int fmt_o = crycbd_o & CRYCB_FORMAT_MASK;
        int fmt_h = vcpu->arch.sie_block->crycbd & CRYCB_FORMAT_MASK;
@@ -297,7 +299,8 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
        scb_s->crycbd = 0;
 
        apie_h = vcpu->arch.sie_block->eca & ECA_APIE;
-       if (!apie_h && (!key_msk || fmt_o == CRYCB_FORMAT0))
+       apie_s = apie_h & scb_o->eca;
+       if (!apie_s && (!key_msk || (fmt_o == CRYCB_FORMAT0)))
                return 0;
 
        if (!crycb_addr)
@@ -308,7 +311,7 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
                    ((crycb_addr + 128) & PAGE_MASK))
                        return set_validity_icpt(scb_s, 0x003CU);
 
-       if (apie_h && (scb_o->eca & ECA_APIE)) {
+       if (apie_s) {
                ret = setup_apcb(vcpu, &vsie_page->crycb, crycb_addr,
                                 vcpu->kvm->arch.crypto.crycb,
                                 fmt_o, fmt_h);
@@ -320,7 +323,8 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
        /* we may only allow it if enabled for guest 2 */
        ecb3_flags = scb_o->ecb3 & vcpu->arch.sie_block->ecb3 &
                     (ECB3_AES | ECB3_DEA);
-       if (!ecb3_flags)
+       ecd_flags = scb_o->ecd & vcpu->arch.sie_block->ecd & ECD_ECC;
+       if (!ecb3_flags && !ecd_flags)
                goto end;
 
        /* copy only the wrapping keys */
@@ -329,6 +333,7 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
                return set_validity_icpt(scb_s, 0x0035U);
 
        scb_s->ecb3 |= ecb3_flags;
+       scb_s->ecd |= ecd_flags;
 
        /* xor both blocks in one run */
        b1 = (unsigned long *) vsie_page->crycb.dea_wrapping_key_mask;
@@ -339,7 +344,7 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 end:
        switch (ret) {
        case -EINVAL:
-               return set_validity_icpt(scb_s, 0x0020U);
+               return set_validity_icpt(scb_s, 0x0022U);
        case -EFAULT:
                return set_validity_icpt(scb_s, 0x0035U);
        case -EACCES:
index 7cf48eefec8fc291ee3090c77107327547b85e95..14d1eae9fe43c9e553d8aa7fa656a92d312d0ea0 100644 (file)
@@ -157,14 +157,6 @@ void free_initmem(void)
        free_initmem_default(POISON_FREE_INITMEM);
 }
 
-#ifdef CONFIG_BLK_DEV_INITRD
-void __init free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
-                          "initrd");
-}
-#endif
-
 unsigned long memory_block_size_bytes(void)
 {
        /*
@@ -227,8 +219,8 @@ device_initcall(s390_cma_mem_init);
 
 #endif /* CONFIG_CMA */
 
-int arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap,
-               bool want_memblock)
+int arch_add_memory(int nid, u64 start, u64 size,
+               struct mhp_restrictions *restrictions)
 {
        unsigned long start_pfn = PFN_DOWN(start);
        unsigned long size_pages = PFN_DOWN(size);
@@ -238,21 +230,22 @@ int arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap,
        if (rc)
                return rc;
 
-       rc = __add_pages(nid, start_pfn, size_pages, altmap, want_memblock);
+       rc = __add_pages(nid, start_pfn, size_pages, restrictions);
        if (rc)
                vmem_remove_mapping(start, size);
        return rc;
 }
 
 #ifdef CONFIG_MEMORY_HOTREMOVE
-int arch_remove_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap)
+void arch_remove_memory(int nid, u64 start, u64 size,
+                       struct vmem_altmap *altmap)
 {
        /*
         * There is no hardware or firmware interface which could trigger a
         * hot memory remove on s390. So there is nothing that needs to be
         * implemented.
         */
-       return -EBUSY;
+       BUG();
 }
 #endif
 #endif /* CONFIG_MEMORY_HOTPLUG */
index 01892dcf4029258c25b7c8514413ae977d6e3220..0c1f257be422247b3e5835233582e07c80465e5c 100644 (file)
@@ -28,7 +28,7 @@ static void __init kasan_early_panic(const char *reason)
 {
        sclp_early_printk("The Linux kernel failed to boot with the KernelAddressSanitizer:\n");
        sclp_early_printk(reason);
-       disabled_wait(0);
+       disabled_wait();
 }
 
 static void * __init kasan_early_alloc_segment(void)
index fd788e0f2e5b8fc39dcfd970e2e54dbd3156fa8f..cead9e0dcffbf3df05c7f6673c61e8b367dc780d 100644 (file)
@@ -93,6 +93,9 @@ static struct facility_def facility_defs[] = {
                        131, /* enhanced-SOP 2 and side-effect */
                        139, /* multiple epoch facility */
                        146, /* msa extension 8 */
+                       150, /* enhanced sort */
+                       151, /* deflate conversion */
+                       155, /* msa extension 9 */
                        -1  /* END */
                }
        },
index 0be08d586d40c64ee7db194210048a7724480ba6..b77f512bb1766ebb22711a7e676063c7134d2f7e 100644 (file)
@@ -10,7 +10,6 @@ config SUPERH
        select DMA_DECLARE_COHERENT
        select HAVE_IDE if HAS_IOPORT_MAP
        select HAVE_MEMBLOCK_NODE_MAP
-       select ARCH_DISCARD_MEMBLOCK
        select HAVE_OPROFILE
        select HAVE_ARCH_TRACEHOOK
        select HAVE_PERF_EVENTS
@@ -53,6 +52,7 @@ config SUPERH
        select HAVE_FUTEX_CMPXCHG if FUTEX
        select HAVE_NMI
        select NEED_SG_DMA_LENGTH
+       select ARCH_HAS_GIGANTIC_PAGE
 
        help
          The SuperH is a RISC processor targeted for use in embedded systems
index 346eda7a2ef6af0563ffbbc9d8c7a16c3e62cce5..abf19a947df354a2886a385d326525294918af3f 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/irq.h>
 #include <linux/clk.h>
 #include <asm/machvec.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/clock.h>
 
 static struct mtd_partition nor_flash_partitions[] = {
index 4efa9c571f64fc7370e4bd51f3ab5b83aa50d57f..fa031a16c9b5c7ba773e5e7e4b281893ad4a26d2 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/irq.h>
 #include <linux/clk.h>
 #include <asm/machvec.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 /* Dummy supplies, where voltage doesn't matter */
 static struct regulator_consumer_supply dummy_supplies[] = {
index 67a8803eb3f9d73a0b34c0206344efd2d87d7c07..0de7d603da2d8c05f60e09272431f521d77ad9a1 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/smc91x.h>
 #include <linux/sh_intc.h>
 #include <asm/machvec.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #define SMC_IOBASE     0xA2000000
 #define SMC_IO_OFFSET  0x300
index 0fbe91cba67a2bb2583bff30ab1fb438aa2376b7..7569d85c5ff5a8227b469eada76b2331c59506c2 100644 (file)
@@ -18,7 +18,7 @@
 #include <asm/addrspace.h>
 #include <asm/delay.h>
 #include <asm/i2c-sh7760.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 /* Bus state controller registers for CS4 area */
 #define BSC_CS4BCR     0xA4FD0010
index f478fee3b48afcdcb5e782cc0c75584bc0be4a69..6e784b5cf5a0b2b7ea007e33dd4c1685e0f8960b 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/sh_eth.h>
 #include <linux/sh_intc.h>
 #include <asm/machvec.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 /* NOR Flash */
 static struct mtd_partition espt_nor_flash_partitions[] = {
index 799af57c0b81532a3cf4a8e9eb63ed2580ce9305..dad2b3b40735cbca1fb06e18a193a6fa4f0fa3ed 100644 (file)
@@ -21,7 +21,7 @@
 #include <mach/urquell.h>
 #include <cpu/sh7786.h>
 #include <asm/heartbeat.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/smp-ops.h>
 
 /*
index a929f764ae04030c2d2aa69ee2abadafe284f129..cc06e4cdb4cdf9b7cab0597183b06061a5901ec9 100644 (file)
@@ -10,7 +10,6 @@
  */
 #include <linux/irq.h>
 #include <linux/io.h>
-#include <linux/irq.h>
 #include <linux/export.h>
 #include <linux/err.h>
 #include <mach/sysasic.h>
index 706b48f797bed63b4ca30b1b362402186757ee29..f4a777fe2d01215b0a9b401d42c77f4f2c880d46 100644 (file)
@@ -15,7 +15,7 @@
 #include <mach/microdev.h>
 #include <asm/io.h>
 #include <asm/machvec.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 static struct resource smc91x_resources[] = {
        [0] = {
index 6d2a3d381c2a4f94d97d30b2496110afb25be1a6..895576ff837632fb642fcc8318fd8b2688e0fc56 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/io.h>
 #include <linux/bcd.h>
 #include <mach/fpga.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #define FPGA_REGS_OFFSET       0x03fff800
 #define FPGA_REGS_SIZE         0x490
index 65721c3a482c2f6bb66ebabeb36c28c2b3a26c40..d183026dbeb19a83b0de5347584d87fb15a6d850 100644 (file)
@@ -19,7 +19,7 @@
 #include <mach/irq.h>
 #include <asm/machvec.h>
 #include <asm/heartbeat.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/clock.h>
 #include <asm/reboot.h>
 #include <asm/smp-ops.h>
index d76cdb7ede39175624e8f3d7cad5c5aeeb5d7239..7c6ca976f332feaa7467417b560c7e0761f550d3 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/string.h>
 #include <mach/fpga.h>
 #include <asm/sram.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 static int __init fpga_sram_init(void)
 {
index 39a3175e72b268f0e6869e7bc3d60de6268494b5..1aedbfe326541f125797221fde621cf68a380f0d 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/irqdomain.h>
 #include <linux/io.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <mach-se/mach/se7343.h>
 
 #define PA_CPLD_BASE_ADDR      0x11400000
index f6e3009edd4e2370dcab708b30b9697e40ca794d..6d34592767f812c1bf50f4bd553f61c9396b337e 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/irqdomain.h>
 #include <linux/io.h>
 #include <linux/err.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <mach-se/mach/se7722.h>
 
 #define IRQ01_BASE_ADDR        0x11800000
index 72b72e50a92edf3feb2bb09c84d8b572a9344e00..0ef3f1f9de5cbe641995d8e8e2c3608e7f63402c 100644 (file)
@@ -35,7 +35,7 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_SH_FLCTL=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_RAM=y
index 3568310c2c2fc120434deca34a8dc9962e2b34f8..ba67e375293810b9a05f20a85c1ce8dd8c39e6bc 100644 (file)
@@ -38,7 +38,7 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=4
index e04f21be0756dc5ec3ea8c472489fa993fa01ebc..121a75d65fb40d34e5eccc5b862e4406a20d1cf3 100644 (file)
@@ -34,7 +34,7 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_PLATFORM=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_SCSI=y
index d16e9334cd98b2b91a767646029a2cd090360d7e..5209889765add4f4041b1775413542449f8310de 100644 (file)
@@ -108,7 +108,7 @@ CONFIG_MTD_ROM=m
 CONFIG_MTD_ABSENT=m
 CONFIG_MTD_PLATRAM=y
 CONFIG_MTD_PHRAM=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_PLATFORM=y
 CONFIG_MTD_NAND_SH_FLCTL=m
 CONFIG_MTD_UBI=y
index aedb3a2d9a10857377fe80c5e6a3a416f3bf8b96..9f6d46d585547c6dd303de5c0b379199c1587ed1 100644 (file)
@@ -37,7 +37,7 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_NAND=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=4
index ceb48e9b70f4fbc6d8b2af38dffe888b3b739e35..822fa9e96f743e5b7240410308c8289bf951f43b 100644 (file)
@@ -155,7 +155,7 @@ CONFIG_INFTL=m
 CONFIG_RFD_FTL=m
 CONFIG_MTD_CFI=m
 CONFIG_MTD_JEDECPROBE=m
-CONFIG_MTD_NAND=m
+CONFIG_MTD_RAW_NAND=m
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_RAM=y
index 1b9e5caac389838b995b1d17deb55b6314f3de13..11ed21c2e9bb10e9d80c888c18cf49171fd8728c 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/io.h>
 #include "pci-sh4.h"
 #include <asm/addrspace.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 static int __init __area_sdram_check(struct pci_channel *chan,
                                     unsigned int area)
index 3fd0f392a0ee05d5466c5dafc4a1f0d19a5fd012..287b3a68570cf0ffde9b2241b09163cb1d5cae14 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/log2.h>
 #include "pci-sh4.h"
 #include <asm/mmu.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #if defined(CONFIG_CPU_BIG_ENDIAN)
 # define PCICR_ENDIANNESS SH4_PCICR_BSWP
index a58b77cea2957f981214aa97f28f11c36d138b96..e0b568aaa7014c261e04b5280565dc5a65dde274 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/sh_intc.h>
 #include <cpu/sh7786.h>
 #include "pcie-sh7786.h"
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 struct sh7786_pcie_port {
        struct pci_channel      *hose;
index 73fff39a0122f0405f0940036a09cc4283946d44..51a54df22c110ee34ab055dd9288e3c9316ac423 100644 (file)
@@ -18,6 +18,5 @@ generic-y += parport.h
 generic-y += percpu.h
 generic-y += preempt.h
 generic-y += serial.h
-generic-y += sizes.h
 generic-y += trace_clock.h
 generic-y += xor.h
index 480b057556ee45a3871485ce7301d2436cca8255..016a727d435784d8386a9a8b0d007f17cafe4322 100644 (file)
 425    common  io_uring_setup                  sys_io_uring_setup
 426    common  io_uring_enter                  sys_io_uring_enter
 427    common  io_uring_register               sys_io_uring_register
+428    common  open_tree                       sys_open_tree
+429    common  move_mount                      sys_move_mount
+430    common  fsopen                          sys_fsopen
+431    common  fsconfig                        sys_fsconfig
+432    common  fsmount                         sys_fsmount
+433    common  fspick                          sys_fspick
index 3e27f6d1f1ec109e45d976eb3a38ef04d583bff7..277c882f7489e37eeb0f8de1d19840ff60983968 100644 (file)
@@ -204,7 +204,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
  * get_user_pages_fast() - pin user pages in memory
  * @start:     starting user address
  * @nr_pages:  number of pages from start to pin
- * @write:     whether pages will be written to
+ * @gup_flags: flags modifying pin behaviour
  * @pages:     array that receives pointers to the pages pinned.
  *             Should be at least nr_pages long.
  *
@@ -216,8 +216,8 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
  * requested. If nr_pages is 0 or negative, returns 0. If no pages
  * were pinned, returns -errno.
  */
-int get_user_pages_fast(unsigned long start, int nr_pages, int write,
-                       struct page **pages)
+int get_user_pages_fast(unsigned long start, int nr_pages,
+                       unsigned int gup_flags, struct page **pages)
 {
        struct mm_struct *mm = current->mm;
        unsigned long addr, len, end;
@@ -241,7 +241,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                next = pgd_addr_end(addr, end);
                if (pgd_none(pgd))
                        goto slow;
-               if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+               if (!gup_pud_range(pgd, addr, next, gup_flags & FOLL_WRITE,
+                                  pages, &nr))
                        goto slow;
        } while (pgdp++, addr = next, addr != end);
        local_irq_enable();
@@ -261,7 +262,7 @@ slow_irqon:
 
                ret = get_user_pages_unlocked(start,
                        (end - start) >> PAGE_SHIFT, pages,
-                       write ? FOLL_WRITE : 0);
+                       gup_flags);
 
                /* Have to be a bit careful with return values */
                if (nr > 0) {
index 70621324db4128f5f805f80a3b58f1360fe2d527..5aeb4d7099a16a21cb07609e3839856bd001a330 100644 (file)
@@ -26,7 +26,7 @@
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/cache.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
@@ -403,28 +403,16 @@ void __init mem_init(void)
        mem_init_done = 1;
 }
 
-void free_initmem(void)
-{
-       free_initmem_default(-1);
-}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-#endif
-
 #ifdef CONFIG_MEMORY_HOTPLUG
-int arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap,
-               bool want_memblock)
+int arch_add_memory(int nid, u64 start, u64 size,
+                       struct mhp_restrictions *restrictions)
 {
        unsigned long start_pfn = PFN_DOWN(start);
        unsigned long nr_pages = size >> PAGE_SHIFT;
        int ret;
 
        /* We only have ZONE_NORMAL, so this is easy.. */
-       ret = __add_pages(nid, start_pfn, nr_pages, altmap, want_memblock);
+       ret = __add_pages(nid, start_pfn, nr_pages, restrictions);
        if (unlikely(ret))
                printk("%s: Failed, __add_pages() == %d\n", __func__, ret);
 
@@ -441,20 +429,15 @@ EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
 #endif
 
 #ifdef CONFIG_MEMORY_HOTREMOVE
-int arch_remove_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap)
+void arch_remove_memory(int nid, u64 start, u64 size,
+                       struct vmem_altmap *altmap)
 {
        unsigned long start_pfn = PFN_DOWN(start);
        unsigned long nr_pages = size >> PAGE_SHIFT;
        struct zone *zone;
-       int ret;
 
        zone = page_zone(pfn_to_page(start_pfn));
-       ret = __remove_pages(zone, start_pfn, nr_pages, altmap);
-       if (unlikely(ret))
-               pr_warn("%s: Failed, __remove_pages() == %d\n", __func__,
-                       ret);
-
-       return ret;
+       __remove_pages(zone, start_pfn, nr_pages, altmap);
 }
 #endif
 #endif /* CONFIG_MEMORY_HOTPLUG */
index 7b2cc490ebb73c3e0afd6246c950f94572d76fcf..a53a040d00543ce3938b1e2dbb850fd629858aa6 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/spinlock.h>
 #include <linux/vmalloc.h>
 #include <asm/cacheflush.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <linux/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
index 010010bf205a77486573fd6d71ad553d6a4792c9..bd1585e8efed92ecbbc5f44a845371c7bd2c9508 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/init.h>
 #include <linux/module.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/page.h>
 #include <asm/addrspace.h>
 
index f6421c9ce5d3f0b7590f198c394ea8d761014e81..7c93f3121ee6bab8cbd1477420df9906a9c15b2f 100644 (file)
@@ -92,6 +92,7 @@ config SPARC64
        select ARCH_CLOCKSOURCE_DATA
        select ARCH_HAS_PTE_SPECIAL
        select PCI_DOMAINS if PCI
+       select ARCH_HAS_GIGANTIC_PAGE
 
 config ARCH_DEFCONFIG
        string
index 1393a8ac596b0a050433b1afcc7d8a97302f47f2..22500c3be7a94b460704b11f439314de7177dc12 100644 (file)
@@ -231,36 +231,6 @@ extern unsigned long _PAGE_ALL_SZ_BITS;
 extern struct page *mem_map_zero;
 #define ZERO_PAGE(vaddr)       (mem_map_zero)
 
-/* This macro must be updated when the size of struct page grows above 80
- * or reduces below 64.
- * The idea that compiler optimizes out switch() statement, and only
- * leaves clrx instructions
- */
-#define        mm_zero_struct_page(pp) do {                                    \
-       unsigned long *_pp = (void *)(pp);                              \
-                                                                       \
-        /* Check that struct page is either 64, 72, or 80 bytes */     \
-       BUILD_BUG_ON(sizeof(struct page) & 7);                          \
-       BUILD_BUG_ON(sizeof(struct page) < 64);                         \
-       BUILD_BUG_ON(sizeof(struct page) > 80);                         \
-                                                                       \
-       switch (sizeof(struct page)) {                                  \
-       case 80:                                                        \
-               _pp[9] = 0;     /* fallthrough */                       \
-       case 72:                                                        \
-               _pp[8] = 0;     /* fallthrough */                       \
-       default:                                                        \
-               _pp[7] = 0;                                             \
-               _pp[6] = 0;                                             \
-               _pp[5] = 0;                                             \
-               _pp[4] = 0;                                             \
-               _pp[3] = 0;                                             \
-               _pp[2] = 0;                                             \
-               _pp[1] = 0;                                             \
-               _pp[0] = 0;                                             \
-       }                                                               \
-} while (0)
-
 /* PFNs are real physical page numbers.  However, mem_map only begins to record
  * per-page information starting at pfn_base.  This is to handle systems where
  * the first physical page in the machine is at some huge physical address,
index a1dd24307b001aa95801d3e24003ffd719711728..e047480b160557c63ed976e63bb66152b9f50632 100644 (file)
 425    common  io_uring_setup                  sys_io_uring_setup
 426    common  io_uring_enter                  sys_io_uring_enter
 427    common  io_uring_register               sys_io_uring_register
+428    common  open_tree                       sys_open_tree
+429    common  move_mount                      sys_move_mount
+430    common  fsopen                          sys_fsopen
+431    common  fsconfig                        sys_fsconfig
+432    common  fsmount                         sys_fsmount
+433    common  fspick                          sys_fspick
index 3eb77943ce129829499c861ffa8ec6aba958bd6a..89fb05f9060959d49d79493dce5f231af2f741c8 100644 (file)
@@ -653,19 +653,23 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val
                                    void *data)
 {
        struct cpufreq_freqs *freq = data;
-       unsigned int cpu = freq->cpu;
-       struct freq_table *ft = &per_cpu(sparc64_freq_table, cpu);
+       unsigned int cpu;
+       struct freq_table *ft;
 
-       if (!ft->ref_freq) {
-               ft->ref_freq = freq->old;
-               ft->clock_tick_ref = cpu_data(cpu).clock_tick;
-       }
-       if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
-           (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
-               cpu_data(cpu).clock_tick =
-                       cpufreq_scale(ft->clock_tick_ref,
-                                     ft->ref_freq,
-                                     freq->new);
+       for_each_cpu(cpu, freq->policy->cpus) {
+               ft = &per_cpu(sparc64_freq_table, cpu);
+
+               if (!ft->ref_freq) {
+                       ft->ref_freq = freq->old;
+                       ft->clock_tick_ref = cpu_data(cpu).clock_tick;
+               }
+
+               if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
+                   (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
+                       cpu_data(cpu).clock_tick =
+                               cpufreq_scale(ft->clock_tick_ref, ft->ref_freq,
+                                             freq->new);
+               }
        }
 
        return 0;
index aee6dba83d0eceed0c3554bafdb5d053f12df64c..1e770a517d4ac7c75b9837479f23152fcc759980 100644 (file)
@@ -245,8 +245,8 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
        return nr;
 }
 
-int get_user_pages_fast(unsigned long start, int nr_pages, int write,
-                       struct page **pages)
+int get_user_pages_fast(unsigned long start, int nr_pages,
+                       unsigned int gup_flags, struct page **pages)
 {
        struct mm_struct *mm = current->mm;
        unsigned long addr, len, end;
@@ -303,7 +303,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                next = pgd_addr_end(addr, end);
                if (pgd_none(pgd))
                        goto slow;
-               if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+               if (!gup_pud_range(pgd, addr, next, gup_flags & FOLL_WRITE,
+                                  pages, &nr))
                        goto slow;
        } while (pgdp++, addr = next, addr != end);
 
@@ -324,7 +325,7 @@ slow:
 
                ret = get_user_pages_unlocked(start,
                        (end - start) >> PAGE_SHIFT, pages,
-                       write ? FOLL_WRITE : 0);
+                       gup_flags);
 
                /* Have to be a bit careful with return values */
                if (nr > 0) {
index a8ff29821bdbc44466481b310fdedf3729c50047..046ab116cc8c6ecc2deeff6d26c0cd9624b0d626 100644 (file)
@@ -294,19 +294,6 @@ void __init mem_init(void)
        mem_init_print_info(NULL);
 }
 
-void free_initmem (void)
-{
-       free_initmem_default(POISON_FREE_INITMEM);
-}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
-                          "initrd");
-}
-#endif
-
 void sparc_flush_page_to_ram(struct page *page)
 {
        unsigned long vaddr = (unsigned long)page_address(page);
index bc2aaa47bc8ac010b9e1d6518bb6c571707a9eb1..4b099dd7a7671566054c3d2c2c51a0ddc7da2b76 100644 (file)
@@ -2572,14 +2572,6 @@ void free_initmem(void)
        }
 }
 
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
-                          "initrd");
-}
-#endif
-
 pgprot_t PAGE_KERNEL __read_mostly;
 EXPORT_SYMBOL(PAGE_KERNEL);
 
index ec9711d068b7f9ab9a4f721d46a0db53b4c62414..6b6eb938fcc1675f0b16a4206ff26fc2aab24acd 100644 (file)
@@ -80,46 +80,46 @@ config LD_SCRIPT_DYN
        bool
        default y
        depends on !LD_SCRIPT_STATIC
-        select MODULE_REL_CRCS if MODVERSIONS
+       select MODULE_REL_CRCS if MODVERSIONS
 
 config HOSTFS
        tristate "Host filesystem"
        help
-          While the User-Mode Linux port uses its own root file system for
-          booting and normal file access, this module lets the UML user
-          access files stored on the host.  It does not require any
-          network connection between the Host and UML.  An example use of
-          this might be:
+         While the User-Mode Linux port uses its own root file system for
+         booting and normal file access, this module lets the UML user
+         access files stored on the host.  It does not require any
+         network connection between the Host and UML.  An example use of
+         this might be:
 
-          mount none /tmp/fromhost -t hostfs -o /tmp/umlshare
+         mount none /tmp/fromhost -t hostfs -o /tmp/umlshare
 
-          where /tmp/fromhost is an empty directory inside UML and
-          /tmp/umlshare is a directory on the host with files the UML user
-          wishes to access.
+         where /tmp/fromhost is an empty directory inside UML and
+         /tmp/umlshare is a directory on the host with files the UML user
+         wishes to access.
 
-          For more information, see
-          <http://user-mode-linux.sourceforge.net/hostfs.html>.
+         For more information, see
+         <http://user-mode-linux.sourceforge.net/hostfs.html>.
 
-          If you'd like to be able to work with files stored on the host,
-          say Y or M here; otherwise say N.
+         If you'd like to be able to work with files stored on the host,
+         say Y or M here; otherwise say N.
 
 config MCONSOLE
        bool "Management console"
        depends on PROC_FS
        default y
        help
-          The user mode linux management console is a low-level interface to
-          the kernel, somewhat like the i386 SysRq interface.  Since there is
-          a full-blown operating system running under every user mode linux
-          instance, there is much greater flexibility possible than with the
-          SysRq mechanism.
+         The user mode linux management console is a low-level interface to
+         the kernel, somewhat like the i386 SysRq interface.  Since there is
+         a full-blown operating system running under every user mode linux
+         instance, there is much greater flexibility possible than with the
+         SysRq mechanism.
 
-          If you answer 'Y' to this option, to use this feature, you need the
-          mconsole client (called uml_mconsole) which is present in CVS in
-          2.4.5-9um and later (path /tools/mconsole), and is also in the
-          distribution RPM package in 2.4.6 and later.
+         If you answer 'Y' to this option, to use this feature, you need the
+         mconsole client (called uml_mconsole) which is present in CVS in
+         2.4.5-9um and later (path /tools/mconsole), and is also in the
+         distribution RPM package in 2.4.6 and later.
 
-          It is safe to say 'Y' here.
+         It is safe to say 'Y' here.
 
 config MAGIC_SYSRQ
        bool "Magic SysRq key"
@@ -142,13 +142,17 @@ config MAGIC_SYSRQ
 
 config KERNEL_STACK_ORDER
        int "Kernel stack size order"
-       default 1 if 64BIT
-       range 1 10 if 64BIT
-       default 0 if !64BIT
+       default 2 if 64BIT
+       range 2 10 if 64BIT
+       default 1 if !64BIT
        help
          This option determines the size of UML kernel stacks.  They will
          be 1 << order pages.  The default is OK unless you're running Valgrind
          on UML, in which case, set this to 3.
+         It is possible to reduce the stack to 1 for 64BIT and 0 for 32BIT on
+         older (pre-2017) CPUs. It is not recommended on newer CPUs due to the
+         increase in the size of the state which needs to be saved when handling
+          signals.
 
 config MMAPPER
        tristate "iomem emulation driver"
index 2b1aaf7755aac11a27e68fc0d08b7eab62e80fef..2638e46f50ccdc26f6eb396363e8ff81209bf76c 100644 (file)
@@ -11,58 +11,58 @@ config STDERR_CONSOLE
 config SSL
        bool "Virtual serial line"
        help
-          The User-Mode Linux environment allows you to create virtual serial
-          lines on the UML that are usually made to show up on the host as
-          ttys or ptys.
+         The User-Mode Linux environment allows you to create virtual serial
+         lines on the UML that are usually made to show up on the host as
+         ttys or ptys.
 
-          See <http://user-mode-linux.sourceforge.net/old/input.html> for more
-          information and command line examples of how to use this facility.
+         See <http://user-mode-linux.sourceforge.net/old/input.html> for more
+         information and command line examples of how to use this facility.
 
-          Unless you have a specific reason for disabling this, say Y.
+         Unless you have a specific reason for disabling this, say Y.
 
 config NULL_CHAN
        bool "null channel support"
        help
-          This option enables support for attaching UML consoles and serial
-          lines to a device similar to /dev/null.  Data written to it disappears
-          and there is never any data to be read.
+         This option enables support for attaching UML consoles and serial
+         lines to a device similar to /dev/null.  Data written to it disappears
+         and there is never any data to be read.
 
 config PORT_CHAN
        bool "port channel support"
        help
-          This option enables support for attaching UML consoles and serial
-          lines to host portals.  They may be accessed with 'telnet <host>
-          <port number>'.  Any number of consoles and serial lines may be
-          attached to a single portal, although what UML device you get when
-          you telnet to that portal will be unpredictable.
-          It is safe to say 'Y' here.
+         This option enables support for attaching UML consoles and serial
+         lines to host portals.  They may be accessed with 'telnet <host>
+         <port number>'.  Any number of consoles and serial lines may be
+         attached to a single portal, although what UML device you get when
+         you telnet to that portal will be unpredictable.
+         It is safe to say 'Y' here.
 
 config PTY_CHAN
        bool "pty channel support"
        help
-          This option enables support for attaching UML consoles and serial
-          lines to host pseudo-terminals.  Access to both traditional
-          pseudo-terminals (/dev/pty*) and pts pseudo-terminals are controlled
-          with this option.  The assignment of UML devices to host devices
-          will be announced in the kernel message log.
-          It is safe to say 'Y' here.
+         This option enables support for attaching UML consoles and serial
+         lines to host pseudo-terminals.  Access to both traditional
+         pseudo-terminals (/dev/pty*) and pts pseudo-terminals are controlled
+         with this option.  The assignment of UML devices to host devices
+         will be announced in the kernel message log.
+         It is safe to say 'Y' here.
 
 config TTY_CHAN
        bool "tty channel support"
        help
-          This option enables support for attaching UML consoles and serial
-          lines to host terminals.  Access to both virtual consoles
-          (/dev/tty*) and the slave side of pseudo-terminals (/dev/ttyp* and
-          /dev/pts/*) are controlled by this option.
-          It is safe to say 'Y' here.
+         This option enables support for attaching UML consoles and serial
+         lines to host terminals.  Access to both virtual consoles
+         (/dev/tty*) and the slave side of pseudo-terminals (/dev/ttyp* and
+         /dev/pts/*) are controlled by this option.
+         It is safe to say 'Y' here.
 
 config XTERM_CHAN
        bool "xterm channel support"
        help
-          This option enables support for attaching UML consoles and serial
-          lines to xterms.  Each UML device so assigned will be brought up in
-          its own xterm.
-          It is safe to say 'Y' here.
+         This option enables support for attaching UML consoles and serial
+         lines to xterms.  Each UML device so assigned will be brought up in
+         its own xterm.
+         It is safe to say 'Y' here.
 
 config NOCONFIG_CHAN
        bool
@@ -72,43 +72,43 @@ config CON_ZERO_CHAN
        string "Default main console channel initialization"
        default "fd:0,fd:1"
        help
-          This is the string describing the channel to which the main console
-          will be attached by default.  This value can be overridden from the
-          command line.  The default value is "fd:0,fd:1", which attaches the
-          main console to stdin and stdout.
-          It is safe to leave this unchanged.
+         This is the string describing the channel to which the main console
+         will be attached by default.  This value can be overridden from the
+         command line.  The default value is "fd:0,fd:1", which attaches the
+         main console to stdin and stdout.
+         It is safe to leave this unchanged.
 
 config CON_CHAN
        string "Default console channel initialization"
        default "xterm"
        help
-          This is the string describing the channel to which all consoles
-          except the main console will be attached by default.  This value can
-          be overridden from the command line.  The default value is "xterm",
-          which brings them up in xterms.
-          It is safe to leave this unchanged, although you may wish to change
-          this if you expect the UML that you build to be run in environments
-          which don't have X or xterm available.
+         This is the string describing the channel to which all consoles
+         except the main console will be attached by default.  This value can
+         be overridden from the command line.  The default value is "xterm",
+         which brings them up in xterms.
+         It is safe to leave this unchanged, although you may wish to change
+         this if you expect the UML that you build to be run in environments
+         which don't have X or xterm available.
 
 config SSL_CHAN
        string "Default serial line channel initialization"
        default "pty"
        help
-          This is the string describing the channel to which the serial lines
-          will be attached by default.  This value can be overridden from the
-          command line.  The default value is "pty", which attaches them to
-          traditional pseudo-terminals.
-          It is safe to leave this unchanged, although you may wish to change
-          this if you expect the UML that you build to be run in environments
-          which don't have a set of /dev/pty* devices.
+         This is the string describing the channel to which the serial lines
+         will be attached by default.  This value can be overridden from the
+         command line.  The default value is "pty", which attaches them to
+         traditional pseudo-terminals.
+         It is safe to leave this unchanged, although you may wish to change
+         this if you expect the UML that you build to be run in environments
+         which don't have a set of /dev/pty* devices.
 
 config UML_SOUND
        tristate "Sound support"
        help
-          This option enables UML sound support.  If enabled, it will pull in
-          soundcore and the UML hostaudio relay, which acts as a intermediary
-          between the host's dsp and mixer devices and the UML sound system.
-          It is safe to say 'Y' here.
+         This option enables UML sound support.  If enabled, it will pull in
+         soundcore and the UML hostaudio relay, which acts as a intermediary
+         between the host's dsp and mixer devices and the UML sound system.
+         It is safe to say 'Y' here.
 
 config SOUND
        tristate
@@ -131,107 +131,107 @@ menu "UML Network Devices"
 config UML_NET
        bool "Virtual network device"
        help
-        While the User-Mode port cannot directly talk to any physical
-        hardware devices, this choice and the following transport options
-        provide one or more virtual network devices through which the UML
-        kernels can talk to each other, the host, and with the host's help,
-        machines on the outside world.
+         While the User-Mode port cannot directly talk to any physical
+         hardware devices, this choice and the following transport options
+         provide one or more virtual network devices through which the UML
+         kernels can talk to each other, the host, and with the host's help,
+         machines on the outside world.
 
-        For more information, including explanations of the networking and
-        sample configurations, see
-        <http://user-mode-linux.sourceforge.net/old/networking.html>.
+         For more information, including explanations of the networking and
+         sample configurations, see
+         <http://user-mode-linux.sourceforge.net/old/networking.html>.
 
-        If you'd like to be able to enable networking in the User-Mode
-        linux environment, say Y; otherwise say N.  Note that you must
-        enable at least one of the following transport options to actually
-        make use of UML networking.
+         If you'd like to be able to enable networking in the User-Mode
+         linux environment, say Y; otherwise say N.  Note that you must
+         enable at least one of the following transport options to actually
+         make use of UML networking.
 
 config UML_NET_ETHERTAP
        bool "Ethertap transport"
        depends on UML_NET
        help
-        The Ethertap User-Mode Linux network transport allows a single
-        running UML to exchange packets with its host over one of the
-        host's Ethertap devices, such as /dev/tap0.  Additional running
-        UMLs can use additional Ethertap devices, one per running UML.
-        While the UML believes it's on a (multi-device, broadcast) virtual
-        Ethernet network, it's in fact communicating over a point-to-point
-        link with the host.
-
-        To use this, your host kernel must have support for Ethertap
-        devices.  Also, if your host kernel is 2.4.x, it must have
-        CONFIG_NETLINK_DEV configured as Y or M.
-
-        For more information, see
-        <http://user-mode-linux.sourceforge.net/old/networking.html>  That site
-        has examples of the UML command line to use to enable Ethertap
-        networking.
-
-        If you'd like to set up an IP network with the host and/or the
-        outside world, say Y to this, the Daemon Transport and/or the
-        Slip Transport.  You'll need at least one of them, but may choose
-        more than one without conflict.  If you don't need UML networking,
-        say N.
+         The Ethertap User-Mode Linux network transport allows a single
+         running UML to exchange packets with its host over one of the
+         host's Ethertap devices, such as /dev/tap0.  Additional running
+         UMLs can use additional Ethertap devices, one per running UML.
+         While the UML believes it's on a (multi-device, broadcast) virtual
+         Ethernet network, it's in fact communicating over a point-to-point
+         link with the host.
+
+         To use this, your host kernel must have support for Ethertap
+         devices.  Also, if your host kernel is 2.4.x, it must have
+         CONFIG_NETLINK_DEV configured as Y or M.
+
+         For more information, see
+         <http://user-mode-linux.sourceforge.net/old/networking.html>  That site
+         has examples of the UML command line to use to enable Ethertap
+         networking.
+
+         If you'd like to set up an IP network with the host and/or the
+         outside world, say Y to this, the Daemon Transport and/or the
+         Slip Transport.  You'll need at least one of them, but may choose
+         more than one without conflict.  If you don't need UML networking,
+         say N.
 
 config UML_NET_TUNTAP
        bool "TUN/TAP transport"
        depends on UML_NET
        help
-        The UML TUN/TAP network transport allows a UML instance to exchange
-        packets with the host over a TUN/TAP device.  This option will only
-        work with a 2.4 host, unless you've applied the TUN/TAP patch to
-        your 2.2 host kernel.
+         The UML TUN/TAP network transport allows a UML instance to exchange
+         packets with the host over a TUN/TAP device.  This option will only
+         work with a 2.4 host, unless you've applied the TUN/TAP patch to
+         your 2.2 host kernel.
 
-        To use this transport, your host kernel must have support for TUN/TAP
-        devices, either built-in or as a module.
+         To use this transport, your host kernel must have support for TUN/TAP
+         devices, either built-in or as a module.
 
 config UML_NET_SLIP
        bool "SLIP transport"
        depends on UML_NET
        help
-        The slip User-Mode Linux network transport allows a running UML to
-        network with its host over a point-to-point link.  Unlike Ethertap,
-        which can carry any Ethernet frame (and hence even non-IP packets),
-        the slip transport can only carry IP packets.
-
-        To use this, your host must support slip devices.
-
-        For more information, see
-        <http://user-mode-linux.sourceforge.net/old/networking.html>.
-        has examples of the UML command line to use to enable slip
-        networking, and details of a few quirks with it.
-
-        The Ethertap Transport is preferred over slip because of its
-        limitations.  If you prefer slip, however, say Y here.  Otherwise
-        choose the Multicast transport (to network multiple UMLs on
-        multiple hosts), Ethertap (to network with the host and the
-        outside world), and/or the Daemon transport (to network multiple
-        UMLs on a single host).  You may choose more than one without
-        conflict.  If you don't need UML networking, say N.
+         The slip User-Mode Linux network transport allows a running UML to
+         network with its host over a point-to-point link.  Unlike Ethertap,
+         which can carry any Ethernet frame (and hence even non-IP packets),
+         the slip transport can only carry IP packets.
+
+         To use this, your host must support slip devices.
+
+         For more information, see
+         <http://user-mode-linux.sourceforge.net/old/networking.html>.
+         has examples of the UML command line to use to enable slip
+         networking, and details of a few quirks with it.
+
+         The Ethertap Transport is preferred over slip because of its
+         limitations.  If you prefer slip, however, say Y here.  Otherwise
+         choose the Multicast transport (to network multiple UMLs on
+         multiple hosts), Ethertap (to network with the host and the
+         outside world), and/or the Daemon transport (to network multiple
+         UMLs on a single host).  You may choose more than one without
+         conflict.  If you don't need UML networking, say N.
 
 config UML_NET_DAEMON
        bool "Daemon transport"
        depends on UML_NET
        help
-        This User-Mode Linux network transport allows one or more running
-        UMLs on a single host to communicate with each other, but not to
-        the host.
-
-        To use this form of networking, you'll need to run the UML
-        networking daemon on the host.
-
-        For more information, see
-        <http://user-mode-linux.sourceforge.net/old/networking.html>  That site
-        has examples of the UML command line to use to enable Daemon
-        networking.
-
-        If you'd like to set up a network with other UMLs on a single host,
-        say Y.  If you need a network between UMLs on multiple physical
-        hosts, choose the Multicast Transport.  To set up a network with
-        the host and/or other IP machines, say Y to the Ethertap or Slip
-        transports.  You'll need at least one of them, but may choose
-        more than one without conflict.  If you don't need UML networking,
-        say N.
+         This User-Mode Linux network transport allows one or more running
+         UMLs on a single host to communicate with each other, but not to
+         the host.
+
+         To use this form of networking, you'll need to run the UML
+         networking daemon on the host.
+
+         For more information, see
+         <http://user-mode-linux.sourceforge.net/old/networking.html>  That site
+         has examples of the UML command line to use to enable Daemon
+         networking.
+
+         If you'd like to set up a network with other UMLs on a single host,
+         say Y.  If you need a network between UMLs on multiple physical
+         hosts, choose the Multicast Transport.  To set up a network with
+         the host and/or other IP machines, say Y to the Ethertap or Slip
+         transports.  You'll need at least one of them, but may choose
+         more than one without conflict.  If you don't need UML networking,
+         say N.
 
 config UML_NET_VECTOR
        bool "Vector I/O high performance network devices"
@@ -270,26 +270,26 @@ config UML_NET_MCAST
        bool "Multicast transport"
        depends on UML_NET
        help
-        This Multicast User-Mode Linux network transport allows multiple
-        UMLs (even ones running on different host machines!) to talk to
-        each other over a virtual ethernet network.  However, it requires
-        at least one UML with one of the other transports to act as a
-        bridge if any of them need to be able to talk to their hosts or any
-        other IP machines.
-
-        To use this, your host kernel(s) must support IP Multicasting.
-
-        For more information, see
-        <http://user-mode-linux.sourceforge.net/old/networking.html>  That site
-        has examples of the UML command line to use to enable Multicast
-        networking, and notes about the security of this approach.
-
-        If you need UMLs on multiple physical hosts to communicate as if
-        they shared an Ethernet network, say Y.  If you need to communicate
-        with other IP machines, make sure you select one of the other
-        transports (possibly in addition to Multicast; they're not
-        exclusive).  If you don't need to network UMLs say N to each of
-        the transports.
+         This Multicast User-Mode Linux network transport allows multiple
+         UMLs (even ones running on different host machines!) to talk to
+         each other over a virtual ethernet network.  However, it requires
+         at least one UML with one of the other transports to act as a
+         bridge if any of them need to be able to talk to their hosts or any
+         other IP machines.
+
+         To use this, your host kernel(s) must support IP Multicasting.
+
+         For more information, see
+         <http://user-mode-linux.sourceforge.net/old/networking.html>  That site
+         has examples of the UML command line to use to enable Multicast
+         networking, and notes about the security of this approach.
+
+         If you need UMLs on multiple physical hosts to communicate as if
+         they shared an Ethernet network, say Y.  If you need to communicate
+         with other IP machines, make sure you select one of the other
+         transports (possibly in addition to Multicast; they're not
+         exclusive).  If you don't need to network UMLs say N to each of
+         the transports.
 
 config UML_NET_PCAP
        bool "pcap transport"
@@ -300,9 +300,9 @@ config UML_NET_PCAP
        UML act as a network monitor for the host.  You must have libcap
        installed in order to build the pcap transport into UML.
 
-        For more information, see
-        <http://user-mode-linux.sourceforge.net/old/networking.html>  That site
-        has examples of the UML command line to use to enable this option.
+         For more information, see
+         <http://user-mode-linux.sourceforge.net/old/networking.html>  That site
+         has examples of the UML command line to use to enable this option.
 
        If you intend to use UML as a network monitor for the host, say
        Y here.  Otherwise, say N.
@@ -311,27 +311,27 @@ config UML_NET_SLIRP
        bool "SLiRP transport"
        depends on UML_NET
        help
-        The SLiRP User-Mode Linux network transport allows a running UML
-        to network by invoking a program that can handle SLIP encapsulated
-        packets.  This is commonly (but not limited to) the application
-        known as SLiRP, a program that can re-socket IP packets back onto
-        the host on which it is run.  Only IP packets are supported,
-        unlike other network transports that can handle all Ethernet
-        frames.  In general, slirp allows the UML the same IP connectivity
-        to the outside world that the host user is permitted, and unlike
-        other transports, SLiRP works without the need of root level
-        privleges, setuid binaries, or SLIP devices on the host.  This
-        also means not every type of connection is possible, but most
-        situations can be accommodated with carefully crafted slirp
-        commands that can be passed along as part of the network device's
-        setup string.  The effect of this transport on the UML is similar
-        that of a host behind a firewall that masquerades all network
-        connections passing through it (but is less secure).
-
-        To use this you should first have slirp compiled somewhere
-        accessible on the host, and have read its documentation.  If you
-        don't need UML networking, say N.
-
-        Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
+         The SLiRP User-Mode Linux network transport allows a running UML
+         to network by invoking a program that can handle SLIP encapsulated
+         packets.  This is commonly (but not limited to) the application
+         known as SLiRP, a program that can re-socket IP packets back onto
+         he host on which it is run.  Only IP packets are supported,
+         unlike other network transports that can handle all Ethernet
+         frames.  In general, slirp allows the UML the same IP connectivity
+         to the outside world that the host user is permitted, and unlike
+         other transports, SLiRP works without the need of root level
+         privleges, setuid binaries, or SLIP devices on the host.  This
+         also means not every type of connection is possible, but most
+         situations can be accommodated with carefully crafted slirp
+         commands that can be passed along as part of the network device's
+         setup string.  The effect of this transport on the UML is similar
+         that of a host behind a firewall that masquerades all network
+         connections passing through it (but is less secure).
+
+         To use this you should first have slirp compiled somewhere
+         accessible on the host, and have read its documentation.  If you
+         don't need UML networking, say N.
+
+         Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
 
 endmenu
index aca09be2373e77245ec9adfccdb540342a4d0bb9..33c1cd6a12ac83fa9f901c98a5bbbca82932e905 100644 (file)
@@ -276,14 +276,14 @@ static int ubd_setup_common(char *str, int *index_out, char **error_out)
                str++;
                if(!strcmp(str, "sync")){
                        global_openflags = of_sync(global_openflags);
-                       goto out1;
+                       return err;
                }
 
                err = -EINVAL;
                major = simple_strtoul(str, &end, 0);
                if((*end != '\0') || (end == str)){
                        *error_out = "Didn't parse major number";
-                       goto out1;
+                       return err;
                }
 
                mutex_lock(&ubd_lock);
index 9c04562310b36630bb3ec008c99fdf05e3597c85..b377df76cc281da4d734d88478f703a05718c40d 100644 (file)
@@ -263,7 +263,12 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval)
        *pteptr = pte_mknewpage(*pteptr);
        if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr);
 }
-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+                             pte_t *pteptr, pte_t pteval)
+{
+       set_pte(pteptr, pteval);
+}
 
 #define __HAVE_ARCH_PTE_SAME
 static inline int pte_same(pte_t pte_a, pte_t pte_b)
index f4874b7ec5038a2dcf8e3cf01b6873048d0bb8e5..598d7b3d93550dc7e5b92ec850ccc61d86d84f00 100644 (file)
@@ -479,7 +479,7 @@ void __init init_IRQ(void)
        irq_set_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq);
 
 
-       for (i = 1; i < NR_IRQS; i++)
+       for (i = 1; i < LAST_IRQ; i++)
                irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq);
        /* Initialize EPOLL Loop */
        os_setup_epoll();
index 99aa11bf53d108d9bb5878d70e7b762b07334b1d..a9c9a94c096f7f44d23bf63249a080f67395b3be 100644 (file)
@@ -188,13 +188,6 @@ void free_initmem(void)
 {
 }
 
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-#endif
-
 /* Allocate and free page tables. */
 
 pgd_t *pgd_alloc(struct mm_struct *mm)
index 7f06fdbc7ee110468e70ba9fbb4670253d655d63..bd3cb694322cb124ee976984232099563a6b0594 100644 (file)
@@ -59,7 +59,6 @@ static pte_t *maybe_map(unsigned long virt, int is_write)
 static int do_op_one_page(unsigned long addr, int len, int is_write,
                 int (*op)(unsigned long addr, int len, void *arg), void *arg)
 {
-       jmp_buf buf;
        struct page *page;
        pte_t *pte;
        int n;
index 052de4c8acb2ec42c04d4fe30b267aa607e8a332..0c572a48158e8de36a18f41ce5b61e3e0ee286b5 100644 (file)
@@ -56,7 +56,7 @@ static int itimer_one_shot(struct clock_event_device *evt)
 static struct clock_event_device timer_clockevent = {
        .name                   = "posix-timer",
        .rating                 = 250,
-       .cpumask                = cpu_all_mask,
+       .cpumask                = cpu_possible_mask,
        .features               = CLOCK_EVT_FEAT_PERIODIC |
                                  CLOCK_EVT_FEAT_ONESHOT,
        .set_state_shutdown     = itimer_shutdown,
index bf0acb8aad8b20e31a4591ec5f1889d38d68d010..75b10235d3691b45adf78b0e9cf5077903bf0825 100644 (file)
@@ -31,29 +31,23 @@ void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
 
 static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)
 {
-       struct uml_pt_regs *r;
+       struct uml_pt_regs r;
        int save_errno = errno;
 
-       r = uml_kmalloc(sizeof(struct uml_pt_regs), UM_GFP_ATOMIC);
-       if (!r)
-               panic("out of memory");
-
-       r->is_user = 0;
+       r.is_user = 0;
        if (sig == SIGSEGV) {
                /* For segfaults, we want the data from the sigcontext. */
-               get_regs_from_mc(r, mc);
-               GET_FAULTINFO_FROM_MC(r->faultinfo, mc);
+               get_regs_from_mc(&r, mc);
+               GET_FAULTINFO_FROM_MC(r.faultinfo, mc);
        }
 
        /* enable signals if sig isn't IRQ signal */
        if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGALRM))
                unblock_signals();
 
-       (*sig_info[sig])(sig, si, r);
+       (*sig_info[sig])(sig, si, &r);
 
        errno = save_errno;
-
-       free(r);
 }
 
 /*
@@ -91,17 +85,11 @@ void sig_handler(int sig, struct siginfo *si, mcontext_t *mc)
 
 static void timer_real_alarm_handler(mcontext_t *mc)
 {
-       struct uml_pt_regs *regs;
-
-       regs = uml_kmalloc(sizeof(struct uml_pt_regs), UM_GFP_ATOMIC);
-       if (!regs)
-               panic("out of memory");
+       struct uml_pt_regs regs;
 
        if (mc != NULL)
-               get_regs_from_mc(regs, mc);
-       timer_handler(SIGALRM, NULL, regs);
-
-       free(regs);
+               get_regs_from_mc(&regs, mc);
+       timer_handler(SIGALRM, NULL, &regs);
 }
 
 void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)
index 998fbb4454586e24ffbf71b0087eb60eb1f7e4f1..e261656fe9d7a9a1a8e19f8975a543a4825dfdbf 100644 (file)
@@ -135,12 +135,18 @@ out:
  */
 static inline int is_umdir_used(char *dir)
 {
-       char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
-       char pid[sizeof("nnnnn\0")], *end;
+       char pid[sizeof("nnnnn\0")], *end, *file;
        int dead, fd, p, n, err;
+       size_t filelen;
 
-       n = snprintf(file, sizeof(file), "%s/pid", dir);
-       if (n >= sizeof(file)) {
+       err = asprintf(&file, "%s/pid", dir);
+       if (err < 0)
+               return 0;
+
+       filelen = strlen(file);
+
+       n = snprintf(file, filelen, "%s/pid", dir);
+       if (n >= filelen) {
                printk(UM_KERN_ERR "is_umdir_used - pid filename too long\n");
                err = -E2BIG;
                goto out;
@@ -185,6 +191,7 @@ static inline int is_umdir_used(char *dir)
 out_close:
        close(fd);
 out:
+       free(file);
        return 0;
 }
 
@@ -210,18 +217,21 @@ static int umdir_take_if_dead(char *dir)
 
 static void __init create_pid_file(void)
 {
-       char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
-       char pid[sizeof("nnnnn\0")];
+       char pid[sizeof("nnnnn\0")], *file;
        int fd, n;
 
-       if (umid_file_name("pid", file, sizeof(file)))
+       file = malloc(strlen(uml_dir) + UMID_LEN + sizeof("/pid\0"));
+       if (!file)
                return;
 
+       if (umid_file_name("pid", file, sizeof(file)))
+               goto out;
+
        fd = open(file, O_RDWR | O_CREAT | O_EXCL, 0644);
        if (fd < 0) {
                printk(UM_KERN_ERR "Open of machine pid file \"%s\" failed: "
                       "%s\n", file, strerror(errno));
-               return;
+               goto out;
        }
 
        snprintf(pid, sizeof(pid), "%d\n", getpid());
@@ -231,6 +241,8 @@ static void __init create_pid_file(void)
                       errno);
 
        close(fd);
+out:
+       free(file);
 }
 
 int __init set_umid(char *name)
@@ -385,13 +397,19 @@ __uml_setup("uml_dir=", set_uml_dir,
 
 static void remove_umid_dir(void)
 {
-       char dir[strlen(uml_dir) + UMID_LEN + 1], err;
+       char *dir, err;
+
+       dir = malloc(strlen(uml_dir) + UMID_LEN + 1);
+       if (!dir)
+               return;
 
        sprintf(dir, "%s%s", uml_dir, umid);
        err = remove_files_and_dir(dir);
        if (err)
                os_warn("%s - remove_files_and_dir failed with err = %d\n",
                        __func__, err);
+
+       free(dir);
 }
 
 __uml_exitcall(remove_umid_dir);
index 2445dfcf64446bd1fbcadb4fe75bab9c6ea62efd..41fe944005f818acf563b6496151af48498b71ae 100644 (file)
@@ -3,6 +3,7 @@ config UNICORE32
        def_bool y
        select ARCH_32BIT_OFF_T
        select ARCH_HAS_DEVMEM_IS_ALLOWED
+       select ARCH_HAS_KEEPINITRD
        select ARCH_MIGHT_HAVE_PC_PARPORT
        select ARCH_MIGHT_HAVE_PC_SERIO
        select HAVE_KERNEL_GZIP
@@ -190,7 +191,6 @@ config I2C_EEPROM_AT24
 
 config LCD_BACKLIGHT
        tristate "LCD Backlight support"
-       select BACKLIGHT_LCD_SUPPORT
        select BACKLIGHT_PWM
 
 endmenu
index aebd01fc28e59a3b5c530c8a596a4fcccd3e15df..360cc9abcdb0933ef3234df5fd647bb383c9bd0f 100644 (file)
@@ -119,7 +119,7 @@ CONFIG_I2C_PUV3=y
 #      Hardware Monitoring support
 #CONFIG_SENSORS_LM75=m
 #      Generic Thermal sysfs driver
-#CONFIG_THERMAL=m
+#CONFIG_THERMAL=y
 #CONFIG_THERMAL_HWMON=y
 
 #      Multimedia support
index b301a0b3c0b2b1f1213174bab772d30a1b144131..5fe2426bb7a579abfcd234e4379e4a1d6f3efe38 100644 (file)
@@ -28,10 +28,8 @@ generic-y += parport.h
 generic-y += percpu.h
 generic-y += preempt.h
 generic-y += sections.h
-generic-y += segment.h
 generic-y += serial.h
 generic-y += shmparam.h
-generic-y += sizes.h
 generic-y += syscalls.h
 generic-y += topology.h
 generic-y += trace_clock.h
index 66bb9f6525c04ca427ae4d4440246106aa37dd9e..46cf27efbb7ebdc512ba1a92a485a5744d3745f1 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <linux/compiler.h>
 #include <linux/const.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <mach/memory.h>
 
 /*
index 74b6a2e29809a8b0253bc5ac5561f943809f2d42..c994cdf1411957f55eb78cae1ea2e29399106423 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <asm/sections.h>
 #include <asm/setup.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/tlb.h>
 #include <asm/memblock.h>
 #include <mach/map.h>
@@ -287,27 +287,3 @@ void __init mem_init(void)
                sysctl_overcommit_memory = OVERCOMMIT_ALWAYS;
        }
 }
-
-void free_initmem(void)
-{
-       free_initmem_default(-1);
-}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-
-static int keep_initrd;
-
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       if (!keep_initrd)
-               free_reserved_area((void *)start, (void *)end, -1, "initrd");
-}
-
-static int __init keepinitrd_setup(char *__unused)
-{
-       keep_initrd = 1;
-       return 1;
-}
-
-__setup("keepinitrd", keepinitrd_setup);
-#endif
index bf012b2b71a91ad61118c9cf0e54a587d715aa19..b69cb18ce8b14ec950e5a507ba8cc5d46996bdfa 100644 (file)
@@ -34,7 +34,7 @@
 #include <asm/mmu_context.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include <mach/map.h>
 #include "mm.h"
index aa2060beb40840d91b9023fce78f116f26c8952d..f0ae623b305f8b53f3e6596f3327e4d81cb3b9e7 100644 (file)
@@ -22,7 +22,7 @@
 #include <asm/cputype.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/tlb.h>
 #include <asm/memblock.h>
 
index e7212731cffb74c1da98cdbbb15cad5946b20849..2bbbd4d1ba31de5c0431393247ac4279878eb13d 100644 (file)
@@ -22,7 +22,7 @@ config X86_64
        def_bool y
        depends on 64BIT
        # Options that are inherently 64-bit kernel only:
-       select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA
+       select ARCH_HAS_GIGANTIC_PAGE
        select ARCH_SUPPORTS_INT128
        select ARCH_USE_CMPXCHG_LOCKREF
        select HAVE_ARCH_SOFT_DIRTY
@@ -31,6 +31,17 @@ config X86_64
        select SWIOTLB
        select ARCH_HAS_SYSCALL_WRAPPER
 
+config FORCE_DYNAMIC_FTRACE
+       def_bool y
+       depends on X86_32
+       depends on FUNCTION_TRACER
+       select DYNAMIC_FTRACE
+       help
+        We keep the static function tracing (!DYNAMIC_FTRACE) around
+        in order to test the non static function tracing in the
+        generic code, as other architectures still use it. But we
+        only need to keep it around for x86_64. No need to keep it
+        for x86_32. For x86_32, force DYNAMIC_FTRACE. 
 #
 # Arch settings
 #
@@ -47,7 +58,6 @@ config X86
        select ARCH_32BIT_OFF_T                 if X86_32
        select ARCH_CLOCKSOURCE_DATA
        select ARCH_CLOCKSOURCE_INIT
-       select ARCH_DISCARD_MEMBLOCK
        select ARCH_HAS_ACPI_TABLE_UPGRADE      if ACPI
        select ARCH_HAS_DEBUG_VIRTUAL
        select ARCH_HAS_DEVMEM_IS_ALLOWED
@@ -260,9 +270,6 @@ config GENERIC_BUG
 config GENERIC_BUG_RELATIVE_POINTERS
        bool
 
-config GENERIC_HWEIGHT
-       def_bool y
-
 config ARCH_MAY_HAVE_PC_FDC
        def_bool y
        depends on ISA_DMA_API
@@ -306,9 +313,6 @@ config ZONE_DMA32
 config AUDIT_ARCH
        def_bool y if X86_64
 
-config ARCH_SUPPORTS_OPTIMIZED_INLINING
-       def_bool y
-
 config ARCH_SUPPORTS_DEBUG_PAGEALLOC
        def_bool y
 
index 15d0fbe278726b7b1fcb33459eef9b0037044ca2..f730680dc818603a25d07412108b491bd02f1b20 100644 (file)
@@ -266,20 +266,6 @@ config CPA_DEBUG
        ---help---
          Do change_page_attr() self-tests every 30 seconds.
 
-config OPTIMIZE_INLINING
-       bool "Allow gcc to uninline functions marked 'inline'"
-       ---help---
-         This option determines if the kernel forces gcc to inline the functions
-         developers have marked 'inline'. Doing so takes away freedom from gcc to
-         do what it thinks is best, which is desirable for the gcc 3.x series of
-         compilers. The gcc 4.x series have a rewritten inlining algorithm and
-         enabling this option will generate a smaller kernel there. Hopefully
-         this algorithm is so good that allowing gcc 4.x and above to make the
-         decision will become the default in the future. Until then this option
-         is there to test gcc for this.
-
-         If unsure, say N.
-
 config DEBUG_ENTRY
        bool "Debug low-level entry code"
        depends on DEBUG_KERNEL
index 51beb8d29123a66f28e1d4d6e0f35c160a9913f7..a986b3c8294c8df7ee0157b27b665cfc4e05d894 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/vdso.h>
 #include <asm/cpufeature.h>
 #include <asm/fpu/api.h>
+#include <asm/nospec-branch.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/syscalls.h>
@@ -220,6 +221,8 @@ __visible inline void prepare_exit_to_usermode(struct pt_regs *regs)
 #endif
 
        user_enter_irqoff();
+
+       mds_user_clear_cpu_buffers();
 }
 
 #define SYSCALL_EXIT_WORK_FLAGS                                \
index 20e45d9b4e156cc90a464715b0370f27f259ee80..11aa3b2afa4d8e2b3a7d9dc619270d1d8ae15a3d 100644 (file)
@@ -878,7 +878,7 @@ apicinterrupt IRQ_WORK_VECTOR                       irq_work_interrupt              smp_irq_work_interrupt
  * @paranoid == 2 is special: the stub will never switch stacks.  This is for
  * #DF: if the thread stack is somehow unusable, we'll still get a useful OOPS.
  */
-.macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 ist_offset=0
+.macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 ist_offset=0 create_gap=0
 ENTRY(\sym)
        UNWIND_HINT_IRET_REGS offset=\has_error_code*8
 
@@ -898,6 +898,20 @@ ENTRY(\sym)
        jnz     .Lfrom_usermode_switch_stack_\@
        .endif
 
+       .if \create_gap == 1
+       /*
+        * If coming from kernel space, create a 6-word gap to allow the
+        * int3 handler to emulate a call instruction.
+        */
+       testb   $3, CS-ORIG_RAX(%rsp)
+       jnz     .Lfrom_usermode_no_gap_\@
+       .rept   6
+       pushq   5*8(%rsp)
+       .endr
+       UNWIND_HINT_IRET_REGS offset=8
+.Lfrom_usermode_no_gap_\@:
+       .endif
+
        .if \paranoid
        call    paranoid_entry
        .else
@@ -1129,7 +1143,7 @@ apicinterrupt3 HYPERV_STIMER0_VECTOR \
 #endif /* CONFIG_HYPERV */
 
 idtentry debug                 do_debug                has_error_code=0        paranoid=1 shift_ist=IST_INDEX_DB ist_offset=DB_STACK_OFFSET
-idtentry int3                  do_int3                 has_error_code=0
+idtentry int3                  do_int3                 has_error_code=0        create_gap=1
 idtentry stack_segment         do_stack_segment        has_error_code=1
 
 #ifdef CONFIG_XEN_PV
index 4cd5f982b1e5d6127175564e0f0f79903605d06f..ad968b7bac72ba4b516dcaaaf49ed9f6c3a69f0a 100644 (file)
 384    i386    arch_prctl              sys_arch_prctl                  __ia32_compat_sys_arch_prctl
 385    i386    io_pgetevents           sys_io_pgetevents_time32        __ia32_compat_sys_io_pgetevents
 386    i386    rseq                    sys_rseq                        __ia32_sys_rseq
-387    i386    open_tree               sys_open_tree                   __ia32_sys_open_tree
-388    i386    move_mount              sys_move_mount                  __ia32_sys_move_mount
-389    i386    fsopen                  sys_fsopen                      __ia32_sys_fsopen
-390    i386    fsconfig                sys_fsconfig                    __ia32_sys_fsconfig
-391    i386    fsmount                 sys_fsmount                     __ia32_sys_fsmount
-392    i386    fspick                  sys_fspick                      __ia32_sys_fspick
 393    i386    semget                  sys_semget                      __ia32_sys_semget
 394    i386    semctl                  sys_semctl                      __ia32_compat_sys_semctl
 395    i386    shmget                  sys_shmget                      __ia32_sys_shmget
 425    i386    io_uring_setup          sys_io_uring_setup              __ia32_sys_io_uring_setup
 426    i386    io_uring_enter          sys_io_uring_enter              __ia32_sys_io_uring_enter
 427    i386    io_uring_register       sys_io_uring_register           __ia32_sys_io_uring_register
+428    i386    open_tree               sys_open_tree                   __ia32_sys_open_tree
+429    i386    move_mount              sys_move_mount                  __ia32_sys_move_mount
+430    i386    fsopen                  sys_fsopen                      __ia32_sys_fsopen
+431    i386    fsconfig                sys_fsconfig                    __ia32_sys_fsconfig
+432    i386    fsmount                 sys_fsmount                     __ia32_sys_fsmount
+433    i386    fspick                  sys_fspick                      __ia32_sys_fspick
index 64ca0d06259a7635ebc8ae1fa5e3a6b1447b3cd3..b4e6f9e6204aa874f03337adc47f9bba0297f707 100644 (file)
 332    common  statx                   __x64_sys_statx
 333    common  io_pgetevents           __x64_sys_io_pgetevents
 334    common  rseq                    __x64_sys_rseq
-335    common  open_tree               __x64_sys_open_tree
-336    common  move_mount              __x64_sys_move_mount
-337    common  fsopen                  __x64_sys_fsopen
-338    common  fsconfig                __x64_sys_fsconfig
-339    common  fsmount                 __x64_sys_fsmount
-340    common  fspick                  __x64_sys_fspick
 # don't use numbers 387 through 423, add new calls after the last
 # 'common' entry
 424    common  pidfd_send_signal       __x64_sys_pidfd_send_signal
 425    common  io_uring_setup          __x64_sys_io_uring_setup
 426    common  io_uring_enter          __x64_sys_io_uring_enter
 427    common  io_uring_register       __x64_sys_io_uring_register
+428    common  open_tree               __x64_sys_open_tree
+429    common  move_mount              __x64_sys_move_mount
+430    common  fsopen                  __x64_sys_fsopen
+431    common  fsconfig                __x64_sys_fsconfig
+432    common  fsmount                 __x64_sys_fsmount
+433    common  fspick                  __x64_sys_fspick
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
index 8e470b018512c29f41d0adc7dd8717b155a07229..3a4d8d4d39f87bb073c4c8b7504a293344ef3cfe 100644 (file)
@@ -73,14 +73,12 @@ const char *outfilename;
 enum {
        sym_vvar_start,
        sym_vvar_page,
-       sym_hpet_page,
        sym_pvclock_page,
        sym_hvclock_page,
 };
 
 const int special_pages[] = {
        sym_vvar_page,
-       sym_hpet_page,
        sym_pvclock_page,
        sym_hvclock_page,
 };
@@ -93,7 +91,6 @@ struct vdso_sym {
 struct vdso_sym required_syms[] = {
        [sym_vvar_start] = {"vvar_start", true},
        [sym_vvar_page] = {"vvar_page", true},
-       [sym_hpet_page] = {"hpet_page", true},
        [sym_pvclock_page] = {"pvclock_page", true},
        [sym_hvclock_page] = {"hvclock_page", true},
        {"VDSO32_NOTE_MASK", true},
index 7635c23f7d82e9839ba306fbb6721333d532d11f..58a6993d7eb3f6aff39f0842b25cb5e4ada0eec9 100644 (file)
@@ -393,7 +393,7 @@ static __init int _init_events_attrs(void)
        return 0;
 }
 
-const struct attribute_group *amd_iommu_attr_groups[] = {
+static const struct attribute_group *amd_iommu_attr_groups[] = {
        &amd_iommu_format_group,
        &amd_iommu_cpumask_group,
        &amd_iommu_events_group,
index 7cdd7b13bbda67352ed0c6e8dad5f381f027514d..890a3fb5706fcae7ce25b3486381b371a186b25a 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/device.h>
 #include <linux/coredump.h>
 
-#include <asm-generic/sizes.h>
+#include <linux/sizes.h>
 #include <asm/perf_event.h>
 
 #include "../perf_event.h"
index ef763f535e3abbd034857ad48a678c1281a358c4..546d13e436aafae54764787736f9501a110a8d4b 100644 (file)
@@ -2384,7 +2384,11 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status)
         */
        if (__test_and_clear_bit(55, (unsigned long *)&status)) {
                handled++;
-               intel_pt_interrupt();
+               if (unlikely(perf_guest_cbs && perf_guest_cbs->is_in_guest() &&
+                       perf_guest_cbs->handle_intel_pt_intr))
+                       perf_guest_cbs->handle_intel_pt_intr();
+               else
+                       intel_pt_interrupt();
        }
 
        /*
@@ -3265,7 +3269,7 @@ static int intel_pmu_hw_config(struct perf_event *event)
                return ret;
 
        if (event->attr.precise_ip) {
-               if (!(event->attr.freq || event->attr.wakeup_events)) {
+               if (!(event->attr.freq || (event->attr.wakeup_events && !event->attr.watermark))) {
                        event->hw.flags |= PERF_X86_EVENT_AUTO_RELOAD;
                        if (!(event->attr.sample_type &
                              ~intel_pmu_large_pebs_flags(event)))
index 07fc84bb85c1e9e85138cd9205045215e1d0d528..a6ac2f4f76fc97ef2409e31fb3f8a3ac54a35bd4 100644 (file)
@@ -394,10 +394,10 @@ struct cpu_hw_events {
 
 /* Event constraint, but match on all event flags too. */
 #define INTEL_FLAGS_EVENT_CONSTRAINT(c, n) \
-       EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS)
+       EVENT_CONSTRAINT(c, n, ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS)
 
 #define INTEL_FLAGS_EVENT_CONSTRAINT_RANGE(c, e, n)                    \
-       EVENT_CONSTRAINT_RANGE(c, e, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS)
+       EVENT_CONSTRAINT_RANGE(c, e, n, ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS)
 
 /* Check only flags, but allow all event/umask */
 #define INTEL_ALL_EVENT_CONSTRAINT(code, n)    \
index fc0693569f7aae7baebcf8c6606ce66c09af701e..ba88edd0d58b1dde141899aee64ce0e33edc4449 100644 (file)
@@ -12,8 +12,6 @@
 #define REG_OUT "a"
 #endif
 
-#define __HAVE_ARCH_SW_HWEIGHT
-
 static __always_inline unsigned int __arch_hweight32(unsigned int w)
 {
        unsigned int res;
index 981ff94796484426911c41e333b82ef395380caa..75f27ee2c263f4233f7818c52c1afa4a3fca768b 100644 (file)
 /* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */
 #define X86_FEATURE_AVX512_4VNNIW      (18*32+ 2) /* AVX-512 Neural Network Instructions */
 #define X86_FEATURE_AVX512_4FMAPS      (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */
+#define X86_FEATURE_MD_CLEAR           (18*32+10) /* VERW clears CPU buffers */
 #define X86_FEATURE_TSX_FORCE_ABORT    (18*32+13) /* "" TSX_FORCE_ABORT */
 #define X86_FEATURE_PCONFIG            (18*32+18) /* Intel PCONFIG */
 #define X86_FEATURE_SPEC_CTRL          (18*32+26) /* "" Speculation Control (IBRS + IBPB) */
 #define X86_BUG_SPECTRE_V2             X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */
 #define X86_BUG_SPEC_STORE_BYPASS      X86_BUG(17) /* CPU is affected by speculative store bypass attack */
 #define X86_BUG_L1TF                   X86_BUG(18) /* CPU is affected by L1 Terminal Fault */
+#define X86_BUG_MDS                    X86_BUG(19) /* CPU is affected by Microarchitectural data sampling */
+#define X86_BUG_MSBDS_ONLY             X86_BUG(20) /* CPU is only affected by the  MSDBS variant of BUG_MDS */
 
 #endif /* _ASM_X86_CPUFEATURES_H */
index 62be73b23d5cd89b778c791da28eb311e739abb9..e8f58ddd06d97fbce6ef1f701f9f91766ef2847d 100644 (file)
@@ -10,6 +10,7 @@ extern struct e820_table *e820_table_firmware;
 
 extern unsigned long pci_mem_start;
 
+extern bool e820__mapped_raw_any(u64 start, u64 end, enum e820_type type);
 extern bool e820__mapped_any(u64 start, u64 end, enum e820_type type);
 extern bool e820__mapped_all(u64 start, u64 end, enum e820_type type);
 
index cf350639e76d1312a9c75f0ab21dfb31e0014afe..287f1f7b2e529419b0401c30c53f3ae7604dcf78 100644 (file)
@@ -3,12 +3,10 @@
 #define _ASM_X86_FTRACE_H
 
 #ifdef CONFIG_FUNCTION_TRACER
-#ifdef CC_USING_FENTRY
-# define MCOUNT_ADDR           ((unsigned long)(__fentry__))
-#else
-# define MCOUNT_ADDR           ((unsigned long)(mcount))
-# define HAVE_FUNCTION_GRAPH_FP_TEST
+#ifndef CC_USING_FENTRY
+# error Compiler does not support fentry?
 #endif
+# define MCOUNT_ADDR           ((unsigned long)(__fentry__))
 #define MCOUNT_INSN_SIZE       5 /* sizeof mcount call */
 
 #ifdef CONFIG_DYNAMIC_FTRACE
index 7469d321f07221a201ace98623f2b34b379b57f9..f65cfb48cfddad0079d45b9a0721b5fec2904a2f 100644 (file)
@@ -17,8 +17,4 @@ static inline void arch_clear_hugepage_flags(struct page *page)
 {
 }
 
-#ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE
-static inline bool gigantic_page_supported(void) { return true; }
-#endif
-
 #endif /* _ASM_X86_HUGETLB_H */
index 2bdbbbcfa393fd6b2df936029917d20dc4ae8e84..cdf44aa9a50142388573eb591b75db38189f4fa6 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* SPDX-License-Identifier: GPL-2.0 */
 
 /*
  * This file contains definitions from Hyper-V Hypervisor Top-Level Functional
index 058e40fed1677f1a3387b9930f1c4c61da32a93b..8a0e56e1dcc9cdfd582ef65e9bbac5fc8506ee83 100644 (file)
@@ -6,6 +6,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <asm/nospec-branch.h>
+
 /* Provide __cpuidle; we can't safely include <linux/cpu.h> */
 #define __cpuidle __attribute__((__section__(".cpuidle.text")))
 
@@ -54,11 +56,13 @@ static inline void native_irq_enable(void)
 
 static inline __cpuidle void native_safe_halt(void)
 {
+       mds_idle_clear_cpu_buffers();
        asm volatile("sti; hlt": : :"memory");
 }
 
 static inline __cpuidle void native_halt(void)
 {
+       mds_idle_clear_cpu_buffers();
        asm volatile("hlt": : :"memory");
 }
 
index c79abe7ca093cf3c81f4de1938066426c8984f04..450d69a1e6fac02579a16df5f091b87807118ae2 100644 (file)
@@ -470,6 +470,7 @@ struct kvm_pmu {
        u64 global_ovf_ctrl;
        u64 counter_bitmask[2];
        u64 global_ctrl_mask;
+       u64 global_ovf_ctrl_mask;
        u64 reserved_bits;
        u8 version;
        struct kvm_pmc gp_counters[INTEL_PMC_MAX_GENERIC];
@@ -781,6 +782,9 @@ struct kvm_vcpu_arch {
 
        /* Flush the L1 Data cache for L1TF mitigation on VMENTER */
        bool l1tf_flush_l1d;
+
+       /* AMD MSRC001_0015 Hardware Configuration */
+       u64 msr_hwcr;
 };
 
 struct kvm_lpage_info {
@@ -1168,7 +1172,8 @@ struct kvm_x86_ops {
                              uint32_t guest_irq, bool set);
        void (*apicv_post_state_restore)(struct kvm_vcpu *vcpu);
 
-       int (*set_hv_timer)(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc);
+       int (*set_hv_timer)(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc,
+                           bool *expired);
        void (*cancel_hv_timer)(struct kvm_vcpu *vcpu);
 
        void (*setup_mce)(struct kvm_vcpu *vcpu);
index ed80003ce3e22255af9f4e8f5153149e09376ead..a66f6706c2dee30ef016ead0fa77dc55561a001e 100644 (file)
 #include <asm/setup.h>
 #include <linux/ftrace.h>
 
-static inline int klp_check_compiler_support(void)
-{
-#ifndef CC_USING_FENTRY
-       return 1;
-#endif
-       return 0;
-}
-
 static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
 {
        regs->ip = ip;
index 1378518cf63ffe6980df592847e8c082e6d4bebb..979ef971cc783ff7cef40a044904812d39c1e28b 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _ASM_X86_MSR_INDEX_H
 #define _ASM_X86_MSR_INDEX_H
 
+#include <linux/bits.h>
+
 /*
  * CPU model specific register (MSR) numbers.
  *
 /* Intel MSRs. Some also available on other CPUs */
 
 #define MSR_IA32_SPEC_CTRL             0x00000048 /* Speculation Control */
-#define SPEC_CTRL_IBRS                 (1 << 0)   /* Indirect Branch Restricted Speculation */
+#define SPEC_CTRL_IBRS                 BIT(0)     /* Indirect Branch Restricted Speculation */
 #define SPEC_CTRL_STIBP_SHIFT          1          /* Single Thread Indirect Branch Predictor (STIBP) bit */
-#define SPEC_CTRL_STIBP                        (1 << SPEC_CTRL_STIBP_SHIFT)    /* STIBP mask */
+#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                 (1 << SPEC_CTRL_SSBD_SHIFT)     /* Speculative Store Bypass Disable */
+#define SPEC_CTRL_SSBD                 BIT(SPEC_CTRL_SSBD_SHIFT)       /* Speculative Store Bypass Disable */
 
 #define MSR_IA32_PRED_CMD              0x00000049 /* Prediction Command */
-#define PRED_CMD_IBPB                  (1 << 0)   /* Indirect Branch Prediction Barrier */
+#define PRED_CMD_IBPB                  BIT(0)     /* Indirect Branch Prediction Barrier */
 
 #define MSR_PPIN_CTL                   0x0000004e
 #define MSR_PPIN                       0x0000004f
 #define MSR_MTRRcap                    0x000000fe
 
 #define MSR_IA32_ARCH_CAPABILITIES     0x0000010a
-#define ARCH_CAP_RDCL_NO               (1 << 0)   /* Not susceptible to Meltdown */
-#define ARCH_CAP_IBRS_ALL              (1 << 1)   /* Enhanced IBRS support */
-#define ARCH_CAP_SKIP_VMENTRY_L1DFLUSH (1 << 3)   /* Skip L1D flush on vmentry */
-#define ARCH_CAP_SSB_NO                        (1 << 4)   /*
-                                                   * Not susceptible to Speculative Store Bypass
-                                                   * attack, so no Speculative Store Bypass
-                                                   * control required.
-                                                   */
+#define ARCH_CAP_RDCL_NO               BIT(0)  /* Not susceptible to Meltdown */
+#define ARCH_CAP_IBRS_ALL              BIT(1)  /* Enhanced IBRS support */
+#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
+                                                * attack, so no Speculative Store Bypass
+                                                * control required.
+                                                */
+#define ARCH_CAP_MDS_NO                        BIT(5)   /*
+                                                 * Not susceptible to
+                                                 * Microarchitectural Data
+                                                 * Sampling (MDS) vulnerabilities.
+                                                 */
 
 #define MSR_IA32_FLUSH_CMD             0x0000010b
-#define L1D_FLUSH                      (1 << 0)   /*
-                                                   * Writeback and invalidate the
-                                                   * L1 data cache.
-                                                   */
+#define L1D_FLUSH                      BIT(0)  /*
+                                                * Writeback and invalidate the
+                                                * L1 data cache.
+                                                */
 
 #define MSR_IA32_BBL_CR_CTL            0x00000119
 #define MSR_IA32_BBL_CR_CTL3           0x0000011e
 #define MSR_CORE_PERF_GLOBAL_CTRL      0x0000038f
 #define MSR_CORE_PERF_GLOBAL_OVF_CTRL  0x00000390
 
+/* PERF_GLOBAL_OVF_CTL bits */
+#define MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI_BIT       55
+#define MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI           (1ULL << MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI_BIT)
+#define MSR_CORE_PERF_GLOBAL_OVF_CTRL_OVF_BUF_BIT              62
+#define MSR_CORE_PERF_GLOBAL_OVF_CTRL_OVF_BUF                  (1ULL <<  MSR_CORE_PERF_GLOBAL_OVF_CTRL_OVF_BUF_BIT)
+#define MSR_CORE_PERF_GLOBAL_OVF_CTRL_COND_CHGD_BIT            63
+#define MSR_CORE_PERF_GLOBAL_OVF_CTRL_COND_CHGD                        (1ULL << MSR_CORE_PERF_GLOBAL_OVF_CTRL_COND_CHGD_BIT)
+
 /* Geode defined MSRs */
 #define MSR_GEODE_BUSCONT_CONF0                0x00001900
 
index 39a2fb29378a6fa1e10d5ad1a0305bfa471bc4c1..eb0f80ce8524d415884d11ecbe555e6a778edfa5 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/sched/idle.h>
 
 #include <asm/cpufeature.h>
+#include <asm/nospec-branch.h>
 
 #define MWAIT_SUBSTATE_MASK            0xf
 #define MWAIT_CSTATE_MASK              0xf
@@ -40,6 +41,8 @@ static inline void __monitorx(const void *eax, unsigned long ecx,
 
 static inline void __mwait(unsigned long eax, unsigned long ecx)
 {
+       mds_idle_clear_cpu_buffers();
+
        /* "mwait %eax, %ecx;" */
        asm volatile(".byte 0x0f, 0x01, 0xc9;"
                     :: "a" (eax), "c" (ecx));
@@ -74,6 +77,8 @@ static inline void __mwait(unsigned long eax, unsigned long ecx)
 static inline void __mwaitx(unsigned long eax, unsigned long ebx,
                            unsigned long ecx)
 {
+       /* No MDS buffer clear as this is AMD/HYGON only */
+
        /* "mwaitx %eax, %ebx, %ecx;" */
        asm volatile(".byte 0x0f, 0x01, 0xfb;"
                     :: "a" (eax), "b" (ebx), "c" (ecx));
@@ -81,6 +86,8 @@ static inline void __mwaitx(unsigned long eax, unsigned long ebx,
 
 static inline void __sti_mwait(unsigned long eax, unsigned long ecx)
 {
+       mds_idle_clear_cpu_buffers();
+
        trace_hardirqs_on();
        /* "mwait %eax, %ecx;" */
        asm volatile("sti; .byte 0x0f, 0x01, 0xc9;"
index daf25b60c9e3a5ff6b83ee80028689b6449e85d2..109f974f983532041ab48e020e1fda9d5539f8f5 100644 (file)
@@ -308,6 +308,56 @@ DECLARE_STATIC_KEY_FALSE(switch_to_cond_stibp);
 DECLARE_STATIC_KEY_FALSE(switch_mm_cond_ibpb);
 DECLARE_STATIC_KEY_FALSE(switch_mm_always_ibpb);
 
+DECLARE_STATIC_KEY_FALSE(mds_user_clear);
+DECLARE_STATIC_KEY_FALSE(mds_idle_clear);
+
+#include <asm/segment.h>
+
+/**
+ * mds_clear_cpu_buffers - Mitigation for MDS vulnerability
+ *
+ * This uses the otherwise unused and obsolete VERW instruction in
+ * combination with microcode which triggers a CPU buffer flush when the
+ * instruction is executed.
+ */
+static inline void mds_clear_cpu_buffers(void)
+{
+       static const u16 ds = __KERNEL_DS;
+
+       /*
+        * Has to be the memory-operand variant because only that
+        * guarantees the CPU buffer flush functionality according to
+        * documentation. The register-operand variant does not.
+        * Works with any segment selector, but a valid writable
+        * data segment is the fastest variant.
+        *
+        * "cc" clobber is required because VERW modifies ZF.
+        */
+       asm volatile("verw %[ds]" : : [ds] "m" (ds) : "cc");
+}
+
+/**
+ * mds_user_clear_cpu_buffers - Mitigation for MDS vulnerability
+ *
+ * Clear CPU buffers if the corresponding static key is enabled
+ */
+static inline void mds_user_clear_cpu_buffers(void)
+{
+       if (static_branch_likely(&mds_user_clear))
+               mds_clear_cpu_buffers();
+}
+
+/**
+ * mds_idle_clear_cpu_buffers - Mitigation for MDS vulnerability
+ *
+ * Clear CPU buffers if the corresponding static key is enabled
+ */
+static inline void mds_idle_clear_cpu_buffers(void)
+{
+       if (static_branch_likely(&mds_idle_clear))
+               mds_clear_cpu_buffers();
+}
+
 #endif /* __ASSEMBLY__ */
 
 /*
index 7e99ef67bff08301d5d43097421e6ffe10ee7d16..c34a35c786185c3161aa7defa1c1714feacd43de 100644 (file)
@@ -978,4 +978,10 @@ enum l1tf_mitigations {
 
 extern enum l1tf_mitigations l1tf_mitigation;
 
+enum mds_mitigations {
+       MDS_MITIGATION_OFF,
+       MDS_MITIGATION_FULL,
+       MDS_MITIGATION_VMWERV,
+};
+
 #endif /* _ASM_X86_PROCESSOR_H */
index c90678fd391a45d8f48453f48b66fa95b73b89d7..880b5515b1d6f4b4e1cba06bf07a4a506de76ca9 100644 (file)
@@ -42,4 +42,34 @@ extern int after_bootmem;
 extern __ro_after_init struct mm_struct *poking_mm;
 extern __ro_after_init unsigned long poking_addr;
 
+#ifndef CONFIG_UML_X86
+static inline void int3_emulate_jmp(struct pt_regs *regs, unsigned long ip)
+{
+       regs->ip = ip;
+}
+
+#define INT3_INSN_SIZE 1
+#define CALL_INSN_SIZE 5
+
+#ifdef CONFIG_X86_64
+static inline void int3_emulate_push(struct pt_regs *regs, unsigned long val)
+{
+       /*
+        * The int3 handler in entry_64.S adds a gap between the
+        * stack where the break point happened, and the saving of
+        * pt_regs. We can extend the original stack because of
+        * this gap. See the idtentry macro's create_gap option.
+        */
+       regs->sp -= sizeof(unsigned long);
+       *(unsigned long *)regs->sp = val;
+}
+
+static inline void int3_emulate_call(struct pt_regs *regs, unsigned long func)
+{
+       int3_emulate_push(regs, regs->ip - INT3_INSN_SIZE + CALL_INSN_SIZE);
+       int3_emulate_jmp(regs, func);
+}
+#endif /* CONFIG_X86_64 */
+#endif /* !CONFIG_UML_X86 */
+
 #endif /* _ASM_X86_TEXT_PATCHING_H */
index 27566e57e87d999c386d3ade383045e921747d6f..230474e2ddb5b3eb687cdd647a15f750a65e5f32 100644 (file)
@@ -19,7 +19,6 @@ struct vdso_image {
        long sym_vvar_start;  /* Negative offset to the vvar area */
 
        long sym_vvar_page;
-       long sym_hpet_page;
        long sym_pvclock_page;
        long sym_hvclock_page;
        long sym_VDSO32_NOTE_MASK;
index 29630393f300733a7a750f3a4eec24091a3e958a..03b4cc0ec3a767267ade9e1cdcdc39382785a913 100644 (file)
@@ -37,6 +37,7 @@
 static void __init spectre_v2_select_mitigation(void);
 static void __init ssb_select_mitigation(void);
 static void __init l1tf_select_mitigation(void);
+static void __init mds_select_mitigation(void);
 
 /* The base value of the SPEC_CTRL MSR that always has to be preserved. */
 u64 x86_spec_ctrl_base;
@@ -63,6 +64,13 @@ DEFINE_STATIC_KEY_FALSE(switch_mm_cond_ibpb);
 /* Control unconditional IBPB in switch_mm() */
 DEFINE_STATIC_KEY_FALSE(switch_mm_always_ibpb);
 
+/* Control MDS CPU buffer clear before returning to user space */
+DEFINE_STATIC_KEY_FALSE(mds_user_clear);
+EXPORT_SYMBOL_GPL(mds_user_clear);
+/* Control MDS CPU buffer clear before idling (halt, mwait) */
+DEFINE_STATIC_KEY_FALSE(mds_idle_clear);
+EXPORT_SYMBOL_GPL(mds_idle_clear);
+
 void __init check_bugs(void)
 {
        identify_boot_cpu();
@@ -101,6 +109,10 @@ void __init check_bugs(void)
 
        l1tf_select_mitigation();
 
+       mds_select_mitigation();
+
+       arch_smt_update();
+
 #ifdef CONFIG_X86_32
        /*
         * Check whether we are able to run this kernel safely on SMP.
@@ -206,6 +218,61 @@ static void x86_amd_ssb_disable(void)
                wrmsrl(MSR_AMD64_LS_CFG, msrval);
 }
 
+#undef pr_fmt
+#define pr_fmt(fmt)    "MDS: " fmt
+
+/* Default mitigation for MDS-affected CPUs */
+static enum mds_mitigations mds_mitigation __ro_after_init = MDS_MITIGATION_FULL;
+static bool mds_nosmt __ro_after_init = false;
+
+static const char * const mds_strings[] = {
+       [MDS_MITIGATION_OFF]    = "Vulnerable",
+       [MDS_MITIGATION_FULL]   = "Mitigation: Clear CPU buffers",
+       [MDS_MITIGATION_VMWERV] = "Vulnerable: Clear CPU buffers attempted, no microcode",
+};
+
+static void __init mds_select_mitigation(void)
+{
+       if (!boot_cpu_has_bug(X86_BUG_MDS) || cpu_mitigations_off()) {
+               mds_mitigation = MDS_MITIGATION_OFF;
+               return;
+       }
+
+       if (mds_mitigation == MDS_MITIGATION_FULL) {
+               if (!boot_cpu_has(X86_FEATURE_MD_CLEAR))
+                       mds_mitigation = MDS_MITIGATION_VMWERV;
+
+               static_branch_enable(&mds_user_clear);
+
+               if (!boot_cpu_has(X86_BUG_MSBDS_ONLY) &&
+                   (mds_nosmt || cpu_mitigations_auto_nosmt()))
+                       cpu_smt_disable(false);
+       }
+
+       pr_info("%s\n", mds_strings[mds_mitigation]);
+}
+
+static int __init mds_cmdline(char *str)
+{
+       if (!boot_cpu_has_bug(X86_BUG_MDS))
+               return 0;
+
+       if (!str)
+               return -EINVAL;
+
+       if (!strcmp(str, "off"))
+               mds_mitigation = MDS_MITIGATION_OFF;
+       else if (!strcmp(str, "full"))
+               mds_mitigation = MDS_MITIGATION_FULL;
+       else if (!strcmp(str, "full,nosmt")) {
+               mds_mitigation = MDS_MITIGATION_FULL;
+               mds_nosmt = true;
+       }
+
+       return 0;
+}
+early_param("mds", mds_cmdline);
+
 #undef pr_fmt
 #define pr_fmt(fmt)     "Spectre V2 : " fmt
 
@@ -575,9 +642,6 @@ specv2_set_mode:
 
        /* Set up IBPB and STIBP depending on the general spectre V2 command */
        spectre_v2_user_select_mitigation(cmd);
-
-       /* Enable STIBP if appropriate */
-       arch_smt_update();
 }
 
 static void update_stibp_msr(void * __unused)
@@ -611,6 +675,31 @@ static void update_indir_branch_cond(void)
                static_branch_disable(&switch_to_cond_stibp);
 }
 
+#undef pr_fmt
+#define pr_fmt(fmt) fmt
+
+/* Update the static key controlling the MDS CPU buffer clear in idle */
+static void update_mds_branch_idle(void)
+{
+       /*
+        * Enable the idle clearing if SMT is active on CPUs which are
+        * affected only by MSBDS and not any other MDS variant.
+        *
+        * The other variants cannot be mitigated when SMT is enabled, so
+        * clearing the buffers on idle just to prevent the Store Buffer
+        * repartitioning leak would be a window dressing exercise.
+        */
+       if (!boot_cpu_has_bug(X86_BUG_MSBDS_ONLY))
+               return;
+
+       if (sched_smt_active())
+               static_branch_enable(&mds_idle_clear);
+       else
+               static_branch_disable(&mds_idle_clear);
+}
+
+#define MDS_MSG_SMT "MDS CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/mds.html for more details.\n"
+
 void arch_smt_update(void)
 {
        /* Enhanced IBRS implies STIBP. No update required. */
@@ -632,6 +721,17 @@ void arch_smt_update(void)
                break;
        }
 
+       switch (mds_mitigation) {
+       case MDS_MITIGATION_FULL:
+       case MDS_MITIGATION_VMWERV:
+               if (sched_smt_active() && !boot_cpu_has(X86_BUG_MSBDS_ONLY))
+                       pr_warn_once(MDS_MSG_SMT);
+               update_mds_branch_idle();
+               break;
+       case MDS_MITIGATION_OFF:
+               break;
+       }
+
        mutex_unlock(&spec_ctrl_mutex);
 }
 
@@ -1043,7 +1143,7 @@ static void __init l1tf_select_mitigation(void)
                pr_info("You may make it effective by booting the kernel with mem=%llu parameter.\n",
                                half_pa);
                pr_info("However, doing so will make a part of your RAM unusable.\n");
-               pr_info("Reading https://www.kernel.org/doc/html/latest/admin-guide/l1tf.html might help you decide.\n");
+               pr_info("Reading https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/l1tf.html might help you decide.\n");
                return;
        }
 
@@ -1076,6 +1176,7 @@ static int __init l1tf_cmdline(char *str)
 early_param("l1tf", l1tf_cmdline);
 
 #undef pr_fmt
+#define pr_fmt(fmt) fmt
 
 #ifdef CONFIG_SYSFS
 
@@ -1114,6 +1215,23 @@ static ssize_t l1tf_show_state(char *buf)
 }
 #endif
 
+static ssize_t mds_show_state(char *buf)
+{
+       if (!hypervisor_is_type(X86_HYPER_NATIVE)) {
+               return sprintf(buf, "%s; SMT Host state unknown\n",
+                              mds_strings[mds_mitigation]);
+       }
+
+       if (boot_cpu_has(X86_BUG_MSBDS_ONLY)) {
+               return sprintf(buf, "%s; SMT %s\n", mds_strings[mds_mitigation],
+                              (mds_mitigation == MDS_MITIGATION_OFF ? "vulnerable" :
+                               sched_smt_active() ? "mitigated" : "disabled"));
+       }
+
+       return sprintf(buf, "%s; SMT %s\n", mds_strings[mds_mitigation],
+                      sched_smt_active() ? "vulnerable" : "disabled");
+}
+
 static char *stibp_state(void)
 {
        if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
@@ -1180,6 +1298,10 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
                if (boot_cpu_has(X86_FEATURE_L1TF_PTEINV))
                        return l1tf_show_state(buf);
                break;
+
+       case X86_BUG_MDS:
+               return mds_show_state(buf);
+
        default:
                break;
        }
@@ -1211,4 +1333,9 @@ ssize_t cpu_show_l1tf(struct device *dev, struct device_attribute *attr, char *b
 {
        return cpu_show_common(dev, attr, buf, X86_BUG_L1TF);
 }
+
+ssize_t cpu_show_mds(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return cpu_show_common(dev, attr, buf, X86_BUG_MDS);
+}
 #endif
index 8739bdfe9bdf8b98980a9eca5e4a8def2b57f613..d7f55ad2dfb1f153fbd95ef6dca7f5d817d26e51 100644 (file)
@@ -940,61 +940,77 @@ static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
 #endif
 }
 
-static const __initconst struct x86_cpu_id cpu_no_speculation[] = {
-       { X86_VENDOR_INTEL,     6, INTEL_FAM6_ATOM_SALTWELL,    X86_FEATURE_ANY },
-       { X86_VENDOR_INTEL,     6, INTEL_FAM6_ATOM_SALTWELL_TABLET,     X86_FEATURE_ANY },
-       { X86_VENDOR_INTEL,     6, INTEL_FAM6_ATOM_BONNELL_MID, X86_FEATURE_ANY },
-       { X86_VENDOR_INTEL,     6, INTEL_FAM6_ATOM_SALTWELL_MID,        X86_FEATURE_ANY },
-       { X86_VENDOR_INTEL,     6, INTEL_FAM6_ATOM_BONNELL,     X86_FEATURE_ANY },
-       { X86_VENDOR_CENTAUR,   5 },
-       { X86_VENDOR_INTEL,     5 },
-       { X86_VENDOR_NSC,       5 },
-       { X86_VENDOR_ANY,       4 },
+#define NO_SPECULATION BIT(0)
+#define NO_MELTDOWN    BIT(1)
+#define NO_SSB         BIT(2)
+#define NO_L1TF                BIT(3)
+#define NO_MDS         BIT(4)
+#define MSBDS_ONLY     BIT(5)
+
+#define VULNWL(_vendor, _family, _model, _whitelist)   \
+       { X86_VENDOR_##_vendor, _family, _model, X86_FEATURE_ANY, _whitelist }
+
+#define VULNWL_INTEL(model, whitelist)         \
+       VULNWL(INTEL, 6, INTEL_FAM6_##model, whitelist)
+
+#define VULNWL_AMD(family, whitelist)          \
+       VULNWL(AMD, family, X86_MODEL_ANY, whitelist)
+
+#define VULNWL_HYGON(family, whitelist)                \
+       VULNWL(HYGON, family, X86_MODEL_ANY, whitelist)
+
+static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
+       VULNWL(ANY,     4, X86_MODEL_ANY,       NO_SPECULATION),
+       VULNWL(CENTAUR, 5, X86_MODEL_ANY,       NO_SPECULATION),
+       VULNWL(INTEL,   5, X86_MODEL_ANY,       NO_SPECULATION),
+       VULNWL(NSC,     5, X86_MODEL_ANY,       NO_SPECULATION),
+
+       /* Intel Family 6 */
+       VULNWL_INTEL(ATOM_SALTWELL,             NO_SPECULATION),
+       VULNWL_INTEL(ATOM_SALTWELL_TABLET,      NO_SPECULATION),
+       VULNWL_INTEL(ATOM_SALTWELL_MID,         NO_SPECULATION),
+       VULNWL_INTEL(ATOM_BONNELL,              NO_SPECULATION),
+       VULNWL_INTEL(ATOM_BONNELL_MID,          NO_SPECULATION),
+
+       VULNWL_INTEL(ATOM_SILVERMONT,           NO_SSB | NO_L1TF | MSBDS_ONLY),
+       VULNWL_INTEL(ATOM_SILVERMONT_X,         NO_SSB | NO_L1TF | MSBDS_ONLY),
+       VULNWL_INTEL(ATOM_SILVERMONT_MID,       NO_SSB | NO_L1TF | MSBDS_ONLY),
+       VULNWL_INTEL(ATOM_AIRMONT,              NO_SSB | NO_L1TF | MSBDS_ONLY),
+       VULNWL_INTEL(XEON_PHI_KNL,              NO_SSB | NO_L1TF | MSBDS_ONLY),
+       VULNWL_INTEL(XEON_PHI_KNM,              NO_SSB | NO_L1TF | MSBDS_ONLY),
+
+       VULNWL_INTEL(CORE_YONAH,                NO_SSB),
+
+       VULNWL_INTEL(ATOM_AIRMONT_MID,          NO_L1TF | MSBDS_ONLY),
+
+       VULNWL_INTEL(ATOM_GOLDMONT,             NO_MDS | NO_L1TF),
+       VULNWL_INTEL(ATOM_GOLDMONT_X,           NO_MDS | NO_L1TF),
+       VULNWL_INTEL(ATOM_GOLDMONT_PLUS,        NO_MDS | NO_L1TF),
+
+       /* AMD Family 0xf - 0x12 */
+       VULNWL_AMD(0x0f,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
+       VULNWL_AMD(0x10,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
+       VULNWL_AMD(0x11,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
+       VULNWL_AMD(0x12,        NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
+
+       /* FAMILY_ANY must be last, otherwise 0x0f - 0x12 matches won't work */
+       VULNWL_AMD(X86_FAMILY_ANY,      NO_MELTDOWN | NO_L1TF | NO_MDS),
+       VULNWL_HYGON(X86_FAMILY_ANY,    NO_MELTDOWN | NO_L1TF | NO_MDS),
        {}
 };
 
-static const __initconst struct x86_cpu_id cpu_no_meltdown[] = {
-       { X86_VENDOR_AMD },
-       { X86_VENDOR_HYGON },
-       {}
-};
-
-/* Only list CPUs which speculate but are non susceptible to SSB */
-static const __initconst struct x86_cpu_id cpu_no_spec_store_bypass[] = {
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_SILVERMONT      },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_AIRMONT         },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_SILVERMONT_X    },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_SILVERMONT_MID  },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_CORE_YONAH           },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_XEON_PHI_KNL         },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_XEON_PHI_KNM         },
-       { X86_VENDOR_AMD,       0x12,                                   },
-       { X86_VENDOR_AMD,       0x11,                                   },
-       { X86_VENDOR_AMD,       0x10,                                   },
-       { X86_VENDOR_AMD,       0xf,                                    },
-       {}
-};
+static bool __init cpu_matches(unsigned long which)
+{
+       const struct x86_cpu_id *m = x86_match_cpu(cpu_vuln_whitelist);
 
-static const __initconst struct x86_cpu_id cpu_no_l1tf[] = {
-       /* in addition to cpu_no_speculation */
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_SILVERMONT      },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_SILVERMONT_X    },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_AIRMONT         },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_SILVERMONT_MID  },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_AIRMONT_MID     },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_GOLDMONT        },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_GOLDMONT_X      },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_GOLDMONT_PLUS   },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_XEON_PHI_KNL         },
-       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_XEON_PHI_KNM         },
-       {}
-};
+       return m && !!(m->driver_data & which);
+}
 
 static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
 {
        u64 ia32_cap = 0;
 
-       if (x86_match_cpu(cpu_no_speculation))
+       if (cpu_matches(NO_SPECULATION))
                return;
 
        setup_force_cpu_bug(X86_BUG_SPECTRE_V1);
@@ -1003,15 +1019,20 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
        if (cpu_has(c, X86_FEATURE_ARCH_CAPABILITIES))
                rdmsrl(MSR_IA32_ARCH_CAPABILITIES, ia32_cap);
 
-       if (!x86_match_cpu(cpu_no_spec_store_bypass) &&
-          !(ia32_cap & ARCH_CAP_SSB_NO) &&
+       if (!cpu_matches(NO_SSB) && !(ia32_cap & ARCH_CAP_SSB_NO) &&
           !cpu_has(c, X86_FEATURE_AMD_SSB_NO))
                setup_force_cpu_bug(X86_BUG_SPEC_STORE_BYPASS);
 
        if (ia32_cap & ARCH_CAP_IBRS_ALL)
                setup_force_cpu_cap(X86_FEATURE_IBRS_ENHANCED);
 
-       if (x86_match_cpu(cpu_no_meltdown))
+       if (!cpu_matches(NO_MDS) && !(ia32_cap & ARCH_CAP_MDS_NO)) {
+               setup_force_cpu_bug(X86_BUG_MDS);
+               if (cpu_matches(MSBDS_ONLY))
+                       setup_force_cpu_bug(X86_BUG_MSBDS_ONLY);
+       }
+
+       if (cpu_matches(NO_MELTDOWN))
                return;
 
        /* Rogue Data Cache Load? No! */
@@ -1020,7 +1041,7 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
 
        setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN);
 
-       if (x86_match_cpu(cpu_no_l1tf))
+       if (cpu_matches(NO_L1TF))
                return;
 
        setup_force_cpu_bug(X86_BUG_L1TF);
index f4dd73396f2882b2780e36e1f0bc88b42722f417..ebb14a26f117cfe68c6984042eba1af9ac32baaa 100644 (file)
@@ -97,6 +97,7 @@ static void intel_epb_restore(void)
        wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, (epb & ~EPB_MASK) | val);
 }
 
+#ifdef CONFIG_PM
 static struct syscore_ops intel_epb_syscore_ops = {
        .suspend = intel_epb_save,
        .resume = intel_epb_restore,
@@ -193,6 +194,25 @@ static int intel_epb_offline(unsigned int cpu)
        return 0;
 }
 
+static inline void register_intel_ebp_syscore_ops(void)
+{
+       register_syscore_ops(&intel_epb_syscore_ops);
+}
+#else /* !CONFIG_PM */
+static int intel_epb_online(unsigned int cpu)
+{
+       intel_epb_restore();
+       return 0;
+}
+
+static int intel_epb_offline(unsigned int cpu)
+{
+       return intel_epb_save();
+}
+
+static inline void register_intel_ebp_syscore_ops(void) {}
+#endif
+
 static __init int intel_epb_init(void)
 {
        int ret;
@@ -206,7 +226,7 @@ static __init int intel_epb_init(void)
        if (ret < 0)
                goto err_out_online;
 
-       register_syscore_ops(&intel_epb_syscore_ops);
+       register_intel_ebp_syscore_ops();
        return 0;
 
 err_out_online:
index 2879e234e1936f76e59383d56ee5c26b58ce6b53..76dd605ee2a38f78137c1f94c66d9e4f1d0d9171 100644 (file)
@@ -73,12 +73,13 @@ EXPORT_SYMBOL(pci_mem_start);
  * This function checks if any part of the range <start,end> is mapped
  * with type.
  */
-bool e820__mapped_any(u64 start, u64 end, enum e820_type type)
+static bool _e820__mapped_any(struct e820_table *table,
+                             u64 start, u64 end, enum e820_type type)
 {
        int i;
 
-       for (i = 0; i < e820_table->nr_entries; i++) {
-               struct e820_entry *entry = &e820_table->entries[i];
+       for (i = 0; i < table->nr_entries; i++) {
+               struct e820_entry *entry = &table->entries[i];
 
                if (type && entry->type != type)
                        continue;
@@ -88,6 +89,17 @@ bool e820__mapped_any(u64 start, u64 end, enum e820_type type)
        }
        return 0;
 }
+
+bool e820__mapped_raw_any(u64 start, u64 end, enum e820_type type)
+{
+       return _e820__mapped_any(e820_table_firmware, start, end, type);
+}
+EXPORT_SYMBOL_GPL(e820__mapped_raw_any);
+
+bool e820__mapped_any(u64 start, u64 end, enum e820_type type)
+{
+       return _e820__mapped_any(e820_table, start, end, type);
+}
 EXPORT_SYMBOL_GPL(e820__mapped_any);
 
 /*
index 0caf8122d68078a1c712aa0dbdf77d7b7eb1c780..0927bb158ffca103c586f0a9a2c7838e4701288b 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/kprobes.h>
 #include <asm/ftrace.h>
 #include <asm/nops.h>
+#include <asm/text-patching.h>
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 
@@ -231,6 +232,7 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
 }
 
 static unsigned long ftrace_update_func;
+static unsigned long ftrace_update_func_call;
 
 static int update_ftrace_func(unsigned long ip, void *new)
 {
@@ -259,6 +261,8 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
        unsigned char *new;
        int ret;
 
+       ftrace_update_func_call = (unsigned long)func;
+
        new = ftrace_call_replace(ip, (unsigned long)func);
        ret = update_ftrace_func(ip, new);
 
@@ -294,13 +298,28 @@ int ftrace_int3_handler(struct pt_regs *regs)
        if (WARN_ON_ONCE(!regs))
                return 0;
 
-       ip = regs->ip - 1;
-       if (!ftrace_location(ip) && !is_ftrace_caller(ip))
-               return 0;
+       ip = regs->ip - INT3_INSN_SIZE;
 
-       regs->ip += MCOUNT_INSN_SIZE - 1;
+#ifdef CONFIG_X86_64
+       if (ftrace_location(ip)) {
+               int3_emulate_call(regs, (unsigned long)ftrace_regs_caller);
+               return 1;
+       } else if (is_ftrace_caller(ip)) {
+               if (!ftrace_update_func_call) {
+                       int3_emulate_jmp(regs, ip + CALL_INSN_SIZE);
+                       return 1;
+               }
+               int3_emulate_call(regs, ftrace_update_func_call);
+               return 1;
+       }
+#else
+       if (ftrace_location(ip) || is_ftrace_caller(ip)) {
+               int3_emulate_jmp(regs, ip + CALL_INSN_SIZE);
+               return 1;
+       }
+#endif
 
-       return 1;
+       return 0;
 }
 NOKPROBE_SYMBOL(ftrace_int3_handler);
 
@@ -865,6 +884,8 @@ void arch_ftrace_update_trampoline(struct ftrace_ops *ops)
 
        func = ftrace_ops_get_func(ops);
 
+       ftrace_update_func_call = (unsigned long)func;
+
        /* Do a safe modify in case the trampoline is executing */
        new = ftrace_call_replace(ip, (unsigned long)func);
        ret = update_ftrace_func(ip, new);
@@ -966,6 +987,7 @@ static int ftrace_mod_jmp(unsigned long ip, void *func)
 {
        unsigned char *new;
 
+       ftrace_update_func_call = 0UL;
        new = ftrace_jmp_replace(ip, (unsigned long)func);
 
        return update_ftrace_func(ip, new);
index 4c8440de33559942a98245cf123a5ed10a30e406..2ba914a34b066995feb4253188fde1f3313a0959 100644 (file)
 #include <asm/ftrace.h>
 #include <asm/nospec-branch.h>
 
-#ifdef CC_USING_FENTRY
 # define function_hook __fentry__
 EXPORT_SYMBOL(__fentry__)
-#else
-# define function_hook mcount
-EXPORT_SYMBOL(mcount)
-#endif
-
-#ifdef CONFIG_DYNAMIC_FTRACE
-
-/* mcount uses a frame pointer even if CONFIG_FRAME_POINTER is not set */
-#if !defined(CC_USING_FENTRY) || defined(CONFIG_FRAME_POINTER)
-# define USING_FRAME_POINTER
-#endif
 
-#ifdef USING_FRAME_POINTER
+#ifdef CONFIG_FRAME_POINTER
 # define MCOUNT_FRAME                  1       /* using frame = true  */
 #else
 # define MCOUNT_FRAME                  0       /* using frame = false */
@@ -37,8 +25,7 @@ END(function_hook)
 
 ENTRY(ftrace_caller)
 
-#ifdef USING_FRAME_POINTER
-# ifdef CC_USING_FENTRY
+#ifdef CONFIG_FRAME_POINTER
        /*
         * Frame pointers are of ip followed by bp.
         * Since fentry is an immediate jump, we are left with
@@ -49,7 +36,7 @@ ENTRY(ftrace_caller)
        pushl   %ebp
        movl    %esp, %ebp
        pushl   2*4(%esp)                       /* function ip */
-# endif
+
        /* For mcount, the function ip is directly above */
        pushl   %ebp
        movl    %esp, %ebp
@@ -59,7 +46,7 @@ ENTRY(ftrace_caller)
        pushl   %edx
        pushl   $0                              /* Pass NULL as regs pointer */
 
-#ifdef USING_FRAME_POINTER
+#ifdef CONFIG_FRAME_POINTER
        /* Load parent ebp into edx */
        movl    4*4(%esp), %edx
 #else
@@ -82,13 +69,11 @@ ftrace_call:
        popl    %edx
        popl    %ecx
        popl    %eax
-#ifdef USING_FRAME_POINTER
+#ifdef CONFIG_FRAME_POINTER
        popl    %ebp
-# ifdef CC_USING_FENTRY
        addl    $4,%esp                         /* skip function ip */
        popl    %ebp                            /* this is the orig bp */
        addl    $4, %esp                        /* skip parent ip */
-# endif
 #endif
 .Lftrace_ret:
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
@@ -133,11 +118,7 @@ ENTRY(ftrace_regs_caller)
 
        movl    12*4(%esp), %eax                /* Load ip (1st parameter) */
        subl    $MCOUNT_INSN_SIZE, %eax         /* Adjust ip */
-#ifdef CC_USING_FENTRY
        movl    15*4(%esp), %edx                /* Load parent ip (2nd parameter) */
-#else
-       movl    0x4(%ebp), %edx                 /* Load parent ip (2nd parameter) */
-#endif
        movl    function_trace_op, %ecx         /* Save ftrace_pos in 3rd parameter */
        pushl   %esp                            /* Save pt_regs as 4th parameter */
 
@@ -170,43 +151,6 @@ GLOBAL(ftrace_regs_call)
        lea     3*4(%esp), %esp                 /* Skip orig_ax, ip and cs */
 
        jmp     .Lftrace_ret
-#else /* ! CONFIG_DYNAMIC_FTRACE */
-
-ENTRY(function_hook)
-       cmpl    $__PAGE_OFFSET, %esp
-       jb      ftrace_stub                     /* Paging not enabled yet? */
-
-       cmpl    $ftrace_stub, ftrace_trace_function
-       jnz     .Ltrace
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-       cmpl    $ftrace_stub, ftrace_graph_return
-       jnz     ftrace_graph_caller
-
-       cmpl    $ftrace_graph_entry_stub, ftrace_graph_entry
-       jnz     ftrace_graph_caller
-#endif
-.globl ftrace_stub
-ftrace_stub:
-       ret
-
-       /* taken from glibc */
-.Ltrace:
-       pushl   %eax
-       pushl   %ecx
-       pushl   %edx
-       movl    0xc(%esp), %eax
-       movl    0x4(%ebp), %edx
-       subl    $MCOUNT_INSN_SIZE, %eax
-
-       movl    ftrace_trace_function, %ecx
-       CALL_NOSPEC %ecx
-
-       popl    %edx
-       popl    %ecx
-       popl    %eax
-       jmp     ftrace_stub
-END(function_hook)
-#endif /* CONFIG_DYNAMIC_FTRACE */
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 ENTRY(ftrace_graph_caller)
@@ -215,13 +159,8 @@ ENTRY(ftrace_graph_caller)
        pushl   %edx
        movl    3*4(%esp), %eax
        /* Even with frame pointers, fentry doesn't have one here */
-#ifdef CC_USING_FENTRY
        lea     4*4(%esp), %edx
        movl    $0, %ecx
-#else
-       lea     0x4(%ebp), %edx
-       movl    (%ebp), %ecx
-#endif
        subl    $MCOUNT_INSN_SIZE, %eax
        call    prepare_ftrace_return
        popl    %edx
@@ -234,11 +173,7 @@ END(ftrace_graph_caller)
 return_to_handler:
        pushl   %eax
        pushl   %edx
-#ifdef CC_USING_FENTRY
        movl    $0, %eax
-#else
-       movl    %ebp, %eax
-#endif
        call    ftrace_return_to_handler
        movl    %eax, %ecx
        popl    %edx
index 75f2b36b41a6956814a82be59c2665798d23fbb4..10eb2760ef2c416cb5830e9e9f7f406c51790977 100644 (file)
        .code64
        .section .entry.text, "ax"
 
-#ifdef CC_USING_FENTRY
 # define function_hook __fentry__
 EXPORT_SYMBOL(__fentry__)
-#else
-# define function_hook mcount
-EXPORT_SYMBOL(mcount)
-#endif
 
 #ifdef CONFIG_FRAME_POINTER
-# ifdef CC_USING_FENTRY
 /* Save parent and function stack frames (rip and rbp) */
 #  define MCOUNT_FRAME_SIZE    (8+16*2)
-# else
-/* Save just function stack frame (rip and rbp) */
-#  define MCOUNT_FRAME_SIZE    (8+16)
-# endif
 #else
 /* No need to save a stack frame */
 # define MCOUNT_FRAME_SIZE     0
@@ -75,17 +65,13 @@ EXPORT_SYMBOL(mcount)
         * fentry is called before the stack frame is set up, where as mcount
         * is called afterward.
         */
-#ifdef CC_USING_FENTRY
+
        /* Save the parent pointer (skip orig rbp and our return address) */
        pushq \added+8*2(%rsp)
        pushq %rbp
        movq %rsp, %rbp
        /* Save the return address (now skip orig rbp, rbp and parent) */
        pushq \added+8*3(%rsp)
-#else
-       /* Can't assume that rip is before this (unless added was zero) */
-       pushq \added+8(%rsp)
-#endif
        pushq %rbp
        movq %rsp, %rbp
 #endif /* CONFIG_FRAME_POINTER */
@@ -113,12 +99,7 @@ EXPORT_SYMBOL(mcount)
        movq %rdx, RBP(%rsp)
 
        /* Copy the parent address into %rsi (second parameter) */
-#ifdef CC_USING_FENTRY
        movq MCOUNT_REG_SIZE+8+\added(%rsp), %rsi
-#else
-       /* %rdx contains original %rbp */
-       movq 8(%rdx), %rsi
-#endif
 
         /* Move RIP to its proper location */
        movq MCOUNT_REG_SIZE+\added(%rsp), %rdi
@@ -303,15 +284,8 @@ ENTRY(ftrace_graph_caller)
        /* Saves rbp into %rdx and fills first parameter  */
        save_mcount_regs
 
-#ifdef CC_USING_FENTRY
        leaq MCOUNT_REG_SIZE+8(%rsp), %rsi
        movq $0, %rdx   /* No framepointers needed */
-#else
-       /* Save address of the return address of traced function */
-       leaq 8(%rdx), %rsi
-       /* ftrace does sanity checks against frame pointers */
-       movq (%rdx), %rdx
-#endif
        call    prepare_ftrace_return
 
        restore_mcount_regs
index cf52ee0d87111c13e0eef8a2429db889ed585962..9e4fa2484d10dd276d4804017466d7b191c07b12 100644 (file)
@@ -768,7 +768,7 @@ static struct kprobe kretprobe_kprobe = {
 /*
  * Called from kretprobe_trampoline
  */
-static __used void *trampoline_handler(struct pt_regs *regs)
+__used __visible void *trampoline_handler(struct pt_regs *regs)
 {
        struct kprobe_ctlblk *kcb;
        struct kretprobe_instance *ri = NULL;
index 3755d0310026aab7d8496afe2efb57b7e9f747bb..05b09896cfafa23ab2706be52920df6178acf4c5 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/x86_init.h>
 #include <asm/reboot.h>
 #include <asm/cache.h>
+#include <asm/nospec-branch.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/nmi.h>
@@ -551,6 +552,9 @@ nmi_restart:
                write_cr2(this_cpu_read(nmi_cr2));
        if (this_cpu_dec_return(nmi_state))
                goto nmi_restart;
+
+       if (user_mode(regs))
+               mds_user_clear_cpu_buffers();
 }
 NOKPROBE_SYMBOL(do_nmi);
 
index 15b5e98a86f996dd7e8635d05b49e83e03be6179..356dfc555a27ff14015eb0d88614383b100a8efc 100644 (file)
@@ -979,7 +979,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
                if (!(freq->flags & CPUFREQ_CONST_LOOPS))
                        mark_tsc_unstable("cpufreq changes");
 
-               set_cyc2ns_scale(tsc_khz, freq->cpu, rdtsc());
+               set_cyc2ns_scale(tsc_khz, freq->policy->cpu, rdtsc());
        }
 
        return 0;
index fd3951638ae45aebcc2c9ecaa0ee5e100b41e741..80a642a0143d7ba98c4cd92fcc42f282ddea0dbe 100644 (file)
@@ -410,7 +410,8 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        /* cpuid 7.0.edx*/
        const u32 kvm_cpuid_7_0_edx_x86_features =
                F(AVX512_4VNNIW) | F(AVX512_4FMAPS) | F(SPEC_CTRL) |
-               F(SPEC_CTRL_SSBD) | F(ARCH_CAPABILITIES) | F(INTEL_STIBP);
+               F(SPEC_CTRL_SSBD) | F(ARCH_CAPABILITIES) | F(INTEL_STIBP) |
+               F(MD_CLEAR);
 
        /* all calls to cpuid_count() should be made on the same cpu */
        get_cpu();
@@ -962,13 +963,13 @@ int kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
        if (cpuid_fault_enabled(vcpu) && !kvm_require_cpl(vcpu, 0))
                return 1;
 
-       eax = kvm_register_read(vcpu, VCPU_REGS_RAX);
-       ecx = kvm_register_read(vcpu, VCPU_REGS_RCX);
+       eax = kvm_rax_read(vcpu);
+       ecx = kvm_rcx_read(vcpu);
        kvm_cpuid(vcpu, &eax, &ebx, &ecx, &edx, true);
-       kvm_register_write(vcpu, VCPU_REGS_RAX, eax);
-       kvm_register_write(vcpu, VCPU_REGS_RBX, ebx);
-       kvm_register_write(vcpu, VCPU_REGS_RCX, ecx);
-       kvm_register_write(vcpu, VCPU_REGS_RDX, edx);
+       kvm_rax_write(vcpu, eax);
+       kvm_rbx_write(vcpu, ebx);
+       kvm_rcx_write(vcpu, ecx);
+       kvm_rdx_write(vcpu, edx);
        return kvm_skip_emulated_instruction(vcpu);
 }
 EXPORT_SYMBOL_GPL(kvm_emulate_cpuid);
index cc24b3a32c449d01bda073f3bb5a5f5e245440a4..8ca4b39918e090ac425b9ce114944013d72a94fe 100644 (file)
@@ -1535,10 +1535,10 @@ static void kvm_hv_hypercall_set_result(struct kvm_vcpu *vcpu, u64 result)
 
        longmode = is_64_bit_mode(vcpu);
        if (longmode)
-               kvm_register_write(vcpu, VCPU_REGS_RAX, result);
+               kvm_rax_write(vcpu, result);
        else {
-               kvm_register_write(vcpu, VCPU_REGS_RDX, result >> 32);
-               kvm_register_write(vcpu, VCPU_REGS_RAX, result & 0xffffffff);
+               kvm_rdx_write(vcpu, result >> 32);
+               kvm_rax_write(vcpu, result & 0xffffffff);
        }
 }
 
@@ -1611,18 +1611,18 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
        longmode = is_64_bit_mode(vcpu);
 
        if (!longmode) {
-               param = ((u64)kvm_register_read(vcpu, VCPU_REGS_RDX) << 32) |
-                       (kvm_register_read(vcpu, VCPU_REGS_RAX) & 0xffffffff);
-               ingpa = ((u64)kvm_register_read(vcpu, VCPU_REGS_RBX) << 32) |
-                       (kvm_register_read(vcpu, VCPU_REGS_RCX) & 0xffffffff);
-               outgpa = ((u64)kvm_register_read(vcpu, VCPU_REGS_RDI) << 32) |
-                       (kvm_register_read(vcpu, VCPU_REGS_RSI) & 0xffffffff);
+               param = ((u64)kvm_rdx_read(vcpu) << 32) |
+                       (kvm_rax_read(vcpu) & 0xffffffff);
+               ingpa = ((u64)kvm_rbx_read(vcpu) << 32) |
+                       (kvm_rcx_read(vcpu) & 0xffffffff);
+               outgpa = ((u64)kvm_rdi_read(vcpu) << 32) |
+                       (kvm_rsi_read(vcpu) & 0xffffffff);
        }
 #ifdef CONFIG_X86_64
        else {
-               param = kvm_register_read(vcpu, VCPU_REGS_RCX);
-               ingpa = kvm_register_read(vcpu, VCPU_REGS_RDX);
-               outgpa = kvm_register_read(vcpu, VCPU_REGS_R8);
+               param = kvm_rcx_read(vcpu);
+               ingpa = kvm_rdx_read(vcpu);
+               outgpa = kvm_r8_read(vcpu);
        }
 #endif
 
index f8f56a93358ba0d53b3fa509f6129911c518810e..1cc6c47dc77e4856c59323be2904214cfbd967f9 100644 (file)
@@ -9,6 +9,34 @@
        (X86_CR4_PVI | X86_CR4_DE | X86_CR4_PCE | X86_CR4_OSFXSR  \
         | X86_CR4_OSXMMEXCPT | X86_CR4_LA57 | X86_CR4_PGE)
 
+#define BUILD_KVM_GPR_ACCESSORS(lname, uname)                                \
+static __always_inline unsigned long kvm_##lname##_read(struct kvm_vcpu *vcpu)\
+{                                                                            \
+       return vcpu->arch.regs[VCPU_REGS_##uname];                            \
+}                                                                            \
+static __always_inline void kvm_##lname##_write(struct kvm_vcpu *vcpu,       \
+                                               unsigned long val)            \
+{                                                                            \
+       vcpu->arch.regs[VCPU_REGS_##uname] = val;                             \
+}
+BUILD_KVM_GPR_ACCESSORS(rax, RAX)
+BUILD_KVM_GPR_ACCESSORS(rbx, RBX)
+BUILD_KVM_GPR_ACCESSORS(rcx, RCX)
+BUILD_KVM_GPR_ACCESSORS(rdx, RDX)
+BUILD_KVM_GPR_ACCESSORS(rbp, RBP)
+BUILD_KVM_GPR_ACCESSORS(rsi, RSI)
+BUILD_KVM_GPR_ACCESSORS(rdi, RDI)
+#ifdef CONFIG_X86_64
+BUILD_KVM_GPR_ACCESSORS(r8,  R8)
+BUILD_KVM_GPR_ACCESSORS(r9,  R9)
+BUILD_KVM_GPR_ACCESSORS(r10, R10)
+BUILD_KVM_GPR_ACCESSORS(r11, R11)
+BUILD_KVM_GPR_ACCESSORS(r12, R12)
+BUILD_KVM_GPR_ACCESSORS(r13, R13)
+BUILD_KVM_GPR_ACCESSORS(r14, R14)
+BUILD_KVM_GPR_ACCESSORS(r15, R15)
+#endif
+
 static inline unsigned long kvm_register_read(struct kvm_vcpu *vcpu,
                                              enum kvm_reg reg)
 {
@@ -37,6 +65,16 @@ static inline void kvm_rip_write(struct kvm_vcpu *vcpu, unsigned long val)
        kvm_register_write(vcpu, VCPU_REGS_RIP, val);
 }
 
+static inline unsigned long kvm_rsp_read(struct kvm_vcpu *vcpu)
+{
+       return kvm_register_read(vcpu, VCPU_REGS_RSP);
+}
+
+static inline void kvm_rsp_write(struct kvm_vcpu *vcpu, unsigned long val)
+{
+       kvm_register_write(vcpu, VCPU_REGS_RSP, val);
+}
+
 static inline u64 kvm_pdptr_read(struct kvm_vcpu *vcpu, int index)
 {
        might_sleep();  /* on svm */
@@ -83,8 +121,8 @@ static inline ulong kvm_read_cr4(struct kvm_vcpu *vcpu)
 
 static inline u64 kvm_read_edx_eax(struct kvm_vcpu *vcpu)
 {
-       return (kvm_register_read(vcpu, VCPU_REGS_RAX) & -1u)
-               | ((u64)(kvm_register_read(vcpu, VCPU_REGS_RDX) & -1u) << 32);
+       return (kvm_rax_read(vcpu) & -1u)
+               | ((u64)(kvm_rdx_read(vcpu) & -1u) << 32);
 }
 
 static inline void enter_guest_mode(struct kvm_vcpu *vcpu)
index bd13fdddbdc4a98782e4c94d2a6403b19e2f9956..4924f83ed4f37266ca1bd0c719fe438914e5f666 100644 (file)
@@ -1454,7 +1454,7 @@ static void apic_timer_expired(struct kvm_lapic *apic)
        if (swait_active(q))
                swake_up_one(q);
 
-       if (apic_lvtt_tscdeadline(apic))
+       if (apic_lvtt_tscdeadline(apic) || ktimer->hv_timer_in_use)
                ktimer->expired_tscdeadline = ktimer->tscdeadline;
 }
 
@@ -1696,37 +1696,42 @@ static void cancel_hv_timer(struct kvm_lapic *apic)
 static bool start_hv_timer(struct kvm_lapic *apic)
 {
        struct kvm_timer *ktimer = &apic->lapic_timer;
-       int r;
+       struct kvm_vcpu *vcpu = apic->vcpu;
+       bool expired;
 
        WARN_ON(preemptible());
        if (!kvm_x86_ops->set_hv_timer)
                return false;
 
-       if (!apic_lvtt_period(apic) && atomic_read(&ktimer->pending))
-               return false;
-
        if (!ktimer->tscdeadline)
                return false;
 
-       r = kvm_x86_ops->set_hv_timer(apic->vcpu, ktimer->tscdeadline);
-       if (r < 0)
+       if (kvm_x86_ops->set_hv_timer(vcpu, ktimer->tscdeadline, &expired))
                return false;
 
        ktimer->hv_timer_in_use = true;
        hrtimer_cancel(&ktimer->timer);
 
        /*
-        * Also recheck ktimer->pending, in case the sw timer triggered in
-        * the window.  For periodic timer, leave the hv timer running for
-        * simplicity, and the deadline will be recomputed on the next vmexit.
+        * To simplify handling the periodic timer, leave the hv timer running
+        * even if the deadline timer has expired, i.e. rely on the resulting
+        * VM-Exit to recompute the periodic timer's target expiration.
         */
-       if (!apic_lvtt_period(apic) && (r || atomic_read(&ktimer->pending))) {
-               if (r)
+       if (!apic_lvtt_period(apic)) {
+               /*
+                * Cancel the hv timer if the sw timer fired while the hv timer
+                * was being programmed, or if the hv timer itself expired.
+                */
+               if (atomic_read(&ktimer->pending)) {
+                       cancel_hv_timer(apic);
+               } else if (expired) {
                        apic_timer_expired(apic);
-               return false;
+                       cancel_hv_timer(apic);
+               }
        }
 
-       trace_kvm_hv_timer_state(apic->vcpu->vcpu_id, true);
+       trace_kvm_hv_timer_state(vcpu->vcpu_id, ktimer->hv_timer_in_use);
+
        return true;
 }
 
@@ -1750,8 +1755,13 @@ static void start_sw_timer(struct kvm_lapic *apic)
 static void restart_apic_timer(struct kvm_lapic *apic)
 {
        preempt_disable();
+
+       if (!apic_lvtt_period(apic) && atomic_read(&apic->lapic_timer.pending))
+               goto out;
+
        if (!start_hv_timer(apic))
                start_sw_timer(apic);
+out:
        preempt_enable();
 }
 
index d9c7b45d231f1582becb071ae6355fc7c63bc79c..1e9ba81accba526b80bb698b193b405c07d48c02 100644 (file)
@@ -44,6 +44,7 @@
 #include <asm/page.h>
 #include <asm/pat.h>
 #include <asm/cmpxchg.h>
+#include <asm/e820/api.h>
 #include <asm/io.h>
 #include <asm/vmx.h>
 #include <asm/kvm_page_track.h>
@@ -487,16 +488,24 @@ static void kvm_mmu_reset_all_pte_masks(void)
         * If the CPU has 46 or less physical address bits, then set an
         * appropriate mask to guard against L1TF attacks. Otherwise, it is
         * assumed that the CPU is not vulnerable to L1TF.
+        *
+        * Some Intel CPUs address the L1 cache using more PA bits than are
+        * reported by CPUID. Use the PA width of the L1 cache when possible
+        * to achieve more effective mitigation, e.g. if system RAM overlaps
+        * the most significant bits of legal physical address space.
         */
-       low_phys_bits = boot_cpu_data.x86_phys_bits;
-       if (boot_cpu_data.x86_phys_bits <
+       shadow_nonpresent_or_rsvd_mask = 0;
+       low_phys_bits = boot_cpu_data.x86_cache_bits;
+       if (boot_cpu_data.x86_cache_bits <
            52 - shadow_nonpresent_or_rsvd_mask_len) {
                shadow_nonpresent_or_rsvd_mask =
-                       rsvd_bits(boot_cpu_data.x86_phys_bits -
+                       rsvd_bits(boot_cpu_data.x86_cache_bits -
                                  shadow_nonpresent_or_rsvd_mask_len,
-                                 boot_cpu_data.x86_phys_bits - 1);
+                                 boot_cpu_data.x86_cache_bits - 1);
                low_phys_bits -= shadow_nonpresent_or_rsvd_mask_len;
-       }
+       } else
+               WARN_ON_ONCE(boot_cpu_has_bug(X86_BUG_L1TF));
+
        shadow_nonpresent_or_rsvd_lower_gfn_mask =
                GENMASK_ULL(low_phys_bits - 1, PAGE_SHIFT);
 }
@@ -2892,7 +2901,9 @@ static bool kvm_is_mmio_pfn(kvm_pfn_t pfn)
                         */
                        (!pat_enabled() || pat_pfn_immune_to_uc_mtrr(pfn));
 
-       return true;
+       return !e820__mapped_raw_any(pfn_to_hpa(pfn),
+                                    pfn_to_hpa(pfn + 1) - 1,
+                                    E820_TYPE_RAM);
 }
 
 /* Bits which may be returned by set_spte() */
index e9ea2d45ae66baa65a2e3818e7120189bcd61e57..9f72cc427158e637b1852e9843c5eddfcf78c43a 100644 (file)
@@ -48,11 +48,6 @@ static bool msr_mtrr_valid(unsigned msr)
        return false;
 }
 
-static bool valid_pat_type(unsigned t)
-{
-       return t < 8 && (1 << t) & 0xf3; /* 0, 1, 4, 5, 6, 7 */
-}
-
 static bool valid_mtrr_type(unsigned t)
 {
        return t < 8 && (1 << t) & 0x73; /* 0, 1, 4, 5, 6 */
@@ -67,10 +62,7 @@ bool kvm_mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data)
                return false;
 
        if (msr == MSR_IA32_CR_PAT) {
-               for (i = 0; i < 8; i++)
-                       if (!valid_pat_type((data >> (i * 8)) & 0xff))
-                               return false;
-               return true;
+               return kvm_pat_valid(data);
        } else if (msr == MSR_MTRRdefType) {
                if (data & ~0xcff)
                        return false;
index 6bdca39829bc8ed611800458e6dcf29d0d759830..367a47df4ba0e749406c6ce6a3598a2c6b3433ec 100644 (file)
@@ -140,16 +140,36 @@ static int FNAME(cmpxchg_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
        pt_element_t *table;
        struct page *page;
 
-       npages = get_user_pages_fast((unsigned long)ptep_user, 1, 1, &page);
-       /* Check if the user is doing something meaningless. */
-       if (unlikely(npages != 1))
-               return -EFAULT;
-
-       table = kmap_atomic(page);
-       ret = CMPXCHG(&table[index], orig_pte, new_pte);
-       kunmap_atomic(table);
-
-       kvm_release_page_dirty(page);
+       npages = get_user_pages_fast((unsigned long)ptep_user, 1, FOLL_WRITE, &page);
+       if (likely(npages == 1)) {
+               table = kmap_atomic(page);
+               ret = CMPXCHG(&table[index], orig_pte, new_pte);
+               kunmap_atomic(table);
+
+               kvm_release_page_dirty(page);
+       } else {
+               struct vm_area_struct *vma;
+               unsigned long vaddr = (unsigned long)ptep_user & PAGE_MASK;
+               unsigned long pfn;
+               unsigned long paddr;
+
+               down_read(&current->mm->mmap_sem);
+               vma = find_vma_intersection(current->mm, vaddr, vaddr + PAGE_SIZE);
+               if (!vma || !(vma->vm_flags & VM_PFNMAP)) {
+                       up_read(&current->mm->mmap_sem);
+                       return -EFAULT;
+               }
+               pfn = ((vaddr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+               paddr = pfn << PAGE_SHIFT;
+               table = memremap(paddr, PAGE_SIZE, MEMREMAP_WB);
+               if (!table) {
+                       up_read(&current->mm->mmap_sem);
+                       return -EFAULT;
+               }
+               ret = CMPXCHG(&table[index], orig_pte, new_pte);
+               memunmap(table);
+               up_read(&current->mm->mmap_sem);
+       }
 
        return (ret != orig_pte);
 }
index 406b558abfef7379eb46bd2de18e5d6890079eb9..a849dcb7fbc5c6810acba2e4b2babecf129a1510 100644 (file)
@@ -1805,7 +1805,7 @@ static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
                return NULL;
 
        /* Pin the user virtual address. */
-       npinned = get_user_pages_fast(uaddr, npages, write ? FOLL_WRITE : 0, pages);
+       npinned = get_user_pages_fast(uaddr, npages, FOLL_WRITE, pages);
        if (npinned != npages) {
                pr_err("SEV: Failure locking %lu pages.\n", npages);
                goto err;
@@ -2091,7 +2091,7 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
        init_vmcb(svm);
 
        kvm_cpuid(vcpu, &eax, &dummy, &dummy, &dummy, true);
-       kvm_register_write(vcpu, VCPU_REGS_RDX, eax);
+       kvm_rdx_write(vcpu, eax);
 
        if (kvm_vcpu_apicv_active(vcpu) && !init_event)
                avic_update_vapic_bar(svm, APIC_DEFAULT_PHYS_BASE);
@@ -3071,32 +3071,6 @@ static inline bool nested_svm_nmi(struct vcpu_svm *svm)
        return false;
 }
 
-static void *nested_svm_map(struct vcpu_svm *svm, u64 gpa, struct page **_page)
-{
-       struct page *page;
-
-       might_sleep();
-
-       page = kvm_vcpu_gfn_to_page(&svm->vcpu, gpa >> PAGE_SHIFT);
-       if (is_error_page(page))
-               goto error;
-
-       *_page = page;
-
-       return kmap(page);
-
-error:
-       kvm_inject_gp(&svm->vcpu, 0);
-
-       return NULL;
-}
-
-static void nested_svm_unmap(struct page *page)
-{
-       kunmap(page);
-       kvm_release_page_dirty(page);
-}
-
 static int nested_svm_intercept_ioio(struct vcpu_svm *svm)
 {
        unsigned port, size, iopm_len;
@@ -3299,10 +3273,11 @@ static inline void copy_vmcb_control_area(struct vmcb *dst_vmcb, struct vmcb *fr
 
 static int nested_svm_vmexit(struct vcpu_svm *svm)
 {
+       int rc;
        struct vmcb *nested_vmcb;
        struct vmcb *hsave = svm->nested.hsave;
        struct vmcb *vmcb = svm->vmcb;
-       struct page *page;
+       struct kvm_host_map map;
 
        trace_kvm_nested_vmexit_inject(vmcb->control.exit_code,
                                       vmcb->control.exit_info_1,
@@ -3311,9 +3286,14 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
                                       vmcb->control.exit_int_info_err,
                                       KVM_ISA_SVM);
 
-       nested_vmcb = nested_svm_map(svm, svm->nested.vmcb, &page);
-       if (!nested_vmcb)
+       rc = kvm_vcpu_map(&svm->vcpu, gfn_to_gpa(svm->nested.vmcb), &map);
+       if (rc) {
+               if (rc == -EINVAL)
+                       kvm_inject_gp(&svm->vcpu, 0);
                return 1;
+       }
+
+       nested_vmcb = map.hva;
 
        /* Exit Guest-Mode */
        leave_guest_mode(&svm->vcpu);
@@ -3408,16 +3388,16 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
        } else {
                (void)kvm_set_cr3(&svm->vcpu, hsave->save.cr3);
        }
-       kvm_register_write(&svm->vcpu, VCPU_REGS_RAX, hsave->save.rax);
-       kvm_register_write(&svm->vcpu, VCPU_REGS_RSP, hsave->save.rsp);
-       kvm_register_write(&svm->vcpu, VCPU_REGS_RIP, hsave->save.rip);
+       kvm_rax_write(&svm->vcpu, hsave->save.rax);
+       kvm_rsp_write(&svm->vcpu, hsave->save.rsp);
+       kvm_rip_write(&svm->vcpu, hsave->save.rip);
        svm->vmcb->save.dr7 = 0;
        svm->vmcb->save.cpl = 0;
        svm->vmcb->control.exit_int_info = 0;
 
        mark_all_dirty(svm->vmcb);
 
-       nested_svm_unmap(page);
+       kvm_vcpu_unmap(&svm->vcpu, &map, true);
 
        nested_svm_uninit_mmu_context(&svm->vcpu);
        kvm_mmu_reset_context(&svm->vcpu);
@@ -3483,7 +3463,7 @@ static bool nested_vmcb_checks(struct vmcb *vmcb)
 }
 
 static void enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb_gpa,
-                                struct vmcb *nested_vmcb, struct page *page)
+                                struct vmcb *nested_vmcb, struct kvm_host_map *map)
 {
        if (kvm_get_rflags(&svm->vcpu) & X86_EFLAGS_IF)
                svm->vcpu.arch.hflags |= HF_HIF_MASK;
@@ -3516,9 +3496,9 @@ static void enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb_gpa,
        kvm_mmu_reset_context(&svm->vcpu);
 
        svm->vmcb->save.cr2 = svm->vcpu.arch.cr2 = nested_vmcb->save.cr2;
-       kvm_register_write(&svm->vcpu, VCPU_REGS_RAX, nested_vmcb->save.rax);
-       kvm_register_write(&svm->vcpu, VCPU_REGS_RSP, nested_vmcb->save.rsp);
-       kvm_register_write(&svm->vcpu, VCPU_REGS_RIP, nested_vmcb->save.rip);
+       kvm_rax_write(&svm->vcpu, nested_vmcb->save.rax);
+       kvm_rsp_write(&svm->vcpu, nested_vmcb->save.rsp);
+       kvm_rip_write(&svm->vcpu, nested_vmcb->save.rip);
 
        /* In case we don't even reach vcpu_run, the fields are not updated */
        svm->vmcb->save.rax = nested_vmcb->save.rax;
@@ -3567,7 +3547,7 @@ static void enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb_gpa,
        svm->vmcb->control.pause_filter_thresh =
                nested_vmcb->control.pause_filter_thresh;
 
-       nested_svm_unmap(page);
+       kvm_vcpu_unmap(&svm->vcpu, map, true);
 
        /* Enter Guest-Mode */
        enter_guest_mode(&svm->vcpu);
@@ -3587,17 +3567,23 @@ static void enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb_gpa,
 
 static bool nested_svm_vmrun(struct vcpu_svm *svm)
 {
+       int rc;
        struct vmcb *nested_vmcb;
        struct vmcb *hsave = svm->nested.hsave;
        struct vmcb *vmcb = svm->vmcb;
-       struct page *page;
+       struct kvm_host_map map;
        u64 vmcb_gpa;
 
        vmcb_gpa = svm->vmcb->save.rax;
 
-       nested_vmcb = nested_svm_map(svm, svm->vmcb->save.rax, &page);
-       if (!nested_vmcb)
+       rc = kvm_vcpu_map(&svm->vcpu, gfn_to_gpa(vmcb_gpa), &map);
+       if (rc) {
+               if (rc == -EINVAL)
+                       kvm_inject_gp(&svm->vcpu, 0);
                return false;
+       }
+
+       nested_vmcb = map.hva;
 
        if (!nested_vmcb_checks(nested_vmcb)) {
                nested_vmcb->control.exit_code    = SVM_EXIT_ERR;
@@ -3605,7 +3591,7 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
                nested_vmcb->control.exit_info_1  = 0;
                nested_vmcb->control.exit_info_2  = 0;
 
-               nested_svm_unmap(page);
+               kvm_vcpu_unmap(&svm->vcpu, &map, true);
 
                return false;
        }
@@ -3649,7 +3635,7 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
 
        copy_vmcb_control_area(hsave, vmcb);
 
-       enter_svm_guest_mode(svm, vmcb_gpa, nested_vmcb, page);
+       enter_svm_guest_mode(svm, vmcb_gpa, nested_vmcb, &map);
 
        return true;
 }
@@ -3673,21 +3659,26 @@ static void nested_svm_vmloadsave(struct vmcb *from_vmcb, struct vmcb *to_vmcb)
 static int vmload_interception(struct vcpu_svm *svm)
 {
        struct vmcb *nested_vmcb;
-       struct page *page;
+       struct kvm_host_map map;
        int ret;
 
        if (nested_svm_check_permissions(svm))
                return 1;
 
-       nested_vmcb = nested_svm_map(svm, svm->vmcb->save.rax, &page);
-       if (!nested_vmcb)
+       ret = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(svm->vmcb->save.rax), &map);
+       if (ret) {
+               if (ret == -EINVAL)
+                       kvm_inject_gp(&svm->vcpu, 0);
                return 1;
+       }
+
+       nested_vmcb = map.hva;
 
        svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
        ret = kvm_skip_emulated_instruction(&svm->vcpu);
 
        nested_svm_vmloadsave(nested_vmcb, svm->vmcb);
-       nested_svm_unmap(page);
+       kvm_vcpu_unmap(&svm->vcpu, &map, true);
 
        return ret;
 }
@@ -3695,21 +3686,26 @@ static int vmload_interception(struct vcpu_svm *svm)
 static int vmsave_interception(struct vcpu_svm *svm)
 {
        struct vmcb *nested_vmcb;
-       struct page *page;
+       struct kvm_host_map map;
        int ret;
 
        if (nested_svm_check_permissions(svm))
                return 1;
 
-       nested_vmcb = nested_svm_map(svm, svm->vmcb->save.rax, &page);
-       if (!nested_vmcb)
+       ret = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(svm->vmcb->save.rax), &map);
+       if (ret) {
+               if (ret == -EINVAL)
+                       kvm_inject_gp(&svm->vcpu, 0);
                return 1;
+       }
+
+       nested_vmcb = map.hva;
 
        svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
        ret = kvm_skip_emulated_instruction(&svm->vcpu);
 
        nested_svm_vmloadsave(svm->vmcb, nested_vmcb);
-       nested_svm_unmap(page);
+       kvm_vcpu_unmap(&svm->vcpu, &map, true);
 
        return ret;
 }
@@ -3791,11 +3787,11 @@ static int invlpga_interception(struct vcpu_svm *svm)
 {
        struct kvm_vcpu *vcpu = &svm->vcpu;
 
-       trace_kvm_invlpga(svm->vmcb->save.rip, kvm_register_read(&svm->vcpu, VCPU_REGS_RCX),
-                         kvm_register_read(&svm->vcpu, VCPU_REGS_RAX));
+       trace_kvm_invlpga(svm->vmcb->save.rip, kvm_rcx_read(&svm->vcpu),
+                         kvm_rax_read(&svm->vcpu));
 
        /* Let's treat INVLPGA the same as INVLPG (can be optimized!) */
-       kvm_mmu_invlpg(vcpu, kvm_register_read(&svm->vcpu, VCPU_REGS_RAX));
+       kvm_mmu_invlpg(vcpu, kvm_rax_read(&svm->vcpu));
 
        svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
        return kvm_skip_emulated_instruction(&svm->vcpu);
@@ -3803,7 +3799,7 @@ static int invlpga_interception(struct vcpu_svm *svm)
 
 static int skinit_interception(struct vcpu_svm *svm)
 {
-       trace_kvm_skinit(svm->vmcb->save.rip, kvm_register_read(&svm->vcpu, VCPU_REGS_RAX));
+       trace_kvm_skinit(svm->vmcb->save.rip, kvm_rax_read(&svm->vcpu));
 
        kvm_queue_exception(&svm->vcpu, UD_VECTOR);
        return 1;
@@ -3817,7 +3813,7 @@ static int wbinvd_interception(struct vcpu_svm *svm)
 static int xsetbv_interception(struct vcpu_svm *svm)
 {
        u64 new_bv = kvm_read_edx_eax(&svm->vcpu);
-       u32 index = kvm_register_read(&svm->vcpu, VCPU_REGS_RCX);
+       u32 index = kvm_rcx_read(&svm->vcpu);
 
        if (kvm_set_xcr(&svm->vcpu, index, new_bv) == 0) {
                svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
@@ -4213,7 +4209,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 
 static int rdmsr_interception(struct vcpu_svm *svm)
 {
-       u32 ecx = kvm_register_read(&svm->vcpu, VCPU_REGS_RCX);
+       u32 ecx = kvm_rcx_read(&svm->vcpu);
        struct msr_data msr_info;
 
        msr_info.index = ecx;
@@ -4225,10 +4221,8 @@ static int rdmsr_interception(struct vcpu_svm *svm)
        } else {
                trace_kvm_msr_read(ecx, msr_info.data);
 
-               kvm_register_write(&svm->vcpu, VCPU_REGS_RAX,
-                                  msr_info.data & 0xffffffff);
-               kvm_register_write(&svm->vcpu, VCPU_REGS_RDX,
-                                  msr_info.data >> 32);
+               kvm_rax_write(&svm->vcpu, msr_info.data & 0xffffffff);
+               kvm_rdx_write(&svm->vcpu, msr_info.data >> 32);
                svm->next_rip = kvm_rip_read(&svm->vcpu) + 2;
                return kvm_skip_emulated_instruction(&svm->vcpu);
        }
@@ -4422,7 +4416,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
 static int wrmsr_interception(struct vcpu_svm *svm)
 {
        struct msr_data msr;
-       u32 ecx = kvm_register_read(&svm->vcpu, VCPU_REGS_RCX);
+       u32 ecx = kvm_rcx_read(&svm->vcpu);
        u64 data = kvm_read_edx_eax(&svm->vcpu);
 
        msr.data = data;
@@ -6236,7 +6230,7 @@ static int svm_pre_leave_smm(struct kvm_vcpu *vcpu, const char *smstate)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
        struct vmcb *nested_vmcb;
-       struct page *page;
+       struct kvm_host_map map;
        u64 guest;
        u64 vmcb;
 
@@ -6244,10 +6238,10 @@ static int svm_pre_leave_smm(struct kvm_vcpu *vcpu, const char *smstate)
        vmcb = GET_SMSTATE(u64, smstate, 0x7ee0);
 
        if (guest) {
-               nested_vmcb = nested_svm_map(svm, vmcb, &page);
-               if (!nested_vmcb)
+               if (kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(vmcb), &map) == -EINVAL)
                        return 1;
-               enter_svm_guest_mode(svm, vmcb, nested_vmcb, page);
+               nested_vmcb = map.hva;
+               enter_svm_guest_mode(svm, vmcb, nested_vmcb, &map);
        }
        return 0;
 }
index 854e144131c6703a41564c3244d365b79344386b..d6664ee3d1276c6213275d6b84962b9f2cbb8289 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef __KVM_X86_VMX_CAPS_H
 #define __KVM_X86_VMX_CAPS_H
 
+#include <asm/vmx.h>
+
 #include "lapic.h"
 
 extern bool __read_mostly enable_vpid;
index 0c601d079cd20e4975f58c0f4fca35c36abbc9f9..f1a69117ac0f1a8b8e73c8df10d8aade220a6ba1 100644 (file)
@@ -193,10 +193,8 @@ static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
        if (!vmx->nested.hv_evmcs)
                return;
 
-       kunmap(vmx->nested.hv_evmcs_page);
-       kvm_release_page_dirty(vmx->nested.hv_evmcs_page);
+       kvm_vcpu_unmap(vcpu, &vmx->nested.hv_evmcs_map, true);
        vmx->nested.hv_evmcs_vmptr = -1ull;
-       vmx->nested.hv_evmcs_page = NULL;
        vmx->nested.hv_evmcs = NULL;
 }
 
@@ -229,16 +227,9 @@ static void free_nested(struct kvm_vcpu *vcpu)
                kvm_release_page_dirty(vmx->nested.apic_access_page);
                vmx->nested.apic_access_page = NULL;
        }
-       if (vmx->nested.virtual_apic_page) {
-               kvm_release_page_dirty(vmx->nested.virtual_apic_page);
-               vmx->nested.virtual_apic_page = NULL;
-       }
-       if (vmx->nested.pi_desc_page) {
-               kunmap(vmx->nested.pi_desc_page);
-               kvm_release_page_dirty(vmx->nested.pi_desc_page);
-               vmx->nested.pi_desc_page = NULL;
-               vmx->nested.pi_desc = NULL;
-       }
+       kvm_vcpu_unmap(vcpu, &vmx->nested.virtual_apic_map, true);
+       kvm_vcpu_unmap(vcpu, &vmx->nested.pi_desc_map, true);
+       vmx->nested.pi_desc = NULL;
 
        kvm_mmu_free_roots(vcpu, &vcpu->arch.guest_mmu, KVM_MMU_ROOTS_ALL);
 
@@ -519,39 +510,19 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
                                                 struct vmcs12 *vmcs12)
 {
        int msr;
-       struct page *page;
        unsigned long *msr_bitmap_l1;
        unsigned long *msr_bitmap_l0 = to_vmx(vcpu)->nested.vmcs02.msr_bitmap;
-       /*
-        * pred_cmd & spec_ctrl are trying to verify two things:
-        *
-        * 1. L0 gave a permission to L1 to actually passthrough the MSR. This
-        *    ensures that we do not accidentally generate an L02 MSR bitmap
-        *    from the L12 MSR bitmap that is too permissive.
-        * 2. That L1 or L2s have actually used the MSR. This avoids
-        *    unnecessarily merging of the bitmap if the MSR is unused. This
-        *    works properly because we only update the L01 MSR bitmap lazily.
-        *    So even if L0 should pass L1 these MSRs, the L01 bitmap is only
-        *    updated to reflect this when L1 (or its L2s) actually write to
-        *    the MSR.
-        */
-       bool pred_cmd = !msr_write_intercepted_l01(vcpu, MSR_IA32_PRED_CMD);
-       bool spec_ctrl = !msr_write_intercepted_l01(vcpu, MSR_IA32_SPEC_CTRL);
+       struct kvm_host_map *map = &to_vmx(vcpu)->nested.msr_bitmap_map;
 
        /* Nothing to do if the MSR bitmap is not in use.  */
        if (!cpu_has_vmx_msr_bitmap() ||
            !nested_cpu_has(vmcs12, CPU_BASED_USE_MSR_BITMAPS))
                return false;
 
-       if (!nested_cpu_has_virt_x2apic_mode(vmcs12) &&
-           !pred_cmd && !spec_ctrl)
-               return false;
-
-       page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->msr_bitmap);
-       if (is_error_page(page))
+       if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->msr_bitmap), map))
                return false;
 
-       msr_bitmap_l1 = (unsigned long *)kmap(page);
+       msr_bitmap_l1 = (unsigned long *)map->hva;
 
        /*
         * To keep the control flow simple, pay eight 8-byte writes (sixteen
@@ -592,20 +563,42 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
                }
        }
 
-       if (spec_ctrl)
+       /* KVM unconditionally exposes the FS/GS base MSRs to L1. */
+       nested_vmx_disable_intercept_for_msr(msr_bitmap_l1, msr_bitmap_l0,
+                                            MSR_FS_BASE, MSR_TYPE_RW);
+
+       nested_vmx_disable_intercept_for_msr(msr_bitmap_l1, msr_bitmap_l0,
+                                            MSR_GS_BASE, MSR_TYPE_RW);
+
+       nested_vmx_disable_intercept_for_msr(msr_bitmap_l1, msr_bitmap_l0,
+                                            MSR_KERNEL_GS_BASE, MSR_TYPE_RW);
+
+       /*
+        * Checking the L0->L1 bitmap is trying to verify two things:
+        *
+        * 1. L0 gave a permission to L1 to actually passthrough the MSR. This
+        *    ensures that we do not accidentally generate an L02 MSR bitmap
+        *    from the L12 MSR bitmap that is too permissive.
+        * 2. That L1 or L2s have actually used the MSR. This avoids
+        *    unnecessarily merging of the bitmap if the MSR is unused. This
+        *    works properly because we only update the L01 MSR bitmap lazily.
+        *    So even if L0 should pass L1 these MSRs, the L01 bitmap is only
+        *    updated to reflect this when L1 (or its L2s) actually write to
+        *    the MSR.
+        */
+       if (!msr_write_intercepted_l01(vcpu, MSR_IA32_SPEC_CTRL))
                nested_vmx_disable_intercept_for_msr(
                                        msr_bitmap_l1, msr_bitmap_l0,
                                        MSR_IA32_SPEC_CTRL,
                                        MSR_TYPE_R | MSR_TYPE_W);
 
-       if (pred_cmd)
+       if (!msr_write_intercepted_l01(vcpu, MSR_IA32_PRED_CMD))
                nested_vmx_disable_intercept_for_msr(
                                        msr_bitmap_l1, msr_bitmap_l0,
                                        MSR_IA32_PRED_CMD,
                                        MSR_TYPE_W);
 
-       kunmap(page);
-       kvm_release_page_clean(page);
+       kvm_vcpu_unmap(vcpu, &to_vmx(vcpu)->nested.msr_bitmap_map, false);
 
        return true;
 }
@@ -613,20 +606,20 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
 static void nested_cache_shadow_vmcs12(struct kvm_vcpu *vcpu,
                                       struct vmcs12 *vmcs12)
 {
+       struct kvm_host_map map;
        struct vmcs12 *shadow;
-       struct page *page;
 
        if (!nested_cpu_has_shadow_vmcs(vmcs12) ||
            vmcs12->vmcs_link_pointer == -1ull)
                return;
 
        shadow = get_shadow_vmcs12(vcpu);
-       page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->vmcs_link_pointer);
 
-       memcpy(shadow, kmap(page), VMCS12_SIZE);
+       if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->vmcs_link_pointer), &map))
+               return;
 
-       kunmap(page);
-       kvm_release_page_clean(page);
+       memcpy(shadow, map.hva, VMCS12_SIZE);
+       kvm_vcpu_unmap(vcpu, &map, false);
 }
 
 static void nested_flush_cached_shadow_vmcs12(struct kvm_vcpu *vcpu,
@@ -930,7 +923,7 @@ static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool ne
        if (cr3 != kvm_read_cr3(vcpu) || (!nested_ept && pdptrs_changed(vcpu))) {
                if (!nested_cr3_valid(vcpu, cr3)) {
                        *entry_failure_code = ENTRY_FAIL_DEFAULT;
-                       return 1;
+                       return -EINVAL;
                }
 
                /*
@@ -941,7 +934,7 @@ static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool ne
                    !nested_ept) {
                        if (!load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3)) {
                                *entry_failure_code = ENTRY_FAIL_PDPTE;
-                               return 1;
+                               return -EINVAL;
                        }
                }
        }
@@ -1794,13 +1787,11 @@ static int nested_vmx_handle_enlightened_vmptrld(struct kvm_vcpu *vcpu,
 
                nested_release_evmcs(vcpu);
 
-               vmx->nested.hv_evmcs_page = kvm_vcpu_gpa_to_page(
-                       vcpu, assist_page.current_nested_vmcs);
-
-               if (unlikely(is_error_page(vmx->nested.hv_evmcs_page)))
+               if (kvm_vcpu_map(vcpu, gpa_to_gfn(assist_page.current_nested_vmcs),
+                                &vmx->nested.hv_evmcs_map))
                        return 0;
 
-               vmx->nested.hv_evmcs = kmap(vmx->nested.hv_evmcs_page);
+               vmx->nested.hv_evmcs = vmx->nested.hv_evmcs_map.hva;
 
                /*
                 * Currently, KVM only supports eVMCS version 1
@@ -2373,19 +2364,19 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
         */
        if (vmx->emulation_required) {
                *entry_failure_code = ENTRY_FAIL_DEFAULT;
-               return 1;
+               return -EINVAL;
        }
 
        /* Shadow page tables on either EPT or shadow page tables. */
        if (nested_vmx_load_cr3(vcpu, vmcs12->guest_cr3, nested_cpu_has_ept(vmcs12),
                                entry_failure_code))
-               return 1;
+               return -EINVAL;
 
        if (!enable_ept)
                vcpu->arch.walk_mmu->inject_page_fault = vmx_inject_page_fault_nested;
 
-       kvm_register_write(vcpu, VCPU_REGS_RSP, vmcs12->guest_rsp);
-       kvm_register_write(vcpu, VCPU_REGS_RIP, vmcs12->guest_rip);
+       kvm_rsp_write(vcpu, vmcs12->guest_rsp);
+       kvm_rip_write(vcpu, vmcs12->guest_rip);
        return 0;
 }
 
@@ -2589,11 +2580,19 @@ static int nested_check_vm_entry_controls(struct kvm_vcpu *vcpu,
        return 0;
 }
 
-/*
- * Checks related to Host Control Registers and MSRs
- */
-static int nested_check_host_control_regs(struct kvm_vcpu *vcpu,
-                                          struct vmcs12 *vmcs12)
+static int nested_vmx_check_controls(struct kvm_vcpu *vcpu,
+                                    struct vmcs12 *vmcs12)
+{
+       if (nested_check_vm_execution_controls(vcpu, vmcs12) ||
+           nested_check_vm_exit_controls(vcpu, vmcs12) ||
+           nested_check_vm_entry_controls(vcpu, vmcs12))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
+                                      struct vmcs12 *vmcs12)
 {
        bool ia32e;
 
@@ -2606,6 +2605,10 @@ static int nested_check_host_control_regs(struct kvm_vcpu *vcpu,
            is_noncanonical_address(vmcs12->host_ia32_sysenter_eip, vcpu))
                return -EINVAL;
 
+       if ((vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PAT) &&
+           !kvm_pat_valid(vmcs12->host_ia32_pat))
+               return -EINVAL;
+
        /*
         * If the load IA32_EFER VM-exit control is 1, bits reserved in the
         * IA32_EFER MSR must be 0 in the field for that register. In addition,
@@ -2624,41 +2627,12 @@ static int nested_check_host_control_regs(struct kvm_vcpu *vcpu,
        return 0;
 }
 
-/*
- * Checks related to Guest Non-register State
- */
-static int nested_check_guest_non_reg_state(struct vmcs12 *vmcs12)
-{
-       if (vmcs12->guest_activity_state != GUEST_ACTIVITY_ACTIVE &&
-           vmcs12->guest_activity_state != GUEST_ACTIVITY_HLT)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int nested_vmx_check_vmentry_prereqs(struct kvm_vcpu *vcpu,
-                                           struct vmcs12 *vmcs12)
-{
-       if (nested_check_vm_execution_controls(vcpu, vmcs12) ||
-           nested_check_vm_exit_controls(vcpu, vmcs12) ||
-           nested_check_vm_entry_controls(vcpu, vmcs12))
-               return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
-
-       if (nested_check_host_control_regs(vcpu, vmcs12))
-               return VMXERR_ENTRY_INVALID_HOST_STATE_FIELD;
-
-       if (nested_check_guest_non_reg_state(vmcs12))
-               return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
-
-       return 0;
-}
-
 static int nested_vmx_check_vmcs_link_ptr(struct kvm_vcpu *vcpu,
                                          struct vmcs12 *vmcs12)
 {
-       int r;
-       struct page *page;
+       int r = 0;
        struct vmcs12 *shadow;
+       struct kvm_host_map map;
 
        if (vmcs12->vmcs_link_pointer == -1ull)
                return 0;
@@ -2666,23 +2640,34 @@ static int nested_vmx_check_vmcs_link_ptr(struct kvm_vcpu *vcpu,
        if (!page_address_valid(vcpu, vmcs12->vmcs_link_pointer))
                return -EINVAL;
 
-       page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->vmcs_link_pointer);
-       if (is_error_page(page))
+       if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->vmcs_link_pointer), &map))
                return -EINVAL;
 
-       r = 0;
-       shadow = kmap(page);
+       shadow = map.hva;
+
        if (shadow->hdr.revision_id != VMCS12_REVISION ||
            shadow->hdr.shadow_vmcs != nested_cpu_has_shadow_vmcs(vmcs12))
                r = -EINVAL;
-       kunmap(page);
-       kvm_release_page_clean(page);
+
+       kvm_vcpu_unmap(vcpu, &map, false);
        return r;
 }
 
-static int nested_vmx_check_vmentry_postreqs(struct kvm_vcpu *vcpu,
-                                            struct vmcs12 *vmcs12,
-                                            u32 *exit_qual)
+/*
+ * Checks related to Guest Non-register State
+ */
+static int nested_check_guest_non_reg_state(struct vmcs12 *vmcs12)
+{
+       if (vmcs12->guest_activity_state != GUEST_ACTIVITY_ACTIVE &&
+           vmcs12->guest_activity_state != GUEST_ACTIVITY_HLT)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu,
+                                       struct vmcs12 *vmcs12,
+                                       u32 *exit_qual)
 {
        bool ia32e;
 
@@ -2690,11 +2675,15 @@ static int nested_vmx_check_vmentry_postreqs(struct kvm_vcpu *vcpu,
 
        if (!nested_guest_cr0_valid(vcpu, vmcs12->guest_cr0) ||
            !nested_guest_cr4_valid(vcpu, vmcs12->guest_cr4))
-               return 1;
+               return -EINVAL;
+
+       if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PAT) &&
+           !kvm_pat_valid(vmcs12->guest_ia32_pat))
+               return -EINVAL;
 
        if (nested_vmx_check_vmcs_link_ptr(vcpu, vmcs12)) {
                *exit_qual = ENTRY_FAIL_VMCS_LINK_PTR;
-               return 1;
+               return -EINVAL;
        }
 
        /*
@@ -2713,13 +2702,16 @@ static int nested_vmx_check_vmentry_postreqs(struct kvm_vcpu *vcpu,
                    ia32e != !!(vmcs12->guest_ia32_efer & EFER_LMA) ||
                    ((vmcs12->guest_cr0 & X86_CR0_PG) &&
                     ia32e != !!(vmcs12->guest_ia32_efer & EFER_LME)))
-                       return 1;
+                       return -EINVAL;
        }
 
        if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS) &&
-               (is_noncanonical_address(vmcs12->guest_bndcfgs & PAGE_MASK, vcpu) ||
-               (vmcs12->guest_bndcfgs & MSR_IA32_BNDCFGS_RSVD)))
-                       return 1;
+           (is_noncanonical_address(vmcs12->guest_bndcfgs & PAGE_MASK, vcpu) ||
+            (vmcs12->guest_bndcfgs & MSR_IA32_BNDCFGS_RSVD)))
+               return -EINVAL;
+
+       if (nested_check_guest_non_reg_state(vmcs12))
+               return -EINVAL;
 
        return 0;
 }
@@ -2832,6 +2824,7 @@ static void nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
 {
        struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
        struct vcpu_vmx *vmx = to_vmx(vcpu);
+       struct kvm_host_map *map;
        struct page *page;
        u64 hpa;
 
@@ -2864,20 +2857,14 @@ static void nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
        }
 
        if (nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW)) {
-               if (vmx->nested.virtual_apic_page) { /* shouldn't happen */
-                       kvm_release_page_dirty(vmx->nested.virtual_apic_page);
-                       vmx->nested.virtual_apic_page = NULL;
-               }
-               page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->virtual_apic_page_addr);
+               map = &vmx->nested.virtual_apic_map;
 
                /*
                 * If translation failed, VM entry will fail because
                 * prepare_vmcs02 set VIRTUAL_APIC_PAGE_ADDR to -1ull.
                 */
-               if (!is_error_page(page)) {
-                       vmx->nested.virtual_apic_page = page;
-                       hpa = page_to_phys(vmx->nested.virtual_apic_page);
-                       vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, hpa);
+               if (!kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->virtual_apic_page_addr), map)) {
+                       vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, pfn_to_hpa(map->pfn));
                } else if (nested_cpu_has(vmcs12, CPU_BASED_CR8_LOAD_EXITING) &&
                           nested_cpu_has(vmcs12, CPU_BASED_CR8_STORE_EXITING) &&
                           !nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) {
@@ -2898,26 +2885,15 @@ static void nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
        }
 
        if (nested_cpu_has_posted_intr(vmcs12)) {
-               if (vmx->nested.pi_desc_page) { /* shouldn't happen */
-                       kunmap(vmx->nested.pi_desc_page);
-                       kvm_release_page_dirty(vmx->nested.pi_desc_page);
-                       vmx->nested.pi_desc_page = NULL;
-                       vmx->nested.pi_desc = NULL;
-                       vmcs_write64(POSTED_INTR_DESC_ADDR, -1ull);
+               map = &vmx->nested.pi_desc_map;
+
+               if (!kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->posted_intr_desc_addr), map)) {
+                       vmx->nested.pi_desc =
+                               (struct pi_desc *)(((void *)map->hva) +
+                               offset_in_page(vmcs12->posted_intr_desc_addr));
+                       vmcs_write64(POSTED_INTR_DESC_ADDR,
+                                    pfn_to_hpa(map->pfn) + offset_in_page(vmcs12->posted_intr_desc_addr));
                }
-               page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->posted_intr_desc_addr);
-               if (is_error_page(page))
-                       return;
-               vmx->nested.pi_desc_page = page;
-               vmx->nested.pi_desc = kmap(vmx->nested.pi_desc_page);
-               vmx->nested.pi_desc =
-                       (struct pi_desc *)((void *)vmx->nested.pi_desc +
-                       (unsigned long)(vmcs12->posted_intr_desc_addr &
-                       (PAGE_SIZE - 1)));
-               vmcs_write64(POSTED_INTR_DESC_ADDR,
-                       page_to_phys(vmx->nested.pi_desc_page) +
-                       (unsigned long)(vmcs12->posted_intr_desc_addr &
-                       (PAGE_SIZE - 1)));
        }
        if (nested_vmx_prepare_msr_bitmap(vcpu, vmcs12))
                vmcs_set_bits(CPU_BASED_VM_EXEC_CONTROL,
@@ -3000,7 +2976,7 @@ int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, bool from_vmentry)
                        return -1;
                }
 
-               if (nested_vmx_check_vmentry_postreqs(vcpu, vmcs12, &exit_qual))
+               if (nested_vmx_check_guest_state(vcpu, vmcs12, &exit_qual))
                        goto vmentry_fail_vmexit;
        }
 
@@ -3145,9 +3121,11 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
                        launch ? VMXERR_VMLAUNCH_NONCLEAR_VMCS
                               : VMXERR_VMRESUME_NONLAUNCHED_VMCS);
 
-       ret = nested_vmx_check_vmentry_prereqs(vcpu, vmcs12);
-       if (ret)
-               return nested_vmx_failValid(vcpu, ret);
+       if (nested_vmx_check_controls(vcpu, vmcs12))
+               return nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
+
+       if (nested_vmx_check_host_state(vcpu, vmcs12))
+               return nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_HOST_STATE_FIELD);
 
        /*
         * We're finally done with prerequisite checking, and can start with
@@ -3310,11 +3288,12 @@ static void vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
 
        max_irr = find_last_bit((unsigned long *)vmx->nested.pi_desc->pir, 256);
        if (max_irr != 256) {
-               vapic_page = kmap(vmx->nested.virtual_apic_page);
+               vapic_page = vmx->nested.virtual_apic_map.hva;
+               if (!vapic_page)
+                       return;
+
                __kvm_apic_update_irr(vmx->nested.pi_desc->pir,
                        vapic_page, &max_irr);
-               kunmap(vmx->nested.virtual_apic_page);
-
                status = vmcs_read16(GUEST_INTR_STATUS);
                if ((u8)max_irr > ((u8)status & 0xff)) {
                        status &= ~0xff;
@@ -3425,8 +3404,8 @@ static void sync_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
        vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12);
        vmcs12->guest_cr4 = vmcs12_guest_cr4(vcpu, vmcs12);
 
-       vmcs12->guest_rsp = kvm_register_read(vcpu, VCPU_REGS_RSP);
-       vmcs12->guest_rip = kvm_register_read(vcpu, VCPU_REGS_RIP);
+       vmcs12->guest_rsp = kvm_rsp_read(vcpu);
+       vmcs12->guest_rip = kvm_rip_read(vcpu);
        vmcs12->guest_rflags = vmcs_readl(GUEST_RFLAGS);
 
        vmcs12->guest_es_selector = vmcs_read16(GUEST_ES_SELECTOR);
@@ -3609,8 +3588,8 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
                vcpu->arch.efer &= ~(EFER_LMA | EFER_LME);
        vmx_set_efer(vcpu, vcpu->arch.efer);
 
-       kvm_register_write(vcpu, VCPU_REGS_RSP, vmcs12->host_rsp);
-       kvm_register_write(vcpu, VCPU_REGS_RIP, vmcs12->host_rip);
+       kvm_rsp_write(vcpu, vmcs12->host_rsp);
+       kvm_rip_write(vcpu, vmcs12->host_rip);
        vmx_set_rflags(vcpu, X86_EFLAGS_FIXED);
        vmx_set_interrupt_shadow(vcpu, 0);
 
@@ -3955,16 +3934,9 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
                kvm_release_page_dirty(vmx->nested.apic_access_page);
                vmx->nested.apic_access_page = NULL;
        }
-       if (vmx->nested.virtual_apic_page) {
-               kvm_release_page_dirty(vmx->nested.virtual_apic_page);
-               vmx->nested.virtual_apic_page = NULL;
-       }
-       if (vmx->nested.pi_desc_page) {
-               kunmap(vmx->nested.pi_desc_page);
-               kvm_release_page_dirty(vmx->nested.pi_desc_page);
-               vmx->nested.pi_desc_page = NULL;
-               vmx->nested.pi_desc = NULL;
-       }
+       kvm_vcpu_unmap(vcpu, &vmx->nested.virtual_apic_map, true);
+       kvm_vcpu_unmap(vcpu, &vmx->nested.pi_desc_map, true);
+       vmx->nested.pi_desc = NULL;
 
        /*
         * We are now running in L2, mmu_notifier will force to reload the
@@ -4260,7 +4232,7 @@ static int handle_vmon(struct kvm_vcpu *vcpu)
 {
        int ret;
        gpa_t vmptr;
-       struct page *page;
+       uint32_t revision;
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        const u64 VMXON_NEEDED_FEATURES = FEATURE_CONTROL_LOCKED
                | FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX;
@@ -4306,20 +4278,12 @@ static int handle_vmon(struct kvm_vcpu *vcpu)
         * Note - IA32_VMX_BASIC[48] will never be 1 for the nested case;
         * which replaces physical address width with 32
         */
-       if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu)))
-               return nested_vmx_failInvalid(vcpu);
-
-       page = kvm_vcpu_gpa_to_page(vcpu, vmptr);
-       if (is_error_page(page))
+       if (!page_address_valid(vcpu, vmptr))
                return nested_vmx_failInvalid(vcpu);
 
-       if (*(u32 *)kmap(page) != VMCS12_REVISION) {
-               kunmap(page);
-               kvm_release_page_clean(page);
+       if (kvm_read_guest(vcpu->kvm, vmptr, &revision, sizeof(revision)) ||
+           revision != VMCS12_REVISION)
                return nested_vmx_failInvalid(vcpu);
-       }
-       kunmap(page);
-       kvm_release_page_clean(page);
 
        vmx->nested.vmxon_ptr = vmptr;
        ret = enter_vmx_operation(vcpu);
@@ -4377,7 +4341,7 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
        if (nested_vmx_get_vmptr(vcpu, &vmptr))
                return 1;
 
-       if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu)))
+       if (!page_address_valid(vcpu, vmptr))
                return nested_vmx_failValid(vcpu,
                        VMXERR_VMCLEAR_INVALID_ADDRESS);
 
@@ -4385,7 +4349,7 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
                return nested_vmx_failValid(vcpu,
                        VMXERR_VMCLEAR_VMXON_POINTER);
 
-       if (vmx->nested.hv_evmcs_page) {
+       if (vmx->nested.hv_evmcs_map.hva) {
                if (vmptr == vmx->nested.hv_evmcs_vmptr)
                        nested_release_evmcs(vcpu);
        } else {
@@ -4584,7 +4548,7 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
        if (nested_vmx_get_vmptr(vcpu, &vmptr))
                return 1;
 
-       if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu)))
+       if (!page_address_valid(vcpu, vmptr))
                return nested_vmx_failValid(vcpu,
                        VMXERR_VMPTRLD_INVALID_ADDRESS);
 
@@ -4597,11 +4561,10 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
                return 1;
 
        if (vmx->nested.current_vmptr != vmptr) {
+               struct kvm_host_map map;
                struct vmcs12 *new_vmcs12;
-               struct page *page;
 
-               page = kvm_vcpu_gpa_to_page(vcpu, vmptr);
-               if (is_error_page(page)) {
+               if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmptr), &map)) {
                        /*
                         * Reads from an unbacked page return all 1s,
                         * which means that the 32 bits located at the
@@ -4611,12 +4574,13 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
                        return nested_vmx_failValid(vcpu,
                                VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID);
                }
-               new_vmcs12 = kmap(page);
+
+               new_vmcs12 = map.hva;
+
                if (new_vmcs12->hdr.revision_id != VMCS12_REVISION ||
                    (new_vmcs12->hdr.shadow_vmcs &&
                     !nested_cpu_has_vmx_shadow_vmcs(vcpu))) {
-                       kunmap(page);
-                       kvm_release_page_clean(page);
+                       kvm_vcpu_unmap(vcpu, &map, false);
                        return nested_vmx_failValid(vcpu,
                                VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID);
                }
@@ -4628,8 +4592,7 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
                 * cached.
                 */
                memcpy(vmx->nested.cached_vmcs12, new_vmcs12, VMCS12_SIZE);
-               kunmap(page);
-               kvm_release_page_clean(page);
+               kvm_vcpu_unmap(vcpu, &map, false);
 
                set_current_vmptr(vmx, vmptr);
        }
@@ -4804,7 +4767,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
 static int nested_vmx_eptp_switching(struct kvm_vcpu *vcpu,
                                     struct vmcs12 *vmcs12)
 {
-       u32 index = vcpu->arch.regs[VCPU_REGS_RCX];
+       u32 index = kvm_rcx_read(vcpu);
        u64 address;
        bool accessed_dirty;
        struct kvm_mmu *mmu = vcpu->arch.walk_mmu;
@@ -4850,7 +4813,7 @@ static int handle_vmfunc(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        struct vmcs12 *vmcs12;
-       u32 function = vcpu->arch.regs[VCPU_REGS_RAX];
+       u32 function = kvm_rax_read(vcpu);
 
        /*
         * VMFUNC is only supported for nested guests, but we always enable the
@@ -4936,7 +4899,7 @@ static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
 static bool nested_vmx_exit_handled_msr(struct kvm_vcpu *vcpu,
        struct vmcs12 *vmcs12, u32 exit_reason)
 {
-       u32 msr_index = vcpu->arch.regs[VCPU_REGS_RCX];
+       u32 msr_index = kvm_rcx_read(vcpu);
        gpa_t bitmap;
 
        if (!nested_cpu_has(vmcs12, CPU_BASED_USE_MSR_BITMAPS))
@@ -5373,9 +5336,6 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
        if (kvm_state->format != 0)
                return -EINVAL;
 
-       if (kvm_state->flags & KVM_STATE_NESTED_EVMCS)
-               nested_enable_evmcs(vcpu, NULL);
-
        if (!nested_vmx_allowed(vcpu))
                return kvm_state->vmx.vmxon_pa == -1ull ? 0 : -EINVAL;
 
@@ -5417,6 +5377,9 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
        if (kvm_state->vmx.vmxon_pa == -1ull)
                return 0;
 
+       if (kvm_state->flags & KVM_STATE_NESTED_EVMCS)
+               nested_enable_evmcs(vcpu, NULL);
+
        vmx->nested.vmxon_ptr = kvm_state->vmx.vmxon_pa;
        ret = enter_vmx_operation(vcpu);
        if (ret)
@@ -5460,9 +5423,6 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
        if (!(kvm_state->flags & KVM_STATE_NESTED_GUEST_MODE))
                return 0;
 
-       vmx->nested.nested_run_pending =
-               !!(kvm_state->flags & KVM_STATE_NESTED_RUN_PENDING);
-
        if (nested_cpu_has_shadow_vmcs(vmcs12) &&
            vmcs12->vmcs_link_pointer != -1ull) {
                struct vmcs12 *shadow_vmcs12 = get_shadow_vmcs12(vcpu);
@@ -5480,14 +5440,20 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
                        return -EINVAL;
        }
 
-       if (nested_vmx_check_vmentry_prereqs(vcpu, vmcs12) ||
-           nested_vmx_check_vmentry_postreqs(vcpu, vmcs12, &exit_qual))
+       if (nested_vmx_check_controls(vcpu, vmcs12) ||
+           nested_vmx_check_host_state(vcpu, vmcs12) ||
+           nested_vmx_check_guest_state(vcpu, vmcs12, &exit_qual))
                return -EINVAL;
 
        vmx->nested.dirty_vmcs12 = true;
+       vmx->nested.nested_run_pending =
+               !!(kvm_state->flags & KVM_STATE_NESTED_RUN_PENDING);
+
        ret = nested_vmx_enter_non_root_mode(vcpu, false);
-       if (ret)
+       if (ret) {
+               vmx->nested.nested_run_pending = 0;
                return -EINVAL;
+       }
 
        return 0;
 }
index 5ab4a364348e3c10987c33203be4ff6fa97e1e73..f8502c376b3702f8897a35442fff539093fef418 100644 (file)
@@ -227,7 +227,7 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                }
                break;
        case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
-               if (!(data & (pmu->global_ctrl_mask & ~(3ull<<62)))) {
+               if (!(data & pmu->global_ovf_ctrl_mask)) {
                        if (!msr_info->host_initiated)
                                pmu->global_status &= ~data;
                        pmu->global_ovf_ctrl = data;
@@ -297,6 +297,12 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
        pmu->global_ctrl = ((1ull << pmu->nr_arch_gp_counters) - 1) |
                (((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED);
        pmu->global_ctrl_mask = ~pmu->global_ctrl;
+       pmu->global_ovf_ctrl_mask = pmu->global_ctrl_mask
+                       & ~(MSR_CORE_PERF_GLOBAL_OVF_CTRL_OVF_BUF |
+                           MSR_CORE_PERF_GLOBAL_OVF_CTRL_COND_CHGD);
+       if (kvm_x86_ops->pt_supported())
+               pmu->global_ovf_ctrl_mask &=
+                               ~MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI;
 
        entry = kvm_find_cpuid_entry(vcpu, 7, 0);
        if (entry &&
index 9663d41cc2bc7ee3e7e17c227880a9ea7992d89f..1ac167614032a317d324a9d43adc4aa1b16a3c59 100644 (file)
@@ -1692,6 +1692,9 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_IA32_SYSENTER_ESP:
                msr_info->data = vmcs_readl(GUEST_SYSENTER_ESP);
                break;
+       case MSR_IA32_POWER_CTL:
+               msr_info->data = vmx->msr_ia32_power_ctl;
+               break;
        case MSR_IA32_BNDCFGS:
                if (!kvm_mpx_supported() ||
                    (!msr_info->host_initiated &&
@@ -1822,6 +1825,9 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_IA32_SYSENTER_ESP:
                vmcs_writel(GUEST_SYSENTER_ESP, data);
                break;
+       case MSR_IA32_POWER_CTL:
+               vmx->msr_ia32_power_ctl = data;
+               break;
        case MSR_IA32_BNDCFGS:
                if (!kvm_mpx_supported() ||
                    (!msr_info->host_initiated &&
@@ -1891,7 +1897,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                break;
        case MSR_IA32_CR_PAT:
                if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) {
-                       if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data))
+                       if (!kvm_pat_valid(data))
                                return 1;
                        vmcs_write64(GUEST_IA32_PAT, data);
                        vcpu->arch.pat = data;
@@ -2288,7 +2294,6 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,
        min |= VM_EXIT_HOST_ADDR_SPACE_SIZE;
 #endif
        opt = VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |
-             VM_EXIT_SAVE_IA32_PAT |
              VM_EXIT_LOAD_IA32_PAT |
              VM_EXIT_LOAD_IA32_EFER |
              VM_EXIT_CLEAR_BNDCFGS |
@@ -3619,14 +3624,13 @@ static bool vmx_guest_apic_has_interrupt(struct kvm_vcpu *vcpu)
 
        if (WARN_ON_ONCE(!is_guest_mode(vcpu)) ||
                !nested_cpu_has_vid(get_vmcs12(vcpu)) ||
-               WARN_ON_ONCE(!vmx->nested.virtual_apic_page))
+               WARN_ON_ONCE(!vmx->nested.virtual_apic_map.gfn))
                return false;
 
        rvi = vmx_get_rvi();
 
-       vapic_page = kmap(vmx->nested.virtual_apic_page);
+       vapic_page = vmx->nested.virtual_apic_map.hva;
        vppr = *((u32 *)(vapic_page + APIC_PROCPRI));
-       kunmap(vmx->nested.virtual_apic_page);
 
        return ((rvi & 0xf0) > (vppr & 0xf0));
 }
@@ -4827,7 +4831,7 @@ static int handle_cpuid(struct kvm_vcpu *vcpu)
 
 static int handle_rdmsr(struct kvm_vcpu *vcpu)
 {
-       u32 ecx = vcpu->arch.regs[VCPU_REGS_RCX];
+       u32 ecx = kvm_rcx_read(vcpu);
        struct msr_data msr_info;
 
        msr_info.index = ecx;
@@ -4840,18 +4844,16 @@ static int handle_rdmsr(struct kvm_vcpu *vcpu)
 
        trace_kvm_msr_read(ecx, msr_info.data);
 
-       /* FIXME: handling of bits 32:63 of rax, rdx */
-       vcpu->arch.regs[VCPU_REGS_RAX] = msr_info.data & -1u;
-       vcpu->arch.regs[VCPU_REGS_RDX] = (msr_info.data >> 32) & -1u;
+       kvm_rax_write(vcpu, msr_info.data & -1u);
+       kvm_rdx_write(vcpu, (msr_info.data >> 32) & -1u);
        return kvm_skip_emulated_instruction(vcpu);
 }
 
 static int handle_wrmsr(struct kvm_vcpu *vcpu)
 {
        struct msr_data msr;
-       u32 ecx = vcpu->arch.regs[VCPU_REGS_RCX];
-       u64 data = (vcpu->arch.regs[VCPU_REGS_RAX] & -1u)
-               | ((u64)(vcpu->arch.regs[VCPU_REGS_RDX] & -1u) << 32);
+       u32 ecx = kvm_rcx_read(vcpu);
+       u64 data = kvm_read_edx_eax(vcpu);
 
        msr.data = data;
        msr.index = ecx;
@@ -4922,7 +4924,7 @@ static int handle_wbinvd(struct kvm_vcpu *vcpu)
 static int handle_xsetbv(struct kvm_vcpu *vcpu)
 {
        u64 new_bv = kvm_read_edx_eax(vcpu);
-       u32 index = kvm_register_read(vcpu, VCPU_REGS_RCX);
+       u32 index = kvm_rcx_read(vcpu);
 
        if (kvm_set_xcr(vcpu, index, new_bv) == 0)
                return kvm_skip_emulated_instruction(vcpu);
@@ -5723,8 +5725,16 @@ void dump_vmcs(void)
        if (secondary_exec_control & SECONDARY_EXEC_TSC_SCALING)
                pr_err("TSC Multiplier = 0x%016llx\n",
                       vmcs_read64(TSC_MULTIPLIER));
-       if (cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW)
-               pr_err("TPR Threshold = 0x%02x\n", vmcs_read32(TPR_THRESHOLD));
+       if (cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW) {
+               if (secondary_exec_control & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY) {
+                       u16 status = vmcs_read16(GUEST_INTR_STATUS);
+                       pr_err("SVI|RVI = %02x|%02x ", status >> 8, status & 0xff);
+               }
+               pr_cont("TPR Threshold = 0x%02x\n", vmcs_read32(TPR_THRESHOLD));
+               if (secondary_exec_control & SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)
+                       pr_err("APIC-access addr = 0x%016llx ", vmcs_read64(APIC_ACCESS_ADDR));
+               pr_cont("virt-APIC addr = 0x%016llx\n", vmcs_read64(VIRTUAL_APIC_PAGE_ADDR));
+       }
        if (pin_based_exec_ctrl & PIN_BASED_POSTED_INTR)
                pr_err("PostedIntrVec = 0x%02x\n", vmcs_read16(POSTED_INTR_NV));
        if ((secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT))
@@ -6431,8 +6441,11 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
         */
        x86_spec_ctrl_set_guest(vmx->spec_ctrl, 0);
 
+       /* L1D Flush includes CPU buffer clear to mitigate MDS */
        if (static_branch_unlikely(&vmx_l1d_should_flush))
                vmx_l1d_flush(vcpu);
+       else if (static_branch_unlikely(&mds_user_clear))
+               mds_clear_cpu_buffers();
 
        if (vcpu->arch.cr2 != read_cr2())
                write_cr2(vcpu->arch.cr2);
@@ -6668,8 +6681,8 @@ free_partial_vcpu:
        return ERR_PTR(err);
 }
 
-#define L1TF_MSG_SMT "L1TF CPU bug present and SMT on, data leak possible. See CVE-2018-3646 and https://www.kernel.org/doc/html/latest/admin-guide/l1tf.html for details.\n"
-#define L1TF_MSG_L1D "L1TF CPU bug present and virtualization mitigation disabled, data leak possible. See CVE-2018-3646 and https://www.kernel.org/doc/html/latest/admin-guide/l1tf.html for details.\n"
+#define L1TF_MSG_SMT "L1TF CPU bug present and SMT on, data leak possible. See CVE-2018-3646 and https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/l1tf.html for details.\n"
+#define L1TF_MSG_L1D "L1TF CPU bug present and virtualization mitigation disabled, data leak possible. See CVE-2018-3646 and https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/l1tf.html for details.\n"
 
 static int vmx_vm_init(struct kvm *kvm)
 {
@@ -6853,30 +6866,6 @@ static void nested_vmx_entry_exit_ctls_update(struct kvm_vcpu *vcpu)
        }
 }
 
-static bool guest_cpuid_has_pmu(struct kvm_vcpu *vcpu)
-{
-       struct kvm_cpuid_entry2 *entry;
-       union cpuid10_eax eax;
-
-       entry = kvm_find_cpuid_entry(vcpu, 0xa, 0);
-       if (!entry)
-               return false;
-
-       eax.full = entry->eax;
-       return (eax.split.version_id > 0);
-}
-
-static void nested_vmx_procbased_ctls_update(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_vmx *vmx = to_vmx(vcpu);
-       bool pmu_enabled = guest_cpuid_has_pmu(vcpu);
-
-       if (pmu_enabled)
-               vmx->nested.msrs.procbased_ctls_high |= CPU_BASED_RDPMC_EXITING;
-       else
-               vmx->nested.msrs.procbased_ctls_high &= ~CPU_BASED_RDPMC_EXITING;
-}
-
 static void update_intel_pt_cfg(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -6965,7 +6954,6 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
        if (nested_vmx_allowed(vcpu)) {
                nested_vmx_cr_fixed1_bits_update(vcpu);
                nested_vmx_entry_exit_ctls_update(vcpu);
-               nested_vmx_procbased_ctls_update(vcpu);
        }
 
        if (boot_cpu_has(X86_FEATURE_INTEL_PT) &&
@@ -7025,7 +7013,8 @@ static inline int u64_shl_div_u64(u64 a, unsigned int shift,
        return 0;
 }
 
-static int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc)
+static int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc,
+                           bool *expired)
 {
        struct vcpu_vmx *vmx;
        u64 tscl, guest_tscl, delta_tsc, lapic_timer_advance_cycles;
@@ -7048,10 +7037,9 @@ static int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc)
 
        /* Convert to host delta tsc if tsc scaling is enabled */
        if (vcpu->arch.tsc_scaling_ratio != kvm_default_tsc_scaling_ratio &&
-                       u64_shl_div_u64(delta_tsc,
+           delta_tsc && u64_shl_div_u64(delta_tsc,
                                kvm_tsc_scaling_ratio_frac_bits,
-                               vcpu->arch.tsc_scaling_ratio,
-                               &delta_tsc))
+                               vcpu->arch.tsc_scaling_ratio, &delta_tsc))
                return -ERANGE;
 
        /*
@@ -7064,7 +7052,8 @@ static int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc)
                return -ERANGE;
 
        vmx->hv_deadline_tsc = tscl + delta_tsc;
-       return delta_tsc == 0;
+       *expired = !delta_tsc;
+       return 0;
 }
 
 static void vmx_cancel_hv_timer(struct kvm_vcpu *vcpu)
@@ -7101,9 +7090,7 @@ static int vmx_write_pml_buffer(struct kvm_vcpu *vcpu)
 {
        struct vmcs12 *vmcs12;
        struct vcpu_vmx *vmx = to_vmx(vcpu);
-       gpa_t gpa;
-       struct page *page = NULL;
-       u64 *pml_address;
+       gpa_t gpa, dst;
 
        if (is_guest_mode(vcpu)) {
                WARN_ON_ONCE(vmx->nested.pml_full);
@@ -7123,15 +7110,13 @@ static int vmx_write_pml_buffer(struct kvm_vcpu *vcpu)
                }
 
                gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS) & ~0xFFFull;
+               dst = vmcs12->pml_address + sizeof(u64) * vmcs12->guest_pml_index;
 
-               page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->pml_address);
-               if (is_error_page(page))
+               if (kvm_write_guest_page(vcpu->kvm, gpa_to_gfn(dst), &gpa,
+                                        offset_in_page(dst), sizeof(gpa)))
                        return 0;
 
-               pml_address = kmap(page);
-               pml_address[vmcs12->guest_pml_index--] = gpa;
-               kunmap(page);
-               kvm_release_page_clean(page);
+               vmcs12->guest_pml_index--;
        }
 
        return 0;
index f879529906b48cd84e99cc0f672210aaeaffeabd..63d37ccce3dc5f02eda451742f6d55c8f82b044f 100644 (file)
@@ -142,8 +142,11 @@ struct nested_vmx {
         * pointers, so we must keep them pinned while L2 runs.
         */
        struct page *apic_access_page;
-       struct page *virtual_apic_page;
-       struct page *pi_desc_page;
+       struct kvm_host_map virtual_apic_map;
+       struct kvm_host_map pi_desc_map;
+
+       struct kvm_host_map msr_bitmap_map;
+
        struct pi_desc *pi_desc;
        bool pi_pending;
        u16 posted_intr_nv;
@@ -169,7 +172,7 @@ struct nested_vmx {
        } smm;
 
        gpa_t hv_evmcs_vmptr;
-       struct page *hv_evmcs_page;
+       struct kvm_host_map hv_evmcs_map;
        struct hv_enlightened_vmcs *hv_evmcs;
 };
 
@@ -257,6 +260,8 @@ struct vcpu_vmx {
 
        unsigned long host_debugctlmsr;
 
+       u64 msr_ia32_power_ctl;
+
        /*
         * Only bits masked by msr_ia32_feature_control_valid_bits can be set in
         * msr_ia32_feature_control. FEATURE_CONTROL_LOCKED is always included
index d75bb97b983cbc9edce0fc7baa3712aaa5199182..536b78c4af6e6f3c067ed7f0497d8a29a01b2984 100644 (file)
@@ -1100,15 +1100,15 @@ EXPORT_SYMBOL_GPL(kvm_get_dr);
 
 bool kvm_rdpmc(struct kvm_vcpu *vcpu)
 {
-       u32 ecx = kvm_register_read(vcpu, VCPU_REGS_RCX);
+       u32 ecx = kvm_rcx_read(vcpu);
        u64 data;
        int err;
 
        err = kvm_pmu_rdpmc(vcpu, ecx, &data);
        if (err)
                return err;
-       kvm_register_write(vcpu, VCPU_REGS_RAX, (u32)data);
-       kvm_register_write(vcpu, VCPU_REGS_RDX, data >> 32);
+       kvm_rax_write(vcpu, (u32)data);
+       kvm_rdx_write(vcpu, data >> 32);
        return err;
 }
 EXPORT_SYMBOL_GPL(kvm_rdpmc);
@@ -1174,6 +1174,9 @@ static u32 emulated_msrs[] = {
        MSR_PLATFORM_INFO,
        MSR_MISC_FEATURES_ENABLES,
        MSR_AMD64_VIRT_SPEC_CTRL,
+       MSR_IA32_POWER_CTL,
+
+       MSR_K7_HWCR,
 };
 
 static unsigned num_emulated_msrs;
@@ -1262,31 +1265,49 @@ static int do_get_msr_feature(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
        return 0;
 }
 
-bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
+static bool __kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
 {
-       if (efer & efer_reserved_bits)
-               return false;
-
        if (efer & EFER_FFXSR && !guest_cpuid_has(vcpu, X86_FEATURE_FXSR_OPT))
-                       return false;
+               return false;
 
        if (efer & EFER_SVME && !guest_cpuid_has(vcpu, X86_FEATURE_SVM))
-                       return false;
+               return false;
+
+       if (efer & (EFER_LME | EFER_LMA) &&
+           !guest_cpuid_has(vcpu, X86_FEATURE_LM))
+               return false;
+
+       if (efer & EFER_NX && !guest_cpuid_has(vcpu, X86_FEATURE_NX))
+               return false;
 
        return true;
+
+}
+bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
+{
+       if (efer & efer_reserved_bits)
+               return false;
+
+       return __kvm_valid_efer(vcpu, efer);
 }
 EXPORT_SYMBOL_GPL(kvm_valid_efer);
 
-static int set_efer(struct kvm_vcpu *vcpu, u64 efer)
+static int set_efer(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 {
        u64 old_efer = vcpu->arch.efer;
+       u64 efer = msr_info->data;
 
-       if (!kvm_valid_efer(vcpu, efer))
-               return 1;
+       if (efer & efer_reserved_bits)
+               return false;
 
-       if (is_paging(vcpu)
-           && (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME))
-               return 1;
+       if (!msr_info->host_initiated) {
+               if (!__kvm_valid_efer(vcpu, efer))
+                       return 1;
+
+               if (is_paging(vcpu) &&
+                   (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME))
+                       return 1;
+       }
 
        efer &= ~EFER_LMA;
        efer |= vcpu->arch.efer & EFER_LMA;
@@ -2279,6 +2300,18 @@ static void kvmclock_sync_fn(struct work_struct *work)
                                        KVMCLOCK_SYNC_PERIOD);
 }
 
+/*
+ * On AMD, HWCR[McStatusWrEn] controls whether setting MCi_STATUS results in #GP.
+ */
+static bool can_set_mci_status(struct kvm_vcpu *vcpu)
+{
+       /* McStatusWrEn enabled? */
+       if (guest_cpuid_is_amd(vcpu))
+               return !!(vcpu->arch.msr_hwcr & BIT_ULL(18));
+
+       return false;
+}
+
 static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 {
        u64 mcg_cap = vcpu->arch.mcg_cap;
@@ -2310,9 +2343,14 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                        if ((offset & 0x3) == 0 &&
                            data != 0 && (data | (1 << 10)) != ~(u64)0)
                                return -1;
+
+                       /* MCi_STATUS */
                        if (!msr_info->host_initiated &&
-                               (offset & 0x3) == 1 && data != 0)
-                               return -1;
+                           (offset & 0x3) == 1 && data != 0) {
+                               if (!can_set_mci_status(vcpu))
+                                       return -1;
+                       }
+
                        vcpu->arch.mce_banks[offset] = data;
                        break;
                }
@@ -2456,13 +2494,16 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                vcpu->arch.arch_capabilities = data;
                break;
        case MSR_EFER:
-               return set_efer(vcpu, data);
+               return set_efer(vcpu, msr_info);
        case MSR_K7_HWCR:
                data &= ~(u64)0x40;     /* ignore flush filter disable */
                data &= ~(u64)0x100;    /* ignore ignne emulation enable */
                data &= ~(u64)0x8;      /* ignore TLB cache disable */
-               data &= ~(u64)0x40000;  /* ignore Mc status write enable */
-               if (data != 0) {
+
+               /* Handle McStatusWrEn */
+               if (data == BIT_ULL(18)) {
+                       vcpu->arch.msr_hwcr = data;
+               } else if (data != 0) {
                        vcpu_unimpl(vcpu, "unimplemented HWCR wrmsr: 0x%llx\n",
                                    data);
                        return 1;
@@ -2736,7 +2777,6 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_K8_SYSCFG:
        case MSR_K8_TSEG_ADDR:
        case MSR_K8_TSEG_MASK:
-       case MSR_K7_HWCR:
        case MSR_VM_HSAVE_PA:
        case MSR_K8_INT_PENDING_MSG:
        case MSR_AMD64_NB_CFG:
@@ -2900,6 +2940,9 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_MISC_FEATURES_ENABLES:
                msr_info->data = vcpu->arch.msr_misc_features_enables;
                break;
+       case MSR_K7_HWCR:
+               msr_info->data = vcpu->arch.msr_hwcr;
+               break;
        default:
                if (kvm_pmu_is_valid_msr(vcpu, msr_info->index))
                        return kvm_pmu_get_msr(vcpu, msr_info->index, &msr_info->data);
@@ -3079,9 +3122,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_MAX_VCPUS:
                r = KVM_MAX_VCPUS;
                break;
-       case KVM_CAP_NR_MEMSLOTS:
-               r = KVM_USER_MEM_SLOTS;
-               break;
        case KVM_CAP_PV_MMU:    /* obsolete */
                r = 0;
                break;
@@ -5521,9 +5561,9 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
                                     unsigned int bytes,
                                     struct x86_exception *exception)
 {
+       struct kvm_host_map map;
        struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
        gpa_t gpa;
-       struct page *page;
        char *kaddr;
        bool exchanged;
 
@@ -5540,12 +5580,11 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
        if (((gpa + bytes - 1) & PAGE_MASK) != (gpa & PAGE_MASK))
                goto emul_write;
 
-       page = kvm_vcpu_gfn_to_page(vcpu, gpa >> PAGE_SHIFT);
-       if (is_error_page(page))
+       if (kvm_vcpu_map(vcpu, gpa_to_gfn(gpa), &map))
                goto emul_write;
 
-       kaddr = kmap_atomic(page);
-       kaddr += offset_in_page(gpa);
+       kaddr = map.hva + offset_in_page(gpa);
+
        switch (bytes) {
        case 1:
                exchanged = CMPXCHG_TYPE(u8, kaddr, old, new);
@@ -5562,13 +5601,12 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
        default:
                BUG();
        }
-       kunmap_atomic(kaddr);
-       kvm_release_page_dirty(page);
+
+       kvm_vcpu_unmap(vcpu, &map, true);
 
        if (!exchanged)
                return X86EMUL_CMPXCHG_FAILED;
 
-       kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
        kvm_page_track_write(vcpu, gpa, new, bytes);
 
        return X86EMUL_CONTINUE;
@@ -6558,7 +6596,7 @@ static int complete_fast_pio_out(struct kvm_vcpu *vcpu)
 static int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size,
                            unsigned short port)
 {
-       unsigned long val = kvm_register_read(vcpu, VCPU_REGS_RAX);
+       unsigned long val = kvm_rax_read(vcpu);
        int ret = emulator_pio_out_emulated(&vcpu->arch.emulate_ctxt,
                                            size, port, &val, 1);
        if (ret)
@@ -6593,8 +6631,7 @@ static int complete_fast_pio_in(struct kvm_vcpu *vcpu)
        }
 
        /* For size less than 4 we merge, else we zero extend */
-       val = (vcpu->arch.pio.size < 4) ? kvm_register_read(vcpu, VCPU_REGS_RAX)
-                                       : 0;
+       val = (vcpu->arch.pio.size < 4) ? kvm_rax_read(vcpu) : 0;
 
        /*
         * Since vcpu->arch.pio.count == 1 let emulator_pio_in_emulated perform
@@ -6602,7 +6639,7 @@ static int complete_fast_pio_in(struct kvm_vcpu *vcpu)
         */
        emulator_pio_in_emulated(&vcpu->arch.emulate_ctxt, vcpu->arch.pio.size,
                                 vcpu->arch.pio.port, &val, 1);
-       kvm_register_write(vcpu, VCPU_REGS_RAX, val);
+       kvm_rax_write(vcpu, val);
 
        return kvm_skip_emulated_instruction(vcpu);
 }
@@ -6614,12 +6651,12 @@ static int kvm_fast_pio_in(struct kvm_vcpu *vcpu, int size,
        int ret;
 
        /* For size less than 4 we merge, else we zero extend */
-       val = (size < 4) ? kvm_register_read(vcpu, VCPU_REGS_RAX) : 0;
+       val = (size < 4) ? kvm_rax_read(vcpu) : 0;
 
        ret = emulator_pio_in_emulated(&vcpu->arch.emulate_ctxt, size, port,
                                       &val, 1);
        if (ret) {
-               kvm_register_write(vcpu, VCPU_REGS_RAX, val);
+               kvm_rax_write(vcpu, val);
                return ret;
        }
 
@@ -6698,10 +6735,8 @@ static void kvm_hyperv_tsc_notifier(void)
 }
 #endif
 
-static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
-                                    void *data)
+static void __kvmclock_cpufreq_notifier(struct cpufreq_freqs *freq, int cpu)
 {
-       struct cpufreq_freqs *freq = data;
        struct kvm *kvm;
        struct kvm_vcpu *vcpu;
        int i, send_ipi = 0;
@@ -6745,17 +6780,12 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va
         *
         */
 
-       if (val == CPUFREQ_PRECHANGE && freq->old > freq->new)
-               return 0;
-       if (val == CPUFREQ_POSTCHANGE && freq->old < freq->new)
-               return 0;
-
-       smp_call_function_single(freq->cpu, tsc_khz_changed, freq, 1);
+       smp_call_function_single(cpu, tsc_khz_changed, freq, 1);
 
        spin_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list) {
                kvm_for_each_vcpu(i, vcpu, kvm) {
-                       if (vcpu->cpu != freq->cpu)
+                       if (vcpu->cpu != cpu)
                                continue;
                        kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
                        if (vcpu->cpu != smp_processor_id())
@@ -6777,8 +6807,24 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va
                 * guest context is entered kvmclock will be updated,
                 * so the guest will not see stale values.
                 */
-               smp_call_function_single(freq->cpu, tsc_khz_changed, freq, 1);
+               smp_call_function_single(cpu, tsc_khz_changed, freq, 1);
        }
+}
+
+static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
+                                    void *data)
+{
+       struct cpufreq_freqs *freq = data;
+       int cpu;
+
+       if (val == CPUFREQ_PRECHANGE && freq->old > freq->new)
+               return 0;
+       if (val == CPUFREQ_POSTCHANGE && freq->old < freq->new)
+               return 0;
+
+       for_each_cpu(cpu, freq->policy->cpus)
+               __kvmclock_cpufreq_notifier(freq, cpu);
+
        return 0;
 }
 
@@ -6845,10 +6891,20 @@ static unsigned long kvm_get_guest_ip(void)
        return ip;
 }
 
+static void kvm_handle_intel_pt_intr(void)
+{
+       struct kvm_vcpu *vcpu = __this_cpu_read(current_vcpu);
+
+       kvm_make_request(KVM_REQ_PMI, vcpu);
+       __set_bit(MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI_BIT,
+                       (unsigned long *)&vcpu->arch.pmu.global_status);
+}
+
 static struct perf_guest_info_callbacks kvm_guest_cbs = {
        .is_in_guest            = kvm_is_in_guest,
        .is_user_mode           = kvm_is_user_mode,
        .get_guest_ip           = kvm_get_guest_ip,
+       .handle_intel_pt_intr   = kvm_handle_intel_pt_intr,
 };
 
 static void kvm_set_mmio_spte_mask(void)
@@ -7124,11 +7180,11 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
        if (kvm_hv_hypercall_enabled(vcpu->kvm))
                return kvm_hv_hypercall(vcpu);
 
-       nr = kvm_register_read(vcpu, VCPU_REGS_RAX);
-       a0 = kvm_register_read(vcpu, VCPU_REGS_RBX);
-       a1 = kvm_register_read(vcpu, VCPU_REGS_RCX);
-       a2 = kvm_register_read(vcpu, VCPU_REGS_RDX);
-       a3 = kvm_register_read(vcpu, VCPU_REGS_RSI);
+       nr = kvm_rax_read(vcpu);
+       a0 = kvm_rbx_read(vcpu);
+       a1 = kvm_rcx_read(vcpu);
+       a2 = kvm_rdx_read(vcpu);
+       a3 = kvm_rsi_read(vcpu);
 
        trace_kvm_hypercall(nr, a0, a1, a2, a3);
 
@@ -7169,7 +7225,7 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
 out:
        if (!op_64_bit)
                ret = (u32)ret;
-       kvm_register_write(vcpu, VCPU_REGS_RAX, ret);
+       kvm_rax_write(vcpu, ret);
 
        ++vcpu->stat.hypercalls;
        return kvm_skip_emulated_instruction(vcpu);
@@ -8271,23 +8327,23 @@ static void __get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
                emulator_writeback_register_cache(&vcpu->arch.emulate_ctxt);
                vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
        }
-       regs->rax = kvm_register_read(vcpu, VCPU_REGS_RAX);
-       regs->rbx = kvm_register_read(vcpu, VCPU_REGS_RBX);
-       regs->rcx = kvm_register_read(vcpu, VCPU_REGS_RCX);
-       regs->rdx = kvm_register_read(vcpu, VCPU_REGS_RDX);
-       regs->rsi = kvm_register_read(vcpu, VCPU_REGS_RSI);
-       regs->rdi = kvm_register_read(vcpu, VCPU_REGS_RDI);
-       regs->rsp = kvm_register_read(vcpu, VCPU_REGS_RSP);
-       regs->rbp = kvm_register_read(vcpu, VCPU_REGS_RBP);
+       regs->rax = kvm_rax_read(vcpu);
+       regs->rbx = kvm_rbx_read(vcpu);
+       regs->rcx = kvm_rcx_read(vcpu);
+       regs->rdx = kvm_rdx_read(vcpu);
+       regs->rsi = kvm_rsi_read(vcpu);
+       regs->rdi = kvm_rdi_read(vcpu);
+       regs->rsp = kvm_rsp_read(vcpu);
+       regs->rbp = kvm_rbp_read(vcpu);
 #ifdef CONFIG_X86_64
-       regs->r8 = kvm_register_read(vcpu, VCPU_REGS_R8);
-       regs->r9 = kvm_register_read(vcpu, VCPU_REGS_R9);
-       regs->r10 = kvm_register_read(vcpu, VCPU_REGS_R10);
-       regs->r11 = kvm_register_read(vcpu, VCPU_REGS_R11);
-       regs->r12 = kvm_register_read(vcpu, VCPU_REGS_R12);
-       regs->r13 = kvm_register_read(vcpu, VCPU_REGS_R13);
-       regs->r14 = kvm_register_read(vcpu, VCPU_REGS_R14);
-       regs->r15 = kvm_register_read(vcpu, VCPU_REGS_R15);
+       regs->r8 = kvm_r8_read(vcpu);
+       regs->r9 = kvm_r9_read(vcpu);
+       regs->r10 = kvm_r10_read(vcpu);
+       regs->r11 = kvm_r11_read(vcpu);
+       regs->r12 = kvm_r12_read(vcpu);
+       regs->r13 = kvm_r13_read(vcpu);
+       regs->r14 = kvm_r14_read(vcpu);
+       regs->r15 = kvm_r15_read(vcpu);
 #endif
 
        regs->rip = kvm_rip_read(vcpu);
@@ -8307,23 +8363,23 @@ static void __set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        vcpu->arch.emulate_regs_need_sync_from_vcpu = true;
        vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
 
-       kvm_register_write(vcpu, VCPU_REGS_RAX, regs->rax);
-       kvm_register_write(vcpu, VCPU_REGS_RBX, regs->rbx);
-       kvm_register_write(vcpu, VCPU_REGS_RCX, regs->rcx);
-       kvm_register_write(vcpu, VCPU_REGS_RDX, regs->rdx);
-       kvm_register_write(vcpu, VCPU_REGS_RSI, regs->rsi);
-       kvm_register_write(vcpu, VCPU_REGS_RDI, regs->rdi);
-       kvm_register_write(vcpu, VCPU_REGS_RSP, regs->rsp);
-       kvm_register_write(vcpu, VCPU_REGS_RBP, regs->rbp);
+       kvm_rax_write(vcpu, regs->rax);
+       kvm_rbx_write(vcpu, regs->rbx);
+       kvm_rcx_write(vcpu, regs->rcx);
+       kvm_rdx_write(vcpu, regs->rdx);
+       kvm_rsi_write(vcpu, regs->rsi);
+       kvm_rdi_write(vcpu, regs->rdi);
+       kvm_rsp_write(vcpu, regs->rsp);
+       kvm_rbp_write(vcpu, regs->rbp);
 #ifdef CONFIG_X86_64
-       kvm_register_write(vcpu, VCPU_REGS_R8, regs->r8);
-       kvm_register_write(vcpu, VCPU_REGS_R9, regs->r9);
-       kvm_register_write(vcpu, VCPU_REGS_R10, regs->r10);
-       kvm_register_write(vcpu, VCPU_REGS_R11, regs->r11);
-       kvm_register_write(vcpu, VCPU_REGS_R12, regs->r12);
-       kvm_register_write(vcpu, VCPU_REGS_R13, regs->r13);
-       kvm_register_write(vcpu, VCPU_REGS_R14, regs->r14);
-       kvm_register_write(vcpu, VCPU_REGS_R15, regs->r15);
+       kvm_r8_write(vcpu, regs->r8);
+       kvm_r9_write(vcpu, regs->r9);
+       kvm_r10_write(vcpu, regs->r10);
+       kvm_r11_write(vcpu, regs->r11);
+       kvm_r12_write(vcpu, regs->r12);
+       kvm_r13_write(vcpu, regs->r13);
+       kvm_r14_write(vcpu, regs->r14);
+       kvm_r15_write(vcpu, regs->r15);
 #endif
 
        kvm_rip_write(vcpu, regs->rip);
index 534d3f28bb01a9a302d0b40d6fe6fc5483a5d97b..a470ff0868c58e1d6f8ceb88dac3a6e5bd0f0a1b 100644 (file)
@@ -345,6 +345,16 @@ static inline void kvm_after_interrupt(struct kvm_vcpu *vcpu)
        __this_cpu_write(current_vcpu, NULL);
 }
 
+
+static inline bool kvm_pat_valid(u64 data)
+{
+       if (data & 0xF8F8F8F8F8F8F8F8ull)
+               return false;
+       /* 0, 1, 4, 5, 6, 7 are valid values.  */
+       return (data | ((data & 0x0202020202020202ull) << 1)) == data;
+}
+
 void kvm_load_guest_xcr0(struct kvm_vcpu *vcpu);
 void kvm_put_guest_xcr0(struct kvm_vcpu *vcpu);
+
 #endif
index 92e4c4b85bbaadec13e54fb614e8a5dc369e2ff5..fab095362c503b99e349ca073babd42edd4a68e5 100644 (file)
@@ -203,7 +203,7 @@ static __init int setup_hugepagesz(char *opt)
 }
 __setup("hugepagesz=", setup_hugepagesz);
 
-#if (defined(CONFIG_MEMORY_ISOLATION) && defined(CONFIG_COMPACTION)) || defined(CONFIG_CMA)
+#ifdef CONFIG_CONTIG_ALLOC
 static __init int gigantic_pages_init(void)
 {
        /* With compaction or CMA we can allocate gigantic pages at runtime */
index 85c94f9a87f8c6247ddb0f645f69fee610cd1fe5..075e568098f25d86910033b994cb9710b5f1a56f 100644 (file)
@@ -850,24 +850,25 @@ void __init mem_init(void)
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-int arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap,
-               bool want_memblock)
+int arch_add_memory(int nid, u64 start, u64 size,
+                       struct mhp_restrictions *restrictions)
 {
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
 
-       return __add_pages(nid, start_pfn, nr_pages, altmap, want_memblock);
+       return __add_pages(nid, start_pfn, nr_pages, restrictions);
 }
 
 #ifdef CONFIG_MEMORY_HOTREMOVE
-int arch_remove_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap)
+void arch_remove_memory(int nid, u64 start, u64 size,
+                       struct vmem_altmap *altmap)
 {
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
        struct zone *zone;
 
        zone = page_zone(pfn_to_page(start_pfn));
-       return __remove_pages(zone, start_pfn, nr_pages, altmap);
+       __remove_pages(zone, start_pfn, nr_pages, altmap);
 }
 #endif
 #endif
index bccff68e32670ddd70762020b68551053c7c3a58..62fc457f3849af0bf867fa202149f4fa556cd6dc 100644 (file)
 
 #include "ident_map.c"
 
+#define DEFINE_POPULATE(fname, type1, type2, init)             \
+static inline void fname##_init(struct mm_struct *mm,          \
+               type1##_t *arg1, type2##_t *arg2, bool init)    \
+{                                                              \
+       if (init)                                               \
+               fname##_safe(mm, arg1, arg2);                   \
+       else                                                    \
+               fname(mm, arg1, arg2);                          \
+}
+
+DEFINE_POPULATE(p4d_populate, p4d, pud, init)
+DEFINE_POPULATE(pgd_populate, pgd, p4d, init)
+DEFINE_POPULATE(pud_populate, pud, pmd, init)
+DEFINE_POPULATE(pmd_populate_kernel, pmd, pte, init)
+
+#define DEFINE_ENTRY(type1, type2, init)                       \
+static inline void set_##type1##_init(type1##_t *arg1,         \
+                       type2##_t arg2, bool init)              \
+{                                                              \
+       if (init)                                               \
+               set_##type1##_safe(arg1, arg2);                 \
+       else                                                    \
+               set_##type1(arg1, arg2);                        \
+}
+
+DEFINE_ENTRY(p4d, p4d, init)
+DEFINE_ENTRY(pud, pud, init)
+DEFINE_ENTRY(pmd, pmd, init)
+DEFINE_ENTRY(pte, pte, init)
+
+
 /*
  * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the
  * physical space so we can cache the place of the first one and move
@@ -414,7 +445,7 @@ void __init cleanup_highmap(void)
  */
 static unsigned long __meminit
 phys_pte_init(pte_t *pte_page, unsigned long paddr, unsigned long paddr_end,
-             pgprot_t prot)
+             pgprot_t prot, bool init)
 {
        unsigned long pages = 0, paddr_next;
        unsigned long paddr_last = paddr_end;
@@ -432,7 +463,7 @@ phys_pte_init(pte_t *pte_page, unsigned long paddr, unsigned long paddr_end,
                                             E820_TYPE_RAM) &&
                            !e820__mapped_any(paddr & PAGE_MASK, paddr_next,
                                             E820_TYPE_RESERVED_KERN))
-                               set_pte_safe(pte, __pte(0));
+                               set_pte_init(pte, __pte(0), init);
                        continue;
                }
 
@@ -452,7 +483,7 @@ phys_pte_init(pte_t *pte_page, unsigned long paddr, unsigned long paddr_end,
                        pr_info("   pte=%p addr=%lx pte=%016lx\n", pte, paddr,
                                pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL).pte);
                pages++;
-               set_pte_safe(pte, pfn_pte(paddr >> PAGE_SHIFT, prot));
+               set_pte_init(pte, pfn_pte(paddr >> PAGE_SHIFT, prot), init);
                paddr_last = (paddr & PAGE_MASK) + PAGE_SIZE;
        }
 
@@ -468,7 +499,7 @@ phys_pte_init(pte_t *pte_page, unsigned long paddr, unsigned long paddr_end,
  */
 static unsigned long __meminit
 phys_pmd_init(pmd_t *pmd_page, unsigned long paddr, unsigned long paddr_end,
-             unsigned long page_size_mask, pgprot_t prot)
+             unsigned long page_size_mask, pgprot_t prot, bool init)
 {
        unsigned long pages = 0, paddr_next;
        unsigned long paddr_last = paddr_end;
@@ -487,7 +518,7 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long paddr, unsigned long paddr_end,
                                             E820_TYPE_RAM) &&
                            !e820__mapped_any(paddr & PMD_MASK, paddr_next,
                                             E820_TYPE_RESERVED_KERN))
-                               set_pmd_safe(pmd, __pmd(0));
+                               set_pmd_init(pmd, __pmd(0), init);
                        continue;
                }
 
@@ -496,7 +527,8 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long paddr, unsigned long paddr_end,
                                spin_lock(&init_mm.page_table_lock);
                                pte = (pte_t *)pmd_page_vaddr(*pmd);
                                paddr_last = phys_pte_init(pte, paddr,
-                                                          paddr_end, prot);
+                                                          paddr_end, prot,
+                                                          init);
                                spin_unlock(&init_mm.page_table_lock);
                                continue;
                        }
@@ -524,19 +556,20 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long paddr, unsigned long paddr_end,
                if (page_size_mask & (1<<PG_LEVEL_2M)) {
                        pages++;
                        spin_lock(&init_mm.page_table_lock);
-                       set_pte_safe((pte_t *)pmd,
-                               pfn_pte((paddr & PMD_MASK) >> PAGE_SHIFT,
-                                       __pgprot(pgprot_val(prot) | _PAGE_PSE)));
+                       set_pte_init((pte_t *)pmd,
+                                    pfn_pte((paddr & PMD_MASK) >> PAGE_SHIFT,
+                                            __pgprot(pgprot_val(prot) | _PAGE_PSE)),
+                                    init);
                        spin_unlock(&init_mm.page_table_lock);
                        paddr_last = paddr_next;
                        continue;
                }
 
                pte = alloc_low_page();
-               paddr_last = phys_pte_init(pte, paddr, paddr_end, new_prot);
+               paddr_last = phys_pte_init(pte, paddr, paddr_end, new_prot, init);
 
                spin_lock(&init_mm.page_table_lock);
-               pmd_populate_kernel_safe(&init_mm, pmd, pte);
+               pmd_populate_kernel_init(&init_mm, pmd, pte, init);
                spin_unlock(&init_mm.page_table_lock);
        }
        update_page_count(PG_LEVEL_2M, pages);
@@ -551,7 +584,7 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long paddr, unsigned long paddr_end,
  */
 static unsigned long __meminit
 phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end,
-             unsigned long page_size_mask)
+             unsigned long page_size_mask, bool init)
 {
        unsigned long pages = 0, paddr_next;
        unsigned long paddr_last = paddr_end;
@@ -573,7 +606,7 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end,
                                             E820_TYPE_RAM) &&
                            !e820__mapped_any(paddr & PUD_MASK, paddr_next,
                                             E820_TYPE_RESERVED_KERN))
-                               set_pud_safe(pud, __pud(0));
+                               set_pud_init(pud, __pud(0), init);
                        continue;
                }
 
@@ -583,7 +616,7 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end,
                                paddr_last = phys_pmd_init(pmd, paddr,
                                                           paddr_end,
                                                           page_size_mask,
-                                                          prot);
+                                                          prot, init);
                                continue;
                        }
                        /*
@@ -610,9 +643,10 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end,
                if (page_size_mask & (1<<PG_LEVEL_1G)) {
                        pages++;
                        spin_lock(&init_mm.page_table_lock);
-                       set_pte_safe((pte_t *)pud,
-                               pfn_pte((paddr & PUD_MASK) >> PAGE_SHIFT,
-                                       PAGE_KERNEL_LARGE));
+                       set_pte_init((pte_t *)pud,
+                                    pfn_pte((paddr & PUD_MASK) >> PAGE_SHIFT,
+                                            PAGE_KERNEL_LARGE),
+                                    init);
                        spin_unlock(&init_mm.page_table_lock);
                        paddr_last = paddr_next;
                        continue;
@@ -620,10 +654,10 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end,
 
                pmd = alloc_low_page();
                paddr_last = phys_pmd_init(pmd, paddr, paddr_end,
-                                          page_size_mask, prot);
+                                          page_size_mask, prot, init);
 
                spin_lock(&init_mm.page_table_lock);
-               pud_populate_safe(&init_mm, pud, pmd);
+               pud_populate_init(&init_mm, pud, pmd, init);
                spin_unlock(&init_mm.page_table_lock);
        }
 
@@ -634,14 +668,15 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end,
 
 static unsigned long __meminit
 phys_p4d_init(p4d_t *p4d_page, unsigned long paddr, unsigned long paddr_end,
-             unsigned long page_size_mask)
+             unsigned long page_size_mask, bool init)
 {
        unsigned long paddr_next, paddr_last = paddr_end;
        unsigned long vaddr = (unsigned long)__va(paddr);
        int i = p4d_index(vaddr);
 
        if (!pgtable_l5_enabled())
-               return phys_pud_init((pud_t *) p4d_page, paddr, paddr_end, page_size_mask);
+               return phys_pud_init((pud_t *) p4d_page, paddr, paddr_end,
+                                    page_size_mask, init);
 
        for (; i < PTRS_PER_P4D; i++, paddr = paddr_next) {
                p4d_t *p4d;
@@ -657,39 +692,34 @@ phys_p4d_init(p4d_t *p4d_page, unsigned long paddr, unsigned long paddr_end,
                                             E820_TYPE_RAM) &&
                            !e820__mapped_any(paddr & P4D_MASK, paddr_next,
                                             E820_TYPE_RESERVED_KERN))
-                               set_p4d_safe(p4d, __p4d(0));
+                               set_p4d_init(p4d, __p4d(0), init);
                        continue;
                }
 
                if (!p4d_none(*p4d)) {
                        pud = pud_offset(p4d, 0);
-                       paddr_last = phys_pud_init(pud, paddr,
-                                       paddr_end,
-                                       page_size_mask);
+                       paddr_last = phys_pud_init(pud, paddr, paddr_end,
+                                                  page_size_mask, init);
                        continue;
                }
 
                pud = alloc_low_page();
                paddr_last = phys_pud_init(pud, paddr, paddr_end,
-                                          page_size_mask);
+                                          page_size_mask, init);
 
                spin_lock(&init_mm.page_table_lock);
-               p4d_populate_safe(&init_mm, p4d, pud);
+               p4d_populate_init(&init_mm, p4d, pud, init);
                spin_unlock(&init_mm.page_table_lock);
        }
 
        return paddr_last;
 }
 
-/*
- * Create page table mapping for the physical memory for specific physical
- * addresses. The virtual and physical addresses have to be aligned on PMD level
- * down. It returns the last physical address mapped.
- */
-unsigned long __meminit
-kernel_physical_mapping_init(unsigned long paddr_start,
-                            unsigned long paddr_end,
-                            unsigned long page_size_mask)
+static unsigned long __meminit
+__kernel_physical_mapping_init(unsigned long paddr_start,
+                              unsigned long paddr_end,
+                              unsigned long page_size_mask,
+                              bool init)
 {
        bool pgd_changed = false;
        unsigned long vaddr, vaddr_start, vaddr_end, vaddr_next, paddr_last;
@@ -709,19 +739,22 @@ kernel_physical_mapping_init(unsigned long paddr_start,
                        p4d = (p4d_t *)pgd_page_vaddr(*pgd);
                        paddr_last = phys_p4d_init(p4d, __pa(vaddr),
                                                   __pa(vaddr_end),
-                                                  page_size_mask);
+                                                  page_size_mask,
+                                                  init);
                        continue;
                }
 
                p4d = alloc_low_page();
                paddr_last = phys_p4d_init(p4d, __pa(vaddr), __pa(vaddr_end),
-                                          page_size_mask);
+                                          page_size_mask, init);
 
                spin_lock(&init_mm.page_table_lock);
                if (pgtable_l5_enabled())
-                       pgd_populate_safe(&init_mm, pgd, p4d);
+                       pgd_populate_init(&init_mm, pgd, p4d, init);
                else
-                       p4d_populate_safe(&init_mm, p4d_offset(pgd, vaddr), (pud_t *) p4d);
+                       p4d_populate_init(&init_mm, p4d_offset(pgd, vaddr),
+                                         (pud_t *) p4d, init);
+
                spin_unlock(&init_mm.page_table_lock);
                pgd_changed = true;
        }
@@ -732,6 +765,37 @@ kernel_physical_mapping_init(unsigned long paddr_start,
        return paddr_last;
 }
 
+
+/*
+ * Create page table mapping for the physical memory for specific physical
+ * addresses. Note that it can only be used to populate non-present entries.
+ * The virtual and physical addresses have to be aligned on PMD level
+ * down. It returns the last physical address mapped.
+ */
+unsigned long __meminit
+kernel_physical_mapping_init(unsigned long paddr_start,
+                            unsigned long paddr_end,
+                            unsigned long page_size_mask)
+{
+       return __kernel_physical_mapping_init(paddr_start, paddr_end,
+                                             page_size_mask, true);
+}
+
+/*
+ * This function is similar to kernel_physical_mapping_init() above with the
+ * exception that it uses set_{pud,pmd}() instead of the set_{pud,pte}_safe()
+ * when updating the mapping. The caller is responsible to flush the TLBs after
+ * the function returns.
+ */
+unsigned long __meminit
+kernel_physical_mapping_change(unsigned long paddr_start,
+                              unsigned long paddr_end,
+                              unsigned long page_size_mask)
+{
+       return __kernel_physical_mapping_init(paddr_start, paddr_end,
+                                             page_size_mask, false);
+}
+
 #ifndef CONFIG_NUMA
 void __init initmem_init(void)
 {
@@ -777,11 +841,11 @@ static void update_end_of_memory_vars(u64 start, u64 size)
 }
 
 int add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
-               struct vmem_altmap *altmap, bool want_memblock)
+                               struct mhp_restrictions *restrictions)
 {
        int ret;
 
-       ret = __add_pages(nid, start_pfn, nr_pages, altmap, want_memblock);
+       ret = __add_pages(nid, start_pfn, nr_pages, restrictions);
        WARN_ON_ONCE(ret);
 
        /* update max_pfn, max_low_pfn and high_memory */
@@ -791,15 +855,15 @@ int add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
        return ret;
 }
 
-int arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap,
-               bool want_memblock)
+int arch_add_memory(int nid, u64 start, u64 size,
+                       struct mhp_restrictions *restrictions)
 {
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
 
        init_memory_mapping(start, start + size);
 
-       return add_pages(nid, start_pfn, nr_pages, altmap, want_memblock);
+       return add_pages(nid, start_pfn, nr_pages, restrictions);
 }
 
 #define PAGE_INUSE 0xFD
@@ -1141,24 +1205,20 @@ kernel_physical_mapping_remove(unsigned long start, unsigned long end)
        remove_pagetable(start, end, true, NULL);
 }
 
-int __ref arch_remove_memory(int nid, u64 start, u64 size,
-                               struct vmem_altmap *altmap)
+void __ref arch_remove_memory(int nid, u64 start, u64 size,
+                             struct vmem_altmap *altmap)
 {
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
        struct page *page = pfn_to_page(start_pfn);
        struct zone *zone;
-       int ret;
 
        /* With altmap the first mapped page is offset from @start */
        if (altmap)
                page += vmem_altmap_offset(altmap);
        zone = page_zone(page);
-       ret = __remove_pages(zone, start_pfn, nr_pages, altmap);
-       WARN_ON_ONCE(ret);
+       __remove_pages(zone, start_pfn, nr_pages, altmap);
        kernel_physical_mapping_remove(start, start + size);
-
-       return ret;
 }
 #endif
 #endif /* CONFIG_MEMORY_HOTPLUG */
index 385afa2b9e17a7ac15683b0d75252274499a8bc0..51f50a7a07ef7842c7e038f58066314dc04d01b5 100644 (file)
@@ -301,9 +301,13 @@ static int __init early_set_memory_enc_dec(unsigned long vaddr,
                else
                        split_page_size_mask = 1 << PG_LEVEL_2M;
 
-               kernel_physical_mapping_init(__pa(vaddr & pmask),
-                                            __pa((vaddr_end & pmask) + psize),
-                                            split_page_size_mask);
+               /*
+                * kernel_physical_mapping_change() does not flush the TLBs, so
+                * a TLB flush is required after we exit from the for loop.
+                */
+               kernel_physical_mapping_change(__pa(vaddr & pmask),
+                                              __pa((vaddr_end & pmask) + psize),
+                                              split_page_size_mask);
        }
 
        ret = 0;
index 319bde386d5f4a9402f695ffb6948b76b58f47bd..eeae142062ed4b06afbb8247a08d3a19b2f00766 100644 (file)
@@ -13,6 +13,9 @@ void early_ioremap_page_table_range_init(void);
 unsigned long kernel_physical_mapping_init(unsigned long start,
                                             unsigned long end,
                                             unsigned long page_size_mask);
+unsigned long kernel_physical_mapping_change(unsigned long start,
+                                            unsigned long end,
+                                            unsigned long page_size_mask);
 void zone_sizes_init(void);
 
 extern int after_bootmem;
index 52e55108404ebfd9f003bde6dd08f4be98531a9f..d3a73f9335e11c3f8f285ab18ce1ae4f04b0c27f 100644 (file)
@@ -1119,6 +1119,8 @@ static const struct dmi_system_id pciirq_dmi_table[] __initconst = {
 
 void __init pcibios_irq_init(void)
 {
+       struct irq_routing_table *rtable = NULL;
+
        DBG(KERN_DEBUG "PCI: IRQ init\n");
 
        if (raw_pci_ops == NULL)
@@ -1129,8 +1131,10 @@ void __init pcibios_irq_init(void)
        pirq_table = pirq_find_routing_table();
 
 #ifdef CONFIG_PCI_BIOS
-       if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
+       if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN)) {
                pirq_table = pcibios_get_irq_routing_table();
+               rtable = pirq_table;
+       }
 #endif
        if (pirq_table) {
                pirq_peer_trick();
@@ -1145,8 +1149,10 @@ void __init pcibios_irq_init(void)
                 * If we're using the I/O APIC, avoid using the PCI IRQ
                 * routing table
                 */
-               if (io_apic_assign_pci_irqs)
+               if (io_apic_assign_pci_irqs) {
+                       kfree(rtable);
                        pirq_table = NULL;
+               }
        }
 
        x86_init.pci.fixup_irqs();
index ac9e7bf49b6670216f9220979a261603304cc311..0296c5b55e6f6b73ea181713cfc1f256fa707cb9 100644 (file)
@@ -220,10 +220,26 @@ static u32 __init olpc_dt_get_board_revision(void)
        return be32_to_cpu(rev);
 }
 
+int olpc_dt_compatible_match(phandle node, const char *compat)
+{
+       char buf[64], *p;
+       int plen, len;
+
+       plen = olpc_dt_getproperty(node, "compatible", buf, sizeof(buf));
+       if (plen <= 0)
+               return 0;
+
+       len = strlen(compat);
+       for (p = buf; p < buf + plen; p += strlen(p) + 1) {
+               if (strcmp(p, compat) == 0)
+                       return 1;
+       }
+
+       return 0;
+}
+
 void __init olpc_dt_fixup(void)
 {
-       int r;
-       char buf[64];
        phandle node;
        u32 board_rev;
 
@@ -231,41 +247,66 @@ void __init olpc_dt_fixup(void)
        if (!node)
                return;
 
-       /*
-        * If the battery node has a compatible property, we are running a new
-        * enough firmware and don't have fixups to make.
-        */
-       r = olpc_dt_getproperty(node, "compatible", buf, sizeof(buf));
-       if (r > 0)
-               return;
-
-       pr_info("PROM DT: Old firmware detected, applying fixes\n");
-
-       /* Add olpc,xo1-battery compatible marker to battery node */
-       olpc_dt_interpret("\" /battery@0\" find-device"
-               " \" olpc,xo1-battery\" +compatible"
-               " device-end");
-
        board_rev = olpc_dt_get_board_revision();
        if (!board_rev)
                return;
 
        if (board_rev >= olpc_board_pre(0xd0)) {
-               /* XO-1.5: add dcon device */
-               olpc_dt_interpret("\" /pci/display@1\" find-device"
-                       " new-device"
-                       " \" dcon\" device-name \" olpc,xo1-dcon\" +compatible"
-                       " finish-device device-end");
+               /* XO-1.5 */
+
+               if (olpc_dt_compatible_match(node, "olpc,xo1.5-battery"))
+                       return;
+
+               /* Add olpc,xo1.5-battery compatible marker to battery node */
+               olpc_dt_interpret("\" /battery@0\" find-device");
+               olpc_dt_interpret("  \" olpc,xo1.5-battery\" +compatible");
+               olpc_dt_interpret("device-end");
+
+               if (olpc_dt_compatible_match(node, "olpc,xo1-battery")) {
+                       /*
+                        * If we have a olpc,xo1-battery compatible, then we're
+                        * running a new enough firmware that already has
+                        * the dcon node.
+                        */
+                       return;
+               }
+
+               /* Add dcon device */
+               olpc_dt_interpret("\" /pci/display@1\" find-device");
+               olpc_dt_interpret("  new-device");
+               olpc_dt_interpret("    \" dcon\" device-name");
+               olpc_dt_interpret("    \" olpc,xo1-dcon\" +compatible");
+               olpc_dt_interpret("  finish-device");
+               olpc_dt_interpret("device-end");
        } else {
-               /* XO-1: add dcon device, mark RTC as olpc,xo1-rtc */
-               olpc_dt_interpret("\" /pci/display@1,1\" find-device"
-                       " new-device"
-                       " \" dcon\" device-name \" olpc,xo1-dcon\" +compatible"
-                       " finish-device device-end"
-                       " \" /rtc\" find-device"
-                       " \" olpc,xo1-rtc\" +compatible"
-                       " device-end");
+               /* XO-1 */
+
+               if (olpc_dt_compatible_match(node, "olpc,xo1-battery")) {
+                       /*
+                        * If we have a olpc,xo1-battery compatible, then we're
+                        * running a new enough firmware that already has
+                        * the dcon and RTC nodes.
+                        */
+                       return;
+               }
+
+               /* Add dcon device, mark RTC as olpc,xo1-rtc */
+               olpc_dt_interpret("\" /pci/display@1,1\" find-device");
+               olpc_dt_interpret("  new-device");
+               olpc_dt_interpret("    \" dcon\" device-name");
+               olpc_dt_interpret("    \" olpc,xo1-dcon\" +compatible");
+               olpc_dt_interpret("  finish-device");
+               olpc_dt_interpret("device-end");
+
+               olpc_dt_interpret("\" /rtc\" find-device");
+               olpc_dt_interpret(" \" olpc,xo1-rtc\" +compatible");
+               olpc_dt_interpret("device-end");
        }
+
+       /* Add olpc,xo1-battery compatible marker to battery node */
+       olpc_dt_interpret("\" /battery@0\" find-device");
+       olpc_dt_interpret("  \" olpc,xo1-battery\" +compatible");
+       olpc_dt_interpret("device-end");
 }
 
 void __init olpc_dt_build_devicetree(void)
index 62f5c70459440e9403afa34d59d299fb90c382cd..1861a2ba0f2b7fe57c41a17c10aea1f6ce8c60ad 100644 (file)
@@ -44,8 +44,6 @@ void __init __weak mem_map_via_hcall(struct boot_params *ptr __maybe_unused)
 
 static void __init init_pvh_bootparams(bool xen_guest)
 {
-       memset(&pvh_bootparams, 0, sizeof(pvh_bootparams));
-
        if ((pvh_start_info.version > 0) && (pvh_start_info.memmap_entries)) {
                struct hvm_memmap_table_entry *ep;
                int i;
@@ -103,7 +101,7 @@ static void __init init_pvh_bootparams(bool xen_guest)
  * If we are trying to boot a Xen PVH guest, it is expected that the kernel
  * will have been configured to provide the required override for this routine.
  */
-void __init __weak xen_pvh_init(void)
+void __init __weak xen_pvh_init(struct boot_params *boot_params)
 {
        xen_raw_printk("Error: Missing xen PVH initialization\n");
        BUG();
@@ -112,7 +110,7 @@ void __init __weak xen_pvh_init(void)
 static void hypervisor_specific_init(bool xen_guest)
 {
        if (xen_guest)
-               xen_pvh_init();
+               xen_pvh_init(&pvh_bootparams);
 }
 
 /*
@@ -131,6 +129,8 @@ void __init xen_prepare_pvh(void)
                BUG();
        }
 
+       memset(&pvh_bootparams, 0, sizeof(pvh_bootparams));
+
        hypervisor_specific_init(xen_guest);
 
        init_pvh_bootparams(xen_guest);
index 1fbb629a9d78fc6b402a1a8fa95ed4b81ebfe21f..0d3365cb64de034ad2cd6e6cc299d8b07977a4de 100644 (file)
@@ -158,7 +158,7 @@ static enum efi_secureboot_mode xen_efi_get_secureboot(void)
        return efi_secureboot_mode_unknown;
 }
 
-void __init xen_efi_init(void)
+void __init xen_efi_init(struct boot_params *boot_params)
 {
        efi_system_table_t *efi_systab_xen;
 
@@ -167,12 +167,12 @@ void __init xen_efi_init(void)
        if (efi_systab_xen == NULL)
                return;
 
-       strncpy((char *)&boot_params.efi_info.efi_loader_signature, "Xen",
-                       sizeof(boot_params.efi_info.efi_loader_signature));
-       boot_params.efi_info.efi_systab = (__u32)__pa(efi_systab_xen);
-       boot_params.efi_info.efi_systab_hi = (__u32)(__pa(efi_systab_xen) >> 32);
+       strncpy((char *)&boot_params->efi_info.efi_loader_signature, "Xen",
+                       sizeof(boot_params->efi_info.efi_loader_signature));
+       boot_params->efi_info.efi_systab = (__u32)__pa(efi_systab_xen);
+       boot_params->efi_info.efi_systab_hi = (__u32)(__pa(efi_systab_xen) >> 32);
 
-       boot_params.secure_boot = xen_efi_get_secureboot();
+       boot_params->secure_boot = xen_efi_get_secureboot();
 
        set_bit(EFI_BOOT, &efi.flags);
        set_bit(EFI_PARAVIRT, &efi.flags);
index c54a493e139a78e37eab27cc36556396303a390e..4722ba2966ac480218f651e84e2d13b795f8e2f7 100644 (file)
@@ -1403,7 +1403,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
        /* We need this for printk timestamps */
        xen_setup_runstate_info(0);
 
-       xen_efi_init();
+       xen_efi_init(&boot_params);
 
        /* Start the world */
 #ifdef CONFIG_X86_32
index 35b7599d2d0be8df7b8c355c62791b00e3c33871..80a79db72fcfd43c4abad268976e331f3e9a370b 100644 (file)
@@ -13,6 +13,8 @@
 
 #include <xen/interface/memory.h>
 
+#include "xen-ops.h"
+
 /*
  * PVH variables.
  *
  */
 bool xen_pvh __attribute__((section(".data"))) = 0;
 
-void __init xen_pvh_init(void)
+void __init xen_pvh_init(struct boot_params *boot_params)
 {
        u32 msr;
        u64 pfn;
 
        xen_pvh = 1;
+       xen_domain_type = XEN_HVM_DOMAIN;
        xen_start_flags = pvh_start_info.flags;
 
        msr = cpuid_ebx(xen_cpuid_base() + 2);
        pfn = __pa(hypercall_page);
        wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
+
+       xen_efi_init(boot_params);
 }
 
 void __init mem_map_via_hcall(struct boot_params *boot_params_p)
index 6e29794573b72f18d9179a17d78d0981b84c5094..befbdd8b17f0152ba835973a19c62375520a53c3 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "xen-ops.h"
 
-/* Xen may fire a timer up to this many ns early */
+/* Minimum amount of time until next clock event fires */
 #define TIMER_SLOP     100000
 
 static u64 xen_sched_clock_offset __read_mostly;
@@ -212,7 +212,7 @@ static int xen_timerop_set_next_event(unsigned long delta,
        return 0;
 }
 
-static const struct clock_event_device xen_timerop_clockevent = {
+static struct clock_event_device xen_timerop_clockevent __ro_after_init = {
        .name                   = "xen",
        .features               = CLOCK_EVT_FEAT_ONESHOT,
 
@@ -273,7 +273,7 @@ static int xen_vcpuop_set_next_event(unsigned long delta,
        return ret;
 }
 
-static const struct clock_event_device xen_vcpuop_clockevent = {
+static struct clock_event_device xen_vcpuop_clockevent __ro_after_init = {
        .name = "xen",
        .features = CLOCK_EVT_FEAT_ONESHOT,
 
@@ -570,3 +570,17 @@ void __init xen_hvm_init_time_ops(void)
        x86_platform.set_wallclock = xen_set_wallclock;
 }
 #endif
+
+/* Kernel parameter to specify Xen timer slop */
+static int __init parse_xen_timer_slop(char *ptr)
+{
+       unsigned long slop = memparse(ptr, NULL);
+
+       xen_timerop_clockevent.min_delta_ns = slop;
+       xen_timerop_clockevent.min_delta_ticks = slop;
+       xen_vcpuop_clockevent.min_delta_ns = slop;
+       xen_vcpuop_clockevent.min_delta_ticks = slop;
+
+       return 0;
+}
+early_param("xen_timer_slop", parse_xen_timer_slop);
index 0e60bd91869548a950b32550f26883ef5c4965f6..2f111f47ba98c961396bab7ba1f209717c280ecf 100644 (file)
@@ -122,9 +122,9 @@ static inline void __init xen_init_vga(const struct dom0_vga_console_info *info,
 void __init xen_init_apic(void);
 
 #ifdef CONFIG_XEN_EFI
-extern void xen_efi_init(void);
+extern void xen_efi_init(struct boot_params *boot_params);
 #else
-static inline void __init xen_efi_init(void)
+static inline void __init xen_efi_init(struct boot_params *boot_params)
 {
 }
 #endif
index 35c8d91e61069df2101eeea4c01eb41648aa91cd..6ec1b75eabc5eece0e7c7155e78be8a99ce301da 100644 (file)
@@ -253,12 +253,26 @@ config MEMMAP_CACHEATTR
          region: bits 0..3 -- for addresses 0x00000000..0x1fffffff,
          bits 4..7 -- for addresses 0x20000000..0x3fffffff, and so on.
 
-         Cache attribute values are specific for the MMU type, so e.g.
-         for region protection MMUs: 2 is cache bypass, 4 is WB cached,
-         1 is WT cached, f is illegal. For ful MMU: bit 0 makes it executable,
-         bit 1 makes it writable, bits 2..3 meaning is 0: cache bypass,
-         1: WB cache, 2: WT cache, 3: special (c and e are illegal, f is
-         reserved).
+         Cache attribute values are specific for the MMU type.
+         For region protection MMUs:
+           1: WT cached,
+           2: cache bypass,
+           4: WB cached,
+           f: illegal.
+         For ful MMU:
+           bit 0: executable,
+           bit 1: writable,
+           bits 2..3:
+             0: cache bypass,
+             1: WB cache,
+             2: WT cache,
+             3: special (c and e are illegal, f is reserved).
+         For MPU:
+           0: illegal,
+           1: WB cache,
+           2: WB, no-write-allocate cache,
+           3: WT cache,
+           4: cache bypass.
 
 config KSEG_PADDR
        hex "Physical address of the KSEG mapping"
index bbf3b4b080cdaf8eceee319382b58666fe1e8601..48ba5a232d948792d95aa8bc3fe3aca5e4c250ec 100644 (file)
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-#include <variant/core.h>
+#include <asm/core.h>
 #include <asm/regs.h>
 #include <asm/asmmacro.h>
 #include <asm/cacheasm.h>
index 7f2ae5872151de9452c1bf837297f81280eda9a2..8308a9c3abb2f085f5df117bd40efed079ac1f60 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef _XTENSA_ASMMACRO_H
 #define _XTENSA_ASMMACRO_H
 
-#include <variant/core.h>
+#include <asm/core.h>
 
 /*
  * Some little helpers for loops. Use zero-overhead-loops
index 7de0149e1cf7dd0e98c98f115b3f155edd34a7f7..7b00d26f472edfd98b663ebf2a13b4d122bd2894 100644 (file)
@@ -15,8 +15,6 @@
 
 #include <linux/stringify.h>
 #include <linux/types.h>
-
-#ifdef __KERNEL__
 #include <asm/processor.h>
 #include <asm/cmpxchg.h>
 #include <asm/barrier.h>
  */
 #define atomic_set(v,i)                WRITE_ONCE((v)->counter, (i))
 
-#if XCHAL_HAVE_S32C1I
+#if XCHAL_HAVE_EXCLUSIVE
+#define ATOMIC_OP(op)                                                  \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       unsigned long tmp;                                              \
+       int result;                                                     \
+                                                                       \
+       __asm__ __volatile__(                                           \
+                       "1:     l32ex   %1, %3\n"                       \
+                       "       " #op " %0, %1, %2\n"                   \
+                       "       s32ex   %0, %3\n"                       \
+                       "       getex   %0\n"                           \
+                       "       beqz    %0, 1b\n"                       \
+                       : "=&a" (result), "=&a" (tmp)                   \
+                       : "a" (i), "a" (v)                              \
+                       : "memory"                                      \
+                       );                                              \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op)                                           \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       unsigned long tmp;                                              \
+       int result;                                                     \
+                                                                       \
+       __asm__ __volatile__(                                           \
+                       "1:     l32ex   %1, %3\n"                       \
+                       "       " #op " %0, %1, %2\n"                   \
+                       "       s32ex   %0, %3\n"                       \
+                       "       getex   %0\n"                           \
+                       "       beqz    %0, 1b\n"                       \
+                       "       " #op " %0, %1, %2\n"                   \
+                       : "=&a" (result), "=&a" (tmp)                   \
+                       : "a" (i), "a" (v)                              \
+                       : "memory"                                      \
+                       );                                              \
+                                                                       \
+       return result;                                                  \
+}
+
+#define ATOMIC_FETCH_OP(op)                                            \
+static inline int atomic_fetch_##op(int i, atomic_t *v)                        \
+{                                                                      \
+       unsigned long tmp;                                              \
+       int result;                                                     \
+                                                                       \
+       __asm__ __volatile__(                                           \
+                       "1:     l32ex   %1, %3\n"                       \
+                       "       " #op " %0, %1, %2\n"                   \
+                       "       s32ex   %0, %3\n"                       \
+                       "       getex   %0\n"                           \
+                       "       beqz    %0, 1b\n"                       \
+                       : "=&a" (result), "=&a" (tmp)                   \
+                       : "a" (i), "a" (v)                              \
+                       : "memory"                                      \
+                       );                                              \
+                                                                       \
+       return tmp;                                                     \
+}
+
+#elif XCHAL_HAVE_S32C1I
 #define ATOMIC_OP(op)                                                  \
 static inline void atomic_##op(int i, atomic_t * v)                    \
 {                                                                      \
@@ -200,6 +258,4 @@ ATOMIC_OPS(xor)
 #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
-#endif /* __KERNEL__ */
-
 #endif /* _XTENSA_ATOMIC_H */
index 956596e4d437470c9d451d3fdaff6577c49477f5..d6f8d4ddc2bca04e850ba75b10677cf8611d6619 100644 (file)
@@ -9,12 +9,16 @@
 #ifndef _XTENSA_SYSTEM_H
 #define _XTENSA_SYSTEM_H
 
+#include <asm/core.h>
+
 #define mb()  ({ __asm__ __volatile__("memw" : : : "memory"); })
 #define rmb() barrier()
 #define wmb() mb()
 
+#if XCHAL_HAVE_S32C1I
 #define __smp_mb__before_atomic()              barrier()
 #define __smp_mb__after_atomic()               barrier()
+#endif
 
 #include <asm-generic/barrier.h>
 
index d3490189792b08a22962d9784c40472eaf5907b4..aeb15f4c755b379de5d0c0f62eba6eaab7d7229e 100644 (file)
@@ -13,8 +13,6 @@
 #ifndef _XTENSA_BITOPS_H
 #define _XTENSA_BITOPS_H
 
-#ifdef __KERNEL__
-
 #ifndef _LINUX_BITOPS_H
 #error only <linux/bitops.h> can be included directly
 #endif
@@ -98,7 +96,126 @@ static inline unsigned long __fls(unsigned long word)
 
 #include <asm-generic/bitops/fls64.h>
 
-#if XCHAL_HAVE_S32C1I
+#if XCHAL_HAVE_EXCLUSIVE
+
+static inline void set_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32ex   %0, %2\n"
+                       "       or      %0, %0, %1\n"
+                       "       s32ex   %0, %2\n"
+                       "       getex   %0\n"
+                       "       beqz    %0, 1b\n"
+                       : "=&a" (tmp)
+                       : "a" (mask), "a" (p)
+                       : "memory");
+}
+
+static inline void clear_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32ex   %0, %2\n"
+                       "       and     %0, %0, %1\n"
+                       "       s32ex   %0, %2\n"
+                       "       getex   %0\n"
+                       "       beqz    %0, 1b\n"
+                       : "=&a" (tmp)
+                       : "a" (~mask), "a" (p)
+                       : "memory");
+}
+
+static inline void change_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32ex   %0, %2\n"
+                       "       xor     %0, %0, %1\n"
+                       "       s32ex   %0, %2\n"
+                       "       getex   %0\n"
+                       "       beqz    %0, 1b\n"
+                       : "=&a" (tmp)
+                       : "a" (~mask), "a" (p)
+                       : "memory");
+}
+
+static inline int
+test_and_set_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32ex   %1, %3\n"
+                       "       or      %0, %1, %2\n"
+                       "       s32ex   %0, %3\n"
+                       "       getex   %0\n"
+                       "       beqz    %0, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (mask), "a" (p)
+                       : "memory");
+
+       return value & mask;
+}
+
+static inline int
+test_and_clear_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32ex   %1, %3\n"
+                       "       and     %0, %1, %2\n"
+                       "       s32ex   %0, %3\n"
+                       "       getex   %0\n"
+                       "       beqz    %0, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (~mask), "a" (p)
+                       : "memory");
+
+       return value & mask;
+}
+
+static inline int
+test_and_change_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32ex   %1, %3\n"
+                       "       xor     %0, %1, %2\n"
+                       "       s32ex   %0, %3\n"
+                       "       getex   %0\n"
+                       "       beqz    %0, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (mask), "a" (p)
+                       : "memory");
+
+       return value & mask;
+}
+
+#elif XCHAL_HAVE_S32C1I
 
 static inline void set_bit(unsigned int bit, volatile unsigned long *p)
 {
@@ -232,6 +349,4 @@ test_and_change_bit(unsigned int bit, volatile unsigned long *p)
 #include <asm-generic/bitops/lock.h>
 #include <asm-generic/bitops/sched.h>
 
-#endif /* __KERNEL__ */
-
 #endif /* _XTENSA_BITOPS_H */
index d2fd932fdb4dd43c2266d8930cc74887c0cf6e4b..b21fd133ff62092a9e7bd171a5831eede1d007d0 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef _XTENSA_CACHE_H
 #define _XTENSA_CACHE_H
 
-#include <variant/core.h>
+#include <asm/core.h>
 
 #define L1_CACHE_SHIFT XCHAL_DCACHE_LINEWIDTH
 #define L1_CACHE_BYTES XCHAL_DCACHE_LINESIZE
index f302ef57973a45e8a9dccf82a8329158f48172a3..8b687176ad7245cfef1e9b06dd0344a0b72eafb0 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <linux/in6.h>
 #include <linux/uaccess.h>
-#include <variant/core.h>
+#include <asm/core.h>
 
 /*
  * computes the checksum of a memory block at buff, length len,
index 22a10c715c1fd1801721803300333f6ca1dfa2eb..7ccc5cbf441b771cabdbf62289696b56d745370d 100644 (file)
 static inline unsigned long
 __cmpxchg_u32(volatile int *p, int old, int new)
 {
-#if XCHAL_HAVE_S32C1I
+#if XCHAL_HAVE_EXCLUSIVE
+       unsigned long tmp, result;
+
+       __asm__ __volatile__(
+                       "1:     l32ex   %0, %3\n"
+                       "       bne     %0, %4, 2f\n"
+                       "       mov     %1, %2\n"
+                       "       s32ex   %1, %3\n"
+                       "       getex   %1\n"
+                       "       beqz    %1, 1b\n"
+                       "2:\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (new), "a" (p), "a" (old)
+                       : "memory"
+                       );
+
+       return result;
+#elif XCHAL_HAVE_S32C1I
        __asm__ __volatile__(
                        "       wsr     %2, scompare1\n"
                        "       s32c1i  %0, %1, 0\n"
@@ -108,7 +125,22 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
 
 static inline unsigned long xchg_u32(volatile int * m, unsigned long val)
 {
-#if XCHAL_HAVE_S32C1I
+#if XCHAL_HAVE_EXCLUSIVE
+       unsigned long tmp, result;
+
+       __asm__ __volatile__(
+                       "1:     l32ex   %0, %3\n"
+                       "       mov     %1, %2\n"
+                       "       s32ex   %1, %3\n"
+                       "       getex   %1\n"
+                       "       beqz    %1, 1b\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (val), "a" (m)
+                       : "memory"
+                       );
+
+       return result;
+#elif XCHAL_HAVE_S32C1I
        unsigned long tmp, result;
        __asm__ __volatile__(
                        "1:     l32i    %1, %2, 0\n"
index 6712929a27c99a69e66c308f3aaefe033fdc1bc3..0fbe2a740b8d6ff494e8f8dbe896f0f0a67e85b0 100644 (file)
@@ -12,8 +12,8 @@
 #ifndef _XTENSA_COPROCESSOR_H
 #define _XTENSA_COPROCESSOR_H
 
-#include <variant/core.h>
 #include <variant/tie.h>
+#include <asm/core.h>
 #include <asm/types.h>
 
 #ifdef __ASSEMBLY__
diff --git a/arch/xtensa/include/asm/core.h b/arch/xtensa/include/asm/core.h
new file mode 100644 (file)
index 0000000..5b4acb7
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 Cadence Design Systems Inc. */
+
+#ifndef _ASM_XTENSA_CORE_H
+#define _ASM_XTENSA_CORE_H
+
+#include <variant/core.h>
+
+#ifndef XCHAL_HAVE_EXCLUSIVE
+#define XCHAL_HAVE_EXCLUSIVE 0
+#endif
+
+#ifndef XCHAL_HAVE_MPU
+#define XCHAL_HAVE_MPU 0
+#endif
+
+#ifndef XCHAL_SPANNING_WAY
+#define XCHAL_SPANNING_WAY 0
+#endif
+
+#endif
index 505d09eff184dba703f8e3ef52203de03faa0617..9538b0f7953c3d4faf8bc3189392b309ca7253fb 100644 (file)
 #ifndef _ASM_XTENSA_FUTEX_H
 #define _ASM_XTENSA_FUTEX_H
 
-#ifdef __KERNEL__
-
 #include <linux/futex.h>
 #include <linux/uaccess.h>
 #include <linux/errno.h>
 
-#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
+#if XCHAL_HAVE_EXCLUSIVE
+#define __futex_atomic_op(insn, ret, old, uaddr, arg)  \
+       __asm__ __volatile(                             \
+       "1:     l32ex   %[oldval], %[addr]\n"           \
+               insn "\n"                               \
+       "2:     s32ex   %[newval], %[addr]\n"           \
+       "       getex   %[newval]\n"                    \
+       "       beqz    %[newval], 1b\n"                \
+       "       movi    %[newval], 0\n"                 \
+       "3:\n"                                          \
+       "       .section .fixup,\"ax\"\n"               \
+       "       .align 4\n"                             \
+       "       .literal_position\n"                    \
+       "5:     movi    %[oldval], 3b\n"                \
+       "       movi    %[newval], %[fault]\n"          \
+       "       jx      %[oldval]\n"                    \
+       "       .previous\n"                            \
+       "       .section __ex_table,\"a\"\n"            \
+       "       .long 1b, 5b, 2b, 5b\n"                 \
+       "       .previous\n"                            \
+       : [oldval] "=&r" (old), [newval] "=&r" (ret)    \
+       : [addr] "r" (uaddr), [oparg] "r" (arg),        \
+         [fault] "I" (-EFAULT)                         \
+       : "memory")
+#elif XCHAL_HAVE_S32C1I
+#define __futex_atomic_op(insn, ret, old, uaddr, arg)  \
        __asm__ __volatile(                             \
-       "1:     l32i    %0, %2, 0\n"                    \
+       "1:     l32i    %[oldval], %[addr], 0\n"        \
                insn "\n"                               \
-       "       wsr     %0, scompare1\n"                \
-       "2:     s32c1i  %1, %2, 0\n"                    \
-       "       bne     %1, %0, 1b\n"                   \
-       "       movi    %1, 0\n"                        \
+       "       wsr     %[oldval], scompare1\n"         \
+       "2:     s32c1i  %[newval], %[addr], 0\n"        \
+       "       bne     %[newval], %[oldval], 1b\n"     \
+       "       movi    %[newval], 0\n"                 \
        "3:\n"                                          \
        "       .section .fixup,\"ax\"\n"               \
        "       .align 4\n"                             \
        "       .literal_position\n"                    \
-       "5:     movi    %0, 3b\n"                       \
-       "       movi    %1, %3\n"                       \
-       "       jx      %0\n"                           \
+       "5:     movi    %[oldval], 3b\n"                \
+       "       movi    %[newval], %[fault]\n"          \
+       "       jx      %[oldval]\n"                    \
        "       .previous\n"                            \
        "       .section __ex_table,\"a\"\n"            \
-       "       .long 1b,5b,2b,5b\n"                    \
+       "       .long 1b, 5b, 2b, 5b\n"                 \
        "       .previous\n"                            \
-       : "=&r" (oldval), "=&r" (ret)                   \
-       : "r" (uaddr), "I" (-EFAULT), "r" (oparg)       \
+       : [oldval] "=&r" (old), [newval] "=&r" (ret)    \
+       : [addr] "r" (uaddr), [oparg] "r" (arg),        \
+         [fault] "I" (-EFAULT)                         \
        : "memory")
+#endif
 
 static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
                u32 __user *uaddr)
 {
+#if XCHAL_HAVE_S32C1I || XCHAL_HAVE_EXCLUSIVE
        int oldval = 0, ret;
 
-#if !XCHAL_HAVE_S32C1I
-       return -ENOSYS;
-#endif
-
        pagefault_disable();
 
        switch (op) {
        case FUTEX_OP_SET:
-               __futex_atomic_op("mov %1, %4", ret, oldval, uaddr, oparg);
+               __futex_atomic_op("mov %[newval], %[oparg]",
+                                 ret, oldval, uaddr, oparg);
                break;
        case FUTEX_OP_ADD:
-               __futex_atomic_op("add %1, %0, %4", ret, oldval, uaddr,
-                               oparg);
+               __futex_atomic_op("add %[newval], %[oldval], %[oparg]",
+                                 ret, oldval, uaddr, oparg);
                break;
        case FUTEX_OP_OR:
-               __futex_atomic_op("or %1, %0, %4", ret, oldval, uaddr,
-                               oparg);
+               __futex_atomic_op("or %[newval], %[oldval], %[oparg]",
+                                 ret, oldval, uaddr, oparg);
                break;
        case FUTEX_OP_ANDN:
-               __futex_atomic_op("and %1, %0, %4", ret, oldval, uaddr,
-                               ~oparg);
+               __futex_atomic_op("and %[newval], %[oldval], %[oparg]",
+                                 ret, oldval, uaddr, ~oparg);
                break;
        case FUTEX_OP_XOR:
-               __futex_atomic_op("xor %1, %0, %4", ret, oldval, uaddr,
-                               oparg);
+               __futex_atomic_op("xor %[newval], %[oldval], %[oparg]",
+                                 ret, oldval, uaddr, oparg);
                break;
        default:
                ret = -ENOSYS;
@@ -85,43 +108,60 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
                *oval = oldval;
 
        return ret;
+#else
+       return -ENOSYS;
+#endif
 }
 
 static inline int
 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
                              u32 oldval, u32 newval)
 {
+#if XCHAL_HAVE_S32C1I || XCHAL_HAVE_EXCLUSIVE
+       unsigned long tmp;
        int ret = 0;
 
        if (!access_ok(uaddr, sizeof(u32)))
                return -EFAULT;
 
-#if !XCHAL_HAVE_S32C1I
-       return -ENOSYS;
-#endif
-
        __asm__ __volatile__ (
        "       # futex_atomic_cmpxchg_inatomic\n"
-       "       wsr     %5, scompare1\n"
-       "1:     s32c1i  %1, %4, 0\n"
-       "       s32i    %1, %6, 0\n"
+#if XCHAL_HAVE_EXCLUSIVE
+       "1:     l32ex   %[tmp], %[addr]\n"
+       "       s32i    %[tmp], %[uval], 0\n"
+       "       bne     %[tmp], %[oldval], 2f\n"
+       "       mov     %[tmp], %[newval]\n"
+       "3:     s32ex   %[tmp], %[addr]\n"
+       "       getex   %[tmp]\n"
+       "       beqz    %[tmp], 1b\n"
+#elif XCHAL_HAVE_S32C1I
+       "       wsr     %[oldval], scompare1\n"
+       "1:     s32c1i  %[newval], %[addr], 0\n"
+       "       s32i    %[newval], %[uval], 0\n"
+#endif
        "2:\n"
        "       .section .fixup,\"ax\"\n"
        "       .align 4\n"
        "       .literal_position\n"
-       "4:     movi    %1, 2b\n"
-       "       movi    %0, %7\n"
-       "       jx      %1\n"
+       "4:     movi    %[tmp], 2b\n"
+       "       movi    %[ret], %[fault]\n"
+       "       jx      %[tmp]\n"
        "       .previous\n"
        "       .section __ex_table,\"a\"\n"
-       "       .long 1b,4b\n"
+       "       .long 1b, 4b\n"
+#if XCHAL_HAVE_EXCLUSIVE
+       "       .long 3b, 4b\n"
+#endif
        "       .previous\n"
-       : "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval)
-       : "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT)
+       : [ret] "+r" (ret), [newval] "+r" (newval), [tmp] "=&r" (tmp)
+       : [addr] "r" (uaddr), [oldval] "r" (oldval), [uval] "r" (uval),
+         [fault] "I" (-EFAULT)
        : "memory");
 
        return ret;
+#else
+       return -ENOSYS;
+#endif
 }
 
-#endif /* __KERNEL__ */
 #endif /* _ASM_XTENSA_FUTEX_H */
index 10e9852b2fb474d18ba8e5401592792fefe3504f..323d0578915903626cc06435c774535f40b6a7bf 100644 (file)
 #define CA_WRITEBACK   (0x4)
 #endif
 
-#ifndef XCHAL_SPANNING_WAY
-#define XCHAL_SPANNING_WAY 0
-#endif
-
 #ifdef __ASSEMBLY__
 
 #define XTENSA_HWVERSION_RC_2009_0 230000
 
        .macro  initialize_cacheattr
 
-#if !defined(CONFIG_MMU) && XCHAL_HAVE_TLBS
+#if !defined(CONFIG_MMU) && (XCHAL_HAVE_TLBS || XCHAL_HAVE_MPU)
 #if CONFIG_MEMMAP_CACHEATTR == 0x22222222 && XCHAL_HAVE_PTP_MMU
 #error Default MEMMAP_CACHEATTR of 0x22222222 does not work with full MMU.
 #endif
 
+#if XCHAL_HAVE_MPU
+       .data
+       .align  4
+.Lattribute_table:
+       .long 0x000000, 0x1fff00, 0x1ddf00, 0x1eef00
+       .long 0x006600, 0x000000, 0x000000, 0x000000
+       .long 0x000000, 0x000000, 0x000000, 0x000000
+       .long 0x000000, 0x000000, 0x000000, 0x000000
+       .previous
+
+       movi    a3, .Lattribute_table
+       movi    a4, CONFIG_MEMMAP_CACHEATTR
+       movi    a5, 1
+       movi    a6, XCHAL_MPU_ENTRIES
+       movi    a10, 0x20000000
+       movi    a11, -1
+1:
+       sub     a5, a5, a10
+       extui   a8, a4, 28, 4
+       beq     a8, a11, 2f
+       addi    a6, a6, -1
+       mov     a11, a8
+2:
+       addx4   a9, a8, a3
+       l32i    a9, a9, 0
+       or      a9, a9, a6
+       wptlb   a9, a5
+       slli    a4, a4, 4
+       bgeu    a5, a10, 1b
+
+#else
        movi    a5, XCHAL_SPANNING_WAY
        movi    a6, ~_PAGE_ATTRIB_MASK
        movi    a4, CONFIG_MEMMAP_CACHEATTR
        bgeu    a5, a8, 1b
 
        isync
+#endif
 #endif
 
        .endm
index acc5bb2cf1c77328cc502dcf69cace9af5b8b3d9..da3e783f896b34c3fd60cfc94a1aa44a6465365b 100644 (file)
@@ -11,7 +11,6 @@
 #ifndef _XTENSA_IO_H
 #define _XTENSA_IO_H
 
-#ifdef __KERNEL__
 #include <asm/byteorder.h>
 #include <asm/page.h>
 #include <asm/vectors.h>
@@ -78,8 +77,6 @@ static inline void iounmap(volatile void __iomem *addr)
 
 #endif /* CONFIG_MMU */
 
-#endif /* __KERNEL__ */
-
 #include <asm-generic/io.h>
 
 #endif /* _XTENSA_IO_H */
index 6c6ed23e0c79c51875710e29a7e59ce59fe2ef7b..0f71a51dab2524647599092dc28bf4782a5ee541 100644 (file)
@@ -12,7 +12,7 @@
 #define _XTENSA_IRQ_H
 
 #include <linux/init.h>
-#include <variant/core.h>
+#include <asm/core.h>
 
 #ifdef CONFIG_PLATFORM_NR_IRQS
 # define PLATFORM_NR_IRQS CONFIG_PLATFORM_NR_IRQS
index 9b5e8526afe59ba2228cf4e189cfc1bbc518258e..12890681587b38245a3293c1b4f3d40c9993b244 100644 (file)
@@ -27,7 +27,7 @@ static inline unsigned long arch_local_irq_save(void)
 {
        unsigned long flags;
 #if XTENSA_FAKE_NMI
-#if defined(CONFIG_DEBUG_KERNEL) && (LOCKLEVEL | TOPLEVEL) >= XCHAL_DEBUGLEVEL
+#if defined(CONFIG_DEBUG_MISC) && (LOCKLEVEL | TOPLEVEL) >= XCHAL_DEBUGLEVEL
        unsigned long tmp;
 
        asm volatile("rsr       %0, ps\t\n"
index 0b68c76ec1e6054e5e4bbdc21c14b82356e96800..405526912d9aee9b43ecc4b4985643a6828fa9cc 100644 (file)
@@ -11,8 +11,6 @@
 #ifndef _XTENSA_PCI_BRIDGE_H
 #define _XTENSA_PCI_BRIDGE_H
 
-#ifdef __KERNEL__
-
 struct device_node;
 struct pci_controller;
 
@@ -84,5 +82,4 @@ int early_write_config_byte(struct pci_controller*, int, int, int, u8);
 int early_write_config_word(struct pci_controller*, int, int, int, u16);
 int early_write_config_dword(struct pci_controller*, int, int, int, u32);
 
-#endif /* __KERNEL__ */
 #endif /* _XTENSA_PCI_BRIDGE_H */
index 883024054b05601f8f03159538e6931f22b0fb4a..8e2b48a268dbb361184e8b4e6ca4b9212f7b1034 100644 (file)
@@ -11,8 +11,6 @@
 #ifndef _XTENSA_PCI_H
 #define _XTENSA_PCI_H
 
-#ifdef __KERNEL__
-
 /* Can be used to override the logic in pci_scan_bus for skipping
  * already-configured bus numbers - to be used for buggy BIOSes
  * or architectures with incomplete PCI setup by the loader
@@ -45,8 +43,6 @@
 #define ARCH_GENERIC_PCI_MMAP_RESOURCE 1
 #define arch_can_pci_mmap_io()         1
 
-#endif /* __KERNEL__ */
-
 /* Generic PCI */
 #include <asm-generic/pci.h>
 
index b3b388ff2f01e4a3e8b48dd898cbf4001b49156e..368284c972e7ccd83650b2f6f5a2ab725db00939 100644 (file)
@@ -11,8 +11,6 @@
 #ifndef _XTENSA_PGALLOC_H
 #define _XTENSA_PGALLOC_H
 
-#ifdef __KERNEL__
-
 #include <linux/highmem.h>
 #include <linux/slab.h>
 
@@ -79,5 +77,4 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
 }
 #define pmd_pgtable(pmd) pmd_page(pmd)
 
-#endif /* __KERNEL__ */
 #endif /* _XTENSA_PGALLOC_H */
index 0c14018d1c2601a63a92b2f29be1270d9919220c..19f6b54e358b1d53594896bb6c2f29113ec0b849 100644 (file)
@@ -10,7 +10,7 @@
 #ifndef _XTENSA_PROCESSOR_H
 #define _XTENSA_PROCESSOR_H
 
-#include <variant/core.h>
+#include <asm/core.h>
 
 #include <linux/compiler.h>
 #include <linux/stringify.h>
index 62a58d2567e94459d0cdbf4c5f9f95236b4d7858..b109416dc07e8047a3963f0f1647ca229a755b86 100644 (file)
@@ -80,7 +80,7 @@ struct pt_regs {
        unsigned long areg[16];
 };
 
-#include <variant/core.h>
+#include <asm/core.h>
 
 # define arch_has_single_step()        (1)
 # define task_pt_regs(tsk) ((struct pt_regs*) \
diff --git a/arch/xtensa/include/asm/segment.h b/arch/xtensa/include/asm/segment.h
deleted file mode 100644 (file)
index 98964ad..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * include/asm-xtensa/segment.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_SEGMENT_H
-#define _XTENSA_SEGMENT_H
-
-#include <linux/uaccess.h>
-
-#endif /* _XTENSA_SEGEMENT_H */
index 7111280c8842287fcc6a177d7c116b837c8974ec..79fe3007919eb2f9039548807306444e5a923c37 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef _XTENSA_VECTORS_H
 #define _XTENSA_VECTORS_H
 
-#include <variant/core.h>
+#include <asm/core.h>
 #include <asm/kmem_layout.h>
 
 #if XCHAL_HAVE_PTP_MMU
index 4f20416061fbb0d25ac7750c5ea1dec02fcca94d..285fb2942b06593a585e154f32fa67d920afc295 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/log2.h>
 #include <linux/percpu.h>
 #include <linux/perf_event.h>
-#include <variant/core.h>
+#include <asm/core.h>
 
 /* Breakpoint currently in use for each IBREAKA. */
 static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[XCHAL_NUM_IBREAK]);
index 4ec6fbb696bf4df7b8019f7315c79a354804c6ea..c0ec24349421b55df1ff180d6f493a332883611b 100644 (file)
@@ -650,6 +650,9 @@ c_show(struct seq_file *f, void *slot)
 #endif
 #if XCHAL_HAVE_S32C1I
                     "s32c1i "
+#endif
+#if XCHAL_HAVE_EXCLUSIVE
+                    "exclusive "
 #endif
                     "\n");
 
index 3699d6d3e47997d394752e1689a38d460a6eb914..83b244ce61eeb4740b72d6b7a1111093e0ff66d3 100644 (file)
@@ -126,7 +126,7 @@ void secondary_start_kernel(void)
 
        init_mmu();
 
-#ifdef CONFIG_DEBUG_KERNEL
+#ifdef CONFIG_DEBUG_MISC
        if (boot_secondary_processors == 0) {
                pr_debug("%s: boot_secondary_processors:%d; Hanging cpu:%d\n",
                        __func__, boot_secondary_processors, cpu);
index 30084eaf84227ac89eb6e5baa0aed77d6fad5f50..5fa0ee1c8e00f4dc3f64d79e913a33e75767c50c 100644 (file)
 425    common  io_uring_setup                  sys_io_uring_setup
 426    common  io_uring_enter                  sys_io_uring_enter
 427    common  io_uring_register               sys_io_uring_register
+428    common  open_tree                       sys_open_tree
+429    common  move_mount                      sys_move_mount
+430    common  fsopen                          sys_fsopen
+431    common  fsconfig                        sys_fsconfig
+432    common  fsmount                         sys_fsmount
+433    common  fspick                          sys_fspick
index b80a430453b1cb7d76b8598db8eb0b06f039df8d..943f10639a93321fea7c28009567503cb370a0bd 100644 (file)
@@ -18,8 +18,8 @@
 #include <asm/page.h>
 #include <asm/thread_info.h>
 
+#include <asm/core.h>
 #include <asm/vectors.h>
-#include <variant/core.h>
 
 OUTPUT_ARCH(xtensa)
 ENTRY(_start)
index 528fe0dd9339f99b318bfd62615193f98ef94536..d82c20c1fb7a525f0919c8ce0208beb18633dc28 100644 (file)
@@ -16,8 +16,8 @@
 
 #include <linux/errno.h>
 #include <linux/linkage.h>
-#include <variant/core.h>
 #include <asm/asmmacro.h>
+#include <asm/core.h>
 
 /*
  * computes a partial checksum, e.g. for TCP/UDP fragments
index c0f6981719d62eea6c492fe5471a1fde815878f7..efecfd7ed8cc8731f674307def47c417ac7ce077 100644 (file)
@@ -10,8 +10,8 @@
  */
 
 #include <linux/linkage.h>
-#include <variant/core.h>
 #include <asm/asmmacro.h>
+#include <asm/core.h>
 
 /*
  * void *memcpy(void *dst, const void *src, size_t len);
index 276747dec300ac51d70799f43351856ba8d7c94c..8632eacbdc8021a903a10d17d58a9dbc2de94439 100644 (file)
@@ -12,8 +12,8 @@
  */
 
 #include <linux/linkage.h>
-#include <variant/core.h>
 #include <asm/asmmacro.h>
+#include <asm/core.h>
 
 /*
  * void *memset(void *dst, int c, size_t length)
index 5fce16b67dca82a66ef4a46828fbe9da3bf8858e..c4c6c8578d5902ddf25a85e51699a4f4a67eda49 100644 (file)
@@ -13,8 +13,8 @@
 
 #include <linux/errno.h>
 #include <linux/linkage.h>
-#include <variant/core.h>
 #include <asm/asmmacro.h>
+#include <asm/core.h>
 
 /*
  * char *__strncpy_user(char *dst, const char *src, size_t len)
index 0b956ce7f38623077038f13dc123a5c2f2b5d29b..1f2ca2bb2ab3a096885ab131f5397f43211dc170 100644 (file)
@@ -12,8 +12,8 @@
  */
 
 #include <linux/linkage.h>
-#include <variant/core.h>
 #include <asm/asmmacro.h>
+#include <asm/core.h>
 
 /*
  * size_t __strnlen_user(const char *s, size_t len)
index 64ab1971324f3a812eb2d3b05f53b9c060c12573..228607e30bc25320f15b53f4e30a2950e54a9ad7 100644 (file)
@@ -54,8 +54,8 @@
  */
 
 #include <linux/linkage.h>
-#include <variant/core.h>
 #include <asm/asmmacro.h>
+#include <asm/core.h>
 
        .text
 ENTRY(__xtensa_copy_user)
index d4986109968415a8f82ee258d6dad4d0b33b31f1..b51746f2b80bf925b9f131384e42e2419bd6ac14 100644 (file)
@@ -216,11 +216,6 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 }
 #endif
 
-void free_initmem(void)
-{
-       free_initmem_default(-1);
-}
-
 static void __init parse_memmap_one(char *p)
 {
        char *oldp;
index 026211e7ab09cec108e076dc4f9ef67ab4e17659..f9cd45860beee7eac6c97fec89d8a7c23545072e 100644 (file)
@@ -297,8 +297,7 @@ out_alloc_disk:
        blk_cleanup_queue(dev->queue);
        dev->queue = NULL;
 out_alloc_queue:
-       simc_close(dev->fd);
-       return -EIO;
+       return -ENOMEM;
 }
 
 static int __init simdisk_init(void)
index 8e5e0d6a81ec7868d0fa7bcb10ca5b37132048fa..9f213f5733306bf8475d8e38a678e39d5d604bad 100644 (file)
@@ -15,7 +15,7 @@
 #ifndef _XTENSA_XT2000_HARDWARE_H
 #define _XTENSA_XT2000_HARDWARE_H
 
-#include <variant/core.h>
+#include <asm/core.h>
 
 /*
  * On-board components.
index 7226cf732b4797c4f7df20ff88f9c11741b62cc4..cde804827626faa886f8b113740da026eeef7e0b 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef _XTENSA_XT2000_SERIAL_H
 #define _XTENSA_XT2000_SERIAL_H
 
-#include <variant/core.h>
+#include <asm/core.h>
 #include <asm/io.h>
 
 /*  National-Semi PC16552D DUART:  */
index 820e8738af11d46d79f06a5a8cbeb87b481ae225..b1506376d502aa2bda724a57181f4f05160fcf62 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/errno.h>
 #include <linux/reboot.h>
 #include <linux/kdev_t.h>
index 42536674020a2daf58681638762cad3255f6d677..4db620849515f7c42843e4825a89918687becd28 100644 (file)
@@ -43,8 +43,7 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
        unsigned inline_vecs;
 
        if (!bs || !mempool_initialized(&bs->bio_integrity_pool)) {
-               bip = kmalloc(sizeof(struct bio_integrity_payload) +
-                             sizeof(struct bio_vec) * nr_vecs, gfp_mask);
+               bip = kmalloc(struct_size(bip, bip_inline_vecs, nr_vecs), gfp_mask);
                inline_vecs = nr_vecs;
        } else {
                bip = mempool_alloc(&bs->bio_integrity_pool, gfp_mask);
index ddf598ae8b6b4c311683d3da5159d66214ed31c2..c16f9460c4a2dd8ea16e43a7808e0e7fc4b8596e 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/clkdev.h>
 #include <linux/acpi.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/pm.h>
 
 #include "internal.h"
index adbf7cbedf80d9a5719a3fcb34800ffd552bbecc..9058cb084b919c7ec8140792914ccfacfc9be295 100644 (file)
@@ -1031,6 +1031,14 @@ void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size)
        dev_dbg(dev, "dma_pfn_offset(%#08llx)\n", offset);
 }
 
+static bool iort_pci_rc_supports_ats(struct acpi_iort_node *node)
+{
+       struct acpi_iort_root_complex *pci_rc;
+
+       pci_rc = (struct acpi_iort_root_complex *)node->node_data;
+       return pci_rc->ats_attribute & ACPI_IORT_ATS_SUPPORTED;
+}
+
 /**
  * iort_iommu_configure - Set-up IOMMU configuration for a device.
  *
@@ -1066,6 +1074,9 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
                info.node = node;
                err = pci_for_each_dma_alias(to_pci_dev(dev),
                                             iort_pci_iommu_init, &info);
+
+               if (!err && iort_pci_rc_supports_ats(node))
+                       dev->iommu_fwspec->flags |= IOMMU_FWSPEC_PCI_RC_ATS;
        } else {
                int i = 0;
 
index 8940054d6250f92c56a82f637d0a326256b4eed8..78c2653bf0206922d28b9d7453c7e4220a5ef710 100644 (file)
@@ -428,8 +428,10 @@ static ssize_t acpi_device_adr_show(struct device *dev,
 {
        struct acpi_device *acpi_dev = to_acpi_device(dev);
 
-       return sprintf(buf, "0x%08x\n",
-                      (unsigned int)(acpi_dev->pnp.bus_address));
+       if (acpi_dev->pnp.bus_address > U32_MAX)
+               return sprintf(buf, "0x%016llx\n", acpi_dev->pnp.bus_address);
+       else
+               return sprintf(buf, "0x%08llx\n", acpi_dev->pnp.bus_address);
 }
 static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL);
 
index a4e8432fc2fba456f9ca489bb2614df01537f72c..b42be067fb832d97d79051f37820296a32bf6203 100644 (file)
@@ -52,6 +52,18 @@ struct mcfg_fixup {
 static struct mcfg_fixup mcfg_quirks[] = {
 /*     { OEM_ID, OEM_TABLE_ID, REV, SEGMENT, BUS_RANGE, ops, cfgres }, */
 
+#define AL_ECAM(table_id, rev, seg, ops) \
+       { "AMAZON", table_id, rev, seg, MCFG_BUS_ANY, ops }
+
+       AL_ECAM("GRAVITON", 0, 0, &al_pcie_ops),
+       AL_ECAM("GRAVITON", 0, 1, &al_pcie_ops),
+       AL_ECAM("GRAVITON", 0, 2, &al_pcie_ops),
+       AL_ECAM("GRAVITON", 0, 3, &al_pcie_ops),
+       AL_ECAM("GRAVITON", 0, 4, &al_pcie_ops),
+       AL_ECAM("GRAVITON", 0, 5, &al_pcie_ops),
+       AL_ECAM("GRAVITON", 0, 6, &al_pcie_ops),
+       AL_ECAM("GRAVITON", 0, 7, &al_pcie_ops),
+
 #define QCOM_ECAM32(seg) \
        { "QCOM  ", "QDF2432 ", 1, seg, MCFG_BUS_ANY, &pci_32b_ops }
 
index 707aafc7c2aa9238576525c52f3469938da55b33..c36781a9b493c1f8fb5bf3de1b37e5ef9b8cbe1e 100644 (file)
@@ -145,6 +145,7 @@ static struct pci_osc_bit_struct pci_osc_support_bit[] = {
        { OSC_PCI_CLOCK_PM_SUPPORT, "ClockPM" },
        { OSC_PCI_SEGMENT_GROUPS_SUPPORT, "Segments" },
        { OSC_PCI_MSI_SUPPORT, "MSI" },
+       { OSC_PCI_HPX_TYPE_3_SUPPORT, "HPX-Type3" },
 };
 
 static struct pci_osc_bit_struct pci_osc_control_bit[] = {
@@ -446,6 +447,7 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,
         * PCI domains, so we indicate this in _OSC support capabilities.
         */
        support = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
+       support |= OSC_PCI_HPX_TYPE_3_SUPPORT;
        if (pci_ext_cfg_avail())
                support |= OSC_PCI_EXT_CONFIG_SUPPORT;
        if (pcie_aspm_support_enabled())
index 403c4ff1534982eff19a839ab5bcfc4bc7b414cc..e52f1238d2d66025b949a51f67b9bb629d3b18a4 100644 (file)
@@ -977,6 +977,8 @@ static int acpi_s2idle_prepare(void)
        if (acpi_sci_irq_valid())
                enable_irq_wake(acpi_sci_irq);
 
+       acpi_enable_wakeup_devices(ACPI_STATE_S0);
+
        /* Change the configuration of GPEs to avoid spurious wakeup. */
        acpi_enable_all_wakeup_gpes();
        acpi_os_wait_events_complete();
@@ -1027,6 +1029,8 @@ static void acpi_s2idle_restore(void)
 {
        acpi_enable_all_runtime_gpes();
 
+       acpi_disable_wakeup_devices(ACPI_STATE_S0);
+
        if (acpi_sci_irq_valid())
                disable_irq_wake(acpi_sci_irq);
 
index cc6d06c1b2c70a8e50c3f6384004f10d25edeba1..db271b70552945052514ac0d5f7df16e5d08d056 100644 (file)
@@ -44,7 +44,7 @@
 #include <linux/ktime.h>
 
 #include <linux/platform_data/dma-ep93xx.h>
-#include <mach/platform.h>
+#include <linux/soc/cirrus/ep93xx.h>
 
 #define DRV_NAME       "ep93xx-ide"
 #define DRV_VERSION    "1.0"
index 59b2317acea99e46b282bd637f7281d716bf0b95..3495e1733a8e6756210a888ce3a773b8d05ff2d8 100644 (file)
@@ -909,7 +909,6 @@ static int sata_rcar_probe(struct platform_device *pdev)
 
        host = ata_host_alloc(dev, 1);
        if (!host) {
-               dev_err(dev, "ata_host_alloc failed\n");
                ret = -ENOMEM;
                goto err_pm_put;
        }
index 668139cfa664084239136650f1488f995e55760b..cc37511de866590ed621a1ea0d49fdb255f2d31f 100644 (file)
@@ -548,11 +548,18 @@ ssize_t __weak cpu_show_l1tf(struct device *dev,
        return sprintf(buf, "Not affected\n");
 }
 
+ssize_t __weak cpu_show_mds(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       return sprintf(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);
 static DEVICE_ATTR(spec_store_bypass, 0444, cpu_show_spec_store_bypass, NULL);
 static DEVICE_ATTR(l1tf, 0444, cpu_show_l1tf, NULL);
+static DEVICE_ATTR(mds, 0444, cpu_show_mds, NULL);
 
 static struct attribute *cpu_root_vulnerabilities_attrs[] = {
        &dev_attr_meltdown.attr,
@@ -560,6 +567,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = {
        &dev_attr_spectre_v2.attr,
        &dev_attr_spec_store_bypass.attr,
        &dev_attr_l1tf.attr,
+       &dev_attr_mds.attr,
        NULL
 };
 
index e49028a604295937a59761488d431b9f4837f731..f180427e48f4e59341795c3090d51d84a5f83dc8 100644 (file)
@@ -231,13 +231,14 @@ static bool pages_correctly_probed(unsigned long start_pfn)
  * OK to have direct references to sparsemem variables in here.
  */
 static int
-memory_block_action(unsigned long phys_index, unsigned long action, int online_type)
+memory_block_action(unsigned long start_section_nr, unsigned long action,
+                   int online_type)
 {
        unsigned long start_pfn;
        unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
        int ret;
 
-       start_pfn = section_nr_to_pfn(phys_index);
+       start_pfn = section_nr_to_pfn(start_section_nr);
 
        switch (action) {
        case MEM_ONLINE:
@@ -251,7 +252,7 @@ memory_block_action(unsigned long phys_index, unsigned long action, int online_t
                break;
        default:
                WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: "
-                    "%ld\n", __func__, phys_index, action, action);
+                    "%ld\n", __func__, start_section_nr, action, action);
                ret = -EINVAL;
        }
 
@@ -733,16 +734,18 @@ unregister_memory(struct memory_block *memory)
 {
        BUG_ON(memory->dev.bus != &memory_subsys);
 
-       /* drop the ref. we got in remove_memory_section() */
+       /* drop the ref. we got via find_memory_block() */
        put_device(&memory->dev);
        device_unregister(&memory->dev);
 }
 
-static int remove_memory_section(unsigned long node_id,
-                              struct mem_section *section, int phys_device)
+void unregister_memory_section(struct mem_section *section)
 {
        struct memory_block *mem;
 
+       if (WARN_ON_ONCE(!present_section(section)))
+               return;
+
        mutex_lock(&mem_sysfs_mutex);
 
        /*
@@ -763,15 +766,6 @@ static int remove_memory_section(unsigned long node_id,
 
 out_unlock:
        mutex_unlock(&mem_sysfs_mutex);
-       return 0;
-}
-
-int unregister_memory_section(struct mem_section *section)
-{
-       if (!present_section(section))
-               return -EINVAL;
-
-       return remove_memory_section(0, section, 0);
 }
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
index 7a6aa2318915eff03a1f2d4a9be2e0ddc484a0a6..33c30c1e6a3030288856aaf8ad179bb0b72dce06 100644 (file)
@@ -128,6 +128,7 @@ static const struct genpd_lock_ops genpd_spin_ops = {
 #define genpd_is_always_on(genpd)      (genpd->flags & GENPD_FLAG_ALWAYS_ON)
 #define genpd_is_active_wakeup(genpd)  (genpd->flags & GENPD_FLAG_ACTIVE_WAKEUP)
 #define genpd_is_cpu_domain(genpd)     (genpd->flags & GENPD_FLAG_CPU_DOMAIN)
+#define genpd_is_rpm_always_on(genpd)  (genpd->flags & GENPD_FLAG_RPM_ALWAYS_ON)
 
 static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev,
                const struct generic_pm_domain *genpd)
@@ -515,7 +516,9 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
         * (1) The domain is configured as always on.
         * (2) When the domain has a subdomain being powered on.
         */
-       if (genpd_is_always_on(genpd) || atomic_read(&genpd->sd_count) > 0)
+       if (genpd_is_always_on(genpd) ||
+                       genpd_is_rpm_always_on(genpd) ||
+                       atomic_read(&genpd->sd_count) > 0)
                return -EBUSY;
 
        list_for_each_entry(pdd, &genpd->dev_list, list_node) {
@@ -1812,7 +1815,8 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
        }
 
        /* Always-on domains must be powered on at initialization. */
-       if (genpd_is_always_on(genpd) && !genpd_status_on(genpd))
+       if ((genpd_is_always_on(genpd) || genpd_is_rpm_always_on(genpd)) &&
+                       !genpd_status_on(genpd))
                return -EINVAL;
 
        if (genpd_is_cpu_domain(genpd) &&
index 17defbf4f332c5267b5cc38e94c25e54a5246d6a..2da615b45b3144b8b6eaebef600627ccae572476 100644 (file)
@@ -152,6 +152,12 @@ static void brd_free_pages(struct brd_device *brd)
 
                pos++;
 
+               /*
+                * It takes 3.4 seconds to remove 80GiB ramdisk.
+                * So, we need cond_resched to avoid stalling the CPU.
+                */
+               cond_resched();
+
                /*
                 * This assumes radix_tree_gang_lookup always returns as
                 * many pages as possible. If the radix-tree code changes,
index 2210c1b9491ba2e9f690dd4a26b209b64f4ad925..e5009a34f9c2622570272cd9ea7789e0e5492b2c 100644 (file)
@@ -934,7 +934,7 @@ static struct rbd_client *rbd_get_client(struct ceph_options *ceph_opts)
        struct rbd_client *rbdc;
        int ret;
 
-       mutex_lock_nested(&client_mutex, SINGLE_DEPTH_NESTING);
+       mutex_lock(&client_mutex);
        rbdc = rbd_client_find(ceph_opts);
        if (rbdc) {
                ceph_destroy_options(ceph_opts);
@@ -1326,7 +1326,7 @@ static void rbd_obj_zero_range(struct rbd_obj_request *obj_req, u32 off,
                zero_bvecs(&obj_req->bvec_pos, off, bytes);
                break;
        default:
-               rbd_assert(0);
+               BUG();
        }
 }
 
@@ -1581,7 +1581,7 @@ static void rbd_obj_request_destroy(struct kref *kref)
                kfree(obj_request->bvec_pos.bvecs);
                break;
        default:
-               rbd_assert(0);
+               BUG();
        }
 
        kfree(obj_request->img_extents);
@@ -1781,7 +1781,7 @@ static void rbd_osd_req_setup_data(struct rbd_obj_request *obj_req, u32 which)
                                                    &obj_req->bvec_pos);
                break;
        default:
-               rbd_assert(0);
+               BUG();
        }
 }
 
@@ -2036,7 +2036,7 @@ static int __rbd_img_fill_request(struct rbd_img_request *img_req)
                        ret = rbd_obj_setup_zeroout(obj_req);
                        break;
                default:
-                       rbd_assert(0);
+                       BUG();
                }
                if (ret < 0)
                        return ret;
@@ -2383,7 +2383,7 @@ static int rbd_obj_read_from_parent(struct rbd_obj_request *obj_req)
                                                      &obj_req->bvec_pos);
                        break;
                default:
-                       rbd_assert(0);
+                       BUG();
                }
        } else {
                ret = rbd_img_fill_from_bvecs(child_img_req,
@@ -2515,7 +2515,7 @@ static int rbd_obj_issue_copyup_ops(struct rbd_obj_request *obj_req, u32 bytes)
                num_osd_ops += count_zeroout_ops(obj_req);
                break;
        default:
-               rbd_assert(0);
+               BUG();
        }
 
        obj_req->osd_req = rbd_osd_req_create(obj_req, num_osd_ops);
@@ -2542,7 +2542,7 @@ static int rbd_obj_issue_copyup_ops(struct rbd_obj_request *obj_req, u32 bytes)
                __rbd_obj_setup_zeroout(obj_req, which);
                break;
        default:
-               rbd_assert(0);
+               BUG();
        }
 
        ret = ceph_osdc_alloc_messages(obj_req->osd_req, GFP_NOIO);
@@ -3842,8 +3842,12 @@ static void rbd_queue_workfn(struct work_struct *work)
                goto err_rq;
        }
 
-       rbd_assert(op_type == OBJ_OP_READ ||
-                  rbd_dev->spec->snap_id == CEPH_NOSNAP);
+       if (op_type != OBJ_OP_READ && rbd_dev->spec->snap_id != CEPH_NOSNAP) {
+               rbd_warn(rbd_dev, "%s on read-only snapshot",
+                        obj_op_name(op_type));
+               result = -EIO;
+               goto err;
+       }
 
        /*
         * Quit early if the mapped snapshot no longer exists.  It's
index 084ae286fa239472cc55bbd398c38d35d63fc8ac..ac58142301f49d9bd0b0e088343510fbccc6e37e 100644 (file)
 #include <linux/module.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
-#include <linux/pm_clock.h>
 #include <linux/pm_runtime.h>
 
+struct tegra_aconnect {
+       struct clk      *ape_clk;
+       struct clk      *apb2ape_clk;
+};
+
 static int tegra_aconnect_probe(struct platform_device *pdev)
 {
-       int ret;
+       struct tegra_aconnect *aconnect;
 
        if (!pdev->dev.of_node)
                return -EINVAL;
 
-       ret = pm_clk_create(&pdev->dev);
-       if (ret)
-               return ret;
+       aconnect = devm_kzalloc(&pdev->dev, sizeof(struct tegra_aconnect),
+                               GFP_KERNEL);
+       if (!aconnect)
+               return -ENOMEM;
 
-       ret = of_pm_clk_add_clk(&pdev->dev, "ape");
-       if (ret)
-               goto clk_destroy;
+       aconnect->ape_clk = devm_clk_get(&pdev->dev, "ape");
+       if (IS_ERR(aconnect->ape_clk)) {
+               dev_err(&pdev->dev, "Can't retrieve ape clock\n");
+               return PTR_ERR(aconnect->ape_clk);
+       }
 
-       ret = of_pm_clk_add_clk(&pdev->dev, "apb2ape");
-       if (ret)
-               goto clk_destroy;
+       aconnect->apb2ape_clk = devm_clk_get(&pdev->dev, "apb2ape");
+       if (IS_ERR(aconnect->apb2ape_clk)) {
+               dev_err(&pdev->dev, "Can't retrieve apb2ape clock\n");
+               return PTR_ERR(aconnect->apb2ape_clk);
+       }
 
+       dev_set_drvdata(&pdev->dev, aconnect);
        pm_runtime_enable(&pdev->dev);
 
        of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
@@ -41,35 +51,51 @@ static int tegra_aconnect_probe(struct platform_device *pdev)
        dev_info(&pdev->dev, "Tegra ACONNECT bus registered\n");
 
        return 0;
-
-clk_destroy:
-       pm_clk_destroy(&pdev->dev);
-
-       return ret;
 }
 
 static int tegra_aconnect_remove(struct platform_device *pdev)
 {
        pm_runtime_disable(&pdev->dev);
 
-       pm_clk_destroy(&pdev->dev);
-
        return 0;
 }
 
 static int tegra_aconnect_runtime_resume(struct device *dev)
 {
-       return pm_clk_resume(dev);
+       struct tegra_aconnect *aconnect = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(aconnect->ape_clk);
+       if (ret) {
+               dev_err(dev, "ape clk_enable failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(aconnect->apb2ape_clk);
+       if (ret) {
+               clk_disable_unprepare(aconnect->ape_clk);
+               dev_err(dev, "apb2ape clk_enable failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
 }
 
 static int tegra_aconnect_runtime_suspend(struct device *dev)
 {
-       return pm_clk_suspend(dev);
+       struct tegra_aconnect *aconnect = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(aconnect->ape_clk);
+       clk_disable_unprepare(aconnect->apb2ape_clk);
+
+       return 0;
 }
 
 static const struct dev_pm_ops tegra_aconnect_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra_aconnect_runtime_suspend,
                           tegra_aconnect_runtime_resume, NULL)
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                                     pm_runtime_force_resume)
 };
 
 static const struct of_device_id tegra_aconnect_of_match[] = {
index d299ec79e4c38bd4b5117b87bd75d639fe596ea1..308475ed4b32ad97033cb7e9df26817c2e3a3986 100644 (file)
@@ -47,7 +47,10 @@ enum sysc_clocks {
        SYSC_MAX_CLOCKS,
 };
 
-static const char * const clock_names[SYSC_ICK + 1] = { "fck", "ick", };
+static const char * const clock_names[SYSC_MAX_CLOCKS] = {
+       "fck", "ick", "opt0", "opt1", "opt2", "opt3", "opt4",
+       "opt5", "opt6", "opt7",
+};
 
 #define SYSC_IDLEMODE_MASK             3
 #define SYSC_CLOCKACTIVITY_MASK                3
@@ -75,6 +78,7 @@ struct sysc {
        u32 module_size;
        void __iomem *module_va;
        int offsets[SYSC_MAX_REGS];
+       struct ti_sysc_module_data *mdata;
        struct clk **clocks;
        const char **clock_roles;
        int nr_clocks;
@@ -94,7 +98,7 @@ struct sysc {
 static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
                                  bool is_child);
 
-void sysc_write(struct sysc *ddata, int offset, u32 value)
+static void sysc_write(struct sysc *ddata, int offset, u32 value)
 {
        writel_relaxed(value, ddata->module_va + offset);
 }
@@ -128,6 +132,81 @@ static u32 sysc_read_revision(struct sysc *ddata)
        return sysc_read(ddata, offset);
 }
 
+static int sysc_add_named_clock_from_child(struct sysc *ddata,
+                                          const char *name,
+                                          const char *optfck_name)
+{
+       struct device_node *np = ddata->dev->of_node;
+       struct device_node *child;
+       struct clk_lookup *cl;
+       struct clk *clock;
+       const char *n;
+
+       if (name)
+               n = name;
+       else
+               n = optfck_name;
+
+       /* Does the clock alias already exist? */
+       clock = of_clk_get_by_name(np, n);
+       if (!IS_ERR(clock)) {
+               clk_put(clock);
+
+               return 0;
+       }
+
+       child = of_get_next_available_child(np, NULL);
+       if (!child)
+               return -ENODEV;
+
+       clock = devm_get_clk_from_child(ddata->dev, child, name);
+       if (IS_ERR(clock))
+               return PTR_ERR(clock);
+
+       /*
+        * Use clkdev_add() instead of clkdev_alloc() to avoid the MAX_DEV_ID
+        * limit for clk_get(). If cl ever needs to be freed, it should be done
+        * with clkdev_drop().
+        */
+       cl = kcalloc(1, sizeof(*cl), GFP_KERNEL);
+       if (!cl)
+               return -ENOMEM;
+
+       cl->con_id = n;
+       cl->dev_id = dev_name(ddata->dev);
+       cl->clk = clock;
+       clkdev_add(cl);
+
+       clk_put(clock);
+
+       return 0;
+}
+
+static int sysc_init_ext_opt_clock(struct sysc *ddata, const char *name)
+{
+       const char *optfck_name;
+       int error, index;
+
+       if (ddata->nr_clocks < SYSC_OPTFCK0)
+               index = SYSC_OPTFCK0;
+       else
+               index = ddata->nr_clocks;
+
+       if (name)
+               optfck_name = name;
+       else
+               optfck_name = clock_names[index];
+
+       error = sysc_add_named_clock_from_child(ddata, name, optfck_name);
+       if (error)
+               return error;
+
+       ddata->clock_roles[index] = optfck_name;
+       ddata->nr_clocks++;
+
+       return 0;
+}
+
 static int sysc_get_one_clock(struct sysc *ddata, const char *name)
 {
        int error, i, index = -ENODEV;
@@ -199,6 +278,12 @@ static int sysc_get_clocks(struct sysc *ddata)
        if (ddata->nr_clocks < 1)
                return 0;
 
+       if ((ddata->cfg.quirks & SYSC_QUIRK_EXT_OPT_CLOCK)) {
+               error = sysc_init_ext_opt_clock(ddata, NULL);
+               if (error)
+                       return error;
+       }
+
        if (ddata->nr_clocks > SYSC_MAX_CLOCKS) {
                dev_err(ddata->dev, "too many clocks for %pOF\n", np);
 
@@ -231,39 +316,125 @@ static int sysc_get_clocks(struct sysc *ddata)
        return 0;
 }
 
+static int sysc_enable_main_clocks(struct sysc *ddata)
+{
+       struct clk *clock;
+       int i, error;
+
+       if (!ddata->clocks)
+               return 0;
+
+       for (i = 0; i < SYSC_OPTFCK0; i++) {
+               clock = ddata->clocks[i];
+
+               /* Main clocks may not have ick */
+               if (IS_ERR_OR_NULL(clock))
+                       continue;
+
+               error = clk_enable(clock);
+               if (error)
+                       goto err_disable;
+       }
+
+       return 0;
+
+err_disable:
+       for (i--; i >= 0; i--) {
+               clock = ddata->clocks[i];
+
+               /* Main clocks may not have ick */
+               if (IS_ERR_OR_NULL(clock))
+                       continue;
+
+               clk_disable(clock);
+       }
+
+       return error;
+}
+
+static void sysc_disable_main_clocks(struct sysc *ddata)
+{
+       struct clk *clock;
+       int i;
+
+       if (!ddata->clocks)
+               return;
+
+       for (i = 0; i < SYSC_OPTFCK0; i++) {
+               clock = ddata->clocks[i];
+               if (IS_ERR_OR_NULL(clock))
+                       continue;
+
+               clk_disable(clock);
+       }
+}
+
+static int sysc_enable_opt_clocks(struct sysc *ddata)
+{
+       struct clk *clock;
+       int i, error;
+
+       if (!ddata->clocks)
+               return 0;
+
+       for (i = SYSC_OPTFCK0; i < SYSC_MAX_CLOCKS; i++) {
+               clock = ddata->clocks[i];
+
+               /* Assume no holes for opt clocks */
+               if (IS_ERR_OR_NULL(clock))
+                       return 0;
+
+               error = clk_enable(clock);
+               if (error)
+                       goto err_disable;
+       }
+
+       return 0;
+
+err_disable:
+       for (i--; i >= 0; i--) {
+               clock = ddata->clocks[i];
+               if (IS_ERR_OR_NULL(clock))
+                       continue;
+
+               clk_disable(clock);
+       }
+
+       return error;
+}
+
+static void sysc_disable_opt_clocks(struct sysc *ddata)
+{
+       struct clk *clock;
+       int i;
+
+       if (!ddata->clocks)
+               return;
+
+       for (i = SYSC_OPTFCK0; i < SYSC_MAX_CLOCKS; i++) {
+               clock = ddata->clocks[i];
+
+               /* Assume no holes for opt clocks */
+               if (IS_ERR_OR_NULL(clock))
+                       return;
+
+               clk_disable(clock);
+       }
+}
+
 /**
- * sysc_init_resets - reset module on init
+ * sysc_init_resets - init rstctrl reset line if configured
  * @ddata: device driver data
  *
- * A module can have both OCP softreset control and external rstctrl.
- * If more complicated rstctrl resets are needed, please handle these
- * directly from the child device driver and map only the module reset
- * for the parent interconnect target module device.
- *
- * Automatic reset of the module on init can be skipped with the
- * "ti,no-reset-on-init" device tree property.
+ * See sysc_rstctrl_reset_deassert().
  */
 static int sysc_init_resets(struct sysc *ddata)
 {
-       int error;
-
        ddata->rsts =
                devm_reset_control_array_get_optional_exclusive(ddata->dev);
        if (IS_ERR(ddata->rsts))
                return PTR_ERR(ddata->rsts);
 
-       if (ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
-               goto deassert;
-
-       error = reset_control_assert(ddata->rsts);
-       if (error)
-               return error;
-
-deassert:
-       error = reset_control_deassert(ddata->rsts);
-       if (error)
-               return error;
-
        return 0;
 }
 
@@ -622,91 +793,239 @@ static void sysc_show_registers(struct sysc *ddata)
                buf);
 }
 
-static int __maybe_unused sysc_runtime_suspend(struct device *dev)
+#define SYSC_IDLE_MASK (SYSC_NR_IDLEMODES - 1)
+
+static int sysc_enable_module(struct device *dev)
 {
-       struct ti_sysc_platform_data *pdata;
        struct sysc *ddata;
-       int error = 0, i;
+       const struct sysc_regbits *regbits;
+       u32 reg, idlemodes, best_mode;
 
        ddata = dev_get_drvdata(dev);
+       if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV)
+               return 0;
 
-       if (!ddata->enabled)
+       /*
+        * TODO: Need to prevent clockdomain autoidle?
+        * See clkdm_deny_idle() in arch/mach-omap2/omap_hwmod.c
+        */
+
+       regbits = ddata->cap->regbits;
+       reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
+
+       /* Set SIDLE mode */
+       idlemodes = ddata->cfg.sidlemodes;
+       if (!idlemodes || regbits->sidle_shift < 0)
+               goto set_midle;
+
+       best_mode = fls(ddata->cfg.sidlemodes) - 1;
+       if (best_mode > SYSC_IDLE_MASK) {
+               dev_err(dev, "%s: invalid sidlemode\n", __func__);
+               return -EINVAL;
+       }
+
+       reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift);
+       reg |= best_mode << regbits->sidle_shift;
+       sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
+
+set_midle:
+       /* Set MIDLE mode */
+       idlemodes = ddata->cfg.midlemodes;
+       if (!idlemodes || regbits->midle_shift < 0)
                return 0;
 
-       if (ddata->legacy_mode) {
-               pdata = dev_get_platdata(ddata->dev);
-               if (!pdata)
-                       return 0;
+       best_mode = fls(ddata->cfg.midlemodes) - 1;
+       if (best_mode > SYSC_IDLE_MASK) {
+               dev_err(dev, "%s: invalid midlemode\n", __func__);
+               return -EINVAL;
+       }
 
-               if (!pdata->idle_module)
-                       return -ENODEV;
+       reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
+       reg |= best_mode << regbits->midle_shift;
+       sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
 
-               error = pdata->idle_module(dev, &ddata->cookie);
-               if (error)
-                       dev_err(dev, "%s: could not idle: %i\n",
-                               __func__, error);
+       return 0;
+}
+
+static int sysc_best_idle_mode(u32 idlemodes, u32 *best_mode)
+{
+       if (idlemodes & BIT(SYSC_IDLE_SMART_WKUP))
+               *best_mode = SYSC_IDLE_SMART_WKUP;
+       else if (idlemodes & BIT(SYSC_IDLE_SMART))
+               *best_mode = SYSC_IDLE_SMART;
+       else if (idlemodes & SYSC_IDLE_FORCE)
+               *best_mode = SYSC_IDLE_FORCE;
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
+static int sysc_disable_module(struct device *dev)
+{
+       struct sysc *ddata;
+       const struct sysc_regbits *regbits;
+       u32 reg, idlemodes, best_mode;
+       int ret;
 
-               goto idled;
+       ddata = dev_get_drvdata(dev);
+       if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV)
+               return 0;
+
+       /*
+        * TODO: Need to prevent clockdomain autoidle?
+        * See clkdm_deny_idle() in arch/mach-omap2/omap_hwmod.c
+        */
+
+       regbits = ddata->cap->regbits;
+       reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
+
+       /* Set MIDLE mode */
+       idlemodes = ddata->cfg.midlemodes;
+       if (!idlemodes || regbits->midle_shift < 0)
+               goto set_sidle;
+
+       ret = sysc_best_idle_mode(idlemodes, &best_mode);
+       if (ret) {
+               dev_err(dev, "%s: invalid midlemode\n", __func__);
+               return ret;
        }
 
-       for (i = 0; i < ddata->nr_clocks; i++) {
-               if (IS_ERR_OR_NULL(ddata->clocks[i]))
-                       continue;
+       reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
+       reg |= best_mode << regbits->midle_shift;
+       sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
 
-               if (i >= SYSC_OPTFCK0 && !sysc_opt_clks_needed(ddata))
-                       break;
+set_sidle:
+       /* Set SIDLE mode */
+       idlemodes = ddata->cfg.sidlemodes;
+       if (!idlemodes || regbits->sidle_shift < 0)
+               return 0;
 
-               clk_disable(ddata->clocks[i]);
+       ret = sysc_best_idle_mode(idlemodes, &best_mode);
+       if (ret) {
+               dev_err(dev, "%s: invalid sidlemode\n", __func__);
+               return ret;
        }
 
-idled:
-       ddata->enabled = false;
+       reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift);
+       reg |= best_mode << regbits->sidle_shift;
+       sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
 
-       return error;
+       return 0;
 }
 
-static int __maybe_unused sysc_runtime_resume(struct device *dev)
+static int __maybe_unused sysc_runtime_suspend_legacy(struct device *dev,
+                                                     struct sysc *ddata)
 {
        struct ti_sysc_platform_data *pdata;
+       int error;
+
+       pdata = dev_get_platdata(ddata->dev);
+       if (!pdata)
+               return 0;
+
+       if (!pdata->idle_module)
+               return -ENODEV;
+
+       error = pdata->idle_module(dev, &ddata->cookie);
+       if (error)
+               dev_err(dev, "%s: could not idle: %i\n",
+                       __func__, error);
+
+       return 0;
+}
+
+static int __maybe_unused sysc_runtime_resume_legacy(struct device *dev,
+                                                    struct sysc *ddata)
+{
+       struct ti_sysc_platform_data *pdata;
+       int error;
+
+       pdata = dev_get_platdata(ddata->dev);
+       if (!pdata)
+               return 0;
+
+       if (!pdata->enable_module)
+               return -ENODEV;
+
+       error = pdata->enable_module(dev, &ddata->cookie);
+       if (error)
+               dev_err(dev, "%s: could not enable: %i\n",
+                       __func__, error);
+
+       return 0;
+}
+
+static int __maybe_unused sysc_runtime_suspend(struct device *dev)
+{
        struct sysc *ddata;
-       int error = 0, i;
+       int error = 0;
 
        ddata = dev_get_drvdata(dev);
 
-       if (ddata->enabled)
+       if (!ddata->enabled)
                return 0;
 
        if (ddata->legacy_mode) {
-               pdata = dev_get_platdata(ddata->dev);
-               if (!pdata)
-                       return 0;
+               error = sysc_runtime_suspend_legacy(dev, ddata);
+               if (error)
+                       return error;
+       } else {
+               error = sysc_disable_module(dev);
+               if (error)
+                       return error;
+       }
 
-               if (!pdata->enable_module)
-                       return -ENODEV;
+       sysc_disable_main_clocks(ddata);
 
-               error = pdata->enable_module(dev, &ddata->cookie);
-               if (error)
-                       dev_err(dev, "%s: could not enable: %i\n",
-                               __func__, error);
+       if (sysc_opt_clks_needed(ddata))
+               sysc_disable_opt_clocks(ddata);
 
-               goto awake;
-       }
+       ddata->enabled = false;
 
-       for (i = 0; i < ddata->nr_clocks; i++) {
-               if (IS_ERR_OR_NULL(ddata->clocks[i]))
-                       continue;
+       return error;
+}
 
-               if (i >= SYSC_OPTFCK0 && !sysc_opt_clks_needed(ddata))
-                       break;
+static int __maybe_unused sysc_runtime_resume(struct device *dev)
+{
+       struct sysc *ddata;
+       int error = 0;
+
+       ddata = dev_get_drvdata(dev);
 
-               error = clk_enable(ddata->clocks[i]);
+       if (ddata->enabled)
+               return 0;
+
+       if (sysc_opt_clks_needed(ddata)) {
+               error = sysc_enable_opt_clocks(ddata);
                if (error)
                        return error;
        }
 
-awake:
+       error = sysc_enable_main_clocks(ddata);
+       if (error)
+               goto err_opt_clocks;
+
+       if (ddata->legacy_mode) {
+               error = sysc_runtime_resume_legacy(dev, ddata);
+               if (error)
+                       goto err_main_clocks;
+       } else {
+               error = sysc_enable_module(dev);
+               if (error)
+                       goto err_main_clocks;
+       }
+
        ddata->enabled = true;
 
+       return 0;
+
+err_main_clocks:
+       sysc_disable_main_clocks(ddata);
+err_opt_clocks:
+       if (sysc_opt_clks_needed(ddata))
+               sysc_disable_opt_clocks(ddata);
+
        return error;
 }
 
@@ -788,12 +1107,17 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
        SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x4fff1301, 0xffff00ff,
                   0),
        SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
-                  SYSC_QUIRK_LEGACY_IDLE),
+                  SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
        /* Uarts on omap4 and later */
        SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffff00ff,
-                  SYSC_QUIRK_LEGACY_IDLE),
+                  SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
        SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47422e03, 0xffffffff,
-                  SYSC_QUIRK_LEGACY_IDLE),
+                  SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
+
+       /* Quirks that need to be set based on the module address */
+       SYSC_QUIRK("mcpdm", 0x40132000, 0, 0x10, -1, 0x50000800, 0xffffffff,
+                  SYSC_QUIRK_EXT_OPT_CLOCK | SYSC_QUIRK_NO_RESET_ON_INIT |
+                  SYSC_QUIRK_SWSUP_SIDLE),
 
 #ifdef DEBUG
        SYSC_QUIRK("adc", 0, 0, 0x10, -1, 0x47300001, 0xffffffff, 0),
@@ -805,6 +1129,7 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
                   0xffff00f0, 0),
        SYSC_QUIRK("dcan", 0, 0, -1, -1, 0xffffffff, 0xffffffff, 0),
        SYSC_QUIRK("dcan", 0, 0, -1, -1, 0x00001401, 0xffffffff, 0),
+       SYSC_QUIRK("dmic", 0, 0, 0x10, -1, 0x50010000, 0xffffffff, 0),
        SYSC_QUIRK("dwc3", 0, 0, 0x10, -1, 0x500a0200, 0xffffffff, 0),
        SYSC_QUIRK("epwmss", 0, 0, 0x4, -1, 0x47400001, 0xffffffff, 0),
        SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0),
@@ -853,6 +1178,42 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
 #endif
 };
 
+/*
+ * Early quirks based on module base and register offsets only that are
+ * needed before the module revision can be read
+ */
+static void sysc_init_early_quirks(struct sysc *ddata)
+{
+       const struct sysc_revision_quirk *q;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(sysc_revision_quirks); i++) {
+               q = &sysc_revision_quirks[i];
+
+               if (!q->base)
+                       continue;
+
+               if (q->base != ddata->module_pa)
+                       continue;
+
+               if (q->rev_offset >= 0 &&
+                   q->rev_offset != ddata->offsets[SYSC_REVISION])
+                       continue;
+
+               if (q->sysc_offset >= 0 &&
+                   q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG])
+                       continue;
+
+               if (q->syss_offset >= 0 &&
+                   q->syss_offset != ddata->offsets[SYSC_SYSSTATUS])
+                       continue;
+
+               ddata->name = q->name;
+               ddata->cfg.quirks |= q->quirks;
+       }
+}
+
+/* Quirks that also consider the revision register value */
 static void sysc_init_revision_quirks(struct sysc *ddata)
 {
        const struct sysc_revision_quirk *q;
@@ -885,6 +1246,55 @@ static void sysc_init_revision_quirks(struct sysc *ddata)
        }
 }
 
+/*
+ * Note that pdata->init_module() typically does a reset first. After
+ * pdata->init_module() is done, PM runtime can be used for the interconnect
+ * target module.
+ */
+static int sysc_legacy_init(struct sysc *ddata)
+{
+       struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev);
+       int error;
+
+       if (!ddata->legacy_mode || !pdata || !pdata->init_module)
+               return 0;
+
+       error = pdata->init_module(ddata->dev, ddata->mdata, &ddata->cookie);
+       if (error == -EEXIST)
+               error = 0;
+
+       return error;
+}
+
+/**
+ * sysc_rstctrl_reset_deassert - deassert rstctrl reset
+ * @ddata: device driver data
+ * @reset: reset before deassert
+ *
+ * A module can have both OCP softreset control and external rstctrl.
+ * If more complicated rstctrl resets are needed, please handle these
+ * directly from the child device driver and map only the module reset
+ * for the parent interconnect target module device.
+ *
+ * Automatic reset of the module on init can be skipped with the
+ * "ti,no-reset-on-init" device tree property.
+ */
+static int sysc_rstctrl_reset_deassert(struct sysc *ddata, bool reset)
+{
+       int error;
+
+       if (!ddata->rsts)
+               return 0;
+
+       if (reset) {
+               error = reset_control_assert(ddata->rsts);
+               if (error)
+                       return error;
+       }
+
+       return reset_control_deassert(ddata->rsts);
+}
+
 static int sysc_reset(struct sysc *ddata)
 {
        int offset = ddata->offsets[SYSC_SYSCONFIG];
@@ -915,38 +1325,58 @@ static int sysc_reset(struct sysc *ddata)
                                  100, MAX_MODULE_SOFTRESET_WAIT);
 }
 
-/* At this point the module is configured enough to read the revision */
+/*
+ * At this point the module is configured enough to read the revision but
+ * module may not be completely configured yet to use PM runtime. Enable
+ * all clocks directly during init to configure the quirks needed for PM
+ * runtime based on the revision register.
+ */
 static int sysc_init_module(struct sysc *ddata)
 {
-       int error;
+       int error = 0;
+       bool manage_clocks = true;
+       bool reset = true;
 
-       if (ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE_ON_INIT) {
-               ddata->revision = sysc_read_revision(ddata);
-               goto rev_quirks;
-       }
+       if (ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
+               reset = false;
 
-       error = pm_runtime_get_sync(ddata->dev);
-       if (error < 0) {
-               pm_runtime_put_noidle(ddata->dev);
+       error = sysc_rstctrl_reset_deassert(ddata, reset);
+       if (error)
+               return error;
 
-               return 0;
-       }
+       if (ddata->cfg.quirks &
+           (SYSC_QUIRK_NO_IDLE | SYSC_QUIRK_NO_IDLE_ON_INIT))
+               manage_clocks = false;
 
-       error = sysc_reset(ddata);
-       if (error) {
-               dev_err(ddata->dev, "Reset failed with %d\n", error);
-               pm_runtime_put_sync(ddata->dev);
+       if (manage_clocks) {
+               error = sysc_enable_opt_clocks(ddata);
+               if (error)
+                       return error;
 
-               return error;
+               error = sysc_enable_main_clocks(ddata);
+               if (error)
+                       goto err_opt_clocks;
        }
 
        ddata->revision = sysc_read_revision(ddata);
-       pm_runtime_put_sync(ddata->dev);
-
-rev_quirks:
        sysc_init_revision_quirks(ddata);
 
-       return 0;
+       error = sysc_legacy_init(ddata);
+       if (error)
+               goto err_main_clocks;
+
+       error = sysc_reset(ddata);
+       if (error)
+               dev_err(ddata->dev, "Reset failed with %d\n", error);
+
+err_main_clocks:
+       if (manage_clocks)
+               sysc_disable_main_clocks(ddata);
+err_opt_clocks:
+       if (manage_clocks)
+               sysc_disable_opt_clocks(ddata);
+
+       return error;
 }
 
 static int sysc_init_sysc_mask(struct sysc *ddata)
@@ -1208,7 +1638,7 @@ static int sysc_child_resume_noirq(struct device *dev)
 }
 #endif
 
-struct dev_pm_domain sysc_child_pm_domain = {
+static struct dev_pm_domain sysc_child_pm_domain = {
        .ops = {
                SET_RUNTIME_PM_OPS(sysc_child_runtime_suspend,
                                   sysc_child_runtime_resume,
@@ -1281,6 +1711,8 @@ static const struct sysc_dts_quirk sysc_dts_quirks[] = {
          .mask = SYSC_QUIRK_NO_IDLE_ON_INIT, },
        { .name = "ti,no-reset-on-init",
          .mask = SYSC_QUIRK_NO_RESET_ON_INIT, },
+       { .name = "ti,no-idle",
+         .mask = SYSC_QUIRK_NO_IDLE, },
 };
 
 static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
@@ -1331,6 +1763,9 @@ static void sysc_unprepare(struct sysc *ddata)
 {
        int i;
 
+       if (!ddata->clocks)
+               return;
+
        for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
                if (!IS_ERR_OR_NULL(ddata->clocks[i]))
                        clk_unprepare(ddata->clocks[i]);
@@ -1576,28 +2011,26 @@ static const struct sysc_capabilities sysc_dra7_mcan = {
 static int sysc_init_pdata(struct sysc *ddata)
 {
        struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev);
-       struct ti_sysc_module_data mdata;
-       int error = 0;
+       struct ti_sysc_module_data *mdata;
 
        if (!pdata || !ddata->legacy_mode)
                return 0;
 
-       mdata.name = ddata->legacy_mode;
-       mdata.module_pa = ddata->module_pa;
-       mdata.module_size = ddata->module_size;
-       mdata.offsets = ddata->offsets;
-       mdata.nr_offsets = SYSC_MAX_REGS;
-       mdata.cap = ddata->cap;
-       mdata.cfg = &ddata->cfg;
+       mdata = devm_kzalloc(ddata->dev, sizeof(*mdata), GFP_KERNEL);
+       if (!mdata)
+               return -ENOMEM;
 
-       if (!pdata->init_module)
-               return -ENODEV;
+       mdata->name = ddata->legacy_mode;
+       mdata->module_pa = ddata->module_pa;
+       mdata->module_size = ddata->module_size;
+       mdata->offsets = ddata->offsets;
+       mdata->nr_offsets = SYSC_MAX_REGS;
+       mdata->cap = ddata->cap;
+       mdata->cfg = &ddata->cfg;
 
-       error = pdata->init_module(ddata->dev, &mdata, &ddata->cookie);
-       if (error == -EEXIST)
-               error = 0;
+       ddata->mdata = mdata;
 
-       return error;
+       return 0;
 }
 
 static int sysc_init_match(struct sysc *ddata)
@@ -1651,10 +2084,6 @@ static int sysc_probe(struct platform_device *pdev)
        if (error)
                goto unprepare;
 
-       error = sysc_get_clocks(ddata);
-       if (error)
-               return error;
-
        error = sysc_map_and_check_registers(ddata);
        if (error)
                goto unprepare;
@@ -1675,15 +2104,21 @@ static int sysc_probe(struct platform_device *pdev)
        if (error)
                goto unprepare;
 
+       sysc_init_early_quirks(ddata);
+
+       error = sysc_get_clocks(ddata);
+       if (error)
+               return error;
+
        error = sysc_init_resets(ddata);
        if (error)
                return error;
 
-       pm_runtime_enable(ddata->dev);
        error = sysc_init_module(ddata);
        if (error)
                goto unprepare;
 
+       pm_runtime_enable(ddata->dev);
        error = pm_runtime_get_sync(ddata->dev);
        if (error < 0) {
                pm_runtime_put_noidle(ddata->dev);
index 02d3bcd6216cbac49ea584a0e205c6d664c58ce7..71c2e9519ca847166407b560c7cd7438d6a5b894 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/device.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/slab.h>
 #include <linux/of.h>
index c68dada973168474ff063b2eba98a11bfec5556e..aba787b2e77181fa89f4f739b91a080eac853876 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/device.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
 #include <linux/slab.h>
index 2a2c7569336acaff1ce9caa0fca1cbf11739eaa3..b6d07ca0164f3c0e4e76551781f3787bb4d8175d 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <dt-bindings/clock/bcm2835-aux.h>
index 9fcae932e082f30b0667903e1e89168fa3e16df2..770bb01f523ed6bc6b304f019b50c323a2ed5339 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/clk.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
index eee64b9e5d10b497d8362acbb92ad8312c9ce4f5..cc3b1e1bc0871ba5abd2c896badb7697d014e714 100644 (file)
@@ -15,8 +15,9 @@
 #include "clk-kona.h"
 
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
-#include <linux/clk.h>
+#include <linux/clk-provider.h>
 
 /*
  * "Policies" affect the frequencies of bus clocks provided by a
index 4d0be66aa6a8cc979088a84655ef06cd6614ef02..eb14a5bc050723561cf4f771d0f8558135b078db 100644 (file)
@@ -7,6 +7,7 @@
  */
 #include <linux/bitops.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/slab.h>
index 0b4b44a2579e1d689660889870021d70446d1e96..bccdfa00fd37394aa62538356783ccd3a9eef8e3 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
index 9b9db743df2550bca44bb8783cdba29b63e1a306..e9518d35f262e171cb1233707579f8b8102a4023 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
index d1a97d971183ed17514637be619c4e010b3fd00a..51f26619b6a23383bbf745a250d74d479146ea40 100644 (file)
@@ -10,8 +10,9 @@
  */
 
 #include <linux/clk-provider.h>
-#include <linux/of_address.h>
+#include <linux/io.h>
 #include <linux/module.h>
+#include <linux/of_address.h>
 #include <linux/platform_device.h>
 
 static struct clk_hw *fixed_mmio_clk_setup(struct device_node *node)
index d81f1d2e9129887595168be8b36faa9f3f7fde41..b1e556f20911f408875fbf7decfbb7131d2fba9e 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/slab.h>
index a47c2b600f20c188fde5c037321afe960dbcd7d9..97d1e8c35b71314b374266b3eea0972c2c560d97 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
index 94470b4eadf41e94f4ea95cf0c337dbc66c079e7..e507aa958da91683ec83837df28fc48be4b7bafa 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/export.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/of.h>
 #include <linux/slab.h>
index 0f7198191ea29d53e1d96633a719dc1f7c5b1632..bf120bec59aef3da93622e1f36adf9636f5557fc 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/clkdev.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/mfd/da8xx-cfgchip.h>
 #include <linux/mfd/syscon.h>
index d413ade95c99337ffd7f17dac9c5380911c9bc0e..376be03bb546f73a98f80ac02c8cf5859ac0b69d 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 
index c7ae653c8a16035ba173addeb38b0a1af6f3b848..67c495b67c18a25c0399ac94a009d7ba8354e8d2 100644 (file)
@@ -6,8 +6,9 @@
  */
 
 #include <linux/clk-provider.h>
-#include <linux/err.h>
 #include <linux/device.h>
+#include <linux/io.h>
+#include <linux/err.h>
 #include <linux/of_address.h>
 #include <linux/slab.h>
 
index e8b2c43b1bb86f17612b63534172a7332f44f6eb..89934bee7c9ec44ff5445281f641fcd62f357530 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/mailbox_client.h>
 #include <linux/module.h>
 #include <linux/of.h>
index 574fac1a169f46c5699a37355aa2f7f280db1efd..388bdb94f841da0a153cb024346832d282e853b8 100644 (file)
@@ -3,9 +3,10 @@
  * Copyright 2018 NXP
  */
 
+#include <linux/clk-provider.h>
 #include <linux/errno.h>
+#include <linux/io.h>
 #include <linux/slab.h>
-#include <linux/clk-provider.h>
 
 #include "clk.h"
 
index 76b9eb15604e1d241c0a91e7358de37e83a48a40..fece503e3610375e070cab00cd8f3f0bcd96401a 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/slab.h>
 #include <linux/bitfield.h>
index e63188eb08ac9d1a0794850d8766d01fd7285f2a..6e93284c397b0acc541ad06341f7595eb68cd985 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <dt-bindings/clock/imx21-clock.h>
index 0a0ab95d16fe6f18380c4ca846b47beb7f9c0927..a3753067fc120d5997418e158edff1773e798d63 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <dt-bindings/clock/imx27-clock.h>
index fb567dcc21185bb714982d5f3999d6d6065e944f..a03bbed662c6bccd94f13497298a0d474e772705 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/slab.h>
 
index d7e62c3620d36941f498e3519bc2f03e203a26a3..8155b12cf0e1a8c5e966358938147a1c1af08620 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/slab.h>
 
index 991bbe63f15633e35767ef96bddede264f8584ff..5d65f65c512e601637bcea860d07decd983cacdb 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/slab.h>
 #include <linux/bitfield.h>
index 510b685212d3f3a92611f4315b79175d53ecf5cc..b80af61dc1f320ed88c7190cd47148faff300158 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/math64.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
index b86edd3282493388590e979eea386cd8b8cdbef9..25f7df028e6775c992c6fec394c9aece15fbb03b 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <dt-bindings/clock/jz4740-cgu.h>
 #include <asm/mach-jz4740/clock.h>
index bf46a0df2004e22d58d7ee7494c2d532e178f3a8..dfce740c25a8aafa5192f448b3d012225a49ce84 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/bitops.h>
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/syscore_ops.h>
 #include <dt-bindings/clock/jz4770-cgu.h>
index 6427be117ff117fce04b5c6b2d2d5b807f1ceb17..d03b7fcfd82be88c761b82fde5d98df781560fc1 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <dt-bindings/clock/jz4780-cgu.h>
 #include "cgu.h"
index 3466f7320b40be2494190ab5a0d5c3200c1d32e3..22a165ef65cf6db1051136a650a1944a1af43ab6 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/clkdev.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 
 #include <loongson1.h>
 #include "clk.h"
index c3b301463425f171acb8153559f5391ac82de94e..4680064f1951175d10930e72dfcf356c7a0c8441 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/iopoll.h>
 #include <asm/mach-pic32/pic32.h>
 #include <asm/traps.h>
index 9f734779be9258055f52bdf2a46a30fd3dd49364..e6c05df2d47f6d0ce5ab73f853b68b8129f441c3 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
index 1f1cff428d7888eb61a2e8e1a046f6d4b6847105..5fc6d486a3812de5ac1b7c65feb9d00b57149951 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/mfd/syscon.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
index ee272d4d8c24ffd6637944dafeaa8f875b53a269..585a02e0b330f2a447ebf5a31e86fedeeabdd2d3 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
index 1fc84b0e72eec18ef5cddd7c3ba6d9ff4ea5e70c..818b175391fadb9dbfd2ea7950598741b008d0ba 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/kernel.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
index 5969f620607a7a1f3c61e741e39966621ef30b93..f2e171a01fb4c3063ae449932a1cfe8c5d8e97b7 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
index f5bc8bd192b7eb49777266463aee6656fd1c3514..8b686da5577b3b8038b0507d8075551cab48c5fc 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
index 7524d19fe60b13eedd548fb4401d00304a7c09aa..7f67c1036ff9f69ff2d313512cb4c5148ba32103 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/regmap.h>
 
index 42627bf8a09ee141aa73498c9850ceea55b419a5..5326f77eb35ae8f74cc338d32b9961e2959e8fa2 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
+#include <linux/io.h>
 #include <linux/of.h>
 
 #include <dt-bindings/clock/pxa-clock.h>
index 2719c248c67beb5fe1317c1c3bdd41ee5e2067f4..cfed11c659d91c73bfbb932fd1c2d56d442aa005 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/clk-provider.h>
 #include <linux/clk/renesas.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/of.h>
index 5967656c13cca91fd1b2822cd06ae27c407b906e..d8190f007a81c21274f3bd09851f4de5ea7b12e5 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/clk-provider.h>
 #include <linux/clk/renesas.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/of.h>
index 2913b414815748632686b6a1e980e84d5ce48c0d..da9fe3f032eb2a0dee30c4ed189cf88777aa846d 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/clk-provider.h>
 #include <linux/clk/renesas.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/math64.h>
 #include <linux/of.h>
index 3cda53a97f4e6b4a0d5b90bd2d70c279e8aa83e1..fbc34beafc7820eaf704d8ce8ddce045f84ab369 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/clk-provider.h>
 #include <linux/clk/renesas.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
index dc8ffc7c727a73a226912e826382e466e8049b0e..5f25a70bc61c40464971e44c108dda123d6d8365 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/clk-provider.h>
 #include <linux/clk/renesas.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
index 97c72477cd54aba0ca92a4f37b12e82354cb41ea..7d042183aa37e41458cdaf7c528574f9104dca91 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/math64.h>
 #include <linux/of.h>
index b241f9ca3d7146ba85b27ffff0355cc0e9f32277..cc90b11a9c250a0a243e424c94e2106c21d60802 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/clk-provider.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
index 30df0dc853f08c91c17c2a497ad2290ba67f5ec6..0201809bbd377df4edc2da317eff4737dbaec93d 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
index 784b81e1ea7c656a30f24d6db834b13eecaee1c2..ba9f00dc9740c610af87c1a42f669067692cf426 100644 (file)
@@ -3,8 +3,9 @@
  * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
  */
 
-#include <linux/slab.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/slab.h>
 #include "clk.h"
 
 #define div_mask(width)        ((1 << (width)) - 1)
index 601a77f1af789cb899715faa6fad8e89363005a0..68d23be18cbceba6a313a72dc90e41489dcfcd34 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/syscore_ops.h>
index c3001980dbdc50fd0201db64cc958a1fc8b02d47..3bf919b6c6e33c208c788eedc112a6d42f48f398 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/syscore_ops.h>
index 5970a50671b9a6638d637f8a017e1cc0cf063e97..8278a54db3437873415d47e4b27c991b535a01b7 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/syscore_ops.h>
index 5ecf28854876ae24169456ca26df5ab6160cb576..378420b8835a2669af9037d9aae9bba2f312c571 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <dt-bindings/clock/rk3188-cru-common.h>
index 7af48184b0224b1428ba1e9788f941511a47c9bb..7176003b5c7cae6b937a70253a743039dee64bf2 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/syscore_ops.h>
index 24baeb56a1b3df53ac7a71ef5214c7a641df78fc..85907f31c63f365ac5d38700e3628b54b74d2913 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/syscore_ops.h>
index f12142d9cea2a0c68101c083993238a0f15fd5d3..9b03c1abf19cf1b764a039458d7a7012ad91efba 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/syscore_ops.h>
index 7c4d242f19c1003b55cc6eee69af7ff503bfe820..d239bbc2fc776a1b3e22bc2c69ce486c0738620f 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
index 5a628148f3f02a641970962dfc864bf8859bf33a..2322d712ba88dd39f1e7052324c6fbcafa1ca6d7 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
index 089cb17925e5b0ade3ae880132a4657845eb2176..6c051aa04e59b427f77bbf6569438d9ee9ae925a 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/syscore_ops.h>
index 0ea8e8080d1a663ca0e09f6da3746afa2e925ee8..d5fac5a8a3d74af2e71e191b2b88141f205cb476 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
 #include <linux/reboot.h>
index a5fddebbe530532be49c3c4dc7e3cfdf6d6deea0..3f80bcd4607415799f073486ea6fadab02237c6e 100644 (file)
@@ -33,6 +33,7 @@
 */
 
 #include <linux/errno.h>
+#include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
index 9c95390d2d773cf9a8894f8ae1e2d81e9f1fa013..ce41f36a0e29e5595375966a664f031188b0838a 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/syscore_ops.h>
index 0e9a41a4cac8da875ee71645fd6803aff005d513..facaad3c56a1d805a9523c771c88f4cd96e73b0e 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
index 54066e6508d3eeb259e89c82e1bf318d0379fa81..d2a68a792a219c9e47ee91f6454fab0b44eb641d 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 
index 8ae44b5db4c2f59dbdb821e0564e6e82c6a5efd2..91db7894125df5bcf6cc1b5c014d4307a9520c25 100644 (file)
@@ -4,6 +4,7 @@
 // Author: Marek Szyprowski <m.szyprowski@samsung.com>
 // Common Clock Framework support for Exynos5 power-domain dependent clocks
 
+#include <linux/io.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
index f14139bcb0c119f5a975dd7759ae62ab0791774f..c8265c4cbc4f414e83cdbc19fe5c0c33dcd787b7 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <dt-bindings/clock/exynos5250.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 
index 1c4c7a3039f1bc53a5ccb1bc558fd304db50c677..0c6782ceac48edd5dcd3c7a2747681e2492faccc 100644 (file)
@@ -13,7 +13,8 @@
 #include <linux/hrtimer.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
 #include "clk.h"
 #include "clk-pll.h"
 
index 82f8ae22fd34982e41411efb89180428946351f4..0117e40c1d0a0b9372f49dfa9928abcea981da7b 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include "clk.h"
index dd1159050a5a54c498396d947756fb8f239f2f32..ce21b89d1eb194e20917aa7fb5e524e9a304b1de 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/reboot.h>
index f38f0e24e3b64746e2cd38ac2e73302224856250..b2ea4dfb5b8ca5a3f3d5b48da33e41d718089b71 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/reboot.h>
index 1f6e47cd327db413ec481ab5403c543b17797e56..9ad546a5f74c41b04655d7c2148ff5d90720ad74 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/clkdev.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/syscore_ops.h>
 
index 0ec8bf7b4b2846105f70d4a7770cfa522ba0a867..6282ee2f361cda507f69fe9a9b1eca75e27ad3ee 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/clk/analogbits-wrpll-cln28hpc.h>
 #include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_clk.h>
index eee2d48ab6563b42d7d2b4696ed0ed03b47775db..54a464fa63e09b7bb6a8ee54f9f4f8f7e6ea4768 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (C) 2017, Intel Corporation
  */
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/slab.h>
 #include "stratix10-clk.h"
 #include "clk.h"
index 568f59b58ddfa94852462ed8fd3531d48fff151c..5c50e723ecae7e945c85da36eacf514ffc71d81c 100644 (file)
@@ -4,6 +4,7 @@
  */
 #include <linux/slab.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 
 #include "stratix10-clk.h"
 #include "clk.h"
index c4d0b6f6abf2e1bb1a6027cd19bf0c22dc1b5cfe..4705eb544f01bdb90baa69b0ef006c773e159a9e 100644 (file)
@@ -4,6 +4,7 @@
  */
 #include <linux/slab.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 
 #include "stratix10-clk.h"
 #include "clk.h"
index c514d39760cb182efba76ca3f25294628123c8c4..23497f07ad89eab9ba193888d23562a1d9149445 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
index 129ebd2588fdcffe0ddcaf8cae447780b20969f9..2bbfb3343311e2c60067687fce316950a00e56b0 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 
 #include "ccu_common.h"
index be0deee7018252dec1a56e4acdf862d0ae0f3a79..d3fc1f5bf3967cc0a2b1736c15050ed51ce772d2 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
 
index 3c32d7798f27b2ff05c912ede945201074adfc64..9d3f989627797ac14175429cd6b0fbe1c64472b2 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
 
index fa2c2dd771021b05ff7782bd514d108b23078d1d..813e9bf73cbfae6bba8ccef8e05d8b4ff87cdbf7 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 
 #include "ccu_common.h"
index 609970c0b6665caa2e1a8babedffe2c5c771588a..b494c4fe0b2c116e5787b05e313a1e4e77f8107b 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 
 #include "ccu_common.h"
index 4b5f8f4e4ab8c197f61b4fcde8b3e4fd7e1a5847..a9c0c5406b85617c57e0b8aabcfb9d904e8b5cf4 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 
 #include "ccu_common.h"
index c7bf814dfd2be14d0f6e6547a4b5777ae6a63990..25bcf3fd2dfc5201962d389b15af3e44a91decc9 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 
 #include "ccu_common.h"
index 5f714b4d8ee42c1119f8ffb9dc7986798bf2ec1e..be5920e8a9cab48a4e090bfe197a180af118cb25 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
 
index e71e2451c2e3d6725c79a6deba041b5c361d9b3b..0f3df565c6c1a640727b7b976f51107fcdf178e1 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 
 #include "ccu_common.h"
index a22d11aa38babbada86fac2ec1952137f5e36f37..f9625f7b9ec2d106f4d06dd465d273f972b0abd5 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 
index eada0e2918591c0cbb589d79587c67651f141891..ec64eb692ecf91294a148cff75f063f8042927b8 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 
 #include "ccu_common.h"
index 8936ef87652c093aade64063c9aa710d8064fbc7..0e23583e4f586d08165d17f0c7e442bbb564e3f0 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
 
index dc9f0a365664ee1db6e17a0be0d8a637dd8802da..e748b8a6f3c5ad6fc02fc71fca2a2193736dd145 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 
 #include "ccu_common.h"
index 302a18efd39fa568b8a7ef362ff194e77823e617..6d407a8a61eedf903ab32c34c6d4890d81e73e13 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 
 #include "ccu_gate.h"
 #include "ccu_div.h"
index d1d168d4c4f00b2de8e30d1a9dc532e7fecc4578..1842603f8f11668df448a9e4cc3a0efc0cd556a8 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/spinlock.h>
 
 #include "ccu_frac.h"
index cd069d5da2150e116d043a06e86597e4a2264f85..9c81644e9dfe25bc76c2802bd6952464b455303e 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 
 #include "ccu_gate.h"
 
index f9869f7353c01473656c3521ac2601d7060319aa..b23410682088836a4f63c391940a724de6bccfc2 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/clk/sunxi-ng.h>
+#include <linux/io.h>
 
 #include "ccu_common.h"
 
index 0357349eb767a041dbc65077fa957f4aee6d7fbd..e17fb4c9fcfe70034ab512c456602b174f38d3e7 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 
 #include "ccu_gate.h"
 #include "ccu_mp.h"
index 12e0783caee64332ddc335c67d3928d0caca8b14..c2a672797a74adab40df28a1775e665b94cc6823 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 
 #include "ccu_gate.h"
 #include "ccu_mult.h"
index 312664155a5416bb9a4d6d6a753374f7463868f2..f9b409c3a89c772f41a48ca12e40267ce6855335 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
 #include "ccu_gate.h"
 #include "ccu_mux.h"
index 2485bda87a9a99851f2113fd4867406374bcdf6c..50c7e6b1ba130ae53a45b5526f3ea3c89329fcb1 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 
 #include "ccu_gate.h"
 #include "ccu_nk.h"
index 841840e35e610374f3f45dad562e4e97ce399554..aa5beaabc29293acbe56817309407092d48f7fe6 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 
 #include "ccu_gate.h"
 #include "ccu_nkm.h"
index cbcdf664f33604c283a64c2e57dea8342537a675..53ec4fb598805d7a991b4d82f14b0eafa936452c 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 
 #include "ccu_gate.h"
 #include "ccu_nkmp.h"
index 424d8635b0537b80ff072e01995a2d27d6c35dbf..e15413174aa7ae5ff67d4fc4bb7a723350c899d2 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 
 #include "ccu_frac.h"
 #include "ccu_gate.h"
index 400c58ad72fdffc98574e2bd190f5814a4685129..0a4a6fd13f5b80e38db6f5c867e0adc382b9d3fd 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/spinlock.h>
 
 #include "ccu_phase.h"
index 3b3dc9bdf2b00ee06b72d6be09fbbe3b064e0e7a..e510467ea24c2e7813dde03dfa2aacaa3d5b1096 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/spinlock.h>
 
 #include "ccu_sdm.h"
index e2819fa09637530e1e779df89aa48e093e0f8cf0..9e6796a7b4c4a6c86740816e5c6c0bdf8a2707b7 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/slab.h>
index d8eab90ae661c245507fc31d11139ff23ff28745..a709b6a551af5851e452b984be154d0ecf8ad3b2 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/slab.h>
index d9ea22ec4e258b0dc29024d1549086b89a668852..d119b453dccd87d6317485f0cf04a5b67e08b4f5 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/reset-controller.h>
index 3437f734c9bf1f7e2ba95051f2debbf71b3c3444..e6d639d9ea70446022246b2302d1a1a0b0ff3178 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/slab.h>
index fc0278a1acc7ac6219617f499c11eca1c5c395a5..915954507d0a006090c63a8f6d63a6f8e29f00dd 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
index a085c3bc127c5d33fd4c4dfd1dbd00cced8e040a..8130467d647a641f5d4ff74695b8c060aaa50c2e 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/slab.h>
index 9780fac6d029b9b1b85a03ce3d489b31be598281..bb2dc83fc697d3f6d7548af340d2b18451de1f22 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/of_address.h>
 #include <linux/reset-controller.h>
index f66267e77d9c5de3e72bef0c6e15e563a55183ab..c879d7e25ca0323a6f7e163961c783430874e9e3 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/slab.h>
index b6d29d1bedcaead534320d5a2cad836005821aac..af8ca5019639d3cf1f1c75a7ad1aea5a91a5f1ad 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/slab.h>
index d5c31804ee54a986bdec2ab21c40cd27c3c9d323..5a7d4dd09e85de7230f59345f9f986c92963cc73 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
index bee305bdddbed0cfd0fad640ae61a9ab7c7e7ccb..bfbcd71b225dd54393220e1936f4c60781745015 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/slab.h>
index 56db89b6979fb219b02e18786dbf3252e6fb1a17..0e924c9cbd5c7173f932a8eea558d134c1b7833d 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/of_address.h>
index 4d5e14142e15b9008f67897b70d2e4f3c0bb4f20..01255d827fc979d28faab5471266a3009c296a89 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/of.h>
index f00d8758ba24f6e5ed537a88be76ff85e5a7c5e4..da264d0f7f4b6655aa1129e7b5acd3174d81f151 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/reset.h>
index 892c29030b7b26772aa7a58b2598faab5c7bc94e..f5b1c00673650cf6d617c514af3405fd6813de81 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/reset-controller.h>
index 917fc27a33ddccc6f79349d8bf083e6ff9d461d4..7d15e0432ed4f61dd02d611e74093e440ae216a4 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/reset-controller.h>
index 93ecb538e59bbf272db3facad5c68f410ec10072..b7f763f0ecd8e6921fd15a046d9812b74ff2f6f2 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/clk.h>
 #include <linux/clkdev.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
index c57dfb037b10ad2488037ab8b89cce34977e3600..956f2215c73351ace2724c82bccd363f63917a98 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 
 #include "clk.h"
 
index 473d418533cb75546b40b7b210b79b41c5523c99..a5cd3e31dbaed5a44ffb616275a7bd7db77cf0ab 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/types.h>
 
 #include "clk.h"
index ffaf17f71860f98a198ebc33f31a4ccac6442931..6f2862eddad70029765a27cb6c65ccce8491eb41 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/clk/tegra.h>
 #include <linux/reset-controller.h>
index 0c210984765af3d06cf3fb2ce15bf31570ac7cf5..fdfb90058504cac09c8acab4b827eee852d5fe3b 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
index ba17cc5bd04bfeb61f5d797da31f11ccec8b3088..e0b8ed3a1e80de3781a433fd0c747d8f561d740c 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/clk/ti.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/list.h>
index ed24f20f63c73f4da764d3a3ec97a8079e3dd9d5..95e36ba64accf517c1a010b58b43371c8b343f9f 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/math64.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
index c2b6bb814742e4dceb98f9dcacfa8bfad36f931c..4fa0cd951d2ee3176329e91d6e0a91b96a55be1e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 
index 19174835693b91cd473b59c7fed787f128f268d1..5970edb6d334d1406c469a85c1080294c6a164fa 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/platform_data/x86/clk-pmc-atom.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
index 8febd2431545c90ac51b2479c60a5ef54baff8a1..a11f93ecbf34a75fba5a9fd4ccb3e936141fc8c1 100644 (file)
@@ -739,8 +739,8 @@ static int zynqmp_clock_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
 
        eemi_ops = zynqmp_pm_get_eemi_ops();
-       if (!eemi_ops)
-               return -ENXIO;
+       if (IS_ERR(eemi_ops))
+               return PTR_ERR(eemi_ops);
 
        ret = zynqmp_clk_setup(dev->of_node);
 
index 4b3d143f0f8a4445df12fcf589bb67fdfaa985df..48321488f0fd0bc644c8ca3c1b33597b73d5a87c 100644 (file)
@@ -69,6 +69,13 @@ config FTTMR010_TIMER
          Enables support for the Faraday Technology timer block
          FTTMR010.
 
+config IXP4XX_TIMER
+       bool "Intel XScale IXP4xx timer driver" if COMPILE_TEST
+       depends on HAS_IOMEM
+       select CLKSRC_MMIO
+       help
+         Enables support for the Intel XScale IXP4xx SoC timer.
+
 config ROCKCHIP_TIMER
        bool "Rockchip timer driver" if COMPILE_TEST
        depends on ARM || ARM64
index be6e0fbc7489519b07a7b2b9c81c1ee8c6d78d85..dba4eff880def870c445d19174e8a9a11bde2526 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_OMAP_DM_TIMER)   += timer-ti-dm.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
+obj-$(CONFIG_IXP4XX_TIMER)     += timer-ixp4xx.o
 obj-$(CONFIG_ROCKCHIP_TIMER)      += timer-rockchip.o
 obj-$(CONFIG_CLKSRC_NOMADIK_MTU)       += nomadik-mtu.o
 obj-$(CONFIG_CLKSRC_DBX500_PRCMU)      += clksrc-dbx500-prcmu.o
diff --git a/drivers/clocksource/timer-ixp4xx.c b/drivers/clocksource/timer-ixp4xx.c
new file mode 100644 (file)
index 0000000..5c2190b
--- /dev/null
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IXP4 timer driver
+ * Copyright (C) 2019 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * Based on arch/arm/mach-ixp4xx/common.c
+ * Copyright 2002 (C) Intel Corporation
+ * Copyright 2003-2004 (C) MontaVista, Software, Inc.
+ * Copyright (C) Deepak Saxena <dsaxena@plexity.net>
+ */
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/sched_clock.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+/* Goes away with OF conversion */
+#include <linux/platform_data/timer-ixp4xx.h>
+
+/*
+ * Constants to make it easy to access Timer Control/Status registers
+ */
+#define IXP4XX_OSTS_OFFSET     0x00  /* Continuous Timestamp */
+#define IXP4XX_OST1_OFFSET     0x04  /* Timer 1 Timestamp */
+#define IXP4XX_OSRT1_OFFSET    0x08  /* Timer 1 Reload */
+#define IXP4XX_OST2_OFFSET     0x0C  /* Timer 2 Timestamp */
+#define IXP4XX_OSRT2_OFFSET    0x10  /* Timer 2 Reload */
+#define IXP4XX_OSWT_OFFSET     0x14  /* Watchdog Timer */
+#define IXP4XX_OSWE_OFFSET     0x18  /* Watchdog Enable */
+#define IXP4XX_OSWK_OFFSET     0x1C  /* Watchdog Key */
+#define IXP4XX_OSST_OFFSET     0x20  /* Timer Status */
+
+/*
+ * Timer register values and bit definitions
+ */
+#define IXP4XX_OST_ENABLE              0x00000001
+#define IXP4XX_OST_ONE_SHOT            0x00000002
+/* Low order bits of reload value ignored */
+#define IXP4XX_OST_RELOAD_MASK         0x00000003
+#define IXP4XX_OST_DISABLED            0x00000000
+#define IXP4XX_OSST_TIMER_1_PEND       0x00000001
+#define IXP4XX_OSST_TIMER_2_PEND       0x00000002
+#define IXP4XX_OSST_TIMER_TS_PEND      0x00000004
+#define IXP4XX_OSST_TIMER_WDOG_PEND    0x00000008
+#define IXP4XX_OSST_TIMER_WARM_RESET   0x00000010
+
+#define        IXP4XX_WDT_KEY                  0x0000482E
+#define        IXP4XX_WDT_RESET_ENABLE         0x00000001
+#define        IXP4XX_WDT_IRQ_ENABLE           0x00000002
+#define        IXP4XX_WDT_COUNT_ENABLE         0x00000004
+
+struct ixp4xx_timer {
+       void __iomem *base;
+       unsigned int tick_rate;
+       u32 latch;
+       struct clock_event_device clkevt;
+#ifdef CONFIG_ARM
+       struct delay_timer delay_timer;
+#endif
+};
+
+/*
+ * A local singleton used by sched_clock and delay timer reads, which are
+ * fast and stateless
+ */
+static struct ixp4xx_timer *local_ixp4xx_timer;
+
+static inline struct ixp4xx_timer *
+to_ixp4xx_timer(struct clock_event_device *evt)
+{
+       return container_of(evt, struct ixp4xx_timer, clkevt);
+}
+
+static u64 notrace ixp4xx_read_sched_clock(void)
+{
+       return __raw_readl(local_ixp4xx_timer->base + IXP4XX_OSTS_OFFSET);
+}
+
+static u64 ixp4xx_clocksource_read(struct clocksource *c)
+{
+       return __raw_readl(local_ixp4xx_timer->base + IXP4XX_OSTS_OFFSET);
+}
+
+static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id)
+{
+       struct ixp4xx_timer *tmr = dev_id;
+       struct clock_event_device *evt = &tmr->clkevt;
+
+       /* Clear Pending Interrupt */
+       __raw_writel(IXP4XX_OSST_TIMER_1_PEND,
+                    tmr->base + IXP4XX_OSST_OFFSET);
+
+       evt->event_handler(evt);
+
+       return IRQ_HANDLED;
+}
+
+static int ixp4xx_set_next_event(unsigned long cycles,
+                                struct clock_event_device *evt)
+{
+       struct ixp4xx_timer *tmr = to_ixp4xx_timer(evt);
+       u32 val;
+
+       val = __raw_readl(tmr->base + IXP4XX_OSRT1_OFFSET);
+       /* Keep enable/oneshot bits */
+       val &= IXP4XX_OST_RELOAD_MASK;
+       __raw_writel((cycles & ~IXP4XX_OST_RELOAD_MASK) | val,
+                    tmr->base + IXP4XX_OSRT1_OFFSET);
+
+       return 0;
+}
+
+static int ixp4xx_shutdown(struct clock_event_device *evt)
+{
+       struct ixp4xx_timer *tmr = to_ixp4xx_timer(evt);
+       u32 val;
+
+       val = __raw_readl(tmr->base + IXP4XX_OSRT1_OFFSET);
+       val &= ~IXP4XX_OST_ENABLE;
+       __raw_writel(val, tmr->base + IXP4XX_OSRT1_OFFSET);
+
+       return 0;
+}
+
+static int ixp4xx_set_oneshot(struct clock_event_device *evt)
+{
+       struct ixp4xx_timer *tmr = to_ixp4xx_timer(evt);
+
+       __raw_writel(IXP4XX_OST_ENABLE | IXP4XX_OST_ONE_SHOT,
+                    tmr->base + IXP4XX_OSRT1_OFFSET);
+
+       return 0;
+}
+
+static int ixp4xx_set_periodic(struct clock_event_device *evt)
+{
+       struct ixp4xx_timer *tmr = to_ixp4xx_timer(evt);
+       u32 val;
+
+       val = tmr->latch & ~IXP4XX_OST_RELOAD_MASK;
+       val |= IXP4XX_OST_ENABLE;
+       __raw_writel(val, tmr->base + IXP4XX_OSRT1_OFFSET);
+
+       return 0;
+}
+
+static int ixp4xx_resume(struct clock_event_device *evt)
+{
+       struct ixp4xx_timer *tmr = to_ixp4xx_timer(evt);
+       u32 val;
+
+       val = __raw_readl(tmr->base + IXP4XX_OSRT1_OFFSET);
+       val |= IXP4XX_OST_ENABLE;
+       __raw_writel(val, tmr->base + IXP4XX_OSRT1_OFFSET);
+
+       return 0;
+}
+
+/*
+ * IXP4xx timer tick
+ * We use OS timer1 on the CPU for the timer tick and the timestamp
+ * counter as a source of real clock ticks to account for missed jiffies.
+ */
+static __init int ixp4xx_timer_register(void __iomem *base,
+                                       int timer_irq,
+                                       unsigned int timer_freq)
+{
+       struct ixp4xx_timer *tmr;
+       int ret;
+
+       tmr = kzalloc(sizeof(*tmr), GFP_KERNEL);
+       if (!tmr)
+               return -ENOMEM;
+       tmr->base = base;
+       tmr->tick_rate = timer_freq;
+
+       /*
+        * The timer register doesn't allow to specify the two least
+        * significant bits of the timeout value and assumes them being zero.
+        * So make sure the latch is the best value with the two least
+        * significant bits unset.
+        */
+       tmr->latch = DIV_ROUND_CLOSEST(timer_freq,
+                                      (IXP4XX_OST_RELOAD_MASK + 1) * HZ)
+               * (IXP4XX_OST_RELOAD_MASK + 1);
+
+       local_ixp4xx_timer = tmr;
+
+       /* Reset/disable counter */
+       __raw_writel(0, tmr->base + IXP4XX_OSRT1_OFFSET);
+
+       /* Clear any pending interrupt on timer 1 */
+       __raw_writel(IXP4XX_OSST_TIMER_1_PEND,
+                    tmr->base + IXP4XX_OSST_OFFSET);
+
+       /* Reset time-stamp counter */
+       __raw_writel(0, tmr->base + IXP4XX_OSTS_OFFSET);
+
+       clocksource_mmio_init(NULL, "OSTS", timer_freq, 200, 32,
+                             ixp4xx_clocksource_read);
+
+       tmr->clkevt.name = "ixp4xx timer1";
+       tmr->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+       tmr->clkevt.rating = 200;
+       tmr->clkevt.set_state_shutdown = ixp4xx_shutdown;
+       tmr->clkevt.set_state_periodic = ixp4xx_set_periodic;
+       tmr->clkevt.set_state_oneshot = ixp4xx_set_oneshot;
+       tmr->clkevt.tick_resume = ixp4xx_resume;
+       tmr->clkevt.set_next_event = ixp4xx_set_next_event;
+       tmr->clkevt.cpumask = cpumask_of(0);
+       tmr->clkevt.irq = timer_irq;
+       ret = request_irq(timer_irq, ixp4xx_timer_interrupt,
+                         IRQF_TIMER, "IXP4XX-TIMER1", tmr);
+       if (ret) {
+               pr_crit("no timer IRQ\n");
+               return -ENODEV;
+       }
+       clockevents_config_and_register(&tmr->clkevt, timer_freq,
+                                       0xf, 0xfffffffe);
+
+       sched_clock_register(ixp4xx_read_sched_clock, 32, timer_freq);
+
+       return 0;
+}
+
+/**
+ * ixp4xx_timer_setup() - Timer setup function to be called from boardfiles
+ * @timerbase: physical base of timer block
+ * @timer_irq: Linux IRQ number for the timer
+ * @timer_freq: Fixed frequency of the timer
+ */
+void __init ixp4xx_timer_setup(resource_size_t timerbase,
+                              int timer_irq,
+                              unsigned int timer_freq)
+{
+       void __iomem *base;
+
+       base = ioremap(timerbase, 0x100);
+       if (!base) {
+               pr_crit("IXP4xx: can't remap timer\n");
+               return;
+       }
+       ixp4xx_timer_register(base, timer_irq, timer_freq);
+}
+EXPORT_SYMBOL_GPL(ixp4xx_timer_setup);
+
+#ifdef CONFIG_OF
+static __init int ixp4xx_of_timer_init(struct device_node *np)
+{
+       void __iomem *base;
+       int irq;
+       int ret;
+
+       base = of_iomap(np, 0);
+       if (!base) {
+               pr_crit("IXP4xx: can't remap timer\n");
+               return -ENODEV;
+       }
+
+       irq = irq_of_parse_and_map(np, 0);
+       if (irq <= 0) {
+               pr_err("Can't parse IRQ\n");
+               ret = -EINVAL;
+               goto out_unmap;
+       }
+
+       /* TODO: get some fixed clocks into the device tree */
+       ret = ixp4xx_timer_register(base, irq, 66666000);
+       if (ret)
+               goto out_unmap;
+       return 0;
+
+out_unmap:
+       iounmap(base);
+       return ret;
+}
+TIMER_OF_DECLARE(ixp4xx, "intel,ixp4xx-timer", ixp4xx_of_timer_init);
+#endif
index db779b650fce46637b6ee0379b057016a8c1f9d7..85ff958e01f108dbe9baac16fb558171edf41a8b 100644 (file)
@@ -340,11 +340,14 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy,
                                      struct cpufreq_freqs *freqs,
                                      unsigned int state)
 {
+       int cpu;
+
        BUG_ON(irqs_disabled());
 
        if (cpufreq_disabled())
                return;
 
+       freqs->policy = policy;
        freqs->flags = cpufreq_driver->flags;
        pr_debug("notification %u of frequency transition to %u kHz\n",
                 state, freqs->new);
@@ -364,10 +367,8 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy,
                        }
                }
 
-               for_each_cpu(freqs->cpu, policy->cpus) {
-                       srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
-                                                CPUFREQ_PRECHANGE, freqs);
-               }
+               srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
+                                        CPUFREQ_PRECHANGE, freqs);
 
                adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
                break;
@@ -377,11 +378,11 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy,
                pr_debug("FREQ: %u - CPUs: %*pbl\n", freqs->new,
                         cpumask_pr_args(policy->cpus));
 
-               for_each_cpu(freqs->cpu, policy->cpus) {
-                       trace_cpu_frequency(freqs->new, freqs->cpu);
-                       srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
-                                                CPUFREQ_POSTCHANGE, freqs);
-               }
+               for_each_cpu(cpu, policy->cpus)
+                       trace_cpu_frequency(freqs->new, cpu);
+
+               srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
+                                        CPUFREQ_POSTCHANGE, freqs);
 
                cpufreq_stats_record_transition(policy, freqs->new);
                policy->cur = freqs->new;
@@ -618,50 +619,52 @@ static struct cpufreq_governor *find_governor(const char *str_governor)
        return NULL;
 }
 
+static int cpufreq_parse_policy(char *str_governor,
+                               struct cpufreq_policy *policy)
+{
+       if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
+               policy->policy = CPUFREQ_POLICY_PERFORMANCE;
+               return 0;
+       }
+       if (!strncasecmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) {
+               policy->policy = CPUFREQ_POLICY_POWERSAVE;
+               return 0;
+       }
+       return -EINVAL;
+}
+
 /**
- * cpufreq_parse_governor - parse a governor string
+ * cpufreq_parse_governor - parse a governor string only for !setpolicy
  */
 static int cpufreq_parse_governor(char *str_governor,
                                  struct cpufreq_policy *policy)
 {
-       if (cpufreq_driver->setpolicy) {
-               if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
-                       policy->policy = CPUFREQ_POLICY_PERFORMANCE;
-                       return 0;
-               }
+       struct cpufreq_governor *t;
 
-               if (!strncasecmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) {
-                       policy->policy = CPUFREQ_POLICY_POWERSAVE;
-                       return 0;
-               }
-       } else {
-               struct cpufreq_governor *t;
+       mutex_lock(&cpufreq_governor_mutex);
 
-               mutex_lock(&cpufreq_governor_mutex);
+       t = find_governor(str_governor);
+       if (!t) {
+               int ret;
 
-               t = find_governor(str_governor);
-               if (!t) {
-                       int ret;
-
-                       mutex_unlock(&cpufreq_governor_mutex);
+               mutex_unlock(&cpufreq_governor_mutex);
 
-                       ret = request_module("cpufreq_%s", str_governor);
-                       if (ret)
-                               return -EINVAL;
+               ret = request_module("cpufreq_%s", str_governor);
+               if (ret)
+                       return -EINVAL;
 
-                       mutex_lock(&cpufreq_governor_mutex);
+               mutex_lock(&cpufreq_governor_mutex);
 
-                       t = find_governor(str_governor);
-               }
-               if (t && !try_module_get(t->owner))
-                       t = NULL;
+               t = find_governor(str_governor);
+       }
+       if (t && !try_module_get(t->owner))
+               t = NULL;
 
-               mutex_unlock(&cpufreq_governor_mutex);
+       mutex_unlock(&cpufreq_governor_mutex);
 
-               if (t) {
-                       policy->governor = t;
-                       return 0;
-               }
+       if (t) {
+               policy->governor = t;
+               return 0;
        }
 
        return -EINVAL;
@@ -783,8 +786,13 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
        if (ret != 1)
                return -EINVAL;
 
-       if (cpufreq_parse_governor(str_governor, &new_policy))
-               return -EINVAL;
+       if (cpufreq_driver->setpolicy) {
+               if (cpufreq_parse_policy(str_governor, &new_policy))
+                       return -EINVAL;
+       } else {
+               if (cpufreq_parse_governor(str_governor, &new_policy))
+                       return -EINVAL;
+       }
 
        ret = cpufreq_set_policy(policy, &new_policy);
 
@@ -1050,32 +1058,39 @@ __weak struct cpufreq_governor *cpufreq_default_governor(void)
 
 static int cpufreq_init_policy(struct cpufreq_policy *policy)
 {
-       struct cpufreq_governor *gov = NULL;
+       struct cpufreq_governor *gov = NULL, *def_gov = NULL;
        struct cpufreq_policy new_policy;
 
        memcpy(&new_policy, policy, sizeof(*policy));
 
-       /* Update governor of new_policy to the governor used before hotplug */
-       gov = find_governor(policy->last_governor);
-       if (gov) {
-               pr_debug("Restoring governor %s for cpu %d\n",
+       def_gov = cpufreq_default_governor();
+
+       if (has_target()) {
+               /*
+                * Update governor of new_policy to the governor used before
+                * hotplug
+                */
+               gov = find_governor(policy->last_governor);
+               if (gov) {
+                       pr_debug("Restoring governor %s for cpu %d\n",
                                policy->governor->name, policy->cpu);
+               } else {
+                       if (!def_gov)
+                               return -ENODATA;
+                       gov = def_gov;
+               }
+               new_policy.governor = gov;
        } else {
-               gov = cpufreq_default_governor();
-               if (!gov)
-                       return -ENODATA;
-       }
-
-       new_policy.governor = gov;
-
-       /* Use the default policy if there is no last_policy. */
-       if (cpufreq_driver->setpolicy) {
-               if (policy->last_policy)
+               /* Use the default policy if there is no last_policy. */
+               if (policy->last_policy) {
                        new_policy.policy = policy->last_policy;
-               else
-                       cpufreq_parse_governor(gov->name, &new_policy);
+               } else {
+                       if (!def_gov)
+                               return -ENODATA;
+                       cpufreq_parse_policy(def_gov->name, &new_policy);
+               }
        }
-       /* set default policy */
+
        return cpufreq_set_policy(policy, &new_policy);
 }
 
@@ -1133,6 +1148,11 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
                                   cpufreq_global_kobject, "policy%u", cpu);
        if (ret) {
                pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret);
+               /*
+                * The entire policy object will be freed below, but the extra
+                * memory allocated for the kobject name needs to be freed by
+                * releasing the kobject.
+                */
                kobject_put(&policy->kobj);
                goto err_free_real_cpus;
        }
index be89416e2358fcbb0464e525421f7f6607d1883b..21c9ce8526c04b97398d12824f8d3827c7782b17 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
index 3e23d4b2cce2a5017c088405334ef2f25c124ff0..c0ece44f303b6cac772b831318731dc4859f6636 100644 (file)
@@ -89,6 +89,7 @@ struct caam_alg_entry {
        int class2_alg_type;
        bool rfc3686;
        bool geniv;
+       bool nodkp;
 };
 
 struct caam_aead_alg {
@@ -2052,6 +2053,7 @@ static struct caam_aead_alg driver_aeads[] = {
                },
                .caam = {
                        .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+                       .nodkp = true,
                },
        },
        {
@@ -2070,6 +2072,7 @@ static struct caam_aead_alg driver_aeads[] = {
                },
                .caam = {
                        .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+                       .nodkp = true,
                },
        },
        /* Galois Counter Mode */
@@ -2089,6 +2092,7 @@ static struct caam_aead_alg driver_aeads[] = {
                },
                .caam = {
                        .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+                       .nodkp = true,
                },
        },
        /* single-pass ipsec_esp descriptor */
@@ -3334,6 +3338,7 @@ static struct caam_aead_alg driver_aeads[] = {
                                           OP_ALG_AAI_AEAD,
                        .class2_alg_type = OP_ALG_ALGSEL_POLY1305 |
                                           OP_ALG_AAI_AEAD,
+                       .nodkp = true,
                },
        },
        {
@@ -3356,6 +3361,7 @@ static struct caam_aead_alg driver_aeads[] = {
                                           OP_ALG_AAI_AEAD,
                        .class2_alg_type = OP_ALG_ALGSEL_POLY1305 |
                                           OP_ALG_AAI_AEAD,
+                       .nodkp = true,
                },
        },
 };
@@ -3417,8 +3423,7 @@ static int caam_aead_init(struct crypto_aead *tfm)
                 container_of(alg, struct caam_aead_alg, aead);
        struct caam_ctx *ctx = crypto_aead_ctx(tfm);
 
-       return caam_init_common(ctx, &caam_alg->caam,
-                               alg->setkey == aead_setkey);
+       return caam_init_common(ctx, &caam_alg->caam, !caam_alg->caam.nodkp);
 }
 
 static void caam_exit_common(struct caam_ctx *ctx)
index 70af211d2d018684b012f611fbe4f80446d903af..d290d6b41825e54d1ff1d9f316d3a1c2e35986bd 100644 (file)
@@ -36,6 +36,7 @@ struct caam_alg_entry {
        int class2_alg_type;
        bool rfc3686;
        bool geniv;
+       bool nodkp;
 };
 
 struct caam_aead_alg {
@@ -1523,6 +1524,7 @@ static struct caam_aead_alg driver_aeads[] = {
                },
                .caam = {
                        .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+                       .nodkp = true,
                },
        },
        {
@@ -1541,6 +1543,7 @@ static struct caam_aead_alg driver_aeads[] = {
                },
                .caam = {
                        .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+                       .nodkp = true,
                },
        },
        /* Galois Counter Mode */
@@ -1560,6 +1563,7 @@ static struct caam_aead_alg driver_aeads[] = {
                },
                .caam = {
                        .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+                       .nodkp = true,
                }
        },
        /* single-pass ipsec_esp descriptor */
@@ -2433,8 +2437,7 @@ static int caam_aead_init(struct crypto_aead *tfm)
                                                      aead);
        struct caam_ctx *ctx = crypto_aead_ctx(tfm);
 
-       return caam_init_common(ctx, &caam_alg->caam,
-                               alg->setkey == aead_setkey);
+       return caam_init_common(ctx, &caam_alg->caam, !caam_alg->caam.nodkp);
 }
 
 static void caam_exit_common(struct caam_ctx *ctx)
index 33a4df6b81de9b2c6a0e55cbe66140b498e537b6..2b2980a8a9b90ed33a887d6112266df53c41319f 100644 (file)
@@ -42,6 +42,7 @@ struct caam_alg_entry {
        int class2_alg_type;
        bool rfc3686;
        bool geniv;
+       bool nodkp;
 };
 
 struct caam_aead_alg {
@@ -1480,7 +1481,7 @@ static int caam_cra_init_aead(struct crypto_aead *tfm)
 
        crypto_aead_set_reqsize(tfm, sizeof(struct caam_request));
        return caam_cra_init(crypto_aead_ctx(tfm), &caam_alg->caam,
-                            alg->setkey == aead_setkey);
+                            !caam_alg->caam.nodkp);
 }
 
 static void caam_exit_common(struct caam_ctx *ctx)
@@ -1641,6 +1642,7 @@ static struct caam_aead_alg driver_aeads[] = {
                },
                .caam = {
                        .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+                       .nodkp = true,
                },
        },
        {
@@ -1659,6 +1661,7 @@ static struct caam_aead_alg driver_aeads[] = {
                },
                .caam = {
                        .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+                       .nodkp = true,
                },
        },
        /* Galois Counter Mode */
@@ -1678,6 +1681,7 @@ static struct caam_aead_alg driver_aeads[] = {
                },
                .caam = {
                        .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+                       .nodkp = true,
                }
        },
        /* single-pass ipsec_esp descriptor */
@@ -2755,6 +2759,7 @@ static struct caam_aead_alg driver_aeads[] = {
                                           OP_ALG_AAI_AEAD,
                        .class2_alg_type = OP_ALG_ALGSEL_POLY1305 |
                                           OP_ALG_AAI_AEAD,
+                       .nodkp = true,
                },
        },
        {
@@ -2777,6 +2782,7 @@ static struct caam_aead_alg driver_aeads[] = {
                                           OP_ALG_AAI_AEAD,
                        .class2_alg_type = OP_ALG_ALGSEL_POLY1305 |
                                           OP_ALG_AAI_AEAD,
+                       .nodkp = true,
                },
        },
        {
index a4129a35a330241b1309e6fa42796e8441bf5119..4da844e4b61defab2ebb520ac5ab6eab602519d8 100644 (file)
@@ -22,7 +22,7 @@ void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type,
        size_t len;
        void *buf;
 
-       for (it = sg; it && tlen > 0 ; it = sg_next(sg)) {
+       for (it = sg; it && tlen > 0 ; it = sg_next(it)) {
                /*
                 * make sure the scatterlist's page
                 * has a valid virtual memory mapping
index 044a69b526f7ba402dde4901518dbf85f6f416d6..1de2562d09824960582472d1a333e15842bc82e0 100644 (file)
@@ -213,7 +213,7 @@ static void caam_jr_dequeue(unsigned long devarg)
                mb();
 
                /* set done */
-               wr_reg32_relaxed(&jrp->rregs->outring_rmvd, 1);
+               wr_reg32(&jrp->rregs->outring_rmvd, 1);
 
                jrp->out_ring_read_index = (jrp->out_ring_read_index + 1) &
                                           (JOBR_DEPTH - 1);
index c1fa1ec701d9700263da3c25fa11b1e5c942bf7d..8591914d5c51b73de69f9832c4bf272eeaff4efc 100644 (file)
@@ -96,14 +96,6 @@ cpu_to_caam(16)
 cpu_to_caam(32)
 cpu_to_caam(64)
 
-static inline void wr_reg32_relaxed(void __iomem *reg, u32 data)
-{
-       if (caam_little_end)
-               writel_relaxed(data, reg);
-       else
-               writel_relaxed(cpu_to_be32(data), reg);
-}
-
 static inline void wr_reg32(void __iomem *reg, u32 data)
 {
        if (caam_little_end)
index 8a76fce22943560dea6e4786f1a8d725e2cfa0e0..177f572b95890c842a574a69fabfd40ddb2c33c9 100644 (file)
@@ -200,17 +200,10 @@ void chcr_verify_tag(struct aead_request *req, u8 *input, int *err)
 
 static int chcr_inc_wrcount(struct chcr_dev *dev)
 {
-       int err = 0;
-
-       spin_lock_bh(&dev->lock_chcr_dev);
        if (dev->state == CHCR_DETACH)
-               err = 1;
-       else
-               atomic_inc(&dev->inflight);
-
-       spin_unlock_bh(&dev->lock_chcr_dev);
-
-       return err;
+               return 1;
+       atomic_inc(&dev->inflight);
+       return 0;
 }
 
 static inline void chcr_dec_wrcount(struct chcr_dev *dev)
@@ -1101,8 +1094,8 @@ static int chcr_final_cipher_iv(struct ablkcipher_request *req,
        int ret = 0;
 
        if (subtype == CRYPTO_ALG_SUB_TYPE_CTR)
-               ctr_add_iv(iv, req->info, (reqctx->processed /
-                          AES_BLOCK_SIZE));
+               ctr_add_iv(iv, req->info, DIV_ROUND_UP(reqctx->processed,
+                                                      AES_BLOCK_SIZE));
        else if (subtype == CRYPTO_ALG_SUB_TYPE_XTS)
                ret = chcr_update_tweak(req, iv, 1);
        else if (subtype == CRYPTO_ALG_SUB_TYPE_CBC) {
index 239b933d6df6507d2e405ae8a370468c7dfb3036..029a7354f5416c9579b5b9840837b8818b15de8e 100644 (file)
@@ -243,15 +243,11 @@ static void chcr_detach_device(struct uld_ctx *u_ctx)
 {
        struct chcr_dev *dev = &u_ctx->dev;
 
-       spin_lock_bh(&dev->lock_chcr_dev);
        if (dev->state == CHCR_DETACH) {
-               spin_unlock_bh(&dev->lock_chcr_dev);
                pr_debug("Detached Event received for already detach device\n");
                return;
        }
        dev->state = CHCR_DETACH;
-       spin_unlock_bh(&dev->lock_chcr_dev);
-
        if (atomic_read(&dev->inflight) != 0) {
                schedule_delayed_work(&dev->detach_work, WQ_DETACH_TM);
                wait_for_completion(&dev->detach_comp);
index 2f60049361ef684624a724b3436b33f013a41f91..f429aae72542f1e5b8f0b773ded5b4c95b7d9792 100644 (file)
@@ -575,7 +575,8 @@ inline void *chcr_crypto_wreq(struct sk_buff *skb,
        if (unlikely(credits < ETHTXQ_STOP_THRES)) {
                netif_tx_stop_queue(q->txq);
                q->q.stops++;
-               wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
+               if (!q->dbqt)
+                       wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
        }
        wr_mid |= FW_ULPTX_WR_DATA_F;
        wr->wreq.flowid_len16 = htonl(wr_mid);
index 9bbde2f26cacc848eccdfadc7b8903385190bfe6..f5414b6dfb55d37b4675a4b3a47a85a1f25271bb 100644 (file)
@@ -30,8 +30,8 @@
 #include <crypto/authenc.h>
 #include <crypto/scatterwalk.h>
 
-#include <mach/npe.h>
-#include <mach/qmgr.h>
+#include <linux/soc/ixp4xx/npe.h>
+#include <linux/soc/ixp4xx/qmgr.h>
 
 #define MAX_KEYLEN 32
 
index 5ef624fe3934c26930e0c2a41166bc1715dd691e..a59f338f520f528157dd5e21d381aec8c1fd1bda 100644 (file)
@@ -23,7 +23,6 @@ config DEV_DAX
 config DEV_DAX_PMEM
        tristate "PMEM DAX: direct access to persistent memory"
        depends on LIBNVDIMM && NVDIMM_DAX && DEV_DAX
-       depends on m # until we can kill DEV_DAX_PMEM_COMPAT
        default DEV_DAX
        help
          Support raw access to persistent memory.  Note that this
@@ -50,7 +49,7 @@ config DEV_DAX_KMEM
 
 config DEV_DAX_PMEM_COMPAT
        tristate "PMEM DAX: support the deprecated /sys/class/dax interface"
-       depends on DEV_DAX_PMEM
+       depends on m && DEV_DAX_PMEM=m
        default DEV_DAX_PMEM
        help
          Older versions of the libdaxctl library expect to find all
index e428468ab6618246b9a09e4258901274d73161b5..996d68ff992a88bf63d9f6ca1a6a617a83b5be6d 100644 (file)
@@ -184,8 +184,7 @@ static vm_fault_t __dev_dax_pmd_fault(struct dev_dax *dev_dax,
 
        *pfn = phys_to_pfn_t(phys, dax_region->pfn_flags);
 
-       return vmf_insert_pfn_pmd(vmf->vma, vmf->address, vmf->pmd, *pfn,
-                       vmf->flags & FAULT_FLAG_WRITE);
+       return vmf_insert_pfn_pmd(vmf, *pfn, vmf->flags & FAULT_FLAG_WRITE);
 }
 
 #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
@@ -235,8 +234,7 @@ static vm_fault_t __dev_dax_pud_fault(struct dev_dax *dev_dax,
 
        *pfn = phys_to_pfn_t(phys, dax_region->pfn_flags);
 
-       return vmf_insert_pfn_pud(vmf->vma, vmf->address, vmf->pud, *pfn,
-                       vmf->flags & FAULT_FLAG_WRITE);
+       return vmf_insert_pfn_pud(vmf, *pfn, vmf->flags & FAULT_FLAG_WRITE);
 }
 #else
 static vm_fault_t __dev_dax_pud_fault(struct dev_dax *dev_dax,
index f71019ce06470019caff8207d7c1fb566206f9eb..f9f51786d55698febb619cb4ddb552739b789416 100644 (file)
@@ -37,13 +37,13 @@ struct dev_dax *__dax_pmem_probe(struct device *dev, enum dev_dax_subsys subsys)
        devm_nsio_disable(dev, nsio);
 
        /* reserve the metadata area, device-dax will reserve the data */
-        pfn_sb = nd_pfn->pfn_sb;
+       pfn_sb = nd_pfn->pfn_sb;
        offset = le64_to_cpu(pfn_sb->dataoff);
        if (!devm_request_mem_region(dev, nsio->res.start, offset,
                                dev_name(&ndns->dev))) {
-                dev_warn(dev, "could not reserve metadata\n");
+               dev_warn(dev, "could not reserve metadata\n");
                return ERR_PTR(-EBUSY);
-        }
+       }
 
        rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", &region_id, &id);
        if (rc != 2)
index 3aa8733f832af9596f664b0f525de3620babf8fc..9bf06042619a1cbb778cfcad8af2c8e3c46e320a 100644 (file)
@@ -29,6 +29,7 @@
 
 EXPORT_TRACEPOINT_SYMBOL(dma_fence_emit);
 EXPORT_TRACEPOINT_SYMBOL(dma_fence_enable_signal);
+EXPORT_TRACEPOINT_SYMBOL(dma_fence_signaled);
 
 static DEFINE_SPINLOCK(dma_fence_stub_lock);
 static struct dma_fence dma_fence_stub;
index 47eb4d13ed5f870c38e2ba9f38de35957418c825..5e2e0348d460fdef29d1e6ff14b82905f14bbb4a 100644 (file)
@@ -263,8 +263,8 @@ config EDAC_PND2
          micro-server but may appear on others in the future.
 
 config EDAC_MPC85XX
-       tristate "Freescale MPC83xx / MPC85xx"
-       depends on FSL_SOC
+       bool "Freescale MPC83xx / MPC85xx"
+       depends on FSL_SOC && EDAC=y
        help
          Support for error detection and correction on the Freescale
          MPC8349, MPC8560, MPC8540, MPC8548, T4240
index 13594ffadcb3aca4b50d0c6e3b89afc78a6addf3..64922c8fa7e3b729ea6b7919b371fcd76515491b 100644 (file)
@@ -679,22 +679,18 @@ static int del_mc_from_global_list(struct mem_ctl_info *mci)
 
 struct mem_ctl_info *edac_mc_find(int idx)
 {
-       struct mem_ctl_info *mci = NULL;
+       struct mem_ctl_info *mci;
        struct list_head *item;
 
        mutex_lock(&mem_ctls_mutex);
 
        list_for_each(item, &mc_devices) {
                mci = list_entry(item, struct mem_ctl_info, link);
-
-               if (mci->mc_idx >= idx) {
-                       if (mci->mc_idx == idx) {
-                               goto unlock;
-                       }
-                       break;
-               }
+               if (mci->mc_idx == idx)
+                       goto unlock;
        }
 
+       mci = NULL;
 unlock:
        mutex_unlock(&mem_ctls_mutex);
        return mci;
index 35e784cffc23d3df4779f9d5c83b4b67225ff70a..5414eb1306aa8904666aa49ae4b11b778fee7d63 100644 (file)
@@ -107,19 +107,8 @@ EXPORT_SYMBOL(fw_iso_buffer_init);
 int fw_iso_buffer_map_vma(struct fw_iso_buffer *buffer,
                          struct vm_area_struct *vma)
 {
-       unsigned long uaddr;
-       int i, err;
-
-       uaddr = vma->vm_start;
-       for (i = 0; i < buffer->page_count; i++) {
-               err = vm_insert_page(vma, uaddr, buffer->pages[i]);
-               if (err)
-                       return err;
-
-               uaddr += PAGE_SIZE;
-       }
-
-       return 0;
+       return vm_map_pages_zero(vma, buffer->pages,
+                                       buffer->page_count);
 }
 
 void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
index 7b655f6156fba922378e6ad6c32cee8399b4aef7..11fda9eb2466651cc53d560ec4ff740086928ea1 100644 (file)
@@ -253,6 +253,22 @@ config TI_SCI_PROTOCOL
          This protocol library is used by client drivers to use the features
          provided by the system controller.
 
+config TRUSTED_FOUNDATIONS
+       bool "Trusted Foundations secure monitor support"
+       depends on ARM
+       help
+         Some devices (including most early Tegra-based consumer devices on
+         the market) are booted with the Trusted Foundations secure monitor
+         active, requiring some core operations to be performed by the secure
+         monitor instead of the kernel.
+
+         This option allows the kernel to invoke the secure monitor whenever
+         required on devices using Trusted Foundations. See the functions and
+         comments in linux/firmware/trusted_foundations.h or the device tree
+         bindings for "tlm,trusted-foundations" for details on how to use it.
+
+         Choose N if you don't know what this is about.
+
 config HAVE_ARM_SMCCC
        bool
 
index 9a3909a226820cae08c5061bf5da5c44148e8995..3fa0b34eb72fdfa44964711e9a26872abf5223a6 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_QCOM_SCM_64)     += qcom_scm-64.o
 obj-$(CONFIG_QCOM_SCM_32)      += qcom_scm-32.o
 CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a
 obj-$(CONFIG_TI_SCI_PROTOCOL)  += ti_sci.o
+obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
 
 obj-$(CONFIG_ARM_SCMI_PROTOCOL)        += arm_scmi/
 obj-y                          += psci/
index 8f952f2f1a29203f8b7729cbfd10aafeba3cd9f6..b5bc4c7a8fab2957bb0842b95e32d152f11837aa 100644 (file)
@@ -654,9 +654,7 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo)
 
 static int scmi_mailbox_check(struct device_node *np)
 {
-       struct of_phandle_args arg;
-
-       return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, &arg);
+       return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, NULL);
 }
 
 static int scmi_mbox_free_channel(int id, void *p, void *data)
@@ -798,7 +796,9 @@ static int scmi_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       desc = of_match_device(scmi_of_match, dev)->data;
+       desc = of_device_get_match_data(dev);
+       if (!desc)
+               return -EINVAL;
 
        info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
        if (!info)
index 1b2e15b3c9caa4aa2cc12540d78ccaab06770f6c..802c4ad8e8f96736d868c9588a51302b18ba5a7e 100644 (file)
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_IMX_SCU)          += imx-scu.o misc.o
+obj-$(CONFIG_IMX_SCU)          += imx-scu.o misc.o imx-scu-irq.o
 obj-$(CONFIG_IMX_SCU_PD)       += scu-pd.o
diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c
new file mode 100644 (file)
index 0000000..043833a
--- /dev/null
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ *
+ * Implementation of the SCU IRQ functions using MU.
+ *
+ */
+
+#include <dt-bindings/firmware/imx/rsrc.h>
+#include <linux/firmware/imx/ipc.h>
+#include <linux/mailbox_client.h>
+
+#define IMX_SC_IRQ_FUNC_ENABLE 1
+#define IMX_SC_IRQ_FUNC_STATUS 2
+#define IMX_SC_IRQ_NUM_GROUP   4
+
+static u32 mu_resource_id;
+
+struct imx_sc_msg_irq_get_status {
+       struct imx_sc_rpc_msg hdr;
+       union {
+               struct {
+                       u16 resource;
+                       u8 group;
+                       u8 reserved;
+               } __packed req;
+               struct {
+                       u32 status;
+               } resp;
+       } data;
+};
+
+struct imx_sc_msg_irq_enable {
+       struct imx_sc_rpc_msg hdr;
+       u32 mask;
+       u16 resource;
+       u8 group;
+       u8 enable;
+} __packed;
+
+static struct imx_sc_ipc *imx_sc_irq_ipc_handle;
+static struct work_struct imx_sc_irq_work;
+static ATOMIC_NOTIFIER_HEAD(imx_scu_irq_notifier_chain);
+
+int imx_scu_irq_register_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(
+               &imx_scu_irq_notifier_chain, nb);
+}
+EXPORT_SYMBOL(imx_scu_irq_register_notifier);
+
+int imx_scu_irq_unregister_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_unregister(
+               &imx_scu_irq_notifier_chain, nb);
+}
+EXPORT_SYMBOL(imx_scu_irq_unregister_notifier);
+
+static int imx_scu_irq_notifier_call_chain(unsigned long status, u8 *group)
+{
+       return atomic_notifier_call_chain(&imx_scu_irq_notifier_chain,
+               status, (void *)group);
+}
+
+static void imx_scu_irq_work_handler(struct work_struct *work)
+{
+       struct imx_sc_msg_irq_get_status msg;
+       struct imx_sc_rpc_msg *hdr = &msg.hdr;
+       u32 irq_status;
+       int ret;
+       u8 i;
+
+       for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) {
+               hdr->ver = IMX_SC_RPC_VERSION;
+               hdr->svc = IMX_SC_RPC_SVC_IRQ;
+               hdr->func = IMX_SC_IRQ_FUNC_STATUS;
+               hdr->size = 2;
+
+               msg.data.req.resource = mu_resource_id;
+               msg.data.req.group = i;
+
+               ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true);
+               if (ret) {
+                       pr_err("get irq group %d status failed, ret %d\n",
+                              i, ret);
+                       return;
+               }
+
+               irq_status = msg.data.resp.status;
+               if (!irq_status)
+                       continue;
+
+               imx_scu_irq_notifier_call_chain(irq_status, &i);
+       }
+}
+
+int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable)
+{
+       struct imx_sc_msg_irq_enable msg;
+       struct imx_sc_rpc_msg *hdr = &msg.hdr;
+       int ret;
+
+       hdr->ver = IMX_SC_RPC_VERSION;
+       hdr->svc = IMX_SC_RPC_SVC_IRQ;
+       hdr->func = IMX_SC_IRQ_FUNC_ENABLE;
+       hdr->size = 3;
+
+       msg.resource = mu_resource_id;
+       msg.group = group;
+       msg.mask = mask;
+       msg.enable = enable;
+
+       ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true);
+       if (ret)
+               pr_err("enable irq failed, group %d, mask %d, ret %d\n",
+                       group, mask, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL(imx_scu_irq_group_enable);
+
+static void imx_scu_irq_callback(struct mbox_client *c, void *msg)
+{
+       schedule_work(&imx_sc_irq_work);
+}
+
+int imx_scu_enable_general_irq_channel(struct device *dev)
+{
+       struct of_phandle_args spec;
+       struct mbox_client *cl;
+       struct mbox_chan *ch;
+       int ret = 0, i = 0;
+
+       ret = imx_scu_get_handle(&imx_sc_irq_ipc_handle);
+       if (ret)
+               return ret;
+
+       cl = devm_kzalloc(dev, sizeof(*cl), GFP_KERNEL);
+       if (!cl)
+               return -ENOMEM;
+
+       cl->dev = dev;
+       cl->rx_callback = imx_scu_irq_callback;
+
+       /* SCU general IRQ uses general interrupt channel 3 */
+       ch = mbox_request_channel_byname(cl, "gip3");
+       if (IS_ERR(ch)) {
+               ret = PTR_ERR(ch);
+               dev_err(dev, "failed to request mbox chan gip3, ret %d\n", ret);
+               devm_kfree(dev, cl);
+               return ret;
+       }
+
+       INIT_WORK(&imx_sc_irq_work, imx_scu_irq_work_handler);
+
+       if (!of_parse_phandle_with_args(dev->of_node, "mboxes",
+                                      "#mbox-cells", 0, &spec))
+               i = of_alias_get_id(spec.np, "mu");
+
+       /* use mu1 as general mu irq channel if failed */
+       if (i < 0)
+               i = 1;
+
+       mu_resource_id = IMX_SC_R_MU_0A + i;
+
+       return ret;
+}
+EXPORT_SYMBOL(imx_scu_enable_general_irq_channel);
index 2bb1a19c413f9ef7df21328776119c9cf8c0d224..04a24a863d6ef7e9884808592ae8363328cdf404 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/err.h>
 #include <linux/firmware/imx/types.h>
 #include <linux/firmware/imx/ipc.h>
+#include <linux/firmware/imx/sci.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/kernel.h>
@@ -246,6 +247,11 @@ static int imx_scu_probe(struct platform_device *pdev)
 
        imx_sc_ipc_handle = sc_ipc;
 
+       ret = imx_scu_enable_general_irq_channel(dev);
+       if (ret)
+               dev_warn(dev,
+                       "failed to enable general irq channel: %d\n", ret);
+
        dev_info(dev, "NXP i.MX SCU Initialized\n");
 
        return devm_of_platform_populate(dev);
index 39a94c7177fc2675f685b2d1e2aa62ab6a17e1cb..480cec69e2c96e9a1f280dd85240c0e31c2b2c1b 100644 (file)
@@ -74,7 +74,10 @@ struct imx_sc_pd_range {
        char *name;
        u32 rsrc;
        u8 num;
+
+       /* add domain index */
        bool postfix;
+       u8 start_from;
 };
 
 struct imx_sc_pd_soc {
@@ -84,71 +87,75 @@ struct imx_sc_pd_soc {
 
 static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
        /* LSIO SS */
-       { "lsio-pwm", IMX_SC_R_PWM_0, 8, 1 },
-       { "lsio-gpio", IMX_SC_R_GPIO_0, 8, 1 },
-       { "lsio-gpt", IMX_SC_R_GPT_0, 5, 1 },
-       { "lsio-kpp", IMX_SC_R_KPP, 1, 0 },
-       { "lsio-fspi", IMX_SC_R_FSPI_0, 2, 1 },
-       { "lsio-mu", IMX_SC_R_MU_0A, 14, 1 },
+       { "pwm", IMX_SC_R_PWM_0, 8, true, 0 },
+       { "gpio", IMX_SC_R_GPIO_0, 8, true, 0 },
+       { "gpt", IMX_SC_R_GPT_0, 5, true, 0 },
+       { "kpp", IMX_SC_R_KPP, 1, false, 0 },
+       { "fspi", IMX_SC_R_FSPI_0, 2, true, 0 },
+       { "mu", IMX_SC_R_MU_0A, 14, true, 0 },
 
        /* CONN SS */
-       { "con-usb", IMX_SC_R_USB_0, 2, 1 },
-       { "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, 0 },
-       { "con-usb2", IMX_SC_R_USB_2, 1, 0 },
-       { "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, 0 },
-       { "con-sdhc", IMX_SC_R_SDHC_0, 3, 1 },
-       { "con-enet", IMX_SC_R_ENET_0, 2, 1 },
-       { "con-nand", IMX_SC_R_NAND, 1, 0 },
-       { "con-mlb", IMX_SC_R_MLB_0, 1, 1 },
-
-       /* Audio DMA SS */
-       { "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, 0 },
-       { "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, 0 },
-       { "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, 0 },
-       { "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, 1 },
-       { "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, 1 },
-       { "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, 1 },
-       { "adma-asrc0", IMX_SC_R_ASRC_0, 1, 0 },
-       { "adma-asrc1", IMX_SC_R_ASRC_1, 1, 0 },
-       { "adma-esai0", IMX_SC_R_ESAI_0, 1, 0 },
-       { "adma-spdif0", IMX_SC_R_SPDIF_0, 1, 0 },
-       { "adma-sai", IMX_SC_R_SAI_0, 3, 1 },
-       { "adma-amix", IMX_SC_R_AMIX, 1, 0 },
-       { "adma-mqs0", IMX_SC_R_MQS_0, 1, 0 },
-       { "adma-dsp", IMX_SC_R_DSP, 1, 0 },
-       { "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, 0 },
-       { "adma-can", IMX_SC_R_CAN_0, 3, 1 },
-       { "adma-ftm", IMX_SC_R_FTM_0, 2, 1 },
-       { "adma-lpi2c", IMX_SC_R_I2C_0, 4, 1 },
-       { "adma-adc", IMX_SC_R_ADC_0, 1, 1 },
-       { "adma-lcd", IMX_SC_R_LCD_0, 1, 1 },
-       { "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, 1 },
-       { "adma-lpuart", IMX_SC_R_UART_0, 4, 1 },
-       { "adma-lpspi", IMX_SC_R_SPI_0, 4, 1 },
-
-       /* VPU SS  */
-       { "vpu", IMX_SC_R_VPU, 1, 0 },
-       { "vpu-pid", IMX_SC_R_VPU_PID0, 8, 1 },
-       { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, 0 },
-       { "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, 0 },
+       { "usb", IMX_SC_R_USB_0, 2, true, 0 },
+       { "usb0phy", IMX_SC_R_USB_0_PHY, 1, false, 0 },
+       { "usb2", IMX_SC_R_USB_2, 1, false, 0 },
+       { "usb2phy", IMX_SC_R_USB_2_PHY, 1, false, 0 },
+       { "sdhc", IMX_SC_R_SDHC_0, 3, true, 0 },
+       { "enet", IMX_SC_R_ENET_0, 2, true, 0 },
+       { "nand", IMX_SC_R_NAND, 1, false, 0 },
+       { "mlb", IMX_SC_R_MLB_0, 1, true, 0 },
+
+       /* AUDIO SS */
+       { "audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false, 0 },
+       { "audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false, 0 },
+       { "audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false, 0 },
+       { "dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true, 0 },
+       { "dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 },
+       { "dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true, 0 },
+       { "asrc0", IMX_SC_R_ASRC_0, 1, false, 0 },
+       { "asrc1", IMX_SC_R_ASRC_1, 1, false, 0 },
+       { "esai0", IMX_SC_R_ESAI_0, 1, false, 0 },
+       { "spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 },
+       { "sai", IMX_SC_R_SAI_0, 3, true, 0 },
+       { "amix", IMX_SC_R_AMIX, 1, false, 0 },
+       { "mqs0", IMX_SC_R_MQS_0, 1, false, 0 },
+       { "dsp", IMX_SC_R_DSP, 1, false, 0 },
+       { "dsp-ram", IMX_SC_R_DSP_RAM, 1, false, 0 },
+
+       /* DMA SS */
+       { "can", IMX_SC_R_CAN_0, 3, true, 0 },
+       { "ftm", IMX_SC_R_FTM_0, 2, true, 0 },
+       { "lpi2c", IMX_SC_R_I2C_0, 4, true, 0 },
+       { "adc", IMX_SC_R_ADC_0, 1, true, 0 },
+       { "lcd", IMX_SC_R_LCD_0, 1, true, 0 },
+       { "lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 },
+       { "lpuart", IMX_SC_R_UART_0, 4, true, 0 },
+       { "lpspi", IMX_SC_R_SPI_0, 4, true, 0 },
+
+       /* VPU SS */
+       { "vpu", IMX_SC_R_VPU, 1, false, 0 },
+       { "vpu-pid", IMX_SC_R_VPU_PID0, 8, true, 0 },
+       { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, false, 0 },
+       { "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, false, 0 },
 
        /* GPU SS */
-       { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, 1 },
+       { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, true, 0 },
 
        /* HSIO SS */
-       { "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, 0 },
-       { "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, 0 },
-       { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, 0 },
+       { "pcie-b", IMX_SC_R_PCIE_B, 1, false, 0 },
+       { "serdes-1", IMX_SC_R_SERDES_1, 1, false, 0 },
+       { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, false, 0 },
+
+       /* MIPI SS */
+       { "mipi0", IMX_SC_R_MIPI_0, 1, false, 0 },
+       { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false, 0 },
+       { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true, 0 },
 
-       /* MIPI/LVDS SS */
-       { "mipi0", IMX_SC_R_MIPI_0, 1, 0 },
-       { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, 0 },
-       { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, 1 },
-       { "lvds0", IMX_SC_R_LVDS_0, 1, 0 },
+       /* LVDS SS */
+       { "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 },
 
        /* DC SS */
-       { "dc0", IMX_SC_R_DC_0, 1, 0 },
-       { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, 1 },
+       { "dc0", IMX_SC_R_DC_0, 1, false, 0 },
+       { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 },
 };
 
 static const struct imx_sc_pd_soc imx8qxp_scu_pd = {
@@ -236,7 +243,7 @@ imx_scu_add_pm_domain(struct device *dev, int idx,
 
        if (pd_ranges->postfix)
                snprintf(sc_pd->name, sizeof(sc_pd->name),
-                        "%s%i", pd_ranges->name, idx);
+                        "%s%i", pd_ranges->name, pd_ranges->start_from + idx);
        else
                snprintf(sc_pd->name, sizeof(sc_pd->name),
                         "%s", pd_ranges->name);
diff --git a/drivers/firmware/trusted_foundations.c b/drivers/firmware/trusted_foundations.c
new file mode 100644 (file)
index 0000000..fd49993
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Trusted Foundations support for ARM CPUs
+ *
+ * Copyright (c) 2013, NVIDIA 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; 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of.h>
+
+#include <linux/firmware/trusted_foundations.h>
+
+#include <asm/firmware.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/outercache.h>
+
+#define TF_CACHE_MAINT         0xfffff100
+
+#define TF_CACHE_ENABLE                1
+#define TF_CACHE_DISABLE       2
+
+#define TF_SET_CPU_BOOT_ADDR_SMC 0xfffff200
+
+#define TF_CPU_PM              0xfffffffc
+#define TF_CPU_PM_S3           0xffffffe3
+#define TF_CPU_PM_S2           0xffffffe6
+#define TF_CPU_PM_S2_NO_MC_CLK 0xffffffe5
+#define TF_CPU_PM_S1           0xffffffe4
+#define TF_CPU_PM_S1_NOFLUSH_L2        0xffffffe7
+
+static unsigned long cpu_boot_addr;
+
+static void tf_generic_smc(u32 type, u32 arg1, u32 arg2)
+{
+       register u32 r0 asm("r0") = type;
+       register u32 r1 asm("r1") = arg1;
+       register u32 r2 asm("r2") = arg2;
+
+       asm volatile(
+               ".arch_extension        sec\n\t"
+               "stmfd  sp!, {r4 - r11}\n\t"
+               __asmeq("%0", "r0")
+               __asmeq("%1", "r1")
+               __asmeq("%2", "r2")
+               "mov    r3, #0\n\t"
+               "mov    r4, #0\n\t"
+               "smc    #0\n\t"
+               "ldmfd  sp!, {r4 - r11}\n\t"
+               :
+               : "r" (r0), "r" (r1), "r" (r2)
+               : "memory", "r3", "r12", "lr");
+}
+
+static int tf_set_cpu_boot_addr(int cpu, unsigned long boot_addr)
+{
+       cpu_boot_addr = boot_addr;
+       tf_generic_smc(TF_SET_CPU_BOOT_ADDR_SMC, cpu_boot_addr, 0);
+
+       return 0;
+}
+
+static int tf_prepare_idle(unsigned long mode)
+{
+       switch (mode) {
+       case TF_PM_MODE_LP0:
+               tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S3, cpu_boot_addr);
+               break;
+
+       case TF_PM_MODE_LP1:
+               tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S2, cpu_boot_addr);
+               break;
+
+       case TF_PM_MODE_LP1_NO_MC_CLK:
+               tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S2_NO_MC_CLK,
+                              cpu_boot_addr);
+               break;
+
+       case TF_PM_MODE_LP2:
+               tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1, cpu_boot_addr);
+               break;
+
+       case TF_PM_MODE_LP2_NOFLUSH_L2:
+               tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1_NOFLUSH_L2,
+                              cpu_boot_addr);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_CACHE_L2X0
+static void tf_cache_write_sec(unsigned long val, unsigned int reg)
+{
+       u32 l2x0_way_mask = 0xff;
+
+       switch (reg) {
+       case L2X0_CTRL:
+               if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_ASSOCIATIVITY_16)
+                       l2x0_way_mask = 0xffff;
+
+               if (val == L2X0_CTRL_EN)
+                       tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_ENABLE,
+                                      l2x0_saved_regs.aux_ctrl);
+               else
+                       tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_DISABLE,
+                                      l2x0_way_mask);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static int tf_init_cache(void)
+{
+       outer_cache.write_sec = tf_cache_write_sec;
+
+       return 0;
+}
+#endif /* CONFIG_CACHE_L2X0 */
+
+static const struct firmware_ops trusted_foundations_ops = {
+       .set_cpu_boot_addr = tf_set_cpu_boot_addr,
+       .prepare_idle = tf_prepare_idle,
+#ifdef CONFIG_CACHE_L2X0
+       .l2x0_init = tf_init_cache,
+#endif
+};
+
+void register_trusted_foundations(struct trusted_foundations_platform_data *pd)
+{
+       /*
+        * we are not using version information for now since currently
+        * supported SMCs are compatible with all TF releases
+        */
+       register_firmware_ops(&trusted_foundations_ops);
+}
+
+void of_register_trusted_foundations(void)
+{
+       struct device_node *node;
+       struct trusted_foundations_platform_data pdata;
+       int err;
+
+       node = of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations");
+       if (!node)
+               return;
+
+       err = of_property_read_u32(node, "tlm,version-major",
+                                  &pdata.version_major);
+       if (err != 0)
+               panic("Trusted Foundation: missing version-major property\n");
+       err = of_property_read_u32(node, "tlm,version-minor",
+                                  &pdata.version_minor);
+       if (err != 0)
+               panic("Trusted Foundation: missing version-minor property\n");
+       register_trusted_foundations(&pdata);
+}
+
+bool trusted_foundations_registered(void)
+{
+       return firmware_ops == &trusted_foundations_ops;
+}
index 2771df6df379e803a9feca4770fccae4549154ee..c6d0724da4dbca771174984efa414170fdd426c3 100644 (file)
@@ -90,9 +90,6 @@ static int process_api_request(u32 pm_id, u64 *pm_api_arg, u32 *pm_api_ret)
        int ret;
        struct zynqmp_pm_query_data qdata = {0};
 
-       if (!eemi_ops)
-               return -ENXIO;
-
        switch (pm_id) {
        case PM_GET_API_VERSION:
                ret = eemi_ops->get_api_version(&pm_api_version);
@@ -163,21 +160,14 @@ static ssize_t zynqmp_pm_debugfs_api_write(struct file *file,
 
        strcpy(debugfs_buf, "");
 
-       if (*off != 0 || len == 0)
+       if (*off != 0 || len <= 1 || len > PAGE_SIZE - 1)
                return -EINVAL;
 
-       kern_buff = kzalloc(len, GFP_KERNEL);
-       if (!kern_buff)
-               return -ENOMEM;
-
+       kern_buff = memdup_user_nul(ptr, len);
+       if (IS_ERR(kern_buff))
+               return PTR_ERR(kern_buff);
        tmp_buff = kern_buff;
 
-       ret = strncpy_from_user(kern_buff, ptr, len);
-       if (ret < 0) {
-               ret = -EFAULT;
-               goto err;
-       }
-
        /* Read the API name from a user request */
        pm_api_req = strsep(&kern_buff, " ");
 
index 98f936125643d9194f1aba79191c71823479604e..fd3d8374520885a77de9ab2a36e25bb51f0b2eb9 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/firmware/xlnx-zynqmp.h>
 #include "zynqmp-debug.h"
 
+static const struct zynqmp_eemi_ops *eemi_ops_tbl;
+
 static const struct mfd_cell firmware_devs[] = {
        {
                .name = "zynqmp_power_controller",
@@ -537,6 +539,49 @@ static int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset,
        return ret;
 }
 
+/**
+ * zynqmp_pm_fpga_load - Perform the fpga load
+ * @address:   Address to write to
+ * @size:      pl bitstream size
+ * @flags:     Bitstream type
+ *     -XILINX_ZYNQMP_PM_FPGA_FULL:  FPGA full reconfiguration
+ *     -XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration
+ *
+ * This function provides access to pmufw. To transfer
+ * the required bitstream into PL.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_fpga_load(const u64 address, const u32 size,
+                              const u32 flags)
+{
+       return zynqmp_pm_invoke_fn(PM_FPGA_LOAD, lower_32_bits(address),
+                                  upper_32_bits(address), size, flags, NULL);
+}
+
+/**
+ * zynqmp_pm_fpga_get_status - Read value from PCAP status register
+ * @value: Value to read
+ *
+ * This function provides access to the pmufw to get the PCAP
+ * status
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_fpga_get_status(u32 *value)
+{
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+       int ret;
+
+       if (!value)
+               return -EINVAL;
+
+       ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload);
+       *value = ret_payload[1];
+
+       return ret;
+}
+
 /**
  * zynqmp_pm_init_finalize() - PM call to inform firmware that the caller
  *                            master has initialized its own power management
@@ -640,6 +685,8 @@ static const struct zynqmp_eemi_ops eemi_ops = {
        .request_node = zynqmp_pm_request_node,
        .release_node = zynqmp_pm_release_node,
        .set_requirement = zynqmp_pm_set_requirement,
+       .fpga_load = zynqmp_pm_fpga_load,
+       .fpga_get_status = zynqmp_pm_fpga_get_status,
 };
 
 /**
@@ -649,7 +696,11 @@ static const struct zynqmp_eemi_ops eemi_ops = {
  */
 const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
 {
-       return &eemi_ops;
+       if (eemi_ops_tbl)
+               return eemi_ops_tbl;
+       else
+               return ERR_PTR(-EPROBE_DEFER);
+
 }
 EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops);
 
@@ -694,6 +745,9 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
        pr_info("%s Trustzone version v%d.%d\n", __func__,
                pm_tz_version >> 16, pm_tz_version & 0xFFFF);
 
+       /* Assign eemi_ops_table */
+       eemi_ops_tbl = &eemi_ops;
+
        zynqmp_pm_api_debugfs_init();
 
        ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, firmware_devs,
index c20445b867ae5e08dab3bad4403fb71c4e89bcac..d892f3efcd76b02503d159b637120885c6e02f62 100644 (file)
@@ -204,4 +204,13 @@ config FPGA_DFL_PCI
 
          To compile this as a module, choose M here.
 
+config FPGA_MGR_ZYNQMP_FPGA
+       tristate "Xilinx ZynqMP FPGA"
+       depends on ARCH_ZYNQMP || COMPILE_TEST
+       help
+         FPGA manager driver support for Xilinx ZynqMP FPGAs.
+         This driver uses the processor configuration port(PCAP)
+         to configure the programmable logic(PL) through PS
+         on ZynqMP SoC.
+
 endif # FPGA
index c0dd4c82fbdbb66d05c161b7b80fa879b44bd0c9..312b9371742f80bbc2b03d7ada8c8ee7c4b9f7a7 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)  += stratix10-soc.o
 obj-$(CONFIG_FPGA_MGR_TS73XX)          += ts73xx-fpga.o
 obj-$(CONFIG_FPGA_MGR_XILINX_SPI)      += xilinx-spi.o
 obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)       += zynq-fpga.o
+obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)     += zynqmp-fpga.o
 obj-$(CONFIG_ALTERA_PR_IP_CORE)         += altera-pr-ip-core.o
 obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT)    += altera-pr-ip-core-plat.o
 
index e18a786fc94383e2fbd5f6b1c9a4692de6506fa6..c438722bf4e12f9c7f006f601f89b4ec72d08bd3 100644 (file)
@@ -102,7 +102,7 @@ static int afu_dma_pin_pages(struct dfl_feature_platform_data *pdata,
                goto unlock_vm;
        }
 
-       pinned = get_user_pages_fast(region->user_addr, npages, 1,
+       pinned = get_user_pages_fast(region->user_addr, npages, FOLL_WRITE,
                                     region->pages);
        if (pinned < 0) {
                ret = pinned;
diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c
new file mode 100644 (file)
index 0000000..f7cbaad
--- /dev/null
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Xilinx, Inc.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/string.h>
+#include <linux/firmware/xlnx-zynqmp.h>
+
+/* Constant Definitions */
+#define IXR_FPGA_DONE_MASK     BIT(3)
+
+/**
+ * struct zynqmp_fpga_priv - Private data structure
+ * @dev:       Device data structure
+ * @flags:     flags which is used to identify the bitfile type
+ */
+struct zynqmp_fpga_priv {
+       struct device *dev;
+       u32 flags;
+};
+
+static int zynqmp_fpga_ops_write_init(struct fpga_manager *mgr,
+                                     struct fpga_image_info *info,
+                                     const char *buf, size_t size)
+{
+       struct zynqmp_fpga_priv *priv;
+
+       priv = mgr->priv;
+       priv->flags = info->flags;
+
+       return 0;
+}
+
+static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
+                                const char *buf, size_t size)
+{
+       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+       struct zynqmp_fpga_priv *priv;
+       dma_addr_t dma_addr;
+       u32 eemi_flags = 0;
+       char *kbuf;
+       int ret;
+
+       if (!eemi_ops || !eemi_ops->fpga_load)
+               return -ENXIO;
+
+       priv = mgr->priv;
+
+       kbuf = dma_alloc_coherent(priv->dev, size, &dma_addr, GFP_KERNEL);
+       if (!kbuf)
+               return -ENOMEM;
+
+       memcpy(kbuf, buf, size);
+
+       wmb(); /* ensure all writes are done before initiate FW call */
+
+       if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG)
+               eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL;
+
+       ret = eemi_ops->fpga_load(dma_addr, size, eemi_flags);
+
+       dma_free_coherent(priv->dev, size, kbuf, dma_addr);
+
+       return ret;
+}
+
+static int zynqmp_fpga_ops_write_complete(struct fpga_manager *mgr,
+                                         struct fpga_image_info *info)
+{
+       return 0;
+}
+
+static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr)
+{
+       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+       u32 status;
+
+       if (!eemi_ops || !eemi_ops->fpga_get_status)
+               return FPGA_MGR_STATE_UNKNOWN;
+
+       eemi_ops->fpga_get_status(&status);
+       if (status & IXR_FPGA_DONE_MASK)
+               return FPGA_MGR_STATE_OPERATING;
+
+       return FPGA_MGR_STATE_UNKNOWN;
+}
+
+static const struct fpga_manager_ops zynqmp_fpga_ops = {
+       .state = zynqmp_fpga_ops_state,
+       .write_init = zynqmp_fpga_ops_write_init,
+       .write = zynqmp_fpga_ops_write,
+       .write_complete = zynqmp_fpga_ops_write_complete,
+};
+
+static int zynqmp_fpga_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct zynqmp_fpga_priv *priv;
+       struct fpga_manager *mgr;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->dev = dev;
+
+       mgr = devm_fpga_mgr_create(dev, "Xilinx ZynqMP FPGA Manager",
+                                  &zynqmp_fpga_ops, priv);
+       if (!mgr)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, mgr);
+
+       ret = fpga_mgr_register(mgr);
+       if (ret) {
+               dev_err(dev, "unable to register FPGA manager");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int zynqmp_fpga_remove(struct platform_device *pdev)
+{
+       struct fpga_manager *mgr = platform_get_drvdata(pdev);
+
+       fpga_mgr_unregister(mgr);
+
+       return 0;
+}
+
+static const struct of_device_id zynqmp_fpga_of_match[] = {
+       { .compatible = "xlnx,zynqmp-pcap-fpga", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match);
+
+static struct platform_driver zynqmp_fpga_driver = {
+       .probe = zynqmp_fpga_probe,
+       .remove = zynqmp_fpga_remove,
+       .driver = {
+               .name = "zynqmp_fpga_manager",
+               .of_match_table = of_match_ptr(zynqmp_fpga_of_match),
+       },
+};
+
+module_platform_driver(zynqmp_fpga_driver);
+
+MODULE_AUTHOR("Nava kishore Manne <navam@xilinx.com>");
+MODULE_DESCRIPTION("Xilinx ZynqMp FPGA Manager");
+MODULE_LICENSE("GPL");
index 0f91600c27aeb5a8c8ac250f85aaf00948708b1b..8023d03ec362fa0a3fd767d5a07e39e9d012c265 100644 (file)
@@ -26,12 +26,12 @@ config GPIOLIB_FASTPATH_LIMIT
        range 32 512
        default 512
        help
-          This adjusts the point at which certain APIs will switch from
-          using a stack allocated buffer to a dynamically allocated buffer.
+         This adjusts the point at which certain APIs will switch from
+         using a stack allocated buffer to a dynamically allocated buffer.
 
-          You shouldn't need to change this unless you really need to
-          optimize either stack space or performance. Change this carefully
-          since setting an incorrect value could cause stack corruption.
+         You shouldn't need to change this unless you really need to
+         optimize either stack space or performance. Change this carefully
+         since setting an incorrect value could cause stack corruption.
 
 config OF_GPIO
        def_bool y
@@ -286,6 +286,19 @@ config GPIO_IOP
 
          If unsure, say N.
 
+config GPIO_IXP4XX
+       bool "Intel IXP4xx GPIO"
+       depends on ARM # For <asm/mach-types.h>
+       depends on ARCH_IXP4XX
+       select GPIO_GENERIC
+       select IRQ_DOMAIN
+       select IRQ_DOMAIN_HIERARCHY
+       help
+         Say yes here to support the GPIO functionality of a number of Intel
+         IXP4xx series of chips.
+
+         If unsure, say N.
+
 config GPIO_LOONGSON
        bool "Loongson-2/3 GPIO support"
        depends on CPU_LOONGSON2 || CPU_LOONGSON3
@@ -319,7 +332,7 @@ config GPIO_MENZ127
        depends on MCB
        select GPIO_GENERIC
        help
-        Say yes here to support the MEN 16Z127 GPIO Controller
+         Say yes here to support the MEN 16Z127 GPIO Controller
 
 config GPIO_MM_LANTIQ
        bool "Lantiq Memory mapped GPIOs"
@@ -329,20 +342,6 @@ config GPIO_MM_LANTIQ
          (EBU) found on Lantiq SoCs. The gpios are output only as they are
          created by attaching a 16bit latch to the bus.
 
-config GPIO_MOCKUP
-       tristate "GPIO Testing Driver"
-       depends on GPIOLIB && SYSFS
-       select GPIO_SYSFS
-       select GPIOLIB_IRQCHIP
-       select IRQ_SIM
-       help
-         This enables GPIO Testing driver, which provides a way to test GPIO
-         subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS
-         must be selected for this test.
-         User could use it through the script in
-         tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in
-         it.
-
 config GPIO_MPC5200
        def_bool y
        depends on PPC_MPC52xx
@@ -861,11 +860,11 @@ config GPIO_MAX732X
          Input and Output (designed by 'P'). The combinations are listed
          below:
 
-         8 bits:       max7319 (8I), max7320 (8O), max7321 (8P),
-                       max7322 (4I4O), max7323 (4P4O)
+         8 bits:       max7319 (8I), max7320 (8O), max7321 (8P),
+                       max7322 (4I4O), max7323 (4P4O)
 
-         16 bits:      max7324 (8I8O), max7325 (8P8O),
-                       max7326 (4I12O), max7327 (4P12O)
+         16 bits:      max7324 (8I8O), max7325 (8P8O),
+                       max7326 (4I12O), max7327 (4P12O)
 
          Board setup code must specify the model to use, and the start
          number for these GPIOs.
@@ -892,17 +891,17 @@ config GPIO_PCA953X
          SMBus I/O expanders, made mostly by NXP or TI.  Compatible
          models include:
 
-         4 bits:       pca9536, pca9537
+         4 bits:       pca9536, pca9537
 
-         8 bits:       max7310, max7315, pca6107, pca9534, pca9538, pca9554,
-                       pca9556, pca9557, pca9574, tca6408, tca9554, xra1202
+         8 bits:       max7310, max7315, pca6107, pca9534, pca9538, pca9554,
+                       pca9556, pca9557, pca9574, tca6408, tca9554, xra1202
 
-         16 bits:      max7312, max7313, pca9535, pca9539, pca9555, pca9575,
-                       tca6416
+         16 bits:      max7312, max7313, pca9535, pca9539, pca9555, pca9575,
+                       tca6416
 
-         24 bits:      tca6424
+         24 bits:      tca6424
 
-         40 bits:      pca9505, pca9698
+         40 bits:      pca9505, pca9698
 
 config GPIO_PCA953X_IRQ
        bool "Interrupt controller support for PCA953x"
@@ -924,7 +923,7 @@ config GPIO_PCF857X
 
          8 bits:   pcf8574, pcf8574a, pca8574, pca8574a,
                    pca9670, pca9672, pca9674, pca9674a,
-                   max7328, max7329
+                   max7328, max7329
 
          16 bits:  pcf8575, pcf8575c, pca8575,
                    pca9671, pca9673, pca9675
@@ -1046,9 +1045,9 @@ config HTC_EGPIO
        bool "HTC EGPIO support"
        depends on GPIOLIB && ARM
        help
-           This driver supports the CPLD egpio chip present on
-           several HTC phones.  It provides basic support for input
-           pins, output pins, and irqs.
+         This driver supports the CPLD egpio chip present on
+         several HTC phones.  It provides basic support for input
+         pins, output pins, and irqs.
 
 config GPIO_JANZ_TTL
        tristate "Janz VMOD-TTL Digital IO Module"
@@ -1084,7 +1083,7 @@ config GPIO_LP873X
          on LP873X PMICs.
 
          This driver can also be built as a module. If so, the module will be
-          called gpio-lp873x.
+         called gpio-lp873x.
 
 config GPIO_LP87565
        tristate "TI LP87565 GPIO"
@@ -1111,6 +1110,13 @@ config GPIO_MAX77620
          driver also provides interrupt support for each of the gpios.
          Say yes here to enable the max77620 to be used as gpio controller.
 
+config GPIO_MAX77650
+       tristate "Maxim MAX77650/77651 GPIO support"
+       depends on MFD_MAX77650
+       help
+         GPIO driver for MAX77650/77651 PMIC from Maxim Semiconductor.
+         These chips have a single pin that can be configured as GPIO.
+
 config GPIO_MSIC
        bool "Intel MSIC mixed signal gpio support"
        depends on (X86 || COMPILE_TEST) && MFD_INTEL_MSIC
@@ -1315,6 +1321,13 @@ config GPIO_MERRIFIELD
        help
          Say Y here to support Intel Merrifield GPIO.
 
+config GPIO_MLXBF
+       tristate "Mellanox BlueField SoC GPIO"
+       depends on (MELLANOX_PLATFORM && ARM64 && ACPI) || (64BIT && COMPILE_TEST)
+       select GPIO_GENERIC
+       help
+         Say Y here if you want GPIO support on Mellanox BlueField SoC.
+
 config GPIO_ML_IOH
        tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
        depends on X86 || COMPILE_TEST
@@ -1435,10 +1448,22 @@ config GPIO_VIPERBOARD
          Say yes here to access the GPIO signals of Nano River
          Technologies Viperboard. There are two GPIO chips on the
          board: gpioa and gpiob.
-          See viperboard API specification and Nano
-          River Tech's viperboard.h for detailed meaning
-          of the module parameters.
+         See viperboard API specification and Nano
+         River Tech's viperboard.h for detailed meaning
+         of the module parameters.
 
 endmenu
 
+config GPIO_MOCKUP
+       tristate "GPIO Testing Driver"
+       depends on GPIOLIB
+       select IRQ_SIM
+       help
+         This enables GPIO Testing driver, which provides a way to test GPIO
+         subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS
+         must be selected for this test.
+         User could use it through the script in
+         tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in
+         it.
+
 endif
index 54d55274b93aba73f40959a975657aa82a366016..6700eee860b76f3babe8985c30956cae473a62ef 100644 (file)
@@ -61,6 +61,7 @@ obj-$(CONFIG_GPIO_HLWD)               += gpio-hlwd.o
 obj-$(CONFIG_HTC_EGPIO)                += gpio-htc-egpio.o
 obj-$(CONFIG_GPIO_ICH)         += gpio-ich.o
 obj-$(CONFIG_GPIO_IOP)         += gpio-iop.o
+obj-$(CONFIG_GPIO_IXP4XX)      += gpio-ixp4xx.o
 obj-$(CONFIG_GPIO_IT87)                += gpio-it87.o
 obj-$(CONFIG_GPIO_JANZ_TTL)    += gpio-janz-ttl.o
 obj-$(CONFIG_GPIO_KEMPLD)      += gpio-kempld.o
@@ -80,11 +81,13 @@ obj-$(CONFIG_GPIO_MAX7300)  += gpio-max7300.o
 obj-$(CONFIG_GPIO_MAX7301)     += gpio-max7301.o
 obj-$(CONFIG_GPIO_MAX732X)     += gpio-max732x.o
 obj-$(CONFIG_GPIO_MAX77620)    += gpio-max77620.o
+obj-$(CONFIG_GPIO_MAX77650)    += gpio-max77650.o
 obj-$(CONFIG_GPIO_MB86S7X)     += gpio-mb86s7x.o
 obj-$(CONFIG_GPIO_MENZ127)     += gpio-menz127.o
 obj-$(CONFIG_GPIO_MERRIFIELD)  += gpio-merrifield.o
 obj-$(CONFIG_GPIO_MC33880)     += gpio-mc33880.o
 obj-$(CONFIG_GPIO_MC9S08DZ60)  += gpio-mc9s08dz60.o
+obj-$(CONFIG_GPIO_MLXBF)       += gpio-mlxbf.o
 obj-$(CONFIG_GPIO_ML_IOH)      += gpio-ml-ioh.o
 obj-$(CONFIG_GPIO_MM_LANTIQ)   += gpio-mm-lantiq.o
 obj-$(CONFIG_GPIO_MOCKUP)      += gpio-mockup.o
index fb7b620763a257658ddd60e5fd0c203248965f4d..e81307f9754e38a99c3f1d50a68e3b16c062ffc5 100644 (file)
@@ -1,21 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver
  *
  *  Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
  *  Copyright (C) 2010 Miguel Gaio <miguel.gaio@efixo.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio/driver.h>
 #include <linux/gpio/consumer.h>
-#include <linux/slab.h>
+#include <linux/gpio/driver.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
 
 #define GEN_74X164_NUMBER_GPIOS        8
 
@@ -116,10 +113,9 @@ static int gen_74x164_probe(struct spi_device *spi)
        if (ret < 0)
                return ret;
 
-       if (of_property_read_u32(spi->dev.of_node, "registers-number",
-                                &nregs)) {
-               dev_err(&spi->dev,
-                       "Missing registers-number property in the DT.\n");
+       ret = device_property_read_u32(&spi->dev, "registers-number", &nregs);
+       if (ret) {
+               dev_err(&spi->dev, "Missing 'registers-number' property.\n");
                return -EINVAL;
        }
 
index 49616ec815ee351b0d807d69b49e990b235f9de4..04247075091dde753bc5439a708aef850042cb52 100644 (file)
@@ -106,7 +106,6 @@ static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 static int mmio_74xx_gpio_probe(struct platform_device *pdev)
 {
        struct mmio_74xx_gpio_priv *priv;
-       struct resource *res;
        void __iomem *dat;
        int err;
 
@@ -116,8 +115,7 @@ static int mmio_74xx_gpio_probe(struct platform_device *pdev)
 
        priv->flags = (uintptr_t)of_device_get_match_data(&pdev->dev);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dat = devm_ioremap_resource(&pdev->dev, res);
+       dat = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(dat))
                return PTR_ERR(dat);
 
index 9b78dc83760314095d1183defca91bf490e14161..1ffd7c2d1285ccf04f68c1d382ffc574654c85c3 100644 (file)
@@ -78,7 +78,6 @@ static int pt_gpio_probe(struct platform_device *pdev)
        struct acpi_device *acpi_dev;
        acpi_handle handle = ACPI_HANDLE(dev);
        struct pt_gpio_chip *pt_gpio;
-       struct resource *res_mem;
        int ret = 0;
 
        if (acpi_bus_get_device(handle, &acpi_dev)) {
@@ -90,12 +89,7 @@ static int pt_gpio_probe(struct platform_device *pdev)
        if (!pt_gpio)
                return -ENOMEM;
 
-       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res_mem) {
-               dev_err(&pdev->dev, "Failed to get MMIO resource for PT GPIO.\n");
-               return -EINVAL;
-       }
-       pt_gpio->reg_base = devm_ioremap_resource(dev, res_mem);
+       pt_gpio->reg_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(pt_gpio->reg_base)) {
                dev_err(&pdev->dev, "Failed to map MMIO resource for PT GPIO.\n");
                return PTR_ERR(pt_gpio->reg_base);
index 217507002dbc38ce7a34c64df751ac5887d304d6..0f1b55c7c36141ce81b97360bbe4dfb0010fe208 100644 (file)
@@ -1156,15 +1156,13 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
 {
        const struct of_device_id *gpio_id;
        struct aspeed_gpio *gpio;
-       struct resource *res;
        int rc, i, banks;
 
        gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
        if (!gpio)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       gpio->base = devm_ioremap_resource(&pdev->dev, res);
+       gpio->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(gpio->base))
                return PTR_ERR(gpio->base);
 
index c5536a509b598795e481057a020787ec2817fcdb..9fa6d3a967d2c3d796933949e241396c4e4de3ed 100644 (file)
@@ -568,7 +568,6 @@ static int bcm_kona_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        const struct of_device_id *match;
-       struct resource *res;
        struct bcm_kona_gpio_bank *bank;
        struct bcm_kona_gpio *kona_gpio;
        struct gpio_chip *chip;
@@ -618,8 +617,7 @@ static int bcm_kona_gpio_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       kona_gpio->reg_base = devm_ioremap_resource(dev, res);
+       kona_gpio->reg_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(kona_gpio->reg_base)) {
                ret = -ENXIO;
                goto err_irq_domain;
index aec8d5df9f3094336a7a3d043007c4b3211c5997..712ae212b0b4eb65b35403e56eb8072e28b27c0d 100644 (file)
@@ -148,7 +148,6 @@ static struct irq_chip cdns_gpio_irqchip = {
 static int cdns_gpio_probe(struct platform_device *pdev)
 {
        struct cdns_gpio_chip *cgpio;
-       struct resource *res;
        int ret, irq;
        u32 dir_prev;
        u32 num_gpios = 32;
@@ -157,8 +156,7 @@ static int cdns_gpio_probe(struct platform_device *pdev)
        if (!cgpio)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       cgpio->regs = devm_ioremap_resource(&pdev->dev, res);
+       cgpio->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(cgpio->regs))
                return PTR_ERR(cgpio->regs);
 
index 52fd63f021340b37955429d1ae1c9c4459e3467d..0fbbb0edc0ba754e5de9f860bdc0411ecf8ba7b2 100644 (file)
@@ -19,7 +19,6 @@ static int clps711x_gpio_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        void __iomem *dat, *dir;
        struct gpio_chip *gc;
-       struct resource *res;
        int err, id;
 
        if (!np)
@@ -33,13 +32,11 @@ static int clps711x_gpio_probe(struct platform_device *pdev)
        if (!gc)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dat = devm_ioremap_resource(&pdev->dev, res);
+       dat = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(dat))
                return PTR_ERR(dat);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       dir = devm_ioremap_resource(&pdev->dev, res);
+       dir = devm_platform_ioremap_resource(pdev, 1);
        if (IS_ERR(dir))
                return PTR_ERR(dir);
 
index 84ae04402f7051de33ae7787235ad830c0dddb58..d3eda65fd6d37b08a46d837dba33c22cc260a0e5 100644 (file)
@@ -655,7 +655,6 @@ MODULE_DEVICE_TABLE(acpi, dwapb_acpi_match);
 static int dwapb_gpio_probe(struct platform_device *pdev)
 {
        unsigned int i;
-       struct resource *res;
        struct dwapb_gpio *gpio;
        int err;
        struct device *dev = &pdev->dev;
@@ -688,8 +687,7 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
        if (!gpio->ports)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       gpio->regs = devm_ioremap_resource(&pdev->dev, res);
+       gpio->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(gpio->regs))
                return PTR_ERR(gpio->regs);
 
index 45fe125823a8d41700efaaf2566c2d9c09b700f1..8ff8ce2970d9db70d82376c9430f0089c6bf592a 100644 (file)
@@ -225,7 +225,6 @@ static int ftgpio_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
 static int ftgpio_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct resource *res;
        struct ftgpio_gpio *g;
        int irq;
        int ret;
@@ -236,8 +235,7 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
 
        g->dev = dev;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       g->base = devm_ioremap_resource(dev, res);
+       g->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(g->base))
                return PTR_ERR(g->base);
 
index a7b17897356e4f65f9db52bafccbb6bc8b37f722..e5fa00f8145f3e41eba8f48f851d832b42d88ac8 100644 (file)
@@ -208,7 +208,6 @@ static int hlwd_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
 static int hlwd_gpio_probe(struct platform_device *pdev)
 {
        struct hlwd_gpio *hlwd;
-       struct resource *regs_resource;
        u32 ngpios;
        int res;
 
@@ -216,8 +215,7 @@ static int hlwd_gpio_probe(struct platform_device *pdev)
        if (!hlwd)
                return -ENOMEM;
 
-       regs_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       hlwd->regs = devm_ioremap_resource(&pdev->dev, regs_resource);
+       hlwd->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(hlwd->regs))
                return PTR_ERR(hlwd->regs);
 
index 8d62db447ec1baff473836ee75b33fdda64c2d7d..11b77d868c89ab636dcb7131abbf05e19ec1f138 100644 (file)
@@ -21,7 +21,6 @@
 
 static int iop3xx_gpio_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        struct gpio_chip *gc;
        void __iomem *base;
        int err;
@@ -30,8 +29,7 @@ static int iop3xx_gpio_probe(struct platform_device *pdev)
        if (!gc)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(&pdev->dev, res);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
diff --git a/drivers/gpio/gpio-ixp4xx.c b/drivers/gpio/gpio-ixp4xx.c
new file mode 100644 (file)
index 0000000..4b1cf7e
--- /dev/null
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// IXP4 GPIO driver
+// Copyright (C) 2019 Linus Walleij <linus.walleij@linaro.org>
+//
+// based on previous work and know-how from:
+// Deepak Saxena <dsaxena@plexity.net>
+
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+/* Include that go away with DT transition */
+#include <linux/irqchip/irq-ixp4xx.h>
+
+#include <asm/mach-types.h>
+
+#define IXP4XX_REG_GPOUT       0x00
+#define IXP4XX_REG_GPOE                0x04
+#define IXP4XX_REG_GPIN                0x08
+#define IXP4XX_REG_GPIS                0x0C
+#define IXP4XX_REG_GPIT1       0x10
+#define IXP4XX_REG_GPIT2       0x14
+#define IXP4XX_REG_GPCLK       0x18
+#define IXP4XX_REG_GPDBSEL     0x1C
+
+/*
+ * The hardware uses 3 bits to indicate interrupt "style".
+ * we clear and set these three bits accordingly. The lower 24
+ * bits in two registers (GPIT1 and GPIT2) are used to set up
+ * the style for 8 lines each for a total of 16 GPIO lines.
+ */
+#define IXP4XX_GPIO_STYLE_ACTIVE_HIGH  0x0
+#define IXP4XX_GPIO_STYLE_ACTIVE_LOW   0x1
+#define IXP4XX_GPIO_STYLE_RISING_EDGE  0x2
+#define IXP4XX_GPIO_STYLE_FALLING_EDGE 0x3
+#define IXP4XX_GPIO_STYLE_TRANSITIONAL 0x4
+#define IXP4XX_GPIO_STYLE_MASK         GENMASK(2, 0)
+#define IXP4XX_GPIO_STYLE_SIZE         3
+
+/**
+ * struct ixp4xx_gpio - IXP4 GPIO state container
+ * @dev: containing device for this instance
+ * @fwnode: the fwnode for this GPIO chip
+ * @gc: gpiochip for this instance
+ * @domain: irqdomain for this chip instance
+ * @base: remapped I/O-memory base
+ * @irq_edge: Each bit represents an IRQ: 1: edge-triggered,
+ * 0: level triggered
+ */
+struct ixp4xx_gpio {
+       struct device *dev;
+       struct fwnode_handle *fwnode;
+       struct gpio_chip gc;
+       struct irq_domain *domain;
+       void __iomem *base;
+       unsigned long long irq_edge;
+};
+
+/**
+ * struct ixp4xx_gpio_map - IXP4 GPIO to parent IRQ map
+ * @gpio_offset: offset of the IXP4 GPIO line
+ * @parent_hwirq: hwirq on the parent IRQ controller
+ */
+struct ixp4xx_gpio_map {
+       int gpio_offset;
+       int parent_hwirq;
+};
+
+/* GPIO lines 0..12 have corresponding IRQs, GPIOs 13..15 have no IRQs */
+const struct ixp4xx_gpio_map ixp4xx_gpiomap[] = {
+       { .gpio_offset = 0, .parent_hwirq = 6 },
+       { .gpio_offset = 1, .parent_hwirq = 7 },
+       { .gpio_offset = 2, .parent_hwirq = 19 },
+       { .gpio_offset = 3, .parent_hwirq = 20 },
+       { .gpio_offset = 4, .parent_hwirq = 21 },
+       { .gpio_offset = 5, .parent_hwirq = 22 },
+       { .gpio_offset = 6, .parent_hwirq = 23 },
+       { .gpio_offset = 7, .parent_hwirq = 24 },
+       { .gpio_offset = 8, .parent_hwirq = 25 },
+       { .gpio_offset = 9, .parent_hwirq = 26 },
+       { .gpio_offset = 10, .parent_hwirq = 27 },
+       { .gpio_offset = 11, .parent_hwirq = 28 },
+       { .gpio_offset = 12, .parent_hwirq = 29 },
+};
+
+static void ixp4xx_gpio_irq_ack(struct irq_data *d)
+{
+       struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d);
+
+       __raw_writel(BIT(d->hwirq), g->base + IXP4XX_REG_GPIS);
+}
+
+static void ixp4xx_gpio_irq_unmask(struct irq_data *d)
+{
+       struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d);
+
+       /* ACK when unmasking if not edge-triggered */
+       if (!(g->irq_edge & BIT(d->hwirq)))
+               ixp4xx_gpio_irq_ack(d);
+
+       irq_chip_unmask_parent(d);
+}
+
+static int ixp4xx_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d);
+       int line = d->hwirq;
+       unsigned long flags;
+       u32 int_style;
+       u32 int_reg;
+       u32 val;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_BOTH:
+               irq_set_handler_locked(d, handle_edge_irq);
+               int_style = IXP4XX_GPIO_STYLE_TRANSITIONAL;
+               g->irq_edge |= BIT(d->hwirq);
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               irq_set_handler_locked(d, handle_edge_irq);
+               int_style = IXP4XX_GPIO_STYLE_RISING_EDGE;
+               g->irq_edge |= BIT(d->hwirq);
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               irq_set_handler_locked(d, handle_edge_irq);
+               int_style = IXP4XX_GPIO_STYLE_FALLING_EDGE;
+               g->irq_edge |= BIT(d->hwirq);
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               irq_set_handler_locked(d, handle_level_irq);
+               int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
+               g->irq_edge &= ~BIT(d->hwirq);
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               irq_set_handler_locked(d, handle_level_irq);
+               int_style = IXP4XX_GPIO_STYLE_ACTIVE_LOW;
+               g->irq_edge &= ~BIT(d->hwirq);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (line >= 8) {
+               /* pins 8-15 */
+               line -= 8;
+               int_reg = IXP4XX_REG_GPIT2;
+       } else {
+               /* pins 0-7 */
+               int_reg = IXP4XX_REG_GPIT1;
+       }
+
+       spin_lock_irqsave(&g->gc.bgpio_lock, flags);
+
+       /* Clear the style for the appropriate pin */
+       val = __raw_readl(g->base + int_reg);
+       val &= ~(IXP4XX_GPIO_STYLE_MASK << (line * IXP4XX_GPIO_STYLE_SIZE));
+       __raw_writel(val, g->base + int_reg);
+
+       __raw_writel(BIT(line), g->base + IXP4XX_REG_GPIS);
+
+       /* Set the new style */
+       val = __raw_readl(g->base + int_reg);
+       val |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE));
+       __raw_writel(val, g->base + int_reg);
+
+       /* Force-configure this line as an input */
+       val = __raw_readl(g->base + IXP4XX_REG_GPOE);
+       val |= BIT(d->hwirq);
+       __raw_writel(val, g->base + IXP4XX_REG_GPOE);
+
+       spin_unlock_irqrestore(&g->gc.bgpio_lock, flags);
+
+       /* This parent only accept level high (asserted) */
+       return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
+}
+
+static struct irq_chip ixp4xx_gpio_irqchip = {
+       .name = "IXP4GPIO",
+       .irq_ack = ixp4xx_gpio_irq_ack,
+       .irq_mask = irq_chip_mask_parent,
+       .irq_unmask = ixp4xx_gpio_irq_unmask,
+       .irq_set_type = ixp4xx_gpio_irq_set_type,
+};
+
+static int ixp4xx_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
+{
+       struct ixp4xx_gpio *g = gpiochip_get_data(gc);
+       struct irq_fwspec fwspec;
+
+       fwspec.fwnode = g->fwnode;
+       fwspec.param_count = 2;
+       fwspec.param[0] = offset;
+       fwspec.param[1] = IRQ_TYPE_NONE;
+
+       return irq_create_fwspec_mapping(&fwspec);
+}
+
+static int ixp4xx_gpio_irq_domain_translate(struct irq_domain *domain,
+                                           struct irq_fwspec *fwspec,
+                                           unsigned long *hwirq,
+                                           unsigned int *type)
+{
+
+       /* We support standard DT translation */
+       if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
+               *hwirq = fwspec->param[0];
+               *type = fwspec->param[1];
+               return 0;
+       }
+
+       /* This goes away when we transition to DT */
+       if (is_fwnode_irqchip(fwspec->fwnode)) {
+               if (fwspec->param_count != 2)
+                       return -EINVAL;
+               *hwirq = fwspec->param[0];
+               *type = fwspec->param[1];
+               WARN_ON(*type == IRQ_TYPE_NONE);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int ixp4xx_gpio_irq_domain_alloc(struct irq_domain *d,
+                                       unsigned int irq, unsigned int nr_irqs,
+                                       void *data)
+{
+       struct ixp4xx_gpio *g = d->host_data;
+       irq_hw_number_t hwirq;
+       unsigned int type = IRQ_TYPE_NONE;
+       struct irq_fwspec *fwspec = data;
+       int ret;
+       int i;
+
+       ret = ixp4xx_gpio_irq_domain_translate(d, fwspec, &hwirq, &type);
+       if (ret)
+               return ret;
+
+       dev_dbg(g->dev, "allocate IRQ %d..%d, hwirq %lu..%lu\n",
+               irq, irq + nr_irqs - 1,
+               hwirq, hwirq + nr_irqs - 1);
+
+       for (i = 0; i < nr_irqs; i++) {
+               struct irq_fwspec parent_fwspec;
+               const struct ixp4xx_gpio_map *map;
+               int j;
+
+               /* Not all lines support IRQs */
+               for (j = 0; j < ARRAY_SIZE(ixp4xx_gpiomap); j++) {
+                       map = &ixp4xx_gpiomap[j];
+                       if (map->gpio_offset == hwirq)
+                               break;
+               }
+               if (j == ARRAY_SIZE(ixp4xx_gpiomap)) {
+                       dev_err(g->dev, "can't look up hwirq %lu\n", hwirq);
+                       return -EINVAL;
+               }
+               dev_dbg(g->dev, "found parent hwirq %u\n", map->parent_hwirq);
+
+               /*
+                * We set handle_bad_irq because the .set_type() should
+                * always be invoked and set the right type of handler.
+                */
+               irq_domain_set_info(d,
+                                   irq + i,
+                                   hwirq + i,
+                                   &ixp4xx_gpio_irqchip,
+                                   g,
+                                   handle_bad_irq,
+                                   NULL, NULL);
+               irq_set_probe(irq + i);
+
+               /*
+                * Create a IRQ fwspec to send up to the parent irqdomain:
+                * specify the hwirq we address on the parent and tie it
+                * all together up the chain.
+                */
+               parent_fwspec.fwnode = d->parent->fwnode;
+               parent_fwspec.param_count = 2;
+               parent_fwspec.param[0] = map->parent_hwirq;
+               /* This parent only handles asserted level IRQs */
+               parent_fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH;
+               dev_dbg(g->dev, "alloc_irqs_parent for %d parent hwirq %d\n",
+                       irq + i, map->parent_hwirq);
+               ret = irq_domain_alloc_irqs_parent(d, irq + i, 1,
+                                                  &parent_fwspec);
+               if (ret)
+                       dev_err(g->dev,
+                               "failed to allocate parent hwirq %d for hwirq %lu\n",
+                               map->parent_hwirq, hwirq);
+       }
+
+       return 0;
+}
+
+static const struct irq_domain_ops ixp4xx_gpio_irqdomain_ops = {
+       .translate = ixp4xx_gpio_irq_domain_translate,
+       .alloc = ixp4xx_gpio_irq_domain_alloc,
+       .free = irq_domain_free_irqs_common,
+};
+
+static int ixp4xx_gpio_probe(struct platform_device *pdev)
+{
+       unsigned long flags;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct irq_domain *parent;
+       struct resource *res;
+       struct ixp4xx_gpio *g;
+       int ret;
+       int i;
+
+       g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);
+       if (!g)
+               return -ENOMEM;
+       g->dev = dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       g->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(g->base)) {
+               dev_err(dev, "ioremap error\n");
+               return PTR_ERR(g->base);
+       }
+
+       /*
+        * Make sure GPIO 14 and 15 are NOT used as clocks but GPIO on
+        * specific machines.
+        */
+       if (machine_is_dsmg600() || machine_is_nas100d())
+               __raw_writel(0x0, g->base + IXP4XX_REG_GPCLK);
+
+       /*
+        * This is a very special big-endian ARM issue: when the IXP4xx is
+        * run in big endian mode, all registers in the machine are switched
+        * around to the CPU-native endianness. As you see mostly in the
+        * driver we use __raw_readl()/__raw_writel() to access the registers
+        * in the appropriate order. With the GPIO library we need to specify
+        * byte order explicitly, so this flag needs to be set when compiling
+        * for big endian.
+        */
+#if defined(CONFIG_CPU_BIG_ENDIAN)
+       flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER;
+#else
+       flags = 0;
+#endif
+
+       /* Populate and register gpio chip */
+       ret = bgpio_init(&g->gc, dev, 4,
+                        g->base + IXP4XX_REG_GPIN,
+                        g->base + IXP4XX_REG_GPOUT,
+                        NULL,
+                        NULL,
+                        g->base + IXP4XX_REG_GPOE,
+                        flags);
+       if (ret) {
+               dev_err(dev, "unable to init generic GPIO\n");
+               return ret;
+       }
+       g->gc.to_irq = ixp4xx_gpio_to_irq;
+       g->gc.ngpio = 16;
+       g->gc.label = "IXP4XX_GPIO_CHIP";
+       /*
+        * TODO: when we have migrated to device tree and all GPIOs
+        * are fetched using phandles, set this to -1 to get rid of
+        * the fixed gpiochip base.
+        */
+       g->gc.base = 0;
+       g->gc.parent = &pdev->dev;
+       g->gc.owner = THIS_MODULE;
+
+       ret = devm_gpiochip_add_data(dev, &g->gc, g);
+       if (ret) {
+               dev_err(dev, "failed to add SoC gpiochip\n");
+               return ret;
+       }
+
+       /*
+        * When we convert to device tree we will simply look up the
+        * parent irqdomain using irq_find_host(parent) as parent comes
+        * from IRQCHIP_DECLARE(), then use of_node_to_fwnode() to get
+        * the fwnode. For now we need this boardfile style code.
+        */
+       if (np) {
+               struct device_node *irq_parent;
+
+               irq_parent = of_irq_find_parent(np);
+               if (!irq_parent) {
+                       dev_err(dev, "no IRQ parent node\n");
+                       return -ENODEV;
+               }
+               parent = irq_find_host(irq_parent);
+               if (!parent) {
+                       dev_err(dev, "no IRQ parent domain\n");
+                       return -ENODEV;
+               }
+               g->fwnode = of_node_to_fwnode(np);
+       } else {
+               parent = ixp4xx_get_irq_domain();
+               g->fwnode = irq_domain_alloc_fwnode(g->base);
+               if (!g->fwnode) {
+                       dev_err(dev, "no domain base\n");
+                       return -ENODEV;
+               }
+       }
+       g->domain = irq_domain_create_hierarchy(parent,
+                                               IRQ_DOMAIN_FLAG_HIERARCHY,
+                                               ARRAY_SIZE(ixp4xx_gpiomap),
+                                               g->fwnode,
+                                               &ixp4xx_gpio_irqdomain_ops,
+                                               g);
+       if (!g->domain) {
+               irq_domain_free_fwnode(g->fwnode);
+               dev_err(dev, "no hierarchical irq domain\n");
+               return ret;
+       }
+
+       /*
+        * After adding OF support, this is no longer needed: irqs
+        * will be allocated for the respective fwnodes.
+        */
+       if (!np) {
+               for (i = 0; i < ARRAY_SIZE(ixp4xx_gpiomap); i++) {
+                       const struct ixp4xx_gpio_map *map = &ixp4xx_gpiomap[i];
+                       struct irq_fwspec fwspec;
+
+                       fwspec.fwnode = g->fwnode;
+                       /* This is the hwirq for the GPIO line side of things */
+                       fwspec.param[0] = map->gpio_offset;
+                       fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
+                       fwspec.param_count = 2;
+                       ret = __irq_domain_alloc_irqs(g->domain,
+                                                     -1, /* just pick something */
+                                                     1,
+                                                     NUMA_NO_NODE,
+                                                     &fwspec,
+                                                     false,
+                                                     NULL);
+                       if (ret < 0) {
+                               irq_domain_free_fwnode(g->fwnode);
+                               dev_err(dev,
+                                       "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n",
+                                       map->gpio_offset, map->parent_hwirq,
+                                       ret);
+                               return ret;
+                       }
+               }
+       }
+
+       platform_set_drvdata(pdev, g);
+       dev_info(dev, "IXP4 GPIO @%p registered\n", g->base);
+
+       return 0;
+}
+
+static const struct of_device_id ixp4xx_gpio_of_match[] = {
+       {
+               .compatible = "intel,ixp4xx-gpio",
+       },
+       {},
+};
+
+
+static struct platform_driver ixp4xx_gpio_driver = {
+       .driver = {
+               .name           = "ixp4xx-gpio",
+               .of_match_table = of_match_ptr(ixp4xx_gpio_of_match),
+       },
+       .probe = ixp4xx_gpio_probe,
+};
+builtin_platform_driver(ixp4xx_gpio_driver);
index 6b9bf8b7bf1668881f4640e6a300cd113382ce48..b97a91166497ac11c4339de2ffdc40254c41144d 100644 (file)
@@ -147,7 +147,6 @@ static int ttl_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct ttl_module *mod;
        struct gpio_chip *gpio;
-       struct resource *res;
        int ret;
 
        pdata = dev_get_platdata(&pdev->dev);
@@ -164,8 +163,7 @@ static int ttl_probe(struct platform_device *pdev)
        spin_lock_init(&mod->lock);
 
        /* get access to the MODULbus registers for this module */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mod->regs = devm_ioremap_resource(dev, res);
+       mod->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(mod->regs))
                return PTR_ERR(mod->regs);
 
index fca84ccac35c4e8105423811e5958f2d8a1a7615..1b1ee94eeab4762a9091b2d1a366e19dcba37629 100644 (file)
@@ -47,15 +47,13 @@ static int ls1x_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct gpio_chip *gc;
-       struct resource *res;
        int ret;
 
        gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
        if (!gc)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       gpio_reg_base = devm_ioremap_resource(dev, res);
+       gpio_reg_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(gpio_reg_base))
                return PTR_ERR(gpio_reg_base);
 
index d441dbaed7a3d2bd22df11e00c1ab5930ae0f059..d711ae06747eeff69e2a0b9b6972fb9b2bef6427 100644 (file)
@@ -340,10 +340,7 @@ static int lpc18xx_gpio_probe(struct platform_device *pdev)
        index = of_property_match_string(dev->of_node, "reg-names", "gpio");
        if (index < 0) {
                /* To support backward compatibility take the first resource */
-               struct resource *res;
-
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               gc->base = devm_ioremap_resource(dev, res);
+               gc->base = devm_platform_ioremap_resource(pdev, 0);
        } else {
                struct resource res;
 
diff --git a/drivers/gpio/gpio-max77650.c b/drivers/gpio/gpio-max77650.c
new file mode 100644 (file)
index 0000000..3f03f4e
--- /dev/null
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 BayLibre SAS
+// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+//
+// GPIO driver for MAXIM 77650/77651 charger/power-supply.
+
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/mfd/max77650.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MAX77650_GPIO_DIR_MASK         BIT(0)
+#define MAX77650_GPIO_INVAL_MASK       BIT(1)
+#define MAX77650_GPIO_DRV_MASK         BIT(2)
+#define MAX77650_GPIO_OUTVAL_MASK      BIT(3)
+#define MAX77650_GPIO_DEBOUNCE_MASK    BIT(4)
+
+#define MAX77650_GPIO_DIR_OUT          0x00
+#define MAX77650_GPIO_DIR_IN           BIT(0)
+#define MAX77650_GPIO_OUT_LOW          0x00
+#define MAX77650_GPIO_OUT_HIGH         BIT(3)
+#define MAX77650_GPIO_DRV_OPEN_DRAIN   0x00
+#define MAX77650_GPIO_DRV_PUSH_PULL    BIT(2)
+#define MAX77650_GPIO_DEBOUNCE         BIT(4)
+
+#define MAX77650_GPIO_DIR_BITS(_reg) \
+               ((_reg) & MAX77650_GPIO_DIR_MASK)
+#define MAX77650_GPIO_INVAL_BITS(_reg) \
+               (((_reg) & MAX77650_GPIO_INVAL_MASK) >> 1)
+
+struct max77650_gpio_chip {
+       struct regmap *map;
+       struct gpio_chip gc;
+       int irq;
+};
+
+static int max77650_gpio_direction_input(struct gpio_chip *gc,
+                                        unsigned int offset)
+{
+       struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
+
+       return regmap_update_bits(chip->map,
+                                 MAX77650_REG_CNFG_GPIO,
+                                 MAX77650_GPIO_DIR_MASK,
+                                 MAX77650_GPIO_DIR_IN);
+}
+
+static int max77650_gpio_direction_output(struct gpio_chip *gc,
+                                         unsigned int offset, int value)
+{
+       struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
+       int mask, regval;
+
+       mask = MAX77650_GPIO_DIR_MASK | MAX77650_GPIO_OUTVAL_MASK;
+       regval = value ? MAX77650_GPIO_OUT_HIGH : MAX77650_GPIO_OUT_LOW;
+       regval |= MAX77650_GPIO_DIR_OUT;
+
+       return regmap_update_bits(chip->map,
+                                 MAX77650_REG_CNFG_GPIO, mask, regval);
+}
+
+static void max77650_gpio_set_value(struct gpio_chip *gc,
+                                   unsigned int offset, int value)
+{
+       struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
+       int rv, regval;
+
+       regval = value ? MAX77650_GPIO_OUT_HIGH : MAX77650_GPIO_OUT_LOW;
+
+       rv = regmap_update_bits(chip->map, MAX77650_REG_CNFG_GPIO,
+                               MAX77650_GPIO_OUTVAL_MASK, regval);
+       if (rv)
+               dev_err(gc->parent, "cannot set GPIO value: %d\n", rv);
+}
+
+static int max77650_gpio_get_value(struct gpio_chip *gc,
+                                  unsigned int offset)
+{
+       struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
+       unsigned int val;
+       int rv;
+
+       rv = regmap_read(chip->map, MAX77650_REG_CNFG_GPIO, &val);
+       if (rv)
+               return rv;
+
+       return MAX77650_GPIO_INVAL_BITS(val);
+}
+
+static int max77650_gpio_get_direction(struct gpio_chip *gc,
+                                      unsigned int offset)
+{
+       struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
+       unsigned int val;
+       int rv;
+
+       rv = regmap_read(chip->map, MAX77650_REG_CNFG_GPIO, &val);
+       if (rv)
+               return rv;
+
+       return MAX77650_GPIO_DIR_BITS(val);
+}
+
+static int max77650_gpio_set_config(struct gpio_chip *gc,
+                                   unsigned int offset, unsigned long cfg)
+{
+       struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
+
+       switch (pinconf_to_config_param(cfg)) {
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+               return regmap_update_bits(chip->map,
+                                         MAX77650_REG_CNFG_GPIO,
+                                         MAX77650_GPIO_DRV_MASK,
+                                         MAX77650_GPIO_DRV_OPEN_DRAIN);
+       case PIN_CONFIG_DRIVE_PUSH_PULL:
+               return regmap_update_bits(chip->map,
+                                         MAX77650_REG_CNFG_GPIO,
+                                         MAX77650_GPIO_DRV_MASK,
+                                         MAX77650_GPIO_DRV_PUSH_PULL);
+       case PIN_CONFIG_INPUT_DEBOUNCE:
+               return regmap_update_bits(chip->map,
+                                         MAX77650_REG_CNFG_GPIO,
+                                         MAX77650_GPIO_DEBOUNCE_MASK,
+                                         MAX77650_GPIO_DEBOUNCE);
+       default:
+               return -ENOTSUPP;
+       }
+}
+
+static int max77650_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
+{
+       struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
+
+       return chip->irq;
+}
+
+static int max77650_gpio_probe(struct platform_device *pdev)
+{
+       struct max77650_gpio_chip *chip;
+       struct device *dev, *parent;
+       struct i2c_client *i2c;
+
+       dev = &pdev->dev;
+       parent = dev->parent;
+       i2c = to_i2c_client(parent);
+
+       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->map = dev_get_regmap(parent, NULL);
+       if (!chip->map)
+               return -ENODEV;
+
+       chip->irq = platform_get_irq_byname(pdev, "GPI");
+       if (chip->irq < 0)
+               return chip->irq;
+
+       chip->gc.base = -1;
+       chip->gc.ngpio = 1;
+       chip->gc.label = i2c->name;
+       chip->gc.parent = dev;
+       chip->gc.owner = THIS_MODULE;
+       chip->gc.can_sleep = true;
+
+       chip->gc.direction_input = max77650_gpio_direction_input;
+       chip->gc.direction_output = max77650_gpio_direction_output;
+       chip->gc.set = max77650_gpio_set_value;
+       chip->gc.get = max77650_gpio_get_value;
+       chip->gc.get_direction = max77650_gpio_get_direction;
+       chip->gc.set_config = max77650_gpio_set_config;
+       chip->gc.to_irq = max77650_gpio_to_irq;
+
+       return devm_gpiochip_add_data(dev, &chip->gc, chip);
+}
+
+static struct platform_driver max77650_gpio_driver = {
+       .driver = {
+               .name = "max77650-gpio",
+       },
+       .probe = max77650_gpio_probe,
+};
+module_platform_driver(max77650_gpio_driver);
+
+MODULE_DESCRIPTION("MAXIM 77650/77651 GPIO driver");
+MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
+MODULE_LICENSE("GPL v2");
index 3134c0d2bfe4bfe25b09bef301316f7dae639a8e..9308081e0a4a42aec1c607b25462a22e0b006ab8 100644 (file)
@@ -146,7 +146,6 @@ static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value)
 static int mb86s70_gpio_probe(struct platform_device *pdev)
 {
        struct mb86s70_gpio_chip *gchip;
-       struct resource *res;
        int ret;
 
        gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL);
@@ -155,8 +154,7 @@ static int mb86s70_gpio_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, gchip);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       gchip->base = devm_ioremap_resource(&pdev->dev, res);
+       gchip->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(gchip->base))
                return PTR_ERR(gchip->base);
 
diff --git a/drivers/gpio/gpio-mlxbf.c b/drivers/gpio/gpio-mlxbf.c
new file mode 100644 (file)
index 0000000..894aaf5
--- /dev/null
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/acpi.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/resource.h>
+#include <linux/types.h>
+
+/* Number of pins on BlueField */
+#define MLXBF_GPIO_NR 54
+
+/* Pad Electrical Controls. */
+#define MLXBF_GPIO_PAD_CONTROL_FIRST_WORD 0x0700
+#define MLXBF_GPIO_PAD_CONTROL_1_FIRST_WORD 0x0708
+#define MLXBF_GPIO_PAD_CONTROL_2_FIRST_WORD 0x0710
+#define MLXBF_GPIO_PAD_CONTROL_3_FIRST_WORD 0x0718
+
+#define MLXBF_GPIO_PIN_DIR_I 0x1040
+#define MLXBF_GPIO_PIN_DIR_O 0x1048
+#define MLXBF_GPIO_PIN_STATE 0x1000
+#define MLXBF_GPIO_SCRATCHPAD 0x20
+
+#ifdef CONFIG_PM
+struct mlxbf_gpio_context_save_regs {
+       u64 scratchpad;
+       u64 pad_control[MLXBF_GPIO_NR];
+       u64 pin_dir_i;
+       u64 pin_dir_o;
+};
+#endif
+
+/* Device state structure. */
+struct mlxbf_gpio_state {
+       struct gpio_chip gc;
+
+       /* Memory Address */
+       void __iomem *base;
+
+#ifdef CONFIG_PM
+       struct mlxbf_gpio_context_save_regs csave_regs;
+#endif
+};
+
+static int mlxbf_gpio_probe(struct platform_device *pdev)
+{
+       struct mlxbf_gpio_state *gs;
+       struct device *dev = &pdev->dev;
+       struct gpio_chip *gc;
+       int ret;
+
+       gs = devm_kzalloc(&pdev->dev, sizeof(*gs), GFP_KERNEL);
+       if (!gs)
+               return -ENOMEM;
+
+       gs->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(gs->base))
+               return PTR_ERR(gs->base);
+
+       gc = &gs->gc;
+       ret = bgpio_init(gc, dev, 8,
+                        gs->base + MLXBF_GPIO_PIN_STATE,
+                        NULL,
+                        NULL,
+                        gs->base + MLXBF_GPIO_PIN_DIR_O,
+                        gs->base + MLXBF_GPIO_PIN_DIR_I,
+                        0);
+       if (ret)
+               return -ENODEV;
+
+       gc->owner = THIS_MODULE;
+       gc->ngpio = MLXBF_GPIO_NR;
+
+       ret = devm_gpiochip_add_data(dev, &gs->gc, gs);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n");
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, gs);
+       dev_info(&pdev->dev, "registered Mellanox BlueField GPIO");
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int mlxbf_gpio_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct mlxbf_gpio_state *gs = platform_get_drvdata(pdev);
+
+       gs->csave_regs.scratchpad = readq(gs->base + MLXBF_GPIO_SCRATCHPAD);
+       gs->csave_regs.pad_control[0] =
+               readq(gs->base + MLXBF_GPIO_PAD_CONTROL_FIRST_WORD);
+       gs->csave_regs.pad_control[1] =
+               readq(gs->base + MLXBF_GPIO_PAD_CONTROL_1_FIRST_WORD);
+       gs->csave_regs.pad_control[2] =
+               readq(gs->base + MLXBF_GPIO_PAD_CONTROL_2_FIRST_WORD);
+       gs->csave_regs.pad_control[3] =
+               readq(gs->base + MLXBF_GPIO_PAD_CONTROL_3_FIRST_WORD);
+       gs->csave_regs.pin_dir_i = readq(gs->base + MLXBF_GPIO_PIN_DIR_I);
+       gs->csave_regs.pin_dir_o = readq(gs->base + MLXBF_GPIO_PIN_DIR_O);
+
+       return 0;
+}
+
+static int mlxbf_gpio_resume(struct platform_device *pdev)
+{
+       struct mlxbf_gpio_state *gs = platform_get_drvdata(pdev);
+
+       writeq(gs->csave_regs.scratchpad, gs->base + MLXBF_GPIO_SCRATCHPAD);
+       writeq(gs->csave_regs.pad_control[0],
+              gs->base + MLXBF_GPIO_PAD_CONTROL_FIRST_WORD);
+       writeq(gs->csave_regs.pad_control[1],
+              gs->base + MLXBF_GPIO_PAD_CONTROL_1_FIRST_WORD);
+       writeq(gs->csave_regs.pad_control[2],
+              gs->base + MLXBF_GPIO_PAD_CONTROL_2_FIRST_WORD);
+       writeq(gs->csave_regs.pad_control[3],
+              gs->base + MLXBF_GPIO_PAD_CONTROL_3_FIRST_WORD);
+       writeq(gs->csave_regs.pin_dir_i, gs->base + MLXBF_GPIO_PIN_DIR_I);
+       writeq(gs->csave_regs.pin_dir_o, gs->base + MLXBF_GPIO_PIN_DIR_O);
+
+       return 0;
+}
+#endif
+
+static const struct acpi_device_id mlxbf_gpio_acpi_match[] = {
+       { "MLNXBF02", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(acpi, mlxbf_gpio_acpi_match);
+
+static struct platform_driver mlxbf_gpio_driver = {
+       .driver = {
+               .name = "mlxbf_gpio",
+               .acpi_match_table = ACPI_PTR(mlxbf_gpio_acpi_match),
+       },
+       .probe    = mlxbf_gpio_probe,
+#ifdef CONFIG_PM
+       .suspend  = mlxbf_gpio_suspend,
+       .resume   = mlxbf_gpio_resume,
+#endif
+};
+
+module_platform_driver(mlxbf_gpio_driver);
+
+MODULE_DESCRIPTION("Mellanox BlueField GPIO Driver");
+MODULE_AUTHOR("Mellanox Technologies");
+MODULE_LICENSE("GPL");
index 50bdc29591c059612b0c5d58b0f3ce8cedfd32c6..6f904c87467826c5e48a2e710c4929488f07ceec 100644 (file)
@@ -134,17 +134,6 @@ static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
        unsigned long pinmask = bgpio_line2mask(gc, gpio);
        bool dir = !!(gc->bgpio_dir & pinmask);
 
-       /*
-        * If the direction is OUT we read the value from the SET
-        * register, and if the direction is IN we read the value
-        * from the DAT register.
-        *
-        * If the direction bits are inverted, naturally this gets
-        * inverted too.
-        */
-       if (gc->bgpio_dir_inverted)
-               dir = !dir;
-
        if (dir)
                return !!(gc->read_reg(gc->reg_set) & pinmask);
        else
@@ -164,14 +153,8 @@ static int bgpio_get_set_multiple(struct gpio_chip *gc, unsigned long *mask,
        /* Make sure we first clear any bits that are zero when we read the register */
        *bits &= ~*mask;
 
-       /* Exploit the fact that we know which directions are set */
-       if (gc->bgpio_dir_inverted) {
-               set_mask = *mask & ~gc->bgpio_dir;
-               get_mask = *mask & gc->bgpio_dir;
-       } else {
-               set_mask = *mask & gc->bgpio_dir;
-               get_mask = *mask & ~gc->bgpio_dir;
-       }
+       set_mask = *mask & gc->bgpio_dir;
+       get_mask = *mask & ~gc->bgpio_dir;
 
        if (set_mask)
                *bits |= gc->read_reg(gc->reg_set) & set_mask;
@@ -372,11 +355,12 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
 
        spin_lock_irqsave(&gc->bgpio_lock, flags);
 
-       if (gc->bgpio_dir_inverted)
-               gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
-       else
-               gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio);
-       gc->write_reg(gc->reg_dir, gc->bgpio_dir);
+       gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio);
+
+       if (gc->reg_dir_in)
+               gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir);
+       if (gc->reg_dir_out)
+               gc->write_reg(gc->reg_dir_out, gc->bgpio_dir);
 
        spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 
@@ -385,11 +369,16 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
 
 static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
 {
-       /* Return 0 if output, 1 of input */
-       if (gc->bgpio_dir_inverted)
-               return !!(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio));
-       else
-               return !(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio));
+       /* Return 0 if output, 1 if input */
+       if (gc->bgpio_dir_unreadable)
+               return !(gc->bgpio_dir & bgpio_line2mask(gc, gpio));
+       if (gc->reg_dir_out)
+               return !(gc->read_reg(gc->reg_dir_out) & bgpio_line2mask(gc, gpio));
+       if (gc->reg_dir_in)
+               return !!(gc->read_reg(gc->reg_dir_in) & bgpio_line2mask(gc, gpio));
+
+       /* This should not happen */
+       return 1;
 }
 
 static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
@@ -400,11 +389,12 @@ static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 
        spin_lock_irqsave(&gc->bgpio_lock, flags);
 
-       if (gc->bgpio_dir_inverted)
-               gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio);
-       else
-               gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
-       gc->write_reg(gc->reg_dir, gc->bgpio_dir);
+       gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
+
+       if (gc->reg_dir_in)
+               gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir);
+       if (gc->reg_dir_out)
+               gc->write_reg(gc->reg_dir_out, gc->bgpio_dir);
 
        spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 
@@ -537,19 +527,12 @@ static int bgpio_setup_direction(struct gpio_chip *gc,
                                 void __iomem *dirin,
                                 unsigned long flags)
 {
-       if (dirout && dirin) {
-               return -EINVAL;
-       } else if (dirout) {
-               gc->reg_dir = dirout;
-               gc->direction_output = bgpio_dir_out;
-               gc->direction_input = bgpio_dir_in;
-               gc->get_direction = bgpio_get_dir;
-       } else if (dirin) {
-               gc->reg_dir = dirin;
+       if (dirout || dirin) {
+               gc->reg_dir_out = dirout;
+               gc->reg_dir_in = dirin;
                gc->direction_output = bgpio_dir_out;
                gc->direction_input = bgpio_dir_in;
                gc->get_direction = bgpio_get_dir;
-               gc->bgpio_dir_inverted = true;
        } else {
                if (flags & BGPIOF_NO_OUTPUT)
                        gc->direction_output = bgpio_dir_out_err;
@@ -588,11 +571,11 @@ static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin)
  * @dirout: MMIO address for the register to set the line as OUTPUT. It is assumed
  *     that setting a line to 1 in this register will turn that line into an
  *     output line. Conversely, setting the line to 0 will turn that line into
- *     an input. Either this or @dirin can be defined, but never both.
+ *     an input.
  * @dirin: MMIO address for the register to set this line as INPUT. It is assumed
  *     that setting a line to 1 in this register will turn that line into an
  *     input line. Conversely, setting the line to 0 will turn that line into
- *     an output. Either this or @dirout can be defined, but never both.
+ *     an output.
  * @flags: Different flags that will affect the behaviour of the device, such as
  *     endianness etc.
  */
@@ -634,8 +617,28 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
        if (gc->set == bgpio_set_set &&
                        !(flags & BGPIOF_UNREADABLE_REG_SET))
                gc->bgpio_data = gc->read_reg(gc->reg_set);
-       if (gc->reg_dir && !(flags & BGPIOF_UNREADABLE_REG_DIR))
-               gc->bgpio_dir = gc->read_reg(gc->reg_dir);
+
+       if (flags & BGPIOF_UNREADABLE_REG_DIR)
+               gc->bgpio_dir_unreadable = true;
+
+       /*
+        * Inspect hardware to find initial direction setting.
+        */
+       if ((gc->reg_dir_out || gc->reg_dir_in) &&
+           !(flags & BGPIOF_UNREADABLE_REG_DIR)) {
+               if (gc->reg_dir_out)
+                       gc->bgpio_dir = gc->read_reg(gc->reg_dir_out);
+               else if (gc->reg_dir_in)
+                       gc->bgpio_dir = ~gc->read_reg(gc->reg_dir_in);
+               /*
+                * If we have two direction registers, synchronise
+                * input setting to output setting, the library
+                * can not handle a line being input and output at
+                * the same time.
+                */
+               if (gc->reg_dir_out && gc->reg_dir_in)
+                       gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir);
+       }
 
        return ret;
 }
index 74401e0adb29ce044c3534745e5f0218ab563965..79654fb2e50f2d55c73bce8e029345aa7a77f79c 100644 (file)
@@ -293,7 +293,6 @@ mediatek_gpio_bank_probe(struct device *dev,
 static int
 mediatek_gpio_probe(struct platform_device *pdev)
 {
-       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
        struct mtk *mtk;
@@ -304,7 +303,7 @@ mediatek_gpio_probe(struct platform_device *pdev)
        if (!mtk)
                return -ENOMEM;
 
-       mtk->base = devm_ioremap_resource(dev, res);
+       mtk->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(mtk->base))
                return PTR_ERR(mtk->base);
 
index f97ed32b8bebfeb2aa4eb2963ab39c261096f9f6..059094ac44cb38458ecfce964041450f409bf039 100644 (file)
@@ -1038,11 +1038,9 @@ static const struct regmap_config mvebu_gpio_regmap_config = {
 static int mvebu_gpio_probe_raw(struct platform_device *pdev,
                                struct mvebu_gpio_chip *mvchip)
 {
-       struct resource *res;
        void __iomem *base;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(&pdev->dev, res);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
@@ -1062,8 +1060,7 @@ static int mvebu_gpio_probe_raw(struct platform_device *pdev,
         * per-CPU registers
         */
        if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_ARMADAXP) {
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               base = devm_ioremap_resource(&pdev->dev, res);
+               base = devm_platform_ioremap_resource(pdev, 1);
                if (IS_ERR(base))
                        return PTR_ERR(base);
 
index e86e61dda4b757fa04c3616aab6c7ffb14554a53..b2813580c5825a08d7f05b45885b8798f44b17fa 100644 (file)
@@ -411,7 +411,6 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct mxc_gpio_port *port;
-       struct resource *iores;
        int irq_base;
        int err;
 
@@ -423,8 +422,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 
        port->dev = &pdev->dev;
 
-       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       port->base = devm_ioremap_resource(&pdev->dev, iores);
+       port->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(port->base))
                return PTR_ERR(port->base);
 
index 1b19c88ea7bb9e9fd4fbe161981b8c02153c97f0..afb0e8a791e5a8f1b3029c4ca890a5eb9b8efe44 100644 (file)
@@ -82,7 +82,6 @@ static int octeon_gpio_probe(struct platform_device *pdev)
 {
        struct octeon_gpio *gpio;
        struct gpio_chip *chip;
-       struct resource *res_mem;
        void __iomem *reg_base;
        int err = 0;
 
@@ -91,8 +90,7 @@ static int octeon_gpio_probe(struct platform_device *pdev)
                return -ENOMEM;
        chip = &gpio->chip;
 
-       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       reg_base = devm_ioremap_resource(&pdev->dev, res_mem);
+       reg_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(reg_base))
                return PTR_ERR(reg_base);
 
index 7f33024b6d83e2ccdc6ae583b4c5fc38461a2dea..16289bafa001e04e51af76af8a0a46920f24684c 100644 (file)
@@ -31,8 +31,6 @@
 
 #define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF
 
-#define OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER    BIT(2)
-
 struct gpio_regs {
        u32 irqenable1;
        u32 irqenable2;
@@ -48,13 +46,6 @@ struct gpio_regs {
        u32 debounce_en;
 };
 
-struct gpio_bank;
-
-struct gpio_omap_funcs {
-       void (*idle_enable_level_quirk)(struct gpio_bank *bank);
-       void (*idle_disable_level_quirk)(struct gpio_bank *bank);
-};
-
 struct gpio_bank {
        struct list_head node;
        void __iomem *base;
@@ -62,7 +53,6 @@ struct gpio_bank {
        u32 non_wakeup_gpios;
        u32 enabled_non_wakeup_gpios;
        struct gpio_regs context;
-       struct gpio_omap_funcs funcs;
        u32 saved_datain;
        u32 level_mask;
        u32 toggle_mask;
@@ -83,8 +73,6 @@ struct gpio_bank {
        int stride;
        u32 width;
        int context_loss_count;
-       bool workaround_enabled;
-       u32 quirks;
 
        void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable);
        void (*set_dataout_multiple)(struct gpio_bank *bank,
@@ -353,6 +341,22 @@ static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned offset)
        }
 }
 
+/*
+ * Off mode wake-up capable GPIOs in bank(s) that are in the wakeup domain.
+ * See TRM section for GPIO for "Wake-Up Generation" for the list of GPIOs
+ * in wakeup domain. If bank->non_wakeup_gpios is not configured, assume none
+ * are capable waking up the system from off mode.
+ */
+static bool omap_gpio_is_off_wakeup_capable(struct gpio_bank *bank, u32 gpio_mask)
+{
+       u32 no_wake = bank->non_wakeup_gpios;
+
+       if (no_wake)
+               return !!(~no_wake & gpio_mask);
+
+       return false;
+}
+
 static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
                                                unsigned trigger)
 {
@@ -363,10 +367,16 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
                      trigger & IRQ_TYPE_LEVEL_LOW);
        omap_gpio_rmw(base, bank->regs->leveldetect1, gpio_bit,
                      trigger & IRQ_TYPE_LEVEL_HIGH);
+
+       /*
+        * We need the edge detection enabled for to allow the GPIO block
+        * to be woken from idle state.  Set the appropriate edge detection
+        * in addition to the level detection.
+        */
        omap_gpio_rmw(base, bank->regs->risingdetect, gpio_bit,
-                     trigger & IRQ_TYPE_EDGE_RISING);
+                     trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH));
        omap_gpio_rmw(base, bank->regs->fallingdetect, gpio_bit,
-                     trigger & IRQ_TYPE_EDGE_FALLING);
+                     trigger & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW));
 
        bank->context.leveldetect0 =
                        readl_relaxed(bank->base + bank->regs->leveldetect0);
@@ -384,13 +394,7 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
        }
 
        /* This part needs to be executed always for OMAP{34xx, 44xx} */
-       if (!bank->regs->irqctrl) {
-               /* On omap24xx proceed only when valid GPIO bit is set */
-               if (bank->non_wakeup_gpios) {
-                       if (!(bank->non_wakeup_gpios & gpio_bit))
-                               goto exit;
-               }
-
+       if (!bank->regs->irqctrl && !omap_gpio_is_off_wakeup_capable(bank, gpio)) {
                /*
                 * Log the edge gpio and manually trigger the IRQ
                 * after resume if the input level changes
@@ -403,7 +407,6 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
                        bank->enabled_non_wakeup_gpios &= ~gpio_bit;
        }
 
-exit:
        bank->level_mask =
                readl_relaxed(bank->base + bank->regs->leveldetect0) |
                readl_relaxed(bank->base + bank->regs->leveldetect1);
@@ -896,44 +899,6 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
        raw_spin_unlock_irqrestore(&bank->lock, flags);
 }
 
-/*
- * Only edges can generate a wakeup event to the PRCM.
- *
- * Therefore, ensure any wake-up capable GPIOs have
- * edge-detection enabled before going idle to ensure a wakeup
- * to the PRCM is generated on a GPIO transition. (c.f. 34xx
- * NDA TRM 25.5.3.1)
- *
- * The normal values will be restored upon ->runtime_resume()
- * by writing back the values saved in bank->context.
- */
-static void __maybe_unused
-omap2_gpio_enable_level_quirk(struct gpio_bank *bank)
-{
-       u32 wake_low, wake_hi;
-
-       /* Enable additional edge detection for level gpios for idle */
-       wake_low = bank->context.leveldetect0 & bank->context.wake_en;
-       if (wake_low)
-               writel_relaxed(wake_low | bank->context.fallingdetect,
-                              bank->base + bank->regs->fallingdetect);
-
-       wake_hi = bank->context.leveldetect1 & bank->context.wake_en;
-       if (wake_hi)
-               writel_relaxed(wake_hi | bank->context.risingdetect,
-                              bank->base + bank->regs->risingdetect);
-}
-
-static void __maybe_unused
-omap2_gpio_disable_level_quirk(struct gpio_bank *bank)
-{
-       /* Disable edge detection for level gpios after idle */
-       writel_relaxed(bank->context.fallingdetect,
-                      bank->base + bank->regs->fallingdetect);
-       writel_relaxed(bank->context.risingdetect,
-                      bank->base + bank->regs->risingdetect);
-}
-
 /*---------------------------------------------------------------------*/
 
 static int omap_mpuio_suspend_noirq(struct device *dev)
@@ -1251,203 +1216,70 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
        return ret;
 }
 
-static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context);
-static void omap_gpio_unidle(struct gpio_bank *bank);
-
-static int gpio_omap_cpu_notifier(struct notifier_block *nb,
-                                 unsigned long cmd, void *v)
+static void omap_gpio_init_context(struct gpio_bank *p)
 {
-       struct gpio_bank *bank;
-       unsigned long flags;
+       struct omap_gpio_reg_offs *regs = p->regs;
+       void __iomem *base = p->base;
 
-       bank = container_of(nb, struct gpio_bank, nb);
+       p->context.ctrl         = readl_relaxed(base + regs->ctrl);
+       p->context.oe           = readl_relaxed(base + regs->direction);
+       p->context.wake_en      = readl_relaxed(base + regs->wkup_en);
+       p->context.leveldetect0 = readl_relaxed(base + regs->leveldetect0);
+       p->context.leveldetect1 = readl_relaxed(base + regs->leveldetect1);
+       p->context.risingdetect = readl_relaxed(base + regs->risingdetect);
+       p->context.fallingdetect = readl_relaxed(base + regs->fallingdetect);
+       p->context.irqenable1   = readl_relaxed(base + regs->irqenable);
+       p->context.irqenable2   = readl_relaxed(base + regs->irqenable2);
 
-       raw_spin_lock_irqsave(&bank->lock, flags);
-       switch (cmd) {
-       case CPU_CLUSTER_PM_ENTER:
-               if (bank->is_suspended)
-                       break;
-               omap_gpio_idle(bank, true);
-               break;
-       case CPU_CLUSTER_PM_ENTER_FAILED:
-       case CPU_CLUSTER_PM_EXIT:
-               if (bank->is_suspended)
-                       break;
-               omap_gpio_unidle(bank);
-               break;
-       }
-       raw_spin_unlock_irqrestore(&bank->lock, flags);
+       if (regs->set_dataout && p->regs->clr_dataout)
+               p->context.dataout = readl_relaxed(base + regs->set_dataout);
+       else
+               p->context.dataout = readl_relaxed(base + regs->dataout);
 
-       return NOTIFY_OK;
+       p->context_valid = true;
 }
 
-static const struct of_device_id omap_gpio_match[];
-
-static int omap_gpio_probe(struct platform_device *pdev)
+static void omap_gpio_restore_context(struct gpio_bank *bank)
 {
-       struct device *dev = &pdev->dev;
-       struct device_node *node = dev->of_node;
-       const struct of_device_id *match;
-       const struct omap_gpio_platform_data *pdata;
-       struct resource *res;
-       struct gpio_bank *bank;
-       struct irq_chip *irqc;
-       int ret;
-
-       match = of_match_device(of_match_ptr(omap_gpio_match), dev);
-
-       pdata = match ? match->data : dev_get_platdata(dev);
-       if (!pdata)
-               return -EINVAL;
-
-       bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
-       if (!bank)
-               return -ENOMEM;
-
-       irqc = devm_kzalloc(dev, sizeof(*irqc), GFP_KERNEL);
-       if (!irqc)
-               return -ENOMEM;
-
-       irqc->irq_startup = omap_gpio_irq_startup,
-       irqc->irq_shutdown = omap_gpio_irq_shutdown,
-       irqc->irq_ack = omap_gpio_ack_irq,
-       irqc->irq_mask = omap_gpio_mask_irq,
-       irqc->irq_unmask = omap_gpio_unmask_irq,
-       irqc->irq_set_type = omap_gpio_irq_type,
-       irqc->irq_set_wake = omap_gpio_wake_enable,
-       irqc->irq_bus_lock = omap_gpio_irq_bus_lock,
-       irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
-       irqc->name = dev_name(&pdev->dev);
-       irqc->flags = IRQCHIP_MASK_ON_SUSPEND;
-       irqc->parent_device = dev;
-
-       bank->irq = platform_get_irq(pdev, 0);
-       if (bank->irq <= 0) {
-               if (!bank->irq)
-                       bank->irq = -ENXIO;
-               if (bank->irq != -EPROBE_DEFER)
-                       dev_err(dev,
-                               "can't get irq resource ret=%d\n", bank->irq);
-               return bank->irq;
-       }
-
-       bank->chip.parent = dev;
-       bank->chip.owner = THIS_MODULE;
-       bank->dbck_flag = pdata->dbck_flag;
-       bank->quirks = pdata->quirks;
-       bank->stride = pdata->bank_stride;
-       bank->width = pdata->bank_width;
-       bank->is_mpuio = pdata->is_mpuio;
-       bank->non_wakeup_gpios = pdata->non_wakeup_gpios;
-       bank->regs = pdata->regs;
-#ifdef CONFIG_OF_GPIO
-       bank->chip.of_node = of_node_get(node);
-#endif
-
-       if (node) {
-               if (!of_property_read_bool(node, "ti,gpio-always-on"))
-                       bank->loses_context = true;
-       } else {
-               bank->loses_context = pdata->loses_context;
-
-               if (bank->loses_context)
-                       bank->get_context_loss_count =
-                               pdata->get_context_loss_count;
-       }
-
-       if (bank->regs->set_dataout && bank->regs->clr_dataout) {
-               bank->set_dataout = omap_set_gpio_dataout_reg;
-               bank->set_dataout_multiple = omap_set_gpio_dataout_reg_multiple;
-       } else {
-               bank->set_dataout = omap_set_gpio_dataout_mask;
-               bank->set_dataout_multiple =
-                               omap_set_gpio_dataout_mask_multiple;
-       }
-
-       if (bank->quirks & OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER) {
-               bank->funcs.idle_enable_level_quirk =
-                       omap2_gpio_enable_level_quirk;
-               bank->funcs.idle_disable_level_quirk =
-                       omap2_gpio_disable_level_quirk;
-       }
-
-       raw_spin_lock_init(&bank->lock);
-       raw_spin_lock_init(&bank->wa_lock);
-
-       /* Static mapping, never released */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       bank->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(bank->base)) {
-               return PTR_ERR(bank->base);
-       }
-
-       if (bank->dbck_flag) {
-               bank->dbck = devm_clk_get(dev, "dbclk");
-               if (IS_ERR(bank->dbck)) {
-                       dev_err(dev,
-                               "Could not get gpio dbck. Disable debounce\n");
-                       bank->dbck_flag = false;
-               } else {
-                       clk_prepare(bank->dbck);
-               }
-       }
-
-       platform_set_drvdata(pdev, bank);
-
-       pm_runtime_enable(dev);
-       pm_runtime_get_sync(dev);
-
-       if (bank->is_mpuio)
-               omap_mpuio_init(bank);
-
-       omap_gpio_mod_init(bank);
-
-       ret = omap_gpio_chip_init(bank, irqc);
-       if (ret) {
-               pm_runtime_put_sync(dev);
-               pm_runtime_disable(dev);
-               if (bank->dbck_flag)
-                       clk_unprepare(bank->dbck);
-               return ret;
-       }
-
-       omap_gpio_show_rev(bank);
+       writel_relaxed(bank->context.wake_en,
+                               bank->base + bank->regs->wkup_en);
+       writel_relaxed(bank->context.ctrl, bank->base + bank->regs->ctrl);
+       writel_relaxed(bank->context.leveldetect0,
+                               bank->base + bank->regs->leveldetect0);
+       writel_relaxed(bank->context.leveldetect1,
+                               bank->base + bank->regs->leveldetect1);
+       writel_relaxed(bank->context.risingdetect,
+                               bank->base + bank->regs->risingdetect);
+       writel_relaxed(bank->context.fallingdetect,
+                               bank->base + bank->regs->fallingdetect);
+       if (bank->regs->set_dataout && bank->regs->clr_dataout)
+               writel_relaxed(bank->context.dataout,
+                               bank->base + bank->regs->set_dataout);
+       else
+               writel_relaxed(bank->context.dataout,
+                               bank->base + bank->regs->dataout);
+       writel_relaxed(bank->context.oe, bank->base + bank->regs->direction);
 
-       if (bank->funcs.idle_enable_level_quirk &&
-           bank->funcs.idle_disable_level_quirk) {
-               bank->nb.notifier_call = gpio_omap_cpu_notifier;
-               cpu_pm_register_notifier(&bank->nb);
+       if (bank->dbck_enable_mask) {
+               writel_relaxed(bank->context.debounce, bank->base +
+                                       bank->regs->debounce);
+               writel_relaxed(bank->context.debounce_en,
+                                       bank->base + bank->regs->debounce_en);
        }
 
-       pm_runtime_put(dev);
-
-       return 0;
-}
-
-static int omap_gpio_remove(struct platform_device *pdev)
-{
-       struct gpio_bank *bank = platform_get_drvdata(pdev);
-
-       if (bank->nb.notifier_call)
-               cpu_pm_unregister_notifier(&bank->nb);
-       list_del(&bank->node);
-       gpiochip_remove(&bank->chip);
-       pm_runtime_disable(&pdev->dev);
-       if (bank->dbck_flag)
-               clk_unprepare(bank->dbck);
-
-       return 0;
+       writel_relaxed(bank->context.irqenable1,
+                               bank->base + bank->regs->irqenable);
+       writel_relaxed(bank->context.irqenable2,
+                               bank->base + bank->regs->irqenable2);
 }
 
-static void omap_gpio_restore_context(struct gpio_bank *bank);
-
 static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
 {
        struct device *dev = bank->chip.parent;
-       u32 l1 = 0, l2 = 0;
+       void __iomem *base = bank->base;
+       u32 nowake;
 
-       if (bank->funcs.idle_enable_level_quirk)
-               bank->funcs.idle_enable_level_quirk(bank);
+       bank->saved_datain = readl_relaxed(base + bank->regs->datain);
 
        if (!bank->enabled_non_wakeup_gpios)
                goto update_gpio_context_count;
@@ -1456,22 +1288,15 @@ static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
                goto update_gpio_context_count;
 
        /*
-        * If going to OFF, remove triggering for all
+        * If going to OFF, remove triggering for all wkup domain
         * non-wakeup GPIOs.  Otherwise spurious IRQs will be
         * generated.  See OMAP2420 Errata item 1.101.
         */
-       bank->saved_datain = readl_relaxed(bank->base +
-                                               bank->regs->datain);
-       l1 = bank->context.fallingdetect;
-       l2 = bank->context.risingdetect;
-
-       l1 &= ~bank->enabled_non_wakeup_gpios;
-       l2 &= ~bank->enabled_non_wakeup_gpios;
-
-       writel_relaxed(l1, bank->base + bank->regs->fallingdetect);
-       writel_relaxed(l2, bank->base + bank->regs->risingdetect);
-
-       bank->workaround_enabled = true;
+       if (!bank->loses_context && bank->enabled_non_wakeup_gpios) {
+               nowake = bank->enabled_non_wakeup_gpios;
+               omap_gpio_rmw(base, bank->regs->fallingdetect, nowake, ~nowake);
+               omap_gpio_rmw(base, bank->regs->risingdetect, nowake, ~nowake);
+       }
 
 update_gpio_context_count:
        if (bank->get_context_loss_count)
@@ -1481,8 +1306,6 @@ update_gpio_context_count:
        omap_gpio_dbck_disable(bank);
 }
 
-static void omap_gpio_init_context(struct gpio_bank *p);
-
 static void omap_gpio_unidle(struct gpio_bank *bank)
 {
        struct device *dev = bank->chip.parent;
@@ -1504,9 +1327,6 @@ static void omap_gpio_unidle(struct gpio_bank *bank)
 
        omap_gpio_dbck_enable(bank);
 
-       if (bank->funcs.idle_disable_level_quirk)
-               bank->funcs.idle_disable_level_quirk(bank);
-
        if (bank->loses_context) {
                if (!bank->get_context_loss_count) {
                        omap_gpio_restore_context(bank);
@@ -1518,11 +1338,14 @@ static void omap_gpio_unidle(struct gpio_bank *bank)
                                return;
                        }
                }
+       } else {
+               /* Restore changes done for OMAP2420 errata 1.101 */
+               writel_relaxed(bank->context.fallingdetect,
+                              bank->base + bank->regs->fallingdetect);
+               writel_relaxed(bank->context.risingdetect,
+                              bank->base + bank->regs->risingdetect);
        }
 
-       if (!bank->workaround_enabled)
-               return;
-
        l = readl_relaxed(bank->base + bank->regs->datain);
 
        /*
@@ -1572,117 +1395,35 @@ static void omap_gpio_unidle(struct gpio_bank *bank)
                writel_relaxed(old0, bank->base + bank->regs->leveldetect0);
                writel_relaxed(old1, bank->base + bank->regs->leveldetect1);
        }
-
-       bank->workaround_enabled = false;
 }
 
-static void omap_gpio_init_context(struct gpio_bank *p)
+static int gpio_omap_cpu_notifier(struct notifier_block *nb,
+                                 unsigned long cmd, void *v)
 {
-       struct omap_gpio_reg_offs *regs = p->regs;
-       void __iomem *base = p->base;
-
-       p->context.ctrl         = readl_relaxed(base + regs->ctrl);
-       p->context.oe           = readl_relaxed(base + regs->direction);
-       p->context.wake_en      = readl_relaxed(base + regs->wkup_en);
-       p->context.leveldetect0 = readl_relaxed(base + regs->leveldetect0);
-       p->context.leveldetect1 = readl_relaxed(base + regs->leveldetect1);
-       p->context.risingdetect = readl_relaxed(base + regs->risingdetect);
-       p->context.fallingdetect = readl_relaxed(base + regs->fallingdetect);
-       p->context.irqenable1   = readl_relaxed(base + regs->irqenable);
-       p->context.irqenable2   = readl_relaxed(base + regs->irqenable2);
-
-       if (regs->set_dataout && p->regs->clr_dataout)
-               p->context.dataout = readl_relaxed(base + regs->set_dataout);
-       else
-               p->context.dataout = readl_relaxed(base + regs->dataout);
-
-       p->context_valid = true;
-}
-
-static void omap_gpio_restore_context(struct gpio_bank *bank)
-{
-       writel_relaxed(bank->context.wake_en,
-                               bank->base + bank->regs->wkup_en);
-       writel_relaxed(bank->context.ctrl, bank->base + bank->regs->ctrl);
-       writel_relaxed(bank->context.leveldetect0,
-                               bank->base + bank->regs->leveldetect0);
-       writel_relaxed(bank->context.leveldetect1,
-                               bank->base + bank->regs->leveldetect1);
-       writel_relaxed(bank->context.risingdetect,
-                               bank->base + bank->regs->risingdetect);
-       writel_relaxed(bank->context.fallingdetect,
-                               bank->base + bank->regs->fallingdetect);
-       if (bank->regs->set_dataout && bank->regs->clr_dataout)
-               writel_relaxed(bank->context.dataout,
-                               bank->base + bank->regs->set_dataout);
-       else
-               writel_relaxed(bank->context.dataout,
-                               bank->base + bank->regs->dataout);
-       writel_relaxed(bank->context.oe, bank->base + bank->regs->direction);
-
-       if (bank->dbck_enable_mask) {
-               writel_relaxed(bank->context.debounce, bank->base +
-                                       bank->regs->debounce);
-               writel_relaxed(bank->context.debounce_en,
-                                       bank->base + bank->regs->debounce_en);
-       }
-
-       writel_relaxed(bank->context.irqenable1,
-                               bank->base + bank->regs->irqenable);
-       writel_relaxed(bank->context.irqenable2,
-                               bank->base + bank->regs->irqenable2);
-}
-
-static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev)
-{
-       struct gpio_bank *bank = dev_get_drvdata(dev);
+       struct gpio_bank *bank;
        unsigned long flags;
-       int error = 0;
-
-       raw_spin_lock_irqsave(&bank->lock, flags);
-       /* Must be idled only by CPU_CLUSTER_PM_ENTER? */
-       if (bank->irq_usage) {
-               error = -EBUSY;
-               goto unlock;
-       }
-       omap_gpio_idle(bank, true);
-       bank->is_suspended = true;
-unlock:
-       raw_spin_unlock_irqrestore(&bank->lock, flags);
-
-       return error;
-}
 
-static int __maybe_unused omap_gpio_runtime_resume(struct device *dev)
-{
-       struct gpio_bank *bank = dev_get_drvdata(dev);
-       unsigned long flags;
-       int error = 0;
+       bank = container_of(nb, struct gpio_bank, nb);
 
        raw_spin_lock_irqsave(&bank->lock, flags);
-       /* Must be unidled only by CPU_CLUSTER_PM_ENTER? */
-       if (bank->irq_usage) {
-               error = -EBUSY;
-               goto unlock;
+       switch (cmd) {
+       case CPU_CLUSTER_PM_ENTER:
+               if (bank->is_suspended)
+                       break;
+               omap_gpio_idle(bank, true);
+               break;
+       case CPU_CLUSTER_PM_ENTER_FAILED:
+       case CPU_CLUSTER_PM_EXIT:
+               if (bank->is_suspended)
+                       break;
+               omap_gpio_unidle(bank);
+               break;
        }
-       omap_gpio_unidle(bank);
-       bank->is_suspended = false;
-unlock:
        raw_spin_unlock_irqrestore(&bank->lock, flags);
 
-       return error;
+       return NOTIFY_OK;
 }
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-static const struct dev_pm_ops gpio_pm_ops = {
-       SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
-                                                                       NULL)
-};
-#else
-static const struct dev_pm_ops gpio_pm_ops;
-#endif /* CONFIG_ARCH_OMAP2PLUS */
-
-#if defined(CONFIG_OF)
 static struct omap_gpio_reg_offs omap2_gpio_regs = {
        .revision =             OMAP24XX_GPIO_REVISION,
        .direction =            OMAP24XX_GPIO_OE,
@@ -1729,11 +1470,6 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = {
        .fallingdetect =        OMAP4_GPIO_FALLINGDETECT,
 };
 
-/*
- * Note that omap2 does not currently support idle modes with context loss so
- * no need to add OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER quirk flag to save
- * and restore context.
- */
 static const struct omap_gpio_platform_data omap2_pdata = {
        .regs = &omap2_gpio_regs,
        .bank_width = 32,
@@ -1744,14 +1480,12 @@ static const struct omap_gpio_platform_data omap3_pdata = {
        .regs = &omap2_gpio_regs,
        .bank_width = 32,
        .dbck_flag = true,
-       .quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER,
 };
 
 static const struct omap_gpio_platform_data omap4_pdata = {
        .regs = &omap4_gpio_regs,
        .bank_width = 32,
        .dbck_flag = true,
-       .quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER,
 };
 
 static const struct of_device_id omap_gpio_match[] = {
@@ -1770,15 +1504,187 @@ static const struct of_device_id omap_gpio_match[] = {
        { },
 };
 MODULE_DEVICE_TABLE(of, omap_gpio_match);
+
+static int omap_gpio_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
+       const struct of_device_id *match;
+       const struct omap_gpio_platform_data *pdata;
+       struct gpio_bank *bank;
+       struct irq_chip *irqc;
+       int ret;
+
+       match = of_match_device(of_match_ptr(omap_gpio_match), dev);
+
+       pdata = match ? match->data : dev_get_platdata(dev);
+       if (!pdata)
+               return -EINVAL;
+
+       bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
+       if (!bank)
+               return -ENOMEM;
+
+       irqc = devm_kzalloc(dev, sizeof(*irqc), GFP_KERNEL);
+       if (!irqc)
+               return -ENOMEM;
+
+       irqc->irq_startup = omap_gpio_irq_startup,
+       irqc->irq_shutdown = omap_gpio_irq_shutdown,
+       irqc->irq_ack = omap_gpio_ack_irq,
+       irqc->irq_mask = omap_gpio_mask_irq,
+       irqc->irq_unmask = omap_gpio_unmask_irq,
+       irqc->irq_set_type = omap_gpio_irq_type,
+       irqc->irq_set_wake = omap_gpio_wake_enable,
+       irqc->irq_bus_lock = omap_gpio_irq_bus_lock,
+       irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
+       irqc->name = dev_name(&pdev->dev);
+       irqc->flags = IRQCHIP_MASK_ON_SUSPEND;
+       irqc->parent_device = dev;
+
+       bank->irq = platform_get_irq(pdev, 0);
+       if (bank->irq <= 0) {
+               if (!bank->irq)
+                       bank->irq = -ENXIO;
+               if (bank->irq != -EPROBE_DEFER)
+                       dev_err(dev,
+                               "can't get irq resource ret=%d\n", bank->irq);
+               return bank->irq;
+       }
+
+       bank->chip.parent = dev;
+       bank->chip.owner = THIS_MODULE;
+       bank->dbck_flag = pdata->dbck_flag;
+       bank->stride = pdata->bank_stride;
+       bank->width = pdata->bank_width;
+       bank->is_mpuio = pdata->is_mpuio;
+       bank->non_wakeup_gpios = pdata->non_wakeup_gpios;
+       bank->regs = pdata->regs;
+#ifdef CONFIG_OF_GPIO
+       bank->chip.of_node = of_node_get(node);
 #endif
 
+       if (node) {
+               if (!of_property_read_bool(node, "ti,gpio-always-on"))
+                       bank->loses_context = true;
+       } else {
+               bank->loses_context = pdata->loses_context;
+
+               if (bank->loses_context)
+                       bank->get_context_loss_count =
+                               pdata->get_context_loss_count;
+       }
+
+       if (bank->regs->set_dataout && bank->regs->clr_dataout) {
+               bank->set_dataout = omap_set_gpio_dataout_reg;
+               bank->set_dataout_multiple = omap_set_gpio_dataout_reg_multiple;
+       } else {
+               bank->set_dataout = omap_set_gpio_dataout_mask;
+               bank->set_dataout_multiple =
+                               omap_set_gpio_dataout_mask_multiple;
+       }
+
+       raw_spin_lock_init(&bank->lock);
+       raw_spin_lock_init(&bank->wa_lock);
+
+       /* Static mapping, never released */
+       bank->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(bank->base)) {
+               return PTR_ERR(bank->base);
+       }
+
+       if (bank->dbck_flag) {
+               bank->dbck = devm_clk_get(dev, "dbclk");
+               if (IS_ERR(bank->dbck)) {
+                       dev_err(dev,
+                               "Could not get gpio dbck. Disable debounce\n");
+                       bank->dbck_flag = false;
+               } else {
+                       clk_prepare(bank->dbck);
+               }
+       }
+
+       platform_set_drvdata(pdev, bank);
+
+       pm_runtime_enable(dev);
+       pm_runtime_get_sync(dev);
+
+       if (bank->is_mpuio)
+               omap_mpuio_init(bank);
+
+       omap_gpio_mod_init(bank);
+
+       ret = omap_gpio_chip_init(bank, irqc);
+       if (ret) {
+               pm_runtime_put_sync(dev);
+               pm_runtime_disable(dev);
+               if (bank->dbck_flag)
+                       clk_unprepare(bank->dbck);
+               return ret;
+       }
+
+       omap_gpio_show_rev(bank);
+
+       bank->nb.notifier_call = gpio_omap_cpu_notifier;
+       cpu_pm_register_notifier(&bank->nb);
+
+       pm_runtime_put(dev);
+
+       return 0;
+}
+
+static int omap_gpio_remove(struct platform_device *pdev)
+{
+       struct gpio_bank *bank = platform_get_drvdata(pdev);
+
+       cpu_pm_unregister_notifier(&bank->nb);
+       list_del(&bank->node);
+       gpiochip_remove(&bank->chip);
+       pm_runtime_disable(&pdev->dev);
+       if (bank->dbck_flag)
+               clk_unprepare(bank->dbck);
+
+       return 0;
+}
+
+static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev)
+{
+       struct gpio_bank *bank = dev_get_drvdata(dev);
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&bank->lock, flags);
+       omap_gpio_idle(bank, true);
+       bank->is_suspended = true;
+       raw_spin_unlock_irqrestore(&bank->lock, flags);
+
+       return 0;
+}
+
+static int __maybe_unused omap_gpio_runtime_resume(struct device *dev)
+{
+       struct gpio_bank *bank = dev_get_drvdata(dev);
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&bank->lock, flags);
+       omap_gpio_unidle(bank);
+       bank->is_suspended = false;
+       raw_spin_unlock_irqrestore(&bank->lock, flags);
+
+       return 0;
+}
+
+static const struct dev_pm_ops gpio_pm_ops = {
+       SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
+                                                                       NULL)
+};
+
 static struct platform_driver omap_gpio_driver = {
        .probe          = omap_gpio_probe,
        .remove         = omap_gpio_remove,
        .driver         = {
                .name   = "omap_gpio",
                .pm     = &gpio_pm_ops,
-               .of_match_table = of_match_ptr(omap_gpio_match),
+               .of_match_table = omap_gpio_match,
        },
 };
 
index 7e76830b33682aa364687ce23ab45aaaab1490cd..b7ef33f63392a29e0aca0329d5d6fb5abab05b52 100644 (file)
@@ -73,6 +73,7 @@
 #define PCA_CHIP_TYPE(x)       ((x) & PCA_TYPE_MASK)
 
 static const struct i2c_device_id pca953x_id[] = {
+       { "pca6416", 16 | PCA953X_TYPE | PCA_INT, },
        { "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
        { "pca9534", 8  | PCA953X_TYPE | PCA_INT, },
        { "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
@@ -153,6 +154,7 @@ struct pca953x_chip {
        u8 irq_trig_fall[MAX_BANK];
        struct irq_chip irq_chip;
 #endif
+       atomic_t wakeup_path;
 
        struct i2c_client *client;
        struct gpio_chip gpio_chip;
@@ -581,6 +583,11 @@ static int pca953x_irq_set_wake(struct irq_data *d, unsigned int on)
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct pca953x_chip *chip = gpiochip_get_data(gc);
 
+       if (on)
+               atomic_inc(&chip->wakeup_path);
+       else
+               atomic_dec(&chip->wakeup_path);
+
        return irq_set_irq_wake(chip->client->irq, on);
 }
 
@@ -1100,7 +1107,10 @@ static int pca953x_suspend(struct device *dev)
 
        regcache_cache_only(chip->regmap, true);
 
-       regulator_disable(chip->regulator);
+       if (atomic_read(&chip->wakeup_path))
+               device_set_wakeup_path(dev);
+       else
+               regulator_disable(chip->regulator);
 
        return 0;
 }
@@ -1110,10 +1120,12 @@ static int pca953x_resume(struct device *dev)
        struct pca953x_chip *chip = dev_get_drvdata(dev);
        int ret;
 
-       ret = regulator_enable(chip->regulator);
-       if (ret != 0) {
-               dev_err(dev, "Failed to enable regulator: %d\n", ret);
-               return 0;
+       if (!atomic_read(&chip->wakeup_path)) {
+               ret = regulator_enable(chip->regulator);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to enable regulator: %d\n", ret);
+                       return 0;
+               }
        }
 
        regcache_cache_only(chip->regmap, false);
@@ -1137,6 +1149,7 @@ static int pca953x_resume(struct device *dev)
 #define OF_957X(__nrgpio, __int) (void *)(__nrgpio | PCA957X_TYPE | __int)
 
 static const struct of_device_id pca953x_dt_ids[] = {
+       { .compatible = "nxp,pca6416", .data = OF_953X(16, PCA_INT), },
        { .compatible = "nxp,pca9505", .data = OF_953X(40, PCA_INT), },
        { .compatible = "nxp,pca9534", .data = OF_953X( 8, PCA_INT), },
        { .compatible = "nxp,pca9535", .data = OF_953X(16, PCA_INT), },
@@ -1152,6 +1165,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
        { .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
        { .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
 
+       { .compatible = "nxp,pcal6416", .data = OF_953X(16, PCA_LATCH_INT), },
        { .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), },
        { .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_LATCH_INT), },
 
@@ -1167,6 +1181,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
        { .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
        { .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
 
+       { .compatible = "onnn,cat9554", .data = OF_953X( 8, PCA_INT), },
        { .compatible = "onnn,pca9654", .data = OF_953X( 8, PCA_INT), },
 
        { .compatible = "exar,xra1202", .data = OF_953X( 8, 0), },
index bcc6be4a5cb2ed38c000c6e15a99e91692c81c2c..26f77fdb217e338a293fdebce941d0e0a48d2e11 100644 (file)
@@ -577,7 +577,7 @@ static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq,
        return 0;
 }
 
-const struct irq_domain_ops pxa_irq_domain_ops = {
+static const struct irq_domain_ops pxa_irq_domain_ops = {
        .map    = pxa_irq_domain_map,
        .xlate  = irq_domain_xlate_twocell,
 };
@@ -622,7 +622,6 @@ static int pxa_gpio_probe(struct platform_device *pdev)
 {
        struct pxa_gpio_chip *pchip;
        struct pxa_gpio_bank *c;
-       struct resource *res;
        struct clk *clk;
        struct pxa_gpio_platform_data *info;
        void __iomem *gpio_reg_base;
@@ -665,11 +664,8 @@ static int pxa_gpio_probe(struct platform_device *pdev)
 
        pchip->irq0 = irq0;
        pchip->irq1 = irq1;
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -EINVAL;
-       gpio_reg_base = devm_ioremap(&pdev->dev, res->start,
-                                    resource_size(res));
+
+       gpio_reg_base = devm_platform_ioremap_resource(pdev, 0);
        if (!gpio_reg_base)
                return -EINVAL;
 
@@ -816,7 +812,7 @@ static void pxa_gpio_resume(void)
 #define pxa_gpio_resume                NULL
 #endif
 
-struct syscore_ops pxa_gpio_syscore_ops = {
+static struct syscore_ops pxa_gpio_syscore_ops = {
        .suspend        = pxa_gpio_suspend,
        .resume         = pxa_gpio_resume,
 };
index 500a3596aaf449e4154591037a7d45120125330b..70e95fc4779fe26289c7b04b7cd25be16734a847 100644 (file)
@@ -430,7 +430,7 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
 static int gpio_rcar_probe(struct platform_device *pdev)
 {
        struct gpio_rcar_priv *p;
-       struct resource *io, *irq;
+       struct resource *irq;
        struct gpio_chip *gpio_chip;
        struct irq_chip *irq_chip;
        struct device *dev = &pdev->dev;
@@ -461,8 +461,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
                goto err0;
        }
 
-       io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       p->base = devm_ioremap_resource(dev, io);
+       p->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(p->base)) {
                ret = PTR_ERR(p->base);
                goto err0;
index c333046d02b8bc28fd7fd83171a2fb2241891acb..fb143f28c386344c78ae00143eeee9b786322a4b 100644 (file)
@@ -23,7 +23,6 @@ struct sch_gpio {
        struct gpio_chip chip;
        spinlock_t lock;
        unsigned short iobase;
-       unsigned short core_base;
        unsigned short resume_base;
 };
 
@@ -166,7 +165,6 @@ static int sch_gpio_probe(struct platform_device *pdev)
 
        switch (pdev->id) {
        case PCI_DEVICE_ID_INTEL_SCH_LPC:
-               sch->core_base = 0;
                sch->resume_base = 10;
                sch->chip.ngpio = 14;
 
@@ -185,19 +183,16 @@ static int sch_gpio_probe(struct platform_device *pdev)
                break;
 
        case PCI_DEVICE_ID_INTEL_ITC_LPC:
-               sch->core_base = 0;
                sch->resume_base = 5;
                sch->chip.ngpio = 14;
                break;
 
        case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
-               sch->core_base = 0;
                sch->resume_base = 21;
                sch->chip.ngpio = 30;
                break;
 
        case PCI_DEVICE_ID_INTEL_QUARK_X1000_ILB:
-               sch->core_base = 0;
                sch->resume_base = 2;
                sch->chip.ngpio = 8;
                break;
index ee3039f091f4a0f9eda947dbb0d8a8a7f301a835..6eca531b7d9600bd8a4d34c08047325244dffe2d 100644 (file)
@@ -122,15 +122,13 @@ static int spics_gpio_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct spear_spics *spics;
-       struct resource *res;
        int ret;
 
        spics = devm_kzalloc(&pdev->dev, sizeof(*spics), GFP_KERNEL);
        if (!spics)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       spics->base = devm_ioremap_resource(&pdev->dev, res);
+       spics->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(spics->base))
                return PTR_ERR(spics->base);
 
index 55072d2b367fad89ffb099dc20abfa32381f5804..f5c8b3a351d593cc7347cc516f8196bc3c68ac1d 100644 (file)
@@ -219,7 +219,6 @@ static int sprd_gpio_probe(struct platform_device *pdev)
 {
        struct gpio_irq_chip *irq;
        struct sprd_gpio *sprd_gpio;
-       struct resource *res;
        int ret;
 
        sprd_gpio = devm_kzalloc(&pdev->dev, sizeof(*sprd_gpio), GFP_KERNEL);
@@ -232,8 +231,7 @@ static int sprd_gpio_probe(struct platform_device *pdev)
                return sprd_gpio->irq;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       sprd_gpio->base = devm_ioremap_resource(&pdev->dev, res);
+       sprd_gpio->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(sprd_gpio->base))
                return PTR_ERR(sprd_gpio->base);
 
index 2283c869ad5db68adbdbf77a125608f8eeb5b948..a51c310708b82847e4dabc14bf876a65f6c61dc3 100644 (file)
@@ -360,7 +360,6 @@ static int gsta_probe(struct platform_device *dev)
        struct pci_dev *pdev;
        struct sta2x11_gpio_pdata *gpio_pdata;
        struct gsta_gpio *chip;
-       struct resource *res;
 
        pdev = *(struct pci_dev **)dev_get_platdata(&dev->dev);
        gpio_pdata = dev_get_platdata(&pdev->dev);
@@ -369,13 +368,11 @@ static int gsta_probe(struct platform_device *dev)
                dev_err(&dev->dev, "no gpio config\n");
        pr_debug("gpio config: %p\n", gpio_pdata);
 
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-
        chip = devm_kzalloc(&dev->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
        chip->dev = &dev->dev;
-       chip->reg_base = devm_ioremap_resource(&dev->dev, res);
+       chip->reg_base = devm_platform_ioremap_resource(dev, 0);
        if (IS_ERR(chip->reg_base))
                return PTR_ERR(chip->reg_base);
 
index 19972084c45bb11b4ec0167ef36071d00f8123b4..8a319d56c5de731a756936ebe5ba88ca72fa52d6 100644 (file)
@@ -210,7 +210,6 @@ static int xway_stp_hw_init(struct xway_stp *chip)
 
 static int xway_stp_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        u32 shadow, groups, dsl, phy;
        struct xway_stp *chip;
        struct clk *clk;
@@ -220,8 +219,7 @@ static int xway_stp_probe(struct platform_device *pdev)
        if (!chip)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       chip->virt = devm_ioremap_resource(&pdev->dev, res);
+       chip->virt = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(chip->virt))
                return PTR_ERR(chip->virt);
 
index d5e5d19f4c0ad3a051802d3f2c832812b0834eaf..6bbac6c83f29322c7d09d2d8863e26f3b6275c65 100644 (file)
@@ -120,7 +120,6 @@ static irqreturn_t tb10x_gpio_irq_cascade(int irq, void *data)
 static int tb10x_gpio_probe(struct platform_device *pdev)
 {
        struct tb10x_gpio *tb10x_gpio;
-       struct resource *mem;
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
        int ret = -EBUSY;
@@ -136,8 +135,7 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
        if (tb10x_gpio == NULL)
                return -ENOMEM;
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       tb10x_gpio->base = devm_ioremap_resource(dev, mem);
+       tb10x_gpio->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(tb10x_gpio->base))
                return PTR_ERR(tb10x_gpio->base);
 
index 1ececf2c328296385d70e98d0312458a6e280880..6d9b6906b9d01b6570866e8ee4ab12da3efbc115 100644 (file)
@@ -569,7 +569,6 @@ static const struct dev_pm_ops tegra_gpio_pm_ops = {
 static int tegra_gpio_probe(struct platform_device *pdev)
 {
        struct tegra_gpio_info *tgi;
-       struct resource *res;
        struct tegra_gpio_bank *bank;
        unsigned int gpio, i, j;
        int ret;
@@ -645,8 +644,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
                bank->tgi = tgi;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       tgi->regs = devm_ioremap_resource(&pdev->dev, res);
+       tgi->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(tgi->regs))
                return PTR_ERR(tgi->regs);
 
index 314e300d6ba33ac0724eb41510caa08a697aff1d..1c70e831069cc92f1efd2ed333926b4aec973973 100644 (file)
@@ -229,7 +229,6 @@ static int timbgpio_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct gpio_chip *gc;
        struct timbgpio *tgpio;
-       struct resource *iomem;
        struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
        int irq = platform_get_irq(pdev, 0);
 
@@ -246,8 +245,7 @@ static int timbgpio_probe(struct platform_device *pdev)
 
        spin_lock_init(&tgpio->lock);
 
-       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       tgpio->membase = devm_ioremap_resource(dev, iomem);
+       tgpio->membase = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(tgpio->membase))
                return PTR_ERR(tgpio->membase);
 
index c2a80b4cbf32c2ce3b83eedf82339a8ad0177b16..8c0d82d926ddf627a4a18aa61377d9310999ba18 100644 (file)
@@ -23,7 +23,6 @@ static int ts4800_gpio_probe(struct platform_device *pdev)
 {
        struct device_node *node;
        struct gpio_chip *chip;
-       struct resource *res;
        void __iomem *base_addr;
        int retval;
        u32 ngpios;
@@ -32,8 +31,7 @@ static int ts4800_gpio_probe(struct platform_device *pdev)
        if (!chip)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base_addr = devm_ioremap_resource(&pdev->dev, res);
+       base_addr = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base_addr))
                return PTR_ERR(base_addr);
 
index 0f662b297a95c9d9833f6e8d00c7fa39f546daa2..93cdcc41e9fbc1949e7dbe4271cfd437b637aa0c 100644 (file)
@@ -346,7 +346,6 @@ static int uniphier_gpio_probe(struct platform_device *pdev)
        struct uniphier_gpio_priv *priv;
        struct gpio_chip *chip;
        struct irq_chip *irq_chip;
-       struct resource *regs;
        unsigned int nregs;
        u32 ngpios;
        int ret;
@@ -370,8 +369,7 @@ static int uniphier_gpio_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->regs = devm_ioremap_resource(dev, regs);
+       priv->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->regs))
                return PTR_ERR(priv->regs);
 
index 541fa6ac399d24b288d7f148717874d2392e9023..30aef41e3b7e64ce51629552b8244ea07680c500 100644 (file)
@@ -29,6 +29,7 @@ struct fsl_gpio_soc_data {
 
 struct vf610_gpio_port {
        struct gpio_chip gc;
+       struct irq_chip ic;
        void __iomem *base;
        void __iomem *gpio_base;
        const struct fsl_gpio_soc_data *sdata;
@@ -60,8 +61,6 @@ struct vf610_gpio_port {
 #define PORT_INT_EITHER_EDGE   0xb
 #define PORT_INT_LOGIC_ONE     0xc
 
-static struct irq_chip vf610_gpio_irq_chip;
-
 static const struct fsl_gpio_soc_data imx_data = {
        .have_paddr = true,
 };
@@ -86,28 +85,24 @@ static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio)
 {
        struct vf610_gpio_port *port = gpiochip_get_data(gc);
        unsigned long mask = BIT(gpio);
-       void __iomem *addr;
+       unsigned long offset = GPIO_PDIR;
 
        if (port->sdata && port->sdata->have_paddr) {
                mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
-               addr = mask ? port->gpio_base + GPIO_PDOR :
-                             port->gpio_base + GPIO_PDIR;
-               return !!(vf610_gpio_readl(addr) & BIT(gpio));
-       } else {
-               return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR)
-                                          & BIT(gpio));
+               if (mask)
+                       offset = GPIO_PDOR;
        }
+
+       return !!(vf610_gpio_readl(port->gpio_base + offset) & BIT(gpio));
 }
 
 static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
 {
        struct vf610_gpio_port *port = gpiochip_get_data(gc);
        unsigned long mask = BIT(gpio);
+       unsigned long offset = val ? GPIO_PSOR : GPIO_PCOR;
 
-       if (val)
-               vf610_gpio_writel(mask, port->gpio_base + GPIO_PSOR);
-       else
-               vf610_gpio_writel(mask, port->gpio_base + GPIO_PCOR);
+       vf610_gpio_writel(mask, port->gpio_base + offset);
 }
 
 static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
@@ -237,37 +232,31 @@ static int vf610_gpio_irq_set_wake(struct irq_data *d, u32 enable)
        return 0;
 }
 
-static struct irq_chip vf610_gpio_irq_chip = {
-       .name           = "gpio-vf610",
-       .irq_ack        = vf610_gpio_irq_ack,
-       .irq_mask       = vf610_gpio_irq_mask,
-       .irq_unmask     = vf610_gpio_irq_unmask,
-       .irq_set_type   = vf610_gpio_irq_set_type,
-       .irq_set_wake   = vf610_gpio_irq_set_wake,
-};
+static void vf610_gpio_disable_clk(void *data)
+{
+       clk_disable_unprepare(data);
+}
 
 static int vf610_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
        struct vf610_gpio_port *port;
-       struct resource *iores;
        struct gpio_chip *gc;
+       struct irq_chip *ic;
        int i;
        int ret;
 
-       port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
+       port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
        if (!port)
                return -ENOMEM;
 
        port->sdata = of_device_get_match_data(dev);
-       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       port->base = devm_ioremap_resource(dev, iores);
+       port->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(port->base))
                return PTR_ERR(port->base);
 
-       iores = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       port->gpio_base = devm_ioremap_resource(dev, iores);
+       port->gpio_base = devm_platform_ioremap_resource(pdev, 1);
        if (IS_ERR(port->gpio_base))
                return PTR_ERR(port->gpio_base);
 
@@ -275,11 +264,15 @@ static int vf610_gpio_probe(struct platform_device *pdev)
        if (port->irq < 0)
                return port->irq;
 
-       port->clk_port = devm_clk_get(&pdev->dev, "port");
+       port->clk_port = devm_clk_get(dev, "port");
        if (!IS_ERR(port->clk_port)) {
                ret = clk_prepare_enable(port->clk_port);
                if (ret)
                        return ret;
+               ret = devm_add_action_or_reset(dev, vf610_gpio_disable_clk,
+                                              port->clk_port);
+               if (ret)
+                       return ret;
        } else if (port->clk_port == ERR_PTR(-EPROBE_DEFER)) {
                /*
                 * Percolate deferrals, for anything else,
@@ -288,20 +281,19 @@ static int vf610_gpio_probe(struct platform_device *pdev)
                return PTR_ERR(port->clk_port);
        }
 
-       port->clk_gpio = devm_clk_get(&pdev->dev, "gpio");
+       port->clk_gpio = devm_clk_get(dev, "gpio");
        if (!IS_ERR(port->clk_gpio)) {
                ret = clk_prepare_enable(port->clk_gpio);
-               if (ret) {
-                       clk_disable_unprepare(port->clk_port);
+               if (ret)
+                       return ret;
+               ret = devm_add_action_or_reset(dev, vf610_gpio_disable_clk,
+                                              port->clk_gpio);
+               if (ret)
                        return ret;
-               }
        } else if (port->clk_gpio == ERR_PTR(-EPROBE_DEFER)) {
-               clk_disable_unprepare(port->clk_port);
                return PTR_ERR(port->clk_gpio);
        }
 
-       platform_set_drvdata(pdev, port);
-
        gc = &port->gc;
        gc->of_node = np;
        gc->parent = dev;
@@ -316,7 +308,15 @@ static int vf610_gpio_probe(struct platform_device *pdev)
        gc->direction_output = vf610_gpio_direction_output;
        gc->set = vf610_gpio_set;
 
-       ret = gpiochip_add_data(gc, port);
+       ic = &port->ic;
+       ic->name = "gpio-vf610";
+       ic->irq_ack = vf610_gpio_irq_ack;
+       ic->irq_mask = vf610_gpio_irq_mask;
+       ic->irq_unmask = vf610_gpio_irq_unmask;
+       ic->irq_set_type = vf610_gpio_irq_set_type;
+       ic->irq_set_wake = vf610_gpio_irq_set_wake;
+
+       ret = devm_gpiochip_add_data(dev, gc, port);
        if (ret < 0)
                return ret;
 
@@ -327,39 +327,23 @@ static int vf610_gpio_probe(struct platform_device *pdev)
        /* Clear the interrupt status register for all GPIO's */
        vf610_gpio_writel(~0, port->base + PORT_ISFR);
 
-       ret = gpiochip_irqchip_add(gc, &vf610_gpio_irq_chip, 0,
-                                  handle_edge_irq, IRQ_TYPE_NONE);
+       ret = gpiochip_irqchip_add(gc, ic, 0, handle_edge_irq, IRQ_TYPE_NONE);
        if (ret) {
                dev_err(dev, "failed to add irqchip\n");
-               gpiochip_remove(gc);
                return ret;
        }
-       gpiochip_set_chained_irqchip(gc, &vf610_gpio_irq_chip, port->irq,
+       gpiochip_set_chained_irqchip(gc, ic, port->irq,
                                     vf610_gpio_irq_handler);
 
        return 0;
 }
 
-static int vf610_gpio_remove(struct platform_device *pdev)
-{
-       struct vf610_gpio_port *port = platform_get_drvdata(pdev);
-
-       gpiochip_remove(&port->gc);
-       if (!IS_ERR(port->clk_port))
-               clk_disable_unprepare(port->clk_port);
-       if (!IS_ERR(port->clk_gpio))
-               clk_disable_unprepare(port->clk_gpio);
-
-       return 0;
-}
-
 static struct platform_driver vf610_gpio_driver = {
        .driver         = {
                .name   = "gpio-vf610",
                .of_match_table = vf610_gpio_dt_ids,
        },
        .probe          = vf610_gpio_probe,
-       .remove         = vf610_gpio_remove,
 };
 
 builtin_platform_driver(vf610_gpio_driver);
index 2eb76f35aa7edebc8e9da79f0e096b3e96ebfc4c..641a051810171164fb7f0d2046ccbe639de4c0c1 100644 (file)
@@ -229,7 +229,6 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
 {
        struct xgene_gpio_sb *priv;
        int ret;
-       struct resource *res;
        void __iomem *regs;
        struct irq_domain *parent_domain = NULL;
        u32 val32;
@@ -238,8 +237,7 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       regs = devm_ioremap_resource(&pdev->dev, res);
+       regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(regs))
                return PTR_ERR(regs);
 
index 0a3607fd21af76c2a97cbd367a7f71b3f7a46c0f..54d3359444f356659576d34053cfa25b6f3cad24 100644 (file)
@@ -290,22 +290,17 @@ MODULE_DEVICE_TABLE(of, xlp_gpio_of_ids);
 static int xlp_gpio_probe(struct platform_device *pdev)
 {
        struct gpio_chip *gc;
-       struct resource *iores;
        struct xlp_gpio_priv *priv;
        void __iomem *gpio_base;
        int irq_base, irq, err;
        int ngpio;
        u32 soc_type;
 
-       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iores)
-               return -ENODEV;
-
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       gpio_base = devm_ioremap_resource(&pdev->dev, iores);
+       gpio_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(gpio_base))
                return PTR_ERR(gpio_base);
 
index 5eacad9b2692111dc2e97b5a68a5f3ac8f86d68a..fb927559aefa8b8e641ea2af14d7f709f708ee99 100644 (file)
@@ -218,15 +218,13 @@ static int zx_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct zx_gpio *chip;
-       struct resource *res;
        int irq, id, ret;
 
        chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       chip->base = devm_ioremap_resource(dev, res);
+       chip->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(chip->base))
                return PTR_ERR(chip->base);
 
index 00ff7b1fa8a11afaa1507ac215c7ca2388b49e1a..9392edaeec3f5b63fcdde298104a7df92de43f6d 100644 (file)
@@ -834,7 +834,6 @@ static int zynq_gpio_probe(struct platform_device *pdev)
        int ret, bank_num;
        struct zynq_gpio *gpio;
        struct gpio_chip *chip;
-       struct resource *res;
        const struct of_device_id *match;
 
        gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
@@ -849,8 +848,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
        gpio->p_data = match->data;
        platform_set_drvdata(pdev, gpio);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       gpio->base_addr = devm_ioremap_resource(&pdev->dev, res);
+       gpio->base_addr = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(gpio->base_addr))
                return PTR_ERR(gpio->base_addr);
 
index 30d0baf7ddaed0e07d6fa94d5ceee8c06ada68df..c9fc9e232aafb37d67c7b72b83183b778963d41a 100644 (file)
  *
  * @node:        list-entry of the events list of the struct acpi_gpio_chip
  * @handle:      handle of ACPI method to execute when the IRQ triggers
- * @handler:     irq_handler to pass to request_irq when requesting the IRQ
- * @pin:         GPIO pin number on the gpio_chip
- * @irq:         Linux IRQ number for the event, for request_ / free_irq
- * @irqflags:     flags to pass to request_irq when requesting the IRQ
+ * @handler:     handler function to pass to request_irq() when requesting the IRQ
+ * @pin:         GPIO pin number on the struct gpio_chip
+ * @irq:         Linux IRQ number for the event, for request_irq() / free_irq()
+ * @irqflags:    flags to pass to request_irq() when requesting the IRQ
  * @irq_is_wake:  If the ACPI flags indicate the IRQ is a wakeup source
- * @irq_requested:True if request_irq has been done
- * @desc:        gpio_desc for the GPIO pin for this event
+ * @irq_requested:True if request_irq() has been done
+ * @desc:        struct gpio_desc for the GPIO pin for this event
  */
 struct acpi_gpio_event {
        struct list_head node;
@@ -65,10 +65,10 @@ struct acpi_gpio_chip {
 };
 
 /*
- * For gpiochips which call acpi_gpiochip_request_interrupts() before late_init
+ * For GPIO chips which call acpi_gpiochip_request_interrupts() before late_init
  * (so builtin drivers) we register the ACPI GpioInt IRQ handlers from a
- * late_initcall_sync handler, so that other builtin drivers can register their
- * OpRegions before the event handlers can run.  This list contains gpiochips
+ * late_initcall_sync() handler, so that other builtin drivers can register their
+ * OpRegions before the event handlers can run. This list contains GPIO chips
  * for which the acpi_gpiochip_request_irqs() call has been deferred.
  */
 static DEFINE_MUTEX(acpi_gpio_deferred_req_irqs_lock);
@@ -90,7 +90,7 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
  *
  * Return: GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR
  * error value. Specifically returns %-EPROBE_DEFER if the referenced GPIO
- * controller does not have gpiochip registered at the moment. This is to
+ * controller does not have GPIO chip registered at the moment. This is to
  * support probe deferral.
  */
 static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
@@ -287,9 +287,9 @@ fail_free_desc:
  *
  * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
  * handled by ACPI event methods which need to be called from the GPIO
- * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which
- * gpio pins have acpi event methods and assigns interrupt handlers that calls
- * the acpi event methods for those pins.
+ * chip's interrupt handler. acpi_gpiochip_request_interrupts() finds out which
+ * GPIO pins have ACPI event methods and assigns interrupt handlers that calls
+ * the ACPI event methods for those pins.
  */
 void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
 {
@@ -444,8 +444,6 @@ static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
 static enum gpiod_flags
 acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio)
 {
-       bool pull_up = agpio->pin_config == ACPI_PIN_CONFIG_PULLUP;
-
        switch (agpio->io_restriction) {
        case ACPI_IO_RESTRICT_INPUT:
                return GPIOD_IN;
@@ -454,16 +452,26 @@ acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio)
                 * ACPI GPIO resources don't contain an initial value for the
                 * GPIO. Therefore we deduce that value from the pull field
                 * instead. If the pin is pulled up we assume default to be
-                * high, otherwise low.
+                * high, if it is pulled down we assume default to be low,
+                * otherwise we leave pin untouched.
                 */
-               return pull_up ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
+               switch (agpio->pin_config) {
+               case ACPI_PIN_CONFIG_PULLUP:
+                       return GPIOD_OUT_HIGH;
+               case ACPI_PIN_CONFIG_PULLDOWN:
+                       return GPIOD_OUT_LOW;
+               default:
+                       break;
+               }
        default:
-               /*
-                * Assume that the BIOS has configured the direction and pull
-                * accordingly.
-                */
-               return GPIOD_ASIS;
+               break;
        }
+
+       /*
+        * Assume that the BIOS has configured the direction and pull
+        * accordingly.
+        */
+       return GPIOD_ASIS;
 }
 
 static int
@@ -517,6 +525,26 @@ acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *inf
        return ret;
 }
 
+int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
+                                       struct acpi_gpio_info *info)
+{
+       switch (info->pin_config) {
+       case ACPI_PIN_CONFIG_PULLUP:
+               *lookupflags |= GPIO_PULL_UP;
+               break;
+       case ACPI_PIN_CONFIG_PULLDOWN:
+               *lookupflags |= GPIO_PULL_DOWN;
+               break;
+       default:
+               break;
+       }
+
+       if (info->polarity == GPIO_ACTIVE_LOW)
+               *lookupflags |= GPIO_ACTIVE_LOW;
+
+       return 0;
+}
+
 struct acpi_gpio_lookup {
        struct acpi_gpio_info info;
        int index;
@@ -550,6 +578,7 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
 
                lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
                                              agpio->pin_table[pin_index]);
+               lookup->info.pin_config = agpio->pin_config;
                lookup->info.gpioint = gpioint;
 
                /*
@@ -653,7 +682,7 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
  * that case @index is used to select the GPIO entry in the property value
  * (in case of multiple).
  *
- * If the GPIO cannot be translated or there is an error an ERR_PTR is
+ * If the GPIO cannot be translated or there is an error, an ERR_PTR is
  * returned.
  *
  * Note: if the GPIO resource has multiple entries in the pin list, this
@@ -696,7 +725,7 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
                                 const char *con_id,
                                 unsigned int idx,
                                 enum gpiod_flags *dflags,
-                                enum gpio_lookup_flags *lookupflags)
+                                unsigned long *lookupflags)
 {
        struct acpi_device *adev = ACPI_COMPANION(dev);
        struct acpi_gpio_info info;
@@ -737,10 +766,8 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
                return ERR_PTR(-ENOENT);
        }
 
-       if (info.polarity == GPIO_ACTIVE_LOW)
-               *lookupflags |= GPIO_ACTIVE_LOW;
-
        acpi_gpio_update_gpiod_flags(dflags, &info);
+       acpi_gpio_update_gpiod_lookup_flags(lookupflags, &info);
        return desc;
 }
 
@@ -751,10 +778,13 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
  * @index: index of GpioIo/GpioInt resource (starting from %0)
  * @info: info pointer to fill in (optional)
  *
- * If @fwnode is an ACPI device object, call %acpi_get_gpiod_by_index() for it.
- * Otherwise (ie. it is a data-only non-device object), use the property-based
+ * If @fwnode is an ACPI device object, call acpi_get_gpiod_by_index() for it.
+ * Otherwise (i.e. it is a data-only non-device object), use the property-based
  * GPIO lookup to get to the GPIO resource with the relevant information and use
  * that to obtain the GPIO descriptor to return.
+ *
+ * If the GPIO cannot be translated or there is an error an ERR_PTR is
+ * returned.
  */
 struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
                                      const char *propname, int index,
@@ -816,6 +846,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
                        return PTR_ERR(desc);
 
                if (info.gpioint && idx++ == index) {
+                       unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
                        char label[32];
                        int irq;
 
@@ -827,7 +858,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
                                return irq;
 
                        snprintf(label, sizeof(label), "GpioInt() %d", index);
-                       ret = gpiod_configure_flags(desc, label, 0, info.flags);
+                       ret = gpiod_configure_flags(desc, label, lflags, info.flags);
                        if (ret < 0)
                                return ret;
 
@@ -992,16 +1023,19 @@ static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
        }
 }
 
-static struct gpio_desc *acpi_gpiochip_parse_own_gpio(
-       struct acpi_gpio_chip *achip, struct fwnode_handle *fwnode,
-       const char **name, unsigned int *lflags, unsigned int *dflags)
+static struct gpio_desc *
+acpi_gpiochip_parse_own_gpio(struct acpi_gpio_chip *achip,
+                            struct fwnode_handle *fwnode,
+                            const char **name,
+                            unsigned long *lflags,
+                            enum gpiod_flags *dflags)
 {
        struct gpio_chip *chip = achip->chip;
        struct gpio_desc *desc;
        u32 gpios[2];
        int ret;
 
-       *lflags = 0;
+       *lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
        *dflags = 0;
        *name = NULL;
 
@@ -1037,7 +1071,8 @@ static void acpi_gpiochip_scan_gpios(struct acpi_gpio_chip *achip)
        struct fwnode_handle *fwnode;
 
        device_for_each_child_node(chip->parent, fwnode) {
-               unsigned int lflags, dflags;
+               unsigned long lflags;
+               enum gpiod_flags dflags;
                struct gpio_desc *desc;
                const char *name;
                int ret;
@@ -1158,11 +1193,13 @@ static int acpi_find_gpio_count(struct acpi_resource *ares, void *data)
 }
 
 /**
- * acpi_gpio_count - return the number of GPIOs associated with a
- *             device / function or -ENOENT if no GPIO has been
- *             assigned to the requested function.
- * @dev:       GPIO consumer, can be NULL for system-global GPIOs
+ * acpi_gpio_count - count the GPIOs associated with a device / function
+ * @dev:       GPIO consumer, can be %NULL for system-global GPIOs
  * @con_id:    function within the GPIO consumer
+ *
+ * Return:
+ * The number of GPIOs associated with a device / function or %-ENOENT,
+ * if no GPIO has been assigned to the requested function.
  */
 int acpi_gpio_count(struct device *dev, const char *con_id)
 {
index 6a3ec575a404ed9fa3dfcf8c78e56381789a8c02..aec7bd86ae7eaab69d4849f2c862301b7d3d7eb8 100644 (file)
@@ -86,9 +86,9 @@ static void of_gpio_flags_quirks(struct device_node *np,
        if (IS_ENABLED(CONFIG_REGULATOR) &&
            (of_device_is_compatible(np, "regulator-fixed") ||
             of_device_is_compatible(np, "reg-fixed-voltage") ||
-            (of_device_is_compatible(np, "regulator-gpio") &&
-             !(strcmp(propname, "enable-gpio") &&
-               strcmp(propname, "enable-gpios"))))) {
+            (!(strcmp(propname, "enable-gpio") &&
+               strcmp(propname, "enable-gpios")) &&
+             of_device_is_compatible(np, "regulator-gpio")))) {
                /*
                 * The regulator GPIO handles are specified such that the
                 * presence or absence of "enable-active-high" solely controls
@@ -119,9 +119,8 @@ static void of_gpio_flags_quirks(struct device_node *np,
         * property named "cs-gpios" we need to inspect the child node
         * to determine if the flags should have inverted semantics.
         */
-       if (IS_ENABLED(CONFIG_SPI_MASTER) &&
-           of_property_read_bool(np, "cs-gpios") &&
-           !strcmp(propname, "cs-gpios")) {
+       if (IS_ENABLED(CONFIG_SPI_MASTER) && !strcmp(propname, "cs-gpios") &&
+           of_property_read_bool(np, "cs-gpios")) {
                struct device_node *child;
                u32 cs;
                int ret;
@@ -288,8 +287,7 @@ static struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char *
 }
 
 struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
-                              unsigned int idx,
-                              enum gpio_lookup_flags *flags)
+                              unsigned int idx, unsigned long *flags)
 {
        char prop_name[32]; /* 32 is max size of property name */
        enum of_gpio_flags of_flags;
@@ -362,8 +360,8 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
  * @chip:      GPIO chip whose hog is parsed
  * @idx:       Index of the GPIO to parse
  * @name:      GPIO line name
- * @lflags:    gpio_lookup_flags - returned from of_find_gpio() or
- *             of_parse_own_gpio()
+ * @lflags:    bitmask of gpio_lookup_flags GPIO_* values - returned from
+ *             of_find_gpio() or of_parse_own_gpio()
  * @dflags:    gpiod_flags - optional GPIO initialization flags
  *
  * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno
@@ -372,7 +370,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
 static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
                                           struct gpio_chip *chip,
                                           unsigned int idx, const char **name,
-                                          enum gpio_lookup_flags *lflags,
+                                          unsigned long *lflags,
                                           enum gpiod_flags *dflags)
 {
        struct device_node *chip_np;
@@ -388,7 +386,7 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
                return ERR_PTR(-EINVAL);
 
        xlate_flags = 0;
-       *lflags = 0;
+       *lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
        *dflags = 0;
 
        ret = of_property_read_u32(chip_np, "#gpio-cells", &tmp);
@@ -445,7 +443,7 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
        struct gpio_desc *desc = NULL;
        struct device_node *np;
        const char *name;
-       enum gpio_lookup_flags lflags;
+       unsigned long lflags;
        enum gpiod_flags dflags;
        unsigned int i;
        int ret;
index bca3e7740ef66c8fac2b8f89866935e3655fc9c3..e013d417a9361c5d19f340bf7a69ce2627781519 100644 (file)
@@ -2519,6 +2519,7 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
                                            const char *label,
                                            enum gpiod_flags flags)
 {
+       unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
        struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum);
        int err;
 
@@ -2531,7 +2532,7 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
        if (err < 0)
                return ERR_PTR(err);
 
-       err = gpiod_configure_flags(desc, label, 0, flags);
+       err = gpiod_configure_flags(desc, label, lflags, flags);
        if (err) {
                chip_err(chip, "setup of own GPIO %s failed\n", label);
                gpiod_free_commit(desc);
@@ -2569,8 +2570,20 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc);
 static int gpio_set_config(struct gpio_chip *gc, unsigned offset,
                           enum pin_config_param mode)
 {
-       unsigned long config = { PIN_CONF_PACKED(mode, 0) };
+       unsigned long config;
+       unsigned arg;
 
+       switch (mode) {
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+       case PIN_CONFIG_BIAS_PULL_UP:
+               arg = 1;
+               break;
+
+       default:
+               arg = 0;
+       }
+
+       config = PIN_CONF_PACKED(mode, arg);
        return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP;
 }
 
@@ -3915,8 +3928,7 @@ found:
 }
 
 static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
-                                   unsigned int idx,
-                                   enum gpio_lookup_flags *flags)
+                                   unsigned int idx, unsigned long *flags)
 {
        struct gpio_desc *desc = ERR_PTR(-ENOENT);
        struct gpiod_lookup_table *table;
@@ -4072,8 +4084,8 @@ EXPORT_SYMBOL_GPL(gpiod_get_optional);
  * gpiod_configure_flags - helper function to configure a given GPIO
  * @desc:      gpio whose value will be assigned
  * @con_id:    function within the GPIO consumer
- * @lflags:    gpio_lookup_flags - returned from of_find_gpio() or
- *             of_get_gpio_hog()
+ * @lflags:    bitmask of gpio_lookup_flags GPIO_* values - returned from
+ *             of_find_gpio() or of_get_gpio_hog()
  * @dflags:    gpiod_flags - optional GPIO initialization flags
  *
  * Return 0 on success, -ENOENT if no GPIO has been assigned to the
@@ -4155,9 +4167,9 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
                                               unsigned int idx,
                                               enum gpiod_flags flags)
 {
+       unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT;
        struct gpio_desc *desc = NULL;
        int status;
-       enum gpio_lookup_flags lookupflags = 0;
        /* Maybe we have a device name, maybe not */
        const char *devname = dev ? dev_name(dev) : "?";
 
@@ -4242,8 +4254,8 @@ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
                                         enum gpiod_flags dflags,
                                         const char *label)
 {
+       unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
        struct gpio_desc *desc;
-       unsigned long lflags = 0;
        enum of_gpio_flags flags;
        bool active_low = false;
        bool single_ended = false;
@@ -4321,8 +4333,8 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
                                         enum gpiod_flags dflags,
                                         const char *label)
 {
+       unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
        struct gpio_desc *desc = ERR_PTR(-ENODEV);
-       unsigned long lflags = 0;
        int ret;
 
        if (!fwnode)
@@ -4342,9 +4354,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
                        return desc;
 
                acpi_gpio_update_gpiod_flags(&dflags, &info);
-
-               if (info.polarity == GPIO_ACTIVE_LOW)
-                       lflags |= GPIO_ACTIVE_LOW;
+               acpi_gpio_update_gpiod_lookup_flags(&lflags, &info);
        }
 
        /* Currently only ACPI takes this path */
@@ -4395,8 +4405,8 @@ EXPORT_SYMBOL_GPL(gpiod_get_index_optional);
  * gpiod_hog - Hog the specified GPIO desc given the provided flags
  * @desc:      gpio whose value will be assigned
  * @name:      gpio line name
- * @lflags:    gpio_lookup_flags - returned from of_find_gpio() or
- *             of_get_gpio_hog()
+ * @lflags:    bitmask of gpio_lookup_flags GPIO_* values - returned from
+ *             of_find_gpio() or of_get_gpio_hog()
  * @dflags:    gpiod_flags - optional GPIO initialization flags
  */
 int gpiod_hog(struct gpio_desc *desc, const char *name,
@@ -4449,8 +4459,6 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
 /**
  * gpiochip_free_hogs - Scan gpio-controller chip and release GPIO hog
  * @chip:      gpio chip to act on
- *
- * This is only used by of_gpiochip_remove to free hogged gpios
  */
 static void gpiochip_free_hogs(struct gpio_chip *chip)
 {
@@ -4620,7 +4628,8 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_optional);
  */
 void gpiod_put(struct gpio_desc *desc)
 {
-       gpiod_free(desc);
+       if (desc)
+               gpiod_free(desc);
 }
 EXPORT_SYMBOL_GPL(gpiod_put);
 
index 3243c1eb5c88b557e4a1551dbd974e6cf917189c..7a65dad43932c62e3741b4576188630c32374f9b 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/cdev.h>
 
 enum of_gpio_flags;
-enum gpio_lookup_flags;
 struct acpi_device;
 
 /**
@@ -75,6 +74,7 @@ struct gpio_device {
  * @adev: reference to ACPI device which consumes GPIO resource
  * @flags: GPIO initialization flags
  * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
+ * @pin_config: pin bias as provided by ACPI
  * @polarity: interrupt polarity as provided by ACPI
  * @triggering: triggering type as provided by ACPI
  * @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
@@ -83,6 +83,7 @@ struct acpi_gpio_info {
        struct acpi_device *adev;
        enum gpiod_flags flags;
        bool gpioint;
+       int pin_config;
        int polarity;
        int triggering;
        unsigned int quirks;
@@ -95,7 +96,7 @@ static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" };
 struct gpio_desc *of_find_gpio(struct device *dev,
                               const char *con_id,
                               unsigned int idx,
-                              enum gpio_lookup_flags *flags);
+                              unsigned long *lookupflags);
 struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
                   const char *list_name, int index, enum of_gpio_flags *flags);
 int of_gpiochip_add(struct gpio_chip *gc);
@@ -104,7 +105,7 @@ void of_gpiochip_remove(struct gpio_chip *gc);
 static inline struct gpio_desc *of_find_gpio(struct device *dev,
                                             const char *con_id,
                                             unsigned int idx,
-                                            enum gpio_lookup_flags *flags)
+                                            unsigned long *lookupflags)
 {
        return ERR_PTR(-ENOENT);
 }
@@ -126,12 +127,14 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
 
 int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
                                 struct acpi_gpio_info *info);
+int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
+                                       struct acpi_gpio_info *info);
 
 struct gpio_desc *acpi_find_gpio(struct device *dev,
                                 const char *con_id,
                                 unsigned int idx,
                                 enum gpiod_flags *dflags,
-                                enum gpio_lookup_flags *lookupflags);
+                                unsigned long *lookupflags);
 struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
                                      const char *propname, int index,
                                      struct acpi_gpio_info *info);
@@ -154,11 +157,17 @@ acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *inf
 {
        return 0;
 }
+static inline int
+acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
+                                   struct acpi_gpio_info *info)
+{
+       return 0;
+}
 
 static inline struct gpio_desc *
 acpi_find_gpio(struct device *dev, const char *con_id,
               unsigned int idx, enum gpiod_flags *dflags,
-              enum gpio_lookup_flags *lookupflags)
+              unsigned long *lookupflags)
 {
        return ERR_PTR(-ENOENT);
 }
index 2267e84d5cb43be062384afd76dc1b6c77adca75..e360a4a131e10b4c711f16b86396e2ef0dac5d90 100644 (file)
@@ -200,7 +200,6 @@ config DRM_RADEON
        select POWER_SUPPLY
        select HWMON
        select BACKLIGHT_CLASS_DEVICE
-       select BACKLIGHT_LCD_SUPPORT
        select INTERVAL_TREE
        help
          Choose this option if you have an ATI Radeon graphics card.  There
@@ -221,7 +220,6 @@ config DRM_AMDGPU
        select POWER_SUPPLY
        select HWMON
        select BACKLIGHT_CLASS_DEVICE
-       select BACKLIGHT_LCD_SUPPORT
        select INTERVAL_TREE
        select CHASH
        help
index 4376b17ca594614f9a02b5f9dfd70601cd06c017..56f8ca2a3bb45e9d2039deeb925eb66bcf16b6c4 100644 (file)
@@ -464,8 +464,7 @@ static int amdgpu_atif_handler(struct amdgpu_device *adev,
                        }
                }
                if (req.pending & ATIF_DGPU_DISPLAY_EVENT) {
-                       if ((adev->flags & AMD_IS_PX) &&
-                           amdgpu_atpx_dgpu_req_power_for_displays()) {
+                       if (adev->flags & AMD_IS_PX) {
                                pm_runtime_get_sync(adev->ddev->dev);
                                /* Just fire off a uevent and let userspace tell us what to do */
                                drm_helper_hpd_irq_event(adev->ddev);
index 3e6823fdd93942cce3ace2c21b456f1e4e1d8d84..58ed401c5996eb3af99843f2be577e633bd04bf4 100644 (file)
@@ -256,14 +256,14 @@ static int amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn,
        /* TODO we should be able to split locking for interval tree and
         * amdgpu_mn_invalidate_node
         */
-       if (amdgpu_mn_read_lock(amn, range->blockable))
+       if (amdgpu_mn_read_lock(amn, mmu_notifier_range_blockable(range)))
                return -EAGAIN;
 
        it = interval_tree_iter_first(&amn->objects, range->start, end);
        while (it) {
                struct amdgpu_mn_node *node;
 
-               if (!range->blockable) {
+               if (!mmu_notifier_range_blockable(range)) {
                        amdgpu_mn_read_unlock(amn);
                        return -EAGAIN;
                }
@@ -299,7 +299,7 @@ static int amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn,
        /* notification is exclusive, but interval is inclusive */
        end = range->end - 1;
 
-       if (amdgpu_mn_read_lock(amn, range->blockable))
+       if (amdgpu_mn_read_lock(amn, mmu_notifier_range_blockable(range)))
                return -EAGAIN;
 
        it = interval_tree_iter_first(&amn->objects, range->start, end);
@@ -307,7 +307,7 @@ static int amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn,
                struct amdgpu_mn_node *node;
                struct amdgpu_bo *bo;
 
-               if (!range->blockable) {
+               if (!mmu_notifier_range_blockable(range)) {
                        amdgpu_mn_read_unlock(amn);
                        return -EAGAIN;
                }
index 95144e49c7f9df9e914b3e37421d4f60913070fd..34471dbaa872ad9d7b18c669a95c2fcd758def83 100644 (file)
@@ -342,6 +342,16 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
        if (current_level == level)
                return count;
 
+       /* profile_exit setting is valid only when current mode is in profile mode */
+       if (!(current_level & (AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
+           AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
+           AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK |
+           AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)) &&
+           (level == AMD_DPM_FORCED_LEVEL_PROFILE_EXIT)) {
+               pr_err("Currently not in any profile mode!\n");
+               return -EINVAL;
+       }
+
        if (is_support_sw_smu(adev)) {
                mutex_lock(&adev->pm.mutex);
                if (adev->pm.dpm.thermal_active) {
index 905cce1814f3fffb1f3a741f5e9731e75edab12c..05897b05766b1bb6ff300d0203404b208d5a8807 100644 (file)
@@ -38,18 +38,10 @@ static void psp_set_funcs(struct amdgpu_device *adev);
 static int psp_early_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       struct psp_context *psp = &adev->psp;
 
        psp_set_funcs(adev);
 
-       return 0;
-}
-
-static int psp_sw_init(void *handle)
-{
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-       struct psp_context *psp = &adev->psp;
-       int ret;
-
        switch (adev->asic_type) {
        case CHIP_VEGA10:
        case CHIP_VEGA12:
@@ -67,6 +59,15 @@ static int psp_sw_init(void *handle)
 
        psp->adev = adev;
 
+       return 0;
+}
+
+static int psp_sw_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       struct psp_context *psp = &adev->psp;
+       int ret;
+
        ret = psp_init_microcode(psp);
        if (ret) {
                DRM_ERROR("Failed to load psp firmware!\n");
index a07c85815b7a65b1dc554a01cf607e8fd41332bb..4f10f5aba00b80ee2e5507323f55a0f28a51d157 100644 (file)
@@ -2756,6 +2756,37 @@ error_free_sched_entity:
        return r;
 }
 
+/**
+ * amdgpu_vm_check_clean_reserved - check if a VM is clean
+ *
+ * @adev: amdgpu_device pointer
+ * @vm: the VM to check
+ *
+ * check all entries of the root PD, if any subsequent PDs are allocated,
+ * it means there are page table creating and filling, and is no a clean
+ * VM
+ *
+ * Returns:
+ *     0 if this VM is clean
+ */
+static int amdgpu_vm_check_clean_reserved(struct amdgpu_device *adev,
+       struct amdgpu_vm *vm)
+{
+       enum amdgpu_vm_level root = adev->vm_manager.root_level;
+       unsigned int entries = amdgpu_vm_num_entries(adev, root);
+       unsigned int i = 0;
+
+       if (!(vm->root.entries))
+               return 0;
+
+       for (i = 0; i < entries; i++) {
+               if (vm->root.entries[i].base.bo)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
 /**
  * amdgpu_vm_make_compute - Turn a GFX VM into a compute VM
  *
@@ -2786,10 +2817,9 @@ int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm, uns
                return r;
 
        /* Sanity checks */
-       if (!RB_EMPTY_ROOT(&vm->va.rb_root) || vm->root.entries) {
-               r = -EINVAL;
+       r = amdgpu_vm_check_clean_reserved(adev, vm);
+       if (r)
                goto unreserve_bo;
-       }
 
        if (pasid) {
                unsigned long flags;
index 8dbad496b29f2a3ab829650d9f50ac172f3aa9dd..2471e7cf75eac4cd565b1e0b070f862dc3b9c444 100644 (file)
@@ -372,6 +372,9 @@ static int xgpu_ai_mailbox_rcv_irq(struct amdgpu_device *adev,
                if (amdgpu_sriov_runtime(adev))
                        schedule_work(&adev->virt.flr_work);
                break;
+               case IDH_QUERY_ALIVE:
+                       xgpu_ai_mailbox_send_ack(adev);
+                       break;
                /* READY_TO_ACCESS_GPU is fetched by kernel polling, IRQ can ignore
                 * it byfar since that polling thread will handle it,
                 * other msg like flr complete is not handled here.
index 39d151b791533cc423e0216c169779f017ef2d4b..077e91a33d62d632c48c0eed5ddf0b3a997be676 100644 (file)
@@ -49,6 +49,7 @@ enum idh_event {
        IDH_FLR_NOTIFICATION_CMPL,
        IDH_SUCCESS,
        IDH_FAIL,
+       IDH_QUERY_ALIVE,
        IDH_EVENT_MAX
 };
 
index dc461df48da09c22020f48bd8c3bd387d276099f..2191d3d0a2190a4cbe5ac93835b2ab753f393c61 100644 (file)
@@ -787,10 +787,13 @@ static int uvd_v7_0_sriov_start(struct amdgpu_device *adev)
                                                           0xFFFFFFFF, 0x00000004);
                        /* mc resume*/
                        if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
-                               MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(UVD, i, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW),
-                                                           lower_32_bits(adev->firmware.ucode[AMDGPU_UCODE_ID_UVD].mc_addr));
-                               MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(UVD, i, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH),
-                                                           upper_32_bits(adev->firmware.ucode[AMDGPU_UCODE_ID_UVD].mc_addr));
+                               MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(UVD, i,
+                                                       mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW),
+                                                       adev->firmware.ucode[AMDGPU_UCODE_ID_UVD].tmr_mc_addr_lo);
+                               MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(UVD, i,
+                                                       mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH),
+                                                       adev->firmware.ucode[AMDGPU_UCODE_ID_UVD].tmr_mc_addr_hi);
+                               MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET0), 0);
                                offset = 0;
                        } else {
                                MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(UVD, i, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW),
@@ -798,10 +801,11 @@ static int uvd_v7_0_sriov_start(struct amdgpu_device *adev)
                                MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(UVD, i, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH),
                                                            upper_32_bits(adev->uvd.inst[i].gpu_addr));
                                offset = size;
+                               MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET0),
+                                                       AMDGPU_UVD_FIRMWARE_OFFSET >> 3);
+
                        }
 
-                       MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET0),
-                                                   AMDGPU_UVD_FIRMWARE_OFFSET >> 3);
                        MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE0), size);
 
                        MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(UVD, i, mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW),
index f3f5938430d4fdb9d393bf73cc22dd8b1e419412..c0ec27991c22ba90ca4fcd6d8f08347abccb1687 100644 (file)
@@ -244,13 +244,18 @@ static int vce_v4_0_sriov_start(struct amdgpu_device *adev)
                MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCE, 0, mmVCE_LMI_SWAP_CNTL1), 0);
                MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCE, 0, mmVCE_LMI_VM_CTRL), 0);
 
+               offset = AMDGPU_VCE_FIRMWARE_OFFSET;
                if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
+                       uint32_t low = adev->firmware.ucode[AMDGPU_UCODE_ID_VCE].tmr_mc_addr_lo;
+                       uint32_t hi = adev->firmware.ucode[AMDGPU_UCODE_ID_VCE].tmr_mc_addr_hi;
+                       uint64_t tmr_mc_addr = (uint64_t)(hi) << 32 | low;
+
                        MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCE, 0,
-                                               mmVCE_LMI_VCPU_CACHE_40BIT_BAR0),
-                                               adev->firmware.ucode[AMDGPU_UCODE_ID_VCE].mc_addr >> 8);
+                                               mmVCE_LMI_VCPU_CACHE_40BIT_BAR0), tmr_mc_addr >> 8);
                        MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCE, 0,
                                                mmVCE_LMI_VCPU_CACHE_64BIT_BAR0),
-                                               (adev->firmware.ucode[AMDGPU_UCODE_ID_VCE].mc_addr >> 40) & 0xff);
+                                               (tmr_mc_addr >> 40) & 0xff);
+                       MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCE, 0, mmVCE_VCPU_CACHE_OFFSET0), 0);
                } else {
                        MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCE, 0,
                                                mmVCE_LMI_VCPU_CACHE_40BIT_BAR0),
@@ -258,6 +263,9 @@ static int vce_v4_0_sriov_start(struct amdgpu_device *adev)
                        MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCE, 0,
                                                mmVCE_LMI_VCPU_CACHE_64BIT_BAR0),
                                                (adev->vce.gpu_addr >> 40) & 0xff);
+                       MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCE, 0, mmVCE_VCPU_CACHE_OFFSET0),
+                                               offset & ~0x0f000000);
+
                }
                MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCE, 0,
                                                mmVCE_LMI_VCPU_CACHE_40BIT_BAR1),
@@ -272,10 +280,7 @@ static int vce_v4_0_sriov_start(struct amdgpu_device *adev)
                                                mmVCE_LMI_VCPU_CACHE_64BIT_BAR2),
                                                (adev->vce.gpu_addr >> 40) & 0xff);
 
-               offset = AMDGPU_VCE_FIRMWARE_OFFSET;
                size = VCE_V4_0_FW_SIZE;
-               MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCE, 0, mmVCE_VCPU_CACHE_OFFSET0),
-                                       offset & ~0x0f000000);
                MMSCH_V1_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCE, 0, mmVCE_VCPU_CACHE_SIZE0), size);
 
                offset = (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) ? offset + size : 0;
index 1b2f69a9a24ef957f5ec701ab664e1e9de3653f1..8d89ab7f0ae86727fe97694f3b4bfe337a5723ea 100644 (file)
@@ -31,7 +31,7 @@
 #include "soc15_common.h"
 #include "vega10_ih.h"
 
-
+#define MAX_REARM_RETRY 10
 
 static void vega10_ih_set_interrupt_funcs(struct amdgpu_device *adev);
 
@@ -381,6 +381,38 @@ static void vega10_ih_decode_iv(struct amdgpu_device *adev,
        ih->rptr += 32;
 }
 
+/**
+ * vega10_ih_irq_rearm - rearm IRQ if lost
+ *
+ * @adev: amdgpu_device pointer
+ *
+ */
+static void vega10_ih_irq_rearm(struct amdgpu_device *adev,
+                              struct amdgpu_ih_ring *ih)
+{
+       uint32_t reg_rptr = 0;
+       uint32_t v = 0;
+       uint32_t i = 0;
+
+       if (ih == &adev->irq.ih)
+               reg_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR);
+       else if (ih == &adev->irq.ih1)
+               reg_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING1);
+       else if (ih == &adev->irq.ih2)
+               reg_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING2);
+       else
+               return;
+
+       /* Rearm IRQ / re-wwrite doorbell if doorbell write is lost */
+       for (i = 0; i < MAX_REARM_RETRY; i++) {
+               v = RREG32_NO_KIQ(reg_rptr);
+               if ((v < ih->ring_size) && (v != ih->rptr))
+                       WDOORBELL32(ih->doorbell_index, ih->rptr);
+               else
+                       break;
+       }
+}
+
 /**
  * vega10_ih_set_rptr - set the IH ring buffer rptr
  *
@@ -395,6 +427,9 @@ static void vega10_ih_set_rptr(struct amdgpu_device *adev,
                /* XXX check if swapping is necessary on BE */
                *ih->rptr_cpu = ih->rptr;
                WDOORBELL32(ih->doorbell_index, ih->rptr);
+
+               if (amdgpu_sriov_vf(adev))
+                       vega10_ih_irq_rearm(adev, ih);
        } else if (ih == &adev->irq.ih) {
                WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, ih->rptr);
        } else if (ih == &adev->irq.ih1) {
index 2cb09e088dcec6e785065340d933fda331992d7d..769dbc7be8cb8b5589066131112e075c5e85a6ea 100644 (file)
@@ -1272,8 +1272,7 @@ int kfd_topology_add_device(struct kfd_dev *gpu)
 
        dev->node_props.vendor_id = gpu->pdev->vendor;
        dev->node_props.device_id = gpu->pdev->device;
-       dev->node_props.location_id = PCI_DEVID(gpu->pdev->bus->number,
-               gpu->pdev->devfn);
+       dev->node_props.location_id = pci_dev_id(gpu->pdev);
        dev->node_props.max_engine_clk_fcompute =
                amdgpu_amdkfd_get_max_engine_clock_in_mhz(dev->gpu->kgd);
        dev->node_props.max_engine_clk_ccompute =
index 1854506e3e8f91cc3f5bd4082e30b3c043d0bbc0..995f9df66142ef92e11f465aae065541d91a3873 100644 (file)
@@ -5242,7 +5242,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                                    struct drm_crtc *pcrtc,
                                    bool wait_for_vblank)
 {
-       uint32_t i, r;
+       uint32_t i;
        uint64_t timestamp_ns;
        struct drm_plane *plane;
        struct drm_plane_state *old_plane_state, *new_plane_state;
@@ -5253,6 +5253,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
        struct dm_crtc_state *dm_old_crtc_state =
                        to_dm_crtc_state(drm_atomic_get_old_crtc_state(state, pcrtc));
        int planes_count = 0, vpos, hpos;
+       long r;
        unsigned long flags;
        struct amdgpu_bo *abo;
        uint64_t tiling_flags;
index 8840f396a7b68b63f1f41c52fc730ef6fec7768e..3dff9997f5e309bd97fc0b7acdb7e10d979a68e5 100644 (file)
@@ -76,7 +76,6 @@ config DRM_PARADE_PS8622
        depends on OF
        select DRM_PANEL
        select DRM_KMS_HELPER
-       select BACKLIGHT_LCD_SUPPORT
        select BACKLIGHT_CLASS_DEVICE
        ---help---
          Parade eDP-LVDS bridge chip driver.
index ec2ca71e132321f2c45d6b2e473a75f894059628..c532e9c9e491e13a524f11c0458949e0bd91461a 100644 (file)
@@ -748,11 +748,11 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
                        vsync_polarity = 1;
        }
 
-       if (mode->vrefresh <= 24000)
+       if (drm_mode_vrefresh(mode) <= 24)
                low_refresh_rate = ADV7511_LOW_REFRESH_RATE_24HZ;
-       else if (mode->vrefresh <= 25000)
+       else if (drm_mode_vrefresh(mode) <= 25)
                low_refresh_rate = ADV7511_LOW_REFRESH_RATE_25HZ;
-       else if (mode->vrefresh <= 30000)
+       else if (drm_mode_vrefresh(mode) <= 30)
                low_refresh_rate = ADV7511_LOW_REFRESH_RATE_30HZ;
        else
                low_refresh_rate = ADV7511_LOW_REFRESH_RATE_NONE;
index 14a72c4c496d2469eccee871f22eb4ccb52eb17a..dc825883400d0f317b627a4f975005060779e220 100644 (file)
@@ -2,7 +2,6 @@ config DRM_FSL_DCU
        tristate "DRM Support for Freescale DCU"
        depends on DRM && OF && ARM && COMMON_CLK
        select BACKLIGHT_CLASS_DEVICE
-       select BACKLIGHT_LCD_SUPPORT
        select DRM_KMS_HELPER
        select DRM_KMS_CMA_HELPER
        select DRM_PANEL
index 148be8e1a09052db6946714cb375985633b98fe3..3d5f1cb6a76ca53221a7f0b04039c84bf6d9f25a 100644 (file)
@@ -15,7 +15,6 @@ config DRM_I915
        select IRQ_WORK
        # i915 depends on ACPI_VIDEO when ACPI is enabled
        # but for select to work, need to select ACPI_VIDEO's dependencies, ick
-       select BACKLIGHT_LCD_SUPPORT if ACPI
        select BACKLIGHT_CLASS_DEVICE if ACPI
        select INPUT if ACPI
        select ACPI_VIDEO if ACPI
index 2ec89bcb59f13099d758a79a20c37ee7a6fcce4f..8a9606f91e68e6a20a9194aca9f84816f75d201d 100644 (file)
@@ -196,9 +196,9 @@ DEFINE_SIMPLE_ATTRIBUTE(vgpu_scan_nonprivbb_fops,
 int intel_gvt_debugfs_add_vgpu(struct intel_vgpu *vgpu)
 {
        struct dentry *ent;
-       char name[10] = "";
+       char name[16] = "";
 
-       sprintf(name, "vgpu%d", vgpu->id);
+       snprintf(name, 16, "vgpu%d", vgpu->id);
        vgpu->debugfs = debugfs_create_dir(name, vgpu->gvt->debugfs_root);
        if (!vgpu->debugfs)
                return -ENOMEM;
index 4e1e425189ba971e58098f95dada623cd0997a85..41c8ebc60c63b301680e8f1881fc452567111e33 100644 (file)
@@ -45,6 +45,7 @@ static int vgpu_gem_get_pages(
        int i, ret;
        gen8_pte_t __iomem *gtt_entries;
        struct intel_vgpu_fb_info *fb_info;
+       u32 page_num;
 
        fb_info = (struct intel_vgpu_fb_info *)obj->gvt_info;
        if (WARN_ON(!fb_info))
@@ -54,14 +55,15 @@ static int vgpu_gem_get_pages(
        if (unlikely(!st))
                return -ENOMEM;
 
-       ret = sg_alloc_table(st, fb_info->size, GFP_KERNEL);
+       page_num = obj->base.size >> PAGE_SHIFT;
+       ret = sg_alloc_table(st, page_num, GFP_KERNEL);
        if (ret) {
                kfree(st);
                return ret;
        }
        gtt_entries = (gen8_pte_t __iomem *)dev_priv->ggtt.gsm +
                (fb_info->start >> PAGE_SHIFT);
-       for_each_sg(st->sgl, sg, fb_info->size, i) {
+       for_each_sg(st->sgl, sg, page_num, i) {
                sg->offset = 0;
                sg->length = PAGE_SIZE;
                sg_dma_address(sg) =
@@ -158,7 +160,7 @@ static struct drm_i915_gem_object *vgpu_create_gem(struct drm_device *dev,
                return NULL;
 
        drm_gem_private_object_init(dev, &obj->base,
-               info->size << PAGE_SHIFT);
+               roundup(info->size, PAGE_SIZE));
        i915_gem_object_init(obj, &intel_vgpu_gem_ops);
 
        obj->read_domains = I915_GEM_DOMAIN_GTT;
@@ -206,11 +208,12 @@ static int vgpu_get_plane_info(struct drm_device *dev,
                struct intel_vgpu_fb_info *info,
                int plane_id)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_vgpu_primary_plane_format p;
        struct intel_vgpu_cursor_plane_format c;
        int ret, tile_height = 1;
 
+       memset(info, 0, sizeof(*info));
+
        if (plane_id == DRM_PLANE_TYPE_PRIMARY) {
                ret = intel_vgpu_decode_primary_plane(vgpu, &p);
                if (ret)
@@ -267,8 +270,7 @@ static int vgpu_get_plane_info(struct drm_device *dev,
                return -EINVAL;
        }
 
-       info->size = (info->stride * roundup(info->height, tile_height)
-                     + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       info->size = info->stride * roundup(info->height, tile_height);
        if (info->size == 0) {
                gvt_vgpu_err("fb size is zero\n");
                return -EINVAL;
@@ -278,11 +280,6 @@ static int vgpu_get_plane_info(struct drm_device *dev,
                gvt_vgpu_err("Not aligned fb address:0x%llx\n", info->start);
                return -EFAULT;
        }
-       if (((info->start >> PAGE_SHIFT) + info->size) >
-               ggtt_total_entries(&dev_priv->ggtt)) {
-               gvt_vgpu_err("Invalid GTT offset or size\n");
-               return -EFAULT;
-       }
 
        if (!intel_gvt_ggtt_validate_range(vgpu, info->start, info->size)) {
                gvt_vgpu_err("invalid gma addr\n");
index c2f7d20f634691c343059b9cb1ac69931e3f81b7..08c74e65836b52aab7f82d80ca7b37d98f202a74 100644 (file)
@@ -811,7 +811,7 @@ static int reclaim_one_ppgtt_mm(struct intel_gvt *gvt);
 
 /* Allocate shadow page table without guest page. */
 static struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt(
-               struct intel_vgpu *vgpu, intel_gvt_gtt_type_t type)
+               struct intel_vgpu *vgpu, enum intel_gvt_gtt_type type)
 {
        struct device *kdev = &vgpu->gvt->dev_priv->drm.pdev->dev;
        struct intel_vgpu_ppgtt_spt *spt = NULL;
@@ -861,7 +861,7 @@ err_free_spt:
 
 /* Allocate shadow page table associated with specific gfn. */
 static struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt_gfn(
-               struct intel_vgpu *vgpu, intel_gvt_gtt_type_t type,
+               struct intel_vgpu *vgpu, enum intel_gvt_gtt_type type,
                unsigned long gfn, bool guest_pde_ips)
 {
        struct intel_vgpu_ppgtt_spt *spt;
@@ -936,7 +936,7 @@ static int ppgtt_invalidate_spt_by_shadow_entry(struct intel_vgpu *vgpu,
 {
        struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
        struct intel_vgpu_ppgtt_spt *s;
-       intel_gvt_gtt_type_t cur_pt_type;
+       enum intel_gvt_gtt_type cur_pt_type;
 
        GEM_BUG_ON(!gtt_type_is_pt(get_next_pt_type(e->type)));
 
@@ -1076,6 +1076,9 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_populate_spt_by_guest_entry(
        } else {
                int type = get_next_pt_type(we->type);
 
+               if (!gtt_type_is_pt(type))
+                       goto err;
+
                spt = ppgtt_alloc_spt_gfn(vgpu, type, ops->get_pfn(we), ips);
                if (IS_ERR(spt)) {
                        ret = PTR_ERR(spt);
@@ -1855,7 +1858,7 @@ static void vgpu_free_mm(struct intel_vgpu_mm *mm)
  * Zero on success, negative error code in pointer if failed.
  */
 struct intel_vgpu_mm *intel_vgpu_create_ppgtt_mm(struct intel_vgpu *vgpu,
-               intel_gvt_gtt_type_t root_entry_type, u64 pdps[])
+               enum intel_gvt_gtt_type root_entry_type, u64 pdps[])
 {
        struct intel_gvt *gvt = vgpu->gvt;
        struct intel_vgpu_mm *mm;
@@ -2309,7 +2312,7 @@ int intel_vgpu_emulate_ggtt_mmio_write(struct intel_vgpu *vgpu,
 }
 
 static int alloc_scratch_pages(struct intel_vgpu *vgpu,
-               intel_gvt_gtt_type_t type)
+               enum intel_gvt_gtt_type type)
 {
        struct intel_vgpu_gtt *gtt = &vgpu->gtt;
        struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
@@ -2594,7 +2597,7 @@ struct intel_vgpu_mm *intel_vgpu_find_ppgtt_mm(struct intel_vgpu *vgpu,
  * Zero on success, negative error code if failed.
  */
 struct intel_vgpu_mm *intel_vgpu_get_ppgtt_mm(struct intel_vgpu *vgpu,
-               intel_gvt_gtt_type_t root_entry_type, u64 pdps[])
+               enum intel_gvt_gtt_type root_entry_type, u64 pdps[])
 {
        struct intel_vgpu_mm *mm;
 
index 32c573aea49468c67597f47272282be4cb73de5c..42d0394f0de2bcd0841fc35f44a7ecc5c8e520f3 100644 (file)
@@ -95,8 +95,8 @@ struct intel_gvt_gtt {
        unsigned long scratch_mfn;
 };
 
-typedef enum {
-       GTT_TYPE_INVALID = -1,
+enum intel_gvt_gtt_type {
+       GTT_TYPE_INVALID = 0,
 
        GTT_TYPE_GGTT_PTE,
 
@@ -124,7 +124,7 @@ typedef enum {
        GTT_TYPE_PPGTT_PML4_PT,
 
        GTT_TYPE_MAX,
-} intel_gvt_gtt_type_t;
+};
 
 enum intel_gvt_mm_type {
        INTEL_GVT_MM_GGTT,
@@ -148,7 +148,7 @@ struct intel_vgpu_mm {
 
        union {
                struct {
-                       intel_gvt_gtt_type_t root_entry_type;
+                       enum intel_gvt_gtt_type root_entry_type;
                        /*
                         * The 4 PDPs in ring context. For 48bit addressing,
                         * only PDP0 is valid and point to PML4. For 32it
@@ -169,7 +169,7 @@ struct intel_vgpu_mm {
 };
 
 struct intel_vgpu_mm *intel_vgpu_create_ppgtt_mm(struct intel_vgpu *vgpu,
-               intel_gvt_gtt_type_t root_entry_type, u64 pdps[]);
+               enum intel_gvt_gtt_type root_entry_type, u64 pdps[]);
 
 static inline void intel_vgpu_mm_get(struct intel_vgpu_mm *mm)
 {
@@ -233,7 +233,7 @@ struct intel_vgpu_ppgtt_spt {
        struct intel_vgpu *vgpu;
 
        struct {
-               intel_gvt_gtt_type_t type;
+               enum intel_gvt_gtt_type type;
                bool pde_ips; /* for 64KB PTEs */
                void *vaddr;
                struct page *page;
@@ -241,7 +241,7 @@ struct intel_vgpu_ppgtt_spt {
        } shadow_page;
 
        struct {
-               intel_gvt_gtt_type_t type;
+               enum intel_gvt_gtt_type type;
                bool pde_ips; /* for 64KB PTEs */
                unsigned long gfn;
                unsigned long write_cnt;
@@ -267,7 +267,7 @@ struct intel_vgpu_mm *intel_vgpu_find_ppgtt_mm(struct intel_vgpu *vgpu,
                u64 pdps[]);
 
 struct intel_vgpu_mm *intel_vgpu_get_ppgtt_mm(struct intel_vgpu *vgpu,
-               intel_gvt_gtt_type_t root_entry_type, u64 pdps[]);
+               enum intel_gvt_gtt_type root_entry_type, u64 pdps[]);
 
 int intel_vgpu_put_ppgtt_mm(struct intel_vgpu *vgpu, u64 pdps[]);
 
index 18f01eeb25105d3a1dc7c5b5e9ca9168a01fc336..90673fca792f3a888b508d77f5f8688a9128ce92 100644 (file)
@@ -1206,7 +1206,7 @@ static int pvinfo_mmio_read(struct intel_vgpu *vgpu, unsigned int offset,
 
 static int handle_g2v_notification(struct intel_vgpu *vgpu, int notification)
 {
-       intel_gvt_gtt_type_t root_entry_type = GTT_TYPE_PPGTT_ROOT_L4_ENTRY;
+       enum intel_gvt_gtt_type root_entry_type = GTT_TYPE_PPGTT_ROOT_L4_ENTRY;
        struct intel_vgpu_mm *mm;
        u64 *pdps;
 
@@ -3303,7 +3303,7 @@ void intel_gvt_clean_mmio_info(struct intel_gvt *gvt)
 /* Special MMIO blocks. */
 static struct gvt_mmio_block mmio_blocks[] = {
        {D_SKL_PLUS, _MMIO(CSR_MMIO_START_RANGE), 0x3000, NULL, NULL},
-       {D_ALL, MCHBAR_MIRROR_REG_BASE, 0x4000, NULL, NULL},
+       {D_ALL, _MMIO(MCHBAR_MIRROR_BASE_SNB), 0x40000, NULL, NULL},
        {D_ALL, _MMIO(VGT_PVINFO_PAGE), VGT_PVINFO_SIZE,
                pvinfo_mmio_read, pvinfo_mmio_write},
        {D_ALL, LGC_PALETTE(PIPE_A, 0), 1024, NULL, NULL},
index e7e14c842be46d57bc583071a19d83b6b287790d..edf6d646eb251e530d94e60baa24876ad7487416 100644 (file)
@@ -132,6 +132,7 @@ static struct engine_mmio gen9_engine_mmio_list[] __cacheline_aligned = {
 
        {RCS0, GEN9_GAMT_ECO_REG_RW_IA, 0x0, false}, /* 0x4ab0 */
        {RCS0, GEN9_CSFE_CHICKEN1_RCS, 0xffff, false}, /* 0x20d4 */
+       {RCS0, _MMIO(0x20D8), 0xffff, true}, /* 0x20d8 */
 
        {RCS0, GEN8_GARBCNTL, 0x0, false}, /* 0xb004 */
        {RCS0, GEN7_FF_THREAD_MODE, 0x0, false}, /* 0x20a0 */
index 3de5b643b266405b8c8f718e72229b531943e931..33aaa14bfdde789775758aa076e4d51af26c85e9 100644 (file)
 #define RING_GFX_MODE(base)    _MMIO((base) + 0x29c)
 #define VF_GUARDBAND           _MMIO(0x83a4)
 
-/* define the effective range of MCHBAR register on Sandybridge+ */
-#define MCHBAR_MIRROR_REG_BASE _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x4000)
-
 #endif
index 8998fa5ab198ffd0282662d5235e23a59a2bb7c4..7c99bbc3e2b8c00c7fad49b9e58f8ed4ae7a63dd 100644 (file)
@@ -1343,7 +1343,7 @@ static int prepare_mm(struct intel_vgpu_workload *workload)
        struct execlist_ctx_descriptor_format *desc = &workload->ctx_desc;
        struct intel_vgpu_mm *mm;
        struct intel_vgpu *vgpu = workload->vgpu;
-       intel_gvt_gtt_type_t root_entry_type;
+       enum intel_gvt_gtt_type root_entry_type;
        u64 pdps[GVT_RING_CTX_NR_PDPS];
 
        switch (desc->addressing_mode) {
index 215bf3fef10c9a1e3785f73ba55fe10a896d0f70..8079ea3af10398b31ea9b7e8a4b7cc7011bc5788 100644 (file)
@@ -122,7 +122,7 @@ userptr_mn_invalidate_range_start(struct mmu_notifier *_mn,
        while (it) {
                struct drm_i915_gem_object *obj;
 
-               if (!range->blockable) {
+               if (!mmu_notifier_range_blockable(range)) {
                        ret = -EAGAIN;
                        break;
                }
index b836721d3b1304f226e3bd8a3b9a9d65901725be..f6c78c0fa74bf9bc93c6ee60d6c5b6e3272d2670 100644 (file)
@@ -425,6 +425,26 @@ void __i915_request_submit(struct i915_request *request)
        if (i915_gem_context_is_banned(request->gem_context))
                i915_request_skip(request, -EIO);
 
+       /*
+        * Are we using semaphores when the gpu is already saturated?
+        *
+        * Using semaphores incurs a cost in having the GPU poll a
+        * memory location, busywaiting for it to change. The continual
+        * memory reads can have a noticeable impact on the rest of the
+        * system with the extra bus traffic, stalling the cpu as it too
+        * tries to access memory across the bus (perf stat -e bus-cycles).
+        *
+        * If we installed a semaphore on this request and we only submit
+        * the request after the signaler completed, that indicates the
+        * system is overloaded and using semaphores at this time only
+        * increases the amount of work we are doing. If so, we disable
+        * further use of semaphores until we are idle again, whence we
+        * optimistically try again.
+        */
+       if (request->sched.semaphores &&
+           i915_sw_fence_signaled(&request->semaphore))
+               request->hw_context->saturated |= request->sched.semaphores;
+
        /* We may be recursing from the signal callback of another i915 fence */
        spin_lock_nested(&request->lock, SINGLE_DEPTH_NESTING);
 
@@ -432,6 +452,7 @@ void __i915_request_submit(struct i915_request *request)
        set_bit(I915_FENCE_FLAG_ACTIVE, &request->fence.flags);
 
        if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &request->fence.flags) &&
+           !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &request->fence.flags) &&
            !i915_request_enable_breadcrumb(request))
                intel_engine_queue_breadcrumbs(engine);
 
@@ -798,6 +819,39 @@ err_unreserve:
        return ERR_PTR(ret);
 }
 
+static int
+i915_request_await_start(struct i915_request *rq, struct i915_request *signal)
+{
+       if (list_is_first(&signal->ring_link, &signal->ring->request_list))
+               return 0;
+
+       signal = list_prev_entry(signal, ring_link);
+       if (i915_timeline_sync_is_later(rq->timeline, &signal->fence))
+               return 0;
+
+       return i915_sw_fence_await_dma_fence(&rq->submit,
+                                            &signal->fence, 0,
+                                            I915_FENCE_GFP);
+}
+
+static intel_engine_mask_t
+already_busywaiting(struct i915_request *rq)
+{
+       /*
+        * Polling a semaphore causes bus traffic, delaying other users of
+        * both the GPU and CPU. We want to limit the impact on others,
+        * while taking advantage of early submission to reduce GPU
+        * latency. Therefore we restrict ourselves to not using more
+        * than one semaphore from each source, and not using a semaphore
+        * if we have detected the engine is saturated (i.e. would not be
+        * submitted early and cause bus traffic reading an already passed
+        * semaphore).
+        *
+        * See the are-we-too-late? check in __i915_request_submit().
+        */
+       return rq->sched.semaphores | rq->hw_context->saturated;
+}
+
 static int
 emit_semaphore_wait(struct i915_request *to,
                    struct i915_request *from,
@@ -811,11 +865,15 @@ emit_semaphore_wait(struct i915_request *to,
        GEM_BUG_ON(INTEL_GEN(to->i915) < 8);
 
        /* Just emit the first semaphore we see as request space is limited. */
-       if (to->sched.semaphores & from->engine->mask)
+       if (already_busywaiting(to) & from->engine->mask)
                return i915_sw_fence_await_dma_fence(&to->submit,
                                                     &from->fence, 0,
                                                     I915_FENCE_GFP);
 
+       err = i915_request_await_start(to, from);
+       if (err < 0)
+               return err;
+
        err = i915_sw_fence_await_dma_fence(&to->semaphore,
                                            &from->fence, 0,
                                            I915_FENCE_GFP);
index 3cbffd400b1bdb15fbb1d0604d41f1001a144f5b..832cb6b1e9bd437d7916ec21508c33330e0921a3 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <linux/kthread.h>
+#include <trace/events/dma_fence.h>
 #include <uapi/linux/sched/types.h>
 
 #include "i915_drv.h"
@@ -80,9 +81,39 @@ static inline bool __request_completed(const struct i915_request *rq)
        return i915_seqno_passed(__hwsp_seqno(rq), rq->fence.seqno);
 }
 
+static bool
+__dma_fence_signal(struct dma_fence *fence)
+{
+       return !test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags);
+}
+
+static void
+__dma_fence_signal__timestamp(struct dma_fence *fence, ktime_t timestamp)
+{
+       fence->timestamp = timestamp;
+       set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags);
+       trace_dma_fence_signaled(fence);
+}
+
+static void
+__dma_fence_signal__notify(struct dma_fence *fence)
+{
+       struct dma_fence_cb *cur, *tmp;
+
+       lockdep_assert_held(fence->lock);
+       lockdep_assert_irqs_disabled();
+
+       list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) {
+               INIT_LIST_HEAD(&cur->node);
+               cur->func(fence, cur);
+       }
+       INIT_LIST_HEAD(&fence->cb_list);
+}
+
 void intel_engine_breadcrumbs_irq(struct intel_engine_cs *engine)
 {
        struct intel_breadcrumbs *b = &engine->breadcrumbs;
+       const ktime_t timestamp = ktime_get();
        struct intel_context *ce, *cn;
        struct list_head *pos, *next;
        LIST_HEAD(signal);
@@ -104,6 +135,10 @@ void intel_engine_breadcrumbs_irq(struct intel_engine_cs *engine)
 
                        GEM_BUG_ON(!test_bit(I915_FENCE_FLAG_SIGNAL,
                                             &rq->fence.flags));
+                       clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);
+
+                       if (!__dma_fence_signal(&rq->fence))
+                               continue;
 
                        /*
                         * Queue for execution after dropping the signaling
@@ -111,14 +146,6 @@ void intel_engine_breadcrumbs_irq(struct intel_engine_cs *engine)
                         * more signalers to the same context or engine.
                         */
                        i915_request_get(rq);
-
-                       /*
-                        * We may race with direct invocation of
-                        * dma_fence_signal(), e.g. i915_request_retire(),
-                        * so we need to acquire our reference to the request
-                        * before we cancel the breadcrumb.
-                        */
-                       clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);
                        list_add_tail(&rq->signal_link, &signal);
                }
 
@@ -141,7 +168,12 @@ void intel_engine_breadcrumbs_irq(struct intel_engine_cs *engine)
                struct i915_request *rq =
                        list_entry(pos, typeof(*rq), signal_link);
 
-               dma_fence_signal(&rq->fence);
+               __dma_fence_signal__timestamp(&rq->fence, timestamp);
+
+               spin_lock(&rq->lock);
+               __dma_fence_signal__notify(&rq->fence);
+               spin_unlock(&rq->lock);
+
                i915_request_put(rq);
        }
 }
@@ -243,19 +275,17 @@ void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine)
 
 bool i915_request_enable_breadcrumb(struct i915_request *rq)
 {
-       struct intel_breadcrumbs *b = &rq->engine->breadcrumbs;
-
-       GEM_BUG_ON(test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags));
+       lockdep_assert_held(&rq->lock);
+       lockdep_assert_irqs_disabled();
 
-       if (!test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags))
-               return true;
-
-       spin_lock(&b->irq_lock);
-       if (test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags) &&
-           !__request_completed(rq)) {
+       if (test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags)) {
+               struct intel_breadcrumbs *b = &rq->engine->breadcrumbs;
                struct intel_context *ce = rq->hw_context;
                struct list_head *pos;
 
+               spin_lock(&b->irq_lock);
+               GEM_BUG_ON(test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags));
+
                __intel_breadcrumbs_arm_irq(b);
 
                /*
@@ -284,8 +314,8 @@ bool i915_request_enable_breadcrumb(struct i915_request *rq)
                        list_move_tail(&ce->signal_link, &b->signalers);
 
                set_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);
+               spin_unlock(&b->irq_lock);
        }
-       spin_unlock(&b->irq_lock);
 
        return !__request_completed(rq);
 }
@@ -294,9 +324,15 @@ void i915_request_cancel_breadcrumb(struct i915_request *rq)
 {
        struct intel_breadcrumbs *b = &rq->engine->breadcrumbs;
 
-       if (!test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags))
-               return;
+       lockdep_assert_held(&rq->lock);
+       lockdep_assert_irqs_disabled();
 
+       /*
+        * We must wait for b->irq_lock so that we know the interrupt handler
+        * has released its reference to the intel_context and has completed
+        * the DMA_FENCE_FLAG_SIGNALED_BIT/I915_FENCE_FLAG_SIGNAL dance (if
+        * required).
+        */
        spin_lock(&b->irq_lock);
        if (test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags)) {
                struct intel_context *ce = rq->hw_context;
index 8931e0fee873d48c8adbdba8c951f0b90ec85cc8..924cc556223ac575703c8aff3b6190ec7cbad25c 100644 (file)
@@ -230,6 +230,7 @@ intel_context_init(struct intel_context *ce,
        ce->gem_context = ctx;
        ce->engine = engine;
        ce->ops = engine->cops;
+       ce->saturated = 0;
 
        INIT_LIST_HEAD(&ce->signal_link);
        INIT_LIST_HEAD(&ce->signals);
index 68b4ca1611e0cb68d3a88e7ecf848f32ea70fdc0..339c7437fe82fe55cab2e4dbe929fc97e4c04e52 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 
 #include "i915_active_types.h"
+#include "intel_engine_types.h"
 
 struct i915_gem_context;
 struct i915_vma;
@@ -58,6 +59,8 @@ struct intel_context {
        atomic_t pin_count;
        struct mutex pin_mutex; /* guards pinning and associated on-gpuing */
 
+       intel_engine_mask_t saturated; /* submitting semaphores too late? */
+
        /**
         * active_tracker: Active tracker for the external rq activity
         * on this intel_context object.
index 3bd40a4a67399370b2c92b36ef3a48981dcdf0f3..5098228f1302d5bcd4818a80727b417a5423b747 100644 (file)
@@ -12082,6 +12082,7 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
                          struct intel_crtc_state *pipe_config,
                          bool adjust)
 {
+       struct intel_crtc *crtc = to_intel_crtc(current_config->base.crtc);
        bool ret = true;
        bool fixup_inherited = adjust &&
                (current_config->base.mode.private_flags & I915_MODE_FLAG_INHERITED) &&
@@ -12303,6 +12304,14 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
                PIPE_CONF_CHECK_X(gmch_pfit.pgm_ratios);
        PIPE_CONF_CHECK_X(gmch_pfit.lvds_border_bits);
 
+       /*
+        * Changing the EDP transcoder input mux
+        * (A_ONOFF vs. A_ON) requires a full modeset.
+        */
+       if (IS_HASWELL(dev_priv) && crtc->pipe == PIPE_A &&
+           current_config->cpu_transcoder == TRANSCODER_EDP)
+               PIPE_CONF_CHECK_BOOL(pch_pfit.enabled);
+
        if (!adjust) {
                PIPE_CONF_CHECK_I(pipe_src_w);
                PIPE_CONF_CHECK_I(pipe_src_h);
index c805a0966395b33c38e5f7259d873939d16a5774..5679f2fffb7c734a2f37242a1dfe1c0e467e1bf3 100644 (file)
@@ -1280,6 +1280,10 @@ static int intel_sanitize_fbc_option(struct drm_i915_private *dev_priv)
        if (!HAS_FBC(dev_priv))
                return 0;
 
+       /* https://bugs.freedesktop.org/show_bug.cgi?id=108085 */
+       if (IS_GEMINILAKE(dev_priv))
+               return 0;
+
        if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9)
                return 1;
 
index 37f60cb8e9e13c7e4ee166486a1c3b92f8d125e1..46cd0e70aecb034b46a877c82910bd6ecb9166ef 100644 (file)
@@ -23,7 +23,6 @@
  */
 
 #include <linux/circ_buf.h>
-#include <trace/events/dma_fence.h>
 
 #include "intel_guc_submission.h"
 #include "intel_lrc_reg.h"
index e94b5b1bc1b7f2015b0613787d0a29e8656bd875..e7c7be4911c1b04db93abd388238cc7978434084 100644 (file)
@@ -311,10 +311,17 @@ retry:
        pipe_config->base.mode_changed = pipe_config->has_psr;
        pipe_config->crc_enabled = enable;
 
-       if (IS_HASWELL(dev_priv) && crtc->pipe == PIPE_A) {
+       if (IS_HASWELL(dev_priv) &&
+           pipe_config->base.active && crtc->pipe == PIPE_A &&
+           pipe_config->cpu_transcoder == TRANSCODER_EDP) {
+               bool old_need_power_well = pipe_config->pch_pfit.enabled ||
+                       pipe_config->pch_pfit.force_thru;
+               bool new_need_power_well = pipe_config->pch_pfit.enabled ||
+                       enable;
+
                pipe_config->pch_pfit.force_thru = enable;
-               if (pipe_config->cpu_transcoder == TRANSCODER_EDP &&
-                   pipe_config->pch_pfit.enabled != enable)
+
+               if (old_need_power_well != new_need_power_well)
                        pipe_config->base.connectors_changed = true;
        }
 
index 9155dafae2a9043871f849770ab2464bba573c66..38e2cfa9cec797f41fc6ca173c3140a9b95564ec 100644 (file)
@@ -747,7 +747,7 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
         * will make sure that the refcounting is correct in case we need to
         * bring down the GX after a GMU failure
         */
-       if (!IS_ERR(gmu->gxpd))
+       if (!IS_ERR_OR_NULL(gmu->gxpd))
                pm_runtime_get(gmu->gxpd);
 
 out:
@@ -863,7 +863,7 @@ int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu)
         * domain. Usually the GMU does this but only if the shutdown sequence
         * was successful
         */
-       if (!IS_ERR(gmu->gxpd))
+       if (!IS_ERR_OR_NULL(gmu->gxpd))
                pm_runtime_put_sync(gmu->gxpd);
 
        clk_bulk_disable_unprepare(gmu->nr_clocks, gmu->clocks);
@@ -1234,7 +1234,7 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu)
 
        pm_runtime_disable(gmu->dev);
 
-       if (!IS_ERR(gmu->gxpd)) {
+       if (!IS_ERR_OR_NULL(gmu->gxpd)) {
                pm_runtime_disable(gmu->gxpd);
                dev_pm_domain_detach(gmu->gxpd, false);
        }
index 018df2c3b7ed61a016a7194883e306cff1f52ab4..45a5bc6ede5dd62583d6bb8ed33b9b4feb916128 100644 (file)
@@ -15,7 +15,6 @@
 #include "dpu_hwio.h"
 #include "dpu_hw_lm.h"
 #include "dpu_hw_mdss.h"
-#include "dpu_kms.h"
 
 #define LM_OP_MODE                        0x00
 #define LM_OUT_SIZE                       0x04
index da1f727d74957ada5271779b4e5d526331ea4804..ce1a555e1f31103cfd08b7a8b4bfa902e1e15f04 100644 (file)
@@ -780,7 +780,6 @@ static int dpu_plane_prepare_fb(struct drm_plane *plane,
        struct dpu_plane_state *pstate = to_dpu_plane_state(new_state);
        struct dpu_hw_fmt_layout layout;
        struct drm_gem_object *obj;
-       struct msm_gem_object *msm_obj;
        struct dma_fence *fence;
        struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base);
        int ret;
@@ -799,8 +798,7 @@ static int dpu_plane_prepare_fb(struct drm_plane *plane,
         *       implicit fence and fb prepare by hand here.
         */
        obj = msm_framebuffer_bo(new_state->fb, 0);
-       msm_obj = to_msm_bo(obj);
-       fence = reservation_object_get_excl_rcu(msm_obj->resv);
+       fence = reservation_object_get_excl_rcu(obj->resv);
        if (fence)
                drm_atomic_set_fence_for_plane(new_state, fence);
 
index f5b1256e32b645fa9c7bac934dbd2aa587f039cf..131c23a267eea763ffbb882d570866a7ff0e44c2 100644 (file)
@@ -49,15 +49,13 @@ int msm_atomic_prepare_fb(struct drm_plane *plane,
        struct msm_drm_private *priv = plane->dev->dev_private;
        struct msm_kms *kms = priv->kms;
        struct drm_gem_object *obj;
-       struct msm_gem_object *msm_obj;
        struct dma_fence *fence;
 
        if (!new_state->fb)
                return 0;
 
        obj = msm_framebuffer_bo(new_state->fb, 0);
-       msm_obj = to_msm_bo(obj);
-       fence = reservation_object_get_excl_rcu(msm_obj->resv);
+       fence = reservation_object_get_excl_rcu(obj->resv);
 
        drm_atomic_set_fence_for_plane(new_state, fence);
 
index eb33d2d00d772b5e71256a0f126860ed579b48a4..e20e6b42980451d2a2cec61575347a741df81b52 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/types.h>
 #include <linux/of_graph.h>
 #include <linux/of_device.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <linux/kthread.h>
 
 #include <drm/drmP.h>
index 31d5a744d84fb213c56a1fe0fff36995f41d01de..35f55dd259944e3c2ea67e666fab8befcf27c5bb 100644 (file)
@@ -803,7 +803,8 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
                seq_puts(m, "      vmas:");
 
                list_for_each_entry(vma, &msm_obj->vmas, list)
-                       seq_printf(m, " [%s: %08llx,%s,inuse=%d]", vma->aspace->name,
+                       seq_printf(m, " [%s: %08llx,%s,inuse=%d]",
+                               vma->aspace != NULL ? vma->aspace->name : NULL,
                                vma->iova, vma->mapped ? "mapped" : "unmapped",
                                vma->inuse);
 
index c5ac781dffeea366402979acebe099fff24528f6..812d1b1369a5814a6275d0b951a87752578f0a6e 100644 (file)
@@ -86,10 +86,6 @@ struct msm_gem_object {
 
        struct llist_node freed;
 
-       /* normally (resv == &_resv) except for imported bo's */
-       struct reservation_object *resv;
-       struct reservation_object _resv;
-
        /* For physically contiguous buffers.  Used when we don't have
         * an IOMMU.  Also used for stolen/splashscreen buffer.
         */
index 553c7da5e8e0405a9b03663d92b3cf59d6535583..1f1395148ff0118402a847456e75e22c85041689 100644 (file)
@@ -5,14 +5,12 @@ config DRM_NOUVEAU
        select DRM_KMS_HELPER
        select DRM_TTM
        select BACKLIGHT_CLASS_DEVICE if DRM_NOUVEAU_BACKLIGHT
-       select BACKLIGHT_LCD_SUPPORT if DRM_NOUVEAU_BACKLIGHT
        select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && INPUT
        select X86_PLATFORM_DEVICES if ACPI && X86
        select ACPI_WMI if ACPI && X86
        select MXM_WMI if ACPI && X86
        select POWER_SUPPLY
        # Similar to i915, we need to select ACPI_VIDEO and it's dependencies
-       select BACKLIGHT_LCD_SUPPORT if ACPI && X86
        select BACKLIGHT_CLASS_DEVICE if ACPI && X86
        select INPUT if ACPI && X86
        select THERMAL if ACPI && X86
index 2216c58620c2de8253b57c17446a24909eca9d3e..7c41b0599d1ac10791b71245e4a2b67a957d1169 100644 (file)
@@ -41,6 +41,7 @@ struct nv50_disp_interlock {
                NV50_DISP_INTERLOCK__SIZE
        } type;
        u32 data;
+       u32 wimm;
 };
 
 void corec37d_ntfy_init(struct nouveau_bo *, u32);
index 2e7a0c347ddbea4cf1005d42d18df84b78f33a93..06ee23823a689054c742d84e43cb4b59a39a97b2 100644 (file)
@@ -306,7 +306,7 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
                        asyh->set.or = head->func->or != NULL;
                }
 
-               if (asyh->state.mode_changed)
+               if (asyh->state.mode_changed || asyh->state.connectors_changed)
                        nv50_head_atomic_check_mode(head, asyh);
 
                if (asyh->state.color_mgmt_changed ||
@@ -413,6 +413,7 @@ nv50_head_atomic_duplicate_state(struct drm_crtc *crtc)
        asyh->ovly = armh->ovly;
        asyh->dither = armh->dither;
        asyh->procamp = armh->procamp;
+       asyh->or = armh->or;
        asyh->dp = armh->dp;
        asyh->clr.mask = 0;
        asyh->set.mask = 0;
index 9103b8494279c6273c85867d6e183e73f507ed06..f7dbd965e4e729ccd98b4e7ed153bba6a327f893 100644 (file)
@@ -75,6 +75,7 @@ wimmc37b_init_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
                return ret;
        }
 
+       wndw->interlock.wimm = wndw->interlock.data;
        wndw->immd = func;
        return 0;
 }
index b95181027b3177610edf8f91c4ba97be6d7314be..283ff690350ea76ee20fe7db1beda003631f4be2 100644 (file)
@@ -127,7 +127,7 @@ void
 nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 *interlock,
                    struct nv50_wndw_atom *asyw)
 {
-       if (interlock) {
+       if (interlock[NV50_DISP_INTERLOCK_CORE]) {
                asyw->image.mode = 0;
                asyw->image.interval = 1;
        }
@@ -149,7 +149,7 @@ nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 *interlock,
        if (asyw->set.point) {
                if (asyw->set.point = false, asyw->set.mask)
                        interlock[wndw->interlock.type] |= wndw->interlock.data;
-               interlock[NV50_DISP_INTERLOCK_WIMM] |= wndw->interlock.data;
+               interlock[NV50_DISP_INTERLOCK_WIMM] |= wndw->interlock.wimm;
 
                wndw->immd->point(wndw, asyw);
                wndw->immd->update(wndw, interlock);
index 22cd45845e076cae1741e0575951ea80389fc6ee..7c2fcaba42d6c38932733fc3f9f39f979230f417 100644 (file)
@@ -631,7 +631,8 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
        /* We need to check that the chipset is supported before booting
         * fbdev off the hardware, as there's no way to put it back.
         */
-       ret = nvkm_device_pci_new(pdev, NULL, "error", true, false, 0, &device);
+       ret = nvkm_device_pci_new(pdev, nouveau_config, "error",
+                                 true, false, 0, &device);
        if (ret)
                return ret;
 
index 7971096b6767466e662f46c8907382c97b718b30..10d91e8bbb945f689c397b456484a0277e60f968 100644 (file)
@@ -2540,6 +2540,41 @@ nv166_chipset = {
        .sec2 = tu102_sec2_new,
 };
 
+static const struct nvkm_device_chip
+nv167_chipset = {
+       .name = "TU117",
+       .bar = tu102_bar_new,
+       .bios = nvkm_bios_new,
+       .bus = gf100_bus_new,
+       .devinit = tu102_devinit_new,
+       .fault = tu102_fault_new,
+       .fb = gv100_fb_new,
+       .fuse = gm107_fuse_new,
+       .gpio = gk104_gpio_new,
+       .gsp = gv100_gsp_new,
+       .i2c = gm200_i2c_new,
+       .ibus = gm200_ibus_new,
+       .imem = nv50_instmem_new,
+       .ltc = gp102_ltc_new,
+       .mc = tu102_mc_new,
+       .mmu = tu102_mmu_new,
+       .pci = gp100_pci_new,
+       .pmu = gp102_pmu_new,
+       .therm = gp100_therm_new,
+       .timer = gk20a_timer_new,
+       .top = gk104_top_new,
+       .ce[0] = tu102_ce_new,
+       .ce[1] = tu102_ce_new,
+       .ce[2] = tu102_ce_new,
+       .ce[3] = tu102_ce_new,
+       .ce[4] = tu102_ce_new,
+       .disp = tu102_disp_new,
+       .dma = gv100_dma_new,
+       .fifo = tu102_fifo_new,
+       .nvdec[0] = gp102_nvdec_new,
+       .sec2 = tu102_sec2_new,
+};
+
 static int
 nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size,
                       struct nvkm_notify *notify)
@@ -2824,8 +2859,8 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
        u64 mmio_base, mmio_size;
        u32 boot0, strap;
        void __iomem *map;
-       int ret = -EEXIST;
-       int i;
+       int ret = -EEXIST, i;
+       unsigned chipset;
 
        mutex_lock(&nv_devices_mutex);
        if (nvkm_device_find_locked(handle))
@@ -2870,6 +2905,26 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
                strap = ioread32_native(map + 0x101000);
                iounmap(map);
 
+               /* chipset can be overridden for devel/testing purposes */
+               chipset = nvkm_longopt(device->cfgopt, "NvChipset", 0);
+               if (chipset) {
+                       u32 override_boot0;
+
+                       if (chipset >= 0x10) {
+                               override_boot0  = ((chipset & 0x1ff) << 20);
+                               override_boot0 |= 0x000000a1;
+                       } else {
+                               if (chipset != 0x04)
+                                       override_boot0 = 0x20104000;
+                               else
+                                       override_boot0 = 0x20004000;
+                       }
+
+                       nvdev_warn(device, "CHIPSET OVERRIDE: %08x -> %08x\n",
+                                  boot0, override_boot0);
+                       boot0 = override_boot0;
+               }
+
                /* determine chipset and derive architecture from it */
                if ((boot0 & 0x1f000000) > 0) {
                        device->chipset = (boot0 & 0x1ff00000) >> 20;
@@ -2996,6 +3051,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
                case 0x162: device->chip = &nv162_chipset; break;
                case 0x164: device->chip = &nv164_chipset; break;
                case 0x166: device->chip = &nv166_chipset; break;
+               case 0x167: device->chip = &nv167_chipset; break;
                default:
                        nvdev_error(device, "unknown chipset (%08x)\n", boot0);
                        goto done;
index 5f301e632599b471c54291797b59c0d51e18be9a..818d21bd28d3122898f11d88c87bc0fec348c5ee 100644 (file)
@@ -365,8 +365,15 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps)
         * and it's better to have a failed modeset than that.
         */
        for (cfg = nvkm_dp_rates; cfg->rate; cfg++) {
-               if (cfg->nr <= outp_nr && cfg->nr <= outp_bw)
-                       failsafe = cfg;
+               if (cfg->nr <= outp_nr && cfg->nr <= outp_bw) {
+                       /* Try to respect sink limits too when selecting
+                        * lowest link configuration.
+                        */
+                       if (!failsafe ||
+                           (cfg->nr <= sink_nr && cfg->bw <= sink_bw))
+                               failsafe = cfg;
+               }
+
                if (failsafe && cfg[1].rate < dataKBps)
                        break;
        }
index 970f669c6d29336ce513d2e1df12219030a3c17a..3b2bced1b015813949f8fda5a7dd8f51a8d37b35 100644 (file)
@@ -165,6 +165,10 @@ err_out0:
 
 void panfrost_device_fini(struct panfrost_device *pfdev)
 {
+       panfrost_job_fini(pfdev);
+       panfrost_mmu_fini(pfdev);
+       panfrost_gpu_fini(pfdev);
+       panfrost_reset_fini(pfdev);
        panfrost_regulator_fini(pfdev);
        panfrost_clk_fini(pfdev);
 }
index 94b0819ad50b70c6f5248f8eb51e92f3bd13c37a..d11e2281dde625d57fd7f544b6bd55481a6baeee 100644 (file)
@@ -219,7 +219,8 @@ static int panfrost_ioctl_submit(struct drm_device *dev, void *data,
 fail_job:
        panfrost_job_put(job);
 fail_out_sync:
-       drm_syncobj_put(sync_out);
+       if (sync_out)
+               drm_syncobj_put(sync_out);
 
        return ret;
 }
index 0c5d391f0a8f3a77b527301fcd91c7817f53bd5b..4501597f30ab1b310052631df0929bcf45cf1724 100644 (file)
@@ -531,14 +531,15 @@ pl111_init_clock_divider(struct drm_device *drm)
                dev_err(drm->dev, "CLCD: unable to get clcdclk.\n");
                return PTR_ERR(parent);
        }
+
+       spin_lock_init(&priv->tim2_lock);
+
        /* If the clock divider is broken, use the parent directly */
        if (priv->variant->broken_clockdivider) {
                priv->clk = parent;
                return 0;
        }
        parent_name = __clk_get_name(parent);
-
-       spin_lock_init(&priv->tim2_lock);
        div->init = &init;
 
        ret = devm_clk_hw_register(drm->dev, div);
index aa898c699101c90e3274cc4c193f52c3847bbf84..433df7036f96726431ffdbd9d2ed0d528482f11e 100644 (file)
@@ -922,12 +922,12 @@ static void avivo_get_fb_ref_div(unsigned nom, unsigned den, unsigned post_div,
        ref_div_max = max(min(100 / post_div, ref_div_max), 1u);
 
        /* get matching reference and feedback divider */
-       *ref_div = min(max(DIV_ROUND_CLOSEST(den, post_div), 1u), ref_div_max);
+       *ref_div = min(max(den/post_div, 1u), ref_div_max);
        *fb_div = DIV_ROUND_CLOSEST(nom * *ref_div * post_div, den);
 
        /* limit fb divider to its maximum */
        if (*fb_div > fb_div_max) {
-               *ref_div = DIV_ROUND_CLOSEST(*ref_div * fb_div_max, *fb_div);
+               *ref_div = (*ref_div * fb_div_max)/(*fb_div);
                *fb_div = fb_div_max;
        }
 }
index b3019505065ab2d2591aad3fb077b9a6183a5a10..c9bd1278f57391bcb145cdc7686d016a65a8ca12 100644 (file)
@@ -133,7 +133,7 @@ static int radeon_mn_invalidate_range_start(struct mmu_notifier *mn,
        /* TODO we should be able to split locking for interval tree and
         * the tear down.
         */
-       if (range->blockable)
+       if (mmu_notifier_range_blockable(range))
                mutex_lock(&rmn->lock);
        else if (!mutex_trylock(&rmn->lock))
                return -EAGAIN;
@@ -144,7 +144,7 @@ static int radeon_mn_invalidate_range_start(struct mmu_notifier *mn,
                struct radeon_bo *bo;
                long r;
 
-               if (!range->blockable) {
+               if (!mmu_notifier_range_blockable(range)) {
                        ret = -EAGAIN;
                        goto out_unlock;
                }
index a8db758d523e94780584090b191625ffdcd28a16..a2ebb08990e9b21142c4e3d1dfb864a1cc877ada 100644 (file)
@@ -221,26 +221,13 @@ static int rockchip_drm_gem_object_mmap_iommu(struct drm_gem_object *obj,
                                              struct vm_area_struct *vma)
 {
        struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
-       unsigned int i, count = obj->size >> PAGE_SHIFT;
+       unsigned int count = obj->size >> PAGE_SHIFT;
        unsigned long user_count = vma_pages(vma);
-       unsigned long uaddr = vma->vm_start;
-       unsigned long offset = vma->vm_pgoff;
-       unsigned long end = user_count + offset;
-       int ret;
 
        if (user_count == 0)
                return -ENXIO;
-       if (end > count)
-               return -ENXIO;
 
-       for (i = offset; i < end; i++) {
-               ret = vm_insert_page(vma, uaddr, rk_obj->pages[i]);
-               if (ret)
-                       return ret;
-               uaddr += PAGE_SIZE;
-       }
-
-       return 0;
+       return vm_map_pages(vma, rk_obj->pages, count);
 }
 
 static int rockchip_drm_gem_object_mmap_dma(struct drm_gem_object *obj,
index 61bbe8e8bcc51db98f064aca875b97f6c96add9b..e2a6c82c8252d8a291431d94b288aca989d2624f 100644 (file)
@@ -4,7 +4,6 @@ config DRM_SHMOBILE
        depends on DRM && ARM
        depends on ARCH_SHMOBILE || COMPILE_TEST
        select BACKLIGHT_CLASS_DEVICE
-       select BACKLIGHT_LCD_SUPPORT
        select DRM_KMS_HELPER
        select DRM_KMS_CMA_HELPER
        select DRM_GEM_CMA_HELPER
index fb985ba1a17613f99bd36c66a8a5e0822c7fd6a6..2598741a00a6e6b5d6e72689243db9de0646f444 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/io.h>
 
 #include "sun4i_hdmi.h"
 
index 52598049c096eb4d5d6d550ac6ef5d00d823d980..cb7df2086aee3b1c681eb497c9a6c3abc5b98f29 100644 (file)
@@ -8,7 +8,6 @@ config DRM_TILCDC
        select DRM_PANEL_BRIDGE
        select VIDEOMODE_HELPERS
        select BACKLIGHT_CLASS_DEVICE
-       select BACKLIGHT_LCD_SUPPORT
        help
          Choose this option if you have an TI SoC with LCDC display
          controller, for example AM33xx in beagle-bone, DA8xx, or
index 9412709067f581883128abd2890a09b8977ca181..2ea4e20b7b8a437bd9eaca5ecbb8cc42a16d6175 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/component.h>
 #include <linux/dmaengine.h>
 #include <linux/i2c.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
index 8bf3a7c23ed369e76f06b9e8a46969651ba447b1..062067438f1d0671db48dbab9f1680f3bc207849 100644 (file)
@@ -243,7 +243,8 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg,  drm_via_dmablit_t *xfer)
        if (NULL == vsg->pages)
                return -ENOMEM;
        ret = get_user_pages_fast((unsigned long)xfer->mem_addr,
-                       vsg->num_pages, vsg->direction == DMA_FROM_DEVICE,
+                       vsg->num_pages,
+                       vsg->direction == DMA_FROM_DEVICE ? FOLL_WRITE : 0,
                        vsg->pages);
        if (ret != vsg->num_pages) {
                if (ret < 0)
index 53c376d55fcf5089010e4741637ab55f2679afb9..a24548489ddeaf3ae04d1ad811d40c1e1204ce38 100644 (file)
@@ -224,8 +224,7 @@ xen_drm_front_gem_import_sg_table(struct drm_device *dev,
 static int gem_mmap_obj(struct xen_gem_object *xen_obj,
                        struct vm_area_struct *vma)
 {
-       unsigned long addr = vma->vm_start;
-       int i;
+       int ret;
 
        /*
         * clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
@@ -252,18 +251,11 @@ static int gem_mmap_obj(struct xen_gem_object *xen_obj,
         * FIXME: as we insert all the pages now then no .fault handler must
         * be called, so don't provide one
         */
-       for (i = 0; i < xen_obj->num_pages; i++) {
-               int ret;
-
-               ret = vm_insert_page(vma, addr, xen_obj->pages[i]);
-               if (ret < 0) {
-                       DRM_ERROR("Failed to insert pages into vma: %d\n", ret);
-                       return ret;
-               }
+       ret = vm_map_pages(vma, xen_obj->pages, xen_obj->num_pages);
+       if (ret < 0)
+               DRM_ERROR("Failed to map pages into vma: %d\n", ret);
 
-               addr += PAGE_SIZE;
-       }
-       return 0;
+       return ret;
 }
 
 int xen_drm_front_gem_mmap(struct file *filp, struct vm_area_struct *vma)
index 46c6efea1404ee664eb2e44837e09c67553fc5c3..abdb01879caa89866b69196b452a8cb7f855f0bb 100644 (file)
@@ -1051,6 +1051,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                case 0x28b: map_key_clear(KEY_FORWARDMAIL);     break;
                case 0x28c: map_key_clear(KEY_SEND);            break;
 
+               case 0x29d: map_key_clear(KEY_KBD_LAYOUT_NEXT); break;
+
                case 0x2c7: map_key_clear(KEY_KBDINPUTASSIST_PREV);             break;
                case 0x2c8: map_key_clear(KEY_KBDINPUTASSIST_NEXT);             break;
                case 0x2c9: map_key_clear(KEY_KBDINPUTASSIST_PREVGROUP);                break;
index c4dd6301e7c82e62660cc7a5bded3d30a663d0cf..0daf0b32aa4acdccdc58d152ece54dd37925ae21 100644 (file)
@@ -830,10 +830,8 @@ static int aspeed_create_pwm_cooling(struct device *dev,
        }
        snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%pOFn%d", child, pwm_port);
 
-       cdev->tcdev = thermal_of_cooling_device_register(child,
-                                                        cdev->name,
-                                                        cdev,
-                                                        &aspeed_pwm_cool_ops);
+       cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child,
+                                       cdev->name, cdev, &aspeed_pwm_cool_ops);
        if (IS_ERR(cdev->tcdev))
                return PTR_ERR(cdev->tcdev);
 
index f1bf67aca9e8be69d2f49cc79a3cac7ef2cfc979..3f6e5b4e399736fc32a868ad66645656ecaa406b 100644 (file)
@@ -498,6 +498,11 @@ static const struct of_device_id of_gpio_fan_match[] = {
 };
 MODULE_DEVICE_TABLE(of, of_gpio_fan_match);
 
+static void gpio_fan_stop(void *data)
+{
+       set_fan_speed(data, 0);
+}
+
 static int gpio_fan_probe(struct platform_device *pdev)
 {
        int err;
@@ -532,6 +537,7 @@ static int gpio_fan_probe(struct platform_device *pdev)
                err = fan_ctrl_init(fan_data);
                if (err)
                        return err;
+               devm_add_action_or_reset(dev, gpio_fan_stop, fan_data);
        }
 
        /* Make this driver part of hwmon class. */
@@ -543,32 +549,20 @@ static int gpio_fan_probe(struct platform_device *pdev)
                return PTR_ERR(fan_data->hwmon_dev);
 
        /* Optional cooling device register for Device tree platforms */
-       fan_data->cdev = thermal_of_cooling_device_register(np,
-                                                           "gpio-fan",
-                                                           fan_data,
-                                                           &gpio_fan_cool_ops);
+       fan_data->cdev = devm_thermal_of_cooling_device_register(dev, np,
+                               "gpio-fan", fan_data, &gpio_fan_cool_ops);
 
        dev_info(dev, "GPIO fan initialized\n");
 
        return 0;
 }
 
-static int gpio_fan_remove(struct platform_device *pdev)
+static void gpio_fan_shutdown(struct platform_device *pdev)
 {
        struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
 
-       if (!IS_ERR(fan_data->cdev))
-               thermal_cooling_device_unregister(fan_data->cdev);
-
        if (fan_data->gpios)
                set_fan_speed(fan_data, 0);
-
-       return 0;
-}
-
-static void gpio_fan_shutdown(struct platform_device *pdev)
-{
-       gpio_fan_remove(pdev);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -602,7 +596,6 @@ static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
 
 static struct platform_driver gpio_fan_driver = {
        .probe          = gpio_fan_probe,
-       .remove         = gpio_fan_remove,
        .shutdown       = gpio_fan_shutdown,
        .driver = {
                .name   = "gpio-fan",
index cd91510a5387d604b86e28af721f3002072b8f70..e694c46ff039cce3c38cfee073d92d0e1b0f4b40 100644 (file)
@@ -118,9 +118,7 @@ static DEFINE_IDA(hwmon_ida);
  * The complex conditional is necessary to avoid a cyclic dependency
  * between hwmon and thermal_sys modules.
  */
-#if IS_REACHABLE(CONFIG_THERMAL) && defined(CONFIG_THERMAL_OF) && \
-       (!defined(CONFIG_THERMAL_HWMON) || \
-        !(defined(MODULE) && IS_MODULE(CONFIG_THERMAL)))
+#ifdef CONFIG_THERMAL_OF
 static int hwmon_thermal_get_temp(void *data, int *temp)
 {
        struct hwmon_thermal_data *tdata = data;
index f816d2ae1e58108ac77c0da93d8455e0411011d5..ed8d59d4eecb361c288b0926f222ec1e380634ea 100644 (file)
@@ -465,42 +465,42 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
 static int mlxreg_fan_probe(struct platform_device *pdev)
 {
        struct mlxreg_core_platform_data *pdata;
+       struct device *dev = &pdev->dev;
        struct mlxreg_fan *fan;
        struct device *hwm;
        int err;
 
-       pdata = dev_get_platdata(&pdev->dev);
+       pdata = dev_get_platdata(dev);
        if (!pdata) {
-               dev_err(&pdev->dev, "Failed to get platform data.\n");
+               dev_err(dev, "Failed to get platform data.\n");
                return -EINVAL;
        }
 
-       fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
+       fan = devm_kzalloc(dev, sizeof(*fan), GFP_KERNEL);
        if (!fan)
                return -ENOMEM;
 
-       fan->dev = &pdev->dev;
+       fan->dev = dev;
        fan->regmap = pdata->regmap;
-       platform_set_drvdata(pdev, fan);
 
        err = mlxreg_fan_config(fan, pdata);
        if (err)
                return err;
 
-       hwm = devm_hwmon_device_register_with_info(&pdev->dev, "mlxreg_fan",
+       hwm = devm_hwmon_device_register_with_info(dev, "mlxreg_fan",
                                                   fan,
                                                   &mlxreg_fan_hwmon_chip_info,
                                                   NULL);
        if (IS_ERR(hwm)) {
-               dev_err(&pdev->dev, "Failed to register hwmon device\n");
+               dev_err(dev, "Failed to register hwmon device\n");
                return PTR_ERR(hwm);
        }
 
        if (IS_REACHABLE(CONFIG_THERMAL)) {
-               fan->cdev = thermal_cooling_device_register("mlxreg_fan", fan,
-                                               &mlxreg_fan_cooling_ops);
+               fan->cdev = devm_thermal_of_cooling_device_register(dev,
+                       NULL, "mlxreg_fan", fan, &mlxreg_fan_cooling_ops);
                if (IS_ERR(fan->cdev)) {
-                       dev_err(&pdev->dev, "Failed to register cooling device\n");
+                       dev_err(dev, "Failed to register cooling device\n");
                        return PTR_ERR(fan->cdev);
                }
        }
@@ -508,22 +508,11 @@ static int mlxreg_fan_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int mlxreg_fan_remove(struct platform_device *pdev)
-{
-       struct mlxreg_fan *fan = platform_get_drvdata(pdev);
-
-       if (IS_REACHABLE(CONFIG_THERMAL))
-               thermal_cooling_device_unregister(fan->cdev);
-
-       return 0;
-}
-
 static struct platform_driver mlxreg_fan_driver = {
        .driver = {
            .name = "mlxreg-fan",
        },
        .probe = mlxreg_fan_probe,
-       .remove = mlxreg_fan_remove,
 };
 
 module_platform_driver(mlxreg_fan_driver);
index 1dc0cd452498de52a5465a57028289079d4f25f6..09aaefa6fdb8c192e561d720dab6cc7d65a40138 100644 (file)
@@ -846,10 +846,8 @@ static int npcm7xx_create_pwm_cooling(struct device *dev,
        snprintf(cdev->name, THERMAL_NAME_LENGTH, "%pOFn%d", child,
                 pwm_port);
 
-       cdev->tcdev = thermal_of_cooling_device_register(child,
-                                                        cdev->name,
-                                                        cdev,
-                                                        &npcm7xx_pwm_cool_ops);
+       cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child,
+                               cdev->name, cdev, &npcm7xx_pwm_cool_ops);
        if (IS_ERR(cdev->tcdev))
                return PTR_ERR(cdev->tcdev);
 
index eead8afe6447b2b31324975f050fc0b6204a1bec..5fb2745f0226a66273d87e39e5b6303a9a994aad 100644 (file)
@@ -273,27 +273,40 @@ static int pwm_fan_of_get_cooling_data(struct device *dev,
        return 0;
 }
 
+static void pwm_fan_regulator_disable(void *data)
+{
+       regulator_disable(data);
+}
+
+static void pwm_fan_pwm_disable(void *__ctx)
+{
+       struct pwm_fan_ctx *ctx = __ctx;
+       pwm_disable(ctx->pwm);
+       del_timer_sync(&ctx->rpm_timer);
+}
+
 static int pwm_fan_probe(struct platform_device *pdev)
 {
        struct thermal_cooling_device *cdev;
+       struct device *dev = &pdev->dev;
        struct pwm_fan_ctx *ctx;
        struct device *hwmon;
        int ret;
        struct pwm_state state = { };
        u32 ppr = 2;
 
-       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
        mutex_init(&ctx->lock);
 
-       ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL);
+       ctx->pwm = devm_of_pwm_get(dev, dev->of_node, NULL);
        if (IS_ERR(ctx->pwm)) {
                ret = PTR_ERR(ctx->pwm);
 
                if (ret != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "Could not get PWM: %d\n", ret);
+                       dev_err(dev, "Could not get PWM: %d\n", ret);
 
                return ret;
        }
@@ -304,7 +317,7 @@ static int pwm_fan_probe(struct platform_device *pdev)
        if (ctx->irq == -EPROBE_DEFER)
                return ctx->irq;
 
-       ctx->reg_en = devm_regulator_get_optional(&pdev->dev, "fan");
+       ctx->reg_en = devm_regulator_get_optional(dev, "fan");
        if (IS_ERR(ctx->reg_en)) {
                if (PTR_ERR(ctx->reg_en) != -ENODEV)
                        return PTR_ERR(ctx->reg_en);
@@ -313,10 +326,11 @@ static int pwm_fan_probe(struct platform_device *pdev)
        } else {
                ret = regulator_enable(ctx->reg_en);
                if (ret) {
-                       dev_err(&pdev->dev,
-                               "Failed to enable fan supply: %d\n", ret);
+                       dev_err(dev, "Failed to enable fan supply: %d\n", ret);
                        return ret;
                }
+               devm_add_action_or_reset(dev, pwm_fan_regulator_disable,
+                                        ctx->reg_en);
        }
 
        ctx->pwm_value = MAX_PWM;
@@ -328,91 +342,57 @@ static int pwm_fan_probe(struct platform_device *pdev)
 
        ret = pwm_apply_state(ctx->pwm, &state);
        if (ret) {
-               dev_err(&pdev->dev, "Failed to configure PWM: %d\n", ret);
-               goto err_reg_disable;
+               dev_err(dev, "Failed to configure PWM: %d\n", ret);
+               return ret;
        }
-
        timer_setup(&ctx->rpm_timer, sample_timer, 0);
+       devm_add_action_or_reset(dev, pwm_fan_pwm_disable, ctx);
 
-       of_property_read_u32(pdev->dev.of_node, "pulses-per-revolution", &ppr);
+       of_property_read_u32(dev->of_node, "pulses-per-revolution", &ppr);
        ctx->pulses_per_revolution = ppr;
        if (!ctx->pulses_per_revolution) {
-               dev_err(&pdev->dev, "pulses-per-revolution can't be zero.\n");
-               ret = -EINVAL;
-               goto err_pwm_disable;
+               dev_err(dev, "pulses-per-revolution can't be zero.\n");
+               return -EINVAL;
        }
 
        if (ctx->irq > 0) {
-               ret = devm_request_irq(&pdev->dev, ctx->irq, pulse_handler, 0,
+               ret = devm_request_irq(dev, ctx->irq, pulse_handler, 0,
                                       pdev->name, ctx);
                if (ret) {
-                       dev_err(&pdev->dev,
-                               "Failed to request interrupt: %d\n", ret);
-                       goto err_pwm_disable;
+                       dev_err(dev, "Failed to request interrupt: %d\n", ret);
+                       return ret;
                }
                ctx->sample_start = ktime_get();
                mod_timer(&ctx->rpm_timer, jiffies + HZ);
        }
 
-       hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, "pwmfan",
+       hwmon = devm_hwmon_device_register_with_groups(dev, "pwmfan",
                                                       ctx, pwm_fan_groups);
        if (IS_ERR(hwmon)) {
-               ret = PTR_ERR(hwmon);
-               dev_err(&pdev->dev,
-                       "Failed to register hwmon device: %d\n", ret);
-               goto err_del_timer;
+               dev_err(dev, "Failed to register hwmon device\n");
+               return PTR_ERR(hwmon);
        }
 
-       ret = pwm_fan_of_get_cooling_data(&pdev->dev, ctx);
+       ret = pwm_fan_of_get_cooling_data(dev, ctx);
        if (ret)
-               goto err_del_timer;
+               return ret;
 
        ctx->pwm_fan_state = ctx->pwm_fan_max_state;
        if (IS_ENABLED(CONFIG_THERMAL)) {
-               cdev = thermal_of_cooling_device_register(pdev->dev.of_node,
-                                                         "pwm-fan", ctx,
-                                                         &pwm_fan_cooling_ops);
+               cdev = devm_thermal_of_cooling_device_register(dev,
+                       dev->of_node, "pwm-fan", ctx, &pwm_fan_cooling_ops);
                if (IS_ERR(cdev)) {
                        ret = PTR_ERR(cdev);
-                       dev_err(&pdev->dev,
+                       dev_err(dev,
                                "Failed to register pwm-fan as cooling device: %d\n",
                                ret);
-                       goto err_del_timer;
+                       return ret;
                }
                ctx->cdev = cdev;
                thermal_cdev_update(cdev);
        }
 
        return 0;
-
-err_del_timer:
-       del_timer_sync(&ctx->rpm_timer);
-
-err_pwm_disable:
-       state.enabled = false;
-       pwm_apply_state(ctx->pwm, &state);
-
-err_reg_disable:
-       if (ctx->reg_en)
-               regulator_disable(ctx->reg_en);
-
-       return ret;
-}
-
-static int pwm_fan_remove(struct platform_device *pdev)
-{
-       struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev);
-
-       thermal_cooling_device_unregister(ctx->cdev);
-       del_timer_sync(&ctx->rpm_timer);
-
-       if (ctx->pwm_value)
-               pwm_disable(ctx->pwm);
-
-       if (ctx->reg_en)
-               regulator_disable(ctx->reg_en);
-
-       return 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -480,7 +460,6 @@ MODULE_DEVICE_TABLE(of, of_pwm_fan_match);
 
 static struct platform_driver pwm_fan_driver = {
        .probe          = pwm_fan_probe,
-       .remove         = pwm_fan_remove,
        .driver = {
                .name           = "pwm-fan",
                .pm             = &pwm_fan_pm,
index 06ca3f7fcc4455ccc6732304356c53920d43fbc4..4a5eff3f18bcd34b39162b377fbc3707d12338ac 100644 (file)
@@ -733,11 +733,11 @@ static int iio_channel_read_avail(struct iio_channel *chan,
                                                 vals, type, length, info);
 }
 
-int iio_read_avail_channel_raw(struct iio_channel *chan,
-                              const int **vals, int *length)
+int iio_read_avail_channel_attribute(struct iio_channel *chan,
+                                    const int **vals, int *type, int *length,
+                                    enum iio_chan_info_enum attribute)
 {
        int ret;
-       int type;
 
        mutex_lock(&chan->indio_dev->info_exist_lock);
        if (!chan->indio_dev->info) {
@@ -745,11 +745,23 @@ int iio_read_avail_channel_raw(struct iio_channel *chan,
                goto err_unlock;
        }
 
-       ret = iio_channel_read_avail(chan,
-                                    vals, &type, length, IIO_CHAN_INFO_RAW);
+       ret = iio_channel_read_avail(chan, vals, type, length, attribute);
 err_unlock:
        mutex_unlock(&chan->indio_dev->info_exist_lock);
 
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iio_read_avail_channel_attribute);
+
+int iio_read_avail_channel_raw(struct iio_channel *chan,
+                              const int **vals, int *length)
+{
+       int ret;
+       int type;
+
+       ret = iio_read_avail_channel_attribute(chan, vals, &type, length,
+                                        IIO_CHAN_INFO_RAW);
+
        if (ret >= 0 && type != IIO_VAL_INT)
                /* raw values are assumed to be IIO_VAL_INT */
                ret = -EINVAL;
index ba01b90c04e7756391c966b900a87f52adc69e44..2f7d14159841f833e26a1974c4e14b5be15f7677 100644 (file)
@@ -731,8 +731,8 @@ int roce_resolve_route_from_path(struct sa_path_rec *rec,
        if (rec->roce.route_resolved)
                return 0;
 
-       rdma_gid2ip(&sgid._sockaddr, &rec->sgid);
-       rdma_gid2ip(&dgid._sockaddr, &rec->dgid);
+       rdma_gid2ip((struct sockaddr *)&sgid, &rec->sgid);
+       rdma_gid2ip((struct sockaddr *)&dgid, &rec->dgid);
 
        if (sgid._sockaddr.sa_family != dgid._sockaddr.sa_family)
                return -EINVAL;
@@ -743,7 +743,7 @@ int roce_resolve_route_from_path(struct sa_path_rec *rec,
        dev_addr.net = &init_net;
        dev_addr.sgid_attr = attr;
 
-       ret = addr_resolve(&sgid._sockaddr, &dgid._sockaddr,
+       ret = addr_resolve((struct sockaddr *)&sgid, (struct sockaddr *)&dgid,
                           &dev_addr, false, true, 0);
        if (ret)
                return ret;
@@ -815,22 +815,22 @@ int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,
        struct rdma_dev_addr dev_addr;
        struct resolve_cb_context ctx;
        union {
-               struct sockaddr     _sockaddr;
                struct sockaddr_in  _sockaddr_in;
                struct sockaddr_in6 _sockaddr_in6;
        } sgid_addr, dgid_addr;
        int ret;
 
-       rdma_gid2ip(&sgid_addr._sockaddr, sgid);
-       rdma_gid2ip(&dgid_addr._sockaddr, dgid);
+       rdma_gid2ip((struct sockaddr *)&sgid_addr, sgid);
+       rdma_gid2ip((struct sockaddr *)&dgid_addr, dgid);
 
        memset(&dev_addr, 0, sizeof(dev_addr));
        dev_addr.net = &init_net;
        dev_addr.sgid_attr = sgid_attr;
 
        init_completion(&ctx.comp);
-       ret = rdma_resolve_ip(&sgid_addr._sockaddr, &dgid_addr._sockaddr,
-                             &dev_addr, 1000, resolve_cb, true, &ctx);
+       ret = rdma_resolve_ip((struct sockaddr *)&sgid_addr,
+                             (struct sockaddr *)&dgid_addr, &dev_addr, 1000,
+                             resolve_cb, true, &ctx);
        if (ret)
                return ret;
 
index 98eadd3089cead9a73b54f876b7ffdfa202f441c..69188cbbd99bd53ffbf4e49e738805dc240344fa 100644 (file)
@@ -1347,32 +1347,35 @@ static int nldev_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
        return 0;
 }
 
-static int nldev_get_sys_get_dumpit(struct sk_buff *skb,
-                                   struct netlink_callback *cb)
+static int nldev_sys_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+                             struct netlink_ext_ack *extack)
 {
        struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
-       struct nlmsghdr *nlh;
+       struct sk_buff *msg;
        int err;
 
-       err = nlmsg_parse(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
-                         nldev_policy, NULL);
+       err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
+                         nldev_policy, extack);
        if (err)
                return err;
 
-       nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
                        RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
                                         RDMA_NLDEV_CMD_SYS_GET),
                        0, 0);
 
-       err = nla_put_u8(skb, RDMA_NLDEV_SYS_ATTR_NETNS_MODE,
+       err = nla_put_u8(msg, RDMA_NLDEV_SYS_ATTR_NETNS_MODE,
                         (u8)ib_devices_shared_netns);
        if (err) {
-               nlmsg_cancel(skb, nlh);
+               nlmsg_free(msg);
                return err;
        }
-
-       nlmsg_end(skb, nlh);
-       return skb->len;
+       nlmsg_end(msg, nlh);
+       return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
 }
 
 static int nldev_set_sys_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -1442,7 +1445,7 @@ static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = {
                .dump = nldev_res_get_pd_dumpit,
        },
        [RDMA_NLDEV_CMD_SYS_GET] = {
-               .dump = nldev_get_sys_get_dumpit,
+               .doit = nldev_sys_get_doit,
        },
        [RDMA_NLDEV_CMD_SYS_SET] = {
                .doit = nldev_set_sys_set_doit,
index 0a23048db523a16cc849ad71445a32aeb8d953b4..e7ea819fcb116dd8bb45a34160af950f4b87316d 100644 (file)
@@ -295,10 +295,11 @@ struct ib_umem *ib_umem_get(struct ib_udata *udata, unsigned long addr,
 
        while (npages) {
                down_read(&mm->mmap_sem);
-               ret = get_user_pages_longterm(cur_base,
+               ret = get_user_pages(cur_base,
                                     min_t(unsigned long, npages,
                                           PAGE_SIZE / sizeof (struct page *)),
-                                    gup_flags, page_list, NULL);
+                                    gup_flags | FOLL_LONGTERM,
+                                    page_list, NULL);
                if (ret < 0) {
                        up_read(&mm->mmap_sem);
                        goto umem_release;
index c7226cf52acc2f2d146efac2ffa9d3405f2303d0..f962b5bbfa40e4268de37f99c78b6653895c9599 100644 (file)
@@ -152,7 +152,7 @@ static int ib_umem_notifier_invalidate_range_start(struct mmu_notifier *mn,
        struct ib_ucontext_per_mm *per_mm =
                container_of(mn, struct ib_ucontext_per_mm, mn);
 
-       if (range->blockable)
+       if (mmu_notifier_range_blockable(range))
                down_read(&per_mm->umem_rwsem);
        else if (!down_read_trylock(&per_mm->umem_rwsem))
                return -EAGAIN;
@@ -170,7 +170,8 @@ static int ib_umem_notifier_invalidate_range_start(struct mmu_notifier *mn,
        return rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, range->start,
                                             range->end,
                                             invalidate_range_start_trampoline,
-                                            range->blockable, NULL);
+                                            mmu_notifier_range_blockable(range),
+                                            NULL);
 }
 
 static int invalidate_range_end_trampoline(struct ib_umem_odp *item, u64 start,
index 24b592c6522e17db62faa05c5a611d35f293c6da..02eee8eff1db138d69d1dc4c2b8c29f4b3a8b599 100644 (file)
@@ -104,8 +104,9 @@ int hfi1_acquire_user_pages(struct mm_struct *mm, unsigned long vaddr, size_t np
                            bool writable, struct page **pages)
 {
        int ret;
+       unsigned int gup_flags = FOLL_LONGTERM | (writable ? FOLL_WRITE : 0);
 
-       ret = get_user_pages_fast(vaddr, npages, writable, pages);
+       ret = get_user_pages_fast(vaddr, npages, gup_flags, pages);
        if (ret < 0)
                return ret;
 
index 169ffffcf5ed73ce939863b367961a059adbfbd7..80b42d0693286084bcc1670f838dff218e00bc0e 100644 (file)
@@ -154,7 +154,7 @@ bool mlx5_ib_devx_is_flow_counter(void *obj, u32 *counter_id)
  * must be considered upon checking for a valid object id.
  * For that the opcode of the creator command is encoded as part of the obj_id.
  */
-static u64 get_enc_obj_id(u16 opcode, u32 obj_id)
+static u64 get_enc_obj_id(u32 opcode, u32 obj_id)
 {
        return ((u64)opcode << 32) | obj_id;
 }
@@ -167,7 +167,9 @@ static u64 devx_get_obj_id(const void *in)
        switch (opcode) {
        case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT:
        case MLX5_CMD_OP_QUERY_GENERAL_OBJECT:
-               obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_GENERAL_OBJECT,
+               obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_GENERAL_OBJECT |
+                                       MLX5_GET(general_obj_in_cmd_hdr, in,
+                                                obj_type) << 16,
                                        MLX5_GET(general_obj_in_cmd_hdr, in,
                                                 obj_id));
                break;
@@ -1171,6 +1173,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
        struct mlx5_ib_dev *dev = to_mdev(c->ibucontext.device);
        u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
        struct devx_obj *obj;
+       u16 obj_type = 0;
        int err;
        int uid;
        u32 obj_id;
@@ -1230,7 +1233,11 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
        if (err)
                goto err_copy;
 
-       obj->obj_id = get_enc_obj_id(opcode, obj_id);
+       if (opcode == MLX5_CMD_OP_CREATE_GENERAL_OBJECT)
+               obj_type = MLX5_GET(general_obj_in_cmd_hdr, cmd_in, obj_type);
+
+       obj->obj_id = get_enc_obj_id(opcode | obj_type << 16, obj_id);
+
        return 0;
 
 err_copy:
index 112d2f38e0de65a84d77e5d97a655c707e49404e..8ff0e90d756485764645de4259c9e6945402b68c 100644 (file)
@@ -472,7 +472,8 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
                goto out;
        }
 
-       ret = get_user_pages_fast(uaddr & PAGE_MASK, 1, FOLL_WRITE, pages);
+       ret = get_user_pages_fast(uaddr & PAGE_MASK, 1,
+                                 FOLL_WRITE | FOLL_LONGTERM, pages);
        if (ret < 0)
                goto out;
 
index 1d4ea135c28f2a0337a6a73f1e27a79319904af8..8d3e36d548aae91264bd797e84106e84a14c41ec 100644 (file)
@@ -83,7 +83,6 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
        struct iphdr ipv4;
        const struct ib_global_route *ib_grh;
        union {
-               struct sockaddr     _sockaddr;
                struct sockaddr_in  _sockaddr_in;
                struct sockaddr_in6 _sockaddr_in6;
        } sgid_addr, dgid_addr;
@@ -133,9 +132,9 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
                ipv4.tot_len = htons(0);
                ipv4.ttl = ib_grh->hop_limit;
                ipv4.protocol = nxthdr;
-               rdma_gid2ip(&sgid_addr._sockaddr, sgid);
+               rdma_gid2ip((struct sockaddr *)&sgid_addr, sgid);
                ipv4.saddr = sgid_addr._sockaddr_in.sin_addr.s_addr;
-               rdma_gid2ip(&dgid_addr._sockaddr, &ib_grh->dgid);
+               rdma_gid2ip((struct sockaddr*)&dgid_addr, &ib_grh->dgid);
                ipv4.daddr = dgid_addr._sockaddr_in.sin_addr.s_addr;
                memcpy((u8 *)ah->av + eth_sz, &ipv4, sizeof(struct iphdr));
        } else {
index 32674b291f60da3e3c7267a33addfd780da1e207..5127e2ea4bdd2d510153ae06c81f28b72f52e88b 100644 (file)
@@ -2499,7 +2499,6 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
        u16 vlan_id = 0xFFFF;
        u8 mac_addr[6], hdr_type;
        union {
-               struct sockaddr     _sockaddr;
                struct sockaddr_in  _sockaddr_in;
                struct sockaddr_in6 _sockaddr_in6;
        } sgid_addr, dgid_addr;
@@ -2542,8 +2541,8 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
 
        hdr_type = rdma_gid_attr_network_type(sgid_attr);
        if (hdr_type == RDMA_NETWORK_IPV4) {
-               rdma_gid2ip(&sgid_addr._sockaddr, &sgid_attr->gid);
-               rdma_gid2ip(&dgid_addr._sockaddr, &grh->dgid);
+               rdma_gid2ip((struct sockaddr *)&sgid_addr, &sgid_attr->gid);
+               rdma_gid2ip((struct sockaddr *)&dgid_addr, &grh->dgid);
                memcpy(&cmd->params.dgid[0],
                       &dgid_addr._sockaddr_in.sin_addr.s_addr, 4);
                memcpy(&cmd->params.sgid[0],
index 123ca8f64f75d28a51d889d2b5116de308a3f418..f712fb7fa82f995b2bbef7c24ddc7bb29cada4f2 100644 (file)
@@ -114,10 +114,10 @@ int qib_get_user_pages(unsigned long start_page, size_t num_pages,
 
        down_read(&current->mm->mmap_sem);
        for (got = 0; got < num_pages; got += ret) {
-               ret = get_user_pages_longterm(start_page + got * PAGE_SIZE,
-                                             num_pages - got,
-                                             FOLL_WRITE | FOLL_FORCE,
-                                             p + got, NULL);
+               ret = get_user_pages(start_page + got * PAGE_SIZE,
+                                    num_pages - got,
+                                    FOLL_LONGTERM | FOLL_WRITE | FOLL_FORCE,
+                                    p + got, NULL);
                if (ret < 0) {
                        up_read(&current->mm->mmap_sem);
                        goto bail_release;
index ef19d39a44b14b15ecaecdd13997bf3c8f1eef31..0c204776263f2da7911126de46a37ff7219a3fcc 100644 (file)
@@ -670,7 +670,7 @@ static int qib_user_sdma_pin_pages(const struct qib_devdata *dd,
                else
                        j = npages;
 
-               ret = get_user_pages_fast(addr, j, 0, pages);
+               ret = get_user_pages_fast(addr, j, FOLL_LONGTERM, pages);
                if (ret != j) {
                        i = 0;
                        j = ret;
index da35d6fdfc5ebde945464304e32af5605a6319c8..e312f522a66de7a3e333d931955474bcaf907916 100644 (file)
@@ -143,10 +143,11 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
        ret = 0;
 
        while (npages) {
-               ret = get_user_pages_longterm(cur_base,
-                                       min_t(unsigned long, npages,
-                                       PAGE_SIZE / sizeof(struct page *)),
-                                       gup_flags, page_list, NULL);
+               ret = get_user_pages(cur_base,
+                                    min_t(unsigned long, npages,
+                                    PAGE_SIZE / sizeof(struct page *)),
+                                    gup_flags | FOLL_LONGTERM,
+                                    page_list, NULL);
 
                if (ret < 0)
                        goto out;
index f040d8881ff2a2db34d56a816026e69524239f3b..d1e25aba8212ad3c19f66bbd704835406e78d065 100644 (file)
@@ -503,14 +503,13 @@ static int evdev_open(struct inode *inode, struct file *file)
 {
        struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);
        unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev);
-       unsigned int size = sizeof(struct evdev_client) +
-                                       bufsize * sizeof(struct input_event);
        struct evdev_client *client;
        int error;
 
-       client = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
+       client = kzalloc(struct_size(client, buffer, bufsize),
+                        GFP_KERNEL | __GFP_NOWARN);
        if (!client)
-               client = vzalloc(size);
+               client = vzalloc(struct_size(client, buffer, bufsize));
        if (!client)
                return -ENOMEM;
 
index 52d7f55fca329c09c9788cb8bcd91509a5f07426..82398827b64f9482be82fb7b46c8bd813e941415 100644 (file)
@@ -137,6 +137,17 @@ config KEYBOARD_ATKBD_RDI_KEYCODES
          right-hand column will be interpreted as the key shown in the
          left-hand column.
 
+config KEYBOARD_QT1050
+       tristate "Microchip AT42QT1050 Touch Sensor Chip"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         Say Y here if you want to use Microchip AT42QT1050 QTouch
+         Sensor chip as input device.
+
+         To compile this driver as a module, choose M here:
+         the module will be called qt1050
+
 config KEYBOARD_QT1070
        tristate "Atmel AT42QT1070 Touch Sensor Chip"
        depends on I2C
@@ -194,7 +205,7 @@ config KEYBOARD_LKKBD
 
 config KEYBOARD_EP93XX
        tristate "EP93xx Matrix Keypad support"
-       depends on ARCH_EP93XX
+       depends on ARCH_EP93XX || COMPILE_TEST
        select INPUT_MATRIXKMAP
        help
          Say Y here to enable the matrix keypad on the Cirrus EP93XX.
index 182e92985dbf69f18c783db7b04523fbc5ae56a3..f0291ca39f624270fd4f1396e361a05d7008546d 100644 (file)
@@ -50,6 +50,7 @@ obj-$(CONFIG_KEYBOARD_OPENCORES)      += opencores-kbd.o
 obj-$(CONFIG_KEYBOARD_PMIC8XXX)                += pmic8xxx-keypad.o
 obj-$(CONFIG_KEYBOARD_PXA27x)          += pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)   += pxa930_rotary.o
+obj-$(CONFIG_KEYBOARD_QT1050)           += qt1050.o
 obj-$(CONFIG_KEYBOARD_QT1070)           += qt1070.o
 obj-$(CONFIG_KEYBOARD_QT2160)          += qt2160.o
 obj-$(CONFIG_KEYBOARD_SAMSUNG)         += samsung-keypad.o
index 850bb259c20ebbba2c68f7dd88c6cfb83c9192a1..3ad93e3e2f4c7efcad2c3902e32e93ea066bdaaa 100644 (file)
@@ -401,6 +401,8 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
                if  (ps2_handle_response(&atkbd->ps2dev, data))
                        goto out;
 
+       pm_wakeup_event(&serio->dev, 0);
+
        if (!atkbd->enabled)
                goto out;
 
index f77b295e0123e9438ada601a70e0b530804c4c30..575dac52f7b47a4171b745f229b9b16118af27fc 100644 (file)
@@ -27,8 +27,7 @@
 #include <linux/io.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/slab.h>
-
-#include <mach/hardware.h>
+#include <linux/soc/cirrus/ep93xx.h>
 #include <linux/platform_data/keypad-ep93xx.h>
 
 /*
@@ -137,10 +136,7 @@ static void ep93xx_keypad_config(struct ep93xx_keypad *keypad)
        struct ep93xx_keypad_platform_data *pdata = keypad->pdata;
        unsigned int val = 0;
 
-       if (pdata->flags & EP93XX_KEYPAD_KDIV)
-               clk_set_rate(keypad->clk, EP93XX_KEYTCHCLK_DIV4);
-       else
-               clk_set_rate(keypad->clk, EP93XX_KEYTCHCLK_DIV16);
+       clk_set_rate(keypad->clk, pdata->clk_rate);
 
        if (pdata->flags & EP93XX_KEYPAD_DISABLE_3_KEY)
                val |= KEY_INIT_DIS3KY;
diff --git a/drivers/input/keyboard/qt1050.c b/drivers/input/keyboard/qt1050.c
new file mode 100644 (file)
index 0000000..403060d
--- /dev/null
@@ -0,0 +1,598 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Microchip AT42QT1050 QTouch Sensor Controller
+ *
+ *  Copyright (C) 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
+ *
+ *  Base on AT42QT1070 driver by:
+ *  Bo Shen <voice.shen@atmel.com>
+ *  Copyright (C) 2011 Atmel
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+/* Chip ID */
+#define QT1050_CHIP_ID         0x00
+#define QT1050_CHIP_ID_VER     0x46
+
+/* Firmware version */
+#define QT1050_FW_VERSION      0x01
+
+/* Detection status */
+#define QT1050_DET_STATUS      0x02
+
+/* Key status */
+#define QT1050_KEY_STATUS      0x03
+
+/* Key Signals */
+#define QT1050_KEY_SIGNAL_0_MSB        0x06
+#define QT1050_KEY_SIGNAL_0_LSB        0x07
+#define QT1050_KEY_SIGNAL_1_MSB        0x08
+#define QT1050_KEY_SIGNAL_1_LSB        0x09
+#define QT1050_KEY_SIGNAL_2_MSB        0x0c
+#define QT1050_KEY_SIGNAL_2_LSB        0x0d
+#define QT1050_KEY_SIGNAL_3_MSB        0x0e
+#define QT1050_KEY_SIGNAL_3_LSB        0x0f
+#define QT1050_KEY_SIGNAL_4_MSB        0x10
+#define QT1050_KEY_SIGNAL_4_LSB        0x11
+
+/* Reference data */
+#define QT1050_REF_DATA_0_MSB  0x14
+#define QT1050_REF_DATA_0_LSB  0x15
+#define QT1050_REF_DATA_1_MSB  0x16
+#define QT1050_REF_DATA_1_LSB  0x17
+#define QT1050_REF_DATA_2_MSB  0x1a
+#define QT1050_REF_DATA_2_LSB  0x1b
+#define QT1050_REF_DATA_3_MSB  0x1c
+#define QT1050_REF_DATA_3_LSB  0x1d
+#define QT1050_REF_DATA_4_MSB  0x1e
+#define QT1050_REF_DATA_4_LSB  0x1f
+
+/* Negative threshold level */
+#define QT1050_NTHR_0          0x21
+#define QT1050_NTHR_1          0x22
+#define QT1050_NTHR_2          0x24
+#define QT1050_NTHR_3          0x25
+#define QT1050_NTHR_4          0x26
+
+/* Pulse / Scale  */
+#define QT1050_PULSE_SCALE_0   0x28
+#define QT1050_PULSE_SCALE_1   0x29
+#define QT1050_PULSE_SCALE_2   0x2b
+#define QT1050_PULSE_SCALE_3   0x2c
+#define QT1050_PULSE_SCALE_4   0x2d
+
+/* Detection integrator counter / AKS */
+#define QT1050_DI_AKS_0                0x2f
+#define QT1050_DI_AKS_1                0x30
+#define QT1050_DI_AKS_2                0x32
+#define QT1050_DI_AKS_3                0x33
+#define QT1050_DI_AKS_4                0x34
+
+/* Charge Share Delay */
+#define QT1050_CSD_0           0x36
+#define QT1050_CSD_1           0x37
+#define QT1050_CSD_2           0x39
+#define QT1050_CSD_3           0x3a
+#define QT1050_CSD_4           0x3b
+
+/* Low Power Mode */
+#define QT1050_LPMODE          0x3d
+
+/* Calibration and Reset */
+#define QT1050_RES_CAL         0x3f
+#define QT1050_RES_CAL_RESET           BIT(7)
+#define QT1050_RES_CAL_CALIBRATE       BIT(1)
+
+#define QT1050_MAX_KEYS                5
+#define QT1050_RESET_TIME      255
+
+struct qt1050_key_regs {
+       unsigned int nthr;
+       unsigned int pulse_scale;
+       unsigned int di_aks;
+       unsigned int csd;
+};
+
+struct qt1050_key {
+       u32 num;
+       u32 charge_delay;
+       u32 thr_cnt;
+       u32 samples;
+       u32 scale;
+       u32 keycode;
+};
+
+struct qt1050_priv {
+       struct i2c_client       *client;
+       struct input_dev        *input;
+       struct regmap           *regmap;
+       struct qt1050_key       keys[QT1050_MAX_KEYS];
+       unsigned short          keycodes[QT1050_MAX_KEYS];
+       u8                      reg_keys;
+       u8                      last_keys;
+};
+
+static const struct qt1050_key_regs qt1050_key_regs_data[] = {
+       {
+               .nthr = QT1050_NTHR_0,
+               .pulse_scale = QT1050_PULSE_SCALE_0,
+               .di_aks = QT1050_DI_AKS_0,
+               .csd = QT1050_CSD_0,
+       }, {
+               .nthr = QT1050_NTHR_1,
+               .pulse_scale = QT1050_PULSE_SCALE_1,
+               .di_aks = QT1050_DI_AKS_1,
+               .csd = QT1050_CSD_1,
+       }, {
+               .nthr = QT1050_NTHR_2,
+               .pulse_scale = QT1050_PULSE_SCALE_2,
+               .di_aks = QT1050_DI_AKS_2,
+               .csd = QT1050_CSD_2,
+       }, {
+               .nthr = QT1050_NTHR_3,
+               .pulse_scale = QT1050_PULSE_SCALE_3,
+               .di_aks = QT1050_DI_AKS_3,
+               .csd = QT1050_CSD_3,
+       }, {
+               .nthr = QT1050_NTHR_4,
+               .pulse_scale = QT1050_PULSE_SCALE_4,
+               .di_aks = QT1050_DI_AKS_4,
+               .csd = QT1050_CSD_4,
+       }
+};
+
+static bool qt1050_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case QT1050_DET_STATUS:
+       case QT1050_KEY_STATUS:
+       case QT1050_KEY_SIGNAL_0_MSB:
+       case QT1050_KEY_SIGNAL_0_LSB:
+       case QT1050_KEY_SIGNAL_1_MSB:
+       case QT1050_KEY_SIGNAL_1_LSB:
+       case QT1050_KEY_SIGNAL_2_MSB:
+       case QT1050_KEY_SIGNAL_2_LSB:
+       case QT1050_KEY_SIGNAL_3_MSB:
+       case QT1050_KEY_SIGNAL_3_LSB:
+       case QT1050_KEY_SIGNAL_4_MSB:
+       case QT1050_KEY_SIGNAL_4_LSB:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_range qt1050_readable_ranges[] = {
+       regmap_reg_range(QT1050_CHIP_ID, QT1050_KEY_STATUS),
+       regmap_reg_range(QT1050_KEY_SIGNAL_0_MSB, QT1050_KEY_SIGNAL_1_LSB),
+       regmap_reg_range(QT1050_KEY_SIGNAL_2_MSB, QT1050_KEY_SIGNAL_4_LSB),
+       regmap_reg_range(QT1050_REF_DATA_0_MSB, QT1050_REF_DATA_1_LSB),
+       regmap_reg_range(QT1050_REF_DATA_2_MSB, QT1050_REF_DATA_4_LSB),
+       regmap_reg_range(QT1050_NTHR_0, QT1050_NTHR_1),
+       regmap_reg_range(QT1050_NTHR_2, QT1050_NTHR_4),
+       regmap_reg_range(QT1050_PULSE_SCALE_0, QT1050_PULSE_SCALE_1),
+       regmap_reg_range(QT1050_PULSE_SCALE_2, QT1050_PULSE_SCALE_4),
+       regmap_reg_range(QT1050_DI_AKS_0, QT1050_DI_AKS_1),
+       regmap_reg_range(QT1050_DI_AKS_2, QT1050_DI_AKS_4),
+       regmap_reg_range(QT1050_CSD_0, QT1050_CSD_1),
+       regmap_reg_range(QT1050_CSD_2, QT1050_RES_CAL),
+};
+
+static const struct regmap_access_table qt1050_readable_table = {
+       .yes_ranges = qt1050_readable_ranges,
+       .n_yes_ranges = ARRAY_SIZE(qt1050_readable_ranges),
+};
+
+static const struct regmap_range qt1050_writeable_ranges[] = {
+       regmap_reg_range(QT1050_NTHR_0, QT1050_NTHR_1),
+       regmap_reg_range(QT1050_NTHR_2, QT1050_NTHR_4),
+       regmap_reg_range(QT1050_PULSE_SCALE_0, QT1050_PULSE_SCALE_1),
+       regmap_reg_range(QT1050_PULSE_SCALE_2, QT1050_PULSE_SCALE_4),
+       regmap_reg_range(QT1050_DI_AKS_0, QT1050_DI_AKS_1),
+       regmap_reg_range(QT1050_DI_AKS_2, QT1050_DI_AKS_4),
+       regmap_reg_range(QT1050_CSD_0, QT1050_CSD_1),
+       regmap_reg_range(QT1050_CSD_2, QT1050_RES_CAL),
+};
+
+static const struct regmap_access_table qt1050_writeable_table = {
+       .yes_ranges = qt1050_writeable_ranges,
+       .n_yes_ranges = ARRAY_SIZE(qt1050_writeable_ranges),
+};
+
+static struct regmap_config qt1050_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = QT1050_RES_CAL,
+
+       .cache_type = REGCACHE_RBTREE,
+
+       .wr_table = &qt1050_writeable_table,
+       .rd_table = &qt1050_readable_table,
+       .volatile_reg = qt1050_volatile_reg,
+};
+
+static bool qt1050_identify(struct qt1050_priv *ts)
+{
+       unsigned int val;
+       int err;
+
+       /* Read Chip ID */
+       regmap_read(ts->regmap, QT1050_CHIP_ID, &val);
+       if (val != QT1050_CHIP_ID_VER) {
+               dev_err(&ts->client->dev, "ID %d not supported\n", val);
+               return false;
+       }
+
+       /* Read firmware version */
+       err = regmap_read(ts->regmap, QT1050_FW_VERSION, &val);
+       if (err) {
+               dev_err(&ts->client->dev, "could not read the firmware version\n");
+               return false;
+       }
+
+       dev_info(&ts->client->dev, "AT42QT1050 firmware version %1d.%1d\n",
+                val >> 4, val & 0xf);
+
+       return true;
+}
+
+static irqreturn_t qt1050_irq_threaded(int irq, void *dev_id)
+{
+       struct qt1050_priv *ts = dev_id;
+       struct input_dev *input = ts->input;
+       unsigned long new_keys, changed;
+       unsigned int val;
+       int i, err;
+
+       /* Read the detected status register, thus clearing interrupt */
+       err = regmap_read(ts->regmap, QT1050_DET_STATUS, &val);
+       if (err) {
+               dev_err(&ts->client->dev, "Fail to read detection status: %d\n",
+                       err);
+               return IRQ_NONE;
+       }
+
+       /* Read which key changed, keys are not continuous */
+       err = regmap_read(ts->regmap, QT1050_KEY_STATUS, &val);
+       if (err) {
+               dev_err(&ts->client->dev,
+                       "Fail to determine the key status: %d\n", err);
+               return IRQ_NONE;
+       }
+       new_keys = (val & 0x70) >> 2 | (val & 0x6) >> 1;
+       changed = ts->last_keys ^ new_keys;
+       /* Report registered keys only */
+       changed &= ts->reg_keys;
+
+       for_each_set_bit(i, &changed, QT1050_MAX_KEYS)
+               input_report_key(input, ts->keys[i].keycode,
+                                test_bit(i, &new_keys));
+
+       ts->last_keys = new_keys;
+       input_sync(input);
+
+       return IRQ_HANDLED;
+}
+
+static const struct qt1050_key_regs *qt1050_get_key_regs(int key_num)
+{
+       return &qt1050_key_regs_data[key_num];
+}
+
+static int qt1050_set_key(struct regmap *map, int number, int on)
+{
+       const struct qt1050_key_regs *key_regs;
+
+       key_regs = qt1050_get_key_regs(number);
+
+       return regmap_update_bits(map, key_regs->di_aks, 0xfc,
+                                 on ? BIT(4) : 0x00);
+}
+
+static int qt1050_apply_fw_data(struct qt1050_priv *ts)
+{
+       struct regmap *map = ts->regmap;
+       struct qt1050_key *button = &ts->keys[0];
+       const struct qt1050_key_regs *key_regs;
+       int i, err;
+
+       /* Disable all keys and enable only the specified ones */
+       for (i = 0; i < QT1050_MAX_KEYS; i++) {
+               err = qt1050_set_key(map, i, 0);
+               if (err)
+                       return err;
+       }
+
+       for (i = 0; i < QT1050_MAX_KEYS; i++, button++) {
+               /* Keep KEY_RESERVED keys off */
+               if (button->keycode == KEY_RESERVED)
+                       continue;
+
+               err = qt1050_set_key(map, button->num, 1);
+               if (err)
+                       return err;
+
+               key_regs = qt1050_get_key_regs(button->num);
+
+               err = regmap_write(map, key_regs->pulse_scale,
+                                  (button->samples << 4) | (button->scale));
+               if (err)
+                       return err;
+               err = regmap_write(map, key_regs->csd, button->charge_delay);
+               if (err)
+                       return err;
+               err = regmap_write(map, key_regs->nthr, button->thr_cnt);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int qt1050_parse_fw(struct qt1050_priv *ts)
+{
+       struct device *dev = &ts->client->dev;
+       struct fwnode_handle *child;
+       int nbuttons;
+
+       nbuttons = device_get_child_node_count(dev);
+       if (nbuttons == 0 || nbuttons > QT1050_MAX_KEYS)
+               return -ENODEV;
+
+       device_for_each_child_node(dev, child) {
+               struct qt1050_key button;
+
+               /* Required properties */
+               if (fwnode_property_read_u32(child, "linux,code",
+                                            &button.keycode)) {
+                       dev_err(dev, "Button without keycode\n");
+                       goto err;
+               }
+               if (button.keycode >= KEY_MAX) {
+                       dev_err(dev, "Invalid keycode 0x%x\n",
+                               button.keycode);
+                       goto err;
+               }
+
+               if (fwnode_property_read_u32(child, "reg",
+                                            &button.num)) {
+                       dev_err(dev, "Button without pad number\n");
+                       goto err;
+               }
+               if (button.num < 0 || button.num > QT1050_MAX_KEYS - 1)
+                       goto err;
+
+               ts->reg_keys |= BIT(button.num);
+
+               /* Optional properties */
+               if (fwnode_property_read_u32(child,
+                                            "microchip,pre-charge-time-ns",
+                                            &button.charge_delay)) {
+                       button.charge_delay = 0;
+               } else {
+                       if (button.charge_delay % 2500 == 0)
+                               button.charge_delay =
+                                       button.charge_delay / 2500;
+                       else
+                               button.charge_delay = 0;
+               }
+
+               if (fwnode_property_read_u32(child, "microchip,average-samples",
+                                        &button.samples)) {
+                       button.samples = 0;
+               } else {
+                       if (is_power_of_2(button.samples))
+                               button.samples = ilog2(button.samples);
+                       else
+                               button.samples = 0;
+               }
+
+               if (fwnode_property_read_u32(child, "microchip,average-scaling",
+                                            &button.scale)) {
+                       button.scale = 0;
+               } else {
+                       if (is_power_of_2(button.scale))
+                               button.scale = ilog2(button.scale);
+                       else
+                               button.scale = 0;
+
+               }
+
+               if (fwnode_property_read_u32(child, "microchip,threshold",
+                                        &button.thr_cnt)) {
+                       button.thr_cnt = 20;
+               } else {
+                       if (button.thr_cnt > 255)
+                               button.thr_cnt = 20;
+               }
+
+               ts->keys[button.num] = button;
+       }
+
+       return 0;
+
+err:
+       fwnode_handle_put(child);
+       return -EINVAL;
+}
+
+static int qt1050_probe(struct i2c_client *client)
+{
+       struct qt1050_priv *ts;
+       struct input_dev *input;
+       struct device *dev = &client->dev;
+       struct regmap *map;
+       unsigned int status, i;
+       int err;
+
+       /* Check basic functionality */
+       err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE);
+       if (!err) {
+               dev_err(&client->dev, "%s adapter not supported\n",
+                       dev_driver_string(&client->adapter->dev));
+               return -ENODEV;
+       }
+
+       if (!client->irq) {
+               dev_err(dev, "assign a irq line to this device\n");
+               return -EINVAL;
+       }
+
+       ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
+       if (!ts)
+               return -ENOMEM;
+
+       input = devm_input_allocate_device(dev);
+       if (!input)
+               return -ENOMEM;
+
+       map = devm_regmap_init_i2c(client, &qt1050_regmap_config);
+       if (IS_ERR(map))
+               return PTR_ERR(map);
+
+       ts->client = client;
+       ts->input = input;
+       ts->regmap = map;
+
+       i2c_set_clientdata(client, ts);
+
+       /* Identify the qt1050 chip */
+       if (!qt1050_identify(ts))
+               return -ENODEV;
+
+       /* Get pdata */
+       err = qt1050_parse_fw(ts);
+       if (err) {
+               dev_err(dev, "Failed to parse firmware: %d\n", err);
+               return err;
+       }
+
+       input->name = "AT42QT1050 QTouch Sensor";
+       input->dev.parent = &client->dev;
+       input->id.bustype = BUS_I2C;
+
+       /* Add the keycode */
+       input->keycode = ts->keycodes;
+       input->keycodesize = sizeof(ts->keycodes[0]);
+       input->keycodemax = QT1050_MAX_KEYS;
+
+       __set_bit(EV_KEY, input->evbit);
+       for (i = 0; i < QT1050_MAX_KEYS; i++) {
+               ts->keycodes[i] = ts->keys[i].keycode;
+               __set_bit(ts->keycodes[i], input->keybit);
+       }
+
+       /* Trigger re-calibration */
+       err = regmap_update_bits(ts->regmap, QT1050_RES_CAL, 0x7f,
+                                QT1050_RES_CAL_CALIBRATE);
+       if (err) {
+               dev_err(dev, "Trigger calibration failed: %d\n", err);
+               return err;
+       }
+       err = regmap_read_poll_timeout(ts->regmap, QT1050_DET_STATUS, status,
+                                status >> 7 == 1, 10000, 200000);
+       if (err) {
+               dev_err(dev, "Calibration failed: %d\n", err);
+               return err;
+       }
+
+       /* Soft reset to set defaults */
+       err = regmap_update_bits(ts->regmap, QT1050_RES_CAL,
+                                QT1050_RES_CAL_RESET, QT1050_RES_CAL_RESET);
+       if (err) {
+               dev_err(dev, "Trigger soft reset failed: %d\n", err);
+               return err;
+       }
+       msleep(QT1050_RESET_TIME);
+
+       /* Set pdata */
+       err = qt1050_apply_fw_data(ts);
+       if (err) {
+               dev_err(dev, "Failed to set firmware data: %d\n", err);
+               return err;
+       }
+
+       err = devm_request_threaded_irq(dev, client->irq, NULL,
+                                       qt1050_irq_threaded, IRQF_ONESHOT,
+                                       "qt1050", ts);
+       if (err) {
+               dev_err(&client->dev, "Failed to request irq: %d\n", err);
+               return err;
+       }
+
+       /* Clear #CHANGE line */
+       err = regmap_read(ts->regmap, QT1050_DET_STATUS, &status);
+       if (err) {
+               dev_err(dev, "Failed to clear #CHANGE line level: %d\n", err);
+               return err;
+       }
+
+       /* Register the input device */
+       err = input_register_device(ts->input);
+       if (err) {
+               dev_err(&client->dev, "Failed to register input device: %d\n",
+                       err);
+               return err;
+       }
+
+       return 0;
+}
+
+static int __maybe_unused qt1050_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct qt1050_priv *ts = i2c_get_clientdata(client);
+
+       disable_irq(client->irq);
+
+       /*
+        * Set measurement interval to 1s (125 x 8ms) if wakeup is allowed
+        * else turn off. The 1s interval seems to be a good compromise between
+        * low power and response time.
+        */
+       return regmap_write(ts->regmap, QT1050_LPMODE,
+                           device_may_wakeup(dev) ? 125 : 0);
+}
+
+static int __maybe_unused qt1050_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct qt1050_priv *ts = i2c_get_clientdata(client);
+
+       enable_irq(client->irq);
+
+       /* Set measurement interval back to 16ms (2 x 8ms) */
+       return regmap_write(ts->regmap, QT1050_LPMODE, 2);
+}
+
+static SIMPLE_DEV_PM_OPS(qt1050_pm_ops, qt1050_suspend, qt1050_resume);
+
+static const struct of_device_id __maybe_unused qt1050_of_match[] = {
+       { .compatible = "microchip,qt1050", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, qt1050_of_match);
+
+static struct i2c_driver qt1050_driver = {
+       .driver = {
+               .name = "qt1050",
+               .of_match_table = of_match_ptr(qt1050_of_match),
+               .pm = &qt1050_pm_ops,
+       },
+       .probe_new = qt1050_probe,
+};
+
+module_i2c_driver(qt1050_driver);
+
+MODULE_AUTHOR("Marco Felsch <kernel@pengutronix.de");
+MODULE_DESCRIPTION("Driver for AT42QT1050 QTouch sensor");
+MODULE_LICENSE("GPL v2");
index 4c67cf30a5d9ab14bff5f5c53d289ba347d241f4..5342d8d45f811b399bb740ec4a0158d50c502c44 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
 
@@ -167,28 +168,9 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
        }
 
        device_init_wakeup(&pdev->dev, pdata->wakeup);
-
-       return 0;
-}
-
-static int __maybe_unused imx_snvs_pwrkey_suspend(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
-
-       if (device_may_wakeup(&pdev->dev))
-               enable_irq_wake(pdata->irq);
-
-       return 0;
-}
-
-static int __maybe_unused imx_snvs_pwrkey_resume(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
-
-       if (device_may_wakeup(&pdev->dev))
-               disable_irq_wake(pdata->irq);
+       error = dev_pm_set_wake_irq(&pdev->dev, pdata->irq);
+       if (error)
+               dev_err(&pdev->dev, "irq wake enable failed.\n");
 
        return 0;
 }
@@ -199,13 +181,9 @@ static const struct of_device_id imx_snvs_pwrkey_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, imx_snvs_pwrkey_ids);
 
-static SIMPLE_DEV_PM_OPS(imx_snvs_pwrkey_pm_ops, imx_snvs_pwrkey_suspend,
-                               imx_snvs_pwrkey_resume);
-
 static struct platform_driver imx_snvs_pwrkey_driver = {
        .driver = {
                .name = "snvs_pwrkey",
-               .pm     = &imx_snvs_pwrkey_pm_ops,
                .of_match_table = imx_snvs_pwrkey_ids,
        },
        .probe = imx_snvs_pwrkey_probe,
index 57272df34cd5447373e32abba853ac694f5af3c0..df3eec72a9b236108ba7f298d5d4488216f0d786 100644 (file)
@@ -46,6 +46,7 @@
 #define CONTINUE_TIME_SEL(x)   ((x) << 16) /* 4 bits */
 #define KEY_MODE_SEL(x)                ((x) << 12) /* 2 bits */
 #define LEVELA_B_CNT(x)                ((x) << 8)  /* 4 bits */
+#define HOLD_KEY_EN(x)         ((x) << 7)
 #define HOLD_EN(x)             ((x) << 6)
 #define LEVELB_VOL(x)          ((x) << 4)  /* 2 bits */
 #define SAMPLE_RATE(x)         ((x) << 2)  /* 2 bits */
 #define        CHAN0_KEYDOWN_IRQ       BIT(1)
 #define CHAN0_DATA_IRQ         BIT(0)
 
+/* struct lradc_variant - Describe sun4i-a10-lradc-keys hardware variant
+ * @divisor_numerator:         The numerator of lradc Vref internally divisor
+ * @divisor_denominator:       The denominator of lradc Vref internally divisor
+ */
+struct lradc_variant {
+       u8 divisor_numerator;
+       u8 divisor_denominator;
+};
+
+static const struct lradc_variant lradc_variant_a10 = {
+       .divisor_numerator = 2,
+       .divisor_denominator = 3
+};
+
+static const struct lradc_variant r_lradc_variant_a83t = {
+       .divisor_numerator = 3,
+       .divisor_denominator = 4
+};
+
 struct sun4i_lradc_keymap {
        u32 voltage;
        u32 keycode;
@@ -74,6 +94,7 @@ struct sun4i_lradc_data {
        void __iomem *base;
        struct regulator *vref_supply;
        struct sun4i_lradc_keymap *chan0_map;
+       const struct lradc_variant *variant;
        u32 chan0_map_count;
        u32 chan0_keycode;
        u32 vref;
@@ -128,9 +149,9 @@ static int sun4i_lradc_open(struct input_dev *dev)
        if (error)
                return error;
 
-       /* lradc Vref internally is divided by 2/3 */
-       lradc->vref = regulator_get_voltage(lradc->vref_supply) * 2 / 3;
-
+       lradc->vref = regulator_get_voltage(lradc->vref_supply) *
+                     lradc->variant->divisor_numerator /
+                     lradc->variant->divisor_denominator;
        /*
         * Set sample time to 4 ms / 250 Hz. Wait 2 * 4 ms for key to
         * stabilize on press, wait (1 + 1) * 4 ms for key release
@@ -222,6 +243,12 @@ static int sun4i_lradc_probe(struct platform_device *pdev)
        if (error)
                return error;
 
+       lradc->variant = of_device_get_match_data(&pdev->dev);
+       if (!lradc->variant) {
+               dev_err(&pdev->dev, "Missing sun4i-a10-lradc-keys variant\n");
+               return -EINVAL;
+       }
+
        lradc->vref_supply = devm_regulator_get(dev, "vref");
        if (IS_ERR(lradc->vref_supply))
                return PTR_ERR(lradc->vref_supply);
@@ -265,7 +292,10 @@ static int sun4i_lradc_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id sun4i_lradc_of_match[] = {
-       { .compatible = "allwinner,sun4i-a10-lradc-keys", },
+       { .compatible = "allwinner,sun4i-a10-lradc-keys",
+               .data = &lradc_variant_a10 },
+       { .compatible = "allwinner,sun8i-a83t-r-lradc",
+               .data = &r_lradc_variant_a83t },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sun4i_lradc_of_match);
index e15ed1bb8558c69e2eda42507953e2e079e759d7..54d36f98b426df4ea4479af7729500ca0308e038 100644 (file)
@@ -190,6 +190,15 @@ config INPUT_M68K_BEEP
        tristate "M68k Beeper support"
        depends on M68K
 
+config INPUT_MAX77650_ONKEY
+       tristate "Maxim MAX77650 ONKEY support"
+       depends on MFD_MAX77650
+       help
+         Support the ONKEY of the MAX77650 PMIC as an input device.
+
+         To compile this driver as a module, choose M here: the module
+         will be called max77650-onkey.
+
 config INPUT_MAX77693_HAPTIC
        tristate "MAXIM MAX77693/MAX77843 haptic controller support"
        depends on (MFD_MAX77693 || MFD_MAX77843) && PWM
@@ -290,6 +299,18 @@ config INPUT_GPIO_DECODER
         To compile this driver as a module, choose M here: the module
         will be called gpio_decoder.
 
+config INPUT_GPIO_VIBRA
+       tristate "GPIO vibrator support"
+       depends on GPIOLIB || COMPILE_TEST
+       select INPUT_FF_MEMLESS
+       help
+         Say Y here to get support for GPIO based vibrator devices.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the module will be
+         called gpio-vibra.
+
 config INPUT_IXP4XX_BEEPER
        tristate "IXP4XX Beeper support"
        depends on ARCH_IXP4XX
index b936c5b1d4ac6ac99f3f86614f886b2bd788637f..8fd187f314bdffd6715793a7e5b654f47e38d6b6 100644 (file)
@@ -36,6 +36,7 @@ obj-$(CONFIG_INPUT_DRV2667_HAPTICS)   += drv2667.o
 obj-$(CONFIG_INPUT_GP2A)               += gp2ap002a00f.o
 obj-$(CONFIG_INPUT_GPIO_BEEPER)                += gpio-beeper.o
 obj-$(CONFIG_INPUT_GPIO_DECODER)       += gpio_decoder.o
+obj-$(CONFIG_INPUT_GPIO_VIBRA)         += gpio-vibra.o
 obj-$(CONFIG_INPUT_HISI_POWERKEY)      += hisi_powerkey.o
 obj-$(CONFIG_HP_SDC_RTC)               += hp_sdc_rtc.o
 obj-$(CONFIG_INPUT_IMS_PCU)            += ims-pcu.o
@@ -43,6 +44,7 @@ obj-$(CONFIG_INPUT_IXP4XX_BEEPER)     += ixp4xx-beeper.o
 obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)     += keyspan_remote.o
 obj-$(CONFIG_INPUT_KXTJ9)              += kxtj9.o
 obj-$(CONFIG_INPUT_M68K_BEEP)          += m68kspkr.o
+obj-$(CONFIG_INPUT_MAX77650_ONKEY)     += max77650-onkey.o
 obj-$(CONFIG_INPUT_MAX77693_HAPTIC)    += max77693-haptic.o
 obj-$(CONFIG_INPUT_MAX8925_ONKEY)      += max8925_onkey.o
 obj-$(CONFIG_INPUT_MAX8997_HAPTIC)     += max8997_haptic.o
diff --git a/drivers/input/misc/gpio-vibra.c b/drivers/input/misc/gpio-vibra.c
new file mode 100644 (file)
index 0000000..f79f755
--- /dev/null
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  GPIO vibrator driver
+ *
+ *  Copyright (C) 2019 Luca Weiss <luca@z3ntu.xyz>
+ *
+ *  Based on PWM vibrator driver:
+ *  Copyright (C) 2017 Collabora Ltd.
+ *
+ *  Based on previous work from:
+ *  Copyright (C) 2012 Dmitry Torokhov <dmitry.torokhov@gmail.com>
+ *
+ *  Based on PWM beeper driver:
+ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+struct gpio_vibrator {
+       struct input_dev *input;
+       struct gpio_desc *gpio;
+       struct regulator *vcc;
+
+       struct work_struct play_work;
+       bool running;
+       bool vcc_on;
+};
+
+static int gpio_vibrator_start(struct gpio_vibrator *vibrator)
+{
+       struct device *pdev = vibrator->input->dev.parent;
+       int err;
+
+       if (!vibrator->vcc_on) {
+               err = regulator_enable(vibrator->vcc);
+               if (err) {
+                       dev_err(pdev, "failed to enable regulator: %d\n", err);
+                       return err;
+               }
+               vibrator->vcc_on = true;
+       }
+
+       gpiod_set_value_cansleep(vibrator->gpio, 1);
+
+       return 0;
+}
+
+static void gpio_vibrator_stop(struct gpio_vibrator *vibrator)
+{
+       gpiod_set_value_cansleep(vibrator->gpio, 0);
+
+       if (vibrator->vcc_on) {
+               regulator_disable(vibrator->vcc);
+               vibrator->vcc_on = false;
+       }
+}
+
+static void gpio_vibrator_play_work(struct work_struct *work)
+{
+       struct gpio_vibrator *vibrator =
+               container_of(work, struct gpio_vibrator, play_work);
+
+       if (vibrator->running)
+               gpio_vibrator_start(vibrator);
+       else
+               gpio_vibrator_stop(vibrator);
+}
+
+static int gpio_vibrator_play_effect(struct input_dev *dev, void *data,
+                                    struct ff_effect *effect)
+{
+       struct gpio_vibrator *vibrator = input_get_drvdata(dev);
+       int level;
+
+       level = effect->u.rumble.strong_magnitude;
+       if (!level)
+               level = effect->u.rumble.weak_magnitude;
+
+       vibrator->running = level;
+       schedule_work(&vibrator->play_work);
+
+       return 0;
+}
+
+static void gpio_vibrator_close(struct input_dev *input)
+{
+       struct gpio_vibrator *vibrator = input_get_drvdata(input);
+
+       cancel_work_sync(&vibrator->play_work);
+       gpio_vibrator_stop(vibrator);
+       vibrator->running = false;
+}
+
+static int gpio_vibrator_probe(struct platform_device *pdev)
+{
+       struct gpio_vibrator *vibrator;
+       int err;
+
+       vibrator = devm_kzalloc(&pdev->dev, sizeof(*vibrator), GFP_KERNEL);
+       if (!vibrator)
+               return -ENOMEM;
+
+       vibrator->input = devm_input_allocate_device(&pdev->dev);
+       if (!vibrator->input)
+               return -ENOMEM;
+
+       vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc");
+       err = PTR_ERR_OR_ZERO(vibrator->vcc);
+       if (err) {
+               if (err != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "Failed to request regulator: %d\n",
+                               err);
+               return err;
+       }
+
+       vibrator->gpio = devm_gpiod_get(&pdev->dev, "enable", GPIOD_OUT_LOW);
+       err = PTR_ERR_OR_ZERO(vibrator->gpio);
+       if (err) {
+               if (err != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "Failed to request main gpio: %d\n",
+                               err);
+               return err;
+       }
+
+       INIT_WORK(&vibrator->play_work, gpio_vibrator_play_work);
+
+       vibrator->input->name = "gpio-vibrator";
+       vibrator->input->id.bustype = BUS_HOST;
+       vibrator->input->close = gpio_vibrator_close;
+
+       input_set_drvdata(vibrator->input, vibrator);
+       input_set_capability(vibrator->input, EV_FF, FF_RUMBLE);
+
+       err = input_ff_create_memless(vibrator->input, NULL,
+                                     gpio_vibrator_play_effect);
+       if (err) {
+               dev_err(&pdev->dev, "Couldn't create FF dev: %d\n", err);
+               return err;
+       }
+
+       err = input_register_device(vibrator->input);
+       if (err) {
+               dev_err(&pdev->dev, "Couldn't register input dev: %d\n", err);
+               return err;
+       }
+
+       platform_set_drvdata(pdev, vibrator);
+
+       return 0;
+}
+
+static int __maybe_unused gpio_vibrator_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_vibrator *vibrator = platform_get_drvdata(pdev);
+
+       cancel_work_sync(&vibrator->play_work);
+       if (vibrator->running)
+               gpio_vibrator_stop(vibrator);
+
+       return 0;
+}
+
+static int __maybe_unused gpio_vibrator_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_vibrator *vibrator = platform_get_drvdata(pdev);
+
+       if (vibrator->running)
+               gpio_vibrator_start(vibrator);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(gpio_vibrator_pm_ops,
+                        gpio_vibrator_suspend, gpio_vibrator_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id gpio_vibra_dt_match_table[] = {
+       { .compatible = "gpio-vibrator" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, gpio_vibra_dt_match_table);
+#endif
+
+static struct platform_driver gpio_vibrator_driver = {
+       .probe  = gpio_vibrator_probe,
+       .driver = {
+               .name   = "gpio-vibrator",
+               .pm     = &gpio_vibrator_pm_ops,
+               .of_match_table = of_match_ptr(gpio_vibra_dt_match_table),
+       },
+};
+module_platform_driver(gpio_vibrator_driver);
+
+MODULE_AUTHOR("Luca Weiss <luca@z3ntu.xy>");
+MODULE_DESCRIPTION("GPIO vibrator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-vibrator");
index 1fe149f3def24b62484c1e02b2ea895758bb67c4..4776273fa10b3590ad4606f2c4d45df7b7d564af 100644 (file)
@@ -30,6 +30,8 @@ MODULE_ALIAS("platform:ixp4xx-beeper");
 
 static DEFINE_SPINLOCK(beep_lock);
 
+static int ixp4xx_timer2_irq;
+
 static void ixp4xx_spkr_control(unsigned int pin, unsigned int count)
 {
        unsigned long flags;
@@ -90,6 +92,7 @@ static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id)
 static int ixp4xx_spkr_probe(struct platform_device *dev)
 {
        struct input_dev *input_dev;
+       int irq;
        int err;
 
        input_dev = input_allocate_device();
@@ -110,15 +113,22 @@ static int ixp4xx_spkr_probe(struct platform_device *dev)
        input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
        input_dev->event = ixp4xx_spkr_event;
 
+       irq = platform_get_irq(dev, 0);
+       if (irq < 0) {
+               err = irq;
+               goto err_free_device;
+       }
+
        err = gpio_request(dev->id, "ixp4-beeper");
        if (err)
                goto err_free_device;
 
-       err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt,
+       err = request_irq(irq, &ixp4xx_spkr_interrupt,
                          IRQF_NO_SUSPEND, "ixp4xx-beeper",
                          (void *) dev->id);
        if (err)
                goto err_free_gpio;
+       ixp4xx_timer2_irq = irq;
 
        err = input_register_device(input_dev);
        if (err)
@@ -129,7 +139,7 @@ static int ixp4xx_spkr_probe(struct platform_device *dev)
        return 0;
 
  err_free_irq:
-       free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id);
+       free_irq(irq, (void *)dev->id);
  err_free_gpio:
        gpio_free(dev->id);
  err_free_device:
@@ -146,10 +156,10 @@ static int ixp4xx_spkr_remove(struct platform_device *dev)
        input_unregister_device(input_dev);
 
        /* turn the speaker off */
-       disable_irq(IRQ_IXP4XX_TIMER2);
+       disable_irq(ixp4xx_timer2_irq);
        ixp4xx_spkr_control(pin, 0);
 
-       free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id);
+       free_irq(ixp4xx_timer2_irq, (void *)dev->id);
        gpio_free(dev->id);
 
        return 0;
@@ -161,7 +171,7 @@ static void ixp4xx_spkr_shutdown(struct platform_device *dev)
        unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
 
        /* turn off the speaker */
-       disable_irq(IRQ_IXP4XX_TIMER2);
+       disable_irq(ixp4xx_timer2_irq);
        ixp4xx_spkr_control(pin, 0);
 }
 
diff --git a/drivers/input/misc/max77650-onkey.c b/drivers/input/misc/max77650-onkey.c
new file mode 100644 (file)
index 0000000..fbf6caa
--- /dev/null
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 BayLibre SAS
+// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+//
+// ONKEY driver for MAXIM 77650/77651 charger/power-supply.
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/max77650.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MAX77650_ONKEY_MODE_MASK       BIT(3)
+#define MAX77650_ONKEY_MODE_PUSH       0x00
+#define MAX77650_ONKEY_MODE_SLIDE      BIT(3)
+
+struct max77650_onkey {
+       struct input_dev *input;
+       unsigned int code;
+};
+
+static irqreturn_t max77650_onkey_falling(int irq, void *data)
+{
+       struct max77650_onkey *onkey = data;
+
+       input_report_key(onkey->input, onkey->code, 0);
+       input_sync(onkey->input);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t max77650_onkey_rising(int irq, void *data)
+{
+       struct max77650_onkey *onkey = data;
+
+       input_report_key(onkey->input, onkey->code, 1);
+       input_sync(onkey->input);
+
+       return IRQ_HANDLED;
+}
+
+static int max77650_onkey_probe(struct platform_device *pdev)
+{
+       int irq_r, irq_f, error, mode;
+       struct max77650_onkey *onkey;
+       struct device *dev, *parent;
+       struct regmap *map;
+       unsigned int type;
+
+       dev = &pdev->dev;
+       parent = dev->parent;
+
+       map = dev_get_regmap(parent, NULL);
+       if (!map)
+               return -ENODEV;
+
+       onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL);
+       if (!onkey)
+               return -ENOMEM;
+
+       error = device_property_read_u32(dev, "linux,code", &onkey->code);
+       if (error)
+               onkey->code = KEY_POWER;
+
+       if (device_property_read_bool(dev, "maxim,onkey-slide")) {
+               mode = MAX77650_ONKEY_MODE_SLIDE;
+               type = EV_SW;
+       } else {
+               mode = MAX77650_ONKEY_MODE_PUSH;
+               type = EV_KEY;
+       }
+
+       error = regmap_update_bits(map, MAX77650_REG_CNFG_GLBL,
+                                  MAX77650_ONKEY_MODE_MASK, mode);
+       if (error)
+               return error;
+
+       irq_f = platform_get_irq_byname(pdev, "nEN_F");
+       if (irq_f < 0)
+               return irq_f;
+
+       irq_r = platform_get_irq_byname(pdev, "nEN_R");
+       if (irq_r < 0)
+               return irq_r;
+
+       onkey->input = devm_input_allocate_device(dev);
+       if (!onkey->input)
+               return -ENOMEM;
+
+       onkey->input->name = "max77650_onkey";
+       onkey->input->phys = "max77650_onkey/input0";
+       onkey->input->id.bustype = BUS_I2C;
+       input_set_capability(onkey->input, type, onkey->code);
+
+       error = devm_request_any_context_irq(dev, irq_f, max77650_onkey_falling,
+                                            IRQF_ONESHOT, "onkey-down", onkey);
+       if (error < 0)
+               return error;
+
+       error = devm_request_any_context_irq(dev, irq_r, max77650_onkey_rising,
+                                            IRQF_ONESHOT, "onkey-up", onkey);
+       if (error < 0)
+               return error;
+
+       return input_register_device(onkey->input);
+}
+
+static struct platform_driver max77650_onkey_driver = {
+       .driver = {
+               .name = "max77650-onkey",
+       },
+       .probe = max77650_onkey_probe,
+};
+module_platform_driver(max77650_onkey_driver);
+
+MODULE_DESCRIPTION("MAXIM 77650/77651 ONKEY driver");
+MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
+MODULE_LICENSE("GPL v2");
index d3ff1fc09af712700507d05ac3548703e49173a1..94f7ca5ad0772a3ec367e0b326b740077eb36d03 100644 (file)
@@ -373,6 +373,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
                if  (ps2_handle_response(&psmouse->ps2dev, data))
                        goto out;
 
+       pm_wakeup_event(&serio->dev, 0);
+
        if (psmouse->state <= PSMOUSE_RESYNCING)
                goto out;
 
index a6f515bcab2228a8783f10dbf10fae30462fd852..516fea06ed5950ed2764d5480e89c4fb92addf66 100644 (file)
@@ -456,25 +456,15 @@ static int rmi_f54_vidioc_fmt(struct file *file, void *priv,
 static int rmi_f54_vidioc_enum_fmt(struct file *file, void *priv,
                                   struct v4l2_fmtdesc *fmt)
 {
+       struct f54_data *f54 = video_drvdata(file);
+
        if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       switch (fmt->index) {
-       case 0:
-               fmt->pixelformat = V4L2_TCH_FMT_DELTA_TD16;
-               break;
-
-       case 1:
-               fmt->pixelformat = V4L2_TCH_FMT_DELTA_TD08;
-               break;
-
-       case 2:
-               fmt->pixelformat = V4L2_TCH_FMT_TU16;
-               break;
-
-       default:
+       if (fmt->index)
                return -EINVAL;
-       }
+
+       fmt->pixelformat = f54->format.pixelformat;
 
        return 0;
 }
@@ -692,6 +682,7 @@ static int rmi_f54_probe(struct rmi_function *fn)
                return -ENOMEM;
 
        rmi_f54_create_input_map(f54);
+       rmi_f54_set_input(f54, 0);
 
        /* register video device */
        strlcpy(f54->v4l2.name, F54_NAME, sizeof(f54->v4l2.name));
index c9c7224d5ae08517489c1d8ee8775c2630170514..bfe436ccb046e3eeb227751fa394c424eb2e2edf 100644 (file)
@@ -254,6 +254,7 @@ config SERIO_APBPS2
 
 config SERIO_OLPC_APSP
        tristate "OLPC AP-SP input support"
+       depends on ARCH_MMP || COMPILE_TEST
        help
          Say Y here if you want support for the keyboard and touchpad included
          in the OLPC XO-1.75 and XO-4 laptops.
index a8b9be3e28db709ef8769e29da2684c3d1e3bcf9..7935e52b54358dc4e3c0937a984d8b929b20531a 100644 (file)
@@ -440,5 +440,7 @@ static void __exit hv_kbd_exit(void)
 }
 
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Keyboard Driver");
+
 module_init(hv_kbd_init);
 module_exit(hv_kbd_exit);
index 95a78ccbd847035007bac3e5ea43e5ee04db35de..6462f1798fbb5ab5976e45071b085eb007d805ad 100644 (file)
@@ -573,9 +573,6 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
        port = &i8042_ports[port_no];
        serio = port->exists ? port->serio : NULL;
 
-       if (irq && serio)
-               pm_wakeup_event(&serio->dev, 0);
-
        filter_dbg(port->driver_bound, data, "<- i8042 (interrupt, %d, %d%s%s)\n",
                   port_no, irq,
                   dfl & SERIO_PARITY ? ", bad parity" : "",
index e6a07e68d1ff69d0ae16ac9d862c8816eb39cc05..22b8e05aa36ca5cc4cfaf2579931f0c841c05a97 100644 (file)
@@ -409,6 +409,7 @@ bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
                        ps2dev->nak = PS2_RET_ERR;
                        break;
                }
+               /* Fall through */
 
        /*
         * Workaround for mice which don't ACK the Get ID command.
index 7a4884ad198b8387f52dff71e4f4f2c1dfcf9a1c..a2029c3235af7e627ce7459fd6f7511ae7918c38 100644 (file)
@@ -1312,4 +1312,14 @@ config TOUCHSCREEN_ROHM_BU21023
          To compile this driver as a module, choose M here: the
          module will be called bu21023_ts.
 
+config TOUCHSCREEN_IQS5XX
+       tristate "Azoteq IQS550/572/525 trackpad/touchscreen controller"
+       depends on I2C
+       help
+         Say Y to enable support for the Azoteq IQS550/572/525
+         family of trackpad/touchscreen controllers.
+
+         To compile this driver as a module, choose M here: the
+         module will be called iqs5xx.
+
 endif
index fcc7605fba8dba99e88d6b319b0ab94bd538f734..084a596a0c8bda9e064498c1c736d9868814bfff 100644 (file)
@@ -110,3 +110,4 @@ obj-$(CONFIG_TOUCHSCREEN_ZFORCE)    += zforce_ts.o
 obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o
 obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
 obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW)       += raspberrypi-ts.o
+obj-$(CONFIG_TOUCHSCREEN_IQS5XX)       += iqs5xx.o
index 702bfda7ee777eb66fa75d2d33b8edacb01cbfa5..c639ebce914c07fb936684bd37d0321e51250f0c 100644 (file)
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
  * Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support)
  * Lothar Waßmann <LW@KARO-electronics.de> (DT support)
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /*
@@ -39,7 +27,6 @@
 #include <linux/gpio/consumer.h>
 #include <linux/input/mt.h>
 #include <linux/input/touchscreen.h>
-#include <linux/of_device.h>
 
 #define WORK_REGISTER_THRESHOLD                0x00
 #define WORK_REGISTER_REPORT_RATE      0x08
@@ -1073,7 +1060,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
                return -ENOMEM;
        }
 
-       chip_data = of_device_get_match_data(&client->dev);
+       chip_data = device_get_match_data(&client->dev);
        if (!chip_data)
                chip_data = (const struct edt_i2c_chip_data *)id->driver_data;
        if (!chip_data || !chip_data->max_support_points) {
@@ -1254,7 +1241,6 @@ static const struct i2c_device_id edt_ft5x06_ts_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
 
-#ifdef CONFIG_OF
 static const struct of_device_id edt_ft5x06_of_match[] = {
        { .compatible = "edt,edt-ft5206", .data = &edt_ft5x06_data },
        { .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data },
@@ -1266,12 +1252,11 @@ static const struct of_device_id edt_ft5x06_of_match[] = {
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
-#endif
 
 static struct i2c_driver edt_ft5x06_ts_driver = {
        .driver = {
                .name = "edt_ft5x06",
-               .of_match_table = of_match_ptr(edt_ft5x06_of_match),
+               .of_match_table = edt_ft5x06_of_match,
                .pm = &edt_ft5x06_ts_pm_ops,
        },
        .id_table = edt_ft5x06_ts_id,
@@ -1283,4 +1268,4 @@ module_i2c_driver(edt_ft5x06_ts_driver);
 
 MODULE_AUTHOR("Simon Budig <simon.budig@kernelconcepts.de>");
 MODULE_DESCRIPTION("EDT FT5x06 I2C Touchscreen Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
index f57d82220a881cca3bef6f76be902e4792dbabda..f7c1d168dd897850368da8f6b915d9a0db148244 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
 #include <linux/of.h>
@@ -47,6 +48,8 @@ struct goodix_ts_data {
        struct touchscreen_properties prop;
        unsigned int max_touch_num;
        unsigned int int_trigger_type;
+       struct regulator *avdd28;
+       struct regulator *vddio;
        struct gpio_desc *gpiod_int;
        struct gpio_desc *gpiod_rst;
        u16 id;
@@ -216,6 +219,7 @@ static const struct goodix_chip_data *goodix_get_chip_data(u16 id)
 {
        switch (id) {
        case 1151:
+       case 5663:
        case 5688:
                return &gt1x_chip_data;
 
@@ -532,6 +536,24 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
                return -EINVAL;
        dev = &ts->client->dev;
 
+       ts->avdd28 = devm_regulator_get(dev, "AVDD28");
+       if (IS_ERR(ts->avdd28)) {
+               error = PTR_ERR(ts->avdd28);
+               if (error != -EPROBE_DEFER)
+                       dev_err(dev,
+                               "Failed to get AVDD28 regulator: %d\n", error);
+               return error;
+       }
+
+       ts->vddio = devm_regulator_get(dev, "VDDIO");
+       if (IS_ERR(ts->vddio)) {
+               error = PTR_ERR(ts->vddio);
+               if (error != -EPROBE_DEFER)
+                       dev_err(dev,
+                               "Failed to get VDDIO regulator: %d\n", error);
+               return error;
+       }
+
        /* Get the interrupt GPIO pin number */
        gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
        if (IS_ERR(gpiod)) {
@@ -764,6 +786,14 @@ err_release_cfg:
        complete_all(&ts->firmware_loading_complete);
 }
 
+static void goodix_disable_regulators(void *arg)
+{
+       struct goodix_ts_data *ts = arg;
+
+       regulator_disable(ts->vddio);
+       regulator_disable(ts->avdd28);
+}
+
 static int goodix_ts_probe(struct i2c_client *client,
                           const struct i2c_device_id *id)
 {
@@ -789,6 +819,29 @@ static int goodix_ts_probe(struct i2c_client *client,
        if (error)
                return error;
 
+       /* power up the controller */
+       error = regulator_enable(ts->avdd28);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to enable AVDD28 regulator: %d\n",
+                       error);
+               return error;
+       }
+
+       error = regulator_enable(ts->vddio);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to enable VDDIO regulator: %d\n",
+                       error);
+               regulator_disable(ts->avdd28);
+               return error;
+       }
+
+       error = devm_add_action_or_reset(&client->dev,
+                                        goodix_disable_regulators, ts);
+       if (error)
+               return error;
+
        if (ts->gpiod_int && ts->gpiod_rst) {
                /* reset the controller */
                error = goodix_reset(ts);
@@ -945,6 +998,7 @@ MODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
 #ifdef CONFIG_OF
 static const struct of_device_id goodix_of_match[] = {
        { .compatible = "goodix,gt1151" },
+       { .compatible = "goodix,gt5663" },
        { .compatible = "goodix,gt5688" },
        { .compatible = "goodix,gt911" },
        { .compatible = "goodix,gt9110" },
diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c
new file mode 100644 (file)
index 0000000..b832fe0
--- /dev/null
@@ -0,0 +1,1133 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS550/572/525 Trackpad/Touchscreen Controller
+ *
+ * Copyright (C) 2018
+ * Author: Jeff LaBundy <jeff@labundy.com>
+ *
+ * These devices require firmware exported from a PC-based configuration tool
+ * made available by the vendor. Firmware files may be pushed to the device's
+ * nonvolatile memory by writing the filename to the 'fw_file' sysfs control.
+ *
+ * Link to PC-based configuration tool and data sheet: http://www.azoteq.com/
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#define IQS5XX_FW_FILE_LEN     64
+#define IQS5XX_NUM_RETRIES     10
+#define IQS5XX_NUM_POINTS      256
+#define IQS5XX_NUM_CONTACTS    5
+#define IQS5XX_WR_BYTES_MAX    2
+
+#define IQS5XX_PROD_NUM_IQS550 40
+#define IQS5XX_PROD_NUM_IQS572 58
+#define IQS5XX_PROD_NUM_IQS525 52
+#define IQS5XX_PROJ_NUM_A000   0
+#define IQS5XX_PROJ_NUM_B000   15
+#define IQS5XX_MAJOR_VER_MIN   2
+
+#define IQS5XX_RESUME          0x00
+#define IQS5XX_SUSPEND         0x01
+
+#define IQS5XX_SW_INPUT_EVENT  0x10
+#define IQS5XX_SETUP_COMPLETE  0x40
+#define IQS5XX_EVENT_MODE      0x01
+#define IQS5XX_TP_EVENT                0x04
+
+#define IQS5XX_FLIP_X          0x01
+#define IQS5XX_FLIP_Y          0x02
+#define IQS5XX_SWITCH_XY_AXIS  0x04
+
+#define IQS5XX_PROD_NUM                0x0000
+#define IQS5XX_ABS_X           0x0016
+#define IQS5XX_ABS_Y           0x0018
+#define IQS5XX_SYS_CTRL0       0x0431
+#define IQS5XX_SYS_CTRL1       0x0432
+#define IQS5XX_SYS_CFG0                0x058E
+#define IQS5XX_SYS_CFG1                0x058F
+#define IQS5XX_TOTAL_RX                0x063D
+#define IQS5XX_TOTAL_TX                0x063E
+#define IQS5XX_XY_CFG0         0x0669
+#define IQS5XX_X_RES           0x066E
+#define IQS5XX_Y_RES           0x0670
+#define IQS5XX_CHKSM           0x83C0
+#define IQS5XX_APP             0x8400
+#define IQS5XX_CSTM            0xBE00
+#define IQS5XX_PMAP_END                0xBFFF
+#define IQS5XX_END_COMM                0xEEEE
+
+#define IQS5XX_CHKSM_LEN       (IQS5XX_APP - IQS5XX_CHKSM)
+#define IQS5XX_APP_LEN         (IQS5XX_CSTM - IQS5XX_APP)
+#define IQS5XX_CSTM_LEN                (IQS5XX_PMAP_END + 1 - IQS5XX_CSTM)
+#define IQS5XX_PMAP_LEN                (IQS5XX_PMAP_END + 1 - IQS5XX_CHKSM)
+
+#define IQS5XX_REC_HDR_LEN     4
+#define IQS5XX_REC_LEN_MAX     255
+#define IQS5XX_REC_TYPE_DATA   0x00
+#define IQS5XX_REC_TYPE_EOF    0x01
+
+#define IQS5XX_BL_ADDR_MASK    0x40
+#define IQS5XX_BL_CMD_VER      0x00
+#define IQS5XX_BL_CMD_READ     0x01
+#define IQS5XX_BL_CMD_EXEC     0x02
+#define IQS5XX_BL_CMD_CRC      0x03
+#define IQS5XX_BL_BLK_LEN_MAX  64
+#define IQS5XX_BL_ID           0x0200
+#define IQS5XX_BL_STATUS_RESET 0x00
+#define IQS5XX_BL_STATUS_AVAIL 0xA5
+#define IQS5XX_BL_STATUS_NONE  0xEE
+#define IQS5XX_BL_CRC_PASS     0x00
+#define IQS5XX_BL_CRC_FAIL     0x01
+#define IQS5XX_BL_ATTEMPTS     3
+
+struct iqs5xx_private {
+       struct i2c_client *client;
+       struct input_dev *input;
+       struct gpio_desc *reset_gpio;
+       struct mutex lock;
+       u8 bl_status;
+};
+
+struct iqs5xx_dev_id_info {
+       __be16 prod_num;
+       __be16 proj_num;
+       u8 major_ver;
+       u8 minor_ver;
+       u8 bl_status;
+} __packed;
+
+struct iqs5xx_ihex_rec {
+       char start;
+       char len[2];
+       char addr[4];
+       char type[2];
+       char data[2];
+} __packed;
+
+struct iqs5xx_touch_data {
+       __be16 abs_x;
+       __be16 abs_y;
+       __be16 strength;
+       u8 area;
+} __packed;
+
+static int iqs5xx_read_burst(struct i2c_client *client,
+                            u16 reg, void *val, u16 len)
+{
+       __be16 reg_buf = cpu_to_be16(reg);
+       int ret, i;
+       struct i2c_msg msg[] = {
+               {
+                       .addr = client->addr,
+                       .flags = 0,
+                       .len = sizeof(reg_buf),
+                       .buf = (u8 *)&reg_buf,
+               },
+               {
+                       .addr = client->addr,
+                       .flags = I2C_M_RD,
+                       .len = len,
+                       .buf = (u8 *)val,
+               },
+       };
+
+       /*
+        * The first addressing attempt outside of a communication window fails
+        * and must be retried, after which the device clock stretches until it
+        * is available.
+        */
+       for (i = 0; i < IQS5XX_NUM_RETRIES; i++) {
+               ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+               if (ret == ARRAY_SIZE(msg))
+                       return 0;
+
+               usleep_range(200, 300);
+       }
+
+       if (ret >= 0)
+               ret = -EIO;
+
+       dev_err(&client->dev, "Failed to read from address 0x%04X: %d\n",
+               reg, ret);
+
+       return ret;
+}
+
+static int iqs5xx_read_word(struct i2c_client *client, u16 reg, u16 *val)
+{
+       __be16 val_buf;
+       int error;
+
+       error = iqs5xx_read_burst(client, reg, &val_buf, sizeof(val_buf));
+       if (error)
+               return error;
+
+       *val = be16_to_cpu(val_buf);
+
+       return 0;
+}
+
+static int iqs5xx_read_byte(struct i2c_client *client, u16 reg, u8 *val)
+{
+       return iqs5xx_read_burst(client, reg, val, sizeof(*val));
+}
+
+static int iqs5xx_write_burst(struct i2c_client *client,
+                             u16 reg, const void *val, u16 len)
+{
+       int ret, i;
+       u16 mlen = sizeof(reg) + len;
+       u8 mbuf[sizeof(reg) + IQS5XX_WR_BYTES_MAX];
+
+       if (len > IQS5XX_WR_BYTES_MAX)
+               return -EINVAL;
+
+       put_unaligned_be16(reg, mbuf);
+       memcpy(mbuf + sizeof(reg), val, len);
+
+       /*
+        * The first addressing attempt outside of a communication window fails
+        * and must be retried, after which the device clock stretches until it
+        * is available.
+        */
+       for (i = 0; i < IQS5XX_NUM_RETRIES; i++) {
+               ret = i2c_master_send(client, mbuf, mlen);
+               if (ret == mlen)
+                       return 0;
+
+               usleep_range(200, 300);
+       }
+
+       if (ret >= 0)
+               ret = -EIO;
+
+       dev_err(&client->dev, "Failed to write to address 0x%04X: %d\n",
+               reg, ret);
+
+       return ret;
+}
+
+static int iqs5xx_write_word(struct i2c_client *client, u16 reg, u16 val)
+{
+       __be16 val_buf = cpu_to_be16(val);
+
+       return iqs5xx_write_burst(client, reg, &val_buf, sizeof(val_buf));
+}
+
+static int iqs5xx_write_byte(struct i2c_client *client, u16 reg, u8 val)
+{
+       return iqs5xx_write_burst(client, reg, &val, sizeof(val));
+}
+
+static void iqs5xx_reset(struct i2c_client *client)
+{
+       struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+
+       gpiod_set_value_cansleep(iqs5xx->reset_gpio, 1);
+       usleep_range(200, 300);
+
+       gpiod_set_value_cansleep(iqs5xx->reset_gpio, 0);
+}
+
+static int iqs5xx_bl_cmd(struct i2c_client *client, u8 bl_cmd, u16 bl_addr)
+{
+       struct i2c_msg msg;
+       int ret;
+       u8 mbuf[sizeof(bl_cmd) + sizeof(bl_addr)];
+
+       msg.addr = client->addr ^ IQS5XX_BL_ADDR_MASK;
+       msg.flags = 0;
+       msg.len = sizeof(bl_cmd);
+       msg.buf = mbuf;
+
+       *mbuf = bl_cmd;
+
+       switch (bl_cmd) {
+       case IQS5XX_BL_CMD_VER:
+       case IQS5XX_BL_CMD_CRC:
+       case IQS5XX_BL_CMD_EXEC:
+               break;
+       case IQS5XX_BL_CMD_READ:
+               msg.len += sizeof(bl_addr);
+               put_unaligned_be16(bl_addr, mbuf + sizeof(bl_cmd));
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = i2c_transfer(client->adapter, &msg, 1);
+       if (ret != 1)
+               goto msg_fail;
+
+       switch (bl_cmd) {
+       case IQS5XX_BL_CMD_VER:
+               msg.len = sizeof(u16);
+               break;
+       case IQS5XX_BL_CMD_CRC:
+               msg.len = sizeof(u8);
+               /*
+                * This delay saves the bus controller the trouble of having to
+                * tolerate a relatively long clock-stretching period while the
+                * CRC is calculated.
+                */
+               msleep(50);
+               break;
+       case IQS5XX_BL_CMD_EXEC:
+               usleep_range(10000, 10100);
+               /* fall through */
+       default:
+               return 0;
+       }
+
+       msg.flags = I2C_M_RD;
+
+       ret = i2c_transfer(client->adapter, &msg, 1);
+       if (ret != 1)
+               goto msg_fail;
+
+       if (bl_cmd == IQS5XX_BL_CMD_VER &&
+           get_unaligned_be16(mbuf) != IQS5XX_BL_ID) {
+               dev_err(&client->dev, "Unrecognized bootloader ID: 0x%04X\n",
+                       get_unaligned_be16(mbuf));
+               return -EINVAL;
+       }
+
+       if (bl_cmd == IQS5XX_BL_CMD_CRC && *mbuf != IQS5XX_BL_CRC_PASS) {
+               dev_err(&client->dev, "Bootloader CRC failed\n");
+               return -EIO;
+       }
+
+       return 0;
+
+msg_fail:
+       if (ret >= 0)
+               ret = -EIO;
+
+       if (bl_cmd != IQS5XX_BL_CMD_VER)
+               dev_err(&client->dev,
+                       "Unsuccessful bootloader command 0x%02X: %d\n",
+                       bl_cmd, ret);
+
+       return ret;
+}
+
+static int iqs5xx_bl_open(struct i2c_client *client)
+{
+       int error, i, j;
+
+       /*
+        * The device opens a bootloader polling window for 2 ms following the
+        * release of reset. If the host cannot establish communication during
+        * this time frame, it must cycle reset again.
+        */
+       for (i = 0; i < IQS5XX_BL_ATTEMPTS; i++) {
+               iqs5xx_reset(client);
+
+               for (j = 0; j < IQS5XX_NUM_RETRIES; j++) {
+                       error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_VER, 0);
+                       if (!error || error == -EINVAL)
+                               return error;
+               }
+       }
+
+       dev_err(&client->dev, "Failed to open bootloader: %d\n", error);
+
+       return error;
+}
+
+static int iqs5xx_bl_write(struct i2c_client *client,
+                          u16 bl_addr, u8 *pmap_data, u16 pmap_len)
+{
+       struct i2c_msg msg;
+       int ret, i;
+       u8 mbuf[sizeof(bl_addr) + IQS5XX_BL_BLK_LEN_MAX];
+
+       if (pmap_len % IQS5XX_BL_BLK_LEN_MAX)
+               return -EINVAL;
+
+       msg.addr = client->addr ^ IQS5XX_BL_ADDR_MASK;
+       msg.flags = 0;
+       msg.len = sizeof(mbuf);
+       msg.buf = mbuf;
+
+       for (i = 0; i < pmap_len; i += IQS5XX_BL_BLK_LEN_MAX) {
+               put_unaligned_be16(bl_addr + i, mbuf);
+               memcpy(mbuf + sizeof(bl_addr), pmap_data + i,
+                      sizeof(mbuf) - sizeof(bl_addr));
+
+               ret = i2c_transfer(client->adapter, &msg, 1);
+               if (ret != 1)
+                       goto msg_fail;
+
+               usleep_range(10000, 10100);
+       }
+
+       return 0;
+
+msg_fail:
+       if (ret >= 0)
+               ret = -EIO;
+
+       dev_err(&client->dev, "Failed to write block at address 0x%04X: %d\n",
+               bl_addr + i, ret);
+
+       return ret;
+}
+
+static int iqs5xx_bl_verify(struct i2c_client *client,
+                           u16 bl_addr, u8 *pmap_data, u16 pmap_len)
+{
+       struct i2c_msg msg;
+       int ret, i;
+       u8 bl_data[IQS5XX_BL_BLK_LEN_MAX];
+
+       if (pmap_len % IQS5XX_BL_BLK_LEN_MAX)
+               return -EINVAL;
+
+       msg.addr = client->addr ^ IQS5XX_BL_ADDR_MASK;
+       msg.flags = I2C_M_RD;
+       msg.len = sizeof(bl_data);
+       msg.buf = bl_data;
+
+       for (i = 0; i < pmap_len; i += IQS5XX_BL_BLK_LEN_MAX) {
+               ret = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_READ, bl_addr + i);
+               if (ret)
+                       return ret;
+
+               ret = i2c_transfer(client->adapter, &msg, 1);
+               if (ret != 1)
+                       goto msg_fail;
+
+               if (memcmp(bl_data, pmap_data + i, sizeof(bl_data))) {
+                       dev_err(&client->dev,
+                               "Failed to verify block at address 0x%04X\n",
+                               bl_addr + i);
+                       return -EIO;
+               }
+       }
+
+       return 0;
+
+msg_fail:
+       if (ret >= 0)
+               ret = -EIO;
+
+       dev_err(&client->dev, "Failed to read block at address 0x%04X: %d\n",
+               bl_addr + i, ret);
+
+       return ret;
+}
+
+static int iqs5xx_set_state(struct i2c_client *client, u8 state)
+{
+       struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+       int error1, error2;
+
+       if (iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
+               return 0;
+
+       mutex_lock(&iqs5xx->lock);
+
+       /*
+        * Addressing the device outside of a communication window prompts it
+        * to assert the RDY output, so disable the interrupt line to prevent
+        * the handler from servicing a false interrupt.
+        */
+       disable_irq(client->irq);
+
+       error1 = iqs5xx_write_byte(client, IQS5XX_SYS_CTRL1, state);
+       error2 = iqs5xx_write_byte(client, IQS5XX_END_COMM, 0);
+
+       usleep_range(50, 100);
+       enable_irq(client->irq);
+
+       mutex_unlock(&iqs5xx->lock);
+
+       if (error1)
+               return error1;
+
+       return error2;
+}
+
+static int iqs5xx_open(struct input_dev *input)
+{
+       struct iqs5xx_private *iqs5xx = input_get_drvdata(input);
+
+       return iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME);
+}
+
+static void iqs5xx_close(struct input_dev *input)
+{
+       struct iqs5xx_private *iqs5xx = input_get_drvdata(input);
+
+       iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND);
+}
+
+static int iqs5xx_axis_init(struct i2c_client *client)
+{
+       struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+       struct touchscreen_properties prop;
+       struct input_dev *input;
+       int error;
+       u16 max_x, max_x_hw;
+       u16 max_y, max_y_hw;
+       u8 val;
+
+       if (!iqs5xx->input) {
+               input = devm_input_allocate_device(&client->dev);
+               if (!input)
+                       return -ENOMEM;
+
+               input->name = client->name;
+               input->id.bustype = BUS_I2C;
+               input->open = iqs5xx_open;
+               input->close = iqs5xx_close;
+
+               input_set_capability(input, EV_ABS, ABS_MT_POSITION_X);
+               input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y);
+               input_set_capability(input, EV_ABS, ABS_MT_PRESSURE);
+
+               error = input_mt_init_slots(input,
+                               IQS5XX_NUM_CONTACTS, INPUT_MT_DIRECT);
+               if (error) {
+                       dev_err(&client->dev,
+                               "Failed to initialize slots: %d\n", error);
+                       return error;
+               }
+
+               input_set_drvdata(input, iqs5xx);
+               iqs5xx->input = input;
+       }
+
+       touchscreen_parse_properties(iqs5xx->input, true, &prop);
+
+       error = iqs5xx_read_byte(client, IQS5XX_TOTAL_RX, &val);
+       if (error)
+               return error;
+       max_x_hw = (val - 1) * IQS5XX_NUM_POINTS;
+
+       error = iqs5xx_read_byte(client, IQS5XX_TOTAL_TX, &val);
+       if (error)
+               return error;
+       max_y_hw = (val - 1) * IQS5XX_NUM_POINTS;
+
+       error = iqs5xx_read_byte(client, IQS5XX_XY_CFG0, &val);
+       if (error)
+               return error;
+
+       if (val & IQS5XX_SWITCH_XY_AXIS)
+               swap(max_x_hw, max_y_hw);
+
+       if (prop.swap_x_y)
+               val ^= IQS5XX_SWITCH_XY_AXIS;
+
+       if (prop.invert_x)
+               val ^= prop.swap_x_y ? IQS5XX_FLIP_Y : IQS5XX_FLIP_X;
+
+       if (prop.invert_y)
+               val ^= prop.swap_x_y ? IQS5XX_FLIP_X : IQS5XX_FLIP_Y;
+
+       error = iqs5xx_write_byte(client, IQS5XX_XY_CFG0, val);
+       if (error)
+               return error;
+
+       if (prop.max_x > max_x_hw) {
+               dev_err(&client->dev, "Invalid maximum x-coordinate: %u > %u\n",
+                       prop.max_x, max_x_hw);
+               return -EINVAL;
+       } else if (prop.max_x == 0) {
+               error = iqs5xx_read_word(client, IQS5XX_X_RES, &max_x);
+               if (error)
+                       return error;
+
+               input_abs_set_max(iqs5xx->input,
+                                 prop.swap_x_y ? ABS_MT_POSITION_Y :
+                                                 ABS_MT_POSITION_X,
+                                 max_x);
+       } else {
+               max_x = (u16)prop.max_x;
+       }
+
+       if (prop.max_y > max_y_hw) {
+               dev_err(&client->dev, "Invalid maximum y-coordinate: %u > %u\n",
+                       prop.max_y, max_y_hw);
+               return -EINVAL;
+       } else if (prop.max_y == 0) {
+               error = iqs5xx_read_word(client, IQS5XX_Y_RES, &max_y);
+               if (error)
+                       return error;
+
+               input_abs_set_max(iqs5xx->input,
+                                 prop.swap_x_y ? ABS_MT_POSITION_X :
+                                                 ABS_MT_POSITION_Y,
+                                 max_y);
+       } else {
+               max_y = (u16)prop.max_y;
+       }
+
+       /*
+        * Write horizontal and vertical resolution to the device in case its
+        * original defaults were overridden or swapped as per the properties
+        * specified in the device tree.
+        */
+       error = iqs5xx_write_word(client,
+                                 prop.swap_x_y ? IQS5XX_Y_RES : IQS5XX_X_RES,
+                                 max_x);
+       if (error)
+               return error;
+
+       return iqs5xx_write_word(client,
+                                prop.swap_x_y ? IQS5XX_X_RES : IQS5XX_Y_RES,
+                                max_y);
+}
+
+static int iqs5xx_dev_init(struct i2c_client *client)
+{
+       struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+       struct iqs5xx_dev_id_info *dev_id_info;
+       int error;
+       u8 val;
+       u8 buf[sizeof(*dev_id_info) + 1];
+
+       error = iqs5xx_read_burst(client, IQS5XX_PROD_NUM,
+                                 &buf[1], sizeof(*dev_id_info));
+       if (error)
+               return iqs5xx_bl_open(client);
+
+       /*
+        * A000 and B000 devices use 8-bit and 16-bit addressing, respectively.
+        * Querying an A000 device's version information with 16-bit addressing
+        * gives the appearance that the data is shifted by one byte; a nonzero
+        * leading array element suggests this could be the case (in which case
+        * the missing zero is prepended).
+        */
+       buf[0] = 0;
+       dev_id_info = (struct iqs5xx_dev_id_info *)&buf[(buf[1] > 0) ? 0 : 1];
+
+       switch (be16_to_cpu(dev_id_info->prod_num)) {
+       case IQS5XX_PROD_NUM_IQS550:
+       case IQS5XX_PROD_NUM_IQS572:
+       case IQS5XX_PROD_NUM_IQS525:
+               break;
+       default:
+               dev_err(&client->dev, "Unrecognized product number: %u\n",
+                       be16_to_cpu(dev_id_info->prod_num));
+               return -EINVAL;
+       }
+
+       switch (be16_to_cpu(dev_id_info->proj_num)) {
+       case IQS5XX_PROJ_NUM_A000:
+               dev_err(&client->dev, "Unsupported project number: %u\n",
+                       be16_to_cpu(dev_id_info->proj_num));
+               return iqs5xx_bl_open(client);
+       case IQS5XX_PROJ_NUM_B000:
+               break;
+       default:
+               dev_err(&client->dev, "Unrecognized project number: %u\n",
+                       be16_to_cpu(dev_id_info->proj_num));
+               return -EINVAL;
+       }
+
+       if (dev_id_info->major_ver < IQS5XX_MAJOR_VER_MIN) {
+               dev_err(&client->dev, "Unsupported major version: %u\n",
+                       dev_id_info->major_ver);
+               return iqs5xx_bl_open(client);
+       }
+
+       switch (dev_id_info->bl_status) {
+       case IQS5XX_BL_STATUS_AVAIL:
+       case IQS5XX_BL_STATUS_NONE:
+               break;
+       default:
+               dev_err(&client->dev,
+                       "Unrecognized bootloader status: 0x%02X\n",
+                       dev_id_info->bl_status);
+               return -EINVAL;
+       }
+
+       error = iqs5xx_axis_init(client);
+       if (error)
+               return error;
+
+       error = iqs5xx_read_byte(client, IQS5XX_SYS_CFG0, &val);
+       if (error)
+               return error;
+
+       val |= IQS5XX_SETUP_COMPLETE;
+       val &= ~IQS5XX_SW_INPUT_EVENT;
+       error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG0, val);
+       if (error)
+               return error;
+
+       val = IQS5XX_TP_EVENT | IQS5XX_EVENT_MODE;
+       error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG1, val);
+       if (error)
+               return error;
+
+       error = iqs5xx_write_byte(client, IQS5XX_END_COMM, 0);
+       if (error)
+               return error;
+
+       iqs5xx->bl_status = dev_id_info->bl_status;
+
+       /*
+        * Closure of the first communication window that appears following the
+        * release of reset appears to kick off an initialization period during
+        * which further communication is met with clock stretching. The return
+        * from this function is delayed so that further communication attempts
+        * avoid this period.
+        */
+       msleep(100);
+
+       return 0;
+}
+
+static irqreturn_t iqs5xx_irq(int irq, void *data)
+{
+       struct iqs5xx_private *iqs5xx = data;
+       struct iqs5xx_touch_data touch_data[IQS5XX_NUM_CONTACTS];
+       struct i2c_client *client = iqs5xx->client;
+       struct input_dev *input = iqs5xx->input;
+       int error, i;
+
+       /*
+        * This check is purely a precaution, as the device does not assert the
+        * RDY output during bootloader mode. If the device operates outside of
+        * bootloader mode, the input device is guaranteed to be allocated.
+        */
+       if (iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
+               return IRQ_NONE;
+
+       error = iqs5xx_read_burst(client, IQS5XX_ABS_X,
+                                 touch_data, sizeof(touch_data));
+       if (error)
+               return IRQ_NONE;
+
+       for (i = 0; i < ARRAY_SIZE(touch_data); i++) {
+               u16 pressure = be16_to_cpu(touch_data[i].strength);
+
+               input_mt_slot(input, i);
+               if (input_mt_report_slot_state(input, MT_TOOL_FINGER,
+                                              pressure != 0)) {
+                       input_report_abs(input, ABS_MT_POSITION_X,
+                                        be16_to_cpu(touch_data[i].abs_x));
+                       input_report_abs(input, ABS_MT_POSITION_Y,
+                                        be16_to_cpu(touch_data[i].abs_y));
+                       input_report_abs(input, ABS_MT_PRESSURE, pressure);
+               }
+       }
+
+       input_mt_sync_frame(input);
+       input_sync(input);
+
+       error = iqs5xx_write_byte(client, IQS5XX_END_COMM, 0);
+       if (error)
+               return IRQ_NONE;
+
+       /*
+        * Once the communication window is closed, a small delay is added to
+        * ensure the device's RDY output has been deasserted by the time the
+        * interrupt handler returns.
+        */
+       usleep_range(50, 100);
+
+       return IRQ_HANDLED;
+}
+
+static int iqs5xx_fw_file_parse(struct i2c_client *client,
+                               const char *fw_file, u8 *pmap)
+{
+       const struct firmware *fw;
+       struct iqs5xx_ihex_rec *rec;
+       size_t pos = 0;
+       int error, i;
+       u16 rec_num = 1;
+       u16 rec_addr;
+       u8 rec_len, rec_type, rec_chksm, chksm;
+       u8 rec_hdr[IQS5XX_REC_HDR_LEN];
+       u8 rec_data[IQS5XX_REC_LEN_MAX];
+
+       /*
+        * Firmware exported from the vendor's configuration tool deviates from
+        * standard ihex as follows: (1) the checksum for records corresponding
+        * to user-exported settings is not recalculated, and (2) an address of
+        * 0xFFFF is used for the EOF record.
+        *
+        * Because the ihex2fw tool tolerates neither (1) nor (2), the slightly
+        * nonstandard ihex firmware is parsed directly by the driver.
+        */
+       error = request_firmware(&fw, fw_file, &client->dev);
+       if (error) {
+               dev_err(&client->dev, "Failed to request firmware %s: %d\n",
+                       fw_file, error);
+               return error;
+       }
+
+       do {
+               if (pos + sizeof(*rec) > fw->size) {
+                       dev_err(&client->dev, "Insufficient firmware size\n");
+                       error = -EINVAL;
+                       break;
+               }
+               rec = (struct iqs5xx_ihex_rec *)(fw->data + pos);
+               pos += sizeof(*rec);
+
+               if (rec->start != ':') {
+                       dev_err(&client->dev, "Invalid start at record %u\n",
+                               rec_num);
+                       error = -EINVAL;
+                       break;
+               }
+
+               error = hex2bin(rec_hdr, rec->len, sizeof(rec_hdr));
+               if (error) {
+                       dev_err(&client->dev, "Invalid header at record %u\n",
+                               rec_num);
+                       break;
+               }
+
+               rec_len = *rec_hdr;
+               rec_addr = get_unaligned_be16(rec_hdr + sizeof(rec_len));
+               rec_type = *(rec_hdr + sizeof(rec_len) + sizeof(rec_addr));
+
+               if (pos + rec_len * 2 > fw->size) {
+                       dev_err(&client->dev, "Insufficient firmware size\n");
+                       error = -EINVAL;
+                       break;
+               }
+               pos += (rec_len * 2);
+
+               error = hex2bin(rec_data, rec->data, rec_len);
+               if (error) {
+                       dev_err(&client->dev, "Invalid data at record %u\n",
+                               rec_num);
+                       break;
+               }
+
+               error = hex2bin(&rec_chksm,
+                               rec->data + rec_len * 2, sizeof(rec_chksm));
+               if (error) {
+                       dev_err(&client->dev, "Invalid checksum at record %u\n",
+                               rec_num);
+                       break;
+               }
+
+               chksm = 0;
+               for (i = 0; i < sizeof(rec_hdr); i++)
+                       chksm += rec_hdr[i];
+               for (i = 0; i < rec_len; i++)
+                       chksm += rec_data[i];
+               chksm = ~chksm + 1;
+
+               if (chksm != rec_chksm && rec_addr < IQS5XX_CSTM) {
+                       dev_err(&client->dev,
+                               "Incorrect checksum at record %u\n",
+                               rec_num);
+                       error = -EINVAL;
+                       break;
+               }
+
+               switch (rec_type) {
+               case IQS5XX_REC_TYPE_DATA:
+                       if (rec_addr < IQS5XX_CHKSM ||
+                           rec_addr > IQS5XX_PMAP_END) {
+                               dev_err(&client->dev,
+                                       "Invalid address at record %u\n",
+                                       rec_num);
+                               error = -EINVAL;
+                       } else {
+                               memcpy(pmap + rec_addr - IQS5XX_CHKSM,
+                                      rec_data, rec_len);
+                       }
+                       break;
+               case IQS5XX_REC_TYPE_EOF:
+                       break;
+               default:
+                       dev_err(&client->dev, "Invalid type at record %u\n",
+                               rec_num);
+                       error = -EINVAL;
+               }
+
+               if (error)
+                       break;
+
+               rec_num++;
+               while (pos < fw->size) {
+                       if (*(fw->data + pos) == ':')
+                               break;
+                       pos++;
+               }
+       } while (rec_type != IQS5XX_REC_TYPE_EOF);
+
+       release_firmware(fw);
+
+       return error;
+}
+
+static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
+{
+       struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+       int error;
+       u8 *pmap;
+
+       if (iqs5xx->bl_status == IQS5XX_BL_STATUS_NONE)
+               return -EPERM;
+
+       pmap = kzalloc(IQS5XX_PMAP_LEN, GFP_KERNEL);
+       if (!pmap)
+               return -ENOMEM;
+
+       error = iqs5xx_fw_file_parse(client, fw_file, pmap);
+       if (error)
+               goto err_kfree;
+
+       mutex_lock(&iqs5xx->lock);
+
+       /*
+        * Disable the interrupt line in case the first attempt(s) to enter the
+        * bootloader don't happen quickly enough, in which case the device may
+        * assert the RDY output until the next attempt.
+        */
+       disable_irq(client->irq);
+
+       iqs5xx->bl_status = IQS5XX_BL_STATUS_RESET;
+
+       error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_VER, 0);
+       if (error) {
+               error = iqs5xx_bl_open(client);
+               if (error)
+                       goto err_reset;
+       }
+
+       error = iqs5xx_bl_write(client, IQS5XX_CHKSM, pmap, IQS5XX_PMAP_LEN);
+       if (error)
+               goto err_reset;
+
+       error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_CRC, 0);
+       if (error)
+               goto err_reset;
+
+       error = iqs5xx_bl_verify(client, IQS5XX_CSTM,
+                                pmap + IQS5XX_CHKSM_LEN + IQS5XX_APP_LEN,
+                                IQS5XX_CSTM_LEN);
+       if (error)
+               goto err_reset;
+
+       error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_EXEC, 0);
+
+err_reset:
+       if (error) {
+               iqs5xx_reset(client);
+               usleep_range(10000, 10100);
+       }
+
+       error = iqs5xx_dev_init(client);
+       if (!error && iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
+               error = -EINVAL;
+
+       enable_irq(client->irq);
+
+       mutex_unlock(&iqs5xx->lock);
+
+err_kfree:
+       kfree(pmap);
+
+       return error;
+}
+
+static ssize_t fw_file_store(struct device *dev, struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
+       struct i2c_client *client = iqs5xx->client;
+       size_t len = count;
+       bool input_reg = !iqs5xx->input;
+       char fw_file[IQS5XX_FW_FILE_LEN + 1];
+       int error;
+
+       if (!len)
+               return -EINVAL;
+
+       if (buf[len - 1] == '\n')
+               len--;
+
+       if (len > IQS5XX_FW_FILE_LEN)
+               return -ENAMETOOLONG;
+
+       memcpy(fw_file, buf, len);
+       fw_file[len] = '\0';
+
+       error = iqs5xx_fw_file_write(client, fw_file);
+       if (error)
+               return error;
+
+       /*
+        * If the input device was not allocated already, it is guaranteed to
+        * be allocated by this point and can finally be registered.
+        */
+       if (input_reg) {
+               error = input_register_device(iqs5xx->input);
+               if (error) {
+                       dev_err(&client->dev,
+                               "Failed to register device: %d\n",
+                               error);
+                       return error;
+               }
+       }
+
+       return count;
+}
+
+static DEVICE_ATTR_WO(fw_file);
+
+static struct attribute *iqs5xx_attrs[] = {
+       &dev_attr_fw_file.attr,
+       NULL,
+};
+
+static const struct attribute_group iqs5xx_attr_group = {
+       .attrs = iqs5xx_attrs,
+};
+
+static int __maybe_unused iqs5xx_suspend(struct device *dev)
+{
+       struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
+       struct input_dev *input = iqs5xx->input;
+       int error = 0;
+
+       if (!input)
+               return error;
+
+       mutex_lock(&input->mutex);
+
+       if (input->users)
+               error = iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND);
+
+       mutex_unlock(&input->mutex);
+
+       return error;
+}
+
+static int __maybe_unused iqs5xx_resume(struct device *dev)
+{
+       struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
+       struct input_dev *input = iqs5xx->input;
+       int error = 0;
+
+       if (!input)
+               return error;
+
+       mutex_lock(&input->mutex);
+
+       if (input->users)
+               error = iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME);
+
+       mutex_unlock(&input->mutex);
+
+       return error;
+}
+
+static SIMPLE_DEV_PM_OPS(iqs5xx_pm, iqs5xx_suspend, iqs5xx_resume);
+
+static int iqs5xx_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct iqs5xx_private *iqs5xx;
+       int error;
+
+       iqs5xx = devm_kzalloc(&client->dev, sizeof(*iqs5xx), GFP_KERNEL);
+       if (!iqs5xx)
+               return -ENOMEM;
+
+       dev_set_drvdata(&client->dev, iqs5xx);
+
+       i2c_set_clientdata(client, iqs5xx);
+       iqs5xx->client = client;
+
+       iqs5xx->reset_gpio = devm_gpiod_get(&client->dev,
+                                           "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(iqs5xx->reset_gpio)) {
+               error = PTR_ERR(iqs5xx->reset_gpio);
+               dev_err(&client->dev, "Failed to request GPIO: %d\n", error);
+               return error;
+       }
+
+       mutex_init(&iqs5xx->lock);
+
+       iqs5xx_reset(client);
+       usleep_range(10000, 10100);
+
+       error = iqs5xx_dev_init(client);
+       if (error)
+               return error;
+
+       error = devm_request_threaded_irq(&client->dev, client->irq,
+                                         NULL, iqs5xx_irq, IRQF_ONESHOT,
+                                         client->name, iqs5xx);
+       if (error) {
+               dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
+               return error;
+       }
+
+       error = devm_device_add_group(&client->dev, &iqs5xx_attr_group);
+       if (error) {
+               dev_err(&client->dev, "Failed to add attributes: %d\n", error);
+               return error;
+       }
+
+       if (iqs5xx->input) {
+               error = input_register_device(iqs5xx->input);
+               if (error)
+                       dev_err(&client->dev,
+                               "Failed to register device: %d\n",
+                               error);
+       }
+
+       return error;
+}
+
+static const struct i2c_device_id iqs5xx_id[] = {
+       { "iqs550", 0 },
+       { "iqs572", 1 },
+       { "iqs525", 2 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, iqs5xx_id);
+
+static const struct of_device_id iqs5xx_of_match[] = {
+       { .compatible = "azoteq,iqs550" },
+       { .compatible = "azoteq,iqs572" },
+       { .compatible = "azoteq,iqs525" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, iqs5xx_of_match);
+
+static struct i2c_driver iqs5xx_i2c_driver = {
+       .driver = {
+               .name           = "iqs5xx",
+               .of_match_table = iqs5xx_of_match,
+               .pm             = &iqs5xx_pm,
+       },
+       .id_table       = iqs5xx_id,
+       .probe          = iqs5xx_probe,
+};
+module_i2c_driver(iqs5xx_i2c_driver);
+
+MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
+MODULE_DESCRIPTION("Azoteq IQS550/572/525 Trackpad/Touchscreen Controller");
+MODULE_LICENSE("GPL");
index 6f07f3b21816c64f40e98c84637fdad6bf53ce52..15b831113dedb0ae538bc5bf9dbdd3d174450901 100644 (file)
@@ -359,6 +359,31 @@ config ARM_SMMU
          Say Y here if your SoC includes an IOMMU device implementing
          the ARM SMMU architecture.
 
+config ARM_SMMU_DISABLE_BYPASS_BY_DEFAULT
+       bool "Default to disabling bypass on ARM SMMU v1 and v2"
+       depends on ARM_SMMU
+       default y
+       help
+         Say Y here to (by default) disable bypass streams such that
+         incoming transactions from devices that are not attached to
+         an iommu domain will report an abort back to the device and
+         will not be allowed to pass through the SMMU.
+
+         Any old kernels that existed before this KConfig was
+         introduced would default to _allowing_ bypass (AKA the
+         equivalent of NO for this config).  However the default for
+         this option is YES because the old behavior is insecure.
+
+         There are few reasons to allow unmatched stream bypass, and
+         even fewer good ones.  If saying YES here breaks your board
+         you should work on fixing your board.  This KConfig option
+         is expected to be removed in the future and we'll simply
+         hardcode the bypass disable in the code.
+
+         NOTE: the kernel command line parameter
+         'arm-smmu.disable_bypass' will continue to override this
+         config.
+
 config ARM_SMMU_V3
        bool "ARM Ltd. System MMU Version 3 (SMMUv3) Support"
        depends on ARM64
index f7cdd2ab7f11f6cba22003d4cf71576b4bc77b72..09c9e45f7fa2ec99751f752f4ff6fe30ccd7dfeb 100644 (file)
@@ -165,7 +165,7 @@ static inline u16 get_pci_device_id(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
 
-       return PCI_DEVID(pdev->bus->number, pdev->devfn);
+       return pci_dev_id(pdev);
 }
 
 static inline int get_acpihid_device_id(struct device *dev,
@@ -1723,31 +1723,6 @@ static void dma_ops_free_iova(struct dma_ops_domain *dma_dom,
  *
  ****************************************************************************/
 
-/*
- * This function adds a protection domain to the global protection domain list
- */
-static void add_domain_to_list(struct protection_domain *domain)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&amd_iommu_pd_lock, flags);
-       list_add(&domain->list, &amd_iommu_pd_list);
-       spin_unlock_irqrestore(&amd_iommu_pd_lock, flags);
-}
-
-/*
- * This function removes a protection domain to the global
- * protection domain list
- */
-static void del_domain_from_list(struct protection_domain *domain)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&amd_iommu_pd_lock, flags);
-       list_del(&domain->list);
-       spin_unlock_irqrestore(&amd_iommu_pd_lock, flags);
-}
-
 static u16 domain_id_alloc(void)
 {
        int id;
@@ -1838,8 +1813,6 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom)
        if (!dom)
                return;
 
-       del_domain_from_list(&dom->domain);
-
        put_iova_domain(&dom->iovad);
 
        free_pagetable(&dom->domain);
@@ -1880,8 +1853,6 @@ static struct dma_ops_domain *dma_ops_domain_alloc(void)
        /* Initialize reserved ranges */
        copy_reserved_iova(&reserved_iova_ranges, &dma_dom->iovad);
 
-       add_domain_to_list(&dma_dom->domain);
-
        return dma_dom;
 
 free_dma_dom:
@@ -2122,23 +2093,6 @@ out_err:
        return ret;
 }
 
-/* FIXME: Move this to PCI code */
-#define PCI_PRI_TLP_OFF                (1 << 15)
-
-static bool pci_pri_tlp_required(struct pci_dev *pdev)
-{
-       u16 status;
-       int pos;
-
-       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
-       if (!pos)
-               return false;
-
-       pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
-
-       return (status & PCI_PRI_TLP_OFF) ? true : false;
-}
-
 /*
  * If a device is not yet associated with a domain, this function makes the
  * device visible in the domain
@@ -2167,7 +2121,7 @@ static int attach_device(struct device *dev,
 
                        dev_data->ats.enabled = true;
                        dev_data->ats.qdep    = pci_ats_queue_depth(pdev);
-                       dev_data->pri_tlp     = pci_pri_tlp_required(pdev);
+                       dev_data->pri_tlp     = pci_prg_resp_pasid_required(pdev);
                }
        } else if (amd_iommu_iotlb_sup &&
                   pci_enable_ats(pdev, PAGE_SHIFT) == 0) {
@@ -2897,8 +2851,6 @@ static void protection_domain_free(struct protection_domain *domain)
        if (!domain)
                return;
 
-       del_domain_from_list(domain);
-
        if (domain->id)
                domain_id_free(domain->id);
 
@@ -2928,8 +2880,6 @@ static struct protection_domain *protection_domain_alloc(void)
        if (protection_domain_init(domain))
                goto out_err;
 
-       add_domain_to_list(domain);
-
        return domain;
 
 out_err:
index ff40ba758cf365e89ddeb2270971e1536554b817..f977df90d2a491274da7c631d5ef7c4300d56a5f 100644 (file)
@@ -188,12 +188,6 @@ static bool amd_iommu_pc_present __read_mostly;
 
 bool amd_iommu_force_isolation __read_mostly;
 
-/*
- * List of protection domains - used during resume
- */
-LIST_HEAD(amd_iommu_pd_list);
-spinlock_t amd_iommu_pd_lock;
-
 /*
  * Pointer to the device table which is shared by all AMD IOMMUs
  * it is indexed by the PCI device id or the HT unit id and contains
@@ -2526,8 +2520,6 @@ static int __init early_amd_iommu_init(void)
         */
        __set_bit(0, amd_iommu_pd_alloc_bitmap);
 
-       spin_lock_init(&amd_iommu_pd_lock);
-
        /*
         * now the data structures are allocated and basically initialized
         * start the real acpi table scan
index 87965e4d964771bd2352d6254bba299f43734107..85c488b8daea542207f83f182b817f4b4c338e71 100644 (file)
@@ -674,12 +674,6 @@ extern struct list_head amd_iommu_list;
  */
 extern struct amd_iommu *amd_iommus[MAX_IOMMUS];
 
-/*
- * Declarations for the global list of all protection domains
- */
-extern spinlock_t amd_iommu_pd_lock;
-extern struct list_head amd_iommu_pd_list;
-
 /*
  * Structure defining one entry in the device table
  */
index a1226e4ab5f89716ec50d8b8f64594ed3c36453f..e9132a926761dfb6a8a699eca1fafa6715f36824 100644 (file)
@@ -147,6 +147,8 @@ enum arm_smmu_s2cr_privcfg {
 #define CBAR_IRPTNDX_SHIFT             24
 #define CBAR_IRPTNDX_MASK              0xff
 
+#define ARM_SMMU_GR1_CBFRSYNRA(n)      (0x400 + ((n) << 2))
+
 #define ARM_SMMU_GR1_CBA2R(n)          (0x800 + ((n) << 2))
 #define CBA2R_RW64_32BIT               (0 << 0)
 #define CBA2R_RW64_64BIT               (1 << 0)
index d3880010c6cfc8c073789807d54cad1fc64f8ad1..4d5a694f02c2bb3159d2e7119a474e35fc384a96 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/of_iommu.h>
 #include <linux/of_platform.h>
 #include <linux/pci.h>
+#include <linux/pci-ats.h>
 #include <linux/platform_device.h>
 
 #include <linux/amba/bus.h>
@@ -86,6 +87,7 @@
 #define IDR5_VAX_52_BIT                        1
 
 #define ARM_SMMU_CR0                   0x20
+#define CR0_ATSCHK                     (1 << 4)
 #define CR0_CMDQEN                     (1 << 3)
 #define CR0_EVTQEN                     (1 << 2)
 #define CR0_PRIQEN                     (1 << 1)
 #define CMDQ_ERR_CERROR_NONE_IDX       0
 #define CMDQ_ERR_CERROR_ILL_IDX                1
 #define CMDQ_ERR_CERROR_ABT_IDX                2
+#define CMDQ_ERR_CERROR_ATC_INV_IDX    3
 
 #define CMDQ_0_OP                      GENMASK_ULL(7, 0)
 #define CMDQ_0_SSV                     (1UL << 11)
 #define CMDQ_TLBI_1_VA_MASK            GENMASK_ULL(63, 12)
 #define CMDQ_TLBI_1_IPA_MASK           GENMASK_ULL(51, 12)
 
+#define CMDQ_ATC_0_SSID                        GENMASK_ULL(31, 12)
+#define CMDQ_ATC_0_SID                 GENMASK_ULL(63, 32)
+#define CMDQ_ATC_0_GLOBAL              (1UL << 9)
+#define CMDQ_ATC_1_SIZE                        GENMASK_ULL(5, 0)
+#define CMDQ_ATC_1_ADDR_MASK           GENMASK_ULL(63, 12)
+
 #define CMDQ_PRI_0_SSID                        GENMASK_ULL(31, 12)
 #define CMDQ_PRI_0_SID                 GENMASK_ULL(63, 32)
 #define CMDQ_PRI_1_GRPID               GENMASK_ULL(8, 0)
@@ -433,6 +442,16 @@ struct arm_smmu_cmdq_ent {
                        u64                     addr;
                } tlbi;
 
+               #define CMDQ_OP_ATC_INV         0x40
+               #define ATC_INV_SIZE_ALL        52
+               struct {
+                       u32                     sid;
+                       u32                     ssid;
+                       u64                     addr;
+                       u8                      size;
+                       bool                    global;
+               } atc;
+
                #define CMDQ_OP_PRI_RESP        0x41
                struct {
                        u32                     sid;
@@ -505,19 +524,6 @@ struct arm_smmu_s2_cfg {
        u64                             vtcr;
 };
 
-struct arm_smmu_strtab_ent {
-       /*
-        * An STE is "assigned" if the master emitting the corresponding SID
-        * is attached to a domain. The behaviour of an unassigned STE is
-        * determined by the disable_bypass parameter, whereas an assigned
-        * STE behaves according to s1_cfg/s2_cfg, which themselves are
-        * configured according to the domain type.
-        */
-       bool                            assigned;
-       struct arm_smmu_s1_cfg          *s1_cfg;
-       struct arm_smmu_s2_cfg          *s2_cfg;
-};
-
 struct arm_smmu_strtab_cfg {
        __le64                          *strtab;
        dma_addr_t                      strtab_dma;
@@ -591,9 +597,14 @@ struct arm_smmu_device {
 };
 
 /* SMMU private data for each master */
-struct arm_smmu_master_data {
+struct arm_smmu_master {
        struct arm_smmu_device          *smmu;
-       struct arm_smmu_strtab_ent      ste;
+       struct device                   *dev;
+       struct arm_smmu_domain          *domain;
+       struct list_head                domain_head;
+       u32                             *sids;
+       unsigned int                    num_sids;
+       bool                            ats_enabled             :1;
 };
 
 /* SMMU private data for an IOMMU domain */
@@ -618,6 +629,9 @@ struct arm_smmu_domain {
        };
 
        struct iommu_domain             domain;
+
+       struct list_head                devices;
+       spinlock_t                      devices_lock;
 };
 
 struct arm_smmu_option_prop {
@@ -820,6 +834,14 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
        case CMDQ_OP_TLBI_S12_VMALL:
                cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid);
                break;
+       case CMDQ_OP_ATC_INV:
+               cmd[0] |= FIELD_PREP(CMDQ_0_SSV, ent->substream_valid);
+               cmd[0] |= FIELD_PREP(CMDQ_ATC_0_GLOBAL, ent->atc.global);
+               cmd[0] |= FIELD_PREP(CMDQ_ATC_0_SSID, ent->atc.ssid);
+               cmd[0] |= FIELD_PREP(CMDQ_ATC_0_SID, ent->atc.sid);
+               cmd[1] |= FIELD_PREP(CMDQ_ATC_1_SIZE, ent->atc.size);
+               cmd[1] |= ent->atc.addr & CMDQ_ATC_1_ADDR_MASK;
+               break;
        case CMDQ_OP_PRI_RESP:
                cmd[0] |= FIELD_PREP(CMDQ_0_SSV, ent->substream_valid);
                cmd[0] |= FIELD_PREP(CMDQ_PRI_0_SSID, ent->pri.ssid);
@@ -864,6 +886,7 @@ static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu)
                [CMDQ_ERR_CERROR_NONE_IDX]      = "No error",
                [CMDQ_ERR_CERROR_ILL_IDX]       = "Illegal command",
                [CMDQ_ERR_CERROR_ABT_IDX]       = "Abort on command fetch",
+               [CMDQ_ERR_CERROR_ATC_INV_IDX]   = "ATC invalidate timeout",
        };
 
        int i;
@@ -883,6 +906,14 @@ static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu)
                dev_err(smmu->dev, "retrying command fetch\n");
        case CMDQ_ERR_CERROR_NONE_IDX:
                return;
+       case CMDQ_ERR_CERROR_ATC_INV_IDX:
+               /*
+                * ATC Invalidation Completion timeout. CONS is still pointing
+                * at the CMD_SYNC. Attempt to complete other pending commands
+                * by repeating the CMD_SYNC, though we might well end up back
+                * here since the ATC invalidation may still be pending.
+                */
+               return;
        case CMDQ_ERR_CERROR_ILL_IDX:
                /* Fallthrough */
        default:
@@ -999,7 +1030,7 @@ static int __arm_smmu_cmdq_issue_sync(struct arm_smmu_device *smmu)
        return ret;
 }
 
-static void arm_smmu_cmdq_issue_sync(struct arm_smmu_device *smmu)
+static int arm_smmu_cmdq_issue_sync(struct arm_smmu_device *smmu)
 {
        int ret;
        bool msi = (smmu->features & ARM_SMMU_FEAT_MSI) &&
@@ -1009,6 +1040,7 @@ static void arm_smmu_cmdq_issue_sync(struct arm_smmu_device *smmu)
                  : __arm_smmu_cmdq_issue_sync(smmu);
        if (ret)
                dev_err_ratelimited(smmu->dev, "CMD_SYNC timeout\n");
+       return ret;
 }
 
 /* Context descriptor manipulation functions */
@@ -1025,7 +1057,6 @@ static u64 arm_smmu_cpu_tcr_to_cd(u64 tcr)
        val |= ARM_SMMU_TCR2CD(tcr, EPD0);
        val |= ARM_SMMU_TCR2CD(tcr, EPD1);
        val |= ARM_SMMU_TCR2CD(tcr, IPS);
-       val |= ARM_SMMU_TCR2CD(tcr, TBI0);
 
        return val;
 }
@@ -1085,8 +1116,8 @@ static void arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid)
        arm_smmu_cmdq_issue_sync(smmu);
 }
 
-static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
-                                     __le64 *dst, struct arm_smmu_strtab_ent *ste)
+static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
+                                     __le64 *dst)
 {
        /*
         * This is hideously complicated, but we only really care about
@@ -1106,6 +1137,10 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
         */
        u64 val = le64_to_cpu(dst[0]);
        bool ste_live = false;
+       struct arm_smmu_device *smmu = NULL;
+       struct arm_smmu_s1_cfg *s1_cfg = NULL;
+       struct arm_smmu_s2_cfg *s2_cfg = NULL;
+       struct arm_smmu_domain *smmu_domain = NULL;
        struct arm_smmu_cmdq_ent prefetch_cmd = {
                .opcode         = CMDQ_OP_PREFETCH_CFG,
                .prefetch       = {
@@ -1113,6 +1148,25 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
                },
        };
 
+       if (master) {
+               smmu_domain = master->domain;
+               smmu = master->smmu;
+       }
+
+       if (smmu_domain) {
+               switch (smmu_domain->stage) {
+               case ARM_SMMU_DOMAIN_S1:
+                       s1_cfg = &smmu_domain->s1_cfg;
+                       break;
+               case ARM_SMMU_DOMAIN_S2:
+               case ARM_SMMU_DOMAIN_NESTED:
+                       s2_cfg = &smmu_domain->s2_cfg;
+                       break;
+               default:
+                       break;
+               }
+       }
+
        if (val & STRTAB_STE_0_V) {
                switch (FIELD_GET(STRTAB_STE_0_CFG, val)) {
                case STRTAB_STE_0_CFG_BYPASS:
@@ -1133,8 +1187,8 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
        val = STRTAB_STE_0_V;
 
        /* Bypass/fault */
-       if (!ste->assigned || !(ste->s1_cfg || ste->s2_cfg)) {
-               if (!ste->assigned && disable_bypass)
+       if (!smmu_domain || !(s1_cfg || s2_cfg)) {
+               if (!smmu_domain && disable_bypass)
                        val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_ABORT);
                else
                        val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_BYPASS);
@@ -1152,41 +1206,42 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
                return;
        }
 
-       if (ste->s1_cfg) {
+       if (s1_cfg) {
                BUG_ON(ste_live);
                dst[1] = cpu_to_le64(
                         FIELD_PREP(STRTAB_STE_1_S1CIR, STRTAB_STE_1_S1C_CACHE_WBRA) |
                         FIELD_PREP(STRTAB_STE_1_S1COR, STRTAB_STE_1_S1C_CACHE_WBRA) |
                         FIELD_PREP(STRTAB_STE_1_S1CSH, ARM_SMMU_SH_ISH) |
-#ifdef CONFIG_PCI_ATS
-                        FIELD_PREP(STRTAB_STE_1_EATS, STRTAB_STE_1_EATS_TRANS) |
-#endif
                         FIELD_PREP(STRTAB_STE_1_STRW, STRTAB_STE_1_STRW_NSEL1));
 
                if (smmu->features & ARM_SMMU_FEAT_STALLS &&
                   !(smmu->features & ARM_SMMU_FEAT_STALL_FORCE))
                        dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD);
 
-               val |= (ste->s1_cfg->cdptr_dma & STRTAB_STE_0_S1CTXPTR_MASK) |
+               val |= (s1_cfg->cdptr_dma & STRTAB_STE_0_S1CTXPTR_MASK) |
                        FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_S1_TRANS);
        }
 
-       if (ste->s2_cfg) {
+       if (s2_cfg) {
                BUG_ON(ste_live);
                dst[2] = cpu_to_le64(
-                        FIELD_PREP(STRTAB_STE_2_S2VMID, ste->s2_cfg->vmid) |
-                        FIELD_PREP(STRTAB_STE_2_VTCR, ste->s2_cfg->vtcr) |
+                        FIELD_PREP(STRTAB_STE_2_S2VMID, s2_cfg->vmid) |
+                        FIELD_PREP(STRTAB_STE_2_VTCR, s2_cfg->vtcr) |
 #ifdef __BIG_ENDIAN
                         STRTAB_STE_2_S2ENDI |
 #endif
                         STRTAB_STE_2_S2PTW | STRTAB_STE_2_S2AA64 |
                         STRTAB_STE_2_S2R);
 
-               dst[3] = cpu_to_le64(ste->s2_cfg->vttbr & STRTAB_STE_3_S2TTB_MASK);
+               dst[3] = cpu_to_le64(s2_cfg->vttbr & STRTAB_STE_3_S2TTB_MASK);
 
                val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_S2_TRANS);
        }
 
+       if (master->ats_enabled)
+               dst[1] |= cpu_to_le64(FIELD_PREP(STRTAB_STE_1_EATS,
+                                                STRTAB_STE_1_EATS_TRANS));
+
        arm_smmu_sync_ste_for_sid(smmu, sid);
        dst[0] = cpu_to_le64(val);
        arm_smmu_sync_ste_for_sid(smmu, sid);
@@ -1199,10 +1254,9 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
 static void arm_smmu_init_bypass_stes(u64 *strtab, unsigned int nent)
 {
        unsigned int i;
-       struct arm_smmu_strtab_ent ste = { .assigned = false };
 
        for (i = 0; i < nent; ++i) {
-               arm_smmu_write_strtab_ent(NULL, -1, strtab, &ste);
+               arm_smmu_write_strtab_ent(NULL, -1, strtab);
                strtab += STRTAB_STE_DWORDS;
        }
 }
@@ -1390,6 +1444,96 @@ static irqreturn_t arm_smmu_combined_irq_handler(int irq, void *dev)
        return IRQ_WAKE_THREAD;
 }
 
+static void
+arm_smmu_atc_inv_to_cmd(int ssid, unsigned long iova, size_t size,
+                       struct arm_smmu_cmdq_ent *cmd)
+{
+       size_t log2_span;
+       size_t span_mask;
+       /* ATC invalidates are always on 4096-bytes pages */
+       size_t inval_grain_shift = 12;
+       unsigned long page_start, page_end;
+
+       *cmd = (struct arm_smmu_cmdq_ent) {
+               .opcode                 = CMDQ_OP_ATC_INV,
+               .substream_valid        = !!ssid,
+               .atc.ssid               = ssid,
+       };
+
+       if (!size) {
+               cmd->atc.size = ATC_INV_SIZE_ALL;
+               return;
+       }
+
+       page_start      = iova >> inval_grain_shift;
+       page_end        = (iova + size - 1) >> inval_grain_shift;
+
+       /*
+        * In an ATS Invalidate Request, the address must be aligned on the
+        * range size, which must be a power of two number of page sizes. We
+        * thus have to choose between grossly over-invalidating the region, or
+        * splitting the invalidation into multiple commands. For simplicity
+        * we'll go with the first solution, but should refine it in the future
+        * if multiple commands are shown to be more efficient.
+        *
+        * Find the smallest power of two that covers the range. The most
+        * significant differing bit between the start and end addresses,
+        * fls(start ^ end), indicates the required span. For example:
+        *
+        * We want to invalidate pages [8; 11]. This is already the ideal range:
+        *              x = 0b1000 ^ 0b1011 = 0b11
+        *              span = 1 << fls(x) = 4
+        *
+        * To invalidate pages [7; 10], we need to invalidate [0; 15]:
+        *              x = 0b0111 ^ 0b1010 = 0b1101
+        *              span = 1 << fls(x) = 16
+        */
+       log2_span       = fls_long(page_start ^ page_end);
+       span_mask       = (1ULL << log2_span) - 1;
+
+       page_start      &= ~span_mask;
+
+       cmd->atc.addr   = page_start << inval_grain_shift;
+       cmd->atc.size   = log2_span;
+}
+
+static int arm_smmu_atc_inv_master(struct arm_smmu_master *master,
+                                  struct arm_smmu_cmdq_ent *cmd)
+{
+       int i;
+
+       if (!master->ats_enabled)
+               return 0;
+
+       for (i = 0; i < master->num_sids; i++) {
+               cmd->atc.sid = master->sids[i];
+               arm_smmu_cmdq_issue_cmd(master->smmu, cmd);
+       }
+
+       return arm_smmu_cmdq_issue_sync(master->smmu);
+}
+
+static int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
+                                  int ssid, unsigned long iova, size_t size)
+{
+       int ret = 0;
+       unsigned long flags;
+       struct arm_smmu_cmdq_ent cmd;
+       struct arm_smmu_master *master;
+
+       if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_ATS))
+               return 0;
+
+       arm_smmu_atc_inv_to_cmd(ssid, iova, size, &cmd);
+
+       spin_lock_irqsave(&smmu_domain->devices_lock, flags);
+       list_for_each_entry(master, &smmu_domain->devices, domain_head)
+               ret |= arm_smmu_atc_inv_master(master, &cmd);
+       spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
+
+       return ret ? -ETIMEDOUT : 0;
+}
+
 /* IO_PGTABLE API */
 static void arm_smmu_tlb_sync(void *cookie)
 {
@@ -1493,6 +1637,9 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
        }
 
        mutex_init(&smmu_domain->init_mutex);
+       INIT_LIST_HEAD(&smmu_domain->devices);
+       spin_lock_init(&smmu_domain->devices_lock);
+
        return &smmu_domain->domain;
 }
 
@@ -1688,55 +1835,97 @@ static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
        return step;
 }
 
-static void arm_smmu_install_ste_for_dev(struct iommu_fwspec *fwspec)
+static void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master)
 {
        int i, j;
-       struct arm_smmu_master_data *master = fwspec->iommu_priv;
        struct arm_smmu_device *smmu = master->smmu;
 
-       for (i = 0; i < fwspec->num_ids; ++i) {
-               u32 sid = fwspec->ids[i];
+       for (i = 0; i < master->num_sids; ++i) {
+               u32 sid = master->sids[i];
                __le64 *step = arm_smmu_get_step_for_sid(smmu, sid);
 
                /* Bridged PCI devices may end up with duplicated IDs */
                for (j = 0; j < i; j++)
-                       if (fwspec->ids[j] == sid)
+                       if (master->sids[j] == sid)
                                break;
                if (j < i)
                        continue;
 
-               arm_smmu_write_strtab_ent(smmu, sid, step, &master->ste);
+               arm_smmu_write_strtab_ent(master, sid, step);
        }
 }
 
-static void arm_smmu_detach_dev(struct device *dev)
+static int arm_smmu_enable_ats(struct arm_smmu_master *master)
 {
-       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-       struct arm_smmu_master_data *master = fwspec->iommu_priv;
+       int ret;
+       size_t stu;
+       struct pci_dev *pdev;
+       struct arm_smmu_device *smmu = master->smmu;
+       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev);
 
-       master->ste.assigned = false;
-       arm_smmu_install_ste_for_dev(fwspec);
+       if (!(smmu->features & ARM_SMMU_FEAT_ATS) || !dev_is_pci(master->dev) ||
+           !(fwspec->flags & IOMMU_FWSPEC_PCI_RC_ATS) || pci_ats_disabled())
+               return -ENXIO;
+
+       pdev = to_pci_dev(master->dev);
+       if (pdev->untrusted)
+               return -EPERM;
+
+       /* Smallest Translation Unit: log2 of the smallest supported granule */
+       stu = __ffs(smmu->pgsize_bitmap);
+
+       ret = pci_enable_ats(pdev, stu);
+       if (ret)
+               return ret;
+
+       master->ats_enabled = true;
+       return 0;
+}
+
+static void arm_smmu_disable_ats(struct arm_smmu_master *master)
+{
+       if (!master->ats_enabled || !dev_is_pci(master->dev))
+               return;
+
+       pci_disable_ats(to_pci_dev(master->dev));
+       master->ats_enabled = false;
+}
+
+static void arm_smmu_detach_dev(struct arm_smmu_master *master)
+{
+       unsigned long flags;
+       struct arm_smmu_domain *smmu_domain = master->domain;
+
+       if (!smmu_domain)
+               return;
+
+       spin_lock_irqsave(&smmu_domain->devices_lock, flags);
+       list_del(&master->domain_head);
+       spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
+
+       master->domain = NULL;
+       arm_smmu_install_ste_for_dev(master);
+
+       /* Disabling ATS invalidates all ATC entries */
+       arm_smmu_disable_ats(master);
 }
 
 static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 {
        int ret = 0;
+       unsigned long flags;
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
        struct arm_smmu_device *smmu;
        struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
-       struct arm_smmu_master_data *master;
-       struct arm_smmu_strtab_ent *ste;
+       struct arm_smmu_master *master;
 
        if (!fwspec)
                return -ENOENT;
 
        master = fwspec->iommu_priv;
        smmu = master->smmu;
-       ste = &master->ste;
 
-       /* Already attached to a different domain? */
-       if (ste->assigned)
-               arm_smmu_detach_dev(dev);
+       arm_smmu_detach_dev(master);
 
        mutex_lock(&smmu_domain->init_mutex);
 
@@ -1756,21 +1945,19 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
                goto out_unlock;
        }
 
-       ste->assigned = true;
+       master->domain = smmu_domain;
 
-       if (smmu_domain->stage == ARM_SMMU_DOMAIN_BYPASS) {
-               ste->s1_cfg = NULL;
-               ste->s2_cfg = NULL;
-       } else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
-               ste->s1_cfg = &smmu_domain->s1_cfg;
-               ste->s2_cfg = NULL;
-               arm_smmu_write_ctx_desc(smmu, ste->s1_cfg);
-       } else {
-               ste->s1_cfg = NULL;
-               ste->s2_cfg = &smmu_domain->s2_cfg;
-       }
+       spin_lock_irqsave(&smmu_domain->devices_lock, flags);
+       list_add(&master->domain_head, &smmu_domain->devices);
+       spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
 
-       arm_smmu_install_ste_for_dev(fwspec);
+       if (smmu_domain->stage != ARM_SMMU_DOMAIN_BYPASS)
+               arm_smmu_enable_ats(master);
+
+       if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1)
+               arm_smmu_write_ctx_desc(smmu, &smmu_domain->s1_cfg);
+
+       arm_smmu_install_ste_for_dev(master);
 out_unlock:
        mutex_unlock(&smmu_domain->init_mutex);
        return ret;
@@ -1790,12 +1977,18 @@ static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
 static size_t
 arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
 {
-       struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;
+       int ret;
+       struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+       struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
 
        if (!ops)
                return 0;
 
-       return ops->unmap(ops, iova, size);
+       ret = ops->unmap(ops, iova, size);
+       if (ret && arm_smmu_atc_inv_domain(smmu_domain, 0, iova, size))
+               return 0;
+
+       return ret;
 }
 
 static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain)
@@ -1860,7 +2053,7 @@ static int arm_smmu_add_device(struct device *dev)
 {
        int i, ret;
        struct arm_smmu_device *smmu;
-       struct arm_smmu_master_data *master;
+       struct arm_smmu_master *master;
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
        struct iommu_group *group;
 
@@ -1882,13 +2075,16 @@ static int arm_smmu_add_device(struct device *dev)
                if (!master)
                        return -ENOMEM;
 
+               master->dev = dev;
                master->smmu = smmu;
+               master->sids = fwspec->ids;
+               master->num_sids = fwspec->num_ids;
                fwspec->iommu_priv = master;
        }
 
        /* Check the SIDs are in range of the SMMU and our stream table */
-       for (i = 0; i < fwspec->num_ids; i++) {
-               u32 sid = fwspec->ids[i];
+       for (i = 0; i < master->num_sids; i++) {
+               u32 sid = master->sids[i];
 
                if (!arm_smmu_sid_in_range(smmu, sid))
                        return -ERANGE;
@@ -1913,7 +2109,7 @@ static int arm_smmu_add_device(struct device *dev)
 static void arm_smmu_remove_device(struct device *dev)
 {
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-       struct arm_smmu_master_data *master;
+       struct arm_smmu_master *master;
        struct arm_smmu_device *smmu;
 
        if (!fwspec || fwspec->ops != &arm_smmu_ops)
@@ -1921,8 +2117,7 @@ static void arm_smmu_remove_device(struct device *dev)
 
        master = fwspec->iommu_priv;
        smmu = master->smmu;
-       if (master && master->ste.assigned)
-               arm_smmu_detach_dev(dev);
+       arm_smmu_detach_dev(master);
        iommu_group_remove_device(dev);
        iommu_device_unlink(&smmu->iommu, dev);
        kfree(master);
@@ -2454,13 +2649,9 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
        /* Clear CR0 and sync (disables SMMU and queue processing) */
        reg = readl_relaxed(smmu->base + ARM_SMMU_CR0);
        if (reg & CR0_SMMUEN) {
-               if (is_kdump_kernel()) {
-                       arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
-                       arm_smmu_device_disable(smmu);
-                       return -EBUSY;
-               }
-
                dev_warn(smmu->dev, "SMMU currently enabled! Resetting...\n");
+               WARN_ON(is_kdump_kernel() && !disable_bypass);
+               arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
        }
 
        ret = arm_smmu_device_disable(smmu);
@@ -2547,12 +2738,24 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
                }
        }
 
+       if (smmu->features & ARM_SMMU_FEAT_ATS) {
+               enables |= CR0_ATSCHK;
+               ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
+                                             ARM_SMMU_CR0ACK);
+               if (ret) {
+                       dev_err(smmu->dev, "failed to enable ATS check\n");
+                       return ret;
+               }
+       }
+
        ret = arm_smmu_setup_irqs(smmu);
        if (ret) {
                dev_err(smmu->dev, "failed to setup irqs\n");
                return ret;
        }
 
+       if (is_kdump_kernel())
+               enables &= ~(CR0_EVTQEN | CR0_PRIQEN);
 
        /* Enable the SMMU interface, or ensure bypass */
        if (!bypass || disable_bypass) {
index 045d938841640c375f13dbbd3997d5df919a782a..5e54cc0a28b30516b65c2516c666ee3d9c398141 100644 (file)
@@ -110,7 +110,8 @@ static int force_stage;
 module_param(force_stage, int, S_IRUGO);
 MODULE_PARM_DESC(force_stage,
        "Force SMMU mappings to be installed at a particular stage of translation. A value of '1' or '2' forces the corresponding stage. All other values are ignored (i.e. no stage is forced). Note that selecting a specific stage will disable support for nested translation.");
-static bool disable_bypass;
+static bool disable_bypass =
+       IS_ENABLED(CONFIG_ARM_SMMU_DISABLE_BYPASS_BY_DEFAULT);
 module_param(disable_bypass, bool, S_IRUGO);
 MODULE_PARM_DESC(disable_bypass,
        "Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU.");
@@ -569,12 +570,13 @@ static const struct iommu_gather_ops arm_smmu_s2_tlb_ops_v1 = {
 
 static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
 {
-       u32 fsr, fsynr;
+       u32 fsr, fsynr, cbfrsynra;
        unsigned long iova;
        struct iommu_domain *domain = dev;
        struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
        struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
        struct arm_smmu_device *smmu = smmu_domain->smmu;
+       void __iomem *gr1_base = ARM_SMMU_GR1(smmu);
        void __iomem *cb_base;
 
        cb_base = ARM_SMMU_CB(smmu, cfg->cbndx);
@@ -585,10 +587,11 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
 
        fsynr = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR0);
        iova = readq_relaxed(cb_base + ARM_SMMU_CB_FAR);
+       cbfrsynra = readl_relaxed(gr1_base + ARM_SMMU_GR1_CBFRSYNRA(cfg->cbndx));
 
        dev_err_ratelimited(smmu->dev,
-       "Unhandled context fault: fsr=0x%x, iova=0x%08lx, fsynr=0x%x, cb=%d\n",
-                           fsr, iova, fsynr, cfg->cbndx);
+       "Unhandled context fault: fsr=0x%x, iova=0x%08lx, fsynr=0x%x, cbfrsynra=0x%x, cb=%d\n",
+                           fsr, iova, fsynr, cbfrsynra, cfg->cbndx);
 
        writel(fsr, cb_base + ARM_SMMU_CB_FSR);
        return IRQ_HANDLED;
index 77aabe637a6019cad2af759edd8aa416cc3c75a3..5e898047c3907337f832c597471141f2d065f97f 100644 (file)
@@ -206,12 +206,13 @@ static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie,
        return 0;
 }
 
-static void iova_reserve_pci_windows(struct pci_dev *dev,
+static int iova_reserve_pci_windows(struct pci_dev *dev,
                struct iova_domain *iovad)
 {
        struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus);
        struct resource_entry *window;
        unsigned long lo, hi;
+       phys_addr_t start = 0, end;
 
        resource_list_for_each_entry(window, &bridge->windows) {
                if (resource_type(window->res) != IORESOURCE_MEM)
@@ -221,6 +222,31 @@ static void iova_reserve_pci_windows(struct pci_dev *dev,
                hi = iova_pfn(iovad, window->res->end - window->offset);
                reserve_iova(iovad, lo, hi);
        }
+
+       /* Get reserved DMA windows from host bridge */
+       resource_list_for_each_entry(window, &bridge->dma_ranges) {
+               end = window->res->start - window->offset;
+resv_iova:
+               if (end > start) {
+                       lo = iova_pfn(iovad, start);
+                       hi = iova_pfn(iovad, end);
+                       reserve_iova(iovad, lo, hi);
+               } else {
+                       /* dma_ranges list should be sorted */
+                       dev_err(&dev->dev, "Failed to reserve IOVA\n");
+                       return -EINVAL;
+               }
+
+               start = window->res->end - window->offset + 1;
+               /* If window is last entry */
+               if (window->node.next == &bridge->dma_ranges &&
+                   end != ~(dma_addr_t)0) {
+                       end = ~(dma_addr_t)0;
+                       goto resv_iova;
+               }
+       }
+
+       return 0;
 }
 
 static int iova_reserve_iommu_regions(struct device *dev,
@@ -232,8 +258,11 @@ static int iova_reserve_iommu_regions(struct device *dev,
        LIST_HEAD(resv_regions);
        int ret = 0;
 
-       if (dev_is_pci(dev))
-               iova_reserve_pci_windows(to_pci_dev(dev), iovad);
+       if (dev_is_pci(dev)) {
+               ret = iova_reserve_pci_windows(to_pci_dev(dev), iovad);
+               if (ret)
+                       return ret;
+       }
 
        iommu_get_resv_regions(dev, &resv_regions);
        list_for_each_entry(region, &resv_regions, list) {
@@ -619,17 +648,7 @@ out_free_pages:
 
 int iommu_dma_mmap(struct page **pages, size_t size, struct vm_area_struct *vma)
 {
-       unsigned long uaddr = vma->vm_start;
-       unsigned int i, count = PAGE_ALIGN(size) >> PAGE_SHIFT;
-       int ret = -ENXIO;
-
-       for (i = vma->vm_pgoff; i < count && uaddr < vma->vm_end; i++) {
-               ret = vm_insert_page(vma, uaddr, pages[i]);
-               if (ret)
-                       break;
-               uaddr += PAGE_SIZE;
-       }
-       return ret;
+       return vm_map_pages(vma, pages, PAGE_ALIGN(size) >> PAGE_SHIFT);
 }
 
 static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
index 9c49300e9fb76ace67cee9930356794234de81d0..6d969a172fbb3491df6b1d38cc6f3b33cd99a4d0 100644 (file)
@@ -145,7 +145,7 @@ dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event)
                for (tmp = dev; tmp; tmp = tmp->bus->self)
                        level++;
 
-       size = sizeof(*info) + level * sizeof(info->path[0]);
+       size = struct_size(info, path, level);
        if (size <= sizeof(dmar_pci_notify_info_buf)) {
                info = (struct dmar_pci_notify_info *)dmar_pci_notify_info_buf;
        } else {
index 28cb713d728ceef9eb7f37caa746a546617e1dbb..a209199f3af646054469378075ab6dae0e61b2f8 100644 (file)
@@ -1391,7 +1391,7 @@ static void iommu_enable_dev_iotlb(struct device_domain_info *info)
 
                /* pdev will be returned if device is not a vf */
                pf_pdev = pci_physfn(pdev);
-               info->pfsid = PCI_DEVID(pf_pdev->bus->number, pf_pdev->devfn);
+               info->pfsid = pci_dev_id(pf_pdev);
        }
 
 #ifdef CONFIG_INTEL_IOMMU_SVM
@@ -2341,32 +2341,33 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
 }
 
 static int domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
-                         struct scatterlist *sg, unsigned long phys_pfn,
-                         unsigned long nr_pages, int prot)
-{
-       int ret;
-       struct intel_iommu *iommu;
-
-       /* Do the real mapping first */
-       ret = __domain_mapping(domain, iov_pfn, sg, phys_pfn, nr_pages, prot);
-       if (ret)
-               return ret;
-
-       /* Notify about the new mapping */
-       if (domain_type_is_vm(domain)) {
-              /* VM typed domains can have more than one IOMMUs */
-              int iommu_id;
-              for_each_domain_iommu(iommu_id, domain) {
-                      iommu = g_iommus[iommu_id];
-                      __mapping_notify_one(iommu, domain, iov_pfn, nr_pages);
-              }
-       } else {
-              /* General domains only have one IOMMU */
-              iommu = domain_get_iommu(domain);
-              __mapping_notify_one(iommu, domain, iov_pfn, nr_pages);
-       }
+                         struct scatterlist *sg, unsigned long phys_pfn,
+                         unsigned long nr_pages, int prot)
+{
+       int ret;
+       struct intel_iommu *iommu;
+
+       /* Do the real mapping first */
+       ret = __domain_mapping(domain, iov_pfn, sg, phys_pfn, nr_pages, prot);
+       if (ret)
+               return ret;
+
+       /* Notify about the new mapping */
+       if (domain_type_is_vm(domain)) {
+               /* VM typed domains can have more than one IOMMUs */
+               int iommu_id;
+
+               for_each_domain_iommu(iommu_id, domain) {
+                       iommu = g_iommus[iommu_id];
+                       __mapping_notify_one(iommu, domain, iov_pfn, nr_pages);
+               }
+       } else {
+               /* General domains only have one IOMMU */
+               iommu = domain_get_iommu(domain);
+               __mapping_notify_one(iommu, domain, iov_pfn, nr_pages);
+       }
 
-       return 0;
+       return 0;
 }
 
 static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
@@ -2485,6 +2486,8 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
        info->domain = domain;
        info->iommu = iommu;
        info->pasid_table = NULL;
+       info->auxd_enabled = 0;
+       INIT_LIST_HEAD(&info->auxiliary_domains);
 
        if (dev && dev_is_pci(dev)) {
                struct pci_dev *pdev = to_pci_dev(info->dev);
@@ -3412,9 +3415,12 @@ static int __init init_dmars(void)
                iommu_identity_mapping |= IDENTMAP_ALL;
 
 #ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
-       iommu_identity_mapping |= IDENTMAP_GFX;
+       dmar_map_gfx = 0;
 #endif
 
+       if (!dmar_map_gfx)
+               iommu_identity_mapping |= IDENTMAP_GFX;
+
        check_tylersburg_isoch();
 
        if (iommu_identity_mapping) {
@@ -3496,7 +3502,13 @@ domains_done:
 
 #ifdef CONFIG_INTEL_IOMMU_SVM
                if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) {
+                       /*
+                        * Call dmar_alloc_hwirq() with dmar_global_lock held,
+                        * could cause possible lock race condition.
+                        */
+                       up_write(&dmar_global_lock);
                        ret = intel_svm_enable_prq(iommu);
+                       down_write(&dmar_global_lock);
                        if (ret)
                                goto free_iommu;
                }
@@ -3606,45 +3618,40 @@ out:
 }
 
 /* Check if the dev needs to go through non-identity map and unmap process.*/
-static int iommu_no_mapping(struct device *dev)
+static bool iommu_need_mapping(struct device *dev)
 {
        int found;
 
        if (iommu_dummy(dev))
-               return 1;
+               return false;
 
        if (!iommu_identity_mapping)
-               return 0;
+               return true;
 
        found = identity_mapping(dev);
        if (found) {
                if (iommu_should_identity_map(dev, 0))
-                       return 1;
-               else {
-                       /*
-                        * 32 bit DMA is removed from si_domain and fall back
-                        * to non-identity mapping.
-                        */
-                       dmar_remove_one_dev_info(dev);
-                       dev_info(dev, "32bit DMA uses non-identity mapping\n");
-                       return 0;
-               }
+                       return false;
+
+               /*
+                * 32 bit DMA is removed from si_domain and fall back to
+                * non-identity mapping.
+                */
+               dmar_remove_one_dev_info(dev);
+               dev_info(dev, "32bit DMA uses non-identity mapping\n");
        } else {
                /*
                 * In case of a detached 64 bit DMA device from vm, the device
                 * is put into si_domain for identity mapping.
                 */
-               if (iommu_should_identity_map(dev, 0)) {
-                       int ret;
-                       ret = domain_add_dev_info(si_domain, dev);
-                       if (!ret) {
-                               dev_info(dev, "64bit DMA uses identity mapping\n");
-                               return 1;
-                       }
+               if (iommu_should_identity_map(dev, 0) &&
+                   !domain_add_dev_info(si_domain, dev)) {
+                       dev_info(dev, "64bit DMA uses identity mapping\n");
+                       return false;
                }
        }
 
-       return 0;
+       return true;
 }
 
 static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr,
@@ -3660,9 +3667,6 @@ static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr,
 
        BUG_ON(dir == DMA_NONE);
 
-       if (iommu_no_mapping(dev))
-               return paddr;
-
        domain = get_valid_domain_for_dev(dev);
        if (!domain)
                return DMA_MAPPING_ERROR;
@@ -3711,15 +3715,20 @@ static dma_addr_t intel_map_page(struct device *dev, struct page *page,
                                 enum dma_data_direction dir,
                                 unsigned long attrs)
 {
-       return __intel_map_single(dev, page_to_phys(page) + offset, size,
-                                 dir, *dev->dma_mask);
+       if (iommu_need_mapping(dev))
+               return __intel_map_single(dev, page_to_phys(page) + offset,
+                               size, dir, *dev->dma_mask);
+       return dma_direct_map_page(dev, page, offset, size, dir, attrs);
 }
 
 static dma_addr_t intel_map_resource(struct device *dev, phys_addr_t phys_addr,
                                     size_t size, enum dma_data_direction dir,
                                     unsigned long attrs)
 {
-       return __intel_map_single(dev, phys_addr, size, dir, *dev->dma_mask);
+       if (iommu_need_mapping(dev))
+               return __intel_map_single(dev, phys_addr, size, dir,
+                               *dev->dma_mask);
+       return dma_direct_map_resource(dev, phys_addr, size, dir, attrs);
 }
 
 static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size)
@@ -3730,9 +3739,7 @@ static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size)
        unsigned long iova_pfn;
        struct intel_iommu *iommu;
        struct page *freelist;
-
-       if (iommu_no_mapping(dev))
-               return;
+       struct pci_dev *pdev = NULL;
 
        domain = find_domain(dev);
        BUG_ON(!domain);
@@ -3745,11 +3752,14 @@ static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size)
        start_pfn = mm_to_dma_pfn(iova_pfn);
        last_pfn = start_pfn + nrpages - 1;
 
+       if (dev_is_pci(dev))
+               pdev = to_pci_dev(dev);
+
        dev_dbg(dev, "Device unmapping: pfn %lx-%lx\n", start_pfn, last_pfn);
 
        freelist = domain_unmap(domain, start_pfn, last_pfn);
 
-       if (intel_iommu_strict) {
+       if (intel_iommu_strict || (pdev && pdev->untrusted)) {
                iommu_flush_iotlb_psi(iommu, domain, start_pfn,
                                      nrpages, !freelist, 0);
                /* free iova */
@@ -3769,7 +3779,17 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
                             size_t size, enum dma_data_direction dir,
                             unsigned long attrs)
 {
-       intel_unmap(dev, dev_addr, size);
+       if (iommu_need_mapping(dev))
+               intel_unmap(dev, dev_addr, size);
+       else
+               dma_direct_unmap_page(dev, dev_addr, size, dir, attrs);
+}
+
+static void intel_unmap_resource(struct device *dev, dma_addr_t dev_addr,
+               size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
+       if (iommu_need_mapping(dev))
+               intel_unmap(dev, dev_addr, size);
 }
 
 static void *intel_alloc_coherent(struct device *dev, size_t size,
@@ -3779,28 +3799,17 @@ static void *intel_alloc_coherent(struct device *dev, size_t size,
        struct page *page = NULL;
        int order;
 
+       if (!iommu_need_mapping(dev))
+               return dma_direct_alloc(dev, size, dma_handle, flags, attrs);
+
        size = PAGE_ALIGN(size);
        order = get_order(size);
 
-       if (!iommu_no_mapping(dev))
-               flags &= ~(GFP_DMA | GFP_DMA32);
-       else if (dev->coherent_dma_mask < dma_get_required_mask(dev)) {
-               if (dev->coherent_dma_mask < DMA_BIT_MASK(32))
-                       flags |= GFP_DMA;
-               else
-                       flags |= GFP_DMA32;
-       }
-
        if (gfpflags_allow_blocking(flags)) {
                unsigned int count = size >> PAGE_SHIFT;
 
                page = dma_alloc_from_contiguous(dev, count, order,
                                                 flags & __GFP_NOWARN);
-               if (page && iommu_no_mapping(dev) &&
-                   page_to_phys(page) + size > dev->coherent_dma_mask) {
-                       dma_release_from_contiguous(dev, page, count);
-                       page = NULL;
-               }
        }
 
        if (!page)
@@ -3826,6 +3835,9 @@ static void intel_free_coherent(struct device *dev, size_t size, void *vaddr,
        int order;
        struct page *page = virt_to_page(vaddr);
 
+       if (!iommu_need_mapping(dev))
+               return dma_direct_free(dev, size, vaddr, dma_handle, attrs);
+
        size = PAGE_ALIGN(size);
        order = get_order(size);
 
@@ -3843,6 +3855,9 @@ static void intel_unmap_sg(struct device *dev, struct scatterlist *sglist,
        struct scatterlist *sg;
        int i;
 
+       if (!iommu_need_mapping(dev))
+               return dma_direct_unmap_sg(dev, sglist, nelems, dir, attrs);
+
        for_each_sg(sglist, sg, nelems, i) {
                nrpages += aligned_nrpages(sg_dma_address(sg), sg_dma_len(sg));
        }
@@ -3850,20 +3865,6 @@ static void intel_unmap_sg(struct device *dev, struct scatterlist *sglist,
        intel_unmap(dev, startaddr, nrpages << VTD_PAGE_SHIFT);
 }
 
-static int intel_nontranslate_map_sg(struct device *hddev,
-       struct scatterlist *sglist, int nelems, int dir)
-{
-       int i;
-       struct scatterlist *sg;
-
-       for_each_sg(sglist, sg, nelems, i) {
-               BUG_ON(!sg_page(sg));
-               sg->dma_address = sg_phys(sg);
-               sg->dma_length = sg->length;
-       }
-       return nelems;
-}
-
 static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nelems,
                        enum dma_data_direction dir, unsigned long attrs)
 {
@@ -3878,8 +3879,8 @@ static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nele
        struct intel_iommu *iommu;
 
        BUG_ON(dir == DMA_NONE);
-       if (iommu_no_mapping(dev))
-               return intel_nontranslate_map_sg(dev, sglist, nelems, dir);
+       if (!iommu_need_mapping(dev))
+               return dma_direct_map_sg(dev, sglist, nelems, dir, attrs);
 
        domain = get_valid_domain_for_dev(dev);
        if (!domain)
@@ -3929,7 +3930,7 @@ static const struct dma_map_ops intel_dma_ops = {
        .map_page = intel_map_page,
        .unmap_page = intel_unmap_page,
        .map_resource = intel_map_resource,
-       .unmap_resource = intel_unmap_page,
+       .unmap_resource = intel_unmap_resource,
        .dma_supported = dma_direct_supported,
 };
 
@@ -4055,9 +4056,7 @@ static void __init init_no_remapping_devices(void)
 
                /* This IOMMU has *only* gfx devices. Either bypass it or
                   set the gfx_mapped flag, as appropriate */
-               if (dmar_map_gfx) {
-                       intel_iommu_gfx_mapped = 1;
-               } else {
+               if (!dmar_map_gfx) {
                        drhd->ignored = 1;
                        for_each_active_dev_scope(drhd->devices,
                                                  drhd->devices_cnt, i, dev)
@@ -4086,7 +4085,7 @@ static int init_iommu_hw(void)
                                iommu_disable_protect_mem_regions(iommu);
                        continue;
                }
-       
+
                iommu_flush_write_buffer(iommu);
 
                iommu_set_root_entry(iommu);
@@ -4896,6 +4895,9 @@ int __init intel_iommu_init(void)
                goto out_free_reserved_range;
        }
 
+       if (dmar_map_gfx)
+               intel_iommu_gfx_mapped = 1;
+
        init_no_remapping_devices();
 
        ret = init_dmars();
@@ -5065,35 +5067,139 @@ static void intel_iommu_domain_free(struct iommu_domain *domain)
        domain_exit(to_dmar_domain(domain));
 }
 
-static int intel_iommu_attach_device(struct iommu_domain *domain,
-                                    struct device *dev)
+/*
+ * Check whether a @domain could be attached to the @dev through the
+ * aux-domain attach/detach APIs.
+ */
+static inline bool
+is_aux_domain(struct device *dev, struct iommu_domain *domain)
 {
-       struct dmar_domain *dmar_domain = to_dmar_domain(domain);
-       struct intel_iommu *iommu;
-       int addr_width;
-       u8 bus, devfn;
+       struct device_domain_info *info = dev->archdata.iommu;
 
-       if (device_is_rmrr_locked(dev)) {
-               dev_warn(dev, "Device is ineligible for IOMMU domain attach due to platform RMRR requirement.  Contact your platform vendor.\n");
-               return -EPERM;
-       }
+       return info && info->auxd_enabled &&
+                       domain->type == IOMMU_DOMAIN_UNMANAGED;
+}
 
-       /* normally dev is not mapped */
-       if (unlikely(domain_context_mapped(dev))) {
-               struct dmar_domain *old_domain;
+static void auxiliary_link_device(struct dmar_domain *domain,
+                                 struct device *dev)
+{
+       struct device_domain_info *info = dev->archdata.iommu;
 
-               old_domain = find_domain(dev);
-               if (old_domain) {
-                       rcu_read_lock();
-                       dmar_remove_one_dev_info(dev);
-                       rcu_read_unlock();
+       assert_spin_locked(&device_domain_lock);
+       if (WARN_ON(!info))
+               return;
 
-                       if (!domain_type_is_vm_or_si(old_domain) &&
-                            list_empty(&old_domain->devices))
-                               domain_exit(old_domain);
+       domain->auxd_refcnt++;
+       list_add(&domain->auxd, &info->auxiliary_domains);
+}
+
+static void auxiliary_unlink_device(struct dmar_domain *domain,
+                                   struct device *dev)
+{
+       struct device_domain_info *info = dev->archdata.iommu;
+
+       assert_spin_locked(&device_domain_lock);
+       if (WARN_ON(!info))
+               return;
+
+       list_del(&domain->auxd);
+       domain->auxd_refcnt--;
+
+       if (!domain->auxd_refcnt && domain->default_pasid > 0)
+               intel_pasid_free_id(domain->default_pasid);
+}
+
+static int aux_domain_add_dev(struct dmar_domain *domain,
+                             struct device *dev)
+{
+       int ret;
+       u8 bus, devfn;
+       unsigned long flags;
+       struct intel_iommu *iommu;
+
+       iommu = device_to_iommu(dev, &bus, &devfn);
+       if (!iommu)
+               return -ENODEV;
+
+       if (domain->default_pasid <= 0) {
+               int pasid;
+
+               pasid = intel_pasid_alloc_id(domain, PASID_MIN,
+                                            pci_max_pasids(to_pci_dev(dev)),
+                                            GFP_KERNEL);
+               if (pasid <= 0) {
+                       pr_err("Can't allocate default pasid\n");
+                       return -ENODEV;
                }
+               domain->default_pasid = pasid;
        }
 
+       spin_lock_irqsave(&device_domain_lock, flags);
+       /*
+        * iommu->lock must be held to attach domain to iommu and setup the
+        * pasid entry for second level translation.
+        */
+       spin_lock(&iommu->lock);
+       ret = domain_attach_iommu(domain, iommu);
+       if (ret)
+               goto attach_failed;
+
+       /* Setup the PASID entry for mediated devices: */
+       ret = intel_pasid_setup_second_level(iommu, domain, dev,
+                                            domain->default_pasid);
+       if (ret)
+               goto table_failed;
+       spin_unlock(&iommu->lock);
+
+       auxiliary_link_device(domain, dev);
+
+       spin_unlock_irqrestore(&device_domain_lock, flags);
+
+       return 0;
+
+table_failed:
+       domain_detach_iommu(domain, iommu);
+attach_failed:
+       spin_unlock(&iommu->lock);
+       spin_unlock_irqrestore(&device_domain_lock, flags);
+       if (!domain->auxd_refcnt && domain->default_pasid > 0)
+               intel_pasid_free_id(domain->default_pasid);
+
+       return ret;
+}
+
+static void aux_domain_remove_dev(struct dmar_domain *domain,
+                                 struct device *dev)
+{
+       struct device_domain_info *info;
+       struct intel_iommu *iommu;
+       unsigned long flags;
+
+       if (!is_aux_domain(dev, &domain->domain))
+               return;
+
+       spin_lock_irqsave(&device_domain_lock, flags);
+       info = dev->archdata.iommu;
+       iommu = info->iommu;
+
+       auxiliary_unlink_device(domain, dev);
+
+       spin_lock(&iommu->lock);
+       intel_pasid_tear_down_entry(iommu, dev, domain->default_pasid);
+       domain_detach_iommu(domain, iommu);
+       spin_unlock(&iommu->lock);
+
+       spin_unlock_irqrestore(&device_domain_lock, flags);
+}
+
+static int prepare_domain_attach_device(struct iommu_domain *domain,
+                                       struct device *dev)
+{
+       struct dmar_domain *dmar_domain = to_dmar_domain(domain);
+       struct intel_iommu *iommu;
+       int addr_width;
+       u8 bus, devfn;
+
        iommu = device_to_iommu(dev, &bus, &devfn);
        if (!iommu)
                return -ENODEV;
@@ -5126,7 +5232,58 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
                dmar_domain->agaw--;
        }
 
-       return domain_add_dev_info(dmar_domain, dev);
+       return 0;
+}
+
+static int intel_iommu_attach_device(struct iommu_domain *domain,
+                                    struct device *dev)
+{
+       int ret;
+
+       if (device_is_rmrr_locked(dev)) {
+               dev_warn(dev, "Device is ineligible for IOMMU domain attach due to platform RMRR requirement.  Contact your platform vendor.\n");
+               return -EPERM;
+       }
+
+       if (is_aux_domain(dev, domain))
+               return -EPERM;
+
+       /* normally dev is not mapped */
+       if (unlikely(domain_context_mapped(dev))) {
+               struct dmar_domain *old_domain;
+
+               old_domain = find_domain(dev);
+               if (old_domain) {
+                       rcu_read_lock();
+                       dmar_remove_one_dev_info(dev);
+                       rcu_read_unlock();
+
+                       if (!domain_type_is_vm_or_si(old_domain) &&
+                           list_empty(&old_domain->devices))
+                               domain_exit(old_domain);
+               }
+       }
+
+       ret = prepare_domain_attach_device(domain, dev);
+       if (ret)
+               return ret;
+
+       return domain_add_dev_info(to_dmar_domain(domain), dev);
+}
+
+static int intel_iommu_aux_attach_device(struct iommu_domain *domain,
+                                        struct device *dev)
+{
+       int ret;
+
+       if (!is_aux_domain(dev, domain))
+               return -EPERM;
+
+       ret = prepare_domain_attach_device(domain, dev);
+       if (ret)
+               return ret;
+
+       return aux_domain_add_dev(to_dmar_domain(domain), dev);
 }
 
 static void intel_iommu_detach_device(struct iommu_domain *domain,
@@ -5135,6 +5292,12 @@ static void intel_iommu_detach_device(struct iommu_domain *domain,
        dmar_remove_one_dev_info(dev);
 }
 
+static void intel_iommu_aux_detach_device(struct iommu_domain *domain,
+                                         struct device *dev)
+{
+       aux_domain_remove_dev(to_dmar_domain(domain), dev);
+}
+
 static int intel_iommu_map(struct iommu_domain *domain,
                           unsigned long iova, phys_addr_t hpa,
                           size_t size, int iommu_prot)
@@ -5223,6 +5386,42 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
        return phys;
 }
 
+static inline bool scalable_mode_support(void)
+{
+       struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu;
+       bool ret = true;
+
+       rcu_read_lock();
+       for_each_active_iommu(iommu, drhd) {
+               if (!sm_supported(iommu)) {
+                       ret = false;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+
+       return ret;
+}
+
+static inline bool iommu_pasid_support(void)
+{
+       struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu;
+       bool ret = true;
+
+       rcu_read_lock();
+       for_each_active_iommu(iommu, drhd) {
+               if (!pasid_supported(iommu)) {
+                       ret = false;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+
+       return ret;
+}
+
 static bool intel_iommu_capable(enum iommu_cap cap)
 {
        if (cap == IOMMU_CAP_CACHE_COHERENCY)
@@ -5307,8 +5506,7 @@ static void intel_iommu_put_resv_regions(struct device *dev,
        }
 }
 
-#ifdef CONFIG_INTEL_IOMMU_SVM
-int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sdev)
+int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct device *dev)
 {
        struct device_domain_info *info;
        struct context_entry *context;
@@ -5317,7 +5515,7 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sd
        u64 ctx_lo;
        int ret;
 
-       domain = get_valid_domain_for_dev(sdev->dev);
+       domain = get_valid_domain_for_dev(dev);
        if (!domain)
                return -EINVAL;
 
@@ -5325,7 +5523,7 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sd
        spin_lock(&iommu->lock);
 
        ret = -EINVAL;
-       info = sdev->dev->archdata.iommu;
+       info = dev->archdata.iommu;
        if (!info || !info->pasid_supported)
                goto out;
 
@@ -5335,14 +5533,13 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sd
 
        ctx_lo = context[0].lo;
 
-       sdev->did = FLPT_DEFAULT_DID;
-       sdev->sid = PCI_DEVID(info->bus, info->devfn);
-
        if (!(ctx_lo & CONTEXT_PASIDE)) {
                ctx_lo |= CONTEXT_PASIDE;
                context[0].lo = ctx_lo;
                wmb();
-               iommu->flush.flush_context(iommu, sdev->did, sdev->sid,
+               iommu->flush.flush_context(iommu,
+                                          domain->iommu_did[iommu->seq_id],
+                                          PCI_DEVID(info->bus, info->devfn),
                                           DMA_CCMD_MASK_NOBIT,
                                           DMA_CCMD_DEVICE_INVL);
        }
@@ -5351,12 +5548,6 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sd
        if (!info->pasid_enabled)
                iommu_enable_dev_iotlb(info);
 
-       if (info->ats_enabled) {
-               sdev->dev_iotlb = 1;
-               sdev->qdep = info->ats_qdep;
-               if (sdev->qdep >= QI_DEV_EIOTLB_MAX_INVS)
-                       sdev->qdep = 0;
-       }
        ret = 0;
 
  out:
@@ -5366,6 +5557,7 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sd
        return ret;
 }
 
+#ifdef CONFIG_INTEL_IOMMU_SVM
 struct intel_iommu *intel_svm_device_to_iommu(struct device *dev)
 {
        struct intel_iommu *iommu;
@@ -5387,12 +5579,142 @@ struct intel_iommu *intel_svm_device_to_iommu(struct device *dev)
 }
 #endif /* CONFIG_INTEL_IOMMU_SVM */
 
+static int intel_iommu_enable_auxd(struct device *dev)
+{
+       struct device_domain_info *info;
+       struct intel_iommu *iommu;
+       unsigned long flags;
+       u8 bus, devfn;
+       int ret;
+
+       iommu = device_to_iommu(dev, &bus, &devfn);
+       if (!iommu || dmar_disabled)
+               return -EINVAL;
+
+       if (!sm_supported(iommu) || !pasid_supported(iommu))
+               return -EINVAL;
+
+       ret = intel_iommu_enable_pasid(iommu, dev);
+       if (ret)
+               return -ENODEV;
+
+       spin_lock_irqsave(&device_domain_lock, flags);
+       info = dev->archdata.iommu;
+       info->auxd_enabled = 1;
+       spin_unlock_irqrestore(&device_domain_lock, flags);
+
+       return 0;
+}
+
+static int intel_iommu_disable_auxd(struct device *dev)
+{
+       struct device_domain_info *info;
+       unsigned long flags;
+
+       spin_lock_irqsave(&device_domain_lock, flags);
+       info = dev->archdata.iommu;
+       if (!WARN_ON(!info))
+               info->auxd_enabled = 0;
+       spin_unlock_irqrestore(&device_domain_lock, flags);
+
+       return 0;
+}
+
+/*
+ * A PCI express designated vendor specific extended capability is defined
+ * in the section 3.7 of Intel scalable I/O virtualization technical spec
+ * for system software and tools to detect endpoint devices supporting the
+ * Intel scalable IO virtualization without host driver dependency.
+ *
+ * Returns the address of the matching extended capability structure within
+ * the device's PCI configuration space or 0 if the device does not support
+ * it.
+ */
+static int siov_find_pci_dvsec(struct pci_dev *pdev)
+{
+       int pos;
+       u16 vendor, id;
+
+       pos = pci_find_next_ext_capability(pdev, 0, 0x23);
+       while (pos) {
+               pci_read_config_word(pdev, pos + 4, &vendor);
+               pci_read_config_word(pdev, pos + 8, &id);
+               if (vendor == PCI_VENDOR_ID_INTEL && id == 5)
+                       return pos;
+
+               pos = pci_find_next_ext_capability(pdev, pos, 0x23);
+       }
+
+       return 0;
+}
+
+static bool
+intel_iommu_dev_has_feat(struct device *dev, enum iommu_dev_features feat)
+{
+       if (feat == IOMMU_DEV_FEAT_AUX) {
+               int ret;
+
+               if (!dev_is_pci(dev) || dmar_disabled ||
+                   !scalable_mode_support() || !iommu_pasid_support())
+                       return false;
+
+               ret = pci_pasid_features(to_pci_dev(dev));
+               if (ret < 0)
+                       return false;
+
+               return !!siov_find_pci_dvsec(to_pci_dev(dev));
+       }
+
+       return false;
+}
+
+static int
+intel_iommu_dev_enable_feat(struct device *dev, enum iommu_dev_features feat)
+{
+       if (feat == IOMMU_DEV_FEAT_AUX)
+               return intel_iommu_enable_auxd(dev);
+
+       return -ENODEV;
+}
+
+static int
+intel_iommu_dev_disable_feat(struct device *dev, enum iommu_dev_features feat)
+{
+       if (feat == IOMMU_DEV_FEAT_AUX)
+               return intel_iommu_disable_auxd(dev);
+
+       return -ENODEV;
+}
+
+static bool
+intel_iommu_dev_feat_enabled(struct device *dev, enum iommu_dev_features feat)
+{
+       struct device_domain_info *info = dev->archdata.iommu;
+
+       if (feat == IOMMU_DEV_FEAT_AUX)
+               return scalable_mode_support() && info && info->auxd_enabled;
+
+       return false;
+}
+
+static int
+intel_iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev)
+{
+       struct dmar_domain *dmar_domain = to_dmar_domain(domain);
+
+       return dmar_domain->default_pasid > 0 ?
+                       dmar_domain->default_pasid : -EINVAL;
+}
+
 const struct iommu_ops intel_iommu_ops = {
        .capable                = intel_iommu_capable,
        .domain_alloc           = intel_iommu_domain_alloc,
        .domain_free            = intel_iommu_domain_free,
        .attach_dev             = intel_iommu_attach_device,
        .detach_dev             = intel_iommu_detach_device,
+       .aux_attach_dev         = intel_iommu_aux_attach_device,
+       .aux_detach_dev         = intel_iommu_aux_detach_device,
+       .aux_get_pasid          = intel_iommu_aux_get_pasid,
        .map                    = intel_iommu_map,
        .unmap                  = intel_iommu_unmap,
        .iova_to_phys           = intel_iommu_iova_to_phys,
@@ -5401,6 +5723,10 @@ const struct iommu_ops intel_iommu_ops = {
        .get_resv_regions       = intel_iommu_get_resv_regions,
        .put_resv_regions       = intel_iommu_put_resv_regions,
        .device_group           = pci_device_group,
+       .dev_has_feat           = intel_iommu_dev_has_feat,
+       .dev_feat_enabled       = intel_iommu_dev_feat_enabled,
+       .dev_enable_feat        = intel_iommu_dev_enable_feat,
+       .dev_disable_feat       = intel_iommu_dev_disable_feat,
        .pgsize_bitmap          = INTEL_IOMMU_PGSIZES,
 };
 
index 03b12d2ee2132fe624eeed719dc486d89279f2e4..2fefeafda437b91541f09a3c5618754516fc96b6 100644 (file)
@@ -154,8 +154,10 @@ int intel_pasid_alloc_table(struct device *dev)
        order = size ? get_order(size) : 0;
        pages = alloc_pages_node(info->iommu->node,
                                 GFP_KERNEL | __GFP_ZERO, order);
-       if (!pages)
+       if (!pages) {
+               kfree(pasid_table);
                return -ENOMEM;
+       }
 
        pasid_table->table = page_address(pages);
        pasid_table->order = order;
index 3a4b09ae8561d965a6ae709b766bd4fe5862c852..8f87304f915c9b7ce264a8b6af279b5a7215952d 100644 (file)
@@ -228,6 +228,7 @@ static LIST_HEAD(global_svm_list);
 int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ops *ops)
 {
        struct intel_iommu *iommu = intel_svm_device_to_iommu(dev);
+       struct device_domain_info *info;
        struct intel_svm_dev *sdev;
        struct intel_svm *svm = NULL;
        struct mm_struct *mm = NULL;
@@ -291,13 +292,29 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_
        }
        sdev->dev = dev;
 
-       ret = intel_iommu_enable_pasid(iommu, sdev);
+       ret = intel_iommu_enable_pasid(iommu, dev);
        if (ret || !pasid) {
                /* If they don't actually want to assign a PASID, this is
                 * just an enabling check/preparation. */
                kfree(sdev);
                goto out;
        }
+
+       info = dev->archdata.iommu;
+       if (!info || !info->pasid_supported) {
+               kfree(sdev);
+               goto out;
+       }
+
+       sdev->did = FLPT_DEFAULT_DID;
+       sdev->sid = PCI_DEVID(info->bus, info->devfn);
+       if (info->ats_enabled) {
+               sdev->dev_iotlb = 1;
+               sdev->qdep = info->ats_qdep;
+               if (sdev->qdep >= QI_DEV_EIOTLB_MAX_INVS)
+                       sdev->qdep = 0;
+       }
+
        /* Finish the setup now we know we're keeping it */
        sdev->users = 1;
        sdev->ops = ops;
index 2d74641b7f7bc5aa51a524e9a018e84cdb8fac9a..4160aa9f3f8086a41b6513c12f67b08b00daf5de 100644 (file)
@@ -424,7 +424,7 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev)
                set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, data.alias);
        else
                set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16,
-                            PCI_DEVID(dev->bus->number, dev->devfn));
+                            pci_dev_id(dev));
 
        return 0;
 }
@@ -548,8 +548,7 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
                goto out_free_table;
        }
 
-       bitmap = kcalloc(BITS_TO_LONGS(INTR_REMAP_TABLE_ENTRIES),
-                        sizeof(long), GFP_ATOMIC);
+       bitmap = bitmap_zalloc(INTR_REMAP_TABLE_ENTRIES, GFP_ATOMIC);
        if (bitmap == NULL) {
                pr_err("IR%d: failed to allocate bitmap\n", iommu->seq_id);
                goto out_free_pages;
@@ -616,7 +615,7 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
        return 0;
 
 out_free_bitmap:
-       kfree(bitmap);
+       bitmap_free(bitmap);
 out_free_pages:
        __free_pages(pages, INTR_REMAP_PAGE_ORDER);
 out_free_table:
@@ -640,7 +639,7 @@ static void intel_teardown_irq_remapping(struct intel_iommu *iommu)
                }
                free_pages((unsigned long)iommu->ir_table->base,
                           INTR_REMAP_PAGE_ORDER);
-               kfree(iommu->ir_table->bitmap);
+               bitmap_free(iommu->ir_table->bitmap);
                kfree(iommu->ir_table);
                iommu->ir_table = NULL;
        }
index 109de67d5d727c227d3970b2879edd60d6478357..67ee6623f9b2a4d07dcae56dfb99fcf6e4edbb0d 100644 (file)
@@ -45,10 +45,6 @@ static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_DMA;
 #endif
 static bool iommu_dma_strict __read_mostly = true;
 
-struct iommu_callback_data {
-       const struct iommu_ops *ops;
-};
-
 struct iommu_group {
        struct kobject kobj;
        struct kobject *devices_kobj;
@@ -1217,9 +1213,6 @@ static int iommu_bus_init(struct bus_type *bus, const struct iommu_ops *ops)
 {
        int err;
        struct notifier_block *nb;
-       struct iommu_callback_data cb = {
-               .ops = ops,
-       };
 
        nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL);
        if (!nb)
@@ -1231,7 +1224,7 @@ static int iommu_bus_init(struct bus_type *bus, const struct iommu_ops *ops)
        if (err)
                goto out_free;
 
-       err = bus_for_each_dev(bus, NULL, &cb, add_iommu_group);
+       err = bus_for_each_dev(bus, NULL, NULL, add_iommu_group);
        if (err)
                goto out_err;
 
@@ -1240,7 +1233,7 @@ static int iommu_bus_init(struct bus_type *bus, const struct iommu_ops *ops)
 
 out_err:
        /* Clean up */
-       bus_for_each_dev(bus, NULL, &cb, remove_iommu_group);
+       bus_for_each_dev(bus, NULL, NULL, remove_iommu_group);
        bus_unregister_notifier(bus, nb);
 
 out_free:
@@ -2039,3 +2032,203 @@ int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
        return 0;
 }
 EXPORT_SYMBOL_GPL(iommu_fwspec_add_ids);
+
+/*
+ * Per device IOMMU features.
+ */
+bool iommu_dev_has_feature(struct device *dev, enum iommu_dev_features feat)
+{
+       const struct iommu_ops *ops = dev->bus->iommu_ops;
+
+       if (ops && ops->dev_has_feat)
+               return ops->dev_has_feat(dev, feat);
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(iommu_dev_has_feature);
+
+int iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features feat)
+{
+       const struct iommu_ops *ops = dev->bus->iommu_ops;
+
+       if (ops && ops->dev_enable_feat)
+               return ops->dev_enable_feat(dev, feat);
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(iommu_dev_enable_feature);
+
+/*
+ * The device drivers should do the necessary cleanups before calling this.
+ * For example, before disabling the aux-domain feature, the device driver
+ * should detach all aux-domains. Otherwise, this will return -EBUSY.
+ */
+int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat)
+{
+       const struct iommu_ops *ops = dev->bus->iommu_ops;
+
+       if (ops && ops->dev_disable_feat)
+               return ops->dev_disable_feat(dev, feat);
+
+       return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(iommu_dev_disable_feature);
+
+bool iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features feat)
+{
+       const struct iommu_ops *ops = dev->bus->iommu_ops;
+
+       if (ops && ops->dev_feat_enabled)
+               return ops->dev_feat_enabled(dev, feat);
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(iommu_dev_feature_enabled);
+
+/*
+ * Aux-domain specific attach/detach.
+ *
+ * Only works if iommu_dev_feature_enabled(dev, IOMMU_DEV_FEAT_AUX) returns
+ * true. Also, as long as domains are attached to a device through this
+ * interface, any tries to call iommu_attach_device() should fail
+ * (iommu_detach_device() can't fail, so we fail when trying to re-attach).
+ * This should make us safe against a device being attached to a guest as a
+ * whole while there are still pasid users on it (aux and sva).
+ */
+int iommu_aux_attach_device(struct iommu_domain *domain, struct device *dev)
+{
+       int ret = -ENODEV;
+
+       if (domain->ops->aux_attach_dev)
+               ret = domain->ops->aux_attach_dev(domain, dev);
+
+       if (!ret)
+               trace_attach_device_to_domain(dev);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_aux_attach_device);
+
+void iommu_aux_detach_device(struct iommu_domain *domain, struct device *dev)
+{
+       if (domain->ops->aux_detach_dev) {
+               domain->ops->aux_detach_dev(domain, dev);
+               trace_detach_device_from_domain(dev);
+       }
+}
+EXPORT_SYMBOL_GPL(iommu_aux_detach_device);
+
+int iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev)
+{
+       int ret = -ENODEV;
+
+       if (domain->ops->aux_get_pasid)
+               ret = domain->ops->aux_get_pasid(domain, dev);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_aux_get_pasid);
+
+/**
+ * iommu_sva_bind_device() - Bind a process address space to a device
+ * @dev: the device
+ * @mm: the mm to bind, caller must hold a reference to it
+ *
+ * Create a bond between device and address space, allowing the device to access
+ * the mm using the returned PASID. If a bond already exists between @device and
+ * @mm, it is returned and an additional reference is taken. Caller must call
+ * iommu_sva_unbind_device() to release each reference.
+ *
+ * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
+ * initialize the required SVA features.
+ *
+ * On error, returns an ERR_PTR value.
+ */
+struct iommu_sva *
+iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
+{
+       struct iommu_group *group;
+       struct iommu_sva *handle = ERR_PTR(-EINVAL);
+       const struct iommu_ops *ops = dev->bus->iommu_ops;
+
+       if (!ops || !ops->sva_bind)
+               return ERR_PTR(-ENODEV);
+
+       group = iommu_group_get(dev);
+       if (!group)
+               return ERR_PTR(-ENODEV);
+
+       /* Ensure device count and domain don't change while we're binding */
+       mutex_lock(&group->mutex);
+
+       /*
+        * To keep things simple, SVA currently doesn't support IOMMU groups
+        * with more than one device. Existing SVA-capable systems are not
+        * affected by the problems that required IOMMU groups (lack of ACS
+        * isolation, device ID aliasing and other hardware issues).
+        */
+       if (iommu_group_device_count(group) != 1)
+               goto out_unlock;
+
+       handle = ops->sva_bind(dev, mm, drvdata);
+
+out_unlock:
+       mutex_unlock(&group->mutex);
+       iommu_group_put(group);
+
+       return handle;
+}
+EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
+
+/**
+ * iommu_sva_unbind_device() - Remove a bond created with iommu_sva_bind_device
+ * @handle: the handle returned by iommu_sva_bind_device()
+ *
+ * Put reference to a bond between device and address space. The device should
+ * not be issuing any more transaction for this PASID. All outstanding page
+ * requests for this PASID must have been flushed to the IOMMU.
+ *
+ * Returns 0 on success, or an error value
+ */
+void iommu_sva_unbind_device(struct iommu_sva *handle)
+{
+       struct iommu_group *group;
+       struct device *dev = handle->dev;
+       const struct iommu_ops *ops = dev->bus->iommu_ops;
+
+       if (!ops || !ops->sva_unbind)
+               return;
+
+       group = iommu_group_get(dev);
+       if (!group)
+               return;
+
+       mutex_lock(&group->mutex);
+       ops->sva_unbind(handle);
+       mutex_unlock(&group->mutex);
+
+       iommu_group_put(group);
+}
+EXPORT_SYMBOL_GPL(iommu_sva_unbind_device);
+
+int iommu_sva_set_ops(struct iommu_sva *handle,
+                     const struct iommu_sva_ops *sva_ops)
+{
+       if (handle->ops && handle->ops != sva_ops)
+               return -EEXIST;
+
+       handle->ops = sva_ops;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iommu_sva_set_ops);
+
+int iommu_sva_get_pasid(struct iommu_sva *handle)
+{
+       const struct iommu_ops *ops = handle->dev->bus->iommu_ops;
+
+       if (!ops || !ops->sva_get_pasid)
+               return IOMMU_PASID_INVALID;
+
+       return ops->sva_get_pasid(handle);
+}
+EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
index 9fb0eb7a4d02be278700244823eb1d3173cfeb0e..b4b87d6ae67f209edd6851264bac306f82db5c1d 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/of_iommu.h>
 
 #include <asm/cacheflush.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include "msm_iommu_hw-8xxx.h"
 #include "msm_iommu.h"
index de3e02277b706390bd70abe8f22fd6f96971ce04..b66d11b0286efb7c73262731558c76a7c09d2bb5 100644 (file)
@@ -632,16 +632,20 @@ static int mtk_iommu_probe(struct platform_device *pdev)
                if (!larbnode)
                        return -EINVAL;
 
-               if (!of_device_is_available(larbnode))
+               if (!of_device_is_available(larbnode)) {
+                       of_node_put(larbnode);
                        continue;
+               }
 
                ret = of_property_read_u32(larbnode, "mediatek,larb-id", &id);
                if (ret)/* The id is consecutive if there is no this property */
                        id = i;
 
                plarbdev = of_find_device_by_node(larbnode);
-               if (!plarbdev)
+               if (!plarbdev) {
+                       of_node_put(larbnode);
                        return -EPROBE_DEFER;
+               }
                data->smi_imu.larb_imu[id].dev = &plarbdev->dev;
 
                component_match_add_release(dev, &match, release_of,
index 5182c7d6171e1a3f569bd765365f4c49326211d1..463ee08f7d3a5956f91d07aed7cf82a01b3ee7fd 100644 (file)
@@ -102,7 +102,6 @@ static inline u32 smmu_readl(struct tegra_smmu *smmu, unsigned long offset)
 #define  SMMU_TLB_FLUSH_VA_MATCH_ALL     (0 << 0)
 #define  SMMU_TLB_FLUSH_VA_MATCH_SECTION (2 << 0)
 #define  SMMU_TLB_FLUSH_VA_MATCH_GROUP   (3 << 0)
-#define  SMMU_TLB_FLUSH_ASID(x)          (((x) & 0x7f) << 24)
 #define  SMMU_TLB_FLUSH_VA_SECTION(addr) ((((addr) & 0xffc00000) >> 12) | \
                                          SMMU_TLB_FLUSH_VA_MATCH_SECTION)
 #define  SMMU_TLB_FLUSH_VA_GROUP(addr)   ((((addr) & 0xffffc000) >> 12) | \
@@ -146,8 +145,6 @@ static inline u32 smmu_readl(struct tegra_smmu *smmu, unsigned long offset)
 
 #define SMMU_PDE_ATTR          (SMMU_PDE_READABLE | SMMU_PDE_WRITABLE | \
                                 SMMU_PDE_NONSECURE)
-#define SMMU_PTE_ATTR          (SMMU_PTE_READABLE | SMMU_PTE_WRITABLE | \
-                                SMMU_PTE_NONSECURE)
 
 static unsigned int iova_pd_index(unsigned long iova)
 {
@@ -205,8 +202,12 @@ static inline void smmu_flush_tlb_asid(struct tegra_smmu *smmu,
 {
        u32 value;
 
-       value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
-               SMMU_TLB_FLUSH_VA_MATCH_ALL;
+       if (smmu->soc->num_asids == 4)
+               value = (asid & 0x3) << 29;
+       else
+               value = (asid & 0x7f) << 24;
+
+       value |= SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_VA_MATCH_ALL;
        smmu_writel(smmu, value, SMMU_TLB_FLUSH);
 }
 
@@ -216,8 +217,12 @@ static inline void smmu_flush_tlb_section(struct tegra_smmu *smmu,
 {
        u32 value;
 
-       value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
-               SMMU_TLB_FLUSH_VA_SECTION(iova);
+       if (smmu->soc->num_asids == 4)
+               value = (asid & 0x3) << 29;
+       else
+               value = (asid & 0x7f) << 24;
+
+       value |= SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_VA_SECTION(iova);
        smmu_writel(smmu, value, SMMU_TLB_FLUSH);
 }
 
@@ -227,8 +232,12 @@ static inline void smmu_flush_tlb_group(struct tegra_smmu *smmu,
 {
        u32 value;
 
-       value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
-               SMMU_TLB_FLUSH_VA_GROUP(iova);
+       if (smmu->soc->num_asids == 4)
+               value = (asid & 0x3) << 29;
+       else
+               value = (asid & 0x7f) << 24;
+
+       value |= SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_VA_GROUP(iova);
        smmu_writel(smmu, value, SMMU_TLB_FLUSH);
 }
 
@@ -316,6 +325,9 @@ static void tegra_smmu_domain_free(struct iommu_domain *domain)
 
        /* TODO: free page directory and page tables */
 
+       WARN_ON_ONCE(as->use_count);
+       kfree(as->count);
+       kfree(as->pts);
        kfree(as);
 }
 
@@ -645,6 +657,7 @@ static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova,
 {
        struct tegra_smmu_as *as = to_smmu_as(domain);
        dma_addr_t pte_dma;
+       u32 pte_attrs;
        u32 *pte;
 
        pte = as_get_pte(as, iova, &pte_dma);
@@ -655,8 +668,16 @@ static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova,
        if (*pte == 0)
                tegra_smmu_pte_get_use(as, iova);
 
+       pte_attrs = SMMU_PTE_NONSECURE;
+
+       if (prot & IOMMU_READ)
+               pte_attrs |= SMMU_PTE_READABLE;
+
+       if (prot & IOMMU_WRITE)
+               pte_attrs |= SMMU_PTE_WRITABLE;
+
        tegra_smmu_set_pte(as, iova, pte, pte_dma,
-                          __phys_to_pfn(paddr) | SMMU_PTE_ATTR);
+                          __phys_to_pfn(paddr) | pte_attrs);
 
        return 0;
 }
index 5438abb1babaf042eb9190e7de2b1aa1161285bc..cf7984991062987e30e9119cfe9164dc9fea4c5b 100644 (file)
@@ -160,6 +160,12 @@ config IMGPDC_IRQ
        select GENERIC_IRQ_CHIP
        select IRQ_DOMAIN
 
+config IXP4XX_IRQ
+       bool
+       select IRQ_DOMAIN
+       select GENERIC_IRQ_MULTI_HANDLER
+       select SPARSE_IRQ
+
 config MADERA_IRQ
        tristate
 
index 85972ae1bd7f978bab67cef8ebc0d9effa6edb63..f8c66e958a64deaad16fea727ab5d9f2ace020bc 100644 (file)
@@ -43,6 +43,7 @@ obj-$(CONFIG_ATMEL_AIC5_IRQ)  += irq-atmel-aic-common.o irq-atmel-aic5.o
 obj-$(CONFIG_I8259)                    += irq-i8259.o
 obj-$(CONFIG_IMGPDC_IRQ)               += irq-imgpdc.o
 obj-$(CONFIG_IRQ_MIPS_CPU)             += irq-mips-cpu.o
+obj-$(CONFIG_IXP4XX_IRQ)               += irq-ixp4xx.o
 obj-$(CONFIG_SIRF_IRQ)                 += irq-sirfsoc.o
 obj-$(CONFIG_JCORE_AIC)                        += irq-jcore-aic.o
 obj-$(CONFIG_RDA_INTC)                 += irq-rda-intc.o
diff --git a/drivers/irqchip/irq-ixp4xx.c b/drivers/irqchip/irq-ixp4xx.c
new file mode 100644 (file)
index 0000000..d576809
--- /dev/null
@@ -0,0 +1,403 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * irqchip for the IXP4xx interrupt controller
+ * Copyright (C) 2019 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * Based on arch/arm/mach-ixp4xx/common.c
+ * Copyright 2002 (C) Intel Corporation
+ * Copyright 2003-2004 (C) MontaVista, Software, Inc.
+ * Copyright (C) Deepak Saxena <dsaxena@plexity.net>
+ */
+#include <linux/bitops.h>
+#include <linux/gpio/driver.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/irq-ixp4xx.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/cpu.h>
+
+#include <asm/exception.h>
+#include <asm/mach/irq.h>
+
+#define IXP4XX_ICPR    0x00 /* Interrupt Status */
+#define IXP4XX_ICMR    0x04 /* Interrupt Enable */
+#define IXP4XX_ICLR    0x08 /* Interrupt IRQ/FIQ Select */
+#define IXP4XX_ICIP    0x0C /* IRQ Status */
+#define IXP4XX_ICFP    0x10 /* FIQ Status */
+#define IXP4XX_ICHR    0x14 /* Interrupt Priority */
+#define IXP4XX_ICIH    0x18 /* IRQ Highest Pri Int */
+#define IXP4XX_ICFH    0x1C /* FIQ Highest Pri Int */
+
+/* IXP43x and IXP46x-only */
+#define        IXP4XX_ICPR2    0x20 /* Interrupt Status 2 */
+#define        IXP4XX_ICMR2    0x24 /* Interrupt Enable 2 */
+#define        IXP4XX_ICLR2    0x28 /* Interrupt IRQ/FIQ Select 2 */
+#define IXP4XX_ICIP2   0x2C /* IRQ Status */
+#define IXP4XX_ICFP2   0x30 /* FIQ Status */
+#define IXP4XX_ICEEN   0x34 /* Error High Pri Enable */
+
+/**
+ * struct ixp4xx_irq - state container for the Faraday IRQ controller
+ * @irqbase: IRQ controller memory base in virtual memory
+ * @is_356: if this is an IXP43x, IXP45x or IX46x SoC (with 64 IRQs)
+ * @irqchip: irqchip for this instance
+ * @domain: IRQ domain for this instance
+ */
+struct ixp4xx_irq {
+       void __iomem *irqbase;
+       bool is_356;
+       struct irq_chip irqchip;
+       struct irq_domain *domain;
+};
+
+/* Local static state container */
+static struct ixp4xx_irq ixirq;
+
+/* GPIO Clocks */
+#define IXP4XX_GPIO_CLK_0              14
+#define IXP4XX_GPIO_CLK_1              15
+
+static int ixp4xx_set_irq_type(struct irq_data *d, unsigned int type)
+{
+       /* All are level active high (asserted) here */
+       if (type != IRQ_TYPE_LEVEL_HIGH)
+               return -EINVAL;
+       return 0;
+}
+
+static void ixp4xx_irq_mask(struct irq_data *d)
+{
+       struct ixp4xx_irq *ixi = irq_data_get_irq_chip_data(d);
+       u32 val;
+
+       if (ixi->is_356 && d->hwirq >= 32) {
+               val = __raw_readl(ixi->irqbase + IXP4XX_ICMR2);
+               val &= ~BIT(d->hwirq - 32);
+               __raw_writel(val, ixi->irqbase + IXP4XX_ICMR2);
+       } else {
+               val = __raw_readl(ixi->irqbase + IXP4XX_ICMR);
+               val &= ~BIT(d->hwirq);
+               __raw_writel(val, ixi->irqbase + IXP4XX_ICMR);
+       }
+}
+
+/*
+ * Level triggered interrupts on GPIO lines can only be cleared when the
+ * interrupt condition disappears.
+ */
+static void ixp4xx_irq_unmask(struct irq_data *d)
+{
+       struct ixp4xx_irq *ixi = irq_data_get_irq_chip_data(d);
+       u32 val;
+
+       if (ixi->is_356 && d->hwirq >= 32) {
+               val = __raw_readl(ixi->irqbase + IXP4XX_ICMR2);
+               val |= BIT(d->hwirq - 32);
+               __raw_writel(val, ixi->irqbase + IXP4XX_ICMR2);
+       } else {
+               val = __raw_readl(ixi->irqbase + IXP4XX_ICMR);
+               val |= BIT(d->hwirq);
+               __raw_writel(val, ixi->irqbase + IXP4XX_ICMR);
+       }
+}
+
+asmlinkage void __exception_irq_entry ixp4xx_handle_irq(struct pt_regs *regs)
+{
+       struct ixp4xx_irq *ixi = &ixirq;
+       unsigned long status;
+       int i;
+
+       status = __raw_readl(ixi->irqbase + IXP4XX_ICIP);
+       for_each_set_bit(i, &status, 32)
+               handle_domain_irq(ixi->domain, i, regs);
+
+       /*
+        * IXP465/IXP435 has an upper IRQ status register
+        */
+       if (ixi->is_356) {
+               status = __raw_readl(ixi->irqbase + IXP4XX_ICIP2);
+               for_each_set_bit(i, &status, 32)
+                       handle_domain_irq(ixi->domain, i + 32, regs);
+       }
+}
+
+static int ixp4xx_irq_domain_translate(struct irq_domain *domain,
+                                      struct irq_fwspec *fwspec,
+                                      unsigned long *hwirq,
+                                      unsigned int *type)
+{
+       /* We support standard DT translation */
+       if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
+               *hwirq = fwspec->param[0];
+               *type = fwspec->param[1];
+               return 0;
+       }
+
+       if (is_fwnode_irqchip(fwspec->fwnode)) {
+               if (fwspec->param_count != 2)
+                       return -EINVAL;
+               *hwirq = fwspec->param[0];
+               *type = fwspec->param[1];
+               WARN_ON(*type == IRQ_TYPE_NONE);
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int ixp4xx_irq_domain_alloc(struct irq_domain *d,
+                                  unsigned int irq, unsigned int nr_irqs,
+                                  void *data)
+{
+       struct ixp4xx_irq *ixi = d->host_data;
+       irq_hw_number_t hwirq;
+       unsigned int type = IRQ_TYPE_NONE;
+       struct irq_fwspec *fwspec = data;
+       int ret;
+       int i;
+
+       ret = ixp4xx_irq_domain_translate(d, fwspec, &hwirq, &type);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < nr_irqs; i++) {
+               /*
+                * TODO: after converting IXP4xx to only device tree, set
+                * handle_bad_irq as default handler and assume all consumers
+                * call .set_type() as this is provided in the second cell in
+                * the device tree phandle.
+                */
+               irq_domain_set_info(d,
+                                   irq + i,
+                                   hwirq + i,
+                                   &ixi->irqchip,
+                                   ixi,
+                                   handle_level_irq,
+                                   NULL, NULL);
+               irq_set_probe(irq + i);
+       }
+
+       return 0;
+}
+
+/*
+ * This needs to be a hierarchical irqdomain to work well with the
+ * GPIO irqchip (which is lower in the hierarchy)
+ */
+static const struct irq_domain_ops ixp4xx_irqdomain_ops = {
+       .translate = ixp4xx_irq_domain_translate,
+       .alloc = ixp4xx_irq_domain_alloc,
+       .free = irq_domain_free_irqs_common,
+};
+
+/**
+ * ixp4xx_get_irq_domain() - retrieve the ixp4xx irq domain
+ *
+ * This function will go away when we transition to DT probing.
+ */
+struct irq_domain *ixp4xx_get_irq_domain(void)
+{
+       struct ixp4xx_irq *ixi = &ixirq;
+
+       return ixi->domain;
+}
+EXPORT_SYMBOL_GPL(ixp4xx_get_irq_domain);
+
+/*
+ * This is the Linux IRQ to hwirq mapping table. This goes away when
+ * we have DT support as all IRQ resources are defined in the device
+ * tree. It will register all the IRQs that are not used by the hierarchical
+ * GPIO IRQ chip. The "holes" inbetween these IRQs will be requested by
+ * the GPIO driver using . This is a step-gap solution.
+ */
+struct ixp4xx_irq_chunk {
+       int irq;
+       int hwirq;
+       int nr_irqs;
+};
+
+static const struct ixp4xx_irq_chunk ixp4xx_irq_chunks[] = {
+       {
+               .irq = 16,
+               .hwirq = 0,
+               .nr_irqs = 6,
+       },
+       {
+               .irq = 24,
+               .hwirq = 8,
+               .nr_irqs = 11,
+       },
+       {
+               .irq = 46,
+               .hwirq = 30,
+               .nr_irqs = 2,
+       },
+       /* Only on the 436 variants */
+       {
+               .irq = 48,
+               .hwirq = 32,
+               .nr_irqs = 10,
+       },
+};
+
+/**
+ * ixp4x_irq_setup() - Common setup code for the IXP4xx interrupt controller
+ * @ixi: State container
+ * @irqbase: Virtual memory base for the interrupt controller
+ * @fwnode: Corresponding fwnode abstraction for this controller
+ * @is_356: if this is an IXP43x, IXP45x or IXP46x SoC variant
+ */
+static int ixp4xx_irq_setup(struct ixp4xx_irq *ixi,
+                           void __iomem *irqbase,
+                           struct fwnode_handle *fwnode,
+                           bool is_356)
+{
+       int nr_irqs;
+
+       ixi->irqbase = irqbase;
+       ixi->is_356 = is_356;
+
+       /* Route all sources to IRQ instead of FIQ */
+       __raw_writel(0x0, ixi->irqbase + IXP4XX_ICLR);
+
+       /* Disable all interrupts */
+       __raw_writel(0x0, ixi->irqbase + IXP4XX_ICMR);
+
+       if (is_356) {
+               /* Route upper 32 sources to IRQ instead of FIQ */
+               __raw_writel(0x0, ixi->irqbase + IXP4XX_ICLR2);
+
+               /* Disable upper 32 interrupts */
+               __raw_writel(0x0, ixi->irqbase + IXP4XX_ICMR2);
+
+               nr_irqs = 64;
+       } else {
+               nr_irqs = 32;
+       }
+
+       ixi->irqchip.name = "IXP4xx";
+       ixi->irqchip.irq_mask = ixp4xx_irq_mask;
+       ixi->irqchip.irq_unmask = ixp4xx_irq_unmask;
+       ixi->irqchip.irq_set_type = ixp4xx_set_irq_type;
+
+       ixi->domain = irq_domain_create_linear(fwnode, nr_irqs,
+                                              &ixp4xx_irqdomain_ops,
+                                              ixi);
+       if (!ixi->domain) {
+               pr_crit("IXP4XX: can not add primary irqdomain\n");
+               return -ENODEV;
+       }
+
+       set_handle_irq(ixp4xx_handle_irq);
+
+       return 0;
+}
+
+/**
+ * ixp4xx_irq_init() - Function to initialize the irqchip from boardfiles
+ * @irqbase: physical base for the irq controller
+ * @is_356: if this is an IXP43x, IXP45x or IXP46x SoC variant
+ */
+void __init ixp4xx_irq_init(resource_size_t irqbase,
+                           bool is_356)
+{
+       struct ixp4xx_irq *ixi = &ixirq;
+       void __iomem *base;
+       struct fwnode_handle *fwnode;
+       struct irq_fwspec fwspec;
+       int nr_chunks;
+       int ret;
+       int i;
+
+       base = ioremap(irqbase, 0x100);
+       if (!base) {
+               pr_crit("IXP4XX: could not ioremap interrupt controller\n");
+               return;
+       }
+       fwnode = irq_domain_alloc_fwnode(base);
+       if (!fwnode) {
+               pr_crit("IXP4XX: no domain handle\n");
+               return;
+       }
+       ret = ixp4xx_irq_setup(ixi, base, fwnode, is_356);
+       if (ret) {
+               pr_crit("IXP4XX: failed to set up irqchip\n");
+               irq_domain_free_fwnode(fwnode);
+       }
+
+       nr_chunks = ARRAY_SIZE(ixp4xx_irq_chunks);
+       if (!is_356)
+               nr_chunks--;
+
+       /*
+        * After adding OF support, this is no longer needed: irqs
+        * will be allocated for the respective fwnodes.
+        */
+       for (i = 0; i < nr_chunks; i++) {
+               const struct ixp4xx_irq_chunk *chunk = &ixp4xx_irq_chunks[i];
+
+               pr_info("Allocate Linux IRQs %d..%d HW IRQs %d..%d\n",
+                       chunk->irq, chunk->irq + chunk->nr_irqs - 1,
+                       chunk->hwirq, chunk->hwirq + chunk->nr_irqs - 1);
+               fwspec.fwnode = fwnode;
+               fwspec.param[0] = chunk->hwirq;
+               fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH;
+               fwspec.param_count = 2;
+               ret = __irq_domain_alloc_irqs(ixi->domain,
+                                             chunk->irq,
+                                             chunk->nr_irqs,
+                                             NUMA_NO_NODE,
+                                             &fwspec,
+                                             false,
+                                             NULL);
+               if (ret < 0) {
+                       pr_crit("IXP4XX: can not allocate irqs in hierarchy %d\n",
+                               ret);
+                       return;
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(ixp4xx_irq_init);
+
+#ifdef CONFIG_OF
+int __init ixp4xx_of_init_irq(struct device_node *np,
+                             struct device_node *parent)
+{
+       struct ixp4xx_irq *ixi = &ixirq;
+       void __iomem *base;
+       struct fwnode_handle *fwnode;
+       bool is_356;
+       int ret;
+
+       base = of_iomap(np, 0);
+       if (!base) {
+               pr_crit("IXP4XX: could not ioremap interrupt controller\n");
+               return -ENODEV;
+       }
+       fwnode = of_node_to_fwnode(np);
+
+       /* These chip variants have 64 interrupts */
+       is_356 = of_device_is_compatible(np, "intel,ixp43x-interrupt") ||
+               of_device_is_compatible(np, "intel,ixp45x-interrupt") ||
+               of_device_is_compatible(np, "intel,ixp46x-interrupt");
+
+       ret = ixp4xx_irq_setup(ixi, base, fwnode, is_356);
+       if (ret)
+               pr_crit("IXP4XX: failed to set up irqchip\n");
+
+       return ret;
+}
+IRQCHIP_DECLARE(ixp42x, "intel,ixp42x-interrupt",
+               ixp4xx_of_init_irq);
+IRQCHIP_DECLARE(ixp43x, "intel,ixp43x-interrupt",
+               ixp4xx_of_init_irq);
+IRQCHIP_DECLARE(ixp45x, "intel,ixp45x-interrupt",
+               ixp4xx_of_init_irq);
+IRQCHIP_DECLARE(ixp46x, "intel,ixp46x-interrupt",
+               ixp4xx_of_init_irq);
+#endif
index f3000ccb8d35e33aba9629b686f3d1f19684559a..71be87bdb926138686dea4e0f4d875fb3694dc02 100644 (file)
@@ -619,6 +619,12 @@ config LEDS_TLC591XX
          This option enables support for Texas Instruments TLC59108
          and TLC59116 LED controllers.
 
+config LEDS_MAX77650
+       tristate "LED support for Maxim MAX77650 PMIC"
+       depends on LEDS_CLASS && MFD_MAX77650
+       help
+         LEDs driver for MAX77650 family of PMICs from Maxim Integrated.
+
 config LEDS_MAX77693
        tristate "LED support for MAX77693 Flash"
        depends on LEDS_CLASS_FLASH
index 7a8b1f55d4598d7852ada86382c8a09481c28bec..1e9702ebffeed65064c365df5ea7a7208af8d86e 100644 (file)
@@ -62,6 +62,7 @@ obj-$(CONFIG_LEDS_MC13783)            += leds-mc13783.o
 obj-$(CONFIG_LEDS_NS2)                 += leds-ns2.o
 obj-$(CONFIG_LEDS_NETXBIG)             += leds-netxbig.o
 obj-$(CONFIG_LEDS_ASIC3)               += leds-asic3.o
+obj-$(CONFIG_LEDS_MAX77650)            += leds-max77650.o
 obj-$(CONFIG_LEDS_MAX77693)            += leds-max77693.o
 obj-$(CONFIG_LEDS_MAX8997)             += leds-max8997.o
 obj-$(CONFIG_LEDS_LM355x)              += leds-lm355x.o
diff --git a/drivers/leds/leds-max77650.c b/drivers/leds/leds-max77650.c
new file mode 100644 (file)
index 0000000..6b74ce9
--- /dev/null
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 BayLibre SAS
+// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+//
+// LED driver for MAXIM 77650/77651 charger/power-supply.
+
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/mfd/max77650.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MAX77650_LED_NUM_LEDS          3
+
+#define MAX77650_LED_A_BASE            0x40
+#define MAX77650_LED_B_BASE            0x43
+
+#define MAX77650_LED_BR_MASK           GENMASK(4, 0)
+#define MAX77650_LED_EN_MASK           GENMASK(7, 6)
+
+#define MAX77650_LED_MAX_BRIGHTNESS    MAX77650_LED_BR_MASK
+
+/* Enable EN_LED_MSTR. */
+#define MAX77650_LED_TOP_DEFAULT       BIT(0)
+
+#define MAX77650_LED_ENABLE            GENMASK(7, 6)
+#define MAX77650_LED_DISABLE           0x00
+
+#define MAX77650_LED_A_DEFAULT         MAX77650_LED_DISABLE
+/* 100% on duty */
+#define MAX77650_LED_B_DEFAULT         GENMASK(3, 0)
+
+struct max77650_led {
+       struct led_classdev cdev;
+       struct regmap *map;
+       unsigned int regA;
+       unsigned int regB;
+};
+
+static struct max77650_led *max77650_to_led(struct led_classdev *cdev)
+{
+       return container_of(cdev, struct max77650_led, cdev);
+}
+
+static int max77650_led_brightness_set(struct led_classdev *cdev,
+                                      enum led_brightness brightness)
+{
+       struct max77650_led *led = max77650_to_led(cdev);
+       int val, mask;
+
+       mask = MAX77650_LED_BR_MASK | MAX77650_LED_EN_MASK;
+
+       if (brightness == LED_OFF)
+               val = MAX77650_LED_DISABLE;
+       else
+               val = MAX77650_LED_ENABLE | brightness;
+
+       return regmap_update_bits(led->map, led->regA, mask, val);
+}
+
+static int max77650_led_probe(struct platform_device *pdev)
+{
+       struct device_node *of_node, *child;
+       struct max77650_led *leds, *led;
+       struct device *parent;
+       struct device *dev;
+       struct regmap *map;
+       const char *label;
+       int rv, num_leds;
+       u32 reg;
+
+       dev = &pdev->dev;
+       parent = dev->parent;
+       of_node = dev->of_node;
+
+       if (!of_node)
+               return -ENODEV;
+
+       leds = devm_kcalloc(dev, sizeof(*leds),
+                           MAX77650_LED_NUM_LEDS, GFP_KERNEL);
+       if (!leds)
+               return -ENOMEM;
+
+       map = dev_get_regmap(dev->parent, NULL);
+       if (!map)
+               return -ENODEV;
+
+       num_leds = of_get_child_count(of_node);
+       if (!num_leds || num_leds > MAX77650_LED_NUM_LEDS)
+               return -ENODEV;
+
+       for_each_child_of_node(of_node, child) {
+               rv = of_property_read_u32(child, "reg", &reg);
+               if (rv || reg >= MAX77650_LED_NUM_LEDS)
+                       return -EINVAL;
+
+               led = &leds[reg];
+               led->map = map;
+               led->regA = MAX77650_LED_A_BASE + reg;
+               led->regB = MAX77650_LED_B_BASE + reg;
+               led->cdev.brightness_set_blocking = max77650_led_brightness_set;
+               led->cdev.max_brightness = MAX77650_LED_MAX_BRIGHTNESS;
+
+               label = of_get_property(child, "label", NULL);
+               if (!label) {
+                       led->cdev.name = "max77650::";
+               } else {
+                       led->cdev.name = devm_kasprintf(dev, GFP_KERNEL,
+                                                       "max77650:%s", label);
+                       if (!led->cdev.name)
+                               return -ENOMEM;
+               }
+
+               of_property_read_string(child, "linux,default-trigger",
+                                       &led->cdev.default_trigger);
+
+               rv = devm_of_led_classdev_register(dev, child, &led->cdev);
+               if (rv)
+                       return rv;
+
+               rv = regmap_write(map, led->regA, MAX77650_LED_A_DEFAULT);
+               if (rv)
+                       return rv;
+
+               rv = regmap_write(map, led->regB, MAX77650_LED_B_DEFAULT);
+               if (rv)
+                       return rv;
+       }
+
+       return regmap_write(map,
+                           MAX77650_REG_CNFG_LED_TOP,
+                           MAX77650_LED_TOP_DEFAULT);
+}
+
+static struct platform_driver max77650_led_driver = {
+       .driver = {
+               .name = "max77650-led",
+       },
+       .probe = max77650_led_probe,
+};
+module_platform_driver(max77650_led_driver);
+
+MODULE_DESCRIPTION("MAXIM 77650/77651 LED driver");
+MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
+MODULE_LICENSE("GPL v2");
index 5f82036fe322ce6e29a72ce33ba685996f7ae6a9..0df7454832efe082af142892d54fbcc6e3635028 100644 (file)
@@ -45,6 +45,8 @@ struct nvm_dev_map {
        int num_ch;
 };
 
+static void nvm_free(struct kref *ref);
+
 static struct nvm_target *nvm_find_target(struct nvm_dev *dev, const char *name)
 {
        struct nvm_target *tgt;
@@ -325,6 +327,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
        struct nvm_target *t;
        struct nvm_tgt_dev *tgt_dev;
        void *targetdata;
+       unsigned int mdts;
        int ret;
 
        switch (create->conf.type) {
@@ -412,8 +415,12 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
        tdisk->private_data = targetdata;
        tqueue->queuedata = targetdata;
 
-       blk_queue_max_hw_sectors(tqueue,
-                       (dev->geo.csecs >> 9) * NVM_MAX_VLBA);
+       mdts = (dev->geo.csecs >> 9) * NVM_MAX_VLBA;
+       if (dev->geo.mdts) {
+               mdts = min_t(u32, dev->geo.mdts,
+                               (dev->geo.csecs >> 9) * NVM_MAX_VLBA);
+       }
+       blk_queue_max_hw_sectors(tqueue, mdts);
 
        set_capacity(tdisk, tt->capacity(targetdata));
        add_disk(tdisk);
@@ -476,7 +483,6 @@ static void __nvm_remove_target(struct nvm_target *t, bool graceful)
 
 /**
  * nvm_remove_tgt - Removes a target from the media manager
- * @dev:       device
  * @remove:    ioctl structure with target name to remove.
  *
  * Returns:
@@ -484,18 +490,28 @@ static void __nvm_remove_target(struct nvm_target *t, bool graceful)
  * 1: on not found
  * <0: on error
  */
-static int nvm_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove)
+static int nvm_remove_tgt(struct nvm_ioctl_remove *remove)
 {
        struct nvm_target *t;
+       struct nvm_dev *dev;
 
-       mutex_lock(&dev->mlock);
-       t = nvm_find_target(dev, remove->tgtname);
-       if (!t) {
+       down_read(&nvm_lock);
+       list_for_each_entry(dev, &nvm_devices, devices) {
+               mutex_lock(&dev->mlock);
+               t = nvm_find_target(dev, remove->tgtname);
+               if (t) {
+                       mutex_unlock(&dev->mlock);
+                       break;
+               }
                mutex_unlock(&dev->mlock);
-               return 1;
        }
+       up_read(&nvm_lock);
+
+       if (!t)
+               return 1;
+
        __nvm_remove_target(t, true);
-       mutex_unlock(&dev->mlock);
+       kref_put(&dev->ref, nvm_free);
 
        return 0;
 }
@@ -1089,15 +1105,16 @@ err_fmtype:
        return ret;
 }
 
-static void nvm_free(struct nvm_dev *dev)
+static void nvm_free(struct kref *ref)
 {
-       if (!dev)
-               return;
+       struct nvm_dev *dev = container_of(ref, struct nvm_dev, ref);
 
        if (dev->dma_pool)
                dev->ops->destroy_dma_pool(dev->dma_pool);
 
-       nvm_unregister_map(dev);
+       if (dev->rmap)
+               nvm_unregister_map(dev);
+
        kfree(dev->lun_map);
        kfree(dev);
 }
@@ -1134,7 +1151,13 @@ err:
 
 struct nvm_dev *nvm_alloc_dev(int node)
 {
-       return kzalloc_node(sizeof(struct nvm_dev), GFP_KERNEL, node);
+       struct nvm_dev *dev;
+
+       dev = kzalloc_node(sizeof(struct nvm_dev), GFP_KERNEL, node);
+       if (dev)
+               kref_init(&dev->ref);
+
+       return dev;
 }
 EXPORT_SYMBOL(nvm_alloc_dev);
 
@@ -1142,12 +1165,16 @@ int nvm_register(struct nvm_dev *dev)
 {
        int ret, exp_pool_size;
 
-       if (!dev->q || !dev->ops)
+       if (!dev->q || !dev->ops) {
+               kref_put(&dev->ref, nvm_free);
                return -EINVAL;
+       }
 
        ret = nvm_init(dev);
-       if (ret)
+       if (ret) {
+               kref_put(&dev->ref, nvm_free);
                return ret;
+       }
 
        exp_pool_size = max_t(int, PAGE_SIZE,
                              (NVM_MAX_VLBA * (sizeof(u64) + dev->geo.sos)));
@@ -1157,7 +1184,7 @@ int nvm_register(struct nvm_dev *dev)
                                                  exp_pool_size);
        if (!dev->dma_pool) {
                pr_err("nvm: could not create dma pool\n");
-               nvm_free(dev);
+               kref_put(&dev->ref, nvm_free);
                return -ENOMEM;
        }
 
@@ -1179,6 +1206,7 @@ void nvm_unregister(struct nvm_dev *dev)
                if (t->dev->parent != dev)
                        continue;
                __nvm_remove_target(t, false);
+               kref_put(&dev->ref, nvm_free);
        }
        mutex_unlock(&dev->mlock);
 
@@ -1186,13 +1214,14 @@ void nvm_unregister(struct nvm_dev *dev)
        list_del(&dev->devices);
        up_write(&nvm_lock);
 
-       nvm_free(dev);
+       kref_put(&dev->ref, nvm_free);
 }
 EXPORT_SYMBOL(nvm_unregister);
 
 static int __nvm_configure_create(struct nvm_ioctl_create *create)
 {
        struct nvm_dev *dev;
+       int ret;
 
        down_write(&nvm_lock);
        dev = nvm_find_nvm_dev(create->dev);
@@ -1203,7 +1232,12 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create)
                return -EINVAL;
        }
 
-       return nvm_create_tgt(dev, create);
+       kref_get(&dev->ref);
+       ret = nvm_create_tgt(dev, create);
+       if (ret)
+               kref_put(&dev->ref, nvm_free);
+
+       return ret;
 }
 
 static long nvm_ioctl_info(struct file *file, void __user *arg)
@@ -1322,8 +1356,6 @@ static long nvm_ioctl_dev_create(struct file *file, void __user *arg)
 static long nvm_ioctl_dev_remove(struct file *file, void __user *arg)
 {
        struct nvm_ioctl_remove remove;
-       struct nvm_dev *dev;
-       int ret = 0;
 
        if (copy_from_user(&remove, arg, sizeof(struct nvm_ioctl_remove)))
                return -EFAULT;
@@ -1335,13 +1367,7 @@ static long nvm_ioctl_dev_remove(struct file *file, void __user *arg)
                return -EINVAL;
        }
 
-       list_for_each_entry(dev, &nvm_devices, devices) {
-               ret = nvm_remove_tgt(dev, &remove);
-               if (!ret)
-                       break;
-       }
-
-       return ret;
+       return nvm_remove_tgt(&remove);
 }
 
 /* kept for compatibility reasons */
index c9fa26f9565980602b445633bef3f0a0df9f3f64..5c1034c22197c18126ba0339829a3c1dd7445511 100644 (file)
@@ -18,7 +18,8 @@
 
 #include "pblk.h"
 
-int pblk_write_to_cache(struct pblk *pblk, struct bio *bio, unsigned long flags)
+void pblk_write_to_cache(struct pblk *pblk, struct bio *bio,
+                               unsigned long flags)
 {
        struct request_queue *q = pblk->dev->q;
        struct pblk_w_ctx w_ctx;
@@ -43,6 +44,7 @@ retry:
                goto retry;
        case NVM_IO_ERR:
                pblk_pipeline_stop(pblk);
+               bio_io_error(bio);
                goto out;
        }
 
@@ -79,7 +81,9 @@ retry:
 out:
        generic_end_io_acct(q, REQ_OP_WRITE, &pblk->disk->part0, start_time);
        pblk_write_should_kick(pblk);
-       return ret;
+
+       if (ret == NVM_IO_DONE)
+               bio_endio(bio);
 }
 
 /*
index 6ca868868feed23b559b303067c7460f6cceb6fb..7735378043199dd1eb1437449bfcce0d994965f5 100644 (file)
@@ -562,11 +562,9 @@ int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd)
 
 int pblk_submit_io_sync_sem(struct pblk *pblk, struct nvm_rq *rqd)
 {
-       struct ppa_addr *ppa_list;
+       struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
        int ret;
 
-       ppa_list = (rqd->nr_ppas > 1) ? rqd->ppa_list : &rqd->ppa_addr;
-
        pblk_down_chunk(pblk, ppa_list[0]);
        ret = pblk_submit_io_sync(pblk, rqd);
        pblk_up_chunk(pblk, ppa_list[0]);
@@ -725,6 +723,7 @@ int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line)
        struct nvm_tgt_dev *dev = pblk->dev;
        struct pblk_line_meta *lm = &pblk->lm;
        struct bio *bio;
+       struct ppa_addr *ppa_list;
        struct nvm_rq rqd;
        u64 paddr = pblk_line_smeta_start(pblk, line);
        int i, ret;
@@ -748,9 +747,10 @@ int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line)
        rqd.opcode = NVM_OP_PREAD;
        rqd.nr_ppas = lm->smeta_sec;
        rqd.is_seq = 1;
+       ppa_list = nvm_rq_to_ppa_list(&rqd);
 
        for (i = 0; i < lm->smeta_sec; i++, paddr++)
-               rqd.ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id);
+               ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id);
 
        ret = pblk_submit_io_sync(pblk, &rqd);
        if (ret) {
@@ -761,8 +761,10 @@ int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line)
 
        atomic_dec(&pblk->inflight_io);
 
-       if (rqd.error)
+       if (rqd.error && rqd.error != NVM_RSP_WARN_HIGHECC) {
                pblk_log_read_err(pblk, &rqd);
+               ret = -EIO;
+       }
 
 clear_rqd:
        pblk_free_rqd_meta(pblk, &rqd);
@@ -775,6 +777,7 @@ static int pblk_line_smeta_write(struct pblk *pblk, struct pblk_line *line,
        struct nvm_tgt_dev *dev = pblk->dev;
        struct pblk_line_meta *lm = &pblk->lm;
        struct bio *bio;
+       struct ppa_addr *ppa_list;
        struct nvm_rq rqd;
        __le64 *lba_list = emeta_to_lbas(pblk, line->emeta->buf);
        __le64 addr_empty = cpu_to_le64(ADDR_EMPTY);
@@ -799,12 +802,13 @@ static int pblk_line_smeta_write(struct pblk *pblk, struct pblk_line *line,
        rqd.opcode = NVM_OP_PWRITE;
        rqd.nr_ppas = lm->smeta_sec;
        rqd.is_seq = 1;
+       ppa_list = nvm_rq_to_ppa_list(&rqd);
 
        for (i = 0; i < lm->smeta_sec; i++, paddr++) {
                struct pblk_sec_meta *meta = pblk_get_meta(pblk,
                                                           rqd.meta_list, i);
 
-               rqd.ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id);
+               ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id);
                meta->lba = lba_list[paddr] = addr_empty;
        }
 
@@ -834,8 +838,9 @@ int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line,
        struct nvm_geo *geo = &dev->geo;
        struct pblk_line_mgmt *l_mg = &pblk->l_mg;
        struct pblk_line_meta *lm = &pblk->lm;
-       void *ppa_list, *meta_list;
+       void *ppa_list_buf, *meta_list;
        struct bio *bio;
+       struct ppa_addr *ppa_list;
        struct nvm_rq rqd;
        u64 paddr = line->emeta_ssec;
        dma_addr_t dma_ppa_list, dma_meta_list;
@@ -851,7 +856,7 @@ int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line,
        if (!meta_list)
                return -ENOMEM;
 
-       ppa_list = meta_list + pblk_dma_meta_size(pblk);
+       ppa_list_buf = meta_list + pblk_dma_meta_size(pblk);
        dma_ppa_list = dma_meta_list + pblk_dma_meta_size(pblk);
 
 next_rq:
@@ -872,11 +877,12 @@ next_rq:
 
        rqd.bio = bio;
        rqd.meta_list = meta_list;
-       rqd.ppa_list = ppa_list;
+       rqd.ppa_list = ppa_list_buf;
        rqd.dma_meta_list = dma_meta_list;
        rqd.dma_ppa_list = dma_ppa_list;
        rqd.opcode = NVM_OP_PREAD;
        rqd.nr_ppas = rq_ppas;
+       ppa_list = nvm_rq_to_ppa_list(&rqd);
 
        for (i = 0; i < rqd.nr_ppas; ) {
                struct ppa_addr ppa = addr_to_gen_ppa(pblk, paddr, line_id);
@@ -904,7 +910,7 @@ next_rq:
                }
 
                for (j = 0; j < min; j++, i++, paddr++)
-                       rqd.ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line_id);
+                       ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line_id);
        }
 
        ret = pblk_submit_io_sync(pblk, &rqd);
@@ -916,8 +922,11 @@ next_rq:
 
        atomic_dec(&pblk->inflight_io);
 
-       if (rqd.error)
+       if (rqd.error && rqd.error != NVM_RSP_WARN_HIGHECC) {
                pblk_log_read_err(pblk, &rqd);
+               ret = -EIO;
+               goto free_rqd_dma;
+       }
 
        emeta_buf += rq_len;
        left_ppas -= rq_ppas;
@@ -1162,7 +1171,6 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line,
        off = bit * geo->ws_opt;
        bitmap_set(line->map_bitmap, off, lm->smeta_sec);
        line->sec_in_line -= lm->smeta_sec;
-       line->smeta_ssec = off;
        line->cur_sec = off + lm->smeta_sec;
 
        if (init && pblk_line_smeta_write(pblk, line, off)) {
@@ -1521,11 +1529,9 @@ void pblk_ppa_to_line_put(struct pblk *pblk, struct ppa_addr ppa)
 
 void pblk_rq_to_line_put(struct pblk *pblk, struct nvm_rq *rqd)
 {
-       struct ppa_addr *ppa_list;
+       struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
        int i;
 
-       ppa_list = (rqd->nr_ppas > 1) ? rqd->ppa_list : &rqd->ppa_addr;
-
        for (i = 0; i < rqd->nr_ppas; i++)
                pblk_ppa_to_line_put(pblk, ppa_list[i]);
 }
@@ -1699,6 +1705,14 @@ static void __pblk_line_put(struct pblk *pblk, struct pblk_line *line)
 
        spin_lock(&line->lock);
        WARN_ON(line->state != PBLK_LINESTATE_GC);
+       if (line->w_err_gc->has_gc_err) {
+               spin_unlock(&line->lock);
+               pblk_err(pblk, "line %d had errors during GC\n", line->id);
+               pblk_put_line_back(pblk, line);
+               line->w_err_gc->has_gc_err = 0;
+               return;
+       }
+
        line->state = PBLK_LINESTATE_FREE;
        trace_pblk_line_state(pblk_disk_name(pblk), line->id,
                                        line->state);
@@ -2023,7 +2037,7 @@ void pblk_update_map(struct pblk *pblk, sector_t lba, struct ppa_addr ppa)
        struct ppa_addr ppa_l2p;
 
        /* logic error: lba out-of-bounds. Ignore update */
-       if (!(lba < pblk->rl.nr_secs)) {
+       if (!(lba < pblk->capacity)) {
                WARN(1, "pblk: corrupted L2P map request\n");
                return;
        }
@@ -2063,7 +2077,7 @@ int pblk_update_map_gc(struct pblk *pblk, sector_t lba, struct ppa_addr ppa_new,
 #endif
 
        /* logic error: lba out-of-bounds. Ignore update */
-       if (!(lba < pblk->rl.nr_secs)) {
+       if (!(lba < pblk->capacity)) {
                WARN(1, "pblk: corrupted L2P map request\n");
                return 0;
        }
@@ -2109,7 +2123,7 @@ void pblk_update_map_dev(struct pblk *pblk, sector_t lba,
        }
 
        /* logic error: lba out-of-bounds. Ignore update */
-       if (!(lba < pblk->rl.nr_secs)) {
+       if (!(lba < pblk->capacity)) {
                WARN(1, "pblk: corrupted L2P map request\n");
                return;
        }
@@ -2135,8 +2149,8 @@ out:
        spin_unlock(&pblk->trans_lock);
 }
 
-void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
-                        sector_t blba, int nr_secs)
+int pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
+                        sector_t blba, int nr_secs, bool *from_cache)
 {
        int i;
 
@@ -2150,10 +2164,19 @@ void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
                if (!pblk_ppa_empty(ppa) && !pblk_addr_in_cache(ppa)) {
                        struct pblk_line *line = pblk_ppa_to_line(pblk, ppa);
 
+                       if (i > 0 && *from_cache)
+                               break;
+                       *from_cache = false;
+
                        kref_get(&line->ref);
+               } else {
+                       if (i > 0 && !*from_cache)
+                               break;
+                       *from_cache = true;
                }
        }
        spin_unlock(&pblk->trans_lock);
+       return i;
 }
 
 void pblk_lookup_l2p_rand(struct pblk *pblk, struct ppa_addr *ppas,
@@ -2167,7 +2190,7 @@ void pblk_lookup_l2p_rand(struct pblk *pblk, struct ppa_addr *ppas,
                lba = lba_list[i];
                if (lba != ADDR_EMPTY) {
                        /* logic error: lba out-of-bounds. Ignore update */
-                       if (!(lba < pblk->rl.nr_secs)) {
+                       if (!(lba < pblk->capacity)) {
                                WARN(1, "pblk: corrupted L2P map request\n");
                                continue;
                        }
index 26a52ea7ec45702c0bd61173c194fe883c958067..63ee205b41c477f9ebc70374f6cf208915e6c4f1 100644 (file)
@@ -59,24 +59,28 @@ static void pblk_gc_writer_kick(struct pblk_gc *gc)
        wake_up_process(gc->gc_writer_ts);
 }
 
-static void pblk_put_line_back(struct pblk *pblk, struct pblk_line *line)
+void pblk_put_line_back(struct pblk *pblk, struct pblk_line *line)
 {
        struct pblk_line_mgmt *l_mg = &pblk->l_mg;
        struct list_head *move_list;
 
+       spin_lock(&l_mg->gc_lock);
        spin_lock(&line->lock);
        WARN_ON(line->state != PBLK_LINESTATE_GC);
        line->state = PBLK_LINESTATE_CLOSED;
        trace_pblk_line_state(pblk_disk_name(pblk), line->id,
                                        line->state);
+
+       /* We need to reset gc_group in order to ensure that
+        * pblk_line_gc_list will return proper move_list
+        * since right now current line is not on any of the
+        * gc lists.
+        */
+       line->gc_group = PBLK_LINEGC_NONE;
        move_list = pblk_line_gc_list(pblk, line);
        spin_unlock(&line->lock);
-
-       if (move_list) {
-               spin_lock(&l_mg->gc_lock);
-               list_add_tail(&line->list, move_list);
-               spin_unlock(&l_mg->gc_lock);
-       }
+       list_add_tail(&line->list, move_list);
+       spin_unlock(&l_mg->gc_lock);
 }
 
 static void pblk_gc_line_ws(struct work_struct *work)
@@ -84,8 +88,6 @@ static void pblk_gc_line_ws(struct work_struct *work)
        struct pblk_line_ws *gc_rq_ws = container_of(work,
                                                struct pblk_line_ws, ws);
        struct pblk *pblk = gc_rq_ws->pblk;
-       struct nvm_tgt_dev *dev = pblk->dev;
-       struct nvm_geo *geo = &dev->geo;
        struct pblk_gc *gc = &pblk->gc;
        struct pblk_line *line = gc_rq_ws->line;
        struct pblk_gc_rq *gc_rq = gc_rq_ws->priv;
@@ -93,18 +95,10 @@ static void pblk_gc_line_ws(struct work_struct *work)
 
        up(&gc->gc_sem);
 
-       gc_rq->data = vmalloc(array_size(gc_rq->nr_secs, geo->csecs));
-       if (!gc_rq->data) {
-               pblk_err(pblk, "could not GC line:%d (%d/%d)\n",
-                                       line->id, *line->vsc, gc_rq->nr_secs);
-               goto out;
-       }
-
        /* Read from GC victim block */
        ret = pblk_submit_read_gc(pblk, gc_rq);
        if (ret) {
-               pblk_err(pblk, "failed GC read in line:%d (err:%d)\n",
-                                                               line->id, ret);
+               line->w_err_gc->has_gc_err = 1;
                goto out;
        }
 
@@ -189,6 +183,8 @@ static void pblk_gc_line_prepare_ws(struct work_struct *work)
        struct pblk_line *line = line_ws->line;
        struct pblk_line_mgmt *l_mg = &pblk->l_mg;
        struct pblk_line_meta *lm = &pblk->lm;
+       struct nvm_tgt_dev *dev = pblk->dev;
+       struct nvm_geo *geo = &dev->geo;
        struct pblk_gc *gc = &pblk->gc;
        struct pblk_line_ws *gc_rq_ws;
        struct pblk_gc_rq *gc_rq;
@@ -247,9 +243,13 @@ next_rq:
        gc_rq->nr_secs = nr_secs;
        gc_rq->line = line;
 
+       gc_rq->data = vmalloc(array_size(gc_rq->nr_secs, geo->csecs));
+       if (!gc_rq->data)
+               goto fail_free_gc_rq;
+
        gc_rq_ws = kmalloc(sizeof(struct pblk_line_ws), GFP_KERNEL);
        if (!gc_rq_ws)
-               goto fail_free_gc_rq;
+               goto fail_free_gc_data;
 
        gc_rq_ws->pblk = pblk;
        gc_rq_ws->line = line;
@@ -281,6 +281,8 @@ out:
 
        return;
 
+fail_free_gc_data:
+       vfree(gc_rq->data);
 fail_free_gc_rq:
        kfree(gc_rq);
 fail_free_lba_list:
@@ -290,8 +292,11 @@ fail_free_invalid_bitmap:
 fail_free_ws:
        kfree(line_ws);
 
+       /* Line goes back to closed state, so we cannot release additional
+        * reference for line, since we do that only when we want to do
+        * gc to free line state transition.
+        */
        pblk_put_line_back(pblk, line);
-       kref_put(&line->ref, pblk_line_put);
        atomic_dec(&gc->read_inflight_gc);
 
        pblk_err(pblk, "failed to GC line %d\n", line->id);
@@ -355,8 +360,13 @@ static int pblk_gc_read(struct pblk *pblk)
 
        pblk_gc_kick(pblk);
 
-       if (pblk_gc_line(pblk, line))
+       if (pblk_gc_line(pblk, line)) {
                pblk_err(pblk, "failed to GC line %d\n", line->id);
+               /* rollback */
+               spin_lock(&gc->r_lock);
+               list_add_tail(&line->list, &gc->r_list);
+               spin_unlock(&gc->r_lock);
+       }
 
        return 0;
 }
index 8b643d0bffaeba853f7d1bc2b3a56f808c60437f..b351c7f002de0509b7bca75a0f64a616eec7ee32 100644 (file)
@@ -47,33 +47,6 @@ static struct pblk_global_caches pblk_caches = {
 
 struct bio_set pblk_bio_set;
 
-static int pblk_rw_io(struct request_queue *q, struct pblk *pblk,
-                         struct bio *bio)
-{
-       int ret;
-
-       /* Read requests must be <= 256kb due to NVMe's 64 bit completion bitmap
-        * constraint. Writes can be of arbitrary size.
-        */
-       if (bio_data_dir(bio) == READ) {
-               blk_queue_split(q, &bio);
-               ret = pblk_submit_read(pblk, bio);
-               if (ret == NVM_IO_DONE && bio_flagged(bio, BIO_CLONED))
-                       bio_put(bio);
-
-               return ret;
-       }
-
-       /* Prevent deadlock in the case of a modest LUN configuration and large
-        * user I/Os. Unless stalled, the rate limiter leaves at least 256KB
-        * available for user I/O.
-        */
-       if (pblk_get_secs(bio) > pblk_rl_max_io(&pblk->rl))
-               blk_queue_split(q, &bio);
-
-       return pblk_write_to_cache(pblk, bio, PBLK_IOTYPE_USER);
-}
-
 static blk_qc_t pblk_make_rq(struct request_queue *q, struct bio *bio)
 {
        struct pblk *pblk = q->queuedata;
@@ -86,13 +59,21 @@ static blk_qc_t pblk_make_rq(struct request_queue *q, struct bio *bio)
                }
        }
 
-       switch (pblk_rw_io(q, pblk, bio)) {
-       case NVM_IO_ERR:
-               bio_io_error(bio);
-               break;
-       case NVM_IO_DONE:
-               bio_endio(bio);
-               break;
+       /* Read requests must be <= 256kb due to NVMe's 64 bit completion bitmap
+        * constraint. Writes can be of arbitrary size.
+        */
+       if (bio_data_dir(bio) == READ) {
+               blk_queue_split(q, &bio);
+               pblk_submit_read(pblk, bio);
+       } else {
+               /* Prevent deadlock in the case of a modest LUN configuration
+                * and large user I/Os. Unless stalled, the rate limiter
+                * leaves at least 256KB available for user I/O.
+                */
+               if (pblk_get_secs(bio) > pblk_rl_max_io(&pblk->rl))
+                       blk_queue_split(q, &bio);
+
+               pblk_write_to_cache(pblk, bio, PBLK_IOTYPE_USER);
        }
 
        return BLK_QC_T_NONE;
@@ -105,7 +86,7 @@ static size_t pblk_trans_map_size(struct pblk *pblk)
        if (pblk->addrf_len < 32)
                entry_size = 4;
 
-       return entry_size * pblk->rl.nr_secs;
+       return entry_size * pblk->capacity;
 }
 
 #ifdef CONFIG_NVM_PBLK_DEBUG
@@ -164,13 +145,18 @@ static int pblk_l2p_init(struct pblk *pblk, bool factory_init)
        int ret = 0;
 
        map_size = pblk_trans_map_size(pblk);
-       pblk->trans_map = vmalloc(map_size);
-       if (!pblk->trans_map)
+       pblk->trans_map = __vmalloc(map_size, GFP_KERNEL | __GFP_NOWARN
+                                       | __GFP_RETRY_MAYFAIL | __GFP_HIGHMEM,
+                                       PAGE_KERNEL);
+       if (!pblk->trans_map) {
+               pblk_err(pblk, "failed to allocate L2P (need %zu of memory)\n",
+                               map_size);
                return -ENOMEM;
+       }
 
        pblk_ppa_set_empty(&ppa);
 
-       for (i = 0; i < pblk->rl.nr_secs; i++)
+       for (i = 0; i < pblk->capacity; i++)
                pblk_trans_map_set(pblk, i, ppa);
 
        ret = pblk_l2p_recover(pblk, factory_init);
@@ -701,7 +687,6 @@ static int pblk_set_provision(struct pblk *pblk, int nr_free_chks)
         * on user capacity consider only provisioned blocks
         */
        pblk->rl.total_blocks = nr_free_chks;
-       pblk->rl.nr_secs = nr_free_chks * geo->clba;
 
        /* Consider sectors used for metadata */
        sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines;
@@ -1284,7 +1269,7 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
 
        pblk_info(pblk, "luns:%u, lines:%d, secs:%llu, buf entries:%u\n",
                        geo->all_luns, pblk->l_mg.nr_lines,
-                       (unsigned long long)pblk->rl.nr_secs,
+                       (unsigned long long)pblk->capacity,
                        pblk->rwb.nr_entries);
 
        wake_up_process(pblk->writer_ts);
index 7fbc99b60cac58da8c20af27c9010d3a7b8d7ea1..5408e32b2f13df6b5fef28573bbe2576c161c79f 100644 (file)
@@ -162,6 +162,7 @@ int pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
 
                        *erase_ppa = ppa_list[i];
                        erase_ppa->a.blk = e_line->id;
+                       erase_ppa->a.reserved = 0;
 
                        spin_unlock(&e_line->lock);
 
index 03c241b340ea7abf016d72d126818c35f833c83d..5abb1705b03975b30991685e8450f45bf9e8975a 100644 (file)
@@ -642,7 +642,7 @@ try:
  * be directed to disk.
  */
 int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
-                       struct ppa_addr ppa, int bio_iter, bool advanced_bio)
+                       struct ppa_addr ppa)
 {
        struct pblk *pblk = container_of(rb, struct pblk, rwb);
        struct pblk_rb_entry *entry;
@@ -673,15 +673,6 @@ int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
                ret = 0;
                goto out;
        }
-
-       /* Only advance the bio if it hasn't been advanced already. If advanced,
-        * this bio is at least a partial bio (i.e., it has partially been
-        * filled with data from the cache). If part of the data resides on the
-        * media, we will read later on
-        */
-       if (unlikely(!advanced_bio))
-               bio_advance(bio, bio_iter * PBLK_EXPOSED_PAGE_SIZE);
-
        data = bio_data(bio);
        memcpy(data, entry->data, rb->seg_size);
 
@@ -799,8 +790,8 @@ int pblk_rb_tear_down_check(struct pblk_rb *rb)
        }
 
 out:
-       spin_unlock(&rb->w_lock);
        spin_unlock_irq(&rb->s_lock);
+       spin_unlock(&rb->w_lock);
 
        return ret;
 }
index 0b7d5fb4548dcd8720f86e98a2567e3d387a061d..d98ea392fe3357c4bf12e0e22a38d6b2a1971b8c 100644 (file)
@@ -26,8 +26,7 @@
  * issued.
  */
 static int pblk_read_from_cache(struct pblk *pblk, struct bio *bio,
-                               sector_t lba, struct ppa_addr ppa,
-                               int bio_iter, bool advanced_bio)
+                               sector_t lba, struct ppa_addr ppa)
 {
 #ifdef CONFIG_NVM_PBLK_DEBUG
        /* Callers must ensure that the ppa points to a cache address */
@@ -35,73 +34,75 @@ static int pblk_read_from_cache(struct pblk *pblk, struct bio *bio,
        BUG_ON(!pblk_addr_in_cache(ppa));
 #endif
 
-       return pblk_rb_copy_to_bio(&pblk->rwb, bio, lba, ppa,
-                                               bio_iter, advanced_bio);
+       return pblk_rb_copy_to_bio(&pblk->rwb, bio, lba, ppa);
 }
 
-static void pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd,
+static int pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd,
                                 struct bio *bio, sector_t blba,
-                                unsigned long *read_bitmap)
+                                bool *from_cache)
 {
        void *meta_list = rqd->meta_list;
-       struct ppa_addr ppas[NVM_MAX_VLBA];
-       int nr_secs = rqd->nr_ppas;
-       bool advanced_bio = false;
-       int i, j = 0;
+       int nr_secs, i;
 
-       pblk_lookup_l2p_seq(pblk, ppas, blba, nr_secs);
+retry:
+       nr_secs = pblk_lookup_l2p_seq(pblk, rqd->ppa_list, blba, rqd->nr_ppas,
+                                       from_cache);
+
+       if (!*from_cache)
+               goto end;
 
        for (i = 0; i < nr_secs; i++) {
-               struct ppa_addr p = ppas[i];
                struct pblk_sec_meta *meta = pblk_get_meta(pblk, meta_list, i);
                sector_t lba = blba + i;
 
-retry:
-               if (pblk_ppa_empty(p)) {
+               if (pblk_ppa_empty(rqd->ppa_list[i])) {
                        __le64 addr_empty = cpu_to_le64(ADDR_EMPTY);
 
-                       WARN_ON(test_and_set_bit(i, read_bitmap));
                        meta->lba = addr_empty;
-
-                       if (unlikely(!advanced_bio)) {
-                               bio_advance(bio, (i) * PBLK_EXPOSED_PAGE_SIZE);
-                               advanced_bio = true;
+               } else if (pblk_addr_in_cache(rqd->ppa_list[i])) {
+                       /*
+                        * Try to read from write buffer. The address is later
+                        * checked on the write buffer to prevent retrieving
+                        * overwritten data.
+                        */
+                       if (!pblk_read_from_cache(pblk, bio, lba,
+                                                       rqd->ppa_list[i])) {
+                               if (i == 0) {
+                                       /*
+                                        * We didn't call with bio_advance()
+                                        * yet, so we can just retry.
+                                        */
+                                       goto retry;
+                               } else {
+                                       /*
+                                        * We already call bio_advance()
+                                        * so we cannot retry and we need
+                                        * to quit that function in order
+                                        * to allow caller to handle the bio
+                                        * splitting in the current sector
+                                        * position.
+                                        */
+                                       nr_secs = i;
+                                       goto end;
+                               }
                        }
-
-                       goto next;
-               }
-
-               /* Try to read from write buffer. The address is later checked
-                * on the write buffer to prevent retrieving overwritten data.
-                */
-               if (pblk_addr_in_cache(p)) {
-                       if (!pblk_read_from_cache(pblk, bio, lba, p, i,
-                                                               advanced_bio)) {
-                               pblk_lookup_l2p_seq(pblk, &p, lba, 1);
-                               goto retry;
-                       }
-                       WARN_ON(test_and_set_bit(i, read_bitmap));
                        meta->lba = cpu_to_le64(lba);
-                       advanced_bio = true;
 #ifdef CONFIG_NVM_PBLK_DEBUG
                        atomic_long_inc(&pblk->cache_reads);
 #endif
-               } else {
-                       /* Read from media non-cached sectors */
-                       rqd->ppa_list[j++] = p;
                }
-
-next:
-               if (advanced_bio)
-                       bio_advance(bio, PBLK_EXPOSED_PAGE_SIZE);
+               bio_advance(bio, PBLK_EXPOSED_PAGE_SIZE);
        }
 
+end:
        if (pblk_io_aligned(pblk, nr_secs))
                rqd->is_seq = 1;
 
 #ifdef CONFIG_NVM_PBLK_DEBUG
        atomic_long_add(nr_secs, &pblk->inflight_reads);
 #endif
+
+       return nr_secs;
 }
 
 
@@ -175,12 +176,12 @@ static void pblk_read_check_rand(struct pblk *pblk, struct nvm_rq *rqd,
        WARN_ONCE(j != rqd->nr_ppas, "pblk: corrupted random request\n");
 }
 
-static void pblk_end_user_read(struct bio *bio)
+static void pblk_end_user_read(struct bio *bio, int error)
 {
-#ifdef CONFIG_NVM_PBLK_DEBUG
-       WARN_ONCE(bio->bi_status, "pblk: corrupted read bio\n");
-#endif
-       bio_endio(bio);
+       if (error && error != NVM_RSP_WARN_HIGHECC)
+               bio_io_error(bio);
+       else
+               bio_endio(bio);
 }
 
 static void __pblk_end_io_read(struct pblk *pblk, struct nvm_rq *rqd,
@@ -197,9 +198,7 @@ static void __pblk_end_io_read(struct pblk *pblk, struct nvm_rq *rqd,
                pblk_log_read_err(pblk, rqd);
 
        pblk_read_check_seq(pblk, rqd, r_ctx->lba);
-
-       if (int_bio)
-               bio_put(int_bio);
+       bio_put(int_bio);
 
        if (put_line)
                pblk_rq_to_line_put(pblk, rqd);
@@ -219,188 +218,17 @@ static void pblk_end_io_read(struct nvm_rq *rqd)
        struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd);
        struct bio *bio = (struct bio *)r_ctx->private;
 
-       pblk_end_user_read(bio);
+       pblk_end_user_read(bio, rqd->error);
        __pblk_end_io_read(pblk, rqd, true);
 }
 
-static void pblk_end_partial_read(struct nvm_rq *rqd)
-{
-       struct pblk *pblk = rqd->private;
-       struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd);
-       struct pblk_pr_ctx *pr_ctx = r_ctx->private;
-       struct pblk_sec_meta *meta;
-       struct bio *new_bio = rqd->bio;
-       struct bio *bio = pr_ctx->orig_bio;
-       void *meta_list = rqd->meta_list;
-       unsigned long *read_bitmap = pr_ctx->bitmap;
-       struct bvec_iter orig_iter = BVEC_ITER_ALL_INIT;
-       struct bvec_iter new_iter = BVEC_ITER_ALL_INIT;
-       int nr_secs = pr_ctx->orig_nr_secs;
-       int nr_holes = nr_secs - bitmap_weight(read_bitmap, nr_secs);
-       void *src_p, *dst_p;
-       int bit, i;
-
-       if (unlikely(nr_holes == 1)) {
-               struct ppa_addr ppa;
-
-               ppa = rqd->ppa_addr;
-               rqd->ppa_list = pr_ctx->ppa_ptr;
-               rqd->dma_ppa_list = pr_ctx->dma_ppa_list;
-               rqd->ppa_list[0] = ppa;
-       }
-
-       for (i = 0; i < nr_secs; i++) {
-               meta = pblk_get_meta(pblk, meta_list, i);
-               pr_ctx->lba_list_media[i] = le64_to_cpu(meta->lba);
-               meta->lba = cpu_to_le64(pr_ctx->lba_list_mem[i]);
-       }
-
-       /* Fill the holes in the original bio */
-       i = 0;
-       for (bit = 0; bit < nr_secs; bit++) {
-               if (!test_bit(bit, read_bitmap)) {
-                       struct bio_vec dst_bv, src_bv;
-                       struct pblk_line *line;
-
-                       line = pblk_ppa_to_line(pblk, rqd->ppa_list[i]);
-                       kref_put(&line->ref, pblk_line_put);
-
-                       meta = pblk_get_meta(pblk, meta_list, bit);
-                       meta->lba = cpu_to_le64(pr_ctx->lba_list_media[i]);
-
-                       dst_bv = bio_iter_iovec(bio, orig_iter);
-                       src_bv = bio_iter_iovec(new_bio, new_iter);
-
-                       src_p = kmap_atomic(src_bv.bv_page);
-                       dst_p = kmap_atomic(dst_bv.bv_page);
-
-                       memcpy(dst_p + dst_bv.bv_offset,
-                               src_p + src_bv.bv_offset,
-                               PBLK_EXPOSED_PAGE_SIZE);
-
-                       kunmap_atomic(src_p);
-                       kunmap_atomic(dst_p);
-
-                       flush_dcache_page(dst_bv.bv_page);
-                       mempool_free(src_bv.bv_page, &pblk->page_bio_pool);
-
-                       bio_advance_iter(new_bio, &new_iter,
-                                       PBLK_EXPOSED_PAGE_SIZE);
-                       i++;
-               }
-               bio_advance_iter(bio, &orig_iter, PBLK_EXPOSED_PAGE_SIZE);
-       }
-
-       bio_put(new_bio);
-       kfree(pr_ctx);
-
-       /* restore original request */
-       rqd->bio = NULL;
-       rqd->nr_ppas = nr_secs;
-
-       bio_endio(bio);
-       __pblk_end_io_read(pblk, rqd, false);
-}
-
-static int pblk_setup_partial_read(struct pblk *pblk, struct nvm_rq *rqd,
-                           unsigned int bio_init_idx,
-                           unsigned long *read_bitmap,
-                           int nr_holes)
-{
-       void *meta_list = rqd->meta_list;
-       struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd);
-       struct pblk_pr_ctx *pr_ctx;
-       struct bio *new_bio, *bio = r_ctx->private;
-       int nr_secs = rqd->nr_ppas;
-       int i;
-
-       new_bio = bio_alloc(GFP_KERNEL, nr_holes);
-
-       if (pblk_bio_add_pages(pblk, new_bio, GFP_KERNEL, nr_holes))
-               goto fail_bio_put;
-
-       if (nr_holes != new_bio->bi_vcnt) {
-               WARN_ONCE(1, "pblk: malformed bio\n");
-               goto fail_free_pages;
-       }
-
-       pr_ctx = kzalloc(sizeof(struct pblk_pr_ctx), GFP_KERNEL);
-       if (!pr_ctx)
-               goto fail_free_pages;
-
-       for (i = 0; i < nr_secs; i++) {
-               struct pblk_sec_meta *meta = pblk_get_meta(pblk, meta_list, i);
-
-               pr_ctx->lba_list_mem[i] = le64_to_cpu(meta->lba);
-       }
-
-       new_bio->bi_iter.bi_sector = 0; /* internal bio */
-       bio_set_op_attrs(new_bio, REQ_OP_READ, 0);
-
-       rqd->bio = new_bio;
-       rqd->nr_ppas = nr_holes;
-
-       pr_ctx->orig_bio = bio;
-       bitmap_copy(pr_ctx->bitmap, read_bitmap, NVM_MAX_VLBA);
-       pr_ctx->bio_init_idx = bio_init_idx;
-       pr_ctx->orig_nr_secs = nr_secs;
-       r_ctx->private = pr_ctx;
-
-       if (unlikely(nr_holes == 1)) {
-               pr_ctx->ppa_ptr = rqd->ppa_list;
-               pr_ctx->dma_ppa_list = rqd->dma_ppa_list;
-               rqd->ppa_addr = rqd->ppa_list[0];
-       }
-       return 0;
-
-fail_free_pages:
-       pblk_bio_free_pages(pblk, new_bio, 0, new_bio->bi_vcnt);
-fail_bio_put:
-       bio_put(new_bio);
-
-       return -ENOMEM;
-}
-
-static int pblk_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd,
-                                unsigned int bio_init_idx,
-                                unsigned long *read_bitmap, int nr_secs)
-{
-       int nr_holes;
-       int ret;
-
-       nr_holes = nr_secs - bitmap_weight(read_bitmap, nr_secs);
-
-       if (pblk_setup_partial_read(pblk, rqd, bio_init_idx, read_bitmap,
-                                   nr_holes))
-               return NVM_IO_ERR;
-
-       rqd->end_io = pblk_end_partial_read;
-
-       ret = pblk_submit_io(pblk, rqd);
-       if (ret) {
-               bio_put(rqd->bio);
-               pblk_err(pblk, "partial read IO submission failed\n");
-               goto err;
-       }
-
-       return NVM_IO_OK;
-
-err:
-       pblk_err(pblk, "failed to perform partial read\n");
-
-       /* Free allocated pages in new bio */
-       pblk_bio_free_pages(pblk, rqd->bio, 0, rqd->bio->bi_vcnt);
-       __pblk_end_io_read(pblk, rqd, false);
-       return NVM_IO_ERR;
-}
-
 static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd, struct bio *bio,
-                        sector_t lba, unsigned long *read_bitmap)
+                        sector_t lba, bool *from_cache)
 {
        struct pblk_sec_meta *meta = pblk_get_meta(pblk, rqd->meta_list, 0);
        struct ppa_addr ppa;
 
-       pblk_lookup_l2p_seq(pblk, &ppa, lba, 1);
+       pblk_lookup_l2p_seq(pblk, &ppa, lba, 1, from_cache);
 
 #ifdef CONFIG_NVM_PBLK_DEBUG
        atomic_long_inc(&pblk->inflight_reads);
@@ -410,7 +238,6 @@ retry:
        if (pblk_ppa_empty(ppa)) {
                __le64 addr_empty = cpu_to_le64(ADDR_EMPTY);
 
-               WARN_ON(test_and_set_bit(0, read_bitmap));
                meta->lba = addr_empty;
                return;
        }
@@ -419,12 +246,11 @@ retry:
         * write buffer to prevent retrieving overwritten data.
         */
        if (pblk_addr_in_cache(ppa)) {
-               if (!pblk_read_from_cache(pblk, bio, lba, ppa, 0, 1)) {
-                       pblk_lookup_l2p_seq(pblk, &ppa, lba, 1);
+               if (!pblk_read_from_cache(pblk, bio, lba, ppa)) {
+                       pblk_lookup_l2p_seq(pblk, &ppa, lba, 1, from_cache);
                        goto retry;
                }
 
-               WARN_ON(test_and_set_bit(0, read_bitmap));
                meta->lba = cpu_to_le64(lba);
 
 #ifdef CONFIG_NVM_PBLK_DEBUG
@@ -435,95 +261,92 @@ retry:
        }
 }
 
-int pblk_submit_read(struct pblk *pblk, struct bio *bio)
+void pblk_submit_read(struct pblk *pblk, struct bio *bio)
 {
        struct nvm_tgt_dev *dev = pblk->dev;
        struct request_queue *q = dev->q;
        sector_t blba = pblk_get_lba(bio);
        unsigned int nr_secs = pblk_get_secs(bio);
+       bool from_cache;
        struct pblk_g_ctx *r_ctx;
        struct nvm_rq *rqd;
-       unsigned int bio_init_idx;
-       DECLARE_BITMAP(read_bitmap, NVM_MAX_VLBA);
-       int ret = NVM_IO_ERR;
+       struct bio *int_bio, *split_bio;
 
        generic_start_io_acct(q, REQ_OP_READ, bio_sectors(bio),
                              &pblk->disk->part0);
 
-       bitmap_zero(read_bitmap, nr_secs);
-
        rqd = pblk_alloc_rqd(pblk, PBLK_READ);
 
        rqd->opcode = NVM_OP_PREAD;
        rqd->nr_ppas = nr_secs;
-       rqd->bio = NULL; /* cloned bio if needed */
        rqd->private = pblk;
        rqd->end_io = pblk_end_io_read;
 
        r_ctx = nvm_rq_to_pdu(rqd);
        r_ctx->start_time = jiffies;
        r_ctx->lba = blba;
-       r_ctx->private = bio; /* original bio */
 
-       /* Save the index for this bio's start. This is needed in case
-        * we need to fill a partial read.
-        */
-       bio_init_idx = pblk_get_bi_idx(bio);
+       if (pblk_alloc_rqd_meta(pblk, rqd)) {
+               bio_io_error(bio);
+               pblk_free_rqd(pblk, rqd, PBLK_READ);
+               return;
+       }
 
-       if (pblk_alloc_rqd_meta(pblk, rqd))
-               goto fail_rqd_free;
+       /* Clone read bio to deal internally with:
+        * -read errors when reading from drive
+        * -bio_advance() calls during cache reads
+        */
+       int_bio = bio_clone_fast(bio, GFP_KERNEL, &pblk_bio_set);
 
        if (nr_secs > 1)
-               pblk_read_ppalist_rq(pblk, rqd, bio, blba, read_bitmap);
+               nr_secs = pblk_read_ppalist_rq(pblk, rqd, int_bio, blba,
+                                               &from_cache);
        else
-               pblk_read_rq(pblk, rqd, bio, blba, read_bitmap);
+               pblk_read_rq(pblk, rqd, int_bio, blba, &from_cache);
 
-       if (bitmap_full(read_bitmap, nr_secs)) {
+split_retry:
+       r_ctx->private = bio; /* original bio */
+       rqd->bio = int_bio; /* internal bio */
+
+       if (from_cache && nr_secs == rqd->nr_ppas) {
+               /* All data was read from cache, we can complete the IO. */
+               pblk_end_user_read(bio, 0);
                atomic_inc(&pblk->inflight_io);
                __pblk_end_io_read(pblk, rqd, false);
-               return NVM_IO_DONE;
-       }
-
-       /* All sectors are to be read from the device */
-       if (bitmap_empty(read_bitmap, rqd->nr_ppas)) {
-               struct bio *int_bio = NULL;
+       } else if (nr_secs != rqd->nr_ppas) {
+               /* The read bio request could be partially filled by the write
+                * buffer, but there are some holes that need to be read from
+                * the drive. In order to handle this, we will use block layer
+                * mechanism to split this request in to smaller ones and make
+                * a chain of it.
+                */
+               split_bio = bio_split(bio, nr_secs * NR_PHY_IN_LOG, GFP_KERNEL,
+                                       &pblk_bio_set);
+               bio_chain(split_bio, bio);
+               generic_make_request(bio);
+
+               /* New bio contains first N sectors of the previous one, so
+                * we can continue to use existing rqd, but we need to shrink
+                * the number of PPAs in it. New bio is also guaranteed that
+                * it contains only either data from cache or from drive, newer
+                * mix of them.
+                */
+               bio = split_bio;
+               rqd->nr_ppas = nr_secs;
+               if (rqd->nr_ppas == 1)
+                       rqd->ppa_addr = rqd->ppa_list[0];
 
-               /* Clone read bio to deal with read errors internally */
+               /* Recreate int_bio - existing might have some needed internal
+                * fields modified already.
+                */
+               bio_put(int_bio);
                int_bio = bio_clone_fast(bio, GFP_KERNEL, &pblk_bio_set);
-               if (!int_bio) {
-                       pblk_err(pblk, "could not clone read bio\n");
-                       goto fail_end_io;
-               }
-
-               rqd->bio = int_bio;
-
-               if (pblk_submit_io(pblk, rqd)) {
-                       pblk_err(pblk, "read IO submission failed\n");
-                       ret = NVM_IO_ERR;
-                       goto fail_end_io;
-               }
-
-               return NVM_IO_OK;
+               goto split_retry;
+       } else if (pblk_submit_io(pblk, rqd)) {
+               /* Submitting IO to drive failed, let's report an error */
+               rqd->error = -ENODEV;
+               pblk_end_io_read(rqd);
        }
-
-       /* The read bio request could be partially filled by the write buffer,
-        * but there are some holes that need to be read from the drive.
-        */
-       ret = pblk_partial_read_bio(pblk, rqd, bio_init_idx, read_bitmap,
-                                   nr_secs);
-       if (ret)
-               goto fail_meta_free;
-
-       return NVM_IO_OK;
-
-fail_meta_free:
-       nvm_dev_dma_free(dev->parent, rqd->meta_list, rqd->dma_meta_list);
-fail_rqd_free:
-       pblk_free_rqd(pblk, rqd, PBLK_READ);
-       return ret;
-fail_end_io:
-       __pblk_end_io_read(pblk, rqd, false);
-       return ret;
 }
 
 static int read_ppalist_rq_gc(struct pblk *pblk, struct nvm_rq *rqd,
@@ -568,7 +391,7 @@ static int read_rq_gc(struct pblk *pblk, struct nvm_rq *rqd,
                goto out;
 
        /* logic error: lba out-of-bounds */
-       if (lba >= pblk->rl.nr_secs) {
+       if (lba >= pblk->capacity) {
                WARN(1, "pblk: read lba out of bounds\n");
                goto out;
        }
@@ -642,7 +465,6 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq)
 
        if (pblk_submit_io_sync(pblk, &rqd)) {
                ret = -EIO;
-               pblk_err(pblk, "GC read request failed\n");
                goto err_free_bio;
        }
 
index d86f580036d377814f6dbf5f41610542f0a61033..e6dda04de144ff347f0de304759a69f9f95189c6 100644 (file)
@@ -93,10 +93,24 @@ static int pblk_recov_l2p_from_emeta(struct pblk *pblk, struct pblk_line *line)
 static void pblk_update_line_wp(struct pblk *pblk, struct pblk_line *line,
                                u64 written_secs)
 {
+       struct pblk_line_mgmt *l_mg = &pblk->l_mg;
        int i;
 
        for (i = 0; i < written_secs; i += pblk->min_write_pgs)
-               pblk_alloc_page(pblk, line, pblk->min_write_pgs);
+               __pblk_alloc_page(pblk, line, pblk->min_write_pgs);
+
+       spin_lock(&l_mg->free_lock);
+       if (written_secs > line->left_msecs) {
+               /*
+                * We have all data sectors written
+                * and some emeta sectors written too.
+                */
+               line->left_msecs = 0;
+       } else {
+               /* We have only some data sectors written. */
+               line->left_msecs -= written_secs;
+       }
+       spin_unlock(&l_mg->free_lock);
 }
 
 static u64 pblk_sec_in_open_line(struct pblk *pblk, struct pblk_line *line)
@@ -165,6 +179,7 @@ static int pblk_recov_pad_line(struct pblk *pblk, struct pblk_line *line,
        struct pblk_pad_rq *pad_rq;
        struct nvm_rq *rqd;
        struct bio *bio;
+       struct ppa_addr *ppa_list;
        void *data;
        __le64 *lba_list = emeta_to_lbas(pblk, line->emeta->buf);
        u64 w_ptr = line->cur_sec;
@@ -194,7 +209,7 @@ next_pad_rq:
        rq_ppas = pblk_calc_secs(pblk, left_ppas, 0, false);
        if (rq_ppas < pblk->min_write_pgs) {
                pblk_err(pblk, "corrupted pad line %d\n", line->id);
-               goto fail_free_pad;
+               goto fail_complete;
        }
 
        rq_len = rq_ppas * geo->csecs;
@@ -203,7 +218,7 @@ next_pad_rq:
                                                PBLK_VMALLOC_META, GFP_KERNEL);
        if (IS_ERR(bio)) {
                ret = PTR_ERR(bio);
-               goto fail_free_pad;
+               goto fail_complete;
        }
 
        bio->bi_iter.bi_sector = 0; /* internal bio */
@@ -212,8 +227,11 @@ next_pad_rq:
        rqd = pblk_alloc_rqd(pblk, PBLK_WRITE_INT);
 
        ret = pblk_alloc_rqd_meta(pblk, rqd);
-       if (ret)
-               goto fail_free_rqd;
+       if (ret) {
+               pblk_free_rqd(pblk, rqd, PBLK_WRITE_INT);
+               bio_put(bio);
+               goto fail_complete;
+       }
 
        rqd->bio = bio;
        rqd->opcode = NVM_OP_PWRITE;
@@ -222,6 +240,7 @@ next_pad_rq:
        rqd->end_io = pblk_end_io_recov;
        rqd->private = pad_rq;
 
+       ppa_list = nvm_rq_to_ppa_list(rqd);
        meta_list = rqd->meta_list;
 
        for (i = 0; i < rqd->nr_ppas; ) {
@@ -249,18 +268,21 @@ next_pad_rq:
                        lba_list[w_ptr] = addr_empty;
                        meta = pblk_get_meta(pblk, meta_list, i);
                        meta->lba = addr_empty;
-                       rqd->ppa_list[i] = dev_ppa;
+                       ppa_list[i] = dev_ppa;
                }
        }
 
        kref_get(&pad_rq->ref);
-       pblk_down_chunk(pblk, rqd->ppa_list[0]);
+       pblk_down_chunk(pblk, ppa_list[0]);
 
        ret = pblk_submit_io(pblk, rqd);
        if (ret) {
                pblk_err(pblk, "I/O submission failed: %d\n", ret);
-               pblk_up_chunk(pblk, rqd->ppa_list[0]);
-               goto fail_free_rqd;
+               pblk_up_chunk(pblk, ppa_list[0]);
+               kref_put(&pad_rq->ref, pblk_recov_complete);
+               pblk_free_rqd(pblk, rqd, PBLK_WRITE_INT);
+               bio_put(bio);
+               goto fail_complete;
        }
 
        left_line_ppas -= rq_ppas;
@@ -268,13 +290,9 @@ next_pad_rq:
        if (left_ppas && left_line_ppas)
                goto next_pad_rq;
 
+fail_complete:
        kref_put(&pad_rq->ref, pblk_recov_complete);
-
-       if (!wait_for_completion_io_timeout(&pad_rq->wait,
-                               msecs_to_jiffies(PBLK_COMMAND_TIMEOUT_MS))) {
-               pblk_err(pblk, "pad write timed out\n");
-               ret = -ETIME;
-       }
+       wait_for_completion(&pad_rq->wait);
 
        if (!pblk_line_is_full(line))
                pblk_err(pblk, "corrupted padded line: %d\n", line->id);
@@ -283,14 +301,6 @@ next_pad_rq:
 free_rq:
        kfree(pad_rq);
        return ret;
-
-fail_free_rqd:
-       pblk_free_rqd(pblk, rqd, PBLK_WRITE_INT);
-       bio_put(bio);
-fail_free_pad:
-       kfree(pad_rq);
-       vfree(data);
-       return ret;
 }
 
 static int pblk_pad_distance(struct pblk *pblk, struct pblk_line *line)
@@ -412,6 +422,7 @@ retry_rq:
        rqd->ppa_list = ppa_list;
        rqd->dma_ppa_list = dma_ppa_list;
        rqd->dma_meta_list = dma_meta_list;
+       ppa_list = nvm_rq_to_ppa_list(rqd);
 
        if (pblk_io_aligned(pblk, rq_ppas))
                rqd->is_seq = 1;
@@ -430,7 +441,7 @@ retry_rq:
                }
 
                for (j = 0; j < pblk->min_write_pgs; j++, i++)
-                       rqd->ppa_list[i] =
+                       ppa_list[i] =
                                addr_to_gen_ppa(pblk, paddr + j, line->id);
        }
 
@@ -444,7 +455,7 @@ retry_rq:
        atomic_dec(&pblk->inflight_io);
 
        /* If a read fails, do a best effort by padding the line and retrying */
-       if (rqd->error) {
+       if (rqd->error && rqd->error != NVM_RSP_WARN_HIGHECC) {
                int pad_distance, ret;
 
                if (padded) {
@@ -474,11 +485,11 @@ retry_rq:
 
                lba_list[paddr++] = cpu_to_le64(lba);
 
-               if (lba == ADDR_EMPTY || lba > pblk->rl.nr_secs)
+               if (lba == ADDR_EMPTY || lba >= pblk->capacity)
                        continue;
 
                line->nr_valid_lbas++;
-               pblk_update_map(pblk, lba, rqd->ppa_list[i]);
+               pblk_update_map(pblk, lba, ppa_list[i]);
        }
 
        left_ppas -= rq_ppas;
@@ -647,10 +658,12 @@ static int pblk_line_was_written(struct pblk_line *line,
        bppa = pblk->luns[smeta_blk].bppa;
        chunk = &line->chks[pblk_ppa_to_pos(geo, bppa)];
 
-       if (chunk->state & NVM_CHK_ST_FREE)
-               return 0;
+       if (chunk->state & NVM_CHK_ST_CLOSED ||
+           (chunk->state & NVM_CHK_ST_OPEN
+            && chunk->wp >= lm->smeta_sec))
+               return 1;
 
-       return 1;
+       return 0;
 }
 
 static bool pblk_line_is_open(struct pblk *pblk, struct pblk_line *line)
@@ -844,6 +857,7 @@ next:
                spin_unlock(&l_mg->free_lock);
        } else {
                spin_lock(&l_mg->free_lock);
+               l_mg->data_line = data_line;
                /* Allocate next line for preparation */
                l_mg->data_next = pblk_line_get(pblk);
                if (l_mg->data_next) {
index 6593deab52da75bebfe9b252b542f8b421522acd..4e63f9b5954ce499de767b3b4012f084b9528959 100644 (file)
@@ -228,6 +228,7 @@ static void pblk_submit_rec(struct work_struct *work)
        mempool_free(recovery, &pblk->rec_pool);
 
        atomic_dec(&pblk->inflight_io);
+       pblk_write_kick(pblk);
 }
 
 
index ac3ab778e9767f677420e6f626f6c89184e76c18..a67855387f53d315d122b9218bbe1223801c51aa 100644 (file)
@@ -43,8 +43,6 @@
 
 #define PBLK_CACHE_NAME_LEN (DISK_NAME_LEN + 16)
 
-#define PBLK_COMMAND_TIMEOUT_MS 30000
-
 /* Max 512 LUNs per device */
 #define PBLK_MAX_LUNS_BITMAP (4)
 
@@ -123,18 +121,6 @@ struct pblk_g_ctx {
        u64 lba;
 };
 
-/* partial read context */
-struct pblk_pr_ctx {
-       struct bio *orig_bio;
-       DECLARE_BITMAP(bitmap, NVM_MAX_VLBA);
-       unsigned int orig_nr_secs;
-       unsigned int bio_init_idx;
-       void *ppa_ptr;
-       dma_addr_t dma_ppa_list;
-       u64 lba_list_mem[NVM_MAX_VLBA];
-       u64 lba_list_media[NVM_MAX_VLBA];
-};
-
 /* Pad context */
 struct pblk_pad_rq {
        struct pblk *pblk;
@@ -305,7 +291,6 @@ struct pblk_rl {
 
        struct timer_list u_timer;
 
-       unsigned long long nr_secs;
        unsigned long total_blocks;
 
        atomic_t free_blocks;           /* Total number of free blocks (+ OP) */
@@ -440,6 +425,7 @@ struct pblk_smeta {
 
 struct pblk_w_err_gc {
        int has_write_err;
+       int has_gc_err;
        __le64 *lba_list;
 };
 
@@ -465,7 +451,6 @@ struct pblk_line {
        int meta_line;                  /* Metadata line id */
        int meta_distance;              /* Distance between data and metadata */
 
-       u64 smeta_ssec;                 /* Sector where smeta starts */
        u64 emeta_ssec;                 /* Sector where emeta starts */
 
        unsigned int sec_in_line;       /* Number of usable secs in line */
@@ -762,7 +747,7 @@ unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct nvm_rq *rqd,
                                 unsigned int pos, unsigned int nr_entries,
                                 unsigned int count);
 int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
-                       struct ppa_addr ppa, int bio_iter, bool advanced_bio);
+                       struct ppa_addr ppa);
 unsigned int pblk_rb_read_commit(struct pblk_rb *rb, unsigned int entries);
 
 unsigned int pblk_rb_sync_init(struct pblk_rb *rb, unsigned long *flags);
@@ -862,15 +847,15 @@ int pblk_update_map_gc(struct pblk *pblk, sector_t lba, struct ppa_addr ppa,
                       struct pblk_line *gc_line, u64 paddr);
 void pblk_lookup_l2p_rand(struct pblk *pblk, struct ppa_addr *ppas,
                          u64 *lba_list, int nr_secs);
-void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
-                        sector_t blba, int nr_secs);
+int pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
+                        sector_t blba, int nr_secs, bool *from_cache);
 void *pblk_get_meta_for_writes(struct pblk *pblk, struct nvm_rq *rqd);
 void pblk_get_packed_meta(struct pblk *pblk, struct nvm_rq *rqd);
 
 /*
  * pblk user I/O write path
  */
-int pblk_write_to_cache(struct pblk *pblk, struct bio *bio,
+void pblk_write_to_cache(struct pblk *pblk, struct bio *bio,
                        unsigned long flags);
 int pblk_write_gc_to_cache(struct pblk *pblk, struct pblk_gc_rq *gc_rq);
 
@@ -896,7 +881,7 @@ void pblk_write_kick(struct pblk *pblk);
  * pblk read path
  */
 extern struct bio_set pblk_bio_set;
-int pblk_submit_read(struct pblk *pblk, struct bio *bio);
+void pblk_submit_read(struct pblk *pblk, struct bio *bio);
 int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq);
 /*
  * pblk recovery
@@ -921,6 +906,7 @@ void pblk_gc_free_full_lines(struct pblk *pblk);
 void pblk_gc_sysfs_state_show(struct pblk *pblk, int *gc_enabled,
                              int *gc_active);
 int pblk_gc_sysfs_force(struct pblk *pblk, int force);
+void pblk_put_line_back(struct pblk *pblk, struct pblk_line *line);
 
 /*
  * pblk rate limiter
index d86e7a4ac04d1a79950a0ab20ef247a5ececc79a..595542bfae85e8abd1ee10938fbcae79e349c014 100644 (file)
@@ -41,6 +41,16 @@ config PL320_MBOX
          Management Engine, primarily for cpufreq. Say Y here if you want
          to use the PL320 IPCM support.
 
+config ARMADA_37XX_RWTM_MBOX
+       tristate "Armada 37xx rWTM BIU Mailbox"
+       depends on ARCH_MVEBU || COMPILE_TEST
+       depends on OF
+       help
+         Mailbox implementation for communication with the the firmware
+         running on the Cortex-M3 rWTM secure processor of the Armada 37xx
+         SOC. Say Y here if you are building for such a device (for example
+         the Turris Mox router).
+
 config OMAP2PLUS_MBOX
        tristate "OMAP2+ Mailbox framework support"
        depends on ARCH_OMAP2PLUS
index 8be3bcbcf882bd0d0957406236ce58f007f1f5f6..c22fad6f696b7efb9765f55342c5c351724b0010 100644 (file)
@@ -9,6 +9,8 @@ obj-$(CONFIG_ARM_MHU)   += arm_mhu.o
 
 obj-$(CONFIG_IMX_MBOX) += imx-mailbox.o
 
+obj-$(CONFIG_ARMADA_37XX_RWTM_MBOX)    += armada-37xx-rwtm-mailbox.o
+
 obj-$(CONFIG_PLATFORM_MHU)     += platform_mhu.o
 
 obj-$(CONFIG_PL320_MBOX)       += pl320-ipc.o
diff --git a/drivers/mailbox/armada-37xx-rwtm-mailbox.c b/drivers/mailbox/armada-37xx-rwtm-mailbox.c
new file mode 100644 (file)
index 0000000..97f90e9
--- /dev/null
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * rWTM BIU Mailbox driver for Armada 37xx
+ *
+ * Author: Marek Behun <marek.behun@nic.cz>
+ */
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/armada-37xx-rwtm-mailbox.h>
+
+#define DRIVER_NAME    "armada-37xx-rwtm-mailbox"
+
+/* relative to rWTM BIU Mailbox Registers */
+#define RWTM_MBOX_PARAM(i)             (0x0 + ((i) << 2))
+#define RWTM_MBOX_COMMAND              0x40
+#define RWTM_MBOX_RETURN_STATUS                0x80
+#define RWTM_MBOX_STATUS(i)            (0x84 + ((i) << 2))
+#define RWTM_MBOX_FIFO_STATUS          0xc4
+#define FIFO_STS_RDY                   0x100
+#define FIFO_STS_CNTR_MASK             0x7
+#define FIFO_STS_CNTR_MAX              4
+
+#define RWTM_HOST_INT_RESET            0xc8
+#define RWTM_HOST_INT_MASK             0xcc
+#define SP_CMD_COMPLETE                        BIT(0)
+#define SP_CMD_QUEUE_FULL_ACCESS       BIT(17)
+#define SP_CMD_QUEUE_FULL              BIT(18)
+
+struct a37xx_mbox {
+       struct device *dev;
+       struct mbox_controller controller;
+       void __iomem *base;
+       int irq;
+};
+
+static void a37xx_mbox_receive(struct mbox_chan *chan)
+{
+       struct a37xx_mbox *mbox = chan->con_priv;
+       struct armada_37xx_rwtm_rx_msg rx_msg;
+       int i;
+
+       rx_msg.retval = readl(mbox->base + RWTM_MBOX_RETURN_STATUS);
+       for (i = 0; i < 16; ++i)
+               rx_msg.status[i] = readl(mbox->base + RWTM_MBOX_STATUS(i));
+
+       mbox_chan_received_data(chan, &rx_msg);
+}
+
+static irqreturn_t a37xx_mbox_irq_handler(int irq, void *data)
+{
+       struct mbox_chan *chan = data;
+       struct a37xx_mbox *mbox = chan->con_priv;
+       u32 reg;
+
+       reg = readl(mbox->base + RWTM_HOST_INT_RESET);
+
+       if (reg & SP_CMD_COMPLETE)
+               a37xx_mbox_receive(chan);
+
+       if (reg & (SP_CMD_QUEUE_FULL_ACCESS | SP_CMD_QUEUE_FULL))
+               dev_err(mbox->dev, "Secure processor command queue full\n");
+
+       writel(reg, mbox->base + RWTM_HOST_INT_RESET);
+       if (reg)
+               mbox_chan_txdone(chan, 0);
+
+       return reg ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int a37xx_mbox_send_data(struct mbox_chan *chan, void *data)
+{
+       struct a37xx_mbox *mbox = chan->con_priv;
+       struct armada_37xx_rwtm_tx_msg *msg = data;
+       int i;
+       u32 reg;
+
+       if (!data)
+               return -EINVAL;
+
+       reg = readl(mbox->base + RWTM_MBOX_FIFO_STATUS);
+       if (!(reg & FIFO_STS_RDY))
+               dev_warn(mbox->dev, "Secure processor not ready\n");
+
+       if ((reg & FIFO_STS_CNTR_MASK) >= FIFO_STS_CNTR_MAX) {
+               dev_err(mbox->dev, "Secure processor command queue full\n");
+               return -EBUSY;
+       }
+
+       for (i = 0; i < 16; ++i)
+               writel(msg->args[i], mbox->base + RWTM_MBOX_PARAM(i));
+       writel(msg->command, mbox->base + RWTM_MBOX_COMMAND);
+
+       return 0;
+}
+
+static int a37xx_mbox_startup(struct mbox_chan *chan)
+{
+       struct a37xx_mbox *mbox = chan->con_priv;
+       u32 reg;
+       int ret;
+
+       ret = devm_request_irq(mbox->dev, mbox->irq, a37xx_mbox_irq_handler, 0,
+                              DRIVER_NAME, chan);
+       if (ret < 0) {
+               dev_err(mbox->dev, "Cannot request irq\n");
+               return ret;
+       }
+
+       /* enable IRQ generation */
+       reg = readl(mbox->base + RWTM_HOST_INT_MASK);
+       reg &= ~(SP_CMD_COMPLETE | SP_CMD_QUEUE_FULL_ACCESS | SP_CMD_QUEUE_FULL);
+       writel(reg, mbox->base + RWTM_HOST_INT_MASK);
+
+       return 0;
+}
+
+static void a37xx_mbox_shutdown(struct mbox_chan *chan)
+{
+       u32 reg;
+       struct a37xx_mbox *mbox = chan->con_priv;
+
+       /* disable interrupt generation */
+       reg = readl(mbox->base + RWTM_HOST_INT_MASK);
+       reg |= SP_CMD_COMPLETE | SP_CMD_QUEUE_FULL_ACCESS | SP_CMD_QUEUE_FULL;
+       writel(reg, mbox->base + RWTM_HOST_INT_MASK);
+
+       devm_free_irq(mbox->dev, mbox->irq, chan);
+}
+
+static const struct mbox_chan_ops a37xx_mbox_ops = {
+       .send_data      = a37xx_mbox_send_data,
+       .startup        = a37xx_mbox_startup,
+       .shutdown       = a37xx_mbox_shutdown,
+};
+
+static int armada_37xx_mbox_probe(struct platform_device *pdev)
+{
+       struct a37xx_mbox *mbox;
+       struct resource *regs;
+       struct mbox_chan *chans;
+       int ret;
+
+       mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+
+       /* Allocated one channel */
+       chans = devm_kzalloc(&pdev->dev, sizeof(*chans), GFP_KERNEL);
+       if (!chans)
+               return -ENOMEM;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       mbox->base = devm_ioremap_resource(&pdev->dev, regs);
+       if (IS_ERR(mbox->base)) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               return PTR_ERR(mbox->base);
+       }
+
+       mbox->irq = platform_get_irq(pdev, 0);
+       if (mbox->irq < 0) {
+               dev_err(&pdev->dev, "Cannot get irq\n");
+               return mbox->irq;
+       }
+
+       mbox->dev = &pdev->dev;
+
+       /* Hardware supports only one channel. */
+       chans[0].con_priv = mbox;
+       mbox->controller.dev = mbox->dev;
+       mbox->controller.num_chans = 1;
+       mbox->controller.chans = chans;
+       mbox->controller.ops = &a37xx_mbox_ops;
+       mbox->controller.txdone_irq = true;
+
+       ret = mbox_controller_register(&mbox->controller);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register mailbox controller\n");
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, mbox);
+       return ret;
+}
+
+static int armada_37xx_mbox_remove(struct platform_device *pdev)
+{
+       struct a37xx_mbox *mbox = platform_get_drvdata(pdev);
+
+       if (!mbox)
+               return -EINVAL;
+
+       mbox_controller_unregister(&mbox->controller);
+
+       return 0;
+}
+
+static const struct of_device_id armada_37xx_mbox_match[] = {
+       { .compatible = "marvell,armada-3700-rwtm-mailbox" },
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, armada_37xx_mbox_match);
+
+static struct platform_driver armada_37xx_mbox_driver = {
+       .probe  = armada_37xx_mbox_probe,
+       .remove = armada_37xx_mbox_remove,
+       .driver = {
+               .name           = DRIVER_NAME,
+               .of_match_table = armada_37xx_mbox_match,
+       },
+};
+
+module_platform_driver(armada_37xx_mbox_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("rWTM BIU Mailbox driver for Armada 37xx");
+MODULE_AUTHOR("Marek Behun <marek.behun@nic.cz>");
index 85fc5b56f99b16e77ace3b5c90fd078b6cd28996..25be8bb5e371d305d1db3c35634c643eb46e3289 100644 (file)
@@ -264,7 +264,6 @@ static int imx_mu_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
-       struct resource *iomem;
        struct imx_mu_priv *priv;
        unsigned int i;
        int ret;
@@ -275,8 +274,7 @@ static int imx_mu_probe(struct platform_device *pdev)
 
        priv->dev = dev;
 
-       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->base = devm_ioremap_resource(&pdev->dev, iomem);
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->base))
                return PTR_ERR(priv->base);
 
index 22811784dc7de9527ddbe60221a8cbb6bac3ca87..00d5219094e5dcde753d583e78b317bfe71b88e2 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
index 210fe504f5aee9954cccc33512bbf11b536b1122..f91dfb1327c7c4e682c6df514f78477bad1655fd 100644 (file)
@@ -8,9 +8,9 @@
 #include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/mailbox_controller.h>
 #include <linux/module.h>
-#include <linux/of_irq.h>
 #include <linux/platform_device.h>
 #include <linux/pm_wakeirq.h>
 
@@ -240,9 +240,11 @@ static int stm32_ipcc_probe(struct platform_device *pdev)
 
        /* irq */
        for (i = 0; i < IPCC_IRQ_NUM; i++) {
-               ipcc->irqs[i] = of_irq_get_byname(dev->of_node, irq_name[i]);
+               ipcc->irqs[i] = platform_get_irq_byname(pdev, irq_name[i]);
                if (ipcc->irqs[i] < 0) {
-                       dev_err(dev, "no IRQ specified %s\n", irq_name[i]);
+                       if (ipcc->irqs[i] != -EPROBE_DEFER)
+                               dev_err(dev, "no IRQ specified %s\n",
+                                       irq_name[i]);
                        ret = ipcc->irqs[i];
                        goto err_clk;
                }
@@ -263,9 +265,10 @@ static int stm32_ipcc_probe(struct platform_device *pdev)
 
        /* wakeup */
        if (of_property_read_bool(np, "wakeup-source")) {
-               ipcc->wkp = of_irq_get_byname(dev->of_node, "wakeup");
+               ipcc->wkp = platform_get_irq_byname(pdev, "wakeup");
                if (ipcc->wkp < 0) {
-                       dev_err(dev, "could not get wakeup IRQ\n");
+                       if (ipcc->wkp != -EPROBE_DEFER)
+                               dev_err(dev, "could not get wakeup IRQ\n");
                        ret = ipcc->wkp;
                        goto err_clk;
                }
index 2557f198e1750002a1a2d7dacd3fefbb926a7fd7..db269a348b20917b035f9c9ec203c6e2d3fdecb9 100644 (file)
@@ -436,6 +436,15 @@ config DM_DELAY
 
        If unsure, say N.
 
+config DM_DUST
+       tristate "Bad sector simulation target"
+       depends on BLK_DEV_DM
+       ---help---
+       A target that simulates bad sector behavior.
+       Useful for testing.
+
+       If unsure, say N.
+
 config DM_INIT
        bool "DM \"dm-mod.create=\" parameter support"
        depends on BLK_DEV_DM=y
index a52b703e588e23dfa3a240f8882acc2d1eb29212..be7a6eb92abcb47a4371fe6ed435f466124dda7a 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_DM_BUFIO)                += dm-bufio.o
 obj-$(CONFIG_DM_BIO_PRISON)    += dm-bio-prison.o
 obj-$(CONFIG_DM_CRYPT)         += dm-crypt.o
 obj-$(CONFIG_DM_DELAY)         += dm-delay.o
+obj-$(CONFIG_DM_DUST)          += dm-dust.o
 obj-$(CONFIG_DM_FLAKEY)                += dm-flakey.o
 obj-$(CONFIG_DM_MULTIPATH)     += dm-multipath.o dm-round-robin.o
 obj-$(CONFIG_DM_MULTIPATH_QL)  += dm-queue-length.o
index 6fc93834da44648176a5163a098fdd485af2bf50..151aa95775be2daee11c7721eb62dde28ec702b1 100644 (file)
@@ -1167,11 +1167,18 @@ static int __load_discards(struct dm_cache_metadata *cmd,
                if (r)
                        return r;
 
-               for (b = 0; b < from_dblock(cmd->discard_nr_blocks); b++) {
+               for (b = 0; ; b++) {
                        r = fn(context, cmd->discard_block_size, to_dblock(b),
                               dm_bitset_cursor_get_value(&c));
                        if (r)
                                break;
+
+                       if (b >= (from_dblock(cmd->discard_nr_blocks) - 1))
+                               break;
+
+                       r = dm_bitset_cursor_next(&c);
+                       if (r)
+                               break;
                }
 
                dm_bitset_cursor_end(&c);
index 7f6462f74ac8fa99dbb3be7ccfe2b5c39068ee7a..1b16d34bb78518a1849aa331c6da2ac1da0e8586 100644 (file)
@@ -946,6 +946,7 @@ static int crypt_integrity_ctr(struct crypt_config *cc, struct dm_target *ti)
 {
 #ifdef CONFIG_BLK_DEV_INTEGRITY
        struct blk_integrity *bi = blk_get_integrity(cc->dev->bdev->bd_disk);
+       struct mapped_device *md = dm_table_get_md(ti->table);
 
        /* From now we require underlying device with our integrity profile */
        if (!bi || strcasecmp(bi->profile->name, "DM-DIF-EXT-TAG")) {
@@ -965,7 +966,7 @@ static int crypt_integrity_ctr(struct crypt_config *cc, struct dm_target *ti)
 
        if (crypt_integrity_aead(cc)) {
                cc->integrity_tag_size = cc->on_disk_tag_size - cc->integrity_iv_size;
-               DMINFO("Integrity AEAD, tag size %u, IV size %u.",
+               DMDEBUG("%s: Integrity AEAD, tag size %u, IV size %u.", dm_device_name(md),
                       cc->integrity_tag_size, cc->integrity_iv_size);
 
                if (crypto_aead_setauthsize(any_tfm_aead(cc), cc->integrity_tag_size)) {
@@ -973,7 +974,7 @@ static int crypt_integrity_ctr(struct crypt_config *cc, struct dm_target *ti)
                        return -EINVAL;
                }
        } else if (cc->integrity_iv_size)
-               DMINFO("Additional per-sector space %u bytes for IV.",
+               DMDEBUG("%s: Additional per-sector space %u bytes for IV.", dm_device_name(md),
                       cc->integrity_iv_size);
 
        if ((cc->integrity_tag_size + cc->integrity_iv_size) != bi->tag_size) {
@@ -1031,11 +1032,11 @@ static u8 *org_iv_of_dmreq(struct crypt_config *cc,
        return iv_of_dmreq(cc, dmreq) + cc->iv_size;
 }
 
-static uint64_t *org_sector_of_dmreq(struct crypt_config *cc,
+static __le64 *org_sector_of_dmreq(struct crypt_config *cc,
                       struct dm_crypt_request *dmreq)
 {
        u8 *ptr = iv_of_dmreq(cc, dmreq) + cc->iv_size + cc->iv_size;
-       return (uint64_t*) ptr;
+       return (__le64 *) ptr;
 }
 
 static unsigned int *org_tag_of_dmreq(struct crypt_config *cc,
@@ -1071,7 +1072,7 @@ static int crypt_convert_block_aead(struct crypt_config *cc,
        struct bio_vec bv_out = bio_iter_iovec(ctx->bio_out, ctx->iter_out);
        struct dm_crypt_request *dmreq;
        u8 *iv, *org_iv, *tag_iv, *tag;
-       uint64_t *sector;
+       __le64 *sector;
        int r = 0;
 
        BUG_ON(cc->integrity_iv_size && cc->integrity_iv_size != cc->iv_size);
@@ -1143,9 +1144,11 @@ static int crypt_convert_block_aead(struct crypt_config *cc,
                r = crypto_aead_decrypt(req);
        }
 
-       if (r == -EBADMSG)
-               DMERR_LIMIT("INTEGRITY AEAD ERROR, sector %llu",
+       if (r == -EBADMSG) {
+               char b[BDEVNAME_SIZE];
+               DMERR_LIMIT("%s: INTEGRITY AEAD ERROR, sector %llu", bio_devname(ctx->bio_in, b),
                            (unsigned long long)le64_to_cpu(*sector));
+       }
 
        if (!r && cc->iv_gen_ops && cc->iv_gen_ops->post)
                r = cc->iv_gen_ops->post(cc, org_iv, dmreq);
@@ -1166,7 +1169,7 @@ static int crypt_convert_block_skcipher(struct crypt_config *cc,
        struct scatterlist *sg_in, *sg_out;
        struct dm_crypt_request *dmreq;
        u8 *iv, *org_iv, *tag_iv;
-       uint64_t *sector;
+       __le64 *sector;
        int r = 0;
 
        /* Reject unexpected unaligned bio. */
@@ -1788,7 +1791,8 @@ static void kcryptd_async_done(struct crypto_async_request *async_req,
                error = cc->iv_gen_ops->post(cc, org_iv_of_dmreq(cc, dmreq), dmreq);
 
        if (error == -EBADMSG) {
-               DMERR_LIMIT("INTEGRITY AEAD ERROR, sector %llu",
+               char b[BDEVNAME_SIZE];
+               DMERR_LIMIT("%s: INTEGRITY AEAD ERROR, sector %llu", bio_devname(ctx->bio_in, b),
                            (unsigned long long)le64_to_cpu(*org_sector_of_dmreq(cc, dmreq)));
                io->error = BLK_STS_PROTECTION;
        } else if (error < 0)
@@ -1887,7 +1891,7 @@ static int crypt_alloc_tfms_skcipher(struct crypt_config *cc, char *ciphermode)
         * algorithm implementation is used.  Help people debug performance
         * problems by logging the ->cra_driver_name.
         */
-       DMINFO("%s using implementation \"%s\"", ciphermode,
+       DMDEBUG_LIMIT("%s using implementation \"%s\"", ciphermode,
               crypto_skcipher_alg(any_tfm(cc))->base.cra_driver_name);
        return 0;
 }
@@ -1907,7 +1911,7 @@ static int crypt_alloc_tfms_aead(struct crypt_config *cc, char *ciphermode)
                return err;
        }
 
-       DMINFO("%s using implementation \"%s\"", ciphermode,
+       DMDEBUG_LIMIT("%s using implementation \"%s\"", ciphermode,
               crypto_aead_alg(any_tfm_aead(cc))->base.cra_driver_name);
        return 0;
 }
index fddffe251bf6bf5c2ded195c31e392bc228568d8..f496213f8b6753b8760901848140c3f9901e7e06 100644 (file)
@@ -121,7 +121,8 @@ static void delay_dtr(struct dm_target *ti)
 {
        struct delay_c *dc = ti->private;
 
-       destroy_workqueue(dc->kdelayd_wq);
+       if (dc->kdelayd_wq)
+               destroy_workqueue(dc->kdelayd_wq);
 
        if (dc->read.dev)
                dm_put_device(ti, dc->read.dev);
diff --git a/drivers/md/dm-dust.c b/drivers/md/dm-dust.c
new file mode 100644 (file)
index 0000000..845f376
--- /dev/null
@@ -0,0 +1,515 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * This is a test "dust" device, which fails reads on specified
+ * sectors, emulating the behavior of a hard disk drive sending
+ * a "Read Medium Error" sense.
+ *
+ */
+
+#include <linux/device-mapper.h>
+#include <linux/module.h>
+#include <linux/rbtree.h>
+
+#define DM_MSG_PREFIX "dust"
+
+struct badblock {
+       struct rb_node node;
+       sector_t bb;
+};
+
+struct dust_device {
+       struct dm_dev *dev;
+       struct rb_root badblocklist;
+       unsigned long long badblock_count;
+       spinlock_t dust_lock;
+       unsigned int blksz;
+       unsigned int sect_per_block;
+       sector_t start;
+       bool fail_read_on_bb:1;
+       bool quiet_mode:1;
+};
+
+static struct badblock *dust_rb_search(struct rb_root *root, sector_t blk)
+{
+       struct rb_node *node = root->rb_node;
+
+       while (node) {
+               struct badblock *bblk = rb_entry(node, struct badblock, node);
+
+               if (bblk->bb > blk)
+                       node = node->rb_left;
+               else if (bblk->bb < blk)
+                       node = node->rb_right;
+               else
+                       return bblk;
+       }
+
+       return NULL;
+}
+
+static bool dust_rb_insert(struct rb_root *root, struct badblock *new)
+{
+       struct badblock *bblk;
+       struct rb_node **link = &root->rb_node, *parent = NULL;
+       sector_t value = new->bb;
+
+       while (*link) {
+               parent = *link;
+               bblk = rb_entry(parent, struct badblock, node);
+
+               if (bblk->bb > value)
+                       link = &(*link)->rb_left;
+               else if (bblk->bb < value)
+                       link = &(*link)->rb_right;
+               else
+                       return false;
+       }
+
+       rb_link_node(&new->node, parent, link);
+       rb_insert_color(&new->node, root);
+
+       return true;
+}
+
+static int dust_remove_block(struct dust_device *dd, unsigned long long block)
+{
+       struct badblock *bblock;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->dust_lock, flags);
+       bblock = dust_rb_search(&dd->badblocklist, block * dd->sect_per_block);
+
+       if (bblock == NULL) {
+               if (!dd->quiet_mode) {
+                       DMERR("%s: block %llu not found in badblocklist",
+                             __func__, block);
+               }
+               spin_unlock_irqrestore(&dd->dust_lock, flags);
+               return -EINVAL;
+       }
+
+       rb_erase(&bblock->node, &dd->badblocklist);
+       dd->badblock_count--;
+       if (!dd->quiet_mode)
+               DMINFO("%s: badblock removed at block %llu", __func__, block);
+       kfree(bblock);
+       spin_unlock_irqrestore(&dd->dust_lock, flags);
+
+       return 0;
+}
+
+static int dust_add_block(struct dust_device *dd, unsigned long long block)
+{
+       struct badblock *bblock;
+       unsigned long flags;
+
+       bblock = kmalloc(sizeof(*bblock), GFP_KERNEL);
+       if (bblock == NULL) {
+               if (!dd->quiet_mode)
+                       DMERR("%s: badblock allocation failed", __func__);
+               return -ENOMEM;
+       }
+
+       spin_lock_irqsave(&dd->dust_lock, flags);
+       bblock->bb = block * dd->sect_per_block;
+       if (!dust_rb_insert(&dd->badblocklist, bblock)) {
+               if (!dd->quiet_mode) {
+                       DMERR("%s: block %llu already in badblocklist",
+                             __func__, block);
+               }
+               spin_unlock_irqrestore(&dd->dust_lock, flags);
+               kfree(bblock);
+               return -EINVAL;
+       }
+
+       dd->badblock_count++;
+       if (!dd->quiet_mode)
+               DMINFO("%s: badblock added at block %llu", __func__, block);
+       spin_unlock_irqrestore(&dd->dust_lock, flags);
+
+       return 0;
+}
+
+static int dust_query_block(struct dust_device *dd, unsigned long long block)
+{
+       struct badblock *bblock;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dd->dust_lock, flags);
+       bblock = dust_rb_search(&dd->badblocklist, block * dd->sect_per_block);
+       if (bblock != NULL)
+               DMINFO("%s: block %llu found in badblocklist", __func__, block);
+       else
+               DMINFO("%s: block %llu not found in badblocklist", __func__, block);
+       spin_unlock_irqrestore(&dd->dust_lock, flags);
+
+       return 0;
+}
+
+static int __dust_map_read(struct dust_device *dd, sector_t thisblock)
+{
+       struct badblock *bblk = dust_rb_search(&dd->badblocklist, thisblock);
+
+       if (bblk)
+               return DM_MAPIO_KILL;
+
+       return DM_MAPIO_REMAPPED;
+}
+
+static int dust_map_read(struct dust_device *dd, sector_t thisblock,
+                        bool fail_read_on_bb)
+{
+       unsigned long flags;
+       int ret = DM_MAPIO_REMAPPED;
+
+       if (fail_read_on_bb) {
+               spin_lock_irqsave(&dd->dust_lock, flags);
+               ret = __dust_map_read(dd, thisblock);
+               spin_unlock_irqrestore(&dd->dust_lock, flags);
+       }
+
+       return ret;
+}
+
+static void __dust_map_write(struct dust_device *dd, sector_t thisblock)
+{
+       struct badblock *bblk = dust_rb_search(&dd->badblocklist, thisblock);
+
+       if (bblk) {
+               rb_erase(&bblk->node, &dd->badblocklist);
+               dd->badblock_count--;
+               kfree(bblk);
+               if (!dd->quiet_mode) {
+                       sector_div(thisblock, dd->sect_per_block);
+                       DMINFO("block %llu removed from badblocklist by write",
+                              (unsigned long long)thisblock);
+               }
+       }
+}
+
+static int dust_map_write(struct dust_device *dd, sector_t thisblock,
+                         bool fail_read_on_bb)
+{
+       unsigned long flags;
+
+       if (fail_read_on_bb) {
+               spin_lock_irqsave(&dd->dust_lock, flags);
+               __dust_map_write(dd, thisblock);
+               spin_unlock_irqrestore(&dd->dust_lock, flags);
+       }
+
+       return DM_MAPIO_REMAPPED;
+}
+
+static int dust_map(struct dm_target *ti, struct bio *bio)
+{
+       struct dust_device *dd = ti->private;
+       int ret;
+
+       bio_set_dev(bio, dd->dev->bdev);
+       bio->bi_iter.bi_sector = dd->start + dm_target_offset(ti, bio->bi_iter.bi_sector);
+
+       if (bio_data_dir(bio) == READ)
+               ret = dust_map_read(dd, bio->bi_iter.bi_sector, dd->fail_read_on_bb);
+       else
+               ret = dust_map_write(dd, bio->bi_iter.bi_sector, dd->fail_read_on_bb);
+
+       return ret;
+}
+
+static bool __dust_clear_badblocks(struct rb_root *tree,
+                                  unsigned long long count)
+{
+       struct rb_node *node = NULL, *nnode = NULL;
+
+       nnode = rb_first(tree);
+       if (nnode == NULL) {
+               BUG_ON(count != 0);
+               return false;
+       }
+
+       while (nnode) {
+               node = nnode;
+               nnode = rb_next(node);
+               rb_erase(node, tree);
+               count--;
+               kfree(node);
+       }
+       BUG_ON(count != 0);
+       BUG_ON(tree->rb_node != NULL);
+
+       return true;
+}
+
+static int dust_clear_badblocks(struct dust_device *dd)
+{
+       unsigned long flags;
+       struct rb_root badblocklist;
+       unsigned long long badblock_count;
+
+       spin_lock_irqsave(&dd->dust_lock, flags);
+       badblocklist = dd->badblocklist;
+       badblock_count = dd->badblock_count;
+       dd->badblocklist = RB_ROOT;
+       dd->badblock_count = 0;
+       spin_unlock_irqrestore(&dd->dust_lock, flags);
+
+       if (!__dust_clear_badblocks(&badblocklist, badblock_count))
+               DMINFO("%s: no badblocks found", __func__);
+       else
+               DMINFO("%s: badblocks cleared", __func__);
+
+       return 0;
+}
+
+/*
+ * Target parameters:
+ *
+ * <device_path> <offset> <blksz>
+ *
+ * device_path: path to the block device
+ * offset: offset to data area from start of device_path
+ * blksz: block size (minimum 512, maximum 1073741824, must be a power of 2)
+ */
+static int dust_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+       struct dust_device *dd;
+       unsigned long long tmp;
+       char dummy;
+       unsigned int blksz;
+       unsigned int sect_per_block;
+       sector_t DUST_MAX_BLKSZ_SECTORS = 2097152;
+       sector_t max_block_sectors = min(ti->len, DUST_MAX_BLKSZ_SECTORS);
+
+       if (argc != 3) {
+               ti->error = "Invalid argument count";
+               return -EINVAL;
+       }
+
+       if (kstrtouint(argv[2], 10, &blksz) || !blksz) {
+               ti->error = "Invalid block size parameter";
+               return -EINVAL;
+       }
+
+       if (blksz < 512) {
+               ti->error = "Block size must be at least 512";
+               return -EINVAL;
+       }
+
+       if (!is_power_of_2(blksz)) {
+               ti->error = "Block size must be a power of 2";
+               return -EINVAL;
+       }
+
+       if (to_sector(blksz) > max_block_sectors) {
+               ti->error = "Block size is too large";
+               return -EINVAL;
+       }
+
+       sect_per_block = (blksz >> SECTOR_SHIFT);
+
+       if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1 || tmp != (sector_t)tmp) {
+               ti->error = "Invalid device offset sector";
+               return -EINVAL;
+       }
+
+       dd = kzalloc(sizeof(struct dust_device), GFP_KERNEL);
+       if (dd == NULL) {
+               ti->error = "Cannot allocate context";
+               return -ENOMEM;
+       }
+
+       if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &dd->dev)) {
+               ti->error = "Device lookup failed";
+               kfree(dd);
+               return -EINVAL;
+       }
+
+       dd->sect_per_block = sect_per_block;
+       dd->blksz = blksz;
+       dd->start = tmp;
+
+       /*
+        * Whether to fail a read on a "bad" block.
+        * Defaults to false; enabled later by message.
+        */
+       dd->fail_read_on_bb = false;
+
+       /*
+        * Initialize bad block list rbtree.
+        */
+       dd->badblocklist = RB_ROOT;
+       dd->badblock_count = 0;
+       spin_lock_init(&dd->dust_lock);
+
+       dd->quiet_mode = false;
+
+       BUG_ON(dm_set_target_max_io_len(ti, dd->sect_per_block) != 0);
+
+       ti->num_discard_bios = 1;
+       ti->num_flush_bios = 1;
+       ti->private = dd;
+
+       return 0;
+}
+
+static void dust_dtr(struct dm_target *ti)
+{
+       struct dust_device *dd = ti->private;
+
+       __dust_clear_badblocks(&dd->badblocklist, dd->badblock_count);
+       dm_put_device(ti, dd->dev);
+       kfree(dd);
+}
+
+static int dust_message(struct dm_target *ti, unsigned int argc, char **argv,
+                       char *result_buf, unsigned int maxlen)
+{
+       struct dust_device *dd = ti->private;
+       sector_t size = i_size_read(dd->dev->bdev->bd_inode) >> SECTOR_SHIFT;
+       bool invalid_msg = false;
+       int result = -EINVAL;
+       unsigned long long tmp, block;
+       unsigned long flags;
+       char dummy;
+
+       if (argc == 1) {
+               if (!strcasecmp(argv[0], "addbadblock") ||
+                   !strcasecmp(argv[0], "removebadblock") ||
+                   !strcasecmp(argv[0], "queryblock")) {
+                       DMERR("%s requires an additional argument", argv[0]);
+               } else if (!strcasecmp(argv[0], "disable")) {
+                       DMINFO("disabling read failures on bad sectors");
+                       dd->fail_read_on_bb = false;
+                       result = 0;
+               } else if (!strcasecmp(argv[0], "enable")) {
+                       DMINFO("enabling read failures on bad sectors");
+                       dd->fail_read_on_bb = true;
+                       result = 0;
+               } else if (!strcasecmp(argv[0], "countbadblocks")) {
+                       spin_lock_irqsave(&dd->dust_lock, flags);
+                       DMINFO("countbadblocks: %llu badblock(s) found",
+                              dd->badblock_count);
+                       spin_unlock_irqrestore(&dd->dust_lock, flags);
+                       result = 0;
+               } else if (!strcasecmp(argv[0], "clearbadblocks")) {
+                       result = dust_clear_badblocks(dd);
+               } else if (!strcasecmp(argv[0], "quiet")) {
+                       if (!dd->quiet_mode)
+                               dd->quiet_mode = true;
+                       else
+                               dd->quiet_mode = false;
+                       result = 0;
+               } else {
+                       invalid_msg = true;
+               }
+       } else if (argc == 2) {
+               if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1)
+                       return result;
+
+               block = tmp;
+               sector_div(size, dd->sect_per_block);
+               if (block > size) {
+                       DMERR("selected block value out of range");
+                       return result;
+               }
+
+               if (!strcasecmp(argv[0], "addbadblock"))
+                       result = dust_add_block(dd, block);
+               else if (!strcasecmp(argv[0], "removebadblock"))
+                       result = dust_remove_block(dd, block);
+               else if (!strcasecmp(argv[0], "queryblock"))
+                       result = dust_query_block(dd, block);
+               else
+                       invalid_msg = true;
+
+       } else
+               DMERR("invalid number of arguments '%d'", argc);
+
+       if (invalid_msg)
+               DMERR("unrecognized message '%s' received", argv[0]);
+
+       return result;
+}
+
+static void dust_status(struct dm_target *ti, status_type_t type,
+                       unsigned int status_flags, char *result, unsigned int maxlen)
+{
+       struct dust_device *dd = ti->private;
+       unsigned int sz = 0;
+
+       switch (type) {
+       case STATUSTYPE_INFO:
+               DMEMIT("%s %s %s", dd->dev->name,
+                      dd->fail_read_on_bb ? "fail_read_on_bad_block" : "bypass",
+                      dd->quiet_mode ? "quiet" : "verbose");
+               break;
+
+       case STATUSTYPE_TABLE:
+               DMEMIT("%s %llu %u", dd->dev->name,
+                      (unsigned long long)dd->start, dd->blksz);
+               break;
+       }
+}
+
+static int dust_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
+{
+       struct dust_device *dd = ti->private;
+       struct dm_dev *dev = dd->dev;
+
+       *bdev = dev->bdev;
+
+       /*
+        * Only pass ioctls through if the device sizes match exactly.
+        */
+       if (dd->start ||
+           ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
+               return 1;
+
+       return 0;
+}
+
+static int dust_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn,
+                               void *data)
+{
+       struct dust_device *dd = ti->private;
+
+       return fn(ti, dd->dev, dd->start, ti->len, data);
+}
+
+static struct target_type dust_target = {
+       .name = "dust",
+       .version = {1, 0, 0},
+       .module = THIS_MODULE,
+       .ctr = dust_ctr,
+       .dtr = dust_dtr,
+       .iterate_devices = dust_iterate_devices,
+       .map = dust_map,
+       .message = dust_message,
+       .status = dust_status,
+       .prepare_ioctl = dust_prepare_ioctl,
+};
+
+static int __init dm_dust_init(void)
+{
+       int result = dm_register_target(&dust_target);
+
+       if (result < 0)
+               DMERR("dm_register_target failed %d", result);
+
+       return result;
+}
+
+static void __exit dm_dust_exit(void)
+{
+       dm_unregister_target(&dust_target);
+}
+
+module_init(dm_dust_init);
+module_exit(dm_dust_exit);
+
+MODULE_DESCRIPTION(DM_NAME " dust test target");
+MODULE_AUTHOR("Bryan Gurney <dm-devel@redhat.com>");
+MODULE_LICENSE("GPL");
index 721efc4939422011a188ed1015473f118285352f..3f4139ac1f602463a452ddacef7cf092c3db6c85 100644 (file)
@@ -11,6 +11,7 @@
 #define _LINUX_DM_EXCEPTION_STORE
 
 #include <linux/blkdev.h>
+#include <linux/list_bl.h>
 #include <linux/device-mapper.h>
 
 /*
@@ -27,7 +28,7 @@ typedef sector_t chunk_t;
  * chunk within the device.
  */
 struct dm_exception {
-       struct list_head hash_list;
+       struct hlist_bl_node hash_list;
 
        chunk_t old_chunk;
        chunk_t new_chunk;
index 4b76f84424c3c1a73ef3bc3b9605a1486e3bf88b..352e803f566e1073b107c0beb2eff1c6256dd482 100644 (file)
@@ -160,7 +160,7 @@ static int __init dm_parse_table(struct dm_device *dev, char *str)
 
        while (table_entry) {
                DMDEBUG("parsing table \"%s\"", str);
-               if (++dev->dmi.target_count >= DM_MAX_TARGETS) {
+               if (++dev->dmi.target_count > DM_MAX_TARGETS) {
                        DMERR("too many targets %u > %d",
                              dev->dmi.target_count, DM_MAX_TARGETS);
                        return -EINVAL;
@@ -242,9 +242,9 @@ static int __init dm_parse_devices(struct list_head *devices, char *str)
                        return -ENOMEM;
                list_add_tail(&dev->list, devices);
 
-               if (++ndev >= DM_MAX_DEVICES) {
-                       DMERR("too many targets %u > %d",
-                             dev->dmi.target_count, DM_MAX_TARGETS);
+               if (++ndev > DM_MAX_DEVICES) {
+                       DMERR("too many devices %lu > %d",
+                             ndev, DM_MAX_DEVICES);
                        return -EINVAL;
                }
 
index c27c32cf4a30df7164793f9129717e3fa020f218..44e76cda087aa658fbb13195fa5d91f4117902b8 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/rbtree.h>
 #include <linux/delay.h>
 #include <linux/random.h>
+#include <linux/reboot.h>
 #include <crypto/hash.h>
 #include <crypto/skcipher.h>
 #include <linux/async_tx.h>
@@ -24,6 +25,7 @@
 
 #define DEFAULT_INTERLEAVE_SECTORS     32768
 #define DEFAULT_JOURNAL_SIZE_FACTOR    7
+#define DEFAULT_SECTORS_PER_BITMAP_BIT 32768
 #define DEFAULT_BUFFER_SECTORS         128
 #define DEFAULT_JOURNAL_WATERMARK      50
 #define DEFAULT_SYNC_MSEC              10000
@@ -33,6 +35,8 @@
 #define METADATA_WORKQUEUE_MAX_ACTIVE  16
 #define RECALC_SECTORS                 8192
 #define RECALC_WRITE_SUPER             16
+#define BITMAP_BLOCK_SIZE              4096    /* don't change it */
+#define BITMAP_FLUSH_INTERVAL          (10 * HZ)
 
 /*
  * Warning - DEBUG_PRINT prints security-sensitive data to the log,
@@ -48,6 +52,7 @@
 #define SB_MAGIC                       "integrt"
 #define SB_VERSION_1                   1
 #define SB_VERSION_2                   2
+#define SB_VERSION_3                   3
 #define SB_SECTORS                     8
 #define MAX_SECTORS_PER_BLOCK          8
 
@@ -60,12 +65,14 @@ struct superblock {
        __u64 provided_data_sectors;    /* userspace uses this value */
        __u32 flags;
        __u8 log2_sectors_per_block;
-       __u8 pad[3];
+       __u8 log2_blocks_per_bitmap_bit;
+       __u8 pad[2];
        __u64 recalc_sector;
 };
 
 #define SB_FLAG_HAVE_JOURNAL_MAC       0x1
 #define SB_FLAG_RECALCULATING          0x2
+#define SB_FLAG_DIRTY_BITMAP           0x4
 
 #define        JOURNAL_ENTRY_ROUNDUP           8
 
@@ -151,9 +158,18 @@ struct dm_integrity_c {
        struct workqueue_struct *metadata_wq;
        struct superblock *sb;
        unsigned journal_pages;
+       unsigned n_bitmap_blocks;
+
        struct page_list *journal;
        struct page_list *journal_io;
        struct page_list *journal_xor;
+       struct page_list *recalc_bitmap;
+       struct page_list *may_write_bitmap;
+       struct bitmap_block_status *bbs;
+       unsigned bitmap_flush_interval;
+       int synchronous_mode;
+       struct bio_list synchronous_bios;
+       struct delayed_work bitmap_flush_work;
 
        struct crypto_skcipher *journal_crypt;
        struct scatterlist **journal_scatterlist;
@@ -180,6 +196,7 @@ struct dm_integrity_c {
        __s8 log2_metadata_run;
        __u8 log2_buffer_sectors;
        __u8 sectors_per_block;
+       __u8 log2_blocks_per_bitmap_bit;
 
        unsigned char mode;
        int suspending;
@@ -232,17 +249,20 @@ struct dm_integrity_c {
 
        bool journal_uptodate;
        bool just_formatted;
+       bool recalculate_flag;
 
        struct alg_spec internal_hash_alg;
        struct alg_spec journal_crypt_alg;
        struct alg_spec journal_mac_alg;
 
        atomic64_t number_of_mismatches;
+
+       struct notifier_block reboot_notifier;
 };
 
 struct dm_integrity_range {
        sector_t logical_sector;
-       unsigned n_sectors;
+       sector_t n_sectors;
        bool waiting;
        union {
                struct rb_node node;
@@ -288,6 +308,16 @@ struct journal_io {
        struct journal_completion *comp;
 };
 
+struct bitmap_block_status {
+       struct work_struct work;
+       struct dm_integrity_c *ic;
+       unsigned idx;
+       unsigned long *bitmap;
+       struct bio_list bio_queue;
+       spinlock_t bio_queue_lock;
+
+};
+
 static struct kmem_cache *journal_io_cache;
 
 #define JOURNAL_IO_MEMPOOL     32
@@ -423,7 +453,9 @@ static void wraparound_section(struct dm_integrity_c *ic, unsigned *sec_ptr)
 
 static void sb_set_version(struct dm_integrity_c *ic)
 {
-       if (ic->meta_dev || ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING))
+       if (ic->mode == 'B' || ic->sb->flags & cpu_to_le32(SB_FLAG_DIRTY_BITMAP))
+               ic->sb->version = SB_VERSION_3;
+       else if (ic->meta_dev || ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING))
                ic->sb->version = SB_VERSION_2;
        else
                ic->sb->version = SB_VERSION_1;
@@ -447,6 +479,137 @@ static int sync_rw_sb(struct dm_integrity_c *ic, int op, int op_flags)
        return dm_io(&io_req, 1, &io_loc, NULL);
 }
 
+#define BITMAP_OP_TEST_ALL_SET         0
+#define BITMAP_OP_TEST_ALL_CLEAR       1
+#define BITMAP_OP_SET                  2
+#define BITMAP_OP_CLEAR                        3
+
+static bool block_bitmap_op(struct dm_integrity_c *ic, struct page_list *bitmap,
+                           sector_t sector, sector_t n_sectors, int mode)
+{
+       unsigned long bit, end_bit, this_end_bit, page, end_page;
+       unsigned long *data;
+
+       if (unlikely(((sector | n_sectors) & ((1 << ic->sb->log2_sectors_per_block) - 1)) != 0)) {
+               DMCRIT("invalid bitmap access (%llx,%llx,%d,%d,%d)",
+                       (unsigned long long)sector,
+                       (unsigned long long)n_sectors,
+                       ic->sb->log2_sectors_per_block,
+                       ic->log2_blocks_per_bitmap_bit,
+                       mode);
+               BUG();
+       }
+
+       if (unlikely(!n_sectors))
+               return true;
+
+       bit = sector >> (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit);
+       end_bit = (sector + n_sectors - 1) >>
+               (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit);
+
+       page = bit / (PAGE_SIZE * 8);
+       bit %= PAGE_SIZE * 8;
+
+       end_page = end_bit / (PAGE_SIZE * 8);
+       end_bit %= PAGE_SIZE * 8;
+
+repeat:
+       if (page < end_page) {
+               this_end_bit = PAGE_SIZE * 8 - 1;
+       } else {
+               this_end_bit = end_bit;
+       }
+
+       data = lowmem_page_address(bitmap[page].page);
+
+       if (mode == BITMAP_OP_TEST_ALL_SET) {
+               while (bit <= this_end_bit) {
+                       if (!(bit % BITS_PER_LONG) && this_end_bit >= bit + BITS_PER_LONG - 1) {
+                               do {
+                                       if (data[bit / BITS_PER_LONG] != -1)
+                                               return false;
+                                       bit += BITS_PER_LONG;
+                               } while (this_end_bit >= bit + BITS_PER_LONG - 1);
+                               continue;
+                       }
+                       if (!test_bit(bit, data))
+                               return false;
+                       bit++;
+               }
+       } else if (mode == BITMAP_OP_TEST_ALL_CLEAR) {
+               while (bit <= this_end_bit) {
+                       if (!(bit % BITS_PER_LONG) && this_end_bit >= bit + BITS_PER_LONG - 1) {
+                               do {
+                                       if (data[bit / BITS_PER_LONG] != 0)
+                                               return false;
+                                       bit += BITS_PER_LONG;
+                               } while (this_end_bit >= bit + BITS_PER_LONG - 1);
+                               continue;
+                       }
+                       if (test_bit(bit, data))
+                               return false;
+                       bit++;
+               }
+       } else if (mode == BITMAP_OP_SET) {
+               while (bit <= this_end_bit) {
+                       if (!(bit % BITS_PER_LONG) && this_end_bit >= bit + BITS_PER_LONG - 1) {
+                               do {
+                                       data[bit / BITS_PER_LONG] = -1;
+                                       bit += BITS_PER_LONG;
+                               } while (this_end_bit >= bit + BITS_PER_LONG - 1);
+                               continue;
+                       }
+                       __set_bit(bit, data);
+                       bit++;
+               }
+       } else if (mode == BITMAP_OP_CLEAR) {
+               if (!bit && this_end_bit == PAGE_SIZE * 8 - 1)
+                       clear_page(data);
+               else while (bit <= this_end_bit) {
+                       if (!(bit % BITS_PER_LONG) && this_end_bit >= bit + BITS_PER_LONG - 1) {
+                               do {
+                                       data[bit / BITS_PER_LONG] = 0;
+                                       bit += BITS_PER_LONG;
+                               } while (this_end_bit >= bit + BITS_PER_LONG - 1);
+                               continue;
+                       }
+                       __clear_bit(bit, data);
+                       bit++;
+               }
+       } else {
+               BUG();
+       }
+
+       if (unlikely(page < end_page)) {
+               bit = 0;
+               page++;
+               goto repeat;
+       }
+
+       return true;
+}
+
+static void block_bitmap_copy(struct dm_integrity_c *ic, struct page_list *dst, struct page_list *src)
+{
+       unsigned n_bitmap_pages = DIV_ROUND_UP(ic->n_bitmap_blocks, PAGE_SIZE / BITMAP_BLOCK_SIZE);
+       unsigned i;
+
+       for (i = 0; i < n_bitmap_pages; i++) {
+               unsigned long *dst_data = lowmem_page_address(dst[i].page);
+               unsigned long *src_data = lowmem_page_address(src[i].page);
+               copy_page(dst_data, src_data);
+       }
+}
+
+static struct bitmap_block_status *sector_to_bitmap_block(struct dm_integrity_c *ic, sector_t sector)
+{
+       unsigned bit = sector >> (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit);
+       unsigned bitmap_block = bit / (BITMAP_BLOCK_SIZE * 8);
+
+       BUG_ON(bitmap_block >= ic->n_bitmap_blocks);
+       return &ic->bbs[bitmap_block];
+}
+
 static void access_journal_check(struct dm_integrity_c *ic, unsigned section, unsigned offset,
                                 bool e, const char *function)
 {
@@ -455,8 +618,8 @@ static void access_journal_check(struct dm_integrity_c *ic, unsigned section, un
 
        if (unlikely(section >= ic->journal_sections) ||
            unlikely(offset >= limit)) {
-               printk(KERN_CRIT "%s: invalid access at (%u,%u), limit (%u,%u)\n",
-                       function, section, offset, ic->journal_sections, limit);
+               DMCRIT("%s: invalid access at (%u,%u), limit (%u,%u)",
+                      function, section, offset, ic->journal_sections, limit);
                BUG();
        }
 #endif
@@ -756,12 +919,12 @@ static void complete_journal_io(unsigned long error, void *context)
        complete_journal_op(comp);
 }
 
-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_sectors(struct dm_integrity_c *ic, int op, int op_flags,
+                              unsigned sector, unsigned n_sectors, struct journal_completion *comp)
 {
        struct dm_io_request io_req;
        struct dm_io_region io_loc;
-       unsigned sector, n_sectors, pl_index, pl_offset;
+       unsigned pl_index, pl_offset;
        int r;
 
        if (unlikely(dm_integrity_failed(ic))) {
@@ -770,9 +933,6 @@ static void rw_journal(struct dm_integrity_c *ic, int op, int op_flags, unsigned
                return;
        }
 
-       sector = section * ic->journal_section_sectors;
-       n_sectors = n_sections * ic->journal_section_sectors;
-
        pl_index = sector >> (PAGE_SHIFT - SECTOR_SHIFT);
        pl_offset = (sector << SECTOR_SHIFT) & (PAGE_SIZE - 1);
 
@@ -805,6 +965,17 @@ static void rw_journal(struct dm_integrity_c *ic, int op, int op_flags, unsigned
        }
 }
 
+static void rw_journal(struct dm_integrity_c *ic, int op, int op_flags, 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);
+}
+
 static void write_journal(struct dm_integrity_c *ic, unsigned commit_start, unsigned commit_sections)
 {
        struct journal_completion io_comp;
@@ -988,6 +1159,12 @@ static void wait_and_add_new_range(struct dm_integrity_c *ic, struct dm_integrit
        } while (unlikely(new_range->waiting));
 }
 
+static void add_new_range_and_wait(struct dm_integrity_c *ic, struct dm_integrity_range *new_range)
+{
+       if (unlikely(!add_new_range(ic, new_range, true)))
+               wait_and_add_new_range(ic, new_range);
+}
+
 static void init_journal_node(struct journal_node *node)
 {
        RB_CLEAR_NODE(&node->node);
@@ -1204,6 +1381,14 @@ static void do_endio(struct dm_integrity_c *ic, struct bio *bio)
        int r = dm_integrity_failed(ic);
        if (unlikely(r) && !bio->bi_status)
                bio->bi_status = errno_to_blk_status(r);
+       if (unlikely(ic->synchronous_mode) && bio_op(bio) == REQ_OP_WRITE) {
+               unsigned long flags;
+               spin_lock_irqsave(&ic->endio_wait.lock, flags);
+               bio_list_add(&ic->synchronous_bios, bio);
+               queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, 0);
+               spin_unlock_irqrestore(&ic->endio_wait.lock, flags);
+               return;
+       }
        bio_endio(bio);
 }
 
@@ -1477,7 +1662,8 @@ static int dm_integrity_map(struct dm_target *ti, struct bio *bio)
                        else
                                wanted_tag_size *= ic->tag_size;
                        if (unlikely(wanted_tag_size != bip->bip_iter.bi_size)) {
-                               DMERR("Invalid integrity data size %u, expected %u", bip->bip_iter.bi_size, wanted_tag_size);
+                               DMERR("Invalid integrity data size %u, expected %u",
+                                     bip->bip_iter.bi_size, wanted_tag_size);
                                return DM_MAPIO_KILL;
                        }
                }
@@ -1681,7 +1867,7 @@ retry:
                        unsigned ws, we, range_sectors;
 
                        dio->range.n_sectors = min(dio->range.n_sectors,
-                                                  ic->free_sectors << ic->sb->log2_sectors_per_block);
+                                                  (sector_t)ic->free_sectors << ic->sb->log2_sectors_per_block);
                        if (unlikely(!dio->range.n_sectors)) {
                                if (from_map)
                                        goto offload_to_thread;
@@ -1764,6 +1950,20 @@ offload_to_thread:
                goto journal_read_write;
        }
 
+       if (ic->mode == 'B' && dio->write) {
+               if (!block_bitmap_op(ic, ic->may_write_bitmap, dio->range.logical_sector,
+                                    dio->range.n_sectors, BITMAP_OP_TEST_ALL_SET)) {
+                       struct bitmap_block_status *bbs;
+
+                       bbs = sector_to_bitmap_block(ic, dio->range.logical_sector);
+                       spin_lock(&bbs->bio_queue_lock);
+                       bio_list_add(&bbs->bio_queue, bio);
+                       spin_unlock(&bbs->bio_queue_lock);
+                       queue_work(ic->writer_wq, &bbs->work);
+                       return;
+               }
+       }
+
        dio->in_flight = (atomic_t)ATOMIC_INIT(2);
 
        if (need_sync_io) {
@@ -1790,10 +1990,15 @@ offload_to_thread:
 
        if (need_sync_io) {
                wait_for_completion_io(&read_comp);
-               if (unlikely(ic->recalc_wq != NULL) &&
-                   ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) &&
+               if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) &&
                    dio->range.logical_sector + dio->range.n_sectors > le64_to_cpu(ic->sb->recalc_sector))
                        goto skip_check;
+               if (ic->mode == 'B') {
+                       if (!block_bitmap_op(ic, ic->recalc_bitmap, dio->range.logical_sector,
+                                            dio->range.n_sectors, BITMAP_OP_TEST_ALL_CLEAR))
+                               goto skip_check;
+               }
+
                if (likely(!bio->bi_status))
                        integrity_metadata(&dio->work);
                else
@@ -1831,8 +2036,16 @@ static void pad_uncommitted(struct dm_integrity_c *ic)
                wraparound_section(ic, &ic->free_section);
                ic->n_uncommitted_sections++;
        }
-       WARN_ON(ic->journal_sections * ic->journal_section_entries !=
-               (ic->n_uncommitted_sections + ic->n_committed_sections) * ic->journal_section_entries + ic->free_sectors);
+       if (WARN_ON(ic->journal_sections * ic->journal_section_entries !=
+                   (ic->n_uncommitted_sections + ic->n_committed_sections) *
+                   ic->journal_section_entries + ic->free_sectors)) {
+               DMCRIT("journal_sections %u, journal_section_entries %u, "
+                      "n_uncommitted_sections %u, n_committed_sections %u, "
+                      "journal_section_entries %u, free_sectors %u",
+                      ic->journal_sections, ic->journal_section_entries,
+                      ic->n_uncommitted_sections, ic->n_committed_sections,
+                      ic->journal_section_entries, ic->free_sectors);
+       }
 }
 
 static void integrity_commit(struct work_struct *w)
@@ -1981,8 +2194,7 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start,
                        io->range.n_sectors = (k - j) << ic->sb->log2_sectors_per_block;
 
                        spin_lock_irq(&ic->endio_wait.lock);
-                       if (unlikely(!add_new_range(ic, &io->range, true)))
-                               wait_and_add_new_range(ic, &io->range);
+                       add_new_range_and_wait(ic, &io->range);
 
                        if (likely(!from_replay)) {
                                struct journal_node *section_node = &ic->journal_tree[i * ic->journal_section_entries];
@@ -2120,11 +2332,14 @@ static void integrity_recalc(struct work_struct *w)
        sector_t area, offset;
        sector_t metadata_block;
        unsigned metadata_offset;
+       sector_t logical_sector, n_sectors;
        __u8 *t;
        unsigned i;
        int r;
        unsigned super_counter = 0;
 
+       DEBUG_print("start recalculation... (position %llx)\n", le64_to_cpu(ic->sb->recalc_sector));
+
        spin_lock_irq(&ic->endio_wait.lock);
 
 next_chunk:
@@ -2133,21 +2348,49 @@ next_chunk:
                goto unlock_ret;
 
        range.logical_sector = le64_to_cpu(ic->sb->recalc_sector);
-       if (unlikely(range.logical_sector >= ic->provided_data_sectors))
+       if (unlikely(range.logical_sector >= ic->provided_data_sectors)) {
+               if (ic->mode == 'B') {
+                       DEBUG_print("queue_delayed_work: bitmap_flush_work\n");
+                       queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, 0);
+               }
                goto unlock_ret;
+       }
 
        get_area_and_offset(ic, range.logical_sector, &area, &offset);
        range.n_sectors = min((sector_t)RECALC_SECTORS, ic->provided_data_sectors - range.logical_sector);
        if (!ic->meta_dev)
-               range.n_sectors = min(range.n_sectors, (1U << ic->sb->log2_interleave_sectors) - (unsigned)offset);
-
-       if (unlikely(!add_new_range(ic, &range, true)))
-               wait_and_add_new_range(ic, &range);
+               range.n_sectors = min(range.n_sectors, ((sector_t)1U << ic->sb->log2_interleave_sectors) - (unsigned)offset);
 
+       add_new_range_and_wait(ic, &range);
        spin_unlock_irq(&ic->endio_wait.lock);
+       logical_sector = range.logical_sector;
+       n_sectors = range.n_sectors;
+
+       if (ic->mode == 'B') {
+               if (block_bitmap_op(ic, ic->recalc_bitmap, logical_sector, n_sectors, BITMAP_OP_TEST_ALL_CLEAR)) {
+                       goto advance_and_next;
+               }
+               while (block_bitmap_op(ic, ic->recalc_bitmap, logical_sector,
+                                      ic->sectors_per_block, BITMAP_OP_TEST_ALL_CLEAR)) {
+                       logical_sector += ic->sectors_per_block;
+                       n_sectors -= ic->sectors_per_block;
+                       cond_resched();
+               }
+               while (block_bitmap_op(ic, ic->recalc_bitmap, logical_sector + n_sectors - ic->sectors_per_block,
+                                      ic->sectors_per_block, BITMAP_OP_TEST_ALL_CLEAR)) {
+                       n_sectors -= ic->sectors_per_block;
+                       cond_resched();
+               }
+               get_area_and_offset(ic, logical_sector, &area, &offset);
+       }
+
+       DEBUG_print("recalculating: %lx, %lx\n", logical_sector, n_sectors);
 
        if (unlikely(++super_counter == RECALC_WRITE_SUPER)) {
                recalc_write_super(ic);
+               if (ic->mode == 'B') {
+                       queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, ic->bitmap_flush_interval);
+               }
                super_counter = 0;
        }
 
@@ -2162,7 +2405,7 @@ next_chunk:
        io_req.client = ic->io;
        io_loc.bdev = ic->dev->bdev;
        io_loc.sector = get_data_sector(ic, area, offset);
-       io_loc.count = range.n_sectors;
+       io_loc.count = n_sectors;
 
        r = dm_io(&io_req, 1, &io_loc, NULL);
        if (unlikely(r)) {
@@ -2171,8 +2414,8 @@ next_chunk:
        }
 
        t = ic->recalc_tags;
-       for (i = 0; i < range.n_sectors; i += ic->sectors_per_block) {
-               integrity_sector_checksum(ic, range.logical_sector + i, ic->recalc_buffer + (i << SECTOR_SHIFT), t);
+       for (i = 0; i < n_sectors; i += ic->sectors_per_block) {
+               integrity_sector_checksum(ic, logical_sector + i, ic->recalc_buffer + (i << SECTOR_SHIFT), t);
                t += ic->tag_size;
        }
 
@@ -2184,6 +2427,9 @@ next_chunk:
                goto err;
        }
 
+advance_and_next:
+       cond_resched();
+
        spin_lock_irq(&ic->endio_wait.lock);
        remove_range_unlocked(ic, &range);
        ic->sb->recalc_sector = cpu_to_le64(range.logical_sector + range.n_sectors);
@@ -2199,6 +2445,103 @@ unlock_ret:
        recalc_write_super(ic);
 }
 
+static void bitmap_block_work(struct work_struct *w)
+{
+       struct bitmap_block_status *bbs = container_of(w, struct bitmap_block_status, work);
+       struct dm_integrity_c *ic = bbs->ic;
+       struct bio *bio;
+       struct bio_list bio_queue;
+       struct bio_list waiting;
+
+       bio_list_init(&waiting);
+
+       spin_lock(&bbs->bio_queue_lock);
+       bio_queue = bbs->bio_queue;
+       bio_list_init(&bbs->bio_queue);
+       spin_unlock(&bbs->bio_queue_lock);
+
+       while ((bio = bio_list_pop(&bio_queue))) {
+               struct dm_integrity_io *dio;
+
+               dio = dm_per_bio_data(bio, sizeof(struct dm_integrity_io));
+
+               if (block_bitmap_op(ic, ic->may_write_bitmap, dio->range.logical_sector,
+                                   dio->range.n_sectors, BITMAP_OP_TEST_ALL_SET)) {
+                       remove_range(ic, &dio->range);
+                       INIT_WORK(&dio->work, integrity_bio_wait);
+                       queue_work(ic->wait_wq, &dio->work);
+               } else {
+                       block_bitmap_op(ic, ic->journal, dio->range.logical_sector,
+                                       dio->range.n_sectors, BITMAP_OP_SET);
+                       bio_list_add(&waiting, bio);
+               }
+       }
+
+       if (bio_list_empty(&waiting))
+               return;
+
+       rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC,
+                          bbs->idx * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT),
+                          BITMAP_BLOCK_SIZE >> SECTOR_SHIFT, NULL);
+
+       while ((bio = bio_list_pop(&waiting))) {
+               struct dm_integrity_io *dio = dm_per_bio_data(bio, sizeof(struct dm_integrity_io));
+
+               block_bitmap_op(ic, ic->may_write_bitmap, dio->range.logical_sector,
+                               dio->range.n_sectors, BITMAP_OP_SET);
+
+               remove_range(ic, &dio->range);
+               INIT_WORK(&dio->work, integrity_bio_wait);
+               queue_work(ic->wait_wq, &dio->work);
+       }
+
+       queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, ic->bitmap_flush_interval);
+}
+
+static void bitmap_flush_work(struct work_struct *work)
+{
+       struct dm_integrity_c *ic = container_of(work, struct dm_integrity_c, bitmap_flush_work.work);
+       struct dm_integrity_range range;
+       unsigned long limit;
+       struct bio *bio;
+
+       dm_integrity_flush_buffers(ic);
+
+       range.logical_sector = 0;
+       range.n_sectors = ic->provided_data_sectors;
+
+       spin_lock_irq(&ic->endio_wait.lock);
+       add_new_range_and_wait(ic, &range);
+       spin_unlock_irq(&ic->endio_wait.lock);
+
+       dm_integrity_flush_buffers(ic);
+       if (ic->meta_dev)
+               blkdev_issue_flush(ic->dev->bdev, GFP_NOIO, NULL);
+
+       limit = ic->provided_data_sectors;
+       if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) {
+               limit = le64_to_cpu(ic->sb->recalc_sector)
+                       >> (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit)
+                       << (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit);
+       }
+       /*DEBUG_print("zeroing journal\n");*/
+       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,
+                          ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
+
+       spin_lock_irq(&ic->endio_wait.lock);
+       remove_range_unlocked(ic, &range);
+       while (unlikely((bio = bio_list_pop(&ic->synchronous_bios)) != NULL)) {
+               bio_endio(bio);
+               spin_unlock_irq(&ic->endio_wait.lock);
+               spin_lock_irq(&ic->endio_wait.lock);
+       }
+       spin_unlock_irq(&ic->endio_wait.lock);
+}
+
+
 static void init_journal(struct dm_integrity_c *ic, unsigned start_section,
                         unsigned n_sections, unsigned char commit_seq)
 {
@@ -2395,9 +2738,37 @@ clear_journal:
                init_journal_node(&ic->journal_tree[i]);
 }
 
+static void dm_integrity_enter_synchronous_mode(struct dm_integrity_c *ic)
+{
+       DEBUG_print("dm_integrity_enter_synchronous_mode\n");
+
+       if (ic->mode == 'B') {
+               ic->bitmap_flush_interval = msecs_to_jiffies(10) + 1;
+               ic->synchronous_mode = 1;
+
+               cancel_delayed_work_sync(&ic->bitmap_flush_work);
+               queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, 0);
+               flush_workqueue(ic->commit_wq);
+       }
+}
+
+static int dm_integrity_reboot(struct notifier_block *n, unsigned long code, void *x)
+{
+       struct dm_integrity_c *ic = container_of(n, struct dm_integrity_c, reboot_notifier);
+
+       DEBUG_print("dm_integrity_reboot\n");
+
+       dm_integrity_enter_synchronous_mode(ic);
+
+       return NOTIFY_DONE;
+}
+
 static void dm_integrity_postsuspend(struct dm_target *ti)
 {
        struct dm_integrity_c *ic = (struct dm_integrity_c *)ti->private;
+       int r;
+
+       WARN_ON(unregister_reboot_notifier(&ic->reboot_notifier));
 
        del_timer_sync(&ic->autocommit_timer);
 
@@ -2406,6 +2777,9 @@ static void dm_integrity_postsuspend(struct dm_target *ti)
        if (ic->recalc_wq)
                drain_workqueue(ic->recalc_wq);
 
+       if (ic->mode == 'B')
+               cancel_delayed_work_sync(&ic->bitmap_flush_work);
+
        queue_work(ic->commit_wq, &ic->commit_work);
        drain_workqueue(ic->commit_wq);
 
@@ -2416,6 +2790,18 @@ static void dm_integrity_postsuspend(struct dm_target *ti)
                dm_integrity_flush_buffers(ic);
        }
 
+       if (ic->mode == 'B') {
+               dm_integrity_flush_buffers(ic);
+#if 1
+               /* 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);
+               if (unlikely(r))
+                       dm_integrity_io_error(ic, "writing superblock", r);
+#endif
+       }
+
        WRITE_ONCE(ic->suspending, 0);
 
        BUG_ON(!RB_EMPTY_ROOT(&ic->in_progress));
@@ -2426,11 +2812,70 @@ static void dm_integrity_postsuspend(struct dm_target *ti)
 static void dm_integrity_resume(struct dm_target *ti)
 {
        struct dm_integrity_c *ic = (struct dm_integrity_c *)ti->private;
+       int r;
+       DEBUG_print("resume\n");
+
+       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,
+                                  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) {
+                               block_bitmap_copy(ic, ic->recalc_bitmap, ic->journal);
+                               block_bitmap_copy(ic, ic->may_write_bitmap, ic->journal);
+                               if (!block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors,
+                                                    BITMAP_OP_TEST_ALL_CLEAR)) {
+                                       ic->sb->flags |= cpu_to_le32(SB_FLAG_RECALCULATING);
+                                       ic->sb->recalc_sector = cpu_to_le64(0);
+                               }
+                       } else {
+                               DEBUG_print("non-matching blocks_per_bitmap_bit: %u, %u\n",
+                                           ic->sb->log2_blocks_per_bitmap_bit, ic->log2_blocks_per_bitmap_bit);
+                               ic->sb->log2_blocks_per_bitmap_bit = ic->log2_blocks_per_bitmap_bit;
+                               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,
+                                                  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);
+                       }
+               } else {
+                       if (!(ic->sb->log2_blocks_per_bitmap_bit == ic->log2_blocks_per_bitmap_bit &&
+                             block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_TEST_ALL_CLEAR))) {
+                               ic->sb->flags |= cpu_to_le32(SB_FLAG_RECALCULATING);
+                               ic->sb->recalc_sector = cpu_to_le64(0);
+                       }
+                       init_journal(ic, 0, ic->journal_sections, 0);
+                       replay_journal(ic);
+                       ic->sb->flags &= ~cpu_to_le32(SB_FLAG_DIRTY_BITMAP);
+               }
+               r = sync_rw_sb(ic, REQ_OP_WRITE, REQ_FUA);
+               if (unlikely(r))
+                       dm_integrity_io_error(ic, "writing superblock", r);
+       } else {
+               replay_journal(ic);
+               if (ic->mode == 'B') {
+                       int mode;
+                       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);
+                       if (unlikely(r))
+                               dm_integrity_io_error(ic, "writing superblock", r);
+
+                       mode = ic->recalculate_flag ? BITMAP_OP_SET : BITMAP_OP_CLEAR;
+                       block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, mode);
+                       block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, mode);
+                       block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, mode);
+                       rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC, 0,
+                                          ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
+               }
+       }
 
-       replay_journal(ic);
-
-       if (ic->recalc_wq && ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) {
+       DEBUG_print("testing recalc: %x\n", ic->sb->flags);
+       if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) {
                __u64 recalc_pos = le64_to_cpu(ic->sb->recalc_sector);
+               DEBUG_print("recalc pos: %lx / %lx\n", (long)recalc_pos, ic->provided_data_sectors);
                if (recalc_pos < ic->provided_data_sectors) {
                        queue_work(ic->recalc_wq, &ic->recalc_work);
                } else if (recalc_pos > ic->provided_data_sectors) {
@@ -2438,6 +2883,16 @@ static void dm_integrity_resume(struct dm_target *ti)
                        recalc_write_super(ic);
                }
        }
+
+       ic->reboot_notifier.notifier_call = dm_integrity_reboot;
+       ic->reboot_notifier.next = NULL;
+       ic->reboot_notifier.priority = INT_MAX - 1;     /* be notified after md and before hardware drivers */
+       WARN_ON(register_reboot_notifier(&ic->reboot_notifier));
+
+#if 0
+       /* set to 1 to stress test synchronous mode */
+       dm_integrity_enter_synchronous_mode(ic);
+#endif
 }
 
 static void dm_integrity_status(struct dm_target *ti, status_type_t type,
@@ -2462,10 +2917,14 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
                __u64 watermark_percentage = (__u64)(ic->journal_entries - ic->free_sectors_threshold) * 100;
                watermark_percentage += ic->journal_entries / 2;
                do_div(watermark_percentage, ic->journal_entries);
-               arg_count = 5;
+               arg_count = 3;
                arg_count += !!ic->meta_dev;
                arg_count += ic->sectors_per_block != 1;
                arg_count += !!(ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING));
+               arg_count += ic->mode == 'J';
+               arg_count += ic->mode == 'J';
+               arg_count += ic->mode == 'B';
+               arg_count += ic->mode == 'B';
                arg_count += !!ic->internal_hash_alg.alg_string;
                arg_count += !!ic->journal_crypt_alg.alg_string;
                arg_count += !!ic->journal_mac_alg.alg_string;
@@ -2475,13 +2934,19 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
                        DMEMIT(" meta_device:%s", ic->meta_dev->name);
                if (ic->sectors_per_block != 1)
                        DMEMIT(" block_size:%u", ic->sectors_per_block << SECTOR_SHIFT);
-               if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING))
+               if (ic->recalculate_flag)
                        DMEMIT(" recalculate");
                DMEMIT(" journal_sectors:%u", ic->initial_sectors - SB_SECTORS);
                DMEMIT(" interleave_sectors:%u", 1U << ic->sb->log2_interleave_sectors);
                DMEMIT(" buffer_sectors:%u", 1U << ic->log2_buffer_sectors);
-               DMEMIT(" journal_watermark:%u", (unsigned)watermark_percentage);
-               DMEMIT(" commit_time:%u", ic->autocommit_msec);
+               if (ic->mode == 'J') {
+                       DMEMIT(" journal_watermark:%u", (unsigned)watermark_percentage);
+                       DMEMIT(" commit_time:%u", ic->autocommit_msec);
+               }
+               if (ic->mode == 'B') {
+                       DMEMIT(" sectors_per_bit:%llu", (unsigned long long)ic->sectors_per_block << ic->log2_blocks_per_bitmap_bit);
+                       DMEMIT(" bitmap_flush_interval:%u", jiffies_to_msecs(ic->bitmap_flush_interval));
+               }
 
 #define EMIT_ALG(a, n)                                                 \
                do {                                                    \
@@ -2562,7 +3027,7 @@ static int calculate_device_limits(struct dm_integrity_c *ic)
                if (last_sector < ic->start || last_sector >= ic->meta_device_sectors)
                        return -EINVAL;
        } else {
-               __u64 meta_size = ic->provided_data_sectors * ic->tag_size;
+               __u64 meta_size = (ic->provided_data_sectors >> ic->sb->log2_sectors_per_block) * ic->tag_size;
                meta_size = (meta_size + ((1U << (ic->log2_buffer_sectors + SECTOR_SHIFT)) - 1))
                                >> (ic->log2_buffer_sectors + SECTOR_SHIFT);
                meta_size <<= ic->log2_buffer_sectors;
@@ -2659,37 +3124,37 @@ static void dm_integrity_set(struct dm_target *ti, struct dm_integrity_c *ic)
        blk_queue_max_integrity_segments(disk->queue, UINT_MAX);
 }
 
-static void dm_integrity_free_page_list(struct dm_integrity_c *ic, struct page_list *pl)
+static void dm_integrity_free_page_list(struct page_list *pl)
 {
        unsigned i;
 
        if (!pl)
                return;
-       for (i = 0; i < ic->journal_pages; i++)
-               if (pl[i].page)
-                       __free_page(pl[i].page);
+       for (i = 0; pl[i].page; i++)
+               __free_page(pl[i].page);
        kvfree(pl);
 }
 
-static struct page_list *dm_integrity_alloc_page_list(struct dm_integrity_c *ic)
+static struct page_list *dm_integrity_alloc_page_list(unsigned n_pages)
 {
-       size_t page_list_desc_size = ic->journal_pages * sizeof(struct page_list);
        struct page_list *pl;
        unsigned i;
 
-       pl = kvmalloc(page_list_desc_size, GFP_KERNEL | __GFP_ZERO);
+       pl = kvmalloc_array(n_pages + 1, sizeof(struct page_list), GFP_KERNEL | __GFP_ZERO);
        if (!pl)
                return NULL;
 
-       for (i = 0; i < ic->journal_pages; i++) {
+       for (i = 0; i < n_pages; i++) {
                pl[i].page = alloc_page(GFP_KERNEL);
                if (!pl[i].page) {
-                       dm_integrity_free_page_list(ic, pl);
+                       dm_integrity_free_page_list(pl);
                        return NULL;
                }
                if (i)
                        pl[i - 1].next = &pl[i];
        }
+       pl[i].page = NULL;
+       pl[i].next = NULL;
 
        return pl;
 }
@@ -2702,7 +3167,8 @@ static void dm_integrity_free_journal_scatterlist(struct dm_integrity_c *ic, str
        kvfree(sl);
 }
 
-static struct scatterlist **dm_integrity_alloc_journal_scatterlist(struct dm_integrity_c *ic, struct page_list *pl)
+static struct scatterlist **dm_integrity_alloc_journal_scatterlist(struct dm_integrity_c *ic,
+                                                                  struct page_list *pl)
 {
        struct scatterlist **sl;
        unsigned i;
@@ -2721,7 +3187,8 @@ static struct scatterlist **dm_integrity_alloc_journal_scatterlist(struct dm_int
                unsigned idx;
 
                page_list_location(ic, i, 0, &start_index, &start_offset);
-               page_list_location(ic, i, ic->journal_section_sectors - 1, &end_index, &end_offset);
+               page_list_location(ic, i, ic->journal_section_sectors - 1,
+                                  &end_index, &end_offset);
 
                n_pages = (end_index - start_index + 1);
 
@@ -2842,7 +3309,7 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
        }
        ic->journal_pages = journal_pages;
 
-       ic->journal = dm_integrity_alloc_page_list(ic);
+       ic->journal = dm_integrity_alloc_page_list(ic->journal_pages);
        if (!ic->journal) {
                *error = "Could not allocate memory for journal";
                r = -ENOMEM;
@@ -2874,7 +3341,7 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
                DEBUG_print("cipher %s, block size %u iv size %u\n",
                            ic->journal_crypt_alg.alg_string, blocksize, ivsize);
 
-               ic->journal_io = dm_integrity_alloc_page_list(ic);
+               ic->journal_io = dm_integrity_alloc_page_list(ic->journal_pages);
                if (!ic->journal_io) {
                        *error = "Could not allocate memory for journal io";
                        r = -ENOMEM;
@@ -2898,7 +3365,7 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
                                goto bad;
                        }
 
-                       ic->journal_xor = dm_integrity_alloc_page_list(ic);
+                       ic->journal_xor = dm_integrity_alloc_page_list(ic->journal_pages);
                        if (!ic->journal_xor) {
                                *error = "Could not allocate memory for journal xor";
                                r = -ENOMEM;
@@ -2922,7 +3389,8 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
                        sg_set_buf(&sg[i], &ic->commit_ids, sizeof ic->commit_ids);
                        memset(crypt_iv, 0x00, ivsize);
 
-                       skcipher_request_set_crypt(req, sg, sg, PAGE_SIZE * ic->journal_pages + sizeof ic->commit_ids, crypt_iv);
+                       skcipher_request_set_crypt(req, sg, sg,
+                                                  PAGE_SIZE * ic->journal_pages + sizeof ic->commit_ids, crypt_iv);
                        init_completion(&comp.comp);
                        comp.in_flight = (atomic_t)ATOMIC_INIT(1);
                        if (do_crypt(true, req, &comp))
@@ -3063,7 +3531,7 @@ bad:
  *     device
  *     offset from the start of the device
  *     tag size
- *     D - direct writes, J - journal writes, R - recovery mode
+ *     D - direct writes, J - journal writes, B - bitmap mode, R - recovery mode
  *     number of optional arguments
  *     optional arguments:
  *             journal_sectors
@@ -3071,10 +3539,14 @@ bad:
  *             buffer_sectors
  *             journal_watermark
  *             commit_time
+ *             meta_device
+ *             block_size
+ *             sectors_per_bit
+ *             bitmap_flush_interval
  *             internal_hash
  *             journal_crypt
  *             journal_mac
- *             block_size
+ *             recalculate
  */
 static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
 {
@@ -3087,10 +3559,13 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                {0, 9, "Invalid number of feature args"},
        };
        unsigned journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec;
-       bool recalculate;
        bool should_write_sb;
        __u64 threshold;
        unsigned long long start;
+       __s8 log2_sectors_per_bitmap_bit = -1;
+       __s8 log2_blocks_per_bitmap_bit;
+       __u64 bits_in_journal;
+       __u64 n_bitmap_bits;
 
 #define DIRECT_ARGUMENTS       4
 
@@ -3114,6 +3589,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
        init_waitqueue_head(&ic->copy_to_journal_wait);
        init_completion(&ic->crypto_backoff);
        atomic64_set(&ic->number_of_mismatches, 0);
+       ic->bitmap_flush_interval = BITMAP_FLUSH_INTERVAL;
 
        r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &ic->dev);
        if (r) {
@@ -3136,10 +3612,11 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                }
        }
 
-       if (!strcmp(argv[3], "J") || !strcmp(argv[3], "D") || !strcmp(argv[3], "R"))
+       if (!strcmp(argv[3], "J") || !strcmp(argv[3], "B") ||
+           !strcmp(argv[3], "D") || !strcmp(argv[3], "R")) {
                ic->mode = argv[3][0];
-       else {
-               ti->error = "Invalid mode (expecting J, D, R)";
+       else {
+               ti->error = "Invalid mode (expecting J, B, D, R)";
                r = -EINVAL;
                goto bad;
        }
@@ -3149,7 +3626,6 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
        buffer_sectors = DEFAULT_BUFFER_SECTORS;
        journal_watermark = DEFAULT_JOURNAL_WATERMARK;
        sync_msec = DEFAULT_SYNC_MSEC;
-       recalculate = false;
        ic->sectors_per_block = 1;
 
        as.argc = argc - DIRECT_ARGUMENTS;
@@ -3161,6 +3637,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
        while (extra_args--) {
                const char *opt_string;
                unsigned val;
+               unsigned long long llval;
                opt_string = dm_shift_arg(&as);
                if (!opt_string) {
                        r = -EINVAL;
@@ -3182,7 +3659,8 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                                dm_put_device(ti, ic->meta_dev);
                                ic->meta_dev = NULL;
                        }
-                       r = dm_get_device(ti, strchr(opt_string, ':') + 1, dm_table_get_mode(ti->table), &ic->meta_dev);
+                       r = dm_get_device(ti, strchr(opt_string, ':') + 1,
+                                         dm_table_get_mode(ti->table), &ic->meta_dev);
                        if (r) {
                                ti->error = "Device lookup failed";
                                goto bad;
@@ -3196,6 +3674,14 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                                goto bad;
                        }
                        ic->sectors_per_block = val >> SECTOR_SHIFT;
+               } else if (sscanf(opt_string, "sectors_per_bit:%llu%c", &llval, &dummy) == 1) {
+                       log2_sectors_per_bitmap_bit = !llval ? 0 : __ilog2_u64(llval);
+               } else if (sscanf(opt_string, "bitmap_flush_interval:%u%c", &val, &dummy) == 1) {
+                       if (val >= (uint64_t)UINT_MAX * 1000 / HZ) {
+                               r = -EINVAL;
+                               ti->error = "Invalid bitmap_flush_interval argument";
+                       }
+                       ic->bitmap_flush_interval = msecs_to_jiffies(val);
                } else if (!strncmp(opt_string, "internal_hash:", strlen("internal_hash:"))) {
                        r = get_alg_and_key(opt_string, &ic->internal_hash_alg, &ti->error,
                                            "Invalid internal_hash argument");
@@ -3212,7 +3698,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                        if (r)
                                goto bad;
                } else if (!strcmp(opt_string, "recalculate")) {
-                       recalculate = true;
+                       ic->recalculate_flag = true;
                } else {
                        r = -EINVAL;
                        ti->error = "Invalid argument";
@@ -3228,7 +3714,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        if (!journal_sectors) {
                journal_sectors = min((sector_t)DEFAULT_MAX_JOURNAL_SECTORS,
-                       ic->data_device_sectors >> DEFAULT_JOURNAL_SIZE_FACTOR);
+                                     ic->data_device_sectors >> DEFAULT_JOURNAL_SIZE_FACTOR);
        }
 
        if (!buffer_sectors)
@@ -3263,6 +3749,12 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
        else
                ic->log2_tag_size = -1;
 
+       if (ic->mode == 'B' && !ic->internal_hash) {
+               r = -EINVAL;
+               ti->error = "Bitmap mode can be only used with internal hash";
+               goto bad;
+       }
+
        ic->autocommit_jiffies = msecs_to_jiffies(sync_msec);
        ic->autocommit_msec = sync_msec;
        timer_setup(&ic->autocommit_timer, autocommit_fn, 0);
@@ -3308,7 +3800,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
        }
        INIT_WORK(&ic->commit_work, integrity_commit);
 
-       if (ic->mode == 'J') {
+       if (ic->mode == 'J' || ic->mode == 'B') {
                ic->writer_wq = alloc_workqueue("dm-integrity-writer", WQ_MEM_RECLAIM, 1);
                if (!ic->writer_wq) {
                        ti->error = "Cannot allocate workqueue";
@@ -3349,7 +3841,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                        should_write_sb = true;
        }
 
-       if (!ic->sb->version || ic->sb->version > SB_VERSION_2) {
+       if (!ic->sb->version || ic->sb->version > SB_VERSION_3) {
                r = -EINVAL;
                ti->error = "Unknown version";
                goto bad;
@@ -3409,6 +3901,27 @@ try_smaller_buffer:
                ti->error = "The device is too small";
                goto bad;
        }
+
+       if (log2_sectors_per_bitmap_bit < 0)
+               log2_sectors_per_bitmap_bit = __fls(DEFAULT_SECTORS_PER_BITMAP_BIT);
+       if (log2_sectors_per_bitmap_bit < ic->sb->log2_sectors_per_block)
+               log2_sectors_per_bitmap_bit = ic->sb->log2_sectors_per_block;
+
+       bits_in_journal = ((__u64)ic->journal_section_sectors * ic->journal_sections) << (SECTOR_SHIFT + 3);
+       if (bits_in_journal > UINT_MAX)
+               bits_in_journal = UINT_MAX;
+       while (bits_in_journal < (ic->provided_data_sectors + ((sector_t)1 << log2_sectors_per_bitmap_bit) - 1) >> log2_sectors_per_bitmap_bit)
+               log2_sectors_per_bitmap_bit++;
+
+       log2_blocks_per_bitmap_bit = log2_sectors_per_bitmap_bit - ic->sb->log2_sectors_per_block;
+       ic->log2_blocks_per_bitmap_bit = log2_blocks_per_bitmap_bit;
+       if (should_write_sb) {
+               ic->sb->log2_blocks_per_bitmap_bit = log2_blocks_per_bitmap_bit;
+       }
+       n_bitmap_bits = ((ic->provided_data_sectors >> ic->sb->log2_sectors_per_block)
+                               + (((sector_t)1 << log2_blocks_per_bitmap_bit) - 1)) >> log2_blocks_per_bitmap_bit;
+       ic->n_bitmap_blocks = DIV_ROUND_UP(n_bitmap_bits, BITMAP_BLOCK_SIZE * 8);
+
        if (!ic->meta_dev)
                ic->log2_buffer_sectors = min(ic->log2_buffer_sectors, (__u8)__ffs(ic->metadata_run));
 
@@ -3433,25 +3946,21 @@ try_smaller_buffer:
        DEBUG_print("   journal_sections %u\n", (unsigned)le32_to_cpu(ic->sb->journal_sections));
        DEBUG_print("   journal_entries %u\n", ic->journal_entries);
        DEBUG_print("   log2_interleave_sectors %d\n", ic->sb->log2_interleave_sectors);
-       DEBUG_print("   device_sectors 0x%llx\n", (unsigned long long)ic->device_sectors);
+       DEBUG_print("   data_device_sectors 0x%llx\n", i_size_read(ic->dev->bdev->bd_inode) >> SECTOR_SHIFT);
        DEBUG_print("   initial_sectors 0x%x\n", ic->initial_sectors);
        DEBUG_print("   metadata_run 0x%x\n", ic->metadata_run);
        DEBUG_print("   log2_metadata_run %d\n", ic->log2_metadata_run);
        DEBUG_print("   provided_data_sectors 0x%llx (%llu)\n", (unsigned long long)ic->provided_data_sectors,
                    (unsigned long long)ic->provided_data_sectors);
        DEBUG_print("   log2_buffer_sectors %u\n", ic->log2_buffer_sectors);
+       DEBUG_print("   bits_in_journal %llu\n", (unsigned long long)bits_in_journal);
 
-       if (recalculate && !(ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING))) {
+       if (ic->recalculate_flag && !(ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING))) {
                ic->sb->flags |= cpu_to_le32(SB_FLAG_RECALCULATING);
                ic->sb->recalc_sector = cpu_to_le64(0);
        }
 
-       if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) {
-               if (!ic->internal_hash) {
-                       r = -EINVAL;
-                       ti->error = "Recalculate is only valid with internal hash";
-                       goto bad;
-               }
+       if (ic->internal_hash) {
                ic->recalc_wq = alloc_workqueue("dm-integrity-recalc", WQ_MEM_RECLAIM, 1);
                if (!ic->recalc_wq ) {
                        ti->error = "Cannot allocate workqueue";
@@ -3488,6 +3997,45 @@ try_smaller_buffer:
                r = create_journal(ic, &ti->error);
                if (r)
                        goto bad;
+
+       }
+
+       if (ic->mode == 'B') {
+               unsigned i;
+               unsigned n_bitmap_pages = DIV_ROUND_UP(ic->n_bitmap_blocks, PAGE_SIZE / BITMAP_BLOCK_SIZE);
+
+               ic->recalc_bitmap = dm_integrity_alloc_page_list(n_bitmap_pages);
+               if (!ic->recalc_bitmap) {
+                       r = -ENOMEM;
+                       goto bad;
+               }
+               ic->may_write_bitmap = dm_integrity_alloc_page_list(n_bitmap_pages);
+               if (!ic->may_write_bitmap) {
+                       r = -ENOMEM;
+                       goto bad;
+               }
+               ic->bbs = kvmalloc_array(ic->n_bitmap_blocks, sizeof(struct bitmap_block_status), GFP_KERNEL);
+               if (!ic->bbs) {
+                       r = -ENOMEM;
+                       goto bad;
+               }
+               INIT_DELAYED_WORK(&ic->bitmap_flush_work, bitmap_flush_work);
+               for (i = 0; i < ic->n_bitmap_blocks; i++) {
+                       struct bitmap_block_status *bbs = &ic->bbs[i];
+                       unsigned sector, pl_index, pl_offset;
+
+                       INIT_WORK(&bbs->work, bitmap_block_work);
+                       bbs->ic = ic;
+                       bbs->idx = i;
+                       bio_list_init(&bbs->bio_queue);
+                       spin_lock_init(&bbs->bio_queue_lock);
+
+                       sector = i * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT);
+                       pl_index = sector >> (PAGE_SHIFT - SECTOR_SHIFT);
+                       pl_offset = (sector << SECTOR_SHIFT) & (PAGE_SIZE - 1);
+
+                       bbs->bitmap = lowmem_page_address(ic->journal[pl_index].page) + pl_offset;
+               }
        }
 
        if (should_write_sb) {
@@ -3512,6 +4060,17 @@ try_smaller_buffer:
                if (r)
                        goto bad;
        }
+       if (ic->mode == 'B') {
+               unsigned max_io_len = ((sector_t)ic->sectors_per_block << ic->log2_blocks_per_bitmap_bit) * (BITMAP_BLOCK_SIZE * 8);
+               if (!max_io_len)
+                       max_io_len = 1U << 31;
+               DEBUG_print("max_io_len: old %u, new %u\n", ti->max_io_len, max_io_len);
+               if (!ti->max_io_len || ti->max_io_len > max_io_len) {
+                       r = dm_set_target_max_io_len(ti, max_io_len);
+                       if (r)
+                               goto bad;
+               }
+       }
 
        if (!ic->internal_hash)
                dm_integrity_set(ti, ic);
@@ -3520,6 +4079,7 @@ try_smaller_buffer:
        ti->flush_supported = true;
 
        return 0;
+
 bad:
        dm_integrity_dtr(ti);
        return r;
@@ -3542,10 +4102,9 @@ static void dm_integrity_dtr(struct dm_target *ti)
                destroy_workqueue(ic->writer_wq);
        if (ic->recalc_wq)
                destroy_workqueue(ic->recalc_wq);
-       if (ic->recalc_buffer)
-               vfree(ic->recalc_buffer);
-       if (ic->recalc_tags)
-               kvfree(ic->recalc_tags);
+       vfree(ic->recalc_buffer);
+       kvfree(ic->recalc_tags);
+       kvfree(ic->bbs);
        if (ic->bufio)
                dm_bufio_client_destroy(ic->bufio);
        mempool_exit(&ic->journal_io_mempool);
@@ -3555,9 +4114,11 @@ static void dm_integrity_dtr(struct dm_target *ti)
                dm_put_device(ti, ic->dev);
        if (ic->meta_dev)
                dm_put_device(ti, ic->meta_dev);
-       dm_integrity_free_page_list(ic, ic->journal);
-       dm_integrity_free_page_list(ic, ic->journal_io);
-       dm_integrity_free_page_list(ic, ic->journal_xor);
+       dm_integrity_free_page_list(ic->journal);
+       dm_integrity_free_page_list(ic->journal_io);
+       dm_integrity_free_page_list(ic->journal_xor);
+       dm_integrity_free_page_list(ic->recalc_bitmap);
+       dm_integrity_free_page_list(ic->may_write_bitmap);
        if (ic->journal_scatterlist)
                dm_integrity_free_journal_scatterlist(ic, ic->journal_scatterlist);
        if (ic->journal_io_scatterlist)
@@ -3595,7 +4156,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
 
 static struct target_type integrity_target = {
        .name                   = "integrity",
-       .version                = {1, 2, 0},
+       .version                = {1, 3, 0},
        .module                 = THIS_MODULE,
        .features               = DM_TARGET_SINGLETON | DM_TARGET_INTEGRITY,
        .ctr                    = dm_integrity_ctr,
index c740153b4e52df15ee7b4cab6c9b1e83d897143f..1e03bc89e20f68ce25c7e0c60e178c1985cec8bf 100644 (file)
@@ -2069,7 +2069,7 @@ int __init dm_early_create(struct dm_ioctl *dmi,
        /* alloc table */
        r = dm_table_create(&t, get_mode(dmi), dmi->target_count, md);
        if (r)
-               goto err_destroy_dm;
+               goto err_hash_remove;
 
        /* add targets */
        for (i = 0; i < dmi->target_count; i++) {
@@ -2116,6 +2116,10 @@ int __init dm_early_create(struct dm_ioctl *dmi,
 
 err_destroy_table:
        dm_table_destroy(t);
+err_hash_remove:
+       (void) __hash_remove(__get_name_cell(dmi->name));
+       /* release reference from __get_name_cell */
+       dm_put(md);
 err_destroy_dm:
        dm_put(md);
        dm_destroy(md);
index 2ee5e357a0a717acf94defdd4fa335a0a49d14b1..dbcc1e41cd57dd5a669466a6907a70f78a16014f 100644 (file)
@@ -544,8 +544,23 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq,
        return DM_MAPIO_REMAPPED;
 }
 
-static void multipath_release_clone(struct request *clone)
+static void multipath_release_clone(struct request *clone,
+                                   union map_info *map_context)
 {
+       if (unlikely(map_context)) {
+               /*
+                * non-NULL map_context means caller is still map
+                * method; must undo multipath_clone_and_map()
+                */
+               struct dm_mpath_io *mpio = get_mpio(map_context);
+               struct pgpath *pgpath = mpio->pgpath;
+
+               if (pgpath && pgpath->pg->ps.type->end_io)
+                       pgpath->pg->ps.type->end_io(&pgpath->pg->ps,
+                                                   &pgpath->path,
+                                                   mpio->nr_bytes);
+       }
+
        blk_put_request(clone);
 }
 
@@ -882,6 +897,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
        if (attached_handler_name || m->hw_handler_name) {
                INIT_DELAYED_WORK(&p->activate_path, activate_path_work);
                r = setup_scsi_dh(p->path.dev->bdev, m, &attached_handler_name, &ti->error);
+               kfree(attached_handler_name);
                if (r) {
                        dm_put_device(ti, p->path.dev);
                        goto bad;
@@ -896,7 +912,6 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
 
        return p;
  bad:
-       kfree(attached_handler_name);
        free_pgpath(p);
        return ERR_PTR(r);
 }
index b66745bd08bbcc2dd1ab349f47c7326199518778..5f7063f05ae0771e3a8ebaaf697da58b9d4308d5 100644 (file)
@@ -168,7 +168,7 @@ static void dm_end_request(struct request *clone, blk_status_t error)
        struct request *rq = tio->orig;
 
        blk_rq_unprep_clone(clone);
-       tio->ti->type->release_clone_rq(clone);
+       tio->ti->type->release_clone_rq(clone, NULL);
 
        rq_end_stats(md, rq);
        blk_mq_end_request(rq, error);
@@ -201,7 +201,7 @@ static void dm_requeue_original_request(struct dm_rq_target_io *tio, bool delay_
        rq_end_stats(md, rq);
        if (tio->clone) {
                blk_rq_unprep_clone(tio->clone);
-               tio->ti->type->release_clone_rq(tio->clone);
+               tio->ti->type->release_clone_rq(tio->clone, NULL);
        }
 
        dm_mq_delay_requeue_request(rq, delay_ms);
@@ -398,7 +398,7 @@ static int map_request(struct dm_rq_target_io *tio)
        case DM_MAPIO_REMAPPED:
                if (setup_clone(clone, rq, tio, GFP_ATOMIC)) {
                        /* -ENOMEM */
-                       ti->type->release_clone_rq(clone);
+                       ti->type->release_clone_rq(clone, &tio->info);
                        return DM_MAPIO_REQUEUE;
                }
 
@@ -408,7 +408,7 @@ static int map_request(struct dm_rq_target_io *tio)
                ret = dm_dispatch_clone_request(clone, rq);
                if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE) {
                        blk_rq_unprep_clone(clone);
-                       tio->ti->type->release_clone_rq(clone);
+                       tio->ti->type->release_clone_rq(clone, &tio->info);
                        tio->clone = NULL;
                        return DM_MAPIO_REQUEUE;
                }
index a168963b757df4fe12c885c48456a50d586851fe..3107f2b1988b35f3b22f8324becb48bdffe3bc13 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/kdev_t.h>
 #include <linux/list.h>
+#include <linux/list_bl.h>
 #include <linux/mempool.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -44,11 +45,11 @@ static const char dm_snapshot_merge_target_name[] = "snapshot-merge";
 struct dm_exception_table {
        uint32_t hash_mask;
        unsigned hash_shift;
-       struct list_head *table;
+       struct hlist_bl_head *table;
 };
 
 struct dm_snapshot {
-       struct mutex lock;
+       struct rw_semaphore lock;
 
        struct dm_dev *origin;
        struct dm_dev *cow;
@@ -76,7 +77,9 @@ struct dm_snapshot {
 
        atomic_t pending_exceptions_count;
 
-       /* Protected by "lock" */
+       spinlock_t pe_allocation_lock;
+
+       /* Protected by "pe_allocation_lock" */
        sector_t exception_start_sequence;
 
        /* Protected by kcopyd single-threaded callback */
@@ -457,9 +460,9 @@ static int __find_snapshots_sharing_cow(struct dm_snapshot *snap,
                if (!bdev_equal(s->cow->bdev, snap->cow->bdev))
                        continue;
 
-               mutex_lock(&s->lock);
+               down_read(&s->lock);
                active = s->active;
-               mutex_unlock(&s->lock);
+               up_read(&s->lock);
 
                if (active) {
                        if (snap_src)
@@ -618,6 +621,36 @@ static void unregister_snapshot(struct dm_snapshot *s)
  * The lowest hash_shift bits of the chunk number are ignored, allowing
  * some consecutive chunks to be grouped together.
  */
+static uint32_t exception_hash(struct dm_exception_table *et, chunk_t chunk);
+
+/* Lock to protect access to the completed and pending exception hash tables. */
+struct dm_exception_table_lock {
+       struct hlist_bl_head *complete_slot;
+       struct hlist_bl_head *pending_slot;
+};
+
+static void dm_exception_table_lock_init(struct dm_snapshot *s, chunk_t chunk,
+                                        struct dm_exception_table_lock *lock)
+{
+       struct dm_exception_table *complete = &s->complete;
+       struct dm_exception_table *pending = &s->pending;
+
+       lock->complete_slot = &complete->table[exception_hash(complete, chunk)];
+       lock->pending_slot = &pending->table[exception_hash(pending, chunk)];
+}
+
+static void dm_exception_table_lock(struct dm_exception_table_lock *lock)
+{
+       hlist_bl_lock(lock->complete_slot);
+       hlist_bl_lock(lock->pending_slot);
+}
+
+static void dm_exception_table_unlock(struct dm_exception_table_lock *lock)
+{
+       hlist_bl_unlock(lock->pending_slot);
+       hlist_bl_unlock(lock->complete_slot);
+}
+
 static int dm_exception_table_init(struct dm_exception_table *et,
                                   uint32_t size, unsigned hash_shift)
 {
@@ -625,12 +658,12 @@ static int dm_exception_table_init(struct dm_exception_table *et,
 
        et->hash_shift = hash_shift;
        et->hash_mask = size - 1;
-       et->table = dm_vcalloc(size, sizeof(struct list_head));
+       et->table = dm_vcalloc(size, sizeof(struct hlist_bl_head));
        if (!et->table)
                return -ENOMEM;
 
        for (i = 0; i < size; i++)
-               INIT_LIST_HEAD(et->table + i);
+               INIT_HLIST_BL_HEAD(et->table + i);
 
        return 0;
 }
@@ -638,15 +671,16 @@ static int dm_exception_table_init(struct dm_exception_table *et,
 static void dm_exception_table_exit(struct dm_exception_table *et,
                                    struct kmem_cache *mem)
 {
-       struct list_head *slot;
-       struct dm_exception *ex, *next;
+       struct hlist_bl_head *slot;
+       struct dm_exception *ex;
+       struct hlist_bl_node *pos, *n;
        int i, size;
 
        size = et->hash_mask + 1;
        for (i = 0; i < size; i++) {
                slot = et->table + i;
 
-               list_for_each_entry_safe (ex, next, slot, hash_list)
+               hlist_bl_for_each_entry_safe(ex, pos, n, slot, hash_list)
                        kmem_cache_free(mem, ex);
        }
 
@@ -660,7 +694,7 @@ static uint32_t exception_hash(struct dm_exception_table *et, chunk_t chunk)
 
 static void dm_remove_exception(struct dm_exception *e)
 {
-       list_del(&e->hash_list);
+       hlist_bl_del(&e->hash_list);
 }
 
 /*
@@ -670,11 +704,12 @@ static void dm_remove_exception(struct dm_exception *e)
 static struct dm_exception *dm_lookup_exception(struct dm_exception_table *et,
                                                chunk_t chunk)
 {
-       struct list_head *slot;
+       struct hlist_bl_head *slot;
+       struct hlist_bl_node *pos;
        struct dm_exception *e;
 
        slot = &et->table[exception_hash(et, chunk)];
-       list_for_each_entry (e, slot, hash_list)
+       hlist_bl_for_each_entry(e, pos, slot, hash_list)
                if (chunk >= e->old_chunk &&
                    chunk <= e->old_chunk + dm_consecutive_chunk_count(e))
                        return e;
@@ -721,7 +756,8 @@ static void free_pending_exception(struct dm_snap_pending_exception *pe)
 static void dm_insert_exception(struct dm_exception_table *eh,
                                struct dm_exception *new_e)
 {
-       struct list_head *l;
+       struct hlist_bl_head *l;
+       struct hlist_bl_node *pos;
        struct dm_exception *e = NULL;
 
        l = &eh->table[exception_hash(eh, new_e->old_chunk)];
@@ -731,7 +767,7 @@ static void dm_insert_exception(struct dm_exception_table *eh,
                goto out;
 
        /* List is ordered by old_chunk */
-       list_for_each_entry_reverse(e, l, hash_list) {
+       hlist_bl_for_each_entry(e, pos, l, hash_list) {
                /* Insert after an existing chunk? */
                if (new_e->old_chunk == (e->old_chunk +
                                         dm_consecutive_chunk_count(e) + 1) &&
@@ -752,12 +788,24 @@ static void dm_insert_exception(struct dm_exception_table *eh,
                        return;
                }
 
-               if (new_e->old_chunk > e->old_chunk)
+               if (new_e->old_chunk < e->old_chunk)
                        break;
        }
 
 out:
-       list_add(&new_e->hash_list, e ? &e->hash_list : l);
+       if (!e) {
+               /*
+                * Either the table doesn't support consecutive chunks or slot
+                * l is empty.
+                */
+               hlist_bl_add_head(&new_e->hash_list, l);
+       } else if (new_e->old_chunk < e->old_chunk) {
+               /* Add before an existing exception */
+               hlist_bl_add_before(&new_e->hash_list, &e->hash_list);
+       } else {
+               /* Add to l's tail: e is the last exception in this slot */
+               hlist_bl_add_behind(&new_e->hash_list, &e->hash_list);
+       }
 }
 
 /*
@@ -766,6 +814,7 @@ out:
  */
 static int dm_add_exception(void *context, chunk_t old, chunk_t new)
 {
+       struct dm_exception_table_lock lock;
        struct dm_snapshot *s = context;
        struct dm_exception *e;
 
@@ -778,7 +827,17 @@ static int dm_add_exception(void *context, chunk_t old, chunk_t new)
        /* Consecutive_count is implicitly initialised to zero */
        e->new_chunk = new;
 
+       /*
+        * Although there is no need to lock access to the exception tables
+        * here, if we don't then hlist_bl_add_head(), called by
+        * dm_insert_exception(), will complain about accessing the
+        * corresponding list without locking it first.
+        */
+       dm_exception_table_lock_init(s, old, &lock);
+
+       dm_exception_table_lock(&lock);
        dm_insert_exception(&s->complete, e);
+       dm_exception_table_unlock(&lock);
 
        return 0;
 }
@@ -807,7 +866,7 @@ static int calc_max_buckets(void)
 {
        /* use a fixed size of 2MB */
        unsigned long mem = 2 * 1024 * 1024;
-       mem /= sizeof(struct list_head);
+       mem /= sizeof(struct hlist_bl_head);
 
        return mem;
 }
@@ -927,7 +986,7 @@ static int remove_single_exception_chunk(struct dm_snapshot *s)
        int r;
        chunk_t old_chunk = s->first_merging_chunk + s->num_merging_chunks - 1;
 
-       mutex_lock(&s->lock);
+       down_write(&s->lock);
 
        /*
         * Process chunks (and associated exceptions) in reverse order
@@ -942,7 +1001,7 @@ static int remove_single_exception_chunk(struct dm_snapshot *s)
        b = __release_queued_bios_after_merge(s);
 
 out:
-       mutex_unlock(&s->lock);
+       up_write(&s->lock);
        if (b)
                flush_bios(b);
 
@@ -1001,9 +1060,9 @@ static void snapshot_merge_next_chunks(struct dm_snapshot *s)
                if (linear_chunks < 0) {
                        DMERR("Read error in exception store: "
                              "shutting down merge");
-                       mutex_lock(&s->lock);
+                       down_write(&s->lock);
                        s->merge_failed = 1;
-                       mutex_unlock(&s->lock);
+                       up_write(&s->lock);
                }
                goto shut;
        }
@@ -1044,10 +1103,10 @@ static void snapshot_merge_next_chunks(struct dm_snapshot *s)
                previous_count = read_pending_exceptions_done_count();
        }
 
-       mutex_lock(&s->lock);
+       down_write(&s->lock);
        s->first_merging_chunk = old_chunk;
        s->num_merging_chunks = linear_chunks;
-       mutex_unlock(&s->lock);
+       up_write(&s->lock);
 
        /* Wait until writes to all 'linear_chunks' drain */
        for (i = 0; i < linear_chunks; i++)
@@ -1089,10 +1148,10 @@ static void merge_callback(int read_err, unsigned long write_err, void *context)
        return;
 
 shut:
-       mutex_lock(&s->lock);
+       down_write(&s->lock);
        s->merge_failed = 1;
        b = __release_queued_bios_after_merge(s);
-       mutex_unlock(&s->lock);
+       up_write(&s->lock);
        error_bios(b);
 
        merge_shutdown(s);
@@ -1188,10 +1247,11 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        s->snapshot_overflowed = 0;
        s->active = 0;
        atomic_set(&s->pending_exceptions_count, 0);
+       spin_lock_init(&s->pe_allocation_lock);
        s->exception_start_sequence = 0;
        s->exception_complete_sequence = 0;
        s->out_of_order_tree = RB_ROOT;
-       mutex_init(&s->lock);
+       init_rwsem(&s->lock);
        INIT_LIST_HEAD(&s->list);
        spin_lock_init(&s->pe_lock);
        s->state_bits = 0;
@@ -1357,9 +1417,9 @@ static void snapshot_dtr(struct dm_target *ti)
        /* Check whether exception handover must be cancelled */
        (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
        if (snap_src && snap_dest && (s == snap_src)) {
-               mutex_lock(&snap_dest->lock);
+               down_write(&snap_dest->lock);
                snap_dest->valid = 0;
-               mutex_unlock(&snap_dest->lock);
+               up_write(&snap_dest->lock);
                DMERR("Cancelling snapshot handover.");
        }
        up_read(&_origins_lock);
@@ -1390,8 +1450,6 @@ static void snapshot_dtr(struct dm_target *ti)
 
        dm_exception_store_destroy(s->store);
 
-       mutex_destroy(&s->lock);
-
        dm_put_device(ti, s->cow);
 
        dm_put_device(ti, s->origin);
@@ -1467,6 +1525,13 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err)
        dm_table_event(s->ti->table);
 }
 
+static void invalidate_snapshot(struct dm_snapshot *s, int err)
+{
+       down_write(&s->lock);
+       __invalidate_snapshot(s, err);
+       up_write(&s->lock);
+}
+
 static void pending_complete(void *context, int success)
 {
        struct dm_snap_pending_exception *pe = context;
@@ -1475,43 +1540,63 @@ static void pending_complete(void *context, int success)
        struct bio *origin_bios = NULL;
        struct bio *snapshot_bios = NULL;
        struct bio *full_bio = NULL;
+       struct dm_exception_table_lock lock;
        int error = 0;
 
+       dm_exception_table_lock_init(s, pe->e.old_chunk, &lock);
+
        if (!success) {
                /* Read/write error - snapshot is unusable */
-               mutex_lock(&s->lock);
-               __invalidate_snapshot(s, -EIO);
+               invalidate_snapshot(s, -EIO);
                error = 1;
+
+               dm_exception_table_lock(&lock);
                goto out;
        }
 
        e = alloc_completed_exception(GFP_NOIO);
        if (!e) {
-               mutex_lock(&s->lock);
-               __invalidate_snapshot(s, -ENOMEM);
+               invalidate_snapshot(s, -ENOMEM);
                error = 1;
+
+               dm_exception_table_lock(&lock);
                goto out;
        }
        *e = pe->e;
 
-       mutex_lock(&s->lock);
+       down_read(&s->lock);
+       dm_exception_table_lock(&lock);
        if (!s->valid) {
+               up_read(&s->lock);
                free_completed_exception(e);
                error = 1;
+
                goto out;
        }
 
-       /* Check for conflicting reads */
-       __check_for_conflicting_io(s, pe->e.old_chunk);
-
        /*
-        * Add a proper exception, and remove the
-        * in-flight exception from the list.
+        * Add a proper exception. After inserting the completed exception all
+        * subsequent snapshot reads to this chunk will be redirected to the
+        * COW device.  This ensures that we do not starve. Moreover, as long
+        * as the pending exception exists, neither origin writes nor snapshot
+        * merging can overwrite the chunk in origin.
         */
        dm_insert_exception(&s->complete, e);
+       up_read(&s->lock);
+
+       /* Wait for conflicting reads to drain */
+       if (__chunk_is_tracked(s, pe->e.old_chunk)) {
+               dm_exception_table_unlock(&lock);
+               __check_for_conflicting_io(s, pe->e.old_chunk);
+               dm_exception_table_lock(&lock);
+       }
 
 out:
+       /* Remove the in-flight exception from the list */
        dm_remove_exception(&pe->e);
+
+       dm_exception_table_unlock(&lock);
+
        snapshot_bios = bio_list_get(&pe->snapshot_bios);
        origin_bios = bio_list_get(&pe->origin_bios);
        full_bio = pe->full_bio;
@@ -1519,8 +1604,6 @@ out:
                full_bio->bi_end_io = pe->full_bio_end_io;
        increment_pending_exceptions_done_count();
 
-       mutex_unlock(&s->lock);
-
        /* Submit any pending write bios */
        if (error) {
                if (full_bio)
@@ -1660,43 +1743,59 @@ __lookup_pending_exception(struct dm_snapshot *s, chunk_t chunk)
 }
 
 /*
- * Looks to see if this snapshot already has a pending exception
- * for this chunk, otherwise it allocates a new one and inserts
- * it into the pending table.
+ * Inserts a pending exception into the pending table.
  *
- * NOTE: a write lock must be held on snap->lock before calling
- * this.
+ * NOTE: a write lock must be held on the chunk's pending exception table slot
+ * before calling this.
  */
 static struct dm_snap_pending_exception *
-__find_pending_exception(struct dm_snapshot *s,
-                        struct dm_snap_pending_exception *pe, chunk_t chunk)
+__insert_pending_exception(struct dm_snapshot *s,
+                          struct dm_snap_pending_exception *pe, chunk_t chunk)
 {
-       struct dm_snap_pending_exception *pe2;
-
-       pe2 = __lookup_pending_exception(s, chunk);
-       if (pe2) {
-               free_pending_exception(pe);
-               return pe2;
-       }
-
        pe->e.old_chunk = chunk;
        bio_list_init(&pe->origin_bios);
        bio_list_init(&pe->snapshot_bios);
        pe->started = 0;
        pe->full_bio = NULL;
 
+       spin_lock(&s->pe_allocation_lock);
        if (s->store->type->prepare_exception(s->store, &pe->e)) {
+               spin_unlock(&s->pe_allocation_lock);
                free_pending_exception(pe);
                return NULL;
        }
 
        pe->exception_sequence = s->exception_start_sequence++;
+       spin_unlock(&s->pe_allocation_lock);
 
        dm_insert_exception(&s->pending, &pe->e);
 
        return pe;
 }
 
+/*
+ * Looks to see if this snapshot already has a pending exception
+ * for this chunk, otherwise it allocates a new one and inserts
+ * it into the pending table.
+ *
+ * NOTE: a write lock must be held on the chunk's pending exception table slot
+ * before calling this.
+ */
+static struct dm_snap_pending_exception *
+__find_pending_exception(struct dm_snapshot *s,
+                        struct dm_snap_pending_exception *pe, chunk_t chunk)
+{
+       struct dm_snap_pending_exception *pe2;
+
+       pe2 = __lookup_pending_exception(s, chunk);
+       if (pe2) {
+               free_pending_exception(pe);
+               return pe2;
+       }
+
+       return __insert_pending_exception(s, pe, chunk);
+}
+
 static void remap_exception(struct dm_snapshot *s, struct dm_exception *e,
                            struct bio *bio, chunk_t chunk)
 {
@@ -1714,6 +1813,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
        int r = DM_MAPIO_REMAPPED;
        chunk_t chunk;
        struct dm_snap_pending_exception *pe = NULL;
+       struct dm_exception_table_lock lock;
 
        init_tracked_chunk(bio);
 
@@ -1723,13 +1823,15 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
        }
 
        chunk = sector_to_chunk(s->store, bio->bi_iter.bi_sector);
+       dm_exception_table_lock_init(s, chunk, &lock);
 
        /* Full snapshots are not usable */
        /* To get here the table must be live so s->active is always set. */
        if (!s->valid)
                return DM_MAPIO_KILL;
 
-       mutex_lock(&s->lock);
+       down_read(&s->lock);
+       dm_exception_table_lock(&lock);
 
        if (!s->valid || (unlikely(s->snapshot_overflowed) &&
            bio_data_dir(bio) == WRITE)) {
@@ -1752,15 +1854,9 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
        if (bio_data_dir(bio) == WRITE) {
                pe = __lookup_pending_exception(s, chunk);
                if (!pe) {
-                       mutex_unlock(&s->lock);
+                       dm_exception_table_unlock(&lock);
                        pe = alloc_pending_exception(s);
-                       mutex_lock(&s->lock);
-
-                       if (!s->valid || s->snapshot_overflowed) {
-                               free_pending_exception(pe);
-                               r = DM_MAPIO_KILL;
-                               goto out_unlock;
-                       }
+                       dm_exception_table_lock(&lock);
 
                        e = dm_lookup_exception(&s->complete, chunk);
                        if (e) {
@@ -1771,13 +1867,22 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
 
                        pe = __find_pending_exception(s, pe, chunk);
                        if (!pe) {
+                               dm_exception_table_unlock(&lock);
+                               up_read(&s->lock);
+
+                               down_write(&s->lock);
+
                                if (s->store->userspace_supports_overflow) {
-                                       s->snapshot_overflowed = 1;
-                                       DMERR("Snapshot overflowed: Unable to allocate exception.");
+                                       if (s->valid && !s->snapshot_overflowed) {
+                                               s->snapshot_overflowed = 1;
+                                               DMERR("Snapshot overflowed: Unable to allocate exception.");
+                                       }
                                } else
                                        __invalidate_snapshot(s, -ENOMEM);
+                               up_write(&s->lock);
+
                                r = DM_MAPIO_KILL;
-                               goto out_unlock;
+                               goto out;
                        }
                }
 
@@ -1789,7 +1894,10 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
                    bio->bi_iter.bi_size ==
                    (s->store->chunk_size << SECTOR_SHIFT)) {
                        pe->started = 1;
-                       mutex_unlock(&s->lock);
+
+                       dm_exception_table_unlock(&lock);
+                       up_read(&s->lock);
+
                        start_full_bio(pe, bio);
                        goto out;
                }
@@ -1797,9 +1905,12 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
                bio_list_add(&pe->snapshot_bios, bio);
 
                if (!pe->started) {
-                       /* this is protected by snap->lock */
+                       /* this is protected by the exception table lock */
                        pe->started = 1;
-                       mutex_unlock(&s->lock);
+
+                       dm_exception_table_unlock(&lock);
+                       up_read(&s->lock);
+
                        start_copy(pe);
                        goto out;
                }
@@ -1809,7 +1920,8 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
        }
 
 out_unlock:
-       mutex_unlock(&s->lock);
+       dm_exception_table_unlock(&lock);
+       up_read(&s->lock);
 out:
        return r;
 }
@@ -1845,7 +1957,7 @@ static int snapshot_merge_map(struct dm_target *ti, struct bio *bio)
 
        chunk = sector_to_chunk(s->store, bio->bi_iter.bi_sector);
 
-       mutex_lock(&s->lock);
+       down_write(&s->lock);
 
        /* Full merging snapshots are redirected to the origin */
        if (!s->valid)
@@ -1876,12 +1988,12 @@ redirect_to_origin:
        bio_set_dev(bio, s->origin->bdev);
 
        if (bio_data_dir(bio) == WRITE) {
-               mutex_unlock(&s->lock);
+               up_write(&s->lock);
                return do_origin(s->origin, bio);
        }
 
 out_unlock:
-       mutex_unlock(&s->lock);
+       up_write(&s->lock);
 
        return r;
 }
@@ -1913,7 +2025,7 @@ static int snapshot_preresume(struct dm_target *ti)
        down_read(&_origins_lock);
        (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
        if (snap_src && snap_dest) {
-               mutex_lock(&snap_src->lock);
+               down_read(&snap_src->lock);
                if (s == snap_src) {
                        DMERR("Unable to resume snapshot source until "
                              "handover completes.");
@@ -1923,7 +2035,7 @@ static int snapshot_preresume(struct dm_target *ti)
                              "source is suspended.");
                        r = -EINVAL;
                }
-               mutex_unlock(&snap_src->lock);
+               up_read(&snap_src->lock);
        }
        up_read(&_origins_lock);
 
@@ -1969,11 +2081,11 @@ static void snapshot_resume(struct dm_target *ti)
 
        (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
        if (snap_src && snap_dest) {
-               mutex_lock(&snap_src->lock);
-               mutex_lock_nested(&snap_dest->lock, SINGLE_DEPTH_NESTING);
+               down_write(&snap_src->lock);
+               down_write_nested(&snap_dest->lock, SINGLE_DEPTH_NESTING);
                __handover_exceptions(snap_src, snap_dest);
-               mutex_unlock(&snap_dest->lock);
-               mutex_unlock(&snap_src->lock);
+               up_write(&snap_dest->lock);
+               up_write(&snap_src->lock);
        }
 
        up_read(&_origins_lock);
@@ -1988,9 +2100,9 @@ static void snapshot_resume(struct dm_target *ti)
        /* Now we have correct chunk size, reregister */
        reregister_snapshot(s);
 
-       mutex_lock(&s->lock);
+       down_write(&s->lock);
        s->active = 1;
-       mutex_unlock(&s->lock);
+       up_write(&s->lock);
 }
 
 static uint32_t get_origin_minimum_chunksize(struct block_device *bdev)
@@ -2030,7 +2142,7 @@ static void snapshot_status(struct dm_target *ti, status_type_t type,
        switch (type) {
        case STATUSTYPE_INFO:
 
-               mutex_lock(&snap->lock);
+               down_write(&snap->lock);
 
                if (!snap->valid)
                        DMEMIT("Invalid");
@@ -2055,7 +2167,7 @@ static void snapshot_status(struct dm_target *ti, status_type_t type,
                                DMEMIT("Unknown");
                }
 
-               mutex_unlock(&snap->lock);
+               up_write(&snap->lock);
 
                break;
 
@@ -2107,9 +2219,10 @@ static int __origin_write(struct list_head *snapshots, sector_t sector,
        int r = DM_MAPIO_REMAPPED;
        struct dm_snapshot *snap;
        struct dm_exception *e;
-       struct dm_snap_pending_exception *pe;
+       struct dm_snap_pending_exception *pe, *pe2;
        struct dm_snap_pending_exception *pe_to_start_now = NULL;
        struct dm_snap_pending_exception *pe_to_start_last = NULL;
+       struct dm_exception_table_lock lock;
        chunk_t chunk;
 
        /* Do all the snapshots on this origin */
@@ -2121,52 +2234,59 @@ static int __origin_write(struct list_head *snapshots, sector_t sector,
                if (dm_target_is_snapshot_merge(snap->ti))
                        continue;
 
-               mutex_lock(&snap->lock);
-
-               /* Only deal with valid and active snapshots */
-               if (!snap->valid || !snap->active)
-                       goto next_snapshot;
-
                /* Nothing to do if writing beyond end of snapshot */
                if (sector >= dm_table_get_size(snap->ti->table))
-                       goto next_snapshot;
+                       continue;
 
                /*
                 * Remember, different snapshots can have
                 * different chunk sizes.
                 */
                chunk = sector_to_chunk(snap->store, sector);
+               dm_exception_table_lock_init(snap, chunk, &lock);
 
-               /*
-                * Check exception table to see if block
-                * is already remapped in this snapshot
-                * and trigger an exception if not.
-                */
-               e = dm_lookup_exception(&snap->complete, chunk);
-               if (e)
+               down_read(&snap->lock);
+               dm_exception_table_lock(&lock);
+
+               /* Only deal with valid and active snapshots */
+               if (!snap->valid || !snap->active)
                        goto next_snapshot;
 
                pe = __lookup_pending_exception(snap, chunk);
                if (!pe) {
-                       mutex_unlock(&snap->lock);
-                       pe = alloc_pending_exception(snap);
-                       mutex_lock(&snap->lock);
-
-                       if (!snap->valid) {
-                               free_pending_exception(pe);
-                               goto next_snapshot;
-                       }
-
+                       /*
+                        * Check exception table to see if block is already
+                        * remapped in this snapshot and trigger an exception
+                        * if not.
+                        */
                        e = dm_lookup_exception(&snap->complete, chunk);
-                       if (e) {
-                               free_pending_exception(pe);
+                       if (e)
                                goto next_snapshot;
-                       }
 
-                       pe = __find_pending_exception(snap, pe, chunk);
-                       if (!pe) {
-                               __invalidate_snapshot(snap, -ENOMEM);
-                               goto next_snapshot;
+                       dm_exception_table_unlock(&lock);
+                       pe = alloc_pending_exception(snap);
+                       dm_exception_table_lock(&lock);
+
+                       pe2 = __lookup_pending_exception(snap, chunk);
+
+                       if (!pe2) {
+                               e = dm_lookup_exception(&snap->complete, chunk);
+                               if (e) {
+                                       free_pending_exception(pe);
+                                       goto next_snapshot;
+                               }
+
+                               pe = __insert_pending_exception(snap, pe, chunk);
+                               if (!pe) {
+                                       dm_exception_table_unlock(&lock);
+                                       up_read(&snap->lock);
+
+                                       invalidate_snapshot(snap, -ENOMEM);
+                                       continue;
+                               }
+                       } else {
+                               free_pending_exception(pe);
+                               pe = pe2;
                        }
                }
 
@@ -2193,7 +2313,8 @@ static int __origin_write(struct list_head *snapshots, sector_t sector,
                }
 
 next_snapshot:
-               mutex_unlock(&snap->lock);
+               dm_exception_table_unlock(&lock);
+               up_read(&snap->lock);
 
                if (pe_to_start_now) {
                        start_copy(pe_to_start_now);
index 314d17ca64668a70ea1f6445111ca19b2024141e..64dd0b34fcf490cee3779e179e9b8c7c543b7e53 100644 (file)
@@ -136,7 +136,8 @@ static int io_err_clone_and_map_rq(struct dm_target *ti, struct request *rq,
        return DM_MAPIO_KILL;
 }
 
-static void io_err_release_clone_rq(struct request *clone)
+static void io_err_release_clone_rq(struct request *clone,
+                                   union map_info *map_context)
 {
 }
 
index ed3caceaed07c07c33e16b9038f0c3bffd7616d5..7f0840601737f473dfde9bdb06de8fc4f639d264 100644 (file)
@@ -201,6 +201,13 @@ struct dm_pool_metadata {
         */
        bool fail_io:1;
 
+       /*
+        * Set once a thin-pool has been accessed through one of the interfaces
+        * that imply the pool is in-service (e.g. thin devices created/deleted,
+        * thin-pool message, metadata snapshots, etc).
+        */
+       bool in_service:1;
+
        /*
         * Reading the space map roots can fail, so we read it into these
         * buffers before the superblock is locked and updated.
@@ -367,6 +374,32 @@ static int subtree_equal(void *context, const void *value1_le, const void *value
 
 /*----------------------------------------------------------------*/
 
+/*
+ * Variant that is used for in-core only changes or code that
+ * shouldn't put the pool in service on its own (e.g. commit).
+ */
+static inline void __pmd_write_lock(struct dm_pool_metadata *pmd)
+       __acquires(pmd->root_lock)
+{
+       down_write(&pmd->root_lock);
+}
+#define pmd_write_lock_in_core(pmd) __pmd_write_lock((pmd))
+
+static inline void pmd_write_lock(struct dm_pool_metadata *pmd)
+{
+       __pmd_write_lock(pmd);
+       if (unlikely(!pmd->in_service))
+               pmd->in_service = true;
+}
+
+static inline void pmd_write_unlock(struct dm_pool_metadata *pmd)
+       __releases(pmd->root_lock)
+{
+       up_write(&pmd->root_lock);
+}
+
+/*----------------------------------------------------------------*/
+
 static int superblock_lock_zero(struct dm_pool_metadata *pmd,
                                struct dm_block **sblock)
 {
@@ -790,6 +823,9 @@ static int __commit_transaction(struct dm_pool_metadata *pmd)
         */
        BUILD_BUG_ON(sizeof(struct thin_disk_superblock) > 512);
 
+       if (unlikely(!pmd->in_service))
+               return 0;
+
        r = __write_changed_details(pmd);
        if (r < 0)
                return r;
@@ -853,6 +889,7 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
        pmd->time = 0;
        INIT_LIST_HEAD(&pmd->thin_devices);
        pmd->fail_io = false;
+       pmd->in_service = false;
        pmd->bdev = bdev;
        pmd->data_block_size = data_block_size;
 
@@ -903,7 +940,6 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
                        DMWARN("%s: __commit_transaction() failed, error = %d",
                               __func__, r);
        }
-
        if (!pmd->fail_io)
                __destroy_persistent_data_objects(pmd);
 
@@ -1032,10 +1068,10 @@ int dm_pool_create_thin(struct dm_pool_metadata *pmd, dm_thin_id dev)
 {
        int r = -EINVAL;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock(pmd);
        if (!pmd->fail_io)
                r = __create_thin(pmd, dev);
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 
        return r;
 }
@@ -1123,10 +1159,10 @@ int dm_pool_create_snap(struct dm_pool_metadata *pmd,
 {
        int r = -EINVAL;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock(pmd);
        if (!pmd->fail_io)
                r = __create_snap(pmd, dev, origin);
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 
        return r;
 }
@@ -1166,10 +1202,10 @@ int dm_pool_delete_thin_device(struct dm_pool_metadata *pmd,
 {
        int r = -EINVAL;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock(pmd);
        if (!pmd->fail_io)
                r = __delete_device(pmd, dev);
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 
        return r;
 }
@@ -1180,7 +1216,7 @@ int dm_pool_set_metadata_transaction_id(struct dm_pool_metadata *pmd,
 {
        int r = -EINVAL;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock(pmd);
 
        if (pmd->fail_io)
                goto out;
@@ -1194,7 +1230,7 @@ int dm_pool_set_metadata_transaction_id(struct dm_pool_metadata *pmd,
        r = 0;
 
 out:
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 
        return r;
 }
@@ -1225,7 +1261,12 @@ static int __reserve_metadata_snap(struct dm_pool_metadata *pmd)
         * We commit to ensure the btree roots which we increment in a
         * moment are up to date.
         */
-       __commit_transaction(pmd);
+       r = __commit_transaction(pmd);
+       if (r < 0) {
+               DMWARN("%s: __commit_transaction() failed, error = %d",
+                      __func__, r);
+               return r;
+       }
 
        /*
         * Copy the superblock.
@@ -1283,10 +1324,10 @@ int dm_pool_reserve_metadata_snap(struct dm_pool_metadata *pmd)
 {
        int r = -EINVAL;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock(pmd);
        if (!pmd->fail_io)
                r = __reserve_metadata_snap(pmd);
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 
        return r;
 }
@@ -1331,10 +1372,10 @@ int dm_pool_release_metadata_snap(struct dm_pool_metadata *pmd)
 {
        int r = -EINVAL;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock(pmd);
        if (!pmd->fail_io)
                r = __release_metadata_snap(pmd);
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 
        return r;
 }
@@ -1377,19 +1418,19 @@ int dm_pool_open_thin_device(struct dm_pool_metadata *pmd, dm_thin_id dev,
 {
        int r = -EINVAL;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock_in_core(pmd);
        if (!pmd->fail_io)
                r = __open_device(pmd, dev, 0, td);
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 
        return r;
 }
 
 int dm_pool_close_thin_device(struct dm_thin_device *td)
 {
-       down_write(&td->pmd->root_lock);
+       pmd_write_lock_in_core(td->pmd);
        __close_device(td);
-       up_write(&td->pmd->root_lock);
+       pmd_write_unlock(td->pmd);
 
        return 0;
 }
@@ -1570,10 +1611,10 @@ int dm_thin_insert_block(struct dm_thin_device *td, dm_block_t block,
 {
        int r = -EINVAL;
 
-       down_write(&td->pmd->root_lock);
+       pmd_write_lock(td->pmd);
        if (!td->pmd->fail_io)
                r = __insert(td, block, data_block);
-       up_write(&td->pmd->root_lock);
+       pmd_write_unlock(td->pmd);
 
        return r;
 }
@@ -1657,10 +1698,10 @@ int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block)
 {
        int r = -EINVAL;
 
-       down_write(&td->pmd->root_lock);
+       pmd_write_lock(td->pmd);
        if (!td->pmd->fail_io)
                r = __remove(td, block);
-       up_write(&td->pmd->root_lock);
+       pmd_write_unlock(td->pmd);
 
        return r;
 }
@@ -1670,10 +1711,10 @@ int dm_thin_remove_range(struct dm_thin_device *td,
 {
        int r = -EINVAL;
 
-       down_write(&td->pmd->root_lock);
+       pmd_write_lock(td->pmd);
        if (!td->pmd->fail_io)
                r = __remove_range(td, begin, end);
-       up_write(&td->pmd->root_lock);
+       pmd_write_unlock(td->pmd);
 
        return r;
 }
@@ -1696,13 +1737,13 @@ int dm_pool_inc_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_
 {
        int r = 0;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock(pmd);
        for (; b != e; b++) {
                r = dm_sm_inc_block(pmd->data_sm, b);
                if (r)
                        break;
        }
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 
        return r;
 }
@@ -1711,13 +1752,13 @@ int dm_pool_dec_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_
 {
        int r = 0;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock(pmd);
        for (; b != e; b++) {
                r = dm_sm_dec_block(pmd->data_sm, b);
                if (r)
                        break;
        }
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 
        return r;
 }
@@ -1765,10 +1806,10 @@ int dm_pool_alloc_data_block(struct dm_pool_metadata *pmd, dm_block_t *result)
 {
        int r = -EINVAL;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock(pmd);
        if (!pmd->fail_io)
                r = dm_sm_new_block(pmd->data_sm, result);
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 
        return r;
 }
@@ -1777,12 +1818,16 @@ int dm_pool_commit_metadata(struct dm_pool_metadata *pmd)
 {
        int r = -EINVAL;
 
-       down_write(&pmd->root_lock);
+       /*
+        * Care is taken to not have commit be what
+        * triggers putting the thin-pool in-service.
+        */
+       __pmd_write_lock(pmd);
        if (pmd->fail_io)
                goto out;
 
        r = __commit_transaction(pmd);
-       if (r <= 0)
+       if (r < 0)
                goto out;
 
        /*
@@ -1790,7 +1835,7 @@ int dm_pool_commit_metadata(struct dm_pool_metadata *pmd)
         */
        r = __begin_transaction(pmd);
 out:
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
        return r;
 }
 
@@ -1806,7 +1851,7 @@ int dm_pool_abort_metadata(struct dm_pool_metadata *pmd)
 {
        int r = -EINVAL;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock(pmd);
        if (pmd->fail_io)
                goto out;
 
@@ -1817,7 +1862,7 @@ int dm_pool_abort_metadata(struct dm_pool_metadata *pmd)
                pmd->fail_io = true;
 
 out:
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 
        return r;
 }
@@ -1948,10 +1993,10 @@ int dm_pool_resize_data_dev(struct dm_pool_metadata *pmd, dm_block_t new_count)
 {
        int r = -EINVAL;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock(pmd);
        if (!pmd->fail_io)
                r = __resize_space_map(pmd->data_sm, new_count);
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 
        return r;
 }
@@ -1960,29 +2005,29 @@ int dm_pool_resize_metadata_dev(struct dm_pool_metadata *pmd, dm_block_t new_cou
 {
        int r = -EINVAL;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock(pmd);
        if (!pmd->fail_io) {
                r = __resize_space_map(pmd->metadata_sm, new_count);
                if (!r)
                        __set_metadata_reserve(pmd);
        }
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 
        return r;
 }
 
 void dm_pool_metadata_read_only(struct dm_pool_metadata *pmd)
 {
-       down_write(&pmd->root_lock);
+       pmd_write_lock_in_core(pmd);
        dm_bm_set_read_only(pmd->bm);
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 }
 
 void dm_pool_metadata_read_write(struct dm_pool_metadata *pmd)
 {
-       down_write(&pmd->root_lock);
+       pmd_write_lock_in_core(pmd);
        dm_bm_set_read_write(pmd->bm);
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 }
 
 int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
@@ -1992,9 +2037,9 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
 {
        int r;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock_in_core(pmd);
        r = dm_sm_register_threshold_callback(pmd->metadata_sm, threshold, fn, context);
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
 
        return r;
 }
@@ -2005,7 +2050,7 @@ int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd)
        struct dm_block *sblock;
        struct thin_disk_superblock *disk_super;
 
-       down_write(&pmd->root_lock);
+       pmd_write_lock(pmd);
        pmd->flags |= THIN_METADATA_NEEDS_CHECK_FLAG;
 
        r = superblock_lock(pmd, &sblock);
@@ -2019,7 +2064,7 @@ int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd)
 
        dm_bm_unlock(sblock);
 out:
-       up_write(&pmd->root_lock);
+       pmd_write_unlock(pmd);
        return r;
 }
 
index f7822875589ea8439764d72a488adc2846a28f6f..1cb137f0ef9d7f4b265779563273ed82d136eee3 100644 (file)
@@ -190,7 +190,6 @@ struct writeback_struct {
        struct dm_writecache *wc;
        struct wc_entry **wc_list;
        unsigned wc_list_n;
-       unsigned page_offset;
        struct page *page;
        struct wc_entry *wc_list_inline[WB_LIST_INLINE];
        struct bio bio;
@@ -546,21 +545,20 @@ static struct wc_entry *writecache_find_entry(struct dm_writecache *wc,
                e = container_of(node, struct wc_entry, rb_node);
                if (read_original_sector(wc, e) == block)
                        break;
+
                node = (read_original_sector(wc, e) >= block ?
                        e->rb_node.rb_left : e->rb_node.rb_right);
                if (unlikely(!node)) {
-                       if (!(flags & WFE_RETURN_FOLLOWING)) {
+                       if (!(flags & WFE_RETURN_FOLLOWING))
                                return NULL;
-                       }
                        if (read_original_sector(wc, e) >= block) {
-                               break;
+                               return e;
                        } else {
                                node = rb_next(&e->rb_node);
-                               if (unlikely(!node)) {
+                               if (unlikely(!node))
                                        return NULL;
-                               }
                                e = container_of(node, struct wc_entry, rb_node);
-                               break;
+                               return e;
                        }
                }
        }
@@ -571,7 +569,7 @@ static struct wc_entry *writecache_find_entry(struct dm_writecache *wc,
                        node = rb_prev(&e->rb_node);
                else
                        node = rb_next(&e->rb_node);
-               if (!node)
+               if (unlikely(!node))
                        return e;
                e2 = container_of(node, struct wc_entry, rb_node);
                if (read_original_sector(wc, e2) != block)
@@ -804,7 +802,7 @@ static void writecache_discard(struct dm_writecache *wc, sector_t start, sector_
                        writecache_free_entry(wc, e);
                }
 
-               if (!node)
+               if (unlikely(!node))
                        break;
 
                e = container_of(node, struct wc_entry, rb_node);
@@ -1478,10 +1476,9 @@ static void __writecache_writeback_pmem(struct dm_writecache *wc, struct writeba
                bio = bio_alloc_bioset(GFP_NOIO, max_pages, &wc->bio_set);
                wb = container_of(bio, struct writeback_struct, bio);
                wb->wc = wc;
-               wb->bio.bi_end_io = writecache_writeback_endio;
-               bio_set_dev(&wb->bio, wc->dev->bdev);
-               wb->bio.bi_iter.bi_sector = read_original_sector(wc, e);
-               wb->page_offset = PAGE_SIZE;
+               bio->bi_end_io = writecache_writeback_endio;
+               bio_set_dev(bio, wc->dev->bdev);
+               bio->bi_iter.bi_sector = read_original_sector(wc, e);
                if (max_pages <= WB_LIST_INLINE ||
                    unlikely(!(wb->wc_list = kmalloc_array(max_pages, sizeof(struct wc_entry *),
                                                           GFP_NOIO | __GFP_NORETRY |
@@ -1507,12 +1504,12 @@ static void __writecache_writeback_pmem(struct dm_writecache *wc, struct writeba
                        wb->wc_list[wb->wc_list_n++] = f;
                        e = f;
                }
-               bio_set_op_attrs(&wb->bio, REQ_OP_WRITE, WC_MODE_FUA(wc) * REQ_FUA);
+               bio_set_op_attrs(bio, REQ_OP_WRITE, WC_MODE_FUA(wc) * REQ_FUA);
                if (writecache_has_error(wc)) {
                        bio->bi_status = BLK_STS_IOERR;
-                       bio_endio(&wb->bio);
+                       bio_endio(bio);
                } else {
-                       submit_bio(&wb->bio);
+                       submit_bio(bio);
                }
 
                __writeback_throttle(wc, wbl);
index fa68336560c34dab4acdc2bd9f2dd207ce1d2f5e..d8334cd45d7cb5eb90745b09463cf4daaa231021 100644 (file)
@@ -1169,6 +1169,9 @@ static int dmz_init_zones(struct dmz_metadata *zmd)
                        goto out;
                }
 
+               if (!nr_blkz)
+                       break;
+
                /* Process report */
                for (i = 0; i < nr_blkz; i++) {
                        ret = dmz_init_zone(zmd, zone, &blkz[i]);
@@ -1204,6 +1207,8 @@ static int dmz_update_zone(struct dmz_metadata *zmd, struct dm_zone *zone)
        /* Get zone information from disk */
        ret = blkdev_report_zones(zmd->dev->bdev, dmz_start_sect(zmd, zone),
                                  &blkz, &nr_blkz, GFP_NOIO);
+       if (!nr_blkz)
+               ret = -EIO;
        if (ret) {
                dmz_dev_err(zmd->dev, "Get zone %u report failed",
                            dmz_id(zmd, zone));
index 8865c1709e16357178ede5284c4477536bf2369d..51d029bbb740c4f032ea63005611b194fcc5cee8 100644 (file)
@@ -643,7 +643,8 @@ static int dmz_get_zoned_device(struct dm_target *ti, char *path)
 
        q = bdev_get_queue(dev->bdev);
        dev->capacity = i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT;
-       aligned_capacity = dev->capacity & ~(blk_queue_zone_sectors(q) - 1);
+       aligned_capacity = dev->capacity &
+                               ~((sector_t)blk_queue_zone_sectors(q) - 1);
        if (ti->begin ||
            ((ti->len != dev->capacity) && (ti->len != aligned_capacity))) {
                ti->error = "Partial mapping not supported";
index 043f0761e4a0aea8a22a1c6745f3f9bbbc021dfd..1fb1333fefec12b881ec5e32f0a12bad8af6108c 100644 (file)
@@ -781,7 +781,8 @@ static void close_table_device(struct table_device *td, struct mapped_device *md
 }
 
 static struct table_device *find_table_device(struct list_head *l, dev_t dev,
-                                             fmode_t mode) {
+                                             fmode_t mode)
+{
        struct table_device *td;
 
        list_for_each_entry(td, l, list)
@@ -792,7 +793,8 @@ static struct table_device *find_table_device(struct list_head *l, dev_t dev,
 }
 
 int dm_get_table_device(struct mapped_device *md, dev_t dev, fmode_t mode,
-                       struct dm_dev **result) {
+                       struct dm_dev **result)
+{
        int r;
        struct table_device *td;
 
@@ -1906,7 +1908,6 @@ static void cleanup_mapped_device(struct mapped_device *md)
 static struct mapped_device *alloc_dev(int minor)
 {
        int r, numa_node_id = dm_get_numa_node();
-       struct dax_device *dax_dev = NULL;
        struct mapped_device *md;
        void *old_md;
 
@@ -1969,11 +1970,10 @@ static struct mapped_device *alloc_dev(int minor)
        sprintf(md->disk->disk_name, "dm-%d", minor);
 
        if (IS_ENABLED(CONFIG_DAX_DRIVER)) {
-               dax_dev = alloc_dax(md, md->disk->disk_name, &dm_dax_ops);
-               if (!dax_dev)
+               md->dax_dev = alloc_dax(md, md->disk->disk_name, &dm_dax_ops);
+               if (!md->dax_dev)
                        goto bad;
        }
-       md->dax_dev = dax_dev;
 
        add_disk_no_queue_reg(md->disk);
        format_dev_t(md->name, MKDEV(_major, minor));
index 0a3b8ae4a29c6789b400e91a912f90b8ced1a806..b8a62188f6be5906630983ef8fe183c9ba68ef2f 100644 (file)
@@ -190,6 +190,8 @@ static int sm_find_free(void *addr, unsigned begin, unsigned end,
 
 static int sm_ll_init(struct ll_disk *ll, struct dm_transaction_manager *tm)
 {
+       memset(ll, 0, sizeof(struct ll_disk));
+
        ll->tm = tm;
 
        ll->bitmap_info.tm = tm;
index 7ebd58a1c4317e553faf947931ee5360acda1a89..3cf25abf58070a8619672be05453d5a0ca8af1b2 100644 (file)
@@ -2201,6 +2201,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
                goto unlock;
        }
 
+       /*
+        * vm_pgoff is treated in V4L2 API as a 'cookie' to select a buffer,
+        * not as a in-buffer offset. We always want to mmap a whole buffer
+        * from its beginning.
+        */
+       vma->vm_pgoff = 0;
+
        ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma);
 
 unlock:
index 82389aead6edad14459c9ec1bf1e5769dbbea76e..ecbef266130b9fc7823f4858d46f148ce1f5253d 100644 (file)
@@ -186,12 +186,6 @@ static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma)
                return -EINVAL;
        }
 
-       /*
-        * dma_mmap_* uses vm_pgoff as in-buffer offset, but we want to
-        * map whole buffer
-        */
-       vma->vm_pgoff = 0;
-
        ret = dma_mmap_attrs(buf->dev, vma, buf->cookie,
                buf->dma_addr, buf->size, buf->attrs);
 
index 270c3162fdcb3fd150cd414757028fbbe0500234..4a4c49d6085ce99c08623a63a5d33c8c36022fca 100644 (file)
@@ -328,28 +328,18 @@ static unsigned int vb2_dma_sg_num_users(void *buf_priv)
 static int vb2_dma_sg_mmap(void *buf_priv, struct vm_area_struct *vma)
 {
        struct vb2_dma_sg_buf *buf = buf_priv;
-       unsigned long uaddr = vma->vm_start;
-       unsigned long usize = vma->vm_end - vma->vm_start;
-       int i = 0;
+       int err;
 
        if (!buf) {
                printk(KERN_ERR "No memory to map\n");
                return -EINVAL;
        }
 
-       do {
-               int ret;
-
-               ret = vm_insert_page(vma, uaddr, buf->pages[i++]);
-               if (ret) {
-                       printk(KERN_ERR "Remapping memory, error: %d\n", ret);
-                       return ret;
-               }
-
-               uaddr += PAGE_SIZE;
-               usize -= PAGE_SIZE;
-       } while (usize > 0);
-
+       err = vm_map_pages(vma, buf->pages, buf->num_pages);
+       if (err) {
+               printk(KERN_ERR "Remapping memory, error: %d\n", err);
+               return err;
+       }
 
        /*
         * Use common vm_area operations to track buffer refcount.
index d730693f299cfccf098f6466f66076a1765109b8..8f7f8efc71a7d945e3e5b014f12f2492e64948ff 100644 (file)
 #define ISC_PFG_CFG0_BPS_TWELVE (0x0 << 28)
 #define ISC_PFE_CFG0_BPS_MASK   GENMASK(30, 28)
 
+#define ISC_PFE_CFG0_COLEN     BIT(12)
+#define ISC_PFE_CFG0_ROWEN     BIT(13)
+
+/* ISC Parallel Front End Configuration 1 Register */
+#define ISC_PFE_CFG1    0x00000010
+
+#define ISC_PFE_CFG1_COLMIN(v)         ((v))
+#define ISC_PFE_CFG1_COLMIN_MASK       GENMASK(15, 0)
+#define ISC_PFE_CFG1_COLMAX(v)         ((v) << 16)
+#define ISC_PFE_CFG1_COLMAX_MASK       GENMASK(31, 16)
+
+/* ISC Parallel Front End Configuration 2 Register */
+#define ISC_PFE_CFG2    0x00000014
+
+#define ISC_PFE_CFG2_ROWMIN(v)         ((v))
+#define ISC_PFE_CFG2_ROWMIN_MASK       GENMASK(15, 0)
+#define ISC_PFE_CFG2_ROWMAX(v)         ((v) << 16)
+#define ISC_PFE_CFG2_ROWMAX_MASK       GENMASK(31, 16)
+
 /* ISC Clock Enable Register */
 #define ISC_CLKEN               0x00000018
 
index 4bba9da206e416a65dde7834b6c25cee14eeed3f..94cb309fdb527dffdf501b0c8fa3fb946e76bdc9 100644 (file)
@@ -721,6 +721,40 @@ static void isc_start_dma(struct isc_device *isc)
        u32 sizeimage = isc->fmt.fmt.pix.sizeimage;
        u32 dctrl_dview;
        dma_addr_t addr0;
+       u32 h, w;
+
+       h = isc->fmt.fmt.pix.height;
+       w = isc->fmt.fmt.pix.width;
+
+       /*
+        * In case the sensor is not RAW, it will output a pixel (12-16 bits)
+        * with two samples on the ISC Data bus (which is 8-12)
+        * ISC will count each sample, so, we need to multiply these values
+        * by two, to get the real number of samples for the required pixels.
+        */
+       if (!ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) {
+               h <<= 1;
+               w <<= 1;
+       }
+
+       /*
+        * We limit the column/row count that the ISC will output according
+        * to the configured resolution that we want.
+        * This will avoid the situation where the sensor is misconfigured,
+        * sending more data, and the ISC will just take it and DMA to memory,
+        * causing corruption.
+        */
+       regmap_write(regmap, ISC_PFE_CFG1,
+                    (ISC_PFE_CFG1_COLMIN(0) & ISC_PFE_CFG1_COLMIN_MASK) |
+                    (ISC_PFE_CFG1_COLMAX(w - 1) & ISC_PFE_CFG1_COLMAX_MASK));
+
+       regmap_write(regmap, ISC_PFE_CFG2,
+                    (ISC_PFE_CFG2_ROWMIN(0) & ISC_PFE_CFG2_ROWMIN_MASK) |
+                    (ISC_PFE_CFG2_ROWMAX(h - 1) & ISC_PFE_CFG2_ROWMAX_MASK));
+
+       regmap_update_bits(regmap, ISC_PFE_CFG0,
+                          ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN,
+                          ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN);
 
        addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0);
        regmap_write(regmap, ISC_DAD0, addr0);
@@ -1965,6 +1999,8 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
        struct vb2_queue *q = &isc->vb2_vidq;
        int ret;
 
+       INIT_WORK(&isc->awb_work, isc_awb_work);
+
        ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev);
        if (ret < 0) {
                v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n");
@@ -2018,8 +2054,6 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
                return ret;
        }
 
-       INIT_WORK(&isc->awb_work, isc_awb_work);
-
        /* Register video device */
        strscpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name));
        vdev->release           = video_device_release_empty;
@@ -2135,8 +2169,11 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc)
                        break;
                }
 
-               subdev_entity->asd = devm_kzalloc(dev,
-                                    sizeof(*subdev_entity->asd), GFP_KERNEL);
+               /* asd will be freed by the subsystem once it's added to the
+                * notifier list
+                */
+               subdev_entity->asd = kzalloc(sizeof(*subdev_entity->asd),
+                                            GFP_KERNEL);
                if (!subdev_entity->asd) {
                        of_node_put(rem);
                        ret = -ENOMEM;
@@ -2284,6 +2321,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
                                                     subdev_entity->asd);
                if (ret) {
                        fwnode_handle_put(subdev_entity->asd->match.fwnode);
+                       kfree(subdev_entity->asd);
                        goto cleanup_subdev;
                }
 
index 3ce58dee4422bd16d61802c641e16e392a9597a3..1d96cca615477d513974e78cec2c7553eb603128 100644 (file)
@@ -1515,10 +1515,20 @@ static int coda_queue_setup(struct vb2_queue *vq,
 
 static int coda_buf_prepare(struct vb2_buffer *vb)
 {
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
        struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
        struct coda_q_data *q_data;
 
        q_data = get_q_data(ctx, vb->vb2_queue->type);
+       if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+               if (vbuf->field == V4L2_FIELD_ANY)
+                       vbuf->field = V4L2_FIELD_NONE;
+               if (vbuf->field != V4L2_FIELD_NONE) {
+                       v4l2_warn(&ctx->dev->v4l2_dev,
+                                 "%s field isn't supported\n", __func__);
+                       return -EINVAL;
+               }
+       }
 
        if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
                v4l2_warn(&ctx->dev->v4l2_dev,
index 8339163a5231e37c5c0dcb926a175bfa64fd3507..4e24f5d781f4fe96da0e43648e13190eac578b49 100644 (file)
@@ -104,7 +104,7 @@ static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev,
                             struct v4l2_output *output)
 {
        struct vpbe_config *cfg = vpbe_dev->cfg;
-       int temp_index = output->index;
+       unsigned int temp_index = output->index;
 
        if (temp_index >= cfg->num_outputs)
                return -EINVAL;
index 37f0d7146dfa480fa3e7b9551177c29495ee7208..cb6a9e3946b6d8fcea499e8d8f5800700e26feae 100644 (file)
@@ -1527,23 +1527,20 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
        unsigned long size;
        struct videobuf_buffer *vb;
 
-       vb = q->bufs[b->index];
-
        if (!vout->streaming)
                return -EINVAL;
 
-       if (file->f_flags & O_NONBLOCK)
-               /* Call videobuf_dqbuf for non blocking mode */
-               ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
-       else
-               /* Call videobuf_dqbuf for  blocking mode */
-               ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
+       ret = videobuf_dqbuf(q, b, !!(file->f_flags & O_NONBLOCK));
+       if (ret)
+               return ret;
+
+       vb = q->bufs[b->index];
 
        addr = (unsigned long) vout->buf_phy_addr[vb->i];
        size = (unsigned long) vb->size;
        dma_unmap_single(vout->vid_dev->v4l2_dev.dev,  addr,
                                size, DMA_TO_DEVICE);
-       return ret;
+       return 0;
 }
 
 static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
index 799e526fd3df555441a0821a8948e35166f575b4..8f097e514900307ff2de242b08f4cdd07b9c3188 100644 (file)
@@ -68,6 +68,7 @@ struct rcar_csi2;
 /* Field Detection Control */
 #define FLD_REG                                0x1c
 #define FLD_FLD_NUM(n)                 (((n) & 0xff) << 16)
+#define FLD_DET_SEL(n)                 (((n) & 0x3) << 4)
 #define FLD_FLD_EN4                    BIT(3)
 #define FLD_FLD_EN3                    BIT(2)
 #define FLD_FLD_EN2                    BIT(1)
@@ -84,6 +85,9 @@ struct rcar_csi2;
 
 /* Interrupt Enable */
 #define INTEN_REG                      0x30
+#define INTEN_INT_AFIFO_OF             BIT(27)
+#define INTEN_INT_ERRSOTHS             BIT(4)
+#define INTEN_INT_ERRSOTSYNCHS         BIT(3)
 
 /* Interrupt Source Mask */
 #define INTCLOSE_REG                   0x34
@@ -475,7 +479,7 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp)
 static int rcsi2_start_receiver(struct rcar_csi2 *priv)
 {
        const struct rcar_csi2_format *format;
-       u32 phycnt, vcdt = 0, vcdt2 = 0;
+       u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0;
        unsigned int i;
        int mbps, ret;
 
@@ -507,6 +511,16 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
                        vcdt2 |= vcdt_part << ((i % 2) * 16);
        }
 
+       if (priv->mf.field == V4L2_FIELD_ALTERNATE) {
+               fld = FLD_DET_SEL(1) | FLD_FLD_EN4 | FLD_FLD_EN3 | FLD_FLD_EN2
+                       | FLD_FLD_EN;
+
+               if (priv->mf.height == 240)
+                       fld |= FLD_FLD_NUM(0);
+               else
+                       fld |= FLD_FLD_NUM(1);
+       }
+
        phycnt = PHYCNT_ENABLECLK;
        phycnt |= (1 << priv->lanes) - 1;
 
@@ -514,6 +528,10 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
        if (mbps < 0)
                return mbps;
 
+       /* Enable interrupts. */
+       rcsi2_write(priv, INTEN_REG, INTEN_INT_AFIFO_OF | INTEN_INT_ERRSOTHS
+                   | INTEN_INT_ERRSOTSYNCHS);
+
        /* Init */
        rcsi2_write(priv, TREF_REG, TREF_TREF);
        rcsi2_write(priv, PHTC_REG, 0);
@@ -549,8 +567,7 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
        rcsi2_write(priv, PHYCNT_REG, phycnt);
        rcsi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN |
                    LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP);
-       rcsi2_write(priv, FLD_REG, FLD_FLD_NUM(2) | FLD_FLD_EN4 |
-                   FLD_FLD_EN3 | FLD_FLD_EN2 | FLD_FLD_EN);
+       rcsi2_write(priv, FLD_REG, fld);
        rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ);
        rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ);
 
@@ -675,6 +692,43 @@ static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
        .pad    = &rcar_csi2_pad_ops,
 };
 
+static irqreturn_t rcsi2_irq(int irq, void *data)
+{
+       struct rcar_csi2 *priv = data;
+       u32 status, err_status;
+
+       status = rcsi2_read(priv, INTSTATE_REG);
+       err_status = rcsi2_read(priv, INTERRSTATE_REG);
+
+       if (!status)
+               return IRQ_HANDLED;
+
+       rcsi2_write(priv, INTSTATE_REG, status);
+
+       if (!err_status)
+               return IRQ_HANDLED;
+
+       rcsi2_write(priv, INTERRSTATE_REG, err_status);
+
+       dev_info(priv->dev, "Transfer error, restarting CSI-2 receiver\n");
+
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t rcsi2_irq_thread(int irq, void *data)
+{
+       struct rcar_csi2 *priv = data;
+
+       mutex_lock(&priv->lock);
+       rcsi2_stop(priv);
+       usleep_range(1000, 2000);
+       if (rcsi2_start(priv))
+               dev_warn(priv->dev, "Failed to restart CSI-2 receiver\n");
+       mutex_unlock(&priv->lock);
+
+       return IRQ_HANDLED;
+}
+
 /* -----------------------------------------------------------------------------
  * Async handling and registration of subdevices and links.
  */
@@ -947,7 +1001,7 @@ static int rcsi2_probe_resources(struct rcar_csi2 *priv,
                                 struct platform_device *pdev)
 {
        struct resource *res;
-       int irq;
+       int irq, ret;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        priv->base = devm_ioremap_resource(&pdev->dev, res);
@@ -958,6 +1012,12 @@ static int rcsi2_probe_resources(struct rcar_csi2 *priv,
        if (irq < 0)
                return irq;
 
+       ret = devm_request_threaded_irq(&pdev->dev, irq, rcsi2_irq,
+                                       rcsi2_irq_thread, IRQF_SHARED,
+                                       KBUILD_MODNAME, priv);
+       if (ret)
+               return ret;
+
        priv->rstc = devm_reset_control_get(&pdev->dev, NULL);
        if (IS_ERR(priv->rstc))
                return PTR_ERR(priv->rstc);
index 7fb3a4fa07c1e7d674a4a39e414b51f40f5656e7..447bdfbe5afe190ca2e5ca67ce990a9291729e7a 100644 (file)
@@ -334,8 +334,8 @@ static int tegra_cec_probe(struct platform_device *pdev)
 
        hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev);
 
-       if (!hdmi_dev)
-               return -ENODEV;
+       if (IS_ERR(hdmi_dev))
+               return PTR_ERR(hdmi_dev);
 
        cec = devm_kzalloc(&pdev->dev, sizeof(struct tegra_cec), GFP_KERNEL);
 
index 08929c087e270397f8d013102e6961f19e2f09b4..870a2a526e0b81440a2d91b1d752eef6a6106878 100644 (file)
@@ -186,12 +186,12 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
        dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n",
                data, size, dma->nr_pages);
 
-       err = get_user_pages_longterm(data & PAGE_MASK, dma->nr_pages,
-                            flags, dma->pages, NULL);
+       err = get_user_pages(data & PAGE_MASK, dma->nr_pages,
+                            flags | FOLL_LONGTERM, dma->pages, NULL);
 
        if (err != dma->nr_pages) {
                dma->nr_pages = (err >= 0) ? err : 0;
-               dprintk(1, "get_user_pages_longterm: err=%d [%d]\n", err,
+               dprintk(1, "get_user_pages: err=%d [%d]\n", err,
                        dma->nr_pages);
                return err < 0 ? err : -EINVAL;
        }
index c3748b414c27911e643d813b1d32281d3ef00a47..0322df9dc2497288f94a818b83bff4b42b15264f 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/of_device.h>
 #include <linux/regmap.h>
+#include <soc/at91/atmel-sfr.h>
 
 struct atmel_ebi_dev_config {
        int cs;
@@ -36,6 +37,7 @@ struct atmel_ebi_dev {
 struct atmel_ebi_caps {
        unsigned int available_cs;
        unsigned int ebi_csa_offs;
+       const char *regmap_name;
        void (*get_config)(struct atmel_ebi_dev *ebid,
                           struct atmel_ebi_dev_config *conf);
        int (*xlate_config)(struct atmel_ebi_dev *ebid,
@@ -47,7 +49,7 @@ struct atmel_ebi_caps {
 
 struct atmel_ebi {
        struct clk *clk;
-       struct regmap *matrix;
+       struct regmap *regmap;
        struct  {
                struct regmap *regmap;
                struct clk *clk;
@@ -357,7 +359,7 @@ static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np,
                 * one "atmel,smc-" property is present.
                 */
                if (ebi->caps->ebi_csa_offs && apply)
-                       regmap_update_bits(ebi->matrix,
+                       regmap_update_bits(ebi->regmap,
                                           ebi->caps->ebi_csa_offs,
                                           BIT(cs), 0);
 
@@ -372,6 +374,7 @@ static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np,
 static const struct atmel_ebi_caps at91sam9260_ebi_caps = {
        .available_cs = 0xff,
        .ebi_csa_offs = AT91SAM9260_MATRIX_EBICSA,
+       .regmap_name = "atmel,matrix",
        .get_config = at91sam9_ebi_get_config,
        .xlate_config = atmel_ebi_xslate_smc_config,
        .apply_config = at91sam9_ebi_apply_config,
@@ -380,6 +383,7 @@ static const struct atmel_ebi_caps at91sam9260_ebi_caps = {
 static const struct atmel_ebi_caps at91sam9261_ebi_caps = {
        .available_cs = 0xff,
        .ebi_csa_offs = AT91SAM9261_MATRIX_EBICSA,
+       .regmap_name = "atmel,matrix",
        .get_config = at91sam9_ebi_get_config,
        .xlate_config = atmel_ebi_xslate_smc_config,
        .apply_config = at91sam9_ebi_apply_config,
@@ -388,6 +392,7 @@ static const struct atmel_ebi_caps at91sam9261_ebi_caps = {
 static const struct atmel_ebi_caps at91sam9263_ebi0_caps = {
        .available_cs = 0x3f,
        .ebi_csa_offs = AT91SAM9263_MATRIX_EBI0CSA,
+       .regmap_name = "atmel,matrix",
        .get_config = at91sam9_ebi_get_config,
        .xlate_config = atmel_ebi_xslate_smc_config,
        .apply_config = at91sam9_ebi_apply_config,
@@ -396,6 +401,7 @@ static const struct atmel_ebi_caps at91sam9263_ebi0_caps = {
 static const struct atmel_ebi_caps at91sam9263_ebi1_caps = {
        .available_cs = 0x7,
        .ebi_csa_offs = AT91SAM9263_MATRIX_EBI1CSA,
+       .regmap_name = "atmel,matrix",
        .get_config = at91sam9_ebi_get_config,
        .xlate_config = atmel_ebi_xslate_smc_config,
        .apply_config = at91sam9_ebi_apply_config,
@@ -404,6 +410,7 @@ static const struct atmel_ebi_caps at91sam9263_ebi1_caps = {
 static const struct atmel_ebi_caps at91sam9rl_ebi_caps = {
        .available_cs = 0x3f,
        .ebi_csa_offs = AT91SAM9RL_MATRIX_EBICSA,
+       .regmap_name = "atmel,matrix",
        .get_config = at91sam9_ebi_get_config,
        .xlate_config = atmel_ebi_xslate_smc_config,
        .apply_config = at91sam9_ebi_apply_config,
@@ -412,6 +419,7 @@ static const struct atmel_ebi_caps at91sam9rl_ebi_caps = {
 static const struct atmel_ebi_caps at91sam9g45_ebi_caps = {
        .available_cs = 0x3f,
        .ebi_csa_offs = AT91SAM9G45_MATRIX_EBICSA,
+       .regmap_name = "atmel,matrix",
        .get_config = at91sam9_ebi_get_config,
        .xlate_config = atmel_ebi_xslate_smc_config,
        .apply_config = at91sam9_ebi_apply_config,
@@ -420,6 +428,7 @@ static const struct atmel_ebi_caps at91sam9g45_ebi_caps = {
 static const struct atmel_ebi_caps at91sam9x5_ebi_caps = {
        .available_cs = 0x3f,
        .ebi_csa_offs = AT91SAM9X5_MATRIX_EBICSA,
+       .regmap_name = "atmel,matrix",
        .get_config = at91sam9_ebi_get_config,
        .xlate_config = atmel_ebi_xslate_smc_config,
        .apply_config = at91sam9_ebi_apply_config,
@@ -432,6 +441,15 @@ static const struct atmel_ebi_caps sama5d3_ebi_caps = {
        .apply_config = sama5_ebi_apply_config,
 };
 
+static const struct atmel_ebi_caps sam9x60_ebi_caps = {
+       .available_cs = 0x3f,
+       .ebi_csa_offs = AT91_SFR_CCFG_EBICSA,
+       .regmap_name = "microchip,sfr",
+       .get_config = at91sam9_ebi_get_config,
+       .xlate_config = atmel_ebi_xslate_smc_config,
+       .apply_config = at91sam9_ebi_apply_config,
+};
+
 static const struct of_device_id atmel_ebi_id_table[] = {
        {
                .compatible = "atmel,at91sam9260-ebi",
@@ -465,6 +483,10 @@ static const struct of_device_id atmel_ebi_id_table[] = {
                .compatible = "atmel,sama5d3-ebi",
                .data = &sama5d3_ebi_caps,
        },
+       {
+               .compatible = "microchip,sam9x60-ebi",
+               .data = &sam9x60_ebi_caps,
+       },
        { /* sentinel */ }
 };
 
@@ -543,13 +565,14 @@ static int atmel_ebi_probe(struct platform_device *pdev)
 
        /*
         * The sama5d3 does not provide an EBICSA register and thus does need
-        * to access the matrix registers.
+        * to access it.
         */
        if (ebi->caps->ebi_csa_offs) {
-               ebi->matrix =
-                       syscon_regmap_lookup_by_phandle(np, "atmel,matrix");
-               if (IS_ERR(ebi->matrix))
-                       return PTR_ERR(ebi->matrix);
+               ebi->regmap =
+                       syscon_regmap_lookup_by_phandle(np,
+                                                       ebi->caps->regmap_name);
+               if (IS_ERR(ebi->regmap))
+                       return PTR_ERR(ebi->regmap);
        }
 
        ret = of_property_read_u32(np, "#address-cells", &val);
index 9e9f8037955d017898161c1a8e165786dc1a73dc..6b71fadb3cfacdbd26a71b852ba77a3a782be2c6 100644 (file)
 #define MCONNID_SHIFT                                  0
 #define MCONNID_MASK                                   (0xff << 0)
 
+/* READ_WRITE_LEVELING_CONTROL */
+#define RDWRLVLFULL_START                              0x80000000
+
 /* DDR_PHY_CTRL_1 - EMIF4D */
 #define DLL_SLAVE_DLY_CTRL_SHIFT_4D                    4
 #define DLL_SLAVE_DLY_CTRL_MASK_4D                     (0xFF << 4)
@@ -598,6 +601,7 @@ extern struct emif_regs_amx3 ti_emif_regs_amx3;
 
 void ti_emif_save_context(void);
 void ti_emif_restore_context(void);
+void ti_emif_run_hw_leveling(void);
 void ti_emif_enter_sr(void);
 void ti_emif_exit_sr(void);
 void ti_emif_abort_sr(void);
index 0a53598d982ff78bcd47a96798e239e9a6330d87..163b6c69e65193a5ed75028f85a53d3a5a90c813 100644 (file)
@@ -51,6 +51,9 @@
 #define MC_EMEM_ADR_CFG 0x54
 #define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0)
 
+#define MC_TIMING_CONTROL              0xfc
+#define MC_TIMING_UPDATE               BIT(0)
+
 static const struct of_device_id tegra_mc_of_match[] = {
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
        { .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc },
@@ -74,7 +77,7 @@ static const struct of_device_id tegra_mc_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
 
-static int terga_mc_block_dma_common(struct tegra_mc *mc,
+static int tegra_mc_block_dma_common(struct tegra_mc *mc,
                                     const struct tegra_mc_reset *rst)
 {
        unsigned long flags;
@@ -90,13 +93,13 @@ static int terga_mc_block_dma_common(struct tegra_mc *mc,
        return 0;
 }
 
-static bool terga_mc_dma_idling_common(struct tegra_mc *mc,
+static bool tegra_mc_dma_idling_common(struct tegra_mc *mc,
                                       const struct tegra_mc_reset *rst)
 {
        return (mc_readl(mc, rst->status) & BIT(rst->bit)) != 0;
 }
 
-static int terga_mc_unblock_dma_common(struct tegra_mc *mc,
+static int tegra_mc_unblock_dma_common(struct tegra_mc *mc,
                                       const struct tegra_mc_reset *rst)
 {
        unsigned long flags;
@@ -112,17 +115,17 @@ static int terga_mc_unblock_dma_common(struct tegra_mc *mc,
        return 0;
 }
 
-static int terga_mc_reset_status_common(struct tegra_mc *mc,
+static int tegra_mc_reset_status_common(struct tegra_mc *mc,
                                        const struct tegra_mc_reset *rst)
 {
        return (mc_readl(mc, rst->control) & BIT(rst->bit)) != 0;
 }
 
-const struct tegra_mc_reset_ops terga_mc_reset_ops_common = {
-       .block_dma = terga_mc_block_dma_common,
-       .dma_idling = terga_mc_dma_idling_common,
-       .unblock_dma = terga_mc_unblock_dma_common,
-       .reset_status = terga_mc_reset_status_common,
+const struct tegra_mc_reset_ops tegra_mc_reset_ops_common = {
+       .block_dma = tegra_mc_block_dma_common,
+       .dma_idling = tegra_mc_dma_idling_common,
+       .unblock_dma = tegra_mc_unblock_dma_common,
+       .reset_status = tegra_mc_reset_status_common,
 };
 
 static inline struct tegra_mc *reset_to_mc(struct reset_controller_dev *rcdev)
@@ -282,25 +285,28 @@ static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
        u32 value;
 
        /* compute the number of MC clock cycles per tick */
-       tick = mc->tick * clk_get_rate(mc->clk);
+       tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk);
        do_div(tick, NSEC_PER_SEC);
 
-       value = readl(mc->regs + MC_EMEM_ARB_CFG);
+       value = mc_readl(mc, MC_EMEM_ARB_CFG);
        value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK;
        value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick);
-       writel(value, mc->regs + MC_EMEM_ARB_CFG);
+       mc_writel(mc, value, MC_EMEM_ARB_CFG);
 
        /* write latency allowance defaults */
        for (i = 0; i < mc->soc->num_clients; i++) {
                const struct tegra_mc_la *la = &mc->soc->clients[i].la;
                u32 value;
 
-               value = readl(mc->regs + la->reg);
+               value = mc_readl(mc, la->reg);
                value &= ~(la->mask << la->shift);
                value |= (la->def & la->mask) << la->shift;
-               writel(value, mc->regs + la->reg);
+               mc_writel(mc, value, la->reg);
        }
 
+       /* latch new values */
+       mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL);
+
        return 0;
 }
 
index 887a3b07334f15b35451e3963d143abba9526051..392993955c9337ba1b273123906a5a45a94c76f9 100644 (file)
@@ -35,7 +35,7 @@ static inline void mc_writel(struct tegra_mc *mc, u32 value,
        writel_relaxed(value, mc->regs + offset);
 }
 
-extern const struct tegra_mc_reset_ops terga_mc_reset_ops_common;
+extern const struct tegra_mc_reset_ops tegra_mc_reset_ops_common;
 
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
 extern const struct tegra_mc_soc tegra20_mc_soc;
index 6560a5101322daeda8f67b329b90bd0de8cba3b5..62305fafd641a885acdbb0e7cc8b426a86f8a67e 100644 (file)
@@ -572,7 +572,7 @@ static const struct tegra_mc_client tegra114_mc_clients[] = {
                },
        }, {
                .id = 0x34,
-               .name = "fdcwr2",
+               .name = "fdcdwr2",
                .swgroup = TEGRA_SWGROUP_NV,
                .smmu = {
                        .reg = 0x22c,
@@ -975,7 +975,7 @@ const struct tegra_mc_soc tegra114_mc_soc = {
        .smmu = &tegra114_smmu_soc,
        .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
                   MC_INT_DECERR_EMEM,
-       .reset_ops = &terga_mc_reset_ops_common,
+       .reset_ops = &tegra_mc_reset_ops_common,
        .resets = tegra114_mc_resets,
        .num_resets = ARRAY_SIZE(tegra114_mc_resets),
 };
index eedb7d48e2ea76586458bf4abaa92ce45247478b..772716ab6b232c760cb4db743590232a10c2c377 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/clkdev.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
index b561a1fe7f46a4e583d69be92f964bf001556095..8f8487bda642bfa8b2673e56fae8bd5c29b0e7de 100644 (file)
@@ -1074,7 +1074,7 @@ const struct tegra_mc_soc tegra124_mc_soc = {
        .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
                   MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
                   MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
-       .reset_ops = &terga_mc_reset_ops_common,
+       .reset_ops = &tegra_mc_reset_ops_common,
        .resets = tegra124_mc_resets,
        .num_resets = ARRAY_SIZE(tegra124_mc_resets),
 };
@@ -1104,7 +1104,7 @@ const struct tegra_mc_soc tegra132_mc_soc = {
        .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
                   MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
                   MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
-       .reset_ops = &terga_mc_reset_ops_common,
+       .reset_ops = &tegra_mc_reset_ops_common,
        .resets = tegra124_mc_resets,
        .num_resets = ARRAY_SIZE(tegra124_mc_resets),
 };
index 7119e532471cc395016cd883cfa427044cdd7a04..121237b16add910289c36ab9bba4f3f76795c876 100644 (file)
@@ -198,7 +198,7 @@ static const struct tegra_mc_reset tegra20_mc_resets[] = {
        TEGRA20_MC_RESET(VI,     0x100, 0x178, 0x104, 14),
 };
 
-static int terga20_mc_hotreset_assert(struct tegra_mc *mc,
+static int tegra20_mc_hotreset_assert(struct tegra_mc *mc,
                                      const struct tegra_mc_reset *rst)
 {
        unsigned long flags;
@@ -214,7 +214,7 @@ static int terga20_mc_hotreset_assert(struct tegra_mc *mc,
        return 0;
 }
 
-static int terga20_mc_hotreset_deassert(struct tegra_mc *mc,
+static int tegra20_mc_hotreset_deassert(struct tegra_mc *mc,
                                        const struct tegra_mc_reset *rst)
 {
        unsigned long flags;
@@ -230,7 +230,7 @@ static int terga20_mc_hotreset_deassert(struct tegra_mc *mc,
        return 0;
 }
 
-static int terga20_mc_block_dma(struct tegra_mc *mc,
+static int tegra20_mc_block_dma(struct tegra_mc *mc,
                                const struct tegra_mc_reset *rst)
 {
        unsigned long flags;
@@ -246,19 +246,19 @@ static int terga20_mc_block_dma(struct tegra_mc *mc,
        return 0;
 }
 
-static bool terga20_mc_dma_idling(struct tegra_mc *mc,
+static bool tegra20_mc_dma_idling(struct tegra_mc *mc,
                                  const struct tegra_mc_reset *rst)
 {
        return mc_readl(mc, rst->status) == 0;
 }
 
-static int terga20_mc_reset_status(struct tegra_mc *mc,
+static int tegra20_mc_reset_status(struct tegra_mc *mc,
                                   const struct tegra_mc_reset *rst)
 {
        return (mc_readl(mc, rst->reset) & BIT(rst->bit)) == 0;
 }
 
-static int terga20_mc_unblock_dma(struct tegra_mc *mc,
+static int tegra20_mc_unblock_dma(struct tegra_mc *mc,
                                  const struct tegra_mc_reset *rst)
 {
        unsigned long flags;
@@ -274,13 +274,13 @@ static int terga20_mc_unblock_dma(struct tegra_mc *mc,
        return 0;
 }
 
-const struct tegra_mc_reset_ops terga20_mc_reset_ops = {
-       .hotreset_assert = terga20_mc_hotreset_assert,
-       .hotreset_deassert = terga20_mc_hotreset_deassert,
-       .block_dma = terga20_mc_block_dma,
-       .dma_idling = terga20_mc_dma_idling,
-       .unblock_dma = terga20_mc_unblock_dma,
-       .reset_status = terga20_mc_reset_status,
+static const struct tegra_mc_reset_ops tegra20_mc_reset_ops = {
+       .hotreset_assert = tegra20_mc_hotreset_assert,
+       .hotreset_deassert = tegra20_mc_hotreset_deassert,
+       .block_dma = tegra20_mc_block_dma,
+       .dma_idling = tegra20_mc_dma_idling,
+       .unblock_dma = tegra20_mc_unblock_dma,
+       .reset_status = tegra20_mc_reset_status,
 };
 
 const struct tegra_mc_soc tegra20_mc_soc = {
@@ -290,7 +290,7 @@ const struct tegra_mc_soc tegra20_mc_soc = {
        .client_id_mask = 0x3f,
        .intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
                   MC_INT_DECERR_EMEM,
-       .reset_ops = &terga20_mc_reset_ops,
+       .reset_ops = &tegra20_mc_reset_ops,
        .resets = tegra20_mc_resets,
        .num_resets = ARRAY_SIZE(tegra20_mc_resets),
 };
index d00a771604072656b195c8510e31c96ce850d1bb..aa22cda637eb2a6ca6c95f881a99f507d50aefd6 100644 (file)
@@ -1132,7 +1132,7 @@ const struct tegra_mc_soc tegra210_mc_soc = {
        .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
                   MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
                   MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
-       .reset_ops = &terga_mc_reset_ops_common,
+       .reset_ops = &tegra_mc_reset_ops_common,
        .resets = tegra210_mc_resets,
        .num_resets = ARRAY_SIZE(tegra210_mc_resets),
 };
index bee5314ed404d5d0af56fb1a542766106ad50b7b..c9af0f682ead7623b68572d77a13e28376cf2bab 100644 (file)
@@ -726,7 +726,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
                },
        }, {
                .id = 0x34,
-               .name = "fdcwr2",
+               .name = "fdcdwr2",
                .swgroup = TEGRA_SWGROUP_NV2,
                .smmu = {
                        .reg = 0x22c,
@@ -999,7 +999,7 @@ const struct tegra_mc_soc tegra30_mc_soc = {
        .smmu = &tegra30_smmu_soc,
        .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
                   MC_INT_DECERR_EMEM,
-       .reset_ops = &terga_mc_reset_ops_common,
+       .reset_ops = &tegra_mc_reset_ops_common,
        .resets = tegra30_mc_resets,
        .num_resets = ARRAY_SIZE(tegra30_mc_resets),
 };
index 2250d03ea17f63f5ad79b8e860aeb6c1383a6047..ab07aa163138aa69ceb20f7300c28c997e0bfb9a 100644 (file)
@@ -138,6 +138,9 @@ static int ti_emif_alloc_sram(struct device *dev,
        emif_data->pm_functions.exit_sr =
                sram_resume_address(emif_data,
                                    (unsigned long)ti_emif_exit_sr);
+       emif_data->pm_functions.run_hw_leveling =
+               sram_resume_address(emif_data,
+                                   (unsigned long)ti_emif_run_hw_leveling);
 
        emif_data->pm_data.regs_virt =
                (struct emif_regs_amx3 *)emif_data->ti_emif_sram_data_virt;
index a5369181e5c288b9cae4a24523a0d0102986de3d..d75ae18efa7dda079da080183f4662af1877dc47 100644 (file)
@@ -27,6 +27,7 @@
 #define EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK         0x0700
 
 #define EMIF_SDCFG_TYPE_DDR2                           0x2 << SDRAM_TYPE_SHIFT
+#define EMIF_SDCFG_TYPE_DDR3                           0x3 << SDRAM_TYPE_SHIFT
 #define EMIF_STATUS_READY                              0x4
 
 #define AM43XX_EMIF_PHY_CTRL_REG_COUNT                  0x120
@@ -244,6 +245,46 @@ emif_skip_restore_extra_regs:
        mov     pc, lr
 ENDPROC(ti_emif_restore_context)
 
+/*
+ * void ti_emif_run_hw_leveling(void)
+ *
+ * Used during resume to run hardware leveling again and restore the
+ * configuration of the EMIF PHY, only for DDR3.
+ */
+ENTRY(ti_emif_run_hw_leveling)
+       adr     r4, ti_emif_pm_sram_data
+       ldr     r0, [r4, #EMIF_PM_BASE_ADDR_PHYS_OFFSET]
+
+       ldr     r3, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL]
+       orr     r3, r3, #RDWRLVLFULL_START
+       ldr     r2, [r0, #EMIF_SDRAM_CONFIG]
+       and     r2, r2, #SDRAM_TYPE_MASK
+       cmp     r2, #EMIF_SDCFG_TYPE_DDR3
+       bne     skip_hwlvl
+
+       str     r3, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL]
+
+       /*
+        * If EMIF registers are touched during initial stage of HW
+        * leveling sequence there will be an L3 NOC timeout error issued
+        * as the EMIF will not respond, which is not fatal, but it is
+        * avoidable. This small wait loop is enough time for this condition
+        * to clear, even at worst case of CPU running at max speed of 1Ghz.
+        */
+       mov     r2, #0x2000
+1:
+       subs    r2, r2, #0x1
+       bne     1b
+
+       /* Bit clears when operation is complete */
+2:     ldr     r1, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL]
+       tst     r1, #RDWRLVLFULL_START
+       bne     2b
+
+skip_hwlvl:
+       mov     pc, lr
+ENDPROC(ti_emif_run_hw_leveling)
+
 /*
  * void ti_emif_enter_sr(void)
  *
index 26ad6468d13a786552f581e3f45eb444febf0b51..294d9567cc71c0de691617c1191b8b9baf5056d1 100644 (file)
@@ -16,7 +16,7 @@ config MFD_CS5535
        depends on PCI && (X86_32 || (X86 && COMPILE_TEST))
        ---help---
          This is the core driver for CS5535/CS5536 MFD functions.  This is
-          necessary for using the board's GPIO and MFGPT functionality.
+         necessary for using the board's GPIO and MFGPT functionality.
 
 config MFD_ALTERA_A10SR
        bool "Altera Arria10 DevKit System Resource chip"
@@ -29,6 +29,16 @@ config MFD_ALTERA_A10SR
          accessing the external gpio extender (LEDs & buttons) and
          power supply alarms (hwmon).
 
+config MFD_ALTERA_SYSMGR
+       bool "Altera SOCFPGA System Manager"
+       depends on (ARCH_SOCFPGA || ARCH_STRATIX10) && OF
+       select MFD_SYSCON
+       help
+         Select this to get System Manager support for all Altera branded
+         SOCFPGAs. The SOCFPGA System Manager handles all SOCFPGAs by
+         using regmap_mmio accesses for ARM32 parts and SMC calls to
+         EL3 for ARM64 parts.
+
 config MFD_ACT8945A
        tristate "Active-semi ACT8945A"
        select MFD_CORE
@@ -213,13 +223,13 @@ config MFD_CROS_EC
          protocol for talking to the EC is defined by the bus driver.
 
 config MFD_CROS_EC_CHARDEV
-        tristate "Chrome OS Embedded Controller userspace device interface"
-        depends on MFD_CROS_EC
-        ---help---
-          This driver adds support to talk with the ChromeOS EC from userspace.
+       tristate "Chrome OS Embedded Controller userspace device interface"
+       depends on MFD_CROS_EC
+       ---help---
+         This driver adds support to talk with the ChromeOS EC from userspace.
 
-          If you have a supported Chromebook, choose Y or M here.
-          The module will be called cros_ec_dev.
+         If you have a supported Chromebook, choose Y or M here.
+         The module will be called cros_ec_dev.
 
 config MFD_MADERA
        tristate "Cirrus Logic Madera codecs"
@@ -733,6 +743,20 @@ config MFD_MAX77620
          provides common support for accessing the device; additional drivers
          must be enabled in order to use the functionality of the device.
 
+config MFD_MAX77650
+       tristate "Maxim MAX77650/77651 PMIC Support"
+       depends on I2C
+       depends on OF || COMPILE_TEST
+       select MFD_CORE
+       select REGMAP_I2C
+       help
+         Say Y here to add support for Maxim Semiconductor MAX77650 and
+         MAX77651 Power Management ICs. This is the core multifunction
+         driver for interacting with the device. The module name is
+         'max77650'. Additional drivers can be enabled in order to use
+         the following functionalities of the device: GPIO, regulator,
+         charger, LED, onkey.
+
 config MFD_MAX77686
        tristate "Maxim Semiconductor MAX77686/802 PMIC Support"
        depends on I2C
@@ -867,7 +891,7 @@ config MFD_CPCAP
          At least Motorola Droid 4 is known to use CPCAP.
 
 config MFD_VIPERBOARD
-        tristate "Nano River Technologies Viperboard"
+       tristate "Nano River Technologies Viperboard"
        select MFD_CORE
        depends on USB
        default n
@@ -903,15 +927,15 @@ config PCF50633_ADC
        tristate "NXP PCF50633 ADC"
        depends on MFD_PCF50633
        help
-        Say yes here if you want to include support for ADC in the
-        NXP PCF50633 chip.
+         Say yes here if you want to include support for ADC in the
+         NXP PCF50633 chip.
 
 config PCF50633_GPIO
        tristate "NXP PCF50633 GPIO"
        depends on MFD_PCF50633
        help
-        Say yes here if you want to include support GPIO for pins on
-        the PCF50633 chip.
+         Say yes here if you want to include support GPIO for pins on
+         the PCF50633 chip.
 
 config UCB1400_CORE
        tristate "Philips UCB1400 Core driver"
@@ -1026,7 +1050,7 @@ config MFD_RN5T618
        select REGMAP_I2C
        help
          Say yes here to add support for the Ricoh RN5T567,
-          RN5T618, RC5T619 PMIC.
+         RN5T618, RC5T619 PMIC.
          This driver provides common support for accessing the device,
          additional drivers must be enabled in order to use the
          functionality of the device.
@@ -1079,9 +1103,9 @@ config MFD_SM501_GPIO
        bool "Export GPIO via GPIO layer"
        depends on MFD_SM501 && GPIOLIB
         ---help---
-        This option uses the gpio library layer to export the 64 GPIO
-        lines on the SM501. The platform data is used to supply the
-        base number for the first GPIO line to register.
+         This option uses the gpio library layer to export the 64 GPIO
+         lines on the SM501. The platform data is used to supply the
+         base number for the first GPIO line to register.
 
 config MFD_SKY81452
        tristate "Skyworks Solutions SKY81452"
@@ -1096,16 +1120,16 @@ config MFD_SKY81452
          will be called sky81452.
 
 config MFD_SMSC
-       bool "SMSC ECE1099 series chips"
-       depends on I2C=y
-       select MFD_CORE
-       select REGMAP_I2C
-       help
-        If you say yes here you get support for the
-        ece1099 chips from SMSC.
+       bool "SMSC ECE1099 series chips"
+       depends on I2C=y
+       select MFD_CORE
+       select REGMAP_I2C
+       help
+         If you say yes here you get support for the
+         ece1099 chips from SMSC.
 
-        To compile this driver as a module, choose M here: the
-        module will be called smsc.
+         To compile this driver as a module, choose M here: the
+         module will be called smsc.
 
 config MFD_SC27XX_PMIC
        tristate "Spreadtrum SC27xx PMICs"
@@ -1171,12 +1195,12 @@ config AB8500_CORE
          This chip embeds various other multimedia funtionalities as well.
 
 config AB8500_DEBUG
-       bool "Enable debug info via debugfs"
-       depends on AB8500_GPADC && DEBUG_FS
-       default y if DEBUG_FS
-       help
-         Select this option if you want debug information using the debug
-         filesystem, debugfs.
+       bool "Enable debug info via debugfs"
+       depends on AB8500_GPADC && DEBUG_FS
+       default y if DEBUG_FS
+       help
+         Select this option if you want debug information using the debug
+         filesystem, debugfs.
 
 config AB8500_GPADC
        bool "ST-Ericsson AB8500 GPADC driver"
@@ -1907,6 +1931,19 @@ config MFD_STPMIC1
          To compile this driver as a module, choose M here: the
          module will be called stpmic1.
 
+config MFD_STMFX
+       tristate "Support for STMicroelectronics Multi-Function eXpander (STMFX)"
+       depends on I2C
+       depends on OF || COMPILE_TEST
+       select MFD_CORE
+       select REGMAP_I2C
+       help
+         Support for the STMicroelectronics Multi-Function eXpander.
+
+         This driver provides common support for accessing the device,
+         additional drivers must be enabled in order to use the functionality
+         of the device.
+
 menu "Multimedia Capabilities Port drivers"
        depends on ARCH_SA1100
 
index b4569ed7f3f324b5ca3b1b5fd27d8a88f2e4e79d..52b1a90ff5159308c984b8ea319d2ba848755b5f 100644 (file)
@@ -155,6 +155,7 @@ obj-$(CONFIG_MFD_DA9150)    += da9150-core.o
 
 obj-$(CONFIG_MFD_MAX14577)     += max14577.o
 obj-$(CONFIG_MFD_MAX77620)     += max77620.o
+obj-$(CONFIG_MFD_MAX77650)     += max77650.o
 obj-$(CONFIG_MFD_MAX77686)     += max77686.o
 obj-$(CONFIG_MFD_MAX77693)     += max77693.o
 obj-$(CONFIG_MFD_MAX77843)     += max77843.o
@@ -237,6 +238,7 @@ obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI)       += intel_soc_pmic_chtdc_ti.o
 obj-$(CONFIG_MFD_MT6397)       += mt6397-core.o
 
 obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
+obj-$(CONFIG_MFD_ALTERA_SYSMGR) += altera-sysmgr.o
 obj-$(CONFIG_MFD_STPMIC1)      += stpmic1.o
 obj-$(CONFIG_MFD_SUN4I_GPADC)  += sun4i-gpadc.o
 
@@ -246,4 +248,4 @@ obj-$(CONFIG_MFD_MXS_LRADC)     += mxs-lradc.o
 obj-$(CONFIG_MFD_SC27XX_PMIC)  += sprd-sc27xx-spi.o
 obj-$(CONFIG_RAVE_SP_CORE)     += rave-sp.o
 obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
-
+obj-$(CONFIG_MFD_STMFX)        += stmfx.o
index 8d652b2f9d14f084e22b0db984236f8407f27254..f70d3f6a959bc9b91cef1370add0e665c523056a 100644 (file)
@@ -2587,7 +2587,7 @@ static ssize_t ab8500_unsubscribe_write(struct file *file,
 }
 
 /*
- * - several deubgfs nodes fops
+ * - several debugfs nodes fops
  */
 
 static const struct file_operations ab8500_bank_fops = {
diff --git a/drivers/mfd/altera-sysmgr.c b/drivers/mfd/altera-sysmgr.c
new file mode 100644 (file)
index 0000000..8976f82
--- /dev/null
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Copyright (C) 2018-2019, Intel Corporation.
+ *  Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *  Copyright (C) 2012 Linaro Ltd.
+ *
+ *  Based on syscon driver.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mfd/altera-sysmgr.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/**
+ * struct altr_sysmgr - Altera SOCFPGA System Manager
+ * @regmap: the regmap used for System Manager accesses.
+ * @base  : the base address for the System Manager
+ */
+struct altr_sysmgr {
+       struct regmap   *regmap;
+       resource_size_t *base;
+};
+
+static struct platform_driver altr_sysmgr_driver;
+
+/**
+ * s10_protected_reg_write
+ * Write to a protected SMC register.
+ * @base: Base address of System Manager
+ * @reg:  Address offset of register
+ * @val:  Value to write
+ * Return: INTEL_SIP_SMC_STATUS_OK (0) on success
+ *        INTEL_SIP_SMC_REG_ERROR on error
+ *        INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION if not supported
+ */
+static int s10_protected_reg_write(void *base,
+                                  unsigned int reg, unsigned int val)
+{
+       struct arm_smccc_res result;
+       unsigned long sysmgr_base = (unsigned long)base;
+
+       arm_smccc_smc(INTEL_SIP_SMC_REG_WRITE, sysmgr_base + reg,
+                     val, 0, 0, 0, 0, 0, &result);
+
+       return (int)result.a0;
+}
+
+/**
+ * s10_protected_reg_read
+ * Read the status of a protected SMC register
+ * @base: Base address of System Manager.
+ * @reg:  Address of register
+ * @val:  Value read.
+ * Return: INTEL_SIP_SMC_STATUS_OK (0) on success
+ *        INTEL_SIP_SMC_REG_ERROR on error
+ *        INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION if not supported
+ */
+static int s10_protected_reg_read(void *base,
+                                 unsigned int reg, unsigned int *val)
+{
+       struct arm_smccc_res result;
+       unsigned long sysmgr_base = (unsigned long)base;
+
+       arm_smccc_smc(INTEL_SIP_SMC_REG_READ, sysmgr_base + reg,
+                     0, 0, 0, 0, 0, 0, &result);
+
+       *val = (unsigned int)result.a1;
+
+       return (int)result.a0;
+}
+
+static struct regmap_config altr_sysmgr_regmap_cfg = {
+       .name = "altr_sysmgr",
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .fast_io = true,
+       .use_single_read = true,
+       .use_single_write = true,
+};
+
+/**
+ * sysmgr_match_phandle
+ * Matching function used by driver_find_device().
+ * Return: True if match is found, otherwise false.
+ */
+static int sysmgr_match_phandle(struct device *dev, void *data)
+{
+       return dev->of_node == (struct device_node *)data;
+}
+
+/**
+ * altr_sysmgr_regmap_lookup_by_phandle
+ * Find the sysmgr previous configured in probe() and return regmap property.
+ * Return: regmap if found or error if not found.
+ */
+struct regmap *altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np,
+                                                   const char *property)
+{
+       struct device *dev;
+       struct altr_sysmgr *sysmgr;
+       struct device_node *sysmgr_np;
+
+       if (property)
+               sysmgr_np = of_parse_phandle(np, property, 0);
+       else
+               sysmgr_np = np;
+
+       if (!sysmgr_np)
+               return ERR_PTR(-ENODEV);
+
+       dev = driver_find_device(&altr_sysmgr_driver.driver, NULL,
+                                (void *)sysmgr_np, sysmgr_match_phandle);
+       of_node_put(sysmgr_np);
+       if (!dev)
+               return ERR_PTR(-EPROBE_DEFER);
+
+       sysmgr = dev_get_drvdata(dev);
+
+       return sysmgr->regmap;
+}
+EXPORT_SYMBOL_GPL(altr_sysmgr_regmap_lookup_by_phandle);
+
+static int sysmgr_probe(struct platform_device *pdev)
+{
+       struct altr_sysmgr *sysmgr;
+       struct regmap *regmap;
+       struct resource *res;
+       struct regmap_config sysmgr_config = altr_sysmgr_regmap_cfg;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+
+       sysmgr = devm_kzalloc(dev, sizeof(*sysmgr), GFP_KERNEL);
+       if (!sysmgr)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENOENT;
+
+       sysmgr_config.max_register = resource_size(res) -
+                                    sysmgr_config.reg_stride;
+       if (of_device_is_compatible(np, "altr,sys-mgr-s10")) {
+               /* Need physical address for SMCC call */
+               sysmgr->base = (resource_size_t *)res->start;
+               sysmgr_config.reg_read = s10_protected_reg_read;
+               sysmgr_config.reg_write = s10_protected_reg_write;
+
+               regmap = devm_regmap_init(dev, NULL, sysmgr->base,
+                                         &sysmgr_config);
+       } else {
+               sysmgr->base = devm_ioremap(dev, res->start,
+                                           resource_size(res));
+               if (!sysmgr->base)
+                       return -ENOMEM;
+
+               sysmgr_config.max_register = res->end - res->start - 3;
+               regmap = devm_regmap_init_mmio(dev, sysmgr->base,
+                                              &sysmgr_config);
+       }
+
+       if (IS_ERR(regmap)) {
+               pr_err("regmap init failed\n");
+               return PTR_ERR(regmap);
+       }
+
+       sysmgr->regmap = regmap;
+
+       platform_set_drvdata(pdev, sysmgr);
+
+       return 0;
+}
+
+static const struct of_device_id altr_sysmgr_of_match[] = {
+       { .compatible = "altr,sys-mgr" },
+       { .compatible = "altr,sys-mgr-s10" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, altr_sysmgr_of_match);
+
+static struct platform_driver altr_sysmgr_driver = {
+       .probe =  sysmgr_probe,
+       .driver = {
+               .name = "altr,system_manager",
+               .of_match_table = altr_sysmgr_of_match,
+       },
+};
+
+static int __init altr_sysmgr_init(void)
+{
+       return platform_driver_register(&altr_sysmgr_driver);
+}
+core_initcall(altr_sysmgr_init);
+
+static void __exit altr_sysmgr_exit(void)
+{
+       platform_driver_unregister(&altr_sysmgr_driver);
+}
+module_exit(altr_sysmgr_exit);
+
+MODULE_AUTHOR("Thor Thayer <>");
+MODULE_DESCRIPTION("SOCFPGA System Manager driver");
+MODULE_LICENSE("GPL v2");
index e82543bcfdc828502dd4124262be0650dfcb7b01..35a9e16f9902cf49444b278ed7c7b2ce790029e9 100644 (file)
@@ -141,6 +141,7 @@ static const struct of_device_id atmel_hlcdc_match[] = {
        { .compatible = "atmel,sama5d2-hlcdc" },
        { .compatible = "atmel,sama5d3-hlcdc" },
        { .compatible = "atmel,sama5d4-hlcdc" },
+       { .compatible = "microchip,sam9x60-hlcdc" },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, atmel_hlcdc_match);
index a7b7c5423ea5b201e9c5e4c465ed6c38ebbe47ee..c2e8a0dee7f86fca9e02d00fbdceab229817ffc8 100644 (file)
@@ -65,6 +65,7 @@ static const struct of_device_id axp20x_i2c_of_match[] = {
        { .compatible = "x-powers,axp202", .data = (void *)AXP202_ID },
        { .compatible = "x-powers,axp209", .data = (void *)AXP209_ID },
        { .compatible = "x-powers,axp221", .data = (void *)AXP221_ID },
+       { .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
        { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID },
        { },
 };
@@ -75,6 +76,7 @@ static const struct i2c_device_id axp20x_i2c_id[] = {
        { "axp202", 0 },
        { "axp209", 0 },
        { "axp221", 0 },
+       { "axp223", 0 },
        { "axp806", 0 },
        { },
 };
index 3c97f2c0fdfed37288d9e57744f3e97df2b2725d..2215660dfa05736c39a3b779b1772821704674f1 100644 (file)
@@ -198,6 +198,12 @@ static const struct resource axp22x_usb_power_supply_resources[] = {
        DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"),
 };
 
+/* AXP803 and AXP813/AXP818 share the same interrupts */
+static const struct resource axp803_usb_power_supply_resources[] = {
+       DEFINE_RES_IRQ_NAMED(AXP803_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"),
+       DEFINE_RES_IRQ_NAMED(AXP803_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"),
+};
+
 static const struct resource axp22x_pek_resources[] = {
        DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
        DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
@@ -741,6 +747,11 @@ static const struct mfd_cell axp803_cells[] = {
                .of_compatible  = "x-powers,axp813-ac-power-supply",
                .num_resources  = ARRAY_SIZE(axp20x_ac_power_supply_resources),
                .resources      = axp20x_ac_power_supply_resources,
+       }, {
+               .name           = "axp20x-usb-power-supply",
+               .num_resources  = ARRAY_SIZE(axp803_usb_power_supply_resources),
+               .resources      = axp803_usb_power_supply_resources,
+               .of_compatible  = "x-powers,axp813-usb-power-supply",
        },
        {       .name           = "axp20x-regulator" },
 };
@@ -793,6 +804,11 @@ static const struct mfd_cell axp813_cells[] = {
                .of_compatible  = "x-powers,axp813-ac-power-supply",
                .num_resources  = ARRAY_SIZE(axp20x_ac_power_supply_resources),
                .resources      = axp20x_ac_power_supply_resources,
+       }, {
+               .name           = "axp20x-usb-power-supply",
+               .num_resources  = ARRAY_SIZE(axp803_usb_power_supply_resources),
+               .resources      = axp803_usb_power_supply_resources,
+               .of_compatible  = "x-powers,axp813-usb-power-supply",
        },
 };
 
index 6acfe036d5222adfe23e36519eee76435bfa160e..bd2bcdd4718b2f9a4971eb10f5b94b022ea7dbc8 100644 (file)
@@ -75,20 +75,49 @@ static irqreturn_t ec_irq_thread(int irq, void *data)
 
 static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
 {
+       int ret;
        struct {
                struct cros_ec_command msg;
-               struct ec_params_host_sleep_event req;
+               union {
+                       struct ec_params_host_sleep_event req0;
+                       struct ec_params_host_sleep_event_v1 req1;
+                       struct ec_response_host_sleep_event_v1 resp1;
+               } u;
        } __packed buf;
 
        memset(&buf, 0, sizeof(buf));
 
-       buf.req.sleep_event = sleep_event;
+       if (ec_dev->host_sleep_v1) {
+               buf.u.req1.sleep_event = sleep_event;
+               buf.u.req1.suspend_params.sleep_timeout_ms =
+                               EC_HOST_SLEEP_TIMEOUT_DEFAULT;
+
+               buf.msg.outsize = sizeof(buf.u.req1);
+               if ((sleep_event == HOST_SLEEP_EVENT_S3_RESUME) ||
+                   (sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME))
+                       buf.msg.insize = sizeof(buf.u.resp1);
+
+               buf.msg.version = 1;
+
+       } else {
+               buf.u.req0.sleep_event = sleep_event;
+               buf.msg.outsize = sizeof(buf.u.req0);
+       }
 
        buf.msg.command = EC_CMD_HOST_SLEEP_EVENT;
-       buf.msg.version = 0;
-       buf.msg.outsize = sizeof(buf.req);
 
-       return cros_ec_cmd_xfer(ec_dev, &buf.msg);
+       ret = cros_ec_cmd_xfer(ec_dev, &buf.msg);
+
+       /* For now, report failure to transition to S0ix with a warning. */
+       if (ret >= 0 && ec_dev->host_sleep_v1 &&
+           (sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME))
+               WARN_ONCE(buf.u.resp1.resume_response.sleep_transitions &
+                         EC_HOST_RESUME_SLEEP_TIMEOUT,
+                         "EC detected sleep transition timeout. Total slp_s0 transitions: %d",
+                         buf.u.resp1.resume_response.sleep_transitions &
+                         EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK);
+
+       return ret;
 }
 
 int cros_ec_register(struct cros_ec_device *ec_dev)
index d275deaecb12540e042ef466605867c2c01cfe0e..54a58df571b6fec2dd296ed53882bb4cd9c8237f 100644 (file)
@@ -385,7 +385,8 @@ static const struct mfd_cell cros_ec_rtc_cells[] = {
 };
 
 static const struct mfd_cell cros_usbpd_charger_cells[] = {
-       { .name = "cros-usbpd-charger" }
+       { .name = "cros-usbpd-charger" },
+       { .name = "cros-usbpd-logger" },
 };
 
 static const struct mfd_cell cros_ec_platform_cells[] = {
@@ -418,6 +419,39 @@ static int ec_device_probe(struct platform_device *pdev)
        device_initialize(&ec->class_dev);
        cdev_init(&ec->cdev, &fops);
 
+       /* Check whether this is actually a Fingerprint MCU rather than an EC */
+       if (cros_ec_check_features(ec, EC_FEATURE_FINGERPRINT)) {
+               dev_info(dev, "CrOS Fingerprint MCU detected.\n");
+               /*
+                * Help userspace differentiating ECs from FP MCU,
+                * regardless of the probing order.
+                */
+               ec_platform->ec_name = CROS_EC_DEV_FP_NAME;
+       }
+
+       /*
+        * Check whether this is actually an Integrated Sensor Hub (ISH)
+        * rather than an EC.
+        */
+       if (cros_ec_check_features(ec, EC_FEATURE_ISH)) {
+               dev_info(dev, "CrOS ISH MCU detected.\n");
+               /*
+                * Help userspace differentiating ECs from ISH MCU,
+                * regardless of the probing order.
+                */
+               ec_platform->ec_name = CROS_EC_DEV_ISH_NAME;
+       }
+
+       /* Check whether this is actually a Touchpad MCU rather than an EC */
+       if (cros_ec_check_features(ec, EC_FEATURE_TOUCHPAD)) {
+               dev_info(dev, "CrOS Touchpad MCU detected.\n");
+               /*
+                * Help userspace differentiating ECs from TP MCU,
+                * regardless of the probing order.
+                */
+               ec_platform->ec_name = CROS_EC_DEV_TP_NAME;
+       }
+
        /*
         * Add the class device
         * Link to the character device for creating the /dev entry
index 604c9dd14df55ba62480237cf0c725a1d994fdeb..338b825127f13a6cde0e19e64396e0cba760e2ea 100644 (file)
@@ -178,6 +178,7 @@ static const struct reg_default cs47l35_reg_default[] = {
        { 0x00000448, 0x0a83 }, /* R1096 (0x448) - eDRE Enable */
        { 0x0000044a, 0x0000 }, /* R1098 (0x44a) - eDRE Manual */
        { 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */
+       { 0x00000451, 0x0000 }, /* R1105 (0x451) - DAC AEC Control 2 */
        { 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */
        { 0x00000490, 0x0069 }, /* R1168 (0x490) - PDM SPK1 CTRL 1 */
        { 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 CTRL 2 */
@@ -970,6 +971,7 @@ static bool cs47l35_16bit_readable_register(struct device *dev,
        case MADERA_EDRE_ENABLE:
        case MADERA_EDRE_MANUAL:
        case MADERA_DAC_AEC_CONTROL_1:
+       case MADERA_DAC_AEC_CONTROL_2:
        case MADERA_NOISE_GATE_CONTROL:
        case MADERA_PDM_SPK1_CTRL_1:
        case MADERA_PDM_SPK1_CTRL_2:
index 77207d98f0cce39ad7fa2d544e41e85bd0cede9b..c040d3d7232a5b7909b92d5f747736abcf9e90e7 100644 (file)
@@ -263,6 +263,7 @@ static const struct reg_default cs47l90_reg_default[] = {
        { 0x00000440, 0x003f }, /* R1088 (0x440) - DRE Enable */
        { 0x00000448, 0x003f }, /* R1096 (0x448) - eDRE Enable */
        { 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */
+       { 0x00000451, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 2 */
        { 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */
        { 0x00000490, 0x0069 }, /* R1168 (0x490) - PDM SPK1 CTRL 1 */
        { 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 CTRL 2 */
@@ -1692,6 +1693,7 @@ static bool cs47l90_16bit_readable_register(struct device *dev,
        case MADERA_DRE_ENABLE:
        case MADERA_EDRE_ENABLE:
        case MADERA_DAC_AEC_CONTROL_1:
+       case MADERA_DAC_AEC_CONTROL_2:
        case MADERA_NOISE_GATE_CONTROL:
        case MADERA_PDM_SPK1_CTRL_1:
        case MADERA_PDM_SPK1_CTRL_2:
index 6e4ce49b4405009589e8f0ca50a0bdad4b75b5e1..b125f90dd375d71b910fb2ee0a616cb6559542f9 100644 (file)
@@ -1,5 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
- * da9063-core.c: Device access for Dialog DA9063 modules
+ * Device access for Dialog DA9063 modules
  *
  * Copyright 2012 Dialog Semiconductors Ltd.
  * Copyright 2013 Philipp Zabel, Pengutronix
@@ -7,11 +8,6 @@
  * Author: Krystian Garbaciak, Dialog Semiconductor
  * Author: Michal Hajduk, Dialog Semiconductor
  *
- *  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.
- *
  */
 
 #include <linux/kernel.h>
@@ -26,7 +22,6 @@
 #include <linux/regmap.h>
 
 #include <linux/mfd/da9063/core.h>
-#include <linux/mfd/da9063/pdata.h>
 #include <linux/mfd/da9063/registers.h>
 
 #include <linux/proc_fs.h>
@@ -165,7 +160,6 @@ static int da9063_clear_fault_log(struct da9063 *da9063)
 
 int da9063_device_init(struct da9063 *da9063, unsigned int irq)
 {
-       struct da9063_pdata *pdata = da9063->dev->platform_data;
        int model, variant_id, variant_code;
        int ret;
 
@@ -173,24 +167,10 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq)
        if (ret < 0)
                dev_err(da9063->dev, "Cannot clear fault log\n");
 
-       if (pdata) {
-               da9063->flags = pdata->flags;
-               da9063->irq_base = pdata->irq_base;
-       } else {
-               da9063->flags = 0;
-               da9063->irq_base = -1;
-       }
+       da9063->flags = 0;
+       da9063->irq_base = -1;
        da9063->chip_irq = irq;
 
-       if (pdata && pdata->init != NULL) {
-               ret = pdata->init(da9063);
-               if (ret != 0) {
-                       dev_err(da9063->dev,
-                               "Platform initialization failed.\n");
-                       return ret;
-               }
-       }
-
        ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_ID, &model);
        if (ret < 0) {
                dev_err(da9063->dev, "Cannot read chip model id.\n");
index 50a24b1921d0b67fc06d5292035bf46b2c069c61..455de74c0dd21f421c33f2b7600af8ca1446a98f 100644 (file)
@@ -1,15 +1,10 @@
-/* da9063-i2c.c: Interrupt support for Dialog DA9063
+// SPDX-License-Identifier: GPL-2.0+
+/* I2C support for Dialog DA9063
  *
  * Copyright 2012 Dialog Semiconductor Ltd.
  * Copyright 2013 Philipp Zabel, Pengutronix
  *
  * Author: Krystian Garbaciak, Dialog Semiconductor
- *
- *  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.
- *
  */
 
 #include <linux/kernel.h>
@@ -22,7 +17,6 @@
 
 #include <linux/mfd/core.h>
 #include <linux/mfd/da9063/core.h>
-#include <linux/mfd/da9063/pdata.h>
 #include <linux/mfd/da9063/registers.h>
 
 #include <linux/of.h>
index ecc0c8ce6c58ff6dbe2db5bff4f8a8001c688907..e2bbedf58e681830e63c9895609e8da62148c24c 100644 (file)
@@ -1,15 +1,10 @@
-/* da9063-irq.c: Interrupts support for Dialog DA9063
+// SPDX-License-Identifier: GPL-2.0+
+/* Interrupt support for Dialog DA9063
  *
  * Copyright 2012 Dialog Semiconductor Ltd.
  * Copyright 2013 Philipp Zabel, Pengutronix
  *
  * Author: Michal Hajduk, Dialog Semiconductor
- *
- *  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.
- *
  */
 
 #include <linux/kernel.h>
@@ -19,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/regmap.h>
 #include <linux/mfd/da9063/core.h>
-#include <linux/mfd/da9063/pdata.h>
 
 #define        DA9063_REG_EVENT_A_OFFSET       0
 #define        DA9063_REG_EVENT_B_OFFSET       1
index cba2eb166650982055ac2ce36a08056c8aad7cde..6b111be944d9c791350bab3ef7e80f37b6d227f0 100644 (file)
@@ -129,6 +129,19 @@ static const struct intel_lpss_platform_info cnl_i2c_info = {
 };
 
 static const struct pci_device_id intel_lpss_pci_ids[] = {
+       /* CML */
+       { PCI_VDEVICE(INTEL, 0x02a8), (kernel_ulong_t)&spt_uart_info },
+       { PCI_VDEVICE(INTEL, 0x02a9), (kernel_ulong_t)&spt_uart_info },
+       { PCI_VDEVICE(INTEL, 0x02aa), (kernel_ulong_t)&spt_info },
+       { PCI_VDEVICE(INTEL, 0x02ab), (kernel_ulong_t)&spt_info },
+       { PCI_VDEVICE(INTEL, 0x02c5), (kernel_ulong_t)&cnl_i2c_info },
+       { PCI_VDEVICE(INTEL, 0x02c6), (kernel_ulong_t)&cnl_i2c_info },
+       { PCI_VDEVICE(INTEL, 0x02c7), (kernel_ulong_t)&spt_uart_info },
+       { PCI_VDEVICE(INTEL, 0x02e8), (kernel_ulong_t)&cnl_i2c_info },
+       { PCI_VDEVICE(INTEL, 0x02e9), (kernel_ulong_t)&cnl_i2c_info },
+       { PCI_VDEVICE(INTEL, 0x02ea), (kernel_ulong_t)&cnl_i2c_info },
+       { PCI_VDEVICE(INTEL, 0x02eb), (kernel_ulong_t)&cnl_i2c_info },
+       { PCI_VDEVICE(INTEL, 0x02fb), (kernel_ulong_t)&spt_info },
        /* BXT A-Step */
        { PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info },
        { PCI_VDEVICE(INTEL, 0x0aae), (kernel_ulong_t)&bxt_i2c_info },
index 45221e092ecf7c2de55c2c88448952128fe0cb5f..fc6aa4c5014422d46170540307f4774fe2ea540e 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/clk-provider.h>
 #include <linux/debugfs.h>
 #include <linux/idr.h>
+#include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -273,6 +274,9 @@ static void intel_lpss_init_dev(const struct intel_lpss *lpss)
 {
        u32 value = LPSS_PRIV_SSP_REG_DIS_DMA_FIN;
 
+       /* Set the device in reset state */
+       writel(0, lpss->priv + LPSS_PRIV_RESETS);
+
        intel_lpss_deassert_reset(lpss);
 
        intel_lpss_set_remap_addr(lpss);
index 5bddb84cfc1f477b8b0c19bce799b0176731d5f5..11adbf77960d265a6e1e57abd1396e41e332e1d6 100644 (file)
@@ -74,16 +74,6 @@ static const struct dmi_system_id dmi_platform_info[] = {
        {
                .matches = {
                        DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
-                       DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
-                                       "6ES7647-0AA00-0YA2"),
-               },
-               .driver_data = (void *)400000,
-       },
-       {
-               .matches = {
-                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
-                       DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
-                                       "6ES7647-0AA00-1YA2"),
                },
                .driver_data = (void *)400000,
        },
index 64a3aece9c5e261800b41258d1717bf16352d7fc..be84bb2aa83745b0dce28cdef5b660da17c06358 100644 (file)
@@ -60,6 +60,7 @@ static struct mfd_cell cht_wc_dev[] = {
                .resources = cht_wc_ext_charger_resources,
        },
        {       .name = "cht_wcove_region", },
+       {       .name = "cht_wcove_leds", },
 };
 
 /*
index d8ddd1a6f30497ff7a866b40fe21f25ad45badea..436361ce373758bb6a41d0ef56662e9824d53d9a 100644 (file)
@@ -37,6 +37,8 @@
 #include <linux/regmap.h>
 #include <linux/slab.h>
 
+static struct max77620_chip *max77620_scratch;
+
 static const struct resource gpio_resources[] = {
        DEFINE_RES_IRQ(MAX77620_IRQ_TOP_GPIO),
 };
@@ -111,6 +113,26 @@ static const struct mfd_cell max20024_children[] = {
        },
 };
 
+static const struct mfd_cell max77663_children[] = {
+       { .name = "max77620-pinctrl", },
+       { .name = "max77620-clock", },
+       { .name = "max77663-pmic", },
+       { .name = "max77620-watchdog", },
+       {
+               .name = "max77620-gpio",
+               .resources = gpio_resources,
+               .num_resources = ARRAY_SIZE(gpio_resources),
+       }, {
+               .name = "max77620-rtc",
+               .resources = rtc_resources,
+               .num_resources = ARRAY_SIZE(rtc_resources),
+       }, {
+               .name = "max77663-power",
+               .resources = power_resources,
+               .num_resources = ARRAY_SIZE(power_resources),
+       },
+};
+
 static const struct regmap_range max77620_readable_ranges[] = {
        regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4),
 };
@@ -171,6 +193,35 @@ static const struct regmap_config max20024_regmap_config = {
        .volatile_table = &max77620_volatile_table,
 };
 
+static const struct regmap_range max77663_readable_ranges[] = {
+       regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_CID5),
+};
+
+static const struct regmap_access_table max77663_readable_table = {
+       .yes_ranges = max77663_readable_ranges,
+       .n_yes_ranges = ARRAY_SIZE(max77663_readable_ranges),
+};
+
+static const struct regmap_range max77663_writable_ranges[] = {
+       regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_CID5),
+};
+
+static const struct regmap_access_table max77663_writable_table = {
+       .yes_ranges = max77663_writable_ranges,
+       .n_yes_ranges = ARRAY_SIZE(max77663_writable_ranges),
+};
+
+static const struct regmap_config max77663_regmap_config = {
+       .name = "power-slave",
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = MAX77620_REG_CID5 + 1,
+       .cache_type = REGCACHE_RBTREE,
+       .rd_table = &max77663_readable_table,
+       .wr_table = &max77663_writable_table,
+       .volatile_table = &max77620_volatile_table,
+};
+
 /*
  * MAX77620 and MAX20024 has the following steps of the interrupt handling
  * for TOP interrupts:
@@ -240,6 +291,9 @@ static int max77620_get_fps_period_reg_value(struct max77620_chip *chip,
        case MAX77620:
                fps_min_period = MAX77620_FPS_PERIOD_MIN_US;
                break;
+       case MAX77663:
+               fps_min_period = MAX20024_FPS_PERIOD_MIN_US;
+               break;
        default:
                return -EINVAL;
        }
@@ -274,6 +328,9 @@ static int max77620_config_fps(struct max77620_chip *chip,
        case MAX77620:
                fps_max_period = MAX77620_FPS_PERIOD_MAX_US;
                break;
+       case MAX77663:
+               fps_max_period = MAX20024_FPS_PERIOD_MAX_US;
+               break;
        default:
                return -EINVAL;
        }
@@ -375,6 +432,9 @@ static int max77620_initialise_fps(struct max77620_chip *chip)
        }
 
 skip_fps:
+       if (chip->chip_id == MAX77663)
+               return 0;
+
        /* Enable wake on EN0 pin */
        ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2,
                                 MAX77620_ONOFFCNFG2_WK_EN0,
@@ -423,6 +483,15 @@ static int max77620_read_es_version(struct max77620_chip *chip)
        return ret;
 }
 
+static void max77620_pm_power_off(void)
+{
+       struct max77620_chip *chip = max77620_scratch;
+
+       regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG1,
+                          MAX77620_ONOFFCNFG1_SFT_RST,
+                          MAX77620_ONOFFCNFG1_SFT_RST);
+}
+
 static int max77620_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
@@ -430,6 +499,7 @@ static int max77620_probe(struct i2c_client *client,
        struct max77620_chip *chip;
        const struct mfd_cell *mfd_cells;
        int n_mfd_cells;
+       bool pm_off;
        int ret;
 
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
@@ -453,6 +523,11 @@ static int max77620_probe(struct i2c_client *client,
                n_mfd_cells = ARRAY_SIZE(max20024_children);
                rmap_config = &max20024_regmap_config;
                break;
+       case MAX77663:
+               mfd_cells = max77663_children;
+               n_mfd_cells = ARRAY_SIZE(max77663_children);
+               rmap_config = &max77663_regmap_config;
+               break;
        default:
                dev_err(chip->dev, "ChipID is invalid %d\n", chip->chip_id);
                return -EINVAL;
@@ -491,6 +566,12 @@ static int max77620_probe(struct i2c_client *client,
                return ret;
        }
 
+       pm_off = of_device_is_system_power_controller(client->dev.of_node);
+       if (pm_off && !pm_power_off) {
+               max77620_scratch = chip;
+               pm_power_off = max77620_pm_power_off;
+       }
+
        return 0;
 }
 
@@ -546,6 +627,9 @@ static int max77620_i2c_suspend(struct device *dev)
                return ret;
        }
 
+       if (chip->chip_id == MAX77663)
+               goto out;
+
        /* Disable WK_EN0 */
        ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2,
                                 MAX77620_ONOFFCNFG2_WK_EN0, 0);
@@ -581,7 +665,7 @@ static int max77620_i2c_resume(struct device *dev)
         * For MAX20024: No need to configure WKEN0 on resume as
         * it is configured on Init.
         */
-       if (chip->chip_id == MAX20024)
+       if (chip->chip_id == MAX20024 || chip->chip_id == MAX77663)
                goto out;
 
        /* Enable WK_EN0 */
@@ -603,6 +687,7 @@ out:
 static const struct i2c_device_id max77620_id[] = {
        {"max77620", MAX77620},
        {"max20024", MAX20024},
+       {"max77663", MAX77663},
        {},
 };
 
diff --git a/drivers/mfd/max77650.c b/drivers/mfd/max77650.c
new file mode 100644 (file)
index 0000000..60e07ac
--- /dev/null
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 BayLibre SAS
+// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+//
+// Core MFD driver for MAXIM 77650/77651 charger/power-supply.
+// Programming manual: https://pdfserv.maximintegrated.com/en/an/AN6428.pdf
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max77650.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#define MAX77650_INT_GPI_F_MSK         BIT(0)
+#define MAX77650_INT_GPI_R_MSK         BIT(1)
+#define MAX77650_INT_GPI_MSK \
+                       (MAX77650_INT_GPI_F_MSK | MAX77650_INT_GPI_R_MSK)
+#define MAX77650_INT_nEN_F_MSK         BIT(2)
+#define MAX77650_INT_nEN_R_MSK         BIT(3)
+#define MAX77650_INT_TJAL1_R_MSK       BIT(4)
+#define MAX77650_INT_TJAL2_R_MSK       BIT(5)
+#define MAX77650_INT_DOD_R_MSK         BIT(6)
+
+#define MAX77650_INT_THM_MSK           BIT(0)
+#define MAX77650_INT_CHG_MSK           BIT(1)
+#define MAX77650_INT_CHGIN_MSK         BIT(2)
+#define MAX77650_INT_TJ_REG_MSK                BIT(3)
+#define MAX77650_INT_CHGIN_CTRL_MSK    BIT(4)
+#define MAX77650_INT_SYS_CTRL_MSK      BIT(5)
+#define MAX77650_INT_SYS_CNFG_MSK      BIT(6)
+
+#define MAX77650_INT_GLBL_OFFSET       0
+#define MAX77650_INT_CHG_OFFSET                1
+
+#define MAX77650_SBIA_LPM_MASK         BIT(5)
+#define MAX77650_SBIA_LPM_DISABLED     0x00
+
+enum {
+       MAX77650_INT_GPI,
+       MAX77650_INT_nEN_F,
+       MAX77650_INT_nEN_R,
+       MAX77650_INT_TJAL1_R,
+       MAX77650_INT_TJAL2_R,
+       MAX77650_INT_DOD_R,
+       MAX77650_INT_THM,
+       MAX77650_INT_CHG,
+       MAX77650_INT_CHGIN,
+       MAX77650_INT_TJ_REG,
+       MAX77650_INT_CHGIN_CTRL,
+       MAX77650_INT_SYS_CTRL,
+       MAX77650_INT_SYS_CNFG,
+};
+
+static const struct resource max77650_charger_resources[] = {
+       DEFINE_RES_IRQ_NAMED(MAX77650_INT_CHG, "CHG"),
+       DEFINE_RES_IRQ_NAMED(MAX77650_INT_CHGIN, "CHGIN"),
+};
+
+static const struct resource max77650_gpio_resources[] = {
+       DEFINE_RES_IRQ_NAMED(MAX77650_INT_GPI, "GPI"),
+};
+
+static const struct resource max77650_onkey_resources[] = {
+       DEFINE_RES_IRQ_NAMED(MAX77650_INT_nEN_F, "nEN_F"),
+       DEFINE_RES_IRQ_NAMED(MAX77650_INT_nEN_R, "nEN_R"),
+};
+
+static const struct mfd_cell max77650_cells[] = {
+       {
+               .name           = "max77650-regulator",
+               .of_compatible  = "maxim,max77650-regulator",
+       }, {
+               .name           = "max77650-charger",
+               .of_compatible  = "maxim,max77650-charger",
+               .resources      = max77650_charger_resources,
+               .num_resources  = ARRAY_SIZE(max77650_charger_resources),
+       }, {
+               .name           = "max77650-gpio",
+               .of_compatible  = "maxim,max77650-gpio",
+               .resources      = max77650_gpio_resources,
+               .num_resources  = ARRAY_SIZE(max77650_gpio_resources),
+       }, {
+               .name           = "max77650-led",
+               .of_compatible  = "maxim,max77650-led",
+       }, {
+               .name           = "max77650-onkey",
+               .of_compatible  = "maxim,max77650-onkey",
+               .resources      = max77650_onkey_resources,
+               .num_resources  = ARRAY_SIZE(max77650_onkey_resources),
+       },
+};
+
+static const struct regmap_irq max77650_irqs[] = {
+       [MAX77650_INT_GPI] = {
+               .reg_offset = MAX77650_INT_GLBL_OFFSET,
+               .mask = MAX77650_INT_GPI_MSK,
+               .type = {
+                       .type_falling_val = MAX77650_INT_GPI_F_MSK,
+                       .type_rising_val = MAX77650_INT_GPI_R_MSK,
+                       .types_supported = IRQ_TYPE_EDGE_BOTH,
+               },
+       },
+       REGMAP_IRQ_REG(MAX77650_INT_nEN_F,
+                      MAX77650_INT_GLBL_OFFSET, MAX77650_INT_nEN_F_MSK),
+       REGMAP_IRQ_REG(MAX77650_INT_nEN_R,
+                      MAX77650_INT_GLBL_OFFSET, MAX77650_INT_nEN_R_MSK),
+       REGMAP_IRQ_REG(MAX77650_INT_TJAL1_R,
+                      MAX77650_INT_GLBL_OFFSET, MAX77650_INT_TJAL1_R_MSK),
+       REGMAP_IRQ_REG(MAX77650_INT_TJAL2_R,
+                      MAX77650_INT_GLBL_OFFSET, MAX77650_INT_TJAL2_R_MSK),
+       REGMAP_IRQ_REG(MAX77650_INT_DOD_R,
+                      MAX77650_INT_GLBL_OFFSET, MAX77650_INT_DOD_R_MSK),
+       REGMAP_IRQ_REG(MAX77650_INT_THM,
+                      MAX77650_INT_CHG_OFFSET, MAX77650_INT_THM_MSK),
+       REGMAP_IRQ_REG(MAX77650_INT_CHG,
+                      MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHG_MSK),
+       REGMAP_IRQ_REG(MAX77650_INT_CHGIN,
+                      MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHGIN_MSK),
+       REGMAP_IRQ_REG(MAX77650_INT_TJ_REG,
+                      MAX77650_INT_CHG_OFFSET, MAX77650_INT_TJ_REG_MSK),
+       REGMAP_IRQ_REG(MAX77650_INT_CHGIN_CTRL,
+                      MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHGIN_CTRL_MSK),
+       REGMAP_IRQ_REG(MAX77650_INT_SYS_CTRL,
+                      MAX77650_INT_CHG_OFFSET, MAX77650_INT_SYS_CTRL_MSK),
+       REGMAP_IRQ_REG(MAX77650_INT_SYS_CNFG,
+                      MAX77650_INT_CHG_OFFSET, MAX77650_INT_SYS_CNFG_MSK),
+};
+
+static const struct regmap_irq_chip max77650_irq_chip = {
+       .name                   = "max77650-irq",
+       .irqs                   = max77650_irqs,
+       .num_irqs               = ARRAY_SIZE(max77650_irqs),
+       .num_regs               = 2,
+       .status_base            = MAX77650_REG_INT_GLBL,
+       .mask_base              = MAX77650_REG_INTM_GLBL,
+       .type_in_mask           = true,
+       .type_invert            = true,
+       .init_ack_masked        = true,
+       .clear_on_unmask        = true,
+};
+
+static const struct regmap_config max77650_regmap_config = {
+       .name           = "max77650",
+       .reg_bits       = 8,
+       .val_bits       = 8,
+};
+
+static int max77650_i2c_probe(struct i2c_client *i2c)
+{
+       struct regmap_irq_chip_data *irq_data;
+       struct device *dev = &i2c->dev;
+       struct irq_domain *domain;
+       struct regmap *map;
+       unsigned int val;
+       int rv, id;
+
+       map = devm_regmap_init_i2c(i2c, &max77650_regmap_config);
+       if (IS_ERR(map)) {
+               dev_err(dev, "Unable to initialise I2C Regmap\n");
+               return PTR_ERR(map);
+       }
+
+       rv = regmap_read(map, MAX77650_REG_CID, &val);
+       if (rv) {
+               dev_err(dev, "Unable to read Chip ID\n");
+               return rv;
+       }
+
+       id = MAX77650_CID_BITS(val);
+       switch (id) {
+       case MAX77650_CID_77650A:
+       case MAX77650_CID_77650C:
+       case MAX77650_CID_77651A:
+       case MAX77650_CID_77651B:
+               break;
+       default:
+               dev_err(dev, "Chip not supported - ID: 0x%02x\n", id);
+               return -ENODEV;
+       }
+
+       /*
+        * This IC has a low-power mode which reduces the quiescent current
+        * consumption to ~5.6uA but is only suitable for systems consuming
+        * less than ~2mA. Since this is not likely the case even on
+        * linux-based wearables - keep the chip in normal power mode.
+        */
+       rv = regmap_update_bits(map,
+                               MAX77650_REG_CNFG_GLBL,
+                               MAX77650_SBIA_LPM_MASK,
+                               MAX77650_SBIA_LPM_DISABLED);
+       if (rv) {
+               dev_err(dev, "Unable to change the power mode\n");
+               return rv;
+       }
+
+       rv = devm_regmap_add_irq_chip(dev, map, i2c->irq,
+                                     IRQF_ONESHOT | IRQF_SHARED, 0,
+                                     &max77650_irq_chip, &irq_data);
+       if (rv) {
+               dev_err(dev, "Unable to add Regmap IRQ chip\n");
+               return rv;
+       }
+
+       domain = regmap_irq_get_domain(irq_data);
+
+       return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
+                                   max77650_cells, ARRAY_SIZE(max77650_cells),
+                                   NULL, 0, domain);
+}
+
+static const struct of_device_id max77650_of_match[] = {
+       { .compatible = "maxim,max77650" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, max77650_of_match);
+
+static struct i2c_driver max77650_i2c_driver = {
+       .driver = {
+               .name = "max77650",
+               .of_match_table = of_match_ptr(max77650_of_match),
+       },
+       .probe_new = max77650_i2c_probe,
+};
+module_i2c_driver(max77650_i2c_driver);
+
+MODULE_DESCRIPTION("MAXIM 77650/77651 multi-function core driver");
+MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
+MODULE_LICENSE("GPL v2");
index 94e3f32ce935717e97f2e938b433f3673c38f22d..1ade4c8cc91f7dbd185f1b84ccaf815a55c9cd70 100644 (file)
@@ -269,6 +269,19 @@ fail_alloc:
        return ret;
 }
 
+/**
+ * mfd_add_devices - register child devices
+ *
+ * @parent:    Pointer to parent device.
+ * @id:                Can be PLATFORM_DEVID_AUTO to let the Platform API take care
+ *             of device numbering, or will be added to a device's cell_id.
+ * @cells:     Array of (struct mfd_cell)s describing child devices.
+ * @n_devs:    Number of child devices to register.
+ * @mem_base:  Parent register range resource for child devices.
+ * @irq_base:  Base of the range of virtual interrupt numbers allocated for
+ *             this MFD device. Unused if @domain is specified.
+ * @domain:    Interrupt domain to create mappings for hardware interrupts.
+ */
 int mfd_add_devices(struct device *parent, int id,
                    const struct mfd_cell *cells, int n_devs,
                    struct resource *mem_base,
index 216fbf6adec9906e9c49991929aaa07f4ec0f1e5..94377782d20851bfef2cc38b7c270eba3577be69 100644 (file)
@@ -568,14 +568,6 @@ static int rk808_remove(struct i2c_client *client)
        return 0;
 }
 
-static const struct i2c_device_id rk808_ids[] = {
-       { "rk805" },
-       { "rk808" },
-       { "rk818" },
-       { },
-};
-MODULE_DEVICE_TABLE(i2c, rk808_ids);
-
 static struct i2c_driver rk808_i2c_driver = {
        .driver = {
                .name = "rk808",
@@ -583,7 +575,6 @@ static struct i2c_driver rk808_i2c_driver = {
        },
        .probe    = rk808_probe,
        .remove   = rk808_remove,
-       .id_table = rk808_ids,
 };
 
 module_i2c_driver(rk808_i2c_driver);
index 521319086c81d15fc6678c136eeffea7af707b5e..95473ff9bb4b5b4162912662f130e40fc48f0c8e 100644 (file)
 #include <linux/regmap.h>
 
 static const struct mfd_cell s5m8751_devs[] = {
-       {
-               .name = "s5m8751-pmic",
-       }, {
-               .name = "s5m-charger",
-       }, {
-               .name = "s5m8751-codec",
-       },
+       { .name = "s5m8751-pmic", },
+       { .name = "s5m-charger", },
+       { .name = "s5m8751-codec", },
 };
 
 static const struct mfd_cell s5m8763_devs[] = {
-       {
-               .name = "s5m8763-pmic",
-       }, {
-               .name = "s5m-rtc",
-       }, {
-               .name = "s5m-charger",
-       },
+       { .name = "s5m8763-pmic", },
+       { .name = "s5m-rtc", },
+       { .name = "s5m-charger", },
 };
 
 static const struct mfd_cell s5m8767_devs[] = {
+       { .name = "s5m8767-pmic", },
+       { .name = "s5m-rtc", },
        {
-               .name = "s5m8767-pmic",
-       }, {
-               .name = "s5m-rtc",
-       }, {
                .name = "s5m8767-clk",
                .of_compatible = "samsung,s5m8767-clk",
-       }
+       },
 };
 
 static const struct mfd_cell s2mps11_devs[] = {
+       { .name = "s2mps11-regulator", },
+       { .name = "s2mps14-rtc", },
        {
-               .name = "s2mps11-regulator",
-       }, {
-               .name = "s2mps14-rtc",
-       }, {
                .name = "s2mps11-clk",
                .of_compatible = "samsung,s2mps11-clk",
-       }
+       },
 };
 
 static const struct mfd_cell s2mps13_devs[] = {
@@ -79,37 +67,30 @@ static const struct mfd_cell s2mps13_devs[] = {
 };
 
 static const struct mfd_cell s2mps14_devs[] = {
+       { .name = "s2mps14-regulator", },
+       { .name = "s2mps14-rtc", },
        {
-               .name = "s2mps14-regulator",
-       }, {
-               .name = "s2mps14-rtc",
-       }, {
                .name = "s2mps14-clk",
                .of_compatible = "samsung,s2mps14-clk",
-       }
+       },
 };
 
 static const struct mfd_cell s2mps15_devs[] = {
+       { .name = "s2mps15-regulator", },
+       { .name = "s2mps15-rtc", },
        {
-               .name = "s2mps15-regulator",
-       }, {
-               .name = "s2mps15-rtc",
-       }, {
                .name = "s2mps13-clk",
                .of_compatible = "samsung,s2mps13-clk",
        },
 };
 
 static const struct mfd_cell s2mpa01_devs[] = {
-       {
-               .name = "s2mpa01-pmic",
-       },
+       { .name = "s2mpa01-pmic", },
+       { .name = "s2mps14-rtc", },
 };
 
 static const struct mfd_cell s2mpu02_devs[] = {
-       {
-               .name = "s2mpu02-regulator",
-       },
+       { .name = "s2mpu02-regulator", },
 };
 
 #ifdef CONFIG_OF
index ad0099077e7ef1d6062d9d9fec5f98009226e3dd..a98c5d165039d92b74e98c2c109ace98aa7d2513 100644 (file)
@@ -455,6 +455,9 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
        case S5M8767X:
                sec_irq_chip = &s5m8767_irq_chip;
                break;
+       case S2MPA01:
+               sec_irq_chip = &s2mps14_irq_chip;
+               break;
        case S2MPS11X:
                sec_irq_chip = &s2mps11_irq_chip;
                break;
index 36b96fee4ce60c2ba4199413319064917eb1d390..0ae27cd30268aabb289200790a190122a8a85186 100644 (file)
@@ -80,8 +80,6 @@ struct ssbi {
        int (*write)(struct ssbi *, u16 addr, const u8 *buf, int len);
 };
 
-#define to_ssbi(dev)   platform_get_drvdata(to_platform_device(dev))
-
 static inline u32 ssbi_readl(struct ssbi *ssbi, u32 reg)
 {
        return readl(ssbi->base + reg);
@@ -243,7 +241,7 @@ err:
 
 int ssbi_read(struct device *dev, u16 addr, u8 *buf, int len)
 {
-       struct ssbi *ssbi = to_ssbi(dev);
+       struct ssbi *ssbi = dev_get_drvdata(dev);
        unsigned long flags;
        int ret;
 
@@ -257,7 +255,7 @@ EXPORT_SYMBOL_GPL(ssbi_read);
 
 int ssbi_write(struct device *dev, u16 addr, const u8 *buf, int len)
 {
-       struct ssbi *ssbi = to_ssbi(dev);
+       struct ssbi *ssbi = dev_get_drvdata(dev);
        unsigned long flags;
        int ret;
 
diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c
new file mode 100644 (file)
index 0000000..fe8efba
--- /dev/null
@@ -0,0 +1,545 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for STMicroelectronics Multi-Function eXpander (STMFX) core
+ *
+ * Copyright (C) 2019 STMicroelectronics
+ * Author(s): Amelie Delaunay <amelie.delaunay@st.com>.
+ */
+#include <linux/bitfield.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/stmfx.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+
+static bool stmfx_reg_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case STMFX_REG_SYS_CTRL:
+       case STMFX_REG_IRQ_SRC_EN:
+       case STMFX_REG_IRQ_PENDING:
+       case STMFX_REG_IRQ_GPI_PENDING1:
+       case STMFX_REG_IRQ_GPI_PENDING2:
+       case STMFX_REG_IRQ_GPI_PENDING3:
+       case STMFX_REG_GPIO_STATE1:
+       case STMFX_REG_GPIO_STATE2:
+       case STMFX_REG_GPIO_STATE3:
+       case STMFX_REG_IRQ_GPI_SRC1:
+       case STMFX_REG_IRQ_GPI_SRC2:
+       case STMFX_REG_IRQ_GPI_SRC3:
+       case STMFX_REG_GPO_SET1:
+       case STMFX_REG_GPO_SET2:
+       case STMFX_REG_GPO_SET3:
+       case STMFX_REG_GPO_CLR1:
+       case STMFX_REG_GPO_CLR2:
+       case STMFX_REG_GPO_CLR3:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool stmfx_reg_writeable(struct device *dev, unsigned int reg)
+{
+       return (reg >= STMFX_REG_SYS_CTRL);
+}
+
+static const struct regmap_config stmfx_regmap_config = {
+       .reg_bits       = 8,
+       .reg_stride     = 1,
+       .val_bits       = 8,
+       .max_register   = STMFX_REG_MAX,
+       .volatile_reg   = stmfx_reg_volatile,
+       .writeable_reg  = stmfx_reg_writeable,
+       .cache_type     = REGCACHE_RBTREE,
+};
+
+static const struct resource stmfx_pinctrl_resources[] = {
+       DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_GPIO),
+};
+
+static const struct resource stmfx_idd_resources[] = {
+       DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_IDD),
+       DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_ERROR),
+};
+
+static const struct resource stmfx_ts_resources[] = {
+       DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_DET),
+       DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_NE),
+       DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_TH),
+       DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_FULL),
+       DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_OVF),
+};
+
+static struct mfd_cell stmfx_cells[] = {
+       {
+               .of_compatible = "st,stmfx-0300-pinctrl",
+               .name = "stmfx-pinctrl",
+               .resources = stmfx_pinctrl_resources,
+               .num_resources = ARRAY_SIZE(stmfx_pinctrl_resources),
+       },
+       {
+               .of_compatible = "st,stmfx-0300-idd",
+               .name = "stmfx-idd",
+               .resources = stmfx_idd_resources,
+               .num_resources = ARRAY_SIZE(stmfx_idd_resources),
+       },
+       {
+               .of_compatible = "st,stmfx-0300-ts",
+               .name = "stmfx-ts",
+               .resources = stmfx_ts_resources,
+               .num_resources = ARRAY_SIZE(stmfx_ts_resources),
+       },
+};
+
+static u8 stmfx_func_to_mask(u32 func)
+{
+       u8 mask = 0;
+
+       if (func & STMFX_FUNC_GPIO)
+               mask |= STMFX_REG_SYS_CTRL_GPIO_EN;
+
+       if ((func & STMFX_FUNC_ALTGPIO_LOW) || (func & STMFX_FUNC_ALTGPIO_HIGH))
+               mask |= STMFX_REG_SYS_CTRL_ALTGPIO_EN;
+
+       if (func & STMFX_FUNC_TS)
+               mask |= STMFX_REG_SYS_CTRL_TS_EN;
+
+       if (func & STMFX_FUNC_IDD)
+               mask |= STMFX_REG_SYS_CTRL_IDD_EN;
+
+       return mask;
+}
+
+int stmfx_function_enable(struct stmfx *stmfx, u32 func)
+{
+       u32 sys_ctrl;
+       u8 mask;
+       int ret;
+
+       ret = regmap_read(stmfx->map, STMFX_REG_SYS_CTRL, &sys_ctrl);
+       if (ret)
+               return ret;
+
+       /*
+        * IDD and TS have priority in STMFX FW, so if IDD and TS are enabled,
+        * ALTGPIO function is disabled by STMFX FW. If IDD or TS is enabled,
+        * the number of aGPIO available decreases. To avoid GPIO management
+        * disturbance, abort IDD or TS function enable in this case.
+        */
+       if (((func & STMFX_FUNC_IDD) || (func & STMFX_FUNC_TS)) &&
+           (sys_ctrl & STMFX_REG_SYS_CTRL_ALTGPIO_EN)) {
+               dev_err(stmfx->dev, "ALTGPIO function already enabled\n");
+               return -EBUSY;
+       }
+
+       /* If TS is enabled, aGPIO[3:0] cannot be used */
+       if ((func & STMFX_FUNC_ALTGPIO_LOW) &&
+           (sys_ctrl & STMFX_REG_SYS_CTRL_TS_EN)) {
+               dev_err(stmfx->dev, "TS in use, aGPIO[3:0] unavailable\n");
+               return -EBUSY;
+       }
+
+       /* If IDD is enabled, aGPIO[7:4] cannot be used */
+       if ((func & STMFX_FUNC_ALTGPIO_HIGH) &&
+           (sys_ctrl & STMFX_REG_SYS_CTRL_IDD_EN)) {
+               dev_err(stmfx->dev, "IDD in use, aGPIO[7:4] unavailable\n");
+               return -EBUSY;
+       }
+
+       mask = stmfx_func_to_mask(func);
+
+       return regmap_update_bits(stmfx->map, STMFX_REG_SYS_CTRL, mask, mask);
+}
+EXPORT_SYMBOL_GPL(stmfx_function_enable);
+
+int stmfx_function_disable(struct stmfx *stmfx, u32 func)
+{
+       u8 mask = stmfx_func_to_mask(func);
+
+       return regmap_update_bits(stmfx->map, STMFX_REG_SYS_CTRL, mask, 0);
+}
+EXPORT_SYMBOL_GPL(stmfx_function_disable);
+
+static void stmfx_irq_bus_lock(struct irq_data *data)
+{
+       struct stmfx *stmfx = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&stmfx->lock);
+}
+
+static void stmfx_irq_bus_sync_unlock(struct irq_data *data)
+{
+       struct stmfx *stmfx = irq_data_get_irq_chip_data(data);
+
+       regmap_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, stmfx->irq_src);
+
+       mutex_unlock(&stmfx->lock);
+}
+
+static void stmfx_irq_mask(struct irq_data *data)
+{
+       struct stmfx *stmfx = irq_data_get_irq_chip_data(data);
+
+       stmfx->irq_src &= ~BIT(data->hwirq % 8);
+}
+
+static void stmfx_irq_unmask(struct irq_data *data)
+{
+       struct stmfx *stmfx = irq_data_get_irq_chip_data(data);
+
+       stmfx->irq_src |= BIT(data->hwirq % 8);
+}
+
+static struct irq_chip stmfx_irq_chip = {
+       .name                   = "stmfx-core",
+       .irq_bus_lock           = stmfx_irq_bus_lock,
+       .irq_bus_sync_unlock    = stmfx_irq_bus_sync_unlock,
+       .irq_mask               = stmfx_irq_mask,
+       .irq_unmask             = stmfx_irq_unmask,
+};
+
+static irqreturn_t stmfx_irq_handler(int irq, void *data)
+{
+       struct stmfx *stmfx = data;
+       unsigned long n, pending;
+       u32 ack;
+       int ret;
+
+       ret = regmap_read(stmfx->map, STMFX_REG_IRQ_PENDING,
+                         (u32 *)&pending);
+       if (ret)
+               return IRQ_NONE;
+
+       /*
+        * There is no ACK for GPIO, MFX_REG_IRQ_PENDING_GPIO is a logical OR
+        * of MFX_REG_IRQ_GPI _PENDING1/_PENDING2/_PENDING3
+        */
+       ack = pending & ~BIT(STMFX_REG_IRQ_SRC_EN_GPIO);
+       if (ack) {
+               ret = regmap_write(stmfx->map, STMFX_REG_IRQ_ACK, ack);
+               if (ret)
+                       return IRQ_NONE;
+       }
+
+       for_each_set_bit(n, &pending, STMFX_REG_IRQ_SRC_MAX)
+               handle_nested_irq(irq_find_mapping(stmfx->irq_domain, n));
+
+       return IRQ_HANDLED;
+}
+
+static int stmfx_irq_map(struct irq_domain *d, unsigned int virq,
+                        irq_hw_number_t hwirq)
+{
+       irq_set_chip_data(virq, d->host_data);
+       irq_set_chip_and_handler(virq, &stmfx_irq_chip, handle_simple_irq);
+       irq_set_nested_thread(virq, 1);
+       irq_set_noprobe(virq);
+
+       return 0;
+}
+
+static void stmfx_irq_unmap(struct irq_domain *d, unsigned int virq)
+{
+       irq_set_chip_and_handler(virq, NULL, NULL);
+       irq_set_chip_data(virq, NULL);
+}
+
+static const struct irq_domain_ops stmfx_irq_ops = {
+       .map    = stmfx_irq_map,
+       .unmap  = stmfx_irq_unmap,
+};
+
+static void stmfx_irq_exit(struct i2c_client *client)
+{
+       struct stmfx *stmfx = i2c_get_clientdata(client);
+       int hwirq;
+
+       for (hwirq = 0; hwirq < STMFX_REG_IRQ_SRC_MAX; hwirq++)
+               irq_dispose_mapping(irq_find_mapping(stmfx->irq_domain, hwirq));
+
+       irq_domain_remove(stmfx->irq_domain);
+}
+
+static int stmfx_irq_init(struct i2c_client *client)
+{
+       struct stmfx *stmfx = i2c_get_clientdata(client);
+       u32 irqoutpin = 0, irqtrigger;
+       int ret;
+
+       stmfx->irq_domain = irq_domain_add_simple(stmfx->dev->of_node,
+                                                 STMFX_REG_IRQ_SRC_MAX, 0,
+                                                 &stmfx_irq_ops, stmfx);
+       if (!stmfx->irq_domain) {
+               dev_err(stmfx->dev, "Failed to create IRQ domain\n");
+               return -EINVAL;
+       }
+
+       if (!of_property_read_bool(stmfx->dev->of_node, "drive-open-drain"))
+               irqoutpin |= STMFX_REG_IRQ_OUT_PIN_TYPE;
+
+       irqtrigger = irq_get_trigger_type(client->irq);
+       if ((irqtrigger & IRQ_TYPE_EDGE_RISING) ||
+           (irqtrigger & IRQ_TYPE_LEVEL_HIGH))
+               irqoutpin |= STMFX_REG_IRQ_OUT_PIN_POL;
+
+       ret = regmap_write(stmfx->map, STMFX_REG_IRQ_OUT_PIN, irqoutpin);
+       if (ret)
+               return ret;
+
+       ret = devm_request_threaded_irq(stmfx->dev, client->irq,
+                                       NULL, stmfx_irq_handler,
+                                       irqtrigger | IRQF_ONESHOT,
+                                       "stmfx", stmfx);
+       if (ret)
+               stmfx_irq_exit(client);
+
+       return ret;
+}
+
+static int stmfx_chip_reset(struct stmfx *stmfx)
+{
+       int ret;
+
+       ret = regmap_write(stmfx->map, STMFX_REG_SYS_CTRL,
+                          STMFX_REG_SYS_CTRL_SWRST);
+       if (ret)
+               return ret;
+
+       msleep(STMFX_BOOT_TIME_MS);
+
+       return ret;
+}
+
+static int stmfx_chip_init(struct i2c_client *client)
+{
+       struct stmfx *stmfx = i2c_get_clientdata(client);
+       u32 id;
+       u8 version[2];
+       int ret;
+
+       stmfx->vdd = devm_regulator_get_optional(&client->dev, "vdd");
+       ret = PTR_ERR_OR_ZERO(stmfx->vdd);
+       if (ret == -ENODEV) {
+               stmfx->vdd = NULL;
+       } else if (ret == -EPROBE_DEFER) {
+               return ret;
+       } else if (ret) {
+               dev_err(&client->dev, "Failed to get VDD regulator: %d\n", ret);
+               return ret;
+       }
+
+       if (stmfx->vdd) {
+               ret = regulator_enable(stmfx->vdd);
+               if (ret) {
+                       dev_err(&client->dev, "VDD enable failed: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = regmap_read(stmfx->map, STMFX_REG_CHIP_ID, &id);
+       if (ret) {
+               dev_err(&client->dev, "Error reading chip ID: %d\n", ret);
+               goto err;
+       }
+
+       /*
+        * Check that ID is the complement of the I2C address:
+        * STMFX I2C address follows the 7-bit format (MSB), that's why
+        * client->addr is shifted.
+        *
+        * STMFX_I2C_ADDR|       STMFX         |        Linux
+        *   input pin   | I2C device address  | I2C device address
+        *---------------------------------------------------------
+        *       0       | b: 1000 010x h:0x84 |       0x42
+        *       1       | b: 1000 011x h:0x86 |       0x43
+        */
+       if (FIELD_GET(STMFX_REG_CHIP_ID_MASK, ~id) != (client->addr << 1)) {
+               dev_err(&client->dev, "Unknown chip ID: %#x\n", id);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = regmap_bulk_read(stmfx->map, STMFX_REG_FW_VERSION_MSB,
+                              version, ARRAY_SIZE(version));
+       if (ret) {
+               dev_err(&client->dev, "Error reading FW version: %d\n", ret);
+               goto err;
+       }
+
+       dev_info(&client->dev, "STMFX id: %#x, fw version: %x.%02x\n",
+                id, version[0], version[1]);
+
+       ret = stmfx_chip_reset(stmfx);
+       if (ret) {
+               dev_err(&client->dev, "Failed to reset chip: %d\n", ret);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       if (stmfx->vdd)
+               return regulator_disable(stmfx->vdd);
+
+       return ret;
+}
+
+static int stmfx_chip_exit(struct i2c_client *client)
+{
+       struct stmfx *stmfx = i2c_get_clientdata(client);
+
+       regmap_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, 0);
+       regmap_write(stmfx->map, STMFX_REG_SYS_CTRL, 0);
+
+       if (stmfx->vdd)
+               return regulator_disable(stmfx->vdd);
+
+       return 0;
+}
+
+static int stmfx_probe(struct i2c_client *client,
+                      const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct stmfx *stmfx;
+       int ret;
+
+       stmfx = devm_kzalloc(dev, sizeof(*stmfx), GFP_KERNEL);
+       if (!stmfx)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, stmfx);
+
+       stmfx->dev = dev;
+
+       stmfx->map = devm_regmap_init_i2c(client, &stmfx_regmap_config);
+       if (IS_ERR(stmfx->map)) {
+               ret = PTR_ERR(stmfx->map);
+               dev_err(dev, "Failed to allocate register map: %d\n", ret);
+               return ret;
+       }
+
+       mutex_init(&stmfx->lock);
+
+       ret = stmfx_chip_init(client);
+       if (ret) {
+               if (ret == -ETIMEDOUT)
+                       return -EPROBE_DEFER;
+               return ret;
+       }
+
+       if (client->irq < 0) {
+               dev_err(dev, "Failed to get IRQ: %d\n", client->irq);
+               ret = client->irq;
+               goto err_chip_exit;
+       }
+
+       ret = stmfx_irq_init(client);
+       if (ret)
+               goto err_chip_exit;
+
+       ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
+                                  stmfx_cells, ARRAY_SIZE(stmfx_cells), NULL,
+                                  0, stmfx->irq_domain);
+       if (ret)
+               goto err_irq_exit;
+
+       return 0;
+
+err_irq_exit:
+       stmfx_irq_exit(client);
+err_chip_exit:
+       stmfx_chip_exit(client);
+
+       return ret;
+}
+
+static int stmfx_remove(struct i2c_client *client)
+{
+       stmfx_irq_exit(client);
+
+       return stmfx_chip_exit(client);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stmfx_suspend(struct device *dev)
+{
+       struct stmfx *stmfx = dev_get_drvdata(dev);
+       int ret;
+
+       ret = regmap_raw_read(stmfx->map, STMFX_REG_SYS_CTRL,
+                             &stmfx->bkp_sysctrl, sizeof(stmfx->bkp_sysctrl));
+       if (ret)
+               return ret;
+
+       ret = regmap_raw_read(stmfx->map, STMFX_REG_IRQ_OUT_PIN,
+                             &stmfx->bkp_irqoutpin,
+                             sizeof(stmfx->bkp_irqoutpin));
+       if (ret)
+               return ret;
+
+       if (stmfx->vdd)
+               return regulator_disable(stmfx->vdd);
+
+       return 0;
+}
+
+static int stmfx_resume(struct device *dev)
+{
+       struct stmfx *stmfx = dev_get_drvdata(dev);
+       int ret;
+
+       if (stmfx->vdd) {
+               ret = regulator_enable(stmfx->vdd);
+               if (ret) {
+                       dev_err(stmfx->dev,
+                               "VDD enable failed: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = regmap_raw_write(stmfx->map, STMFX_REG_SYS_CTRL,
+                              &stmfx->bkp_sysctrl, sizeof(stmfx->bkp_sysctrl));
+       if (ret)
+               return ret;
+
+       ret = regmap_raw_write(stmfx->map, STMFX_REG_IRQ_OUT_PIN,
+                              &stmfx->bkp_irqoutpin,
+                              sizeof(stmfx->bkp_irqoutpin));
+       if (ret)
+               return ret;
+
+       ret = regmap_raw_write(stmfx->map, STMFX_REG_IRQ_SRC_EN,
+                              &stmfx->irq_src, sizeof(stmfx->irq_src));
+       if (ret)
+               return ret;
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(stmfx_dev_pm_ops, stmfx_suspend, stmfx_resume);
+
+static const struct of_device_id stmfx_of_match[] = {
+       { .compatible = "st,stmfx-0300", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, stmfx_of_match);
+
+static struct i2c_driver stmfx_driver = {
+       .driver = {
+               .name = "stmfx-core",
+               .of_match_table = of_match_ptr(stmfx_of_match),
+               .pm = &stmfx_dev_pm_ops,
+       },
+       .probe = stmfx_probe,
+       .remove = stmfx_remove,
+};
+module_i2c_driver(stmfx_driver);
+
+MODULE_DESCRIPTION("STMFX core driver");
+MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
+MODULE_LICENSE("GPL v2");
index 2b658bed47db64f9718925576bb41995e1855c2b..2f12a415b80755575bdf8285a7e2c4f6b9f54163 100644 (file)
@@ -148,13 +148,12 @@ static const struct of_device_id sun6i_prcm_dt_ids[] = {
 
 static int sun6i_prcm_probe(struct platform_device *pdev)
 {
-       struct device_node *np = pdev->dev.of_node;
        const struct of_device_id *match;
        const struct prcm_data *data;
        struct resource *res;
        int ret;
 
-       match = of_match_node(sun6i_prcm_dt_ids, np);
+       match = of_match_node(sun6i_prcm_dt_ids, pdev->dev.of_node);
        if (!match)
                return -EINVAL;
 
index 0ecdffb3d96728ba89fb7dc34f57483364784fe7..f6922a0f8058af3f563a4a720e7cfec2d98f55af 100644 (file)
@@ -12,6 +12,7 @@
  * (at your option) any later version.
  */
 
+#include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/hwspinlock.h>
 #include <linux/io.h>
@@ -45,6 +46,7 @@ static const struct regmap_config syscon_regmap_config = {
 
 static struct syscon *of_syscon_register(struct device_node *np)
 {
+       struct clk *clk;
        struct syscon *syscon;
        struct regmap *regmap;
        void __iomem *base;
@@ -119,6 +121,18 @@ static struct syscon *of_syscon_register(struct device_node *np)
                goto err_regmap;
        }
 
+       clk = of_clk_get(np, 0);
+       if (IS_ERR(clk)) {
+               ret = PTR_ERR(clk);
+               /* clock is optional */
+               if (ret != -ENOENT)
+                       goto err_clk;
+       } else {
+               ret = regmap_mmio_attach_clk(regmap, clk);
+               if (ret)
+                       goto err_attach;
+       }
+
        syscon->regmap = regmap;
        syscon->np = np;
 
@@ -128,6 +142,11 @@ static struct syscon *of_syscon_register(struct device_node *np)
 
        return syscon;
 
+err_attach:
+       if (!IS_ERR(clk))
+               clk_put(clk);
+err_clk:
+       regmap_exit(regmap);
 err_regmap:
        iounmap(base);
 err_map:
index 43d8683266de298aea8bbdb0388a9fba10a2c1cd..e9cfb147345e4a7465a66ebd6a27b59db8867c78 100644 (file)
@@ -82,8 +82,7 @@ struct t7l66xb {
 
 static int t7l66xb_mmc_enable(struct platform_device *mmc)
 {
-       struct platform_device *dev = to_platform_device(mmc->dev.parent);
-       struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
+       struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
        unsigned long flags;
        u8 dev_ctl;
        int ret;
@@ -108,8 +107,7 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc)
 
 static int t7l66xb_mmc_disable(struct platform_device *mmc)
 {
-       struct platform_device *dev = to_platform_device(mmc->dev.parent);
-       struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
+       struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
        unsigned long flags;
        u8 dev_ctl;
 
@@ -128,16 +126,14 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc)
 
 static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state)
 {
-       struct platform_device *dev = to_platform_device(mmc->dev.parent);
-       struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
+       struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
 
        tmio_core_mmc_pwr(t7l66xb->scr + 0x200, 0, state);
 }
 
 static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state)
 {
-       struct platform_device *dev = to_platform_device(mmc->dev.parent);
-       struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
+       struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
 
        tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, 0, state);
 }
index 85fab3729102545ddf0ac609f78f29804ae19846..f417c6fecfe24abc7fb99eb02886888e2512e9dc 100644 (file)
@@ -80,16 +80,14 @@ static int tc6387xb_resume(struct platform_device *dev)
 
 static void tc6387xb_mmc_pwr(struct platform_device *mmc, int state)
 {
-       struct platform_device *dev = to_platform_device(mmc->dev.parent);
-       struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
+       struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent);
 
        tmio_core_mmc_pwr(tc6387xb->scr + 0x200, 0, state);
 }
 
 static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state)
 {
-       struct platform_device *dev = to_platform_device(mmc->dev.parent);
-       struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
+       struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent);
 
        tmio_core_mmc_clk_div(tc6387xb->scr + 0x200, 0, state);
 }
@@ -97,8 +95,7 @@ static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state)
 
 static int tc6387xb_mmc_enable(struct platform_device *mmc)
 {
-       struct platform_device *dev      = to_platform_device(mmc->dev.parent);
-       struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
+       struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent);
 
        clk_prepare_enable(tc6387xb->clk32k);
 
@@ -110,8 +107,7 @@ static int tc6387xb_mmc_enable(struct platform_device *mmc)
 
 static int tc6387xb_mmc_disable(struct platform_device *mmc)
 {
-       struct platform_device *dev      = to_platform_device(mmc->dev.parent);
-       struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
+       struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent);
 
        clk_disable_unprepare(tc6387xb->clk32k);
 
index 0c9f0390e891949ff7c84d78f75a36fff168aecd..6943048a64c2c34f38b946f43b42f404fcbe3076 100644 (file)
@@ -122,14 +122,13 @@ enum {
 
 static int tc6393xb_nand_enable(struct platform_device *nand)
 {
-       struct platform_device *dev = to_platform_device(nand->dev.parent);
-       struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb *tc6393xb = dev_get_drvdata(nand->dev.parent);
        unsigned long flags;
 
        raw_spin_lock_irqsave(&tc6393xb->lock, flags);
 
        /* SMD buffer on */
-       dev_dbg(&dev->dev, "SMD buffer on\n");
+       dev_dbg(nand->dev.parent, "SMD buffer on\n");
        tmio_iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1));
 
        raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
@@ -312,8 +311,7 @@ static int tc6393xb_fb_disable(struct platform_device *dev)
 
 int tc6393xb_lcd_set_power(struct platform_device *fb, bool on)
 {
-       struct platform_device *dev = to_platform_device(fb->dev.parent);
-       struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb *tc6393xb = dev_get_drvdata(fb->dev.parent);
        u8 fer;
        unsigned long flags;
 
@@ -334,8 +332,7 @@ EXPORT_SYMBOL(tc6393xb_lcd_set_power);
 
 int tc6393xb_lcd_mode(struct platform_device *fb,
                                        const struct fb_videomode *mode) {
-       struct platform_device *dev = to_platform_device(fb->dev.parent);
-       struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb *tc6393xb = dev_get_drvdata(fb->dev.parent);
        unsigned long flags;
 
        raw_spin_lock_irqsave(&tc6393xb->lock, flags);
@@ -351,8 +348,7 @@ EXPORT_SYMBOL(tc6393xb_lcd_mode);
 
 static int tc6393xb_mmc_enable(struct platform_device *mmc)
 {
-       struct platform_device *dev = to_platform_device(mmc->dev.parent);
-       struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent);
 
        tmio_core_mmc_enable(tc6393xb->scr + 0x200, 0,
                tc6393xb_mmc_resources[0].start & 0xfffe);
@@ -362,8 +358,7 @@ static int tc6393xb_mmc_enable(struct platform_device *mmc)
 
 static int tc6393xb_mmc_resume(struct platform_device *mmc)
 {
-       struct platform_device *dev = to_platform_device(mmc->dev.parent);
-       struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent);
 
        tmio_core_mmc_resume(tc6393xb->scr + 0x200, 0,
                tc6393xb_mmc_resources[0].start & 0xfffe);
@@ -373,16 +368,14 @@ static int tc6393xb_mmc_resume(struct platform_device *mmc)
 
 static void tc6393xb_mmc_pwr(struct platform_device *mmc, int state)
 {
-       struct platform_device *dev = to_platform_device(mmc->dev.parent);
-       struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent);
 
        tmio_core_mmc_pwr(tc6393xb->scr + 0x200, 0, state);
 }
 
 static void tc6393xb_mmc_clk_div(struct platform_device *mmc, int state)
 {
-       struct platform_device *dev = to_platform_device(mmc->dev.parent);
-       struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent);
 
        tmio_core_mmc_clk_div(tc6393xb->scr + 0x200, 0, state);
 }
index 3bd75061f7776882065697de527e52938ad350e6..f78be039e4637636b4a119547e9c2aa0d0decc51 100644 (file)
@@ -27,6 +27,7 @@ static const struct of_device_id tps65912_spi_of_match_table[] = {
        { .compatible = "ti,tps65912", },
        { /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, tps65912_spi_of_match_table);
 
 static int tps65912_spi_probe(struct spi_device *spi)
 {
index 7c3c5fd5fcd04790dea4be42ab087c0a61582c4c..86052c5c606960473af11a199577fba3ef17c7f9 100644 (file)
@@ -322,8 +322,19 @@ int twl6040_power(struct twl6040 *twl6040, int on)
                        }
                }
 
+               /*
+                * Register access can produce errors after power-up unless we
+                * wait at least 8ms based on measurements on duovero.
+                */
+               usleep_range(10000, 12000);
+
                /* Sync with the HW */
-               regcache_sync(twl6040->regmap);
+               ret = regcache_sync(twl6040->regmap);
+               if (ret) {
+                       dev_err(twl6040->dev, "Failed to sync with the HW: %i\n",
+                               ret);
+                       goto out;
+               }
 
                /* Default PLL configuration after power up */
                twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL;
index 3209ee020b153a4a539b7f4a84e60e5bf75df861..b80cb6af0cb4d1acacabbb1ec37ee4d212cb5d76 100644 (file)
@@ -496,30 +496,6 @@ config VEXPRESS_SYSCFG
          bus. System Configuration interface is one of the possible means
          of generating transactions on this bus.
 
-config ASPEED_P2A_CTRL
-       depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON
-       tristate "Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC bridge control"
-       help
-         Control Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC mappings through
-         ioctl()s, the driver also provides an interface for userspace mappings to
-         a pre-defined region.
-
-config ASPEED_LPC_CTRL
-       depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON
-       tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control"
-       ---help---
-         Control Aspeed ast2400/2500 HOST LPC to BMC mappings through
-         ioctl()s, the driver also provides a read/write interface to a BMC ram
-         region where the host LPC read/write region can be buffered.
-
-config ASPEED_LPC_SNOOP
-       tristate "Aspeed ast2500 HOST LPC snoop support"
-       depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON
-       help
-         Provides a driver to control the LPC snoop interface which
-         allows the BMC to listen on and save the data written by
-         the host to an arbitrary LPC I/O port.
-
 config PCI_ENDPOINT_TEST
        depends on PCI
        select CRC32
index c36239573a5cab4167b1ece45e3de2972142a019..b9affcdaa3d6ebe32e383aa8e6cb0288055d47e3 100644 (file)
@@ -54,9 +54,6 @@ obj-$(CONFIG_GENWQE)          += genwqe/
 obj-$(CONFIG_ECHO)             += echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)  += vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)         += cxl/
-obj-$(CONFIG_ASPEED_LPC_CTRL)  += aspeed-lpc-ctrl.o
-obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
-obj-$(CONFIG_ASPEED_P2A_CTRL)  += aspeed-p2a-ctrl.o
 obj-$(CONFIG_PCI_ENDPOINT_TEST)        += pci_endpoint_test.o
 obj-$(CONFIG_OCXL)             += ocxl/
 obj-y                          += cardreader/
diff --git a/drivers/misc/aspeed-lpc-ctrl.c b/drivers/misc/aspeed-lpc-ctrl.c
deleted file mode 100644 (file)
index a024f80..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright 2017 IBM 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; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/clk.h>
-#include <linux/mfd/syscon.h>
-#include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/platform_device.h>
-#include <linux/poll.h>
-#include <linux/regmap.h>
-
-#include <linux/aspeed-lpc-ctrl.h>
-
-#define DEVICE_NAME    "aspeed-lpc-ctrl"
-
-#define HICR5 0x0
-#define HICR5_ENL2H    BIT(8)
-#define HICR5_ENFWH    BIT(10)
-
-#define HICR7 0x8
-#define HICR8 0xc
-
-struct aspeed_lpc_ctrl {
-       struct miscdevice       miscdev;
-       struct regmap           *regmap;
-       struct clk              *clk;
-       phys_addr_t             mem_base;
-       resource_size_t         mem_size;
-       u32             pnor_size;
-       u32             pnor_base;
-};
-
-static struct aspeed_lpc_ctrl *file_aspeed_lpc_ctrl(struct file *file)
-{
-       return container_of(file->private_data, struct aspeed_lpc_ctrl,
-                       miscdev);
-}
-
-static int aspeed_lpc_ctrl_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file);
-       unsigned long vsize = vma->vm_end - vma->vm_start;
-       pgprot_t prot = vma->vm_page_prot;
-
-       if (vma->vm_pgoff + vsize > lpc_ctrl->mem_base + lpc_ctrl->mem_size)
-               return -EINVAL;
-
-       /* ast2400/2500 AHB accesses are not cache coherent */
-       prot = pgprot_noncached(prot);
-
-       if (remap_pfn_range(vma, vma->vm_start,
-               (lpc_ctrl->mem_base >> PAGE_SHIFT) + vma->vm_pgoff,
-               vsize, prot))
-               return -EAGAIN;
-
-       return 0;
-}
-
-static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd,
-               unsigned long param)
-{
-       struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file);
-       void __user *p = (void __user *)param;
-       struct aspeed_lpc_ctrl_mapping map;
-       u32 addr;
-       u32 size;
-       long rc;
-
-       if (copy_from_user(&map, p, sizeof(map)))
-               return -EFAULT;
-
-       if (map.flags != 0)
-               return -EINVAL;
-
-       switch (cmd) {
-       case ASPEED_LPC_CTRL_IOCTL_GET_SIZE:
-               /* The flash windows don't report their size */
-               if (map.window_type != ASPEED_LPC_CTRL_WINDOW_MEMORY)
-                       return -EINVAL;
-
-               /* Support more than one window id in the future */
-               if (map.window_id != 0)
-                       return -EINVAL;
-
-               map.size = lpc_ctrl->mem_size;
-
-               return copy_to_user(p, &map, sizeof(map)) ? -EFAULT : 0;
-       case ASPEED_LPC_CTRL_IOCTL_MAP:
-
-               /*
-                * The top half of HICR7 is the MSB of the BMC address of the
-                * mapping.
-                * The bottom half of HICR7 is the MSB of the HOST LPC
-                * firmware space address of the mapping.
-                *
-                * The 1 bits in the top of half of HICR8 represent the bits
-                * (in the requested address) that should be ignored and
-                * replaced with those from the top half of HICR7.
-                * The 1 bits in the bottom half of HICR8 represent the bits
-                * (in the requested address) that should be kept and pass
-                * into the BMC address space.
-                */
-
-               /*
-                * It doesn't make sense to talk about a size or offset with
-                * low 16 bits set. Both HICR7 and HICR8 talk about the top 16
-                * bits of addresses and sizes.
-                */
-
-               if ((map.size & 0x0000ffff) || (map.offset & 0x0000ffff))
-                       return -EINVAL;
-
-               /*
-                * Because of the way the masks work in HICR8 offset has to
-                * be a multiple of size.
-                */
-               if (map.offset & (map.size - 1))
-                       return -EINVAL;
-
-               if (map.window_type == ASPEED_LPC_CTRL_WINDOW_FLASH) {
-                       addr = lpc_ctrl->pnor_base;
-                       size = lpc_ctrl->pnor_size;
-               } else if (map.window_type == ASPEED_LPC_CTRL_WINDOW_MEMORY) {
-                       addr = lpc_ctrl->mem_base;
-                       size = lpc_ctrl->mem_size;
-               } else {
-                       return -EINVAL;
-               }
-
-               /* Check overflow first! */
-               if (map.offset + map.size < map.offset ||
-                       map.offset + map.size > size)
-                       return -EINVAL;
-
-               if (map.size == 0 || map.size > size)
-                       return -EINVAL;
-
-               addr += map.offset;
-
-               /*
-                * addr (host lpc address) is safe regardless of values. This
-                * simply changes the address the host has to request on its
-                * side of the LPC bus. This cannot impact the hosts own
-                * memory space by surprise as LPC specific accessors are
-                * required. The only strange thing that could be done is
-                * setting the lower 16 bits but the shift takes care of that.
-                */
-
-               rc = regmap_write(lpc_ctrl->regmap, HICR7,
-                               (addr | (map.addr >> 16)));
-               if (rc)
-                       return rc;
-
-               rc = regmap_write(lpc_ctrl->regmap, HICR8,
-                               (~(map.size - 1)) | ((map.size >> 16) - 1));
-               if (rc)
-                       return rc;
-
-               /*
-                * Enable LPC FHW cycles. This is required for the host to
-                * access the regions specified.
-                */
-               return regmap_update_bits(lpc_ctrl->regmap, HICR5,
-                               HICR5_ENFWH | HICR5_ENL2H,
-                               HICR5_ENFWH | HICR5_ENL2H);
-       }
-
-       return -EINVAL;
-}
-
-static const struct file_operations aspeed_lpc_ctrl_fops = {
-       .owner          = THIS_MODULE,
-       .mmap           = aspeed_lpc_ctrl_mmap,
-       .unlocked_ioctl = aspeed_lpc_ctrl_ioctl,
-};
-
-static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
-{
-       struct aspeed_lpc_ctrl *lpc_ctrl;
-       struct device_node *node;
-       struct resource resm;
-       struct device *dev;
-       int rc;
-
-       dev = &pdev->dev;
-
-       lpc_ctrl = devm_kzalloc(dev, sizeof(*lpc_ctrl), GFP_KERNEL);
-       if (!lpc_ctrl)
-               return -ENOMEM;
-
-       node = of_parse_phandle(dev->of_node, "flash", 0);
-       if (!node) {
-               dev_err(dev, "Didn't find host pnor flash node\n");
-               return -ENODEV;
-       }
-
-       rc = of_address_to_resource(node, 1, &resm);
-       of_node_put(node);
-       if (rc) {
-               dev_err(dev, "Couldn't address to resource for flash\n");
-               return rc;
-       }
-
-       lpc_ctrl->pnor_size = resource_size(&resm);
-       lpc_ctrl->pnor_base = resm.start;
-
-       dev_set_drvdata(&pdev->dev, lpc_ctrl);
-
-       node = of_parse_phandle(dev->of_node, "memory-region", 0);
-       if (!node) {
-               dev_err(dev, "Didn't find reserved memory\n");
-               return -EINVAL;
-       }
-
-       rc = of_address_to_resource(node, 0, &resm);
-       of_node_put(node);
-       if (rc) {
-               dev_err(dev, "Couldn't address to resource for reserved memory\n");
-               return -ENOMEM;
-       }
-
-       lpc_ctrl->mem_size = resource_size(&resm);
-       lpc_ctrl->mem_base = resm.start;
-
-       lpc_ctrl->regmap = syscon_node_to_regmap(
-                       pdev->dev.parent->of_node);
-       if (IS_ERR(lpc_ctrl->regmap)) {
-               dev_err(dev, "Couldn't get regmap\n");
-               return -ENODEV;
-       }
-
-       lpc_ctrl->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(lpc_ctrl->clk)) {
-               dev_err(dev, "couldn't get clock\n");
-               return PTR_ERR(lpc_ctrl->clk);
-       }
-       rc = clk_prepare_enable(lpc_ctrl->clk);
-       if (rc) {
-               dev_err(dev, "couldn't enable clock\n");
-               return rc;
-       }
-
-       lpc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR;
-       lpc_ctrl->miscdev.name = DEVICE_NAME;
-       lpc_ctrl->miscdev.fops = &aspeed_lpc_ctrl_fops;
-       lpc_ctrl->miscdev.parent = dev;
-       rc = misc_register(&lpc_ctrl->miscdev);
-       if (rc) {
-               dev_err(dev, "Unable to register device\n");
-               goto err;
-       }
-
-       dev_info(dev, "Loaded at %pr\n", &resm);
-
-       return 0;
-
-err:
-       clk_disable_unprepare(lpc_ctrl->clk);
-       return rc;
-}
-
-static int aspeed_lpc_ctrl_remove(struct platform_device *pdev)
-{
-       struct aspeed_lpc_ctrl *lpc_ctrl = dev_get_drvdata(&pdev->dev);
-
-       misc_deregister(&lpc_ctrl->miscdev);
-       clk_disable_unprepare(lpc_ctrl->clk);
-
-       return 0;
-}
-
-static const struct of_device_id aspeed_lpc_ctrl_match[] = {
-       { .compatible = "aspeed,ast2400-lpc-ctrl" },
-       { .compatible = "aspeed,ast2500-lpc-ctrl" },
-       { },
-};
-
-static struct platform_driver aspeed_lpc_ctrl_driver = {
-       .driver = {
-               .name           = DEVICE_NAME,
-               .of_match_table = aspeed_lpc_ctrl_match,
-       },
-       .probe = aspeed_lpc_ctrl_probe,
-       .remove = aspeed_lpc_ctrl_remove,
-};
-
-module_platform_driver(aspeed_lpc_ctrl_driver);
-
-MODULE_DEVICE_TABLE(of, aspeed_lpc_ctrl_match);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Cyril Bur <cyrilbur@gmail.com>");
-MODULE_DESCRIPTION("Control for aspeed 2400/2500 LPC HOST to BMC mappings");
diff --git a/drivers/misc/aspeed-lpc-snoop.c b/drivers/misc/aspeed-lpc-snoop.c
deleted file mode 100644 (file)
index 2feb434..0000000
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Copyright 2017 Google Inc
- *
- * 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.
- *
- * Provides a simple driver to control the ASPEED LPC snoop interface which
- * allows the BMC to listen on and save the data written by
- * the host to an arbitrary LPC I/O port.
- *
- * Typically used by the BMC to "watch" host boot progress via port
- * 0x80 writes made by the BIOS during the boot process.
- */
-
-#include <linux/bitops.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/kfifo.h>
-#include <linux/mfd/syscon.h>
-#include <linux/miscdevice.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/poll.h>
-#include <linux/regmap.h>
-
-#define DEVICE_NAME    "aspeed-lpc-snoop"
-
-#define NUM_SNOOP_CHANNELS 2
-#define SNOOP_FIFO_SIZE 2048
-
-#define HICR5  0x0
-#define HICR5_EN_SNP0W         BIT(0)
-#define HICR5_ENINT_SNP0W      BIT(1)
-#define HICR5_EN_SNP1W         BIT(2)
-#define HICR5_ENINT_SNP1W      BIT(3)
-
-#define HICR6  0x4
-#define HICR6_STR_SNP0W                BIT(0)
-#define HICR6_STR_SNP1W                BIT(1)
-#define SNPWADR        0x10
-#define SNPWADR_CH0_MASK       GENMASK(15, 0)
-#define SNPWADR_CH0_SHIFT      0
-#define SNPWADR_CH1_MASK       GENMASK(31, 16)
-#define SNPWADR_CH1_SHIFT      16
-#define SNPWDR 0x14
-#define SNPWDR_CH0_MASK                GENMASK(7, 0)
-#define SNPWDR_CH0_SHIFT       0
-#define SNPWDR_CH1_MASK                GENMASK(15, 8)
-#define SNPWDR_CH1_SHIFT       8
-#define HICRB  0x80
-#define HICRB_ENSNP0D          BIT(14)
-#define HICRB_ENSNP1D          BIT(15)
-
-struct aspeed_lpc_snoop_model_data {
-       /* The ast2400 has bits 14 and 15 as reserved, whereas the ast2500
-        * can use them.
-        */
-       unsigned int has_hicrb_ensnp;
-};
-
-struct aspeed_lpc_snoop_channel {
-       struct kfifo            fifo;
-       wait_queue_head_t       wq;
-       struct miscdevice       miscdev;
-};
-
-struct aspeed_lpc_snoop {
-       struct regmap           *regmap;
-       int                     irq;
-       struct aspeed_lpc_snoop_channel chan[NUM_SNOOP_CHANNELS];
-};
-
-static struct aspeed_lpc_snoop_channel *snoop_file_to_chan(struct file *file)
-{
-       return container_of(file->private_data,
-                           struct aspeed_lpc_snoop_channel,
-                           miscdev);
-}
-
-static ssize_t snoop_file_read(struct file *file, char __user *buffer,
-                               size_t count, loff_t *ppos)
-{
-       struct aspeed_lpc_snoop_channel *chan = snoop_file_to_chan(file);
-       unsigned int copied;
-       int ret = 0;
-
-       if (kfifo_is_empty(&chan->fifo)) {
-               if (file->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
-               ret = wait_event_interruptible(chan->wq,
-                               !kfifo_is_empty(&chan->fifo));
-               if (ret == -ERESTARTSYS)
-                       return -EINTR;
-       }
-       ret = kfifo_to_user(&chan->fifo, buffer, count, &copied);
-
-       return ret ? ret : copied;
-}
-
-static unsigned int snoop_file_poll(struct file *file,
-                                   struct poll_table_struct *pt)
-{
-       struct aspeed_lpc_snoop_channel *chan = snoop_file_to_chan(file);
-
-       poll_wait(file, &chan->wq, pt);
-       return !kfifo_is_empty(&chan->fifo) ? POLLIN : 0;
-}
-
-static const struct file_operations snoop_fops = {
-       .owner  = THIS_MODULE,
-       .read   = snoop_file_read,
-       .poll   = snoop_file_poll,
-       .llseek = noop_llseek,
-};
-
-/* Save a byte to a FIFO and discard the oldest byte if FIFO is full */
-static void put_fifo_with_discard(struct aspeed_lpc_snoop_channel *chan, u8 val)
-{
-       if (!kfifo_initialized(&chan->fifo))
-               return;
-       if (kfifo_is_full(&chan->fifo))
-               kfifo_skip(&chan->fifo);
-       kfifo_put(&chan->fifo, val);
-       wake_up_interruptible(&chan->wq);
-}
-
-static irqreturn_t aspeed_lpc_snoop_irq(int irq, void *arg)
-{
-       struct aspeed_lpc_snoop *lpc_snoop = arg;
-       u32 reg, data;
-
-       if (regmap_read(lpc_snoop->regmap, HICR6, &reg))
-               return IRQ_NONE;
-
-       /* Check if one of the snoop channels is interrupting */
-       reg &= (HICR6_STR_SNP0W | HICR6_STR_SNP1W);
-       if (!reg)
-               return IRQ_NONE;
-
-       /* Ack pending IRQs */
-       regmap_write(lpc_snoop->regmap, HICR6, reg);
-
-       /* Read and save most recent snoop'ed data byte to FIFO */
-       regmap_read(lpc_snoop->regmap, SNPWDR, &data);
-
-       if (reg & HICR6_STR_SNP0W) {
-               u8 val = (data & SNPWDR_CH0_MASK) >> SNPWDR_CH0_SHIFT;
-
-               put_fifo_with_discard(&lpc_snoop->chan[0], val);
-       }
-       if (reg & HICR6_STR_SNP1W) {
-               u8 val = (data & SNPWDR_CH1_MASK) >> SNPWDR_CH1_SHIFT;
-
-               put_fifo_with_discard(&lpc_snoop->chan[1], val);
-       }
-
-       return IRQ_HANDLED;
-}
-
-static int aspeed_lpc_snoop_config_irq(struct aspeed_lpc_snoop *lpc_snoop,
-                                      struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       int rc;
-
-       lpc_snoop->irq = platform_get_irq(pdev, 0);
-       if (!lpc_snoop->irq)
-               return -ENODEV;
-
-       rc = devm_request_irq(dev, lpc_snoop->irq,
-                             aspeed_lpc_snoop_irq, IRQF_SHARED,
-                             DEVICE_NAME, lpc_snoop);
-       if (rc < 0) {
-               dev_warn(dev, "Unable to request IRQ %d\n", lpc_snoop->irq);
-               lpc_snoop->irq = 0;
-               return rc;
-       }
-
-       return 0;
-}
-
-static int aspeed_lpc_enable_snoop(struct aspeed_lpc_snoop *lpc_snoop,
-                                  struct device *dev,
-                                  int channel, u16 lpc_port)
-{
-       int rc = 0;
-       u32 hicr5_en, snpwadr_mask, snpwadr_shift, hicrb_en;
-       const struct aspeed_lpc_snoop_model_data *model_data =
-               of_device_get_match_data(dev);
-
-       init_waitqueue_head(&lpc_snoop->chan[channel].wq);
-       /* Create FIFO datastructure */
-       rc = kfifo_alloc(&lpc_snoop->chan[channel].fifo,
-                        SNOOP_FIFO_SIZE, GFP_KERNEL);
-       if (rc)
-               return rc;
-
-       lpc_snoop->chan[channel].miscdev.minor = MISC_DYNAMIC_MINOR;
-       lpc_snoop->chan[channel].miscdev.name =
-               devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, channel);
-       lpc_snoop->chan[channel].miscdev.fops = &snoop_fops;
-       lpc_snoop->chan[channel].miscdev.parent = dev;
-       rc = misc_register(&lpc_snoop->chan[channel].miscdev);
-       if (rc)
-               return rc;
-
-       /* Enable LPC snoop channel at requested port */
-       switch (channel) {
-       case 0:
-               hicr5_en = HICR5_EN_SNP0W | HICR5_ENINT_SNP0W;
-               snpwadr_mask = SNPWADR_CH0_MASK;
-               snpwadr_shift = SNPWADR_CH0_SHIFT;
-               hicrb_en = HICRB_ENSNP0D;
-               break;
-       case 1:
-               hicr5_en = HICR5_EN_SNP1W | HICR5_ENINT_SNP1W;
-               snpwadr_mask = SNPWADR_CH1_MASK;
-               snpwadr_shift = SNPWADR_CH1_SHIFT;
-               hicrb_en = HICRB_ENSNP1D;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       regmap_update_bits(lpc_snoop->regmap, HICR5, hicr5_en, hicr5_en);
-       regmap_update_bits(lpc_snoop->regmap, SNPWADR, snpwadr_mask,
-                          lpc_port << snpwadr_shift);
-       if (model_data->has_hicrb_ensnp)
-               regmap_update_bits(lpc_snoop->regmap, HICRB,
-                               hicrb_en, hicrb_en);
-
-       return rc;
-}
-
-static void aspeed_lpc_disable_snoop(struct aspeed_lpc_snoop *lpc_snoop,
-                                    int channel)
-{
-       switch (channel) {
-       case 0:
-               regmap_update_bits(lpc_snoop->regmap, HICR5,
-                                  HICR5_EN_SNP0W | HICR5_ENINT_SNP0W,
-                                  0);
-               break;
-       case 1:
-               regmap_update_bits(lpc_snoop->regmap, HICR5,
-                                  HICR5_EN_SNP1W | HICR5_ENINT_SNP1W,
-                                  0);
-               break;
-       default:
-               return;
-       }
-
-       kfifo_free(&lpc_snoop->chan[channel].fifo);
-       misc_deregister(&lpc_snoop->chan[channel].miscdev);
-}
-
-static int aspeed_lpc_snoop_probe(struct platform_device *pdev)
-{
-       struct aspeed_lpc_snoop *lpc_snoop;
-       struct device *dev;
-       u32 port;
-       int rc;
-
-       dev = &pdev->dev;
-
-       lpc_snoop = devm_kzalloc(dev, sizeof(*lpc_snoop), GFP_KERNEL);
-       if (!lpc_snoop)
-               return -ENOMEM;
-
-       lpc_snoop->regmap = syscon_node_to_regmap(
-                       pdev->dev.parent->of_node);
-       if (IS_ERR(lpc_snoop->regmap)) {
-               dev_err(dev, "Couldn't get regmap\n");
-               return -ENODEV;
-       }
-
-       dev_set_drvdata(&pdev->dev, lpc_snoop);
-
-       rc = of_property_read_u32_index(dev->of_node, "snoop-ports", 0, &port);
-       if (rc) {
-               dev_err(dev, "no snoop ports configured\n");
-               return -ENODEV;
-       }
-
-       rc = aspeed_lpc_snoop_config_irq(lpc_snoop, pdev);
-       if (rc)
-               return rc;
-
-       rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 0, port);
-       if (rc)
-               return rc;
-
-       /* Configuration of 2nd snoop channel port is optional */
-       if (of_property_read_u32_index(dev->of_node, "snoop-ports",
-                                      1, &port) == 0) {
-               rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 1, port);
-               if (rc)
-                       aspeed_lpc_disable_snoop(lpc_snoop, 0);
-       }
-
-       return rc;
-}
-
-static int aspeed_lpc_snoop_remove(struct platform_device *pdev)
-{
-       struct aspeed_lpc_snoop *lpc_snoop = dev_get_drvdata(&pdev->dev);
-
-       /* Disable both snoop channels */
-       aspeed_lpc_disable_snoop(lpc_snoop, 0);
-       aspeed_lpc_disable_snoop(lpc_snoop, 1);
-
-       return 0;
-}
-
-static const struct aspeed_lpc_snoop_model_data ast2400_model_data = {
-       .has_hicrb_ensnp = 0,
-};
-
-static const struct aspeed_lpc_snoop_model_data ast2500_model_data = {
-       .has_hicrb_ensnp = 1,
-};
-
-static const struct of_device_id aspeed_lpc_snoop_match[] = {
-       { .compatible = "aspeed,ast2400-lpc-snoop",
-         .data = &ast2400_model_data },
-       { .compatible = "aspeed,ast2500-lpc-snoop",
-         .data = &ast2500_model_data },
-       { },
-};
-
-static struct platform_driver aspeed_lpc_snoop_driver = {
-       .driver = {
-               .name           = DEVICE_NAME,
-               .of_match_table = aspeed_lpc_snoop_match,
-       },
-       .probe = aspeed_lpc_snoop_probe,
-       .remove = aspeed_lpc_snoop_remove,
-};
-
-module_platform_driver(aspeed_lpc_snoop_driver);
-
-MODULE_DEVICE_TABLE(of, aspeed_lpc_snoop_match);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Robert Lippert <rlippert@google.com>");
-MODULE_DESCRIPTION("Linux driver to control Aspeed LPC snoop functionality");
diff --git a/drivers/misc/aspeed-p2a-ctrl.c b/drivers/misc/aspeed-p2a-ctrl.c
deleted file mode 100644 (file)
index b60fbea..0000000
+++ /dev/null
@@ -1,444 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2019 Google Inc
- *
- * 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.
- *
- * Provides a simple driver to control the ASPEED P2A interface which allows
- * the host to read and write to various regions of the BMC's memory.
- */
-
-#include <linux/fs.h>
-#include <linux/io.h>
-#include <linux/mfd/syscon.h>
-#include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/regmap.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-
-#include <linux/aspeed-p2a-ctrl.h>
-
-#define DEVICE_NAME    "aspeed-p2a-ctrl"
-
-/* SCU2C is a Misc. Control Register. */
-#define SCU2C 0x2c
-/* SCU180 is the PCIe Configuration Setting Control Register. */
-#define SCU180 0x180
-/* Bit 1 controls the P2A bridge, while bit 0 controls the entire VGA device
- * on the PCI bus.
- */
-#define SCU180_ENP2A BIT(1)
-
-/* The ast2400/2500 both have six ranges. */
-#define P2A_REGION_COUNT 6
-
-struct region {
-       u64 min;
-       u64 max;
-       u32 bit;
-};
-
-struct aspeed_p2a_model_data {
-       /* min, max, bit */
-       struct region regions[P2A_REGION_COUNT];
-};
-
-struct aspeed_p2a_ctrl {
-       struct miscdevice miscdev;
-       struct regmap *regmap;
-
-       const struct aspeed_p2a_model_data *config;
-
-       /* Access to these needs to be locked, held via probe, mapping ioctl,
-        * and release, remove.
-        */
-       struct mutex tracking;
-       u32 readers;
-       u32 readerwriters[P2A_REGION_COUNT];
-
-       phys_addr_t mem_base;
-       resource_size_t mem_size;
-};
-
-struct aspeed_p2a_user {
-       struct file *file;
-       struct aspeed_p2a_ctrl *parent;
-
-       /* The entire memory space is opened for reading once the bridge is
-        * enabled, therefore this needs only to be tracked once per user.
-        * If any user has it open for read, the bridge must stay enabled.
-        */
-       u32 read;
-
-       /* Each entry of the array corresponds to a P2A Region.  If the user
-        * opens for read or readwrite, the reference goes up here.  On
-        * release, this array is walked and references adjusted accordingly.
-        */
-       u32 readwrite[P2A_REGION_COUNT];
-};
-
-static void aspeed_p2a_enable_bridge(struct aspeed_p2a_ctrl *p2a_ctrl)
-{
-       regmap_update_bits(p2a_ctrl->regmap,
-               SCU180, SCU180_ENP2A, SCU180_ENP2A);
-}
-
-static void aspeed_p2a_disable_bridge(struct aspeed_p2a_ctrl *p2a_ctrl)
-{
-       regmap_update_bits(p2a_ctrl->regmap, SCU180, SCU180_ENP2A, 0);
-}
-
-static int aspeed_p2a_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       unsigned long vsize;
-       pgprot_t prot;
-       struct aspeed_p2a_user *priv = file->private_data;
-       struct aspeed_p2a_ctrl *ctrl = priv->parent;
-
-       if (ctrl->mem_base == 0 && ctrl->mem_size == 0)
-               return -EINVAL;
-
-       vsize = vma->vm_end - vma->vm_start;
-       prot = vma->vm_page_prot;
-
-       if (vma->vm_pgoff + vsize > ctrl->mem_base + ctrl->mem_size)
-               return -EINVAL;
-
-       /* ast2400/2500 AHB accesses are not cache coherent */
-       prot = pgprot_noncached(prot);
-
-       if (remap_pfn_range(vma, vma->vm_start,
-               (ctrl->mem_base >> PAGE_SHIFT) + vma->vm_pgoff,
-               vsize, prot))
-               return -EAGAIN;
-
-       return 0;
-}
-
-static bool aspeed_p2a_region_acquire(struct aspeed_p2a_user *priv,
-               struct aspeed_p2a_ctrl *ctrl,
-               struct aspeed_p2a_ctrl_mapping *map)
-{
-       int i;
-       u64 base, end;
-       bool matched = false;
-
-       base = map->addr;
-       end = map->addr + (map->length - 1);
-
-       /* If the value is a legal u32, it will find a match. */
-       for (i = 0; i < P2A_REGION_COUNT; i++) {
-               const struct region *curr = &ctrl->config->regions[i];
-
-               /* If the top of this region is lower than your base, skip it.
-                */
-               if (curr->max < base)
-                       continue;
-
-               /* If the bottom of this region is higher than your end, bail.
-                */
-               if (curr->min > end)
-                       break;
-
-               /* Lock this and update it, therefore it someone else is
-                * closing their file out, this'll preserve the increment.
-                */
-               mutex_lock(&ctrl->tracking);
-               ctrl->readerwriters[i] += 1;
-               mutex_unlock(&ctrl->tracking);
-
-               /* Track with the user, so when they close their file, we can
-                * decrement properly.
-                */
-               priv->readwrite[i] += 1;
-
-               /* Enable the region as read-write. */
-               regmap_update_bits(ctrl->regmap, SCU2C, curr->bit, 0);
-               matched = true;
-       }
-
-       return matched;
-}
-
-static long aspeed_p2a_ioctl(struct file *file, unsigned int cmd,
-               unsigned long data)
-{
-       struct aspeed_p2a_user *priv = file->private_data;
-       struct aspeed_p2a_ctrl *ctrl = priv->parent;
-       void __user *arg = (void __user *)data;
-       struct aspeed_p2a_ctrl_mapping map;
-
-       if (copy_from_user(&map, arg, sizeof(map)))
-               return -EFAULT;
-
-       switch (cmd) {
-       case ASPEED_P2A_CTRL_IOCTL_SET_WINDOW:
-               /* If they want a region to be read-only, since the entire
-                * region is read-only once enabled, we just need to track this
-                * user wants to read from the bridge, and if it's not enabled.
-                * Enable it.
-                */
-               if (map.flags == ASPEED_P2A_CTRL_READ_ONLY) {
-                       mutex_lock(&ctrl->tracking);
-                       ctrl->readers += 1;
-                       mutex_unlock(&ctrl->tracking);
-
-                       /* Track with the user, so when they close their file,
-                        * we can decrement properly.
-                        */
-                       priv->read += 1;
-               } else if (map.flags == ASPEED_P2A_CTRL_READWRITE) {
-                       /* If we don't acquire any region return error. */
-                       if (!aspeed_p2a_region_acquire(priv, ctrl, &map)) {
-                               return -EINVAL;
-                       }
-               } else {
-                       /* Invalid map flags. */
-                       return -EINVAL;
-               }
-
-               aspeed_p2a_enable_bridge(ctrl);
-               return 0;
-       case ASPEED_P2A_CTRL_IOCTL_GET_MEMORY_CONFIG:
-               /* This is a request for the memory-region and corresponding
-                * length that is used by the driver for mmap.
-                */
-
-               map.flags = 0;
-               map.addr = ctrl->mem_base;
-               map.length = ctrl->mem_size;
-
-               return copy_to_user(arg, &map, sizeof(map)) ? -EFAULT : 0;
-       }
-
-       return -EINVAL;
-}
-
-
-/*
- * When a user opens this file, we create a structure to track their mappings.
- *
- * A user can map a region as read-only (bridge enabled), or read-write (bit
- * flipped, and bridge enabled).  Either way, this tracking is used, s.t. when
- * they release the device references are handled.
- *
- * The bridge is not enabled until a user calls an ioctl to map a region,
- * simply opening the device does not enable it.
- */
-static int aspeed_p2a_open(struct inode *inode, struct file *file)
-{
-       struct aspeed_p2a_user *priv;
-
-       priv = kmalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->file = file;
-       priv->read = 0;
-       memset(priv->readwrite, 0, sizeof(priv->readwrite));
-
-       /* The file's private_data is initialized to the p2a_ctrl. */
-       priv->parent = file->private_data;
-
-       /* Set the file's private_data to the user's data. */
-       file->private_data = priv;
-
-       return 0;
-}
-
-/*
- * This will close the users mappings.  It will go through what they had opened
- * for readwrite, and decrement those counts.  If at the end, this is the last
- * user, it'll close the bridge.
- */
-static int aspeed_p2a_release(struct inode *inode, struct file *file)
-{
-       int i;
-       u32 bits = 0;
-       bool open_regions = false;
-       struct aspeed_p2a_user *priv = file->private_data;
-
-       /* Lock others from changing these values until everything is updated
-        * in one pass.
-        */
-       mutex_lock(&priv->parent->tracking);
-
-       priv->parent->readers -= priv->read;
-
-       for (i = 0; i < P2A_REGION_COUNT; i++) {
-               priv->parent->readerwriters[i] -= priv->readwrite[i];
-
-               if (priv->parent->readerwriters[i] > 0)
-                       open_regions = true;
-               else
-                       bits |= priv->parent->config->regions[i].bit;
-       }
-
-       /* Setting a bit to 1 disables the region, so let's just OR with the
-        * above to disable any.
-        */
-
-       /* Note, if another user is trying to ioctl, they can't grab tracking,
-        * and therefore can't grab either register mutex.
-        * If another user is trying to close, they can't grab tracking either.
-        */
-       regmap_update_bits(priv->parent->regmap, SCU2C, bits, bits);
-
-       /* If parent->readers is zero and open windows is 0, disable the
-        * bridge.
-        */
-       if (!open_regions && priv->parent->readers == 0)
-               aspeed_p2a_disable_bridge(priv->parent);
-
-       mutex_unlock(&priv->parent->tracking);
-
-       kfree(priv);
-
-       return 0;
-}
-
-static const struct file_operations aspeed_p2a_ctrl_fops = {
-       .owner = THIS_MODULE,
-       .mmap = aspeed_p2a_mmap,
-       .unlocked_ioctl = aspeed_p2a_ioctl,
-       .open = aspeed_p2a_open,
-       .release = aspeed_p2a_release,
-};
-
-/* The regions are controlled by SCU2C */
-static void aspeed_p2a_disable_all(struct aspeed_p2a_ctrl *p2a_ctrl)
-{
-       int i;
-       u32 value = 0;
-
-       for (i = 0; i < P2A_REGION_COUNT; i++)
-               value |= p2a_ctrl->config->regions[i].bit;
-
-       regmap_update_bits(p2a_ctrl->regmap, SCU2C, value, value);
-
-       /* Disable the bridge. */
-       aspeed_p2a_disable_bridge(p2a_ctrl);
-}
-
-static int aspeed_p2a_ctrl_probe(struct platform_device *pdev)
-{
-       struct aspeed_p2a_ctrl *misc_ctrl;
-       struct device *dev;
-       struct resource resm;
-       struct device_node *node;
-       int rc = 0;
-
-       dev = &pdev->dev;
-
-       misc_ctrl = devm_kzalloc(dev, sizeof(*misc_ctrl), GFP_KERNEL);
-       if (!misc_ctrl)
-               return -ENOMEM;
-
-       mutex_init(&misc_ctrl->tracking);
-
-       /* optional. */
-       node = of_parse_phandle(dev->of_node, "memory-region", 0);
-       if (node) {
-               rc = of_address_to_resource(node, 0, &resm);
-               of_node_put(node);
-               if (rc) {
-                       dev_err(dev, "Couldn't address to resource for reserved memory\n");
-                       return -ENODEV;
-               }
-
-               misc_ctrl->mem_size = resource_size(&resm);
-               misc_ctrl->mem_base = resm.start;
-       }
-
-       misc_ctrl->regmap = syscon_node_to_regmap(pdev->dev.parent->of_node);
-       if (IS_ERR(misc_ctrl->regmap)) {
-               dev_err(dev, "Couldn't get regmap\n");
-               return -ENODEV;
-       }
-
-       misc_ctrl->config = of_device_get_match_data(dev);
-
-       dev_set_drvdata(&pdev->dev, misc_ctrl);
-
-       aspeed_p2a_disable_all(misc_ctrl);
-
-       misc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR;
-       misc_ctrl->miscdev.name = DEVICE_NAME;
-       misc_ctrl->miscdev.fops = &aspeed_p2a_ctrl_fops;
-       misc_ctrl->miscdev.parent = dev;
-
-       rc = misc_register(&misc_ctrl->miscdev);
-       if (rc)
-               dev_err(dev, "Unable to register device\n");
-
-       return rc;
-}
-
-static int aspeed_p2a_ctrl_remove(struct platform_device *pdev)
-{
-       struct aspeed_p2a_ctrl *p2a_ctrl = dev_get_drvdata(&pdev->dev);
-
-       misc_deregister(&p2a_ctrl->miscdev);
-
-       return 0;
-}
-
-#define SCU2C_DRAM     BIT(25)
-#define SCU2C_SPI      BIT(24)
-#define SCU2C_SOC      BIT(23)
-#define SCU2C_FLASH    BIT(22)
-
-static const struct aspeed_p2a_model_data ast2400_model_data = {
-       .regions = {
-               {0x00000000, 0x17FFFFFF, SCU2C_FLASH},
-               {0x18000000, 0x1FFFFFFF, SCU2C_SOC},
-               {0x20000000, 0x2FFFFFFF, SCU2C_FLASH},
-               {0x30000000, 0x3FFFFFFF, SCU2C_SPI},
-               {0x40000000, 0x5FFFFFFF, SCU2C_DRAM},
-               {0x60000000, 0xFFFFFFFF, SCU2C_SOC},
-       }
-};
-
-static const struct aspeed_p2a_model_data ast2500_model_data = {
-       .regions = {
-               {0x00000000, 0x0FFFFFFF, SCU2C_FLASH},
-               {0x10000000, 0x1FFFFFFF, SCU2C_SOC},
-               {0x20000000, 0x3FFFFFFF, SCU2C_FLASH},
-               {0x40000000, 0x5FFFFFFF, SCU2C_SOC},
-               {0x60000000, 0x7FFFFFFF, SCU2C_SPI},
-               {0x80000000, 0xFFFFFFFF, SCU2C_DRAM},
-       }
-};
-
-static const struct of_device_id aspeed_p2a_ctrl_match[] = {
-       { .compatible = "aspeed,ast2400-p2a-ctrl",
-         .data = &ast2400_model_data },
-       { .compatible = "aspeed,ast2500-p2a-ctrl",
-         .data = &ast2500_model_data },
-       { },
-};
-
-static struct platform_driver aspeed_p2a_ctrl_driver = {
-       .driver = {
-               .name           = DEVICE_NAME,
-               .of_match_table = aspeed_p2a_ctrl_match,
-       },
-       .probe = aspeed_p2a_ctrl_probe,
-       .remove = aspeed_p2a_ctrl_remove,
-};
-
-module_platform_driver(aspeed_p2a_ctrl_driver);
-
-MODULE_DEVICE_TABLE(of, aspeed_p2a_ctrl_match);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Patrick Venture <venture@google.com>");
-MODULE_DESCRIPTION("Control for aspeed 2400/2500 P2A VGA HOST to BMC mappings");
index 25265fd0fd6e913a8ac0095cf6ca71f4c3588b60..89cff9d1012bf4eaa58ff56e8715a9face9d2d9f 100644 (file)
@@ -603,7 +603,7 @@ int genwqe_user_vmap(struct genwqe_dev *cd, struct dma_mapping *m, void *uaddr,
        /* pin user pages in memory */
        rc = get_user_pages_fast(data & PAGE_MASK, /* page aligned addr */
                                 m->nr_pages,
-                                m->write,              /* readable/writable */
+                                m->write ? FOLL_WRITE : 0,     /* readable/writable */
                                 m->page_list); /* ptrs to pages */
        if (rc < 0)
                goto fail_get_user_pages;
index 29582fe571519754f7a49df7f605aaf9c0a3d4f8..7b015f2a1c6f43f56547be120ff3a97860876bdc 100644 (file)
 #define PCI_ENDPOINT_TEST_IRQ_TYPE             0x24
 #define PCI_ENDPOINT_TEST_IRQ_NUMBER           0x28
 
+#define PCI_DEVICE_ID_TI_AM654                 0xb00c
+
+#define is_am654_pci_dev(pdev)         \
+               ((pdev)->device == PCI_DEVICE_ID_TI_AM654)
+
 static DEFINE_IDA(pci_endpoint_test_ida);
 
 #define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \
@@ -588,6 +593,7 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
        int ret = -EINVAL;
        enum pci_barno bar;
        struct pci_endpoint_test *test = to_endpoint_test(file->private_data);
+       struct pci_dev *pdev = test->pdev;
 
        mutex_lock(&test->mutex);
        switch (cmd) {
@@ -595,6 +601,8 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
                bar = arg;
                if (bar < 0 || bar > 5)
                        goto ret;
+               if (is_am654_pci_dev(pdev) && bar == BAR_0)
+                       goto ret;
                ret = pci_endpoint_test_bar(test, bar);
                break;
        case PCITEST_LEGACY_IRQ:
@@ -662,6 +670,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
        data = (struct pci_endpoint_test_data *)ent->driver_data;
        if (data) {
                test_reg_bar = data->test_reg_bar;
+               test->test_reg_bar = test_reg_bar;
                test->alignment = data->alignment;
                irq_type = data->irq_type;
        }
@@ -785,11 +794,20 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
+static const struct pci_endpoint_test_data am654_data = {
+       .test_reg_bar = BAR_2,
+       .alignment = SZ_64K,
+       .irq_type = IRQ_TYPE_MSI,
+};
+
 static const struct pci_device_id pci_endpoint_test_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) },
        { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) },
        { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) },
        { PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 0xedda) },
+       { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
+         .driver_data = (kernel_ulong_t)&am654_data
+       },
        { }
 };
 MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl);
index 997f92543dd442b4c4ae3d9944b0b05c4ff2c4c0..422d08da32447c87c0a3775784113e212f832bec 100644 (file)
@@ -242,7 +242,7 @@ static int vmci_host_setup_notify(struct vmci_ctx *context,
        /*
         * Lock physical page backing a given user VA.
         */
-       retval = get_user_pages_fast(uva, 1, 1, &context->notify_page);
+       retval = get_user_pages_fast(uva, 1, FOLL_WRITE, &context->notify_page);
        if (retval != 1) {
                context->notify_page = NULL;
                return VMCI_ERROR_GENERIC;
index f5f1aac9d1633189d2e5068dec76bdfc4b0fceb0..1174735f003d3e96b756fe59683765a2ffbbe3c1 100644 (file)
@@ -659,7 +659,8 @@ static int qp_host_get_user_memory(u64 produce_uva,
        int err = VMCI_SUCCESS;
 
        retval = get_user_pages_fast((uintptr_t) produce_uva,
-                                    produce_q->kernel_if->num_pages, 1,
+                                    produce_q->kernel_if->num_pages,
+                                    FOLL_WRITE,
                                     produce_q->kernel_if->u.h.header_page);
        if (retval < (int)produce_q->kernel_if->num_pages) {
                pr_debug("get_user_pages_fast(produce) failed (retval=%d)",
@@ -671,7 +672,8 @@ static int qp_host_get_user_memory(u64 produce_uva,
        }
 
        retval = get_user_pages_fast((uintptr_t) consume_uva,
-                                    consume_q->kernel_if->num_pages, 1,
+                                    consume_q->kernel_if->num_pages,
+                                    FOLL_WRITE,
                                     consume_q->kernel_if->u.h.header_page);
        if (retval < (int)consume_q->kernel_if->num_pages) {
                pr_debug("get_user_pages_fast(consume) failed (retval=%d)",
index ec980bda071c3faaeead09a224e83b79df4ad09e..b61de360f26f0c578869d944ef7c9b8cae6b611f 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 #include <linux/of_platform.h>
index e22bbff89c8d24c62d075327de4b65935a345162..9cb93e15b197442379cefc21fff2ee4fe2769e6c 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/slot-gpio.h>
 
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/unaligned.h>
 
 #include "mvsdio.h"
index c1d3f0e3892131a46192a68e12807d39b1a36c69..e7d80c83da2c837f6b85a49b2eef4f1377425048 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include <mach/hardware.h>
 #include <linux/platform_data/mmc-pxamci.h>
index 79a8ff5428839abf126dde0362be50478cdcb109..fb31a7f649a3d908989c69149bdaebca24f9f24f 100644 (file)
@@ -60,22 +60,6 @@ config MTD_CMDLINE_PARTS
 
          If unsure, say 'N'.
 
-config MTD_AFS_PARTS
-       tristate "ARM Firmware Suite partition parsing"
-       depends on (ARM || ARM64)
-       help
-         The ARM Firmware Suite allows the user to divide flash devices into
-         multiple 'images'. Each such image has a header containing its name
-         and offset/size etc.
-
-         If you need code which can detect and parse these tables, and
-         register MTD 'partitions' corresponding to each image detected,
-         enable this option.
-
-         You will still need the parsing functions to be called by the driver
-         for your particular device. It won't happen automatically. The
-         'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example.
-
 config MTD_OF_PARTS
        tristate "OpenFirmware partitioning information support"
        default y
@@ -94,6 +78,7 @@ config MTD_BCM63XX_PARTS
        tristate "BCM63XX CFE partitioning support"
        depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
        select CRC32
+       select MTD_PARSER_IMAGETAG
        help
          This provides partition parsing for BCM63xx devices with CFE
          bootloaders.
@@ -230,12 +215,11 @@ config SSFDC
          This enables read only access to SmartMedia formatted NAND
          flash. You can mount it with FAT file system.
 
-
 config SM_FTL
        tristate "SmartMedia/xD new translation layer"
        depends on BLOCK
        select MTD_BLKDEVS
-       select MTD_NAND_ECC
+       select MTD_NAND_ECC_SW_HAMMING
        help
          This enables EXPERIMENTAL R/W support for SmartMedia/xD
          FTL (Flash translation layer).
index 58fc327a5276889b9e6875175cd8958a4930dfa7..806287e80e842621f4560f09e611073bb380364e 100644 (file)
@@ -9,7 +9,6 @@ mtd-y                           := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o
 
 obj-$(CONFIG_MTD_OF_PARTS)     += ofpart.o
 obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
-obj-$(CONFIG_MTD_AFS_PARTS)    += afs.o
 obj-$(CONFIG_MTD_AR7_PARTS)    += ar7part.o
 obj-$(CONFIG_MTD_BCM63XX_PARTS)        += bcm63xxpart.o
 obj-$(CONFIG_MTD_BCM47XX_PARTS)        += bcm47xxpart.o
diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c
deleted file mode 100644 (file)
index d61b7ed..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/*======================================================================
-
-    drivers/mtd/afs.c: ARM Flash Layout/Partitioning
-
-    Copyright © 2000 ARM Limited
-
-   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.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-   This is access code for flashes using ARM's flash partitioning
-   standards.
-
-======================================================================*/
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#define AFSV1_FOOTER_MAGIC 0xA0FFFF9F
-
-struct footer_v1 {
-       u32 image_info_base;    /* Address of first word of ImageFooter  */
-       u32 image_start;        /* Start of area reserved by this footer */
-       u32 signature;          /* 'Magic' number proves it's a footer   */
-       u32 type;               /* Area type: ARM Image, SIB, customer   */
-       u32 checksum;           /* Just this structure                   */
-};
-
-struct image_info_v1 {
-       u32 bootFlags;          /* Boot flags, compression etc.          */
-       u32 imageNumber;        /* Unique number, selects for boot etc.  */
-       u32 loadAddress;        /* Address program should be loaded to   */
-       u32 length;             /* Actual size of image                  */
-       u32 address;            /* Image is executed from here           */
-       char name[16];          /* Null terminated                       */
-       u32 headerBase;         /* Flash Address of any stripped header  */
-       u32 header_length;      /* Length of header in memory            */
-       u32 headerType;         /* AIF, RLF, s-record etc.               */
-       u32 checksum;           /* Image checksum (inc. this struct)     */
-};
-
-static u32 word_sum(void *words, int num)
-{
-       u32 *p = words;
-       u32 sum = 0;
-
-       while (num--)
-               sum += *p++;
-
-       return sum;
-}
-
-static int
-afs_read_footer_v1(struct mtd_info *mtd, u_int *img_start, u_int *iis_start,
-                  u_int off, u_int mask)
-{
-       struct footer_v1 fs;
-       u_int ptr = off + mtd->erasesize - sizeof(fs);
-       size_t sz;
-       int ret;
-
-       ret = mtd_read(mtd, ptr, sizeof(fs), &sz, (u_char *)&fs);
-       if (ret >= 0 && sz != sizeof(fs))
-               ret = -EINVAL;
-
-       if (ret < 0) {
-               printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
-                       ptr, ret);
-               return ret;
-       }
-
-       /*
-        * Does it contain the magic number?
-        */
-       if (fs.signature != AFSV1_FOOTER_MAGIC)
-               return 0;
-
-       /*
-        * Check the checksum.
-        */
-       if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff)
-               return 0;
-
-       /*
-        * Don't touch the SIB.
-        */
-       if (fs.type == 2)
-               return 0;
-
-       *iis_start = fs.image_info_base & mask;
-       *img_start = fs.image_start & mask;
-
-       /*
-        * Check the image info base.  This can not
-        * be located after the footer structure.
-        */
-       if (*iis_start >= ptr)
-               return 0;
-
-       /*
-        * Check the start of this image.  The image
-        * data can not be located after this block.
-        */
-       if (*img_start > off)
-               return 0;
-
-       return 1;
-}
-
-static int
-afs_read_iis_v1(struct mtd_info *mtd, struct image_info_v1 *iis, u_int ptr)
-{
-       size_t sz;
-       int ret, i;
-
-       memset(iis, 0, sizeof(*iis));
-       ret = mtd_read(mtd, ptr, sizeof(*iis), &sz, (u_char *)iis);
-       if (ret < 0)
-               goto failed;
-
-       if (sz != sizeof(*iis)) {
-               ret = -EINVAL;
-               goto failed;
-       }
-
-       ret = 0;
-
-       /*
-        * Validate the name - it must be NUL terminated.
-        */
-       for (i = 0; i < sizeof(iis->name); i++)
-               if (iis->name[i] == '\0')
-                       break;
-
-       if (i < sizeof(iis->name))
-               ret = 1;
-
-       return ret;
-
- failed:
-       printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
-               ptr, ret);
-       return ret;
-}
-
-static int parse_afs_partitions(struct mtd_info *mtd,
-                               const struct mtd_partition **pparts,
-                               struct mtd_part_parser_data *data)
-{
-       struct mtd_partition *parts;
-       u_int mask, off, idx, sz;
-       int ret = 0;
-       char *str;
-
-       /*
-        * This is the address mask; we use this to mask off out of
-        * range address bits.
-        */
-       mask = mtd->size - 1;
-
-       /*
-        * First, calculate the size of the array we need for the
-        * partition information.  We include in this the size of
-        * the strings.
-        */
-       for (idx = off = sz = 0; off < mtd->size; off += mtd->erasesize) {
-               struct image_info_v1 iis;
-               u_int iis_ptr, img_ptr;
-
-               ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask);
-               if (ret < 0)
-                       break;
-               if (ret) {
-                       ret = afs_read_iis_v1(mtd, &iis, iis_ptr);
-                       if (ret < 0)
-                               break;
-                       if (ret == 0)
-                               continue;
-
-                       sz += sizeof(struct mtd_partition);
-                       sz += strlen(iis.name) + 1;
-                       idx += 1;
-               }
-       }
-
-       if (!sz)
-               return ret;
-
-       parts = kzalloc(sz, GFP_KERNEL);
-       if (!parts)
-               return -ENOMEM;
-
-       str = (char *)(parts + idx);
-
-       /*
-        * Identify the partitions
-        */
-       for (idx = off = 0; off < mtd->size; off += mtd->erasesize) {
-               struct image_info_v1 iis;
-               u_int iis_ptr, img_ptr;
-
-               /* Read the footer. */
-               ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask);
-               if (ret < 0)
-                       break;
-               if (ret == 0)
-                       continue;
-
-               /* Read the image info block */
-               ret = afs_read_iis_v1(mtd, &iis, iis_ptr);
-               if (ret < 0)
-                       break;
-               if (ret == 0)
-                       continue;
-
-               strcpy(str, iis.name);
-
-               parts[idx].name         = str;
-               parts[idx].size         = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1);
-               parts[idx].offset       = img_ptr;
-               parts[idx].mask_flags   = 0;
-
-               printk("  mtd%d: at 0x%08x, %5lluKiB, %8u, %s\n",
-                       idx, img_ptr, parts[idx].size / 1024,
-                       iis.imageNumber, str);
-
-               idx += 1;
-               str = str + strlen(iis.name) + 1;
-       }
-
-       if (!idx) {
-               kfree(parts);
-               parts = NULL;
-       }
-
-       *pparts = parts;
-       return idx ? idx : ret;
-}
-
-static struct mtd_part_parser afs_parser = {
-       .parse_fn = parse_afs_partitions,
-       .name = "afs",
-};
-module_mtd_part_parser(afs_parser);
-
-MODULE_AUTHOR("ARM Ltd");
-MODULE_DESCRIPTION("ARM Firmware Suite partition parser");
-MODULE_LICENSE("GPL");
index 41d1d3149c611777fcd904d12546ed50db739cec..b2bd04764e9544f1a7e21965d893498ac87e64ba 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/vmalloc.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/of.h>
 
 #define BCM963XX_CFE_BLOCK_SIZE                SZ_64K  /* always at least 64KiB */
 
@@ -93,51 +94,19 @@ static int bcm63xx_read_nvram(struct mtd_info *master,
        return 0;
 }
 
-static int bcm63xx_read_image_tag(struct mtd_info *master, const char *name,
-       loff_t tag_offset, struct bcm_tag *buf)
-{
-       int ret;
-       size_t retlen;
-       u32 computed_crc;
-
-       ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf);
-       if (ret)
-               return ret;
-
-       if (retlen != sizeof(*buf))
-               return -EIO;
-
-       computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
-                               offsetof(struct bcm_tag, header_crc));
-       if (computed_crc == buf->header_crc) {
-               STR_NULL_TERMINATE(buf->board_id);
-               STR_NULL_TERMINATE(buf->tag_version);
-
-               pr_info("%s: CFE image tag found at 0x%llx with version %s, board type %s\n",
-                       name, tag_offset, buf->tag_version, buf->board_id);
-
-               return 0;
-       }
-
-       pr_warn("%s: CFE image tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n",
-               name, tag_offset, buf->header_crc, computed_crc);
-       return 1;
-}
+static const char * const bcm63xx_cfe_part_types[] = {
+       "bcm963xx-imagetag",
+       NULL,
+};
 
 static int bcm63xx_parse_cfe_nor_partitions(struct mtd_info *master,
        const struct mtd_partition **pparts, struct bcm963xx_nvram *nvram)
 {
-       /* CFE, NVRAM and global Linux are always present */
-       int nrparts = 3, curpart = 0;
-       struct bcm_tag *buf = NULL;
        struct mtd_partition *parts;
-       int ret;
-       unsigned int rootfsaddr, kerneladdr, spareaddr;
-       unsigned int rootfslen, kernellen, sparelen, totallen;
+       int nrparts = 3, curpart = 0;
        unsigned int cfelen, nvramlen;
        unsigned int cfe_erasesize;
        int i;
-       bool rootfs_first = false;
 
        cfe_erasesize = max_t(uint32_t, master->erasesize,
                              BCM963XX_CFE_BLOCK_SIZE);
@@ -146,83 +115,9 @@ static int bcm63xx_parse_cfe_nor_partitions(struct mtd_info *master,
        nvramlen = nvram->psi_size * SZ_1K;
        nvramlen = roundup(nvramlen, cfe_erasesize);
 
-       buf = vmalloc(sizeof(struct bcm_tag));
-       if (!buf)
-               return -ENOMEM;
-
-       /* Get the tag */
-       ret = bcm63xx_read_image_tag(master, "rootfs", cfelen, buf);
-       if (!ret) {
-               STR_NULL_TERMINATE(buf->flash_image_start);
-               if (kstrtouint(buf->flash_image_start, 10, &rootfsaddr) ||
-                               rootfsaddr < BCM963XX_EXTENDED_SIZE) {
-                       pr_err("invalid rootfs address: %*ph\n",
-                               (int)sizeof(buf->flash_image_start),
-                               buf->flash_image_start);
-                       goto invalid_tag;
-               }
-
-               STR_NULL_TERMINATE(buf->kernel_address);
-               if (kstrtouint(buf->kernel_address, 10, &kerneladdr) ||
-                               kerneladdr < BCM963XX_EXTENDED_SIZE) {
-                       pr_err("invalid kernel address: %*ph\n",
-                               (int)sizeof(buf->kernel_address),
-                               buf->kernel_address);
-                       goto invalid_tag;
-               }
-
-               STR_NULL_TERMINATE(buf->kernel_length);
-               if (kstrtouint(buf->kernel_length, 10, &kernellen)) {
-                       pr_err("invalid kernel length: %*ph\n",
-                               (int)sizeof(buf->kernel_length),
-                               buf->kernel_length);
-                       goto invalid_tag;
-               }
-
-               STR_NULL_TERMINATE(buf->total_length);
-               if (kstrtouint(buf->total_length, 10, &totallen)) {
-                       pr_err("invalid total length: %*ph\n",
-                               (int)sizeof(buf->total_length),
-                               buf->total_length);
-                       goto invalid_tag;
-               }
-
-               kerneladdr = kerneladdr - BCM963XX_EXTENDED_SIZE;
-               rootfsaddr = rootfsaddr - BCM963XX_EXTENDED_SIZE;
-               spareaddr = roundup(totallen, master->erasesize) + cfelen;
-
-               if (rootfsaddr < kerneladdr) {
-                       /* default Broadcom layout */
-                       rootfslen = kerneladdr - rootfsaddr;
-                       rootfs_first = true;
-               } else {
-                       /* OpenWrt layout */
-                       rootfsaddr = kerneladdr + kernellen;
-                       rootfslen = spareaddr - rootfsaddr;
-               }
-       } else if (ret > 0) {
-invalid_tag:
-               kernellen = 0;
-               rootfslen = 0;
-               rootfsaddr = 0;
-               spareaddr = cfelen;
-       } else {
-               goto out;
-       }
-       sparelen = master->size - spareaddr - nvramlen;
-
-       /* Determine number of partitions */
-       if (rootfslen > 0)
-               nrparts++;
-
-       if (kernellen > 0)
-               nrparts++;
-
        parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
-       if (!parts) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!parts)
+               return -ENOMEM;
 
        /* Start building partition list */
        parts[curpart].name = "CFE";
@@ -230,30 +125,6 @@ invalid_tag:
        parts[curpart].size = cfelen;
        curpart++;
 
-       if (kernellen > 0) {
-               int kernelpart = curpart;
-
-               if (rootfslen > 0 && rootfs_first)
-                       kernelpart++;
-               parts[kernelpart].name = "kernel";
-               parts[kernelpart].offset = kerneladdr;
-               parts[kernelpart].size = kernellen;
-               curpart++;
-       }
-
-       if (rootfslen > 0) {
-               int rootfspart = curpart;
-
-               if (kernellen > 0 && rootfs_first)
-                       rootfspart--;
-               parts[rootfspart].name = "rootfs";
-               parts[rootfspart].offset = rootfsaddr;
-               parts[rootfspart].size = rootfslen;
-               if (sparelen > 0  && !rootfs_first)
-                       parts[rootfspart].size += sparelen;
-               curpart++;
-       }
-
        parts[curpart].name = "nvram";
        parts[curpart].offset = master->size - nvramlen;
        parts[curpart].size = nvramlen;
@@ -263,22 +134,13 @@ invalid_tag:
        parts[curpart].name = "linux";
        parts[curpart].offset = cfelen;
        parts[curpart].size = master->size - cfelen - nvramlen;
+       parts[curpart].types = bcm63xx_cfe_part_types;
 
        for (i = 0; i < nrparts; i++)
                pr_info("Partition %d is %s offset %llx and length %llx\n", i,
                        parts[i].name, parts[i].offset, parts[i].size);
 
-       pr_info("Spare partition is offset %x and length %x\n", spareaddr,
-               sparelen);
-
        *pparts = parts;
-       ret = 0;
-
-out:
-       vfree(buf);
-
-       if (ret)
-               return ret;
 
        return nrparts;
 }
@@ -311,9 +173,16 @@ out:
        return ret;
 };
 
+static const struct of_device_id parse_bcm63xx_cfe_match_table[] = {
+       { .compatible = "brcm,bcm963xx-cfe-nor-partitions" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, parse_bcm63xx_cfe_match_table);
+
 static struct mtd_part_parser bcm63xx_cfe_parser = {
        .parse_fn = bcm63xx_parse_cfe_partitions,
        .name = "bcm63xxpart",
+       .of_match_table = parse_bcm63xx_cfe_match_table,
 };
 module_mtd_part_parser(bcm63xx_cfe_parser);
 
index 7b7286b4d81ef660d22a9ca93e5f0f2870ea5666..c8fa5906bdf9a2a3b9fb356032e59a7617cce165 100644 (file)
@@ -869,6 +869,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                /* Only if there's no operation suspended... */
                if (mode == FL_READY && chip->oldstate == FL_READY)
                        return 0;
+               /* fall through */
 
        default:
        sleep:
@@ -2751,6 +2752,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd)
                         * as the whole point is that nobody can do anything
                         * with the chip now anyway.
                         */
+                       /* fall through */
                case FL_SYNCING:
                        mutex_unlock(&chip->mutex);
                        break;
index 6f16552cd59f48d4cb4aab5f6fb3a250190cb4c2..e3b266ee06affca58e561b399d5744cd0d6794f2 100644 (file)
@@ -109,10 +109,13 @@ map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi
        case 8:
                onecmd |= (onecmd << (chip_mode * 32));
 #endif
+               /* fall through */
        case 4:
                onecmd |= (onecmd << (chip_mode * 16));
+               /* fall through */
        case 2:
                onecmd |= (onecmd << (chip_mode * 8));
+               /* fall through */
        case 1:
                ;
        }
@@ -162,10 +165,13 @@ unsigned long cfi_merge_status(map_word val, struct map_info *map,
        case 8:
                res |= (onestat >> (chip_mode * 32));
 #endif
+               /* fall through */
        case 4:
                res |= (onestat >> (chip_mode * 16));
+               /* fall through */
        case 2:
                res |= (onestat >> (chip_mode * 8));
+               /* fall through */
        case 1:
                ;
        }
index aa983422aa970f1035201a1a4841b7a09d9acc3f..f9258d6668460643cf1d8849a4dca6b8b3059840 100644 (file)
@@ -207,7 +207,7 @@ comment "Disk-On-Chip Device Drivers"
 config MTD_DOCG3
        tristate "M-Systems Disk-On-Chip G3"
        select BCH
-       select BCH_CONST_PARAMS if !MTD_NAND_BCH
+       select BCH_CONST_PARAMS if !MTD_NAND_ECC_SW_BCH
        select BITREVERSE
        help
          This provides an MTD device driver for the M-Systems DiskOnChip
index 9ee04b5f931139cbb6d119c6901c39a4a39cda0f..8a8627c30aedfa60cd8fdf2448cb47a3ed80a99d 100644 (file)
@@ -147,8 +147,10 @@ static int parse_num64(uint64_t *num64, char *token)
                        switch (token[len - 2]) {
                        case 'G':
                                shift += 10;
+                               /* fall through */
                        case 'M':
                                shift += 10;
+                               /* fall through */
                        case 'k':
                                shift += 10;
                                token[len - 2] = 0;
index b13557fe52bd0b3d4589eeb7ae7c890bf69eca77..76a4c73e100e836fd2259ee0aa6b944d424e7252 100644 (file)
@@ -318,6 +318,7 @@ static int chip_ready(struct map_info *map, struct flchip *chip, int mode)
                /* Only if there's no operation suspended... */
                if (mode == FL_READY && chip->oldstate == FL_READY)
                        return 0;
+               /* fall through */
 
        default:
 sleep:
index e0cf869c854439d5b178f2f2361d638ad97c4cb4..544ed193184348b8fa93d6a77c68388660dde75a 100644 (file)
@@ -10,7 +10,7 @@ config MTD_COMPLEX_MAPPINGS
 
 config MTD_PHYSMAP
        tristate "Flash device in physical memory map"
-       depends on MTD_CFI || MTD_JEDECPROBE || MTD_ROM || MTD_LPDDR
+       depends on MTD_CFI || MTD_JEDECPROBE || MTD_ROM || MTD_RAM || MTD_LPDDR
        help
          This provides a 'mapping' driver which allows the NOR Flash and
          ROM driver code to communicate with chips which are mapped
index d9a3e4bebe5d8b94fea7fe983fc2db405dd729ae..21b556afc30504709b5d38552068bdf4981dadca 100644 (file)
@@ -132,6 +132,8 @@ static void physmap_set_addr_gpios(struct physmap_flash_info *info,
 
                gpiod_set_value(info->gpios->desc[i], !!(BIT(i) & ofs));
        }
+
+       info->gpio_values = ofs;
 }
 
 #define win_mask(order)                (BIT(order) - 1)
index 60775b208fc9dd5254fbe6afa4d7afb207a1cc5b..a289c8b5cabf8e57a81f23d3efe6085bc6c904eb 100644 (file)
@@ -86,7 +86,7 @@ static void gemini_flash_disable_pins(void)
 static map_word __xipram gemini_flash_map_read(struct map_info *map,
                                               unsigned long ofs)
 {
-       map_word __xipram ret;
+       map_word ret;
 
        gemini_flash_enable_pins();
        ret = inline_map_read(map, ofs);
index fd5fe12d74613ecebddb88699dcae5e1862d3829..893239629d6bb64523d228195adeb893b84c6034 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/mtd/concat.h>
 
 #include <mach/hardware.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/mach/flash.h>
 
 struct sa_subdev_info {
index aef030ca8601c709cc735a180b6c997f8b951f7c..de4c46318abb80c1938345fe0b62083c7c673017 100644 (file)
 #define MAP_NAME "ram"
 #endif
 
-/*
- * Blackfin uses uclinux_ram_map during startup, so it must not be static.
- * Provide a dummy declaration to make sparse happy.
- */
-extern struct map_info uclinux_ram_map;
-
-struct map_info uclinux_ram_map = {
+static struct map_info uclinux_ram_map = {
        .name = MAP_NAME,
        .size = 0,
 };
index 37f174ccbcec4b1f10d0af717707a38fa46d4499..dfa241ad018b3e7f0e35510eb170ef061c842ac1 100644 (file)
@@ -572,7 +572,7 @@ static ssize_t mtd_partition_offset_show(struct device *dev,
 {
        struct mtd_info *mtd = dev_get_drvdata(dev);
        struct mtd_part *part = mtd_to_part(mtd);
-       return snprintf(buf, PAGE_SIZE, "%lld\n", part->offset);
+       return snprintf(buf, PAGE_SIZE, "%llu\n", part->offset);
 }
 
 static DEVICE_ATTR(offset, S_IRUGO, mtd_partition_offset_show, NULL);
index 9033215e62ea001b1b39ef02b5e0258115b7875f..495751ed3fd7648ec111dd233a57eaeba3b11718 100644 (file)
@@ -2,6 +2,5 @@ config MTD_NAND_CORE
        tristate
 
 source "drivers/mtd/nand/onenand/Kconfig"
-
 source "drivers/mtd/nand/raw/Kconfig"
 source "drivers/mtd/nand/spi/Kconfig"
index 9c9f8936b63bc37bbcbd7c6d22d6ca85d69f388f..b6de955ac8bf106d3e9e9c4438ff96e36a9ec183 100644 (file)
@@ -173,6 +173,40 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)
 }
 EXPORT_SYMBOL_GPL(nanddev_mtd_erase);
 
+/**
+ * nanddev_mtd_max_bad_blocks() - Get the maximum number of bad eraseblock on
+ *                               a specific region of the NAND device
+ * @mtd: MTD device
+ * @offs: offset of the NAND region
+ * @len: length of the NAND region
+ *
+ * Default implementation for mtd->_max_bad_blocks(). Only works if
+ * nand->memorg.max_bad_eraseblocks_per_lun is > 0.
+ *
+ * Return: a positive number encoding the maximum number of eraseblocks on a
+ * portion of memory, a negative error code otherwise.
+ */
+int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len)
+{
+       struct nand_device *nand = mtd_to_nanddev(mtd);
+       struct nand_pos pos, end;
+       unsigned int max_bb = 0;
+
+       if (!nand->memorg.max_bad_eraseblocks_per_lun)
+               return -ENOTSUPP;
+
+       nanddev_offs_to_pos(nand, offs, &pos);
+       nanddev_offs_to_pos(nand, offs + len, &end);
+
+       for (nanddev_offs_to_pos(nand, offs, &pos);
+            nanddev_pos_cmp(&pos, &end) < 0;
+            nanddev_pos_next_lun(nand, &pos))
+               max_bb += nand->memorg.max_bad_eraseblocks_per_lun;
+
+       return max_bb;
+}
+EXPORT_SYMBOL_GPL(nanddev_mtd_max_bad_blocks);
+
 /**
  * nanddev_init() - Initialize a NAND device
  * @nand: NAND device
index 4ca4b194e7d724411de9ad2fbc43fbb7a338cb39..f41d7624855049d1546d3c74268759e069ad761f 100644 (file)
@@ -2458,7 +2458,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
                 bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
 
         /* We write two bytes, so we don't have to mess with 16-bit access */
-        ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
+        ofs += mtd->oobsize + (this->badblockpos & ~0x01);
        /* FIXME : What to do when marking SLC block in partition
         *         with MLC erasesize? For now, it is not advisable to
         *         create partitions containing both SLC and MLC regions.
@@ -3967,6 +3967,9 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
        if (!(this->options & ONENAND_SKIP_INITIAL_UNLOCKING))
                this->unlock_all(mtd);
 
+       /* Set the bad block marker position */
+       this->badblockpos = ONENAND_BADBLOCK_POS;
+
        ret = this->scan_bbt(mtd);
        if ((!FLEXONENAND(this)) || ret)
                return ret;
index dde20487937dde328ce6b82d829c29c193eb75be..57c31c81be1865cdddd9f5451e7b1c4372d31897 100644 (file)
@@ -190,9 +190,6 @@ static int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
        if (!bbm->bbt)
                return -ENOMEM;
 
-       /* Set the bad block position */
-       bbm->badblockpos = ONENAND_BADBLOCK_POS;
-
        /* Set erase shift */
        bbm->bbt_erase_shift = this->erase_shift;
 
index e604625e2dfa402c783d14266e8a201de81ee7d2..0500c42f31cbd177bf3112bba899967d939dd702 100644 (file)
@@ -1,34 +1,29 @@
-config MTD_NAND_ECC
+config MTD_NAND_ECC_SW_HAMMING
        tristate
 
-config MTD_NAND_ECC_SMC
+config MTD_NAND_ECC_SW_HAMMING_SMC
        bool "NAND ECC Smart Media byte order"
-       depends on MTD_NAND_ECC
+       depends on MTD_NAND_ECC_SW_HAMMING
        default n
        help
          Software ECC according to the Smart Media Specification.
          The original Linux implementation had byte 0 and 1 swapped.
 
-
-menuconfig MTD_NAND
+menuconfig MTD_RAW_NAND
        tristate "Raw/Parallel NAND Device Support"
        depends on MTD
-       select MTD_NAND_ECC
+       select MTD_NAND_CORE
+       select MTD_NAND_ECC_SW_HAMMING
        help
          This enables support for accessing all type of raw/parallel
          NAND flash devices. For further information see
          <http://www.linux-mtd.infradead.org/doc/nand.html>.
 
-if MTD_NAND
+if MTD_RAW_NAND
 
-config MTD_NAND_BCH
-       tristate
-       select BCH
-       depends on MTD_NAND_ECC_BCH
-       default MTD_NAND
-
-config MTD_NAND_ECC_BCH
+config MTD_NAND_ECC_SW_BCH
        bool "Support software BCH ECC"
+       select BCH
        default n
        help
          This enables support for software BCH error correction. Binary BCH
@@ -36,15 +31,13 @@ config MTD_NAND_ECC_BCH
          ECC codes. They are used with NAND devices requiring more than 1 bit
          of error correction.
 
-config MTD_SM_COMMON
-       tristate
-       default n
+comment "Raw/parallel NAND flash controllers"
 
 config MTD_NAND_DENALI
        tristate
 
 config MTD_NAND_DENALI_PCI
-       tristate "Support Denali NAND controller on Intel Moorestown"
+       tristate "Denali NAND controller on Intel Moorestown"
        select MTD_NAND_DENALI
        depends on PCI
        help
@@ -52,31 +45,22 @@ config MTD_NAND_DENALI_PCI
          Denali NAND controller core.
 
 config MTD_NAND_DENALI_DT
-       tristate "Support Denali NAND controller as a DT device"
+       tristate "Denali NAND controller as a DT device"
        select MTD_NAND_DENALI
        depends on HAS_DMA && HAVE_CLK && OF
        help
          Enable the driver for NAND flash on platforms using a Denali NAND
          controller as a DT device.
 
-config MTD_NAND_GPIO
-       tristate "GPIO assisted NAND Flash driver"
-       depends on GPIOLIB || COMPILE_TEST
-       depends on HAS_IOMEM
-       help
-         This enables a NAND flash driver where control signals are
-         connected to GPIO pins, and commands and data are communicated
-         via a memory mapped interface.
-
 config MTD_NAND_AMS_DELTA
-       tristate "NAND Flash device on Amstrad E3"
+       tristate "Amstrad E3 NAND controller"
        depends on MACH_AMS_DELTA || COMPILE_TEST
        default y
        help
          Support for NAND flash on Amstrad E3 (Delta).
 
 config MTD_NAND_OMAP2
-       tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
+       tristate "OMAP2, OMAP3, OMAP4 and Keystone NAND controller"
        depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || COMPILE_TEST
        depends on HAS_IOMEM
        help
@@ -98,18 +82,6 @@ config MTD_NAND_OMAP_BCH
 config MTD_NAND_OMAP_BCH_BUILD
        def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
 
-config MTD_NAND_RICOH
-       tristate "Ricoh xD card reader"
-       default n
-       depends on PCI
-       select MTD_SM_COMMON
-       help
-         Enable support for Ricoh R5C852 xD card reader
-         You also need to enable ether
-         NAND SSFDC (SmartMedia) read only translation layer' or new
-         expermental, readwrite
-         'SmartMedia/xD new translation layer'
-
 config MTD_NAND_AU1550
        tristate "Au1550/1200 NAND support"
        depends on MIPS_ALCHEMY
@@ -117,8 +89,15 @@ config MTD_NAND_AU1550
          This enables the driver for the NAND flash controller on the
          AMD/Alchemy 1550 SOC.
 
+config MTD_NAND_NDFC
+       tristate "IBM/MCC 4xx NAND controller"
+       depends on 4xx
+       select MTD_NAND_ECC_SW_HAMMING_SMC
+       help
+         NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
+
 config MTD_NAND_S3C2410
-       tristate "NAND Flash support for Samsung S3C SoCs"
+       tristate "Samsung S3C NAND controller"
        depends on ARCH_S3C24XX || ARCH_S3C64XX
        help
          This enables the NAND flash controller on the S3C24xx and S3C64xx
@@ -128,18 +107,11 @@ config MTD_NAND_S3C2410
          must advertise a platform_device for the driver to attach.
 
 config MTD_NAND_S3C2410_DEBUG
-       bool "Samsung S3C NAND driver debug"
+       bool "Samsung S3C NAND controller debug"
        depends on MTD_NAND_S3C2410
        help
          Enable debugging of the S3C NAND driver
 
-config MTD_NAND_NDFC
-       tristate "NDFC NanD Flash Controller"
-       depends on 4xx
-       select MTD_NAND_ECC_SMC
-       help
-         NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
-
 config MTD_NAND_S3C2410_CLKSTOP
        bool "Samsung S3C NAND IDLE clock stop"
        depends on MTD_NAND_S3C2410
@@ -151,89 +123,19 @@ config MTD_NAND_S3C2410_CLKSTOP
          approximately 5mA of power when there is nothing happening.
 
 config MTD_NAND_TANGO
-       tristate "NAND Flash support for Tango chips"
+       tristate "Tango NAND controller"
        depends on ARCH_TANGO || COMPILE_TEST
        depends on HAS_IOMEM
        help
          Enables the NAND Flash controller on Tango chips.
 
-config MTD_NAND_DISKONCHIP
-       tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
-       depends on HAS_IOMEM
-       select REED_SOLOMON
-       select REED_SOLOMON_DEC16
-       help
-         This is a reimplementation of M-Systems DiskOnChip 2000,
-         Millennium and Millennium Plus as a standard NAND device driver,
-         as opposed to the earlier self-contained MTD device drivers.
-         This should enable, among other things, proper JFFS2 operation on
-         these devices.
-
-config MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-       bool "Advanced detection options for DiskOnChip"
-       depends on MTD_NAND_DISKONCHIP
-       help
-         This option allows you to specify nonstandard address at which to
-         probe for a DiskOnChip, or to change the detection options.  You
-         are unlikely to need any of this unless you are using LinuxBIOS.
-         Say 'N'.
-
-config MTD_NAND_DISKONCHIP_PROBE_ADDRESS
-       hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-       depends on MTD_NAND_DISKONCHIP
-       default "0"
-       help
-         By default, the probe for DiskOnChip devices will look for a
-         DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
-         This option allows you to specify a single address at which to probe
-         for the device, which is useful if you have other devices in that
-         range which get upset when they are probed.
-
-         (Note that on PowerPC, the normal probe will only check at
-         0xE4000000.)
-
-         Normally, you should leave this set to zero, to allow the probe at
-         the normal addresses.
-
-config MTD_NAND_DISKONCHIP_PROBE_HIGH
-       bool "Probe high addresses"
-       depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-       help
-         By default, the probe for DiskOnChip devices will look for a
-         DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
-         This option changes to make it probe between 0xFFFC8000 and
-         0xFFFEE000.  Unless you are using LinuxBIOS, this is unlikely to be
-         useful to you.  Say 'N'.
-
-config MTD_NAND_DISKONCHIP_BBTWRITE
-       bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
-       depends on MTD_NAND_DISKONCHIP
-       help
-         On DiskOnChip devices shipped with the INFTL filesystem (Millennium
-         and 2000 TSOP/Alon), Linux reserves some space at the end of the
-         device for the Bad Block Table (BBT).  If you have existing INFTL
-         data on your device (created by non-Linux tools such as M-Systems'
-         DOS drivers), your data might overlap the area Linux wants to use for
-         the BBT.  If this is a concern for you, leave this option disabled and
-         Linux will not write BBT data into this area.
-         The downside of leaving this option disabled is that if bad blocks
-         are detected by Linux, they will not be recorded in the BBT, which
-         could cause future problems.
-         Once you enable this option, new filesystems (INFTL or others, created
-         in Linux or other operating systems) will not use the reserved area.
-         The only reason not to enable this option is to prevent damage to
-         preexisting filesystems.
-         Even if you leave this disabled, you can enable BBT writes at module
-         load time (assuming you build diskonchip as a module) with the module
-         parameter "inftl_bbt_write=1".
-
 config MTD_NAND_SHARPSL
-       tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
+       tristate "Sharp SL Series (C7xx + others) NAND controller"
        depends on ARCH_PXA || COMPILE_TEST
        depends on HAS_IOMEM
 
 config MTD_NAND_CAFE
-       tristate "NAND support for OLPC CAFÉ chip"
+       tristate "OLPC CAFÉ NAND controller"
        depends on PCI
        select REED_SOLOMON
        select REED_SOLOMON_DEC16
@@ -242,7 +144,7 @@ config MTD_NAND_CAFE
          laptop.
 
 config MTD_NAND_CS553X
-       tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
+       tristate "CS5535/CS5536 (AMD Geode companion) NAND controller"
        depends on X86_32
        depends on !UML && HAS_IOMEM
        help
@@ -256,7 +158,7 @@ config MTD_NAND_CS553X
          If you say "m", the module will be called cs553x_nand.
 
 config MTD_NAND_ATMEL
-       tristate "Support for NAND Flash / SmartMedia on AT91"
+       tristate "Atmel AT91 NAND Flash/SmartMedia NAND controller"
        depends on ARCH_AT91 || COMPILE_TEST
        depends on HAS_IOMEM
        select GENERIC_ALLOCATOR
@@ -265,8 +167,17 @@ config MTD_NAND_ATMEL
          Enables support for NAND Flash / Smart Media Card interface
          on Atmel AT91 processors.
 
+config MTD_NAND_ORION
+       tristate "Marvell Orion NAND controller"
+       depends on PLAT_ORION
+       help
+         This enables the NAND flash controller on Orion machines.
+
+         No board specific support is done by this driver, each board
+         must advertise a platform_device for the driver to attach.
+
 config MTD_NAND_MARVELL
-       tristate "NAND controller support on Marvell boards"
+       tristate "Marvell EBU NAND controller"
        depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \
                   COMPILE_TEST
        depends on HAS_IOMEM
@@ -278,7 +189,7 @@ config MTD_NAND_MARVELL
          - 64-bit Aramda platforms (7k, 8k) (NFCv2)
 
 config MTD_NAND_SLC_LPC32XX
-       tristate "NXP LPC32xx SLC Controller"
+       tristate "NXP LPC32xx SLC NAND controller"
        depends on ARCH_LPC32XX || COMPILE_TEST
        depends on HAS_IOMEM
        help
@@ -290,7 +201,7 @@ config MTD_NAND_SLC_LPC32XX
          by the SLC NAND controller.
 
 config MTD_NAND_MLC_LPC32XX
-       tristate "NXP LPC32xx MLC Controller"
+       tristate "NXP LPC32xx MLC NAND controller"
        depends on ARCH_LPC32XX || COMPILE_TEST
        depends on HAS_IOMEM
        help
@@ -302,38 +213,23 @@ config MTD_NAND_MLC_LPC32XX
          by the MLC NAND controller.
 
 config MTD_NAND_CM_X270
-       tristate "Support for NAND Flash on CM-X270 modules"
+       tristate "CM-X270 modules NAND controller"
        depends on MACH_ARMCORE
 
 config MTD_NAND_PASEMI
-       tristate "NAND support for PA Semi PWRficient"
+       tristate "PA Semi PWRficient NAND controller"
        depends on PPC_PASEMI
        help
          Enables support for NAND Flash interface on PA Semi PWRficient
          based boards
 
 config MTD_NAND_TMIO
-       tristate "NAND Flash device on Toshiba Mobile IO Controller"
+       tristate "Toshiba Mobile IO NAND controller"
        depends on MFD_TMIO
        help
          Support for NAND flash connected to a Toshiba Mobile IO
          Controller in some PDAs, including the Sharp SL6000x.
 
-config MTD_NAND_NANDSIM
-       tristate "Support for NAND Flash Simulator"
-       help
-         The simulator may simulate various NAND flash chips for the
-         MTD nand layer.
-
-config MTD_NAND_GPMI_NAND
-       tristate "GPMI NAND Flash Controller driver"
-       depends on MXS_DMA
-       help
-         Enables NAND Flash support for IMX23, IMX28 or IMX6.
-         The GPMI controller is very powerful, with the help of BCH
-         module, it can do the hardware ECC. The GPMI supports several
-         NAND flashs at the same time.
-
 config MTD_NAND_BRCMNAND
        tristate "Broadcom STB NAND controller"
        depends on ARM || ARM64 || MIPS || COMPILE_TEST
@@ -344,7 +240,7 @@ config MTD_NAND_BRCMNAND
          BCM3xxx, BCM63xxx, iProc/Cygnus and more.
 
 config MTD_NAND_BCM47XXNFLASH
-       tristate "Support for NAND flash on BCM4706 BCMA bus"
+       tristate "BCM4706 BCMA NAND controller"
        depends on BCMA_NFLASH
        depends on BCMA
        help
@@ -352,32 +248,31 @@ config MTD_NAND_BCM47XXNFLASH
          registered by bcma as platform devices. This enables driver for
          NAND flash memories. For now only BCM4706 is supported.
 
-config MTD_NAND_PLATFORM
-       tristate "Support for generic platform NAND driver"
+config MTD_NAND_OXNAS
+       tristate "Oxford Semiconductor NAND controller"
+       depends on ARCH_OXNAS || COMPILE_TEST
        depends on HAS_IOMEM
        help
-         This implements a generic NAND driver for on-SOC platform
-         devices. You will need to provide platform-specific functions
-         via platform_data.
+         This enables the NAND flash controller on Oxford Semiconductor SoCs.
 
-config MTD_NAND_ORION
-       tristate "NAND Flash support for Marvell Orion SoC"
-       depends on PLAT_ORION
+config MTD_NAND_MPC5121_NFC
+       tristate "MPC5121 NAND controller"
+       depends on PPC_MPC512x
        help
-         This enables the NAND flash controller on Orion machines.
-
-         No board specific support is done by this driver, each board
-         must advertise a platform_device for the driver to attach.
+         This enables the driver for the NAND flash controller on the
+         MPC5121 SoC.
 
-config MTD_NAND_OXNAS
-       tristate "NAND Flash support for Oxford Semiconductor SoC"
-       depends on ARCH_OXNAS || COMPILE_TEST
-       depends on HAS_IOMEM
+config MTD_NAND_GPMI_NAND
+       tristate "Freescale GPMI NAND controller"
+       depends on MXS_DMA
        help
-         This enables the NAND flash controller on Oxford Semiconductor SoCs.
+         Enables NAND Flash support for IMX23, IMX28 or IMX6.
+         The GPMI controller is very powerful, with the help of BCH
+         module, it can do the hardware ECC. The GPMI supports several
+         NAND flashs at the same time.
 
 config MTD_NAND_FSL_ELBC
-       tristate "NAND support for Freescale eLBC controllers"
+       tristate "Freescale eLBC NAND controller"
        depends on FSL_SOC
        select FSL_LBC
        help
@@ -387,7 +282,7 @@ config MTD_NAND_FSL_ELBC
          external NAND devices.
 
 config MTD_NAND_FSL_IFC
-       tristate "NAND support for Freescale IFC controller"
+       tristate "Freescale IFC NAND controller"
        depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A || COMPILE_TEST
        depends on HAS_IOMEM
        select FSL_IFC
@@ -399,22 +294,15 @@ config MTD_NAND_FSL_IFC
          external NAND devices.
 
 config MTD_NAND_FSL_UPM
-       tristate "Support for NAND on Freescale UPM"
+       tristate "Freescale UPM NAND controller"
        depends on PPC_83xx || PPC_85xx
        select FSL_LBC
        help
          Enables support for NAND Flash chips wired onto Freescale PowerPC
          processor localbus with User-Programmable Machine support.
 
-config MTD_NAND_MPC5121_NFC
-       tristate "MPC5121 built-in NAND Flash Controller support"
-       depends on PPC_MPC512x
-       help
-         This enables the driver for the NAND flash controller on the
-         MPC5121 SoC.
-
 config MTD_NAND_VF610_NFC
-       tristate "Support for Freescale NFC for VF610/MPC5125"
+       tristate "Freescale VF610/MPC5125 NAND controller"
        depends on (SOC_VF610 || COMPILE_TEST)
        depends on HAS_IOMEM
        help
@@ -426,7 +314,7 @@ config MTD_NAND_VF610_NFC
          device tree.
 
 config MTD_NAND_MXC
-       tristate "MXC NAND support"
+       tristate "Freescale MXC NAND controller"
        depends on ARCH_MXC || COMPILE_TEST
        depends on HAS_IOMEM
        help
@@ -434,7 +322,7 @@ config MTD_NAND_MXC
          MXC processors.
 
 config MTD_NAND_SH_FLCTL
-       tristate "Support for NAND on Renesas SuperH FLCTL"
+       tristate "Renesas SuperH FLCTL NAND controller"
        depends on SUPERH || COMPILE_TEST
        depends on HAS_IOMEM
        help
@@ -442,7 +330,7 @@ config MTD_NAND_SH_FLCTL
          for NAND Flash using FLCTL.
 
 config MTD_NAND_DAVINCI
-       tristate "Support NAND on DaVinci/Keystone SoC"
+       tristate "DaVinci/Keystone NAND controller"
        depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF) || COMPILE_TEST
        depends on HAS_IOMEM
        help
@@ -450,42 +338,30 @@ config MTD_NAND_DAVINCI
          DaVinci/Keystone processors.
 
 config MTD_NAND_TXX9NDFMC
-       tristate "NAND Flash support for TXx9 SoC"
+       tristate "TXx9 NAND controller"
        depends on SOC_TX4938 || SOC_TX4939 || COMPILE_TEST
        depends on HAS_IOMEM
        help
          This enables the NAND flash controller on the TXx9 SoCs.
 
 config MTD_NAND_SOCRATES
-       tristate "Support for NAND on Socrates board"
+       tristate "Socrates NAND controller"
        depends on SOCRATES
        help
          Enables support for NAND Flash chips wired onto Socrates board.
 
 config MTD_NAND_NUC900
-       tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards."
+       tristate "Nuvoton NUC9xx/w90p910 NAND controller"
        depends on ARCH_W90X900 || COMPILE_TEST
        depends on HAS_IOMEM
        help
          This enables the driver for the NAND Flash on evaluation board based
          on w90p910 / NUC9xx.
 
-config MTD_NAND_JZ4740
-       tristate "Support for JZ4740 SoC NAND controller"
-       depends on MACH_JZ4740 || COMPILE_TEST
-       depends on HAS_IOMEM
-       help
-         Enables support for NAND Flash on JZ4740 SoC based boards.
-
-config MTD_NAND_JZ4780
-       tristate "Support for NAND on JZ4780 SoC"
-       depends on JZ4780_NEMC
-       help
-         Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
-         based boards, using the BCH controller for hardware error correction.
+source "drivers/mtd/nand/raw/ingenic/Kconfig"
 
 config MTD_NAND_FSMC
-       tristate "Support for NAND on ST Micros FSMC"
+       tristate "ST Micros FSMC NAND controller"
        depends on OF && HAS_IOMEM
        depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300 || \
                   COMPILE_TEST
@@ -494,28 +370,28 @@ config MTD_NAND_FSMC
          Flexible Static Memory Controller (FSMC)
 
 config MTD_NAND_XWAY
-       bool "Support for NAND on Lantiq XWAY SoC"
+       bool "Lantiq XWAY NAND controller"
        depends on LANTIQ && SOC_TYPE_XWAY
        help
          Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
          to the External Bus Unit (EBU).
 
 config MTD_NAND_SUNXI
-       tristate "Support for NAND on Allwinner SoCs"
+       tristate "Allwinner NAND controller"
        depends on ARCH_SUNXI || COMPILE_TEST
        depends on HAS_IOMEM
        help
          Enables support for NAND Flash chips on Allwinner SoCs.
 
 config MTD_NAND_HISI504
-       tristate "Support for NAND controller on Hisilicon SoC Hip04"
+       tristate "Hisilicon Hip04 NAND controller"
        depends on ARCH_HISI || COMPILE_TEST
        depends on HAS_IOMEM
        help
          Enables support for NAND controller on Hisilicon SoC Hip04.
 
 config MTD_NAND_QCOM
-       tristate "Support for NAND on QCOM SoCs"
+       tristate "QCOM NAND controller"
        depends on ARCH_QCOM || COMPILE_TEST
        depends on HAS_IOMEM
        help
@@ -523,7 +399,7 @@ config MTD_NAND_QCOM
          controller. This controller is found on IPQ806x SoC.
 
 config MTD_NAND_MTK
-       tristate "Support for NAND controller on MTK SoCs"
+       tristate "MTK NAND controller"
        depends on ARCH_MEDIATEK || COMPILE_TEST
        depends on HAS_IOMEM
        help
@@ -531,7 +407,7 @@ config MTD_NAND_MTK
          This controller is found on mt27xx, mt81xx, mt65xx SoCs.
 
 config MTD_NAND_TEGRA
-       tristate "Support for NAND controller on NVIDIA Tegra"
+       tristate "NVIDIA Tegra NAND controller"
        depends on ARCH_TEGRA || COMPILE_TEST
        depends on HAS_IOMEM
        help
@@ -558,4 +434,115 @@ config MTD_NAND_MESON
          Enables support for NAND controller on Amlogic's Meson SoCs.
          This controller is found on Meson SoCs.
 
-endif # MTD_NAND
+config MTD_NAND_GPIO
+       tristate "GPIO assisted NAND controller"
+       depends on GPIOLIB || COMPILE_TEST
+       depends on HAS_IOMEM
+       help
+         This enables a NAND flash driver where control signals are
+         connected to GPIO pins, and commands and data are communicated
+         via a memory mapped interface.
+
+config MTD_NAND_PLATFORM
+       tristate "Generic NAND controller"
+       depends on HAS_IOMEM
+       help
+         This implements a generic NAND driver for on-SOC platform
+         devices. You will need to provide platform-specific functions
+         via platform_data.
+
+comment "Misc"
+
+config MTD_SM_COMMON
+       tristate
+       default n
+
+config MTD_NAND_NANDSIM
+       tristate "Support for NAND Flash Simulator"
+       help
+         The simulator may simulate various NAND flash chips for the
+         MTD nand layer.
+
+config MTD_NAND_RICOH
+       tristate "Ricoh xD card reader"
+       default n
+       depends on PCI
+       select MTD_SM_COMMON
+       help
+         Enable support for Ricoh R5C852 xD card reader
+         You also need to enable ether
+         NAND SSFDC (SmartMedia) read only translation layer' or new
+         expermental, readwrite
+         'SmartMedia/xD new translation layer'
+
+config MTD_NAND_DISKONCHIP
+       tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
+       depends on HAS_IOMEM
+       select REED_SOLOMON
+       select REED_SOLOMON_DEC16
+       help
+         This is a reimplementation of M-Systems DiskOnChip 2000,
+         Millennium and Millennium Plus as a standard NAND device driver,
+         as opposed to the earlier self-contained MTD device drivers.
+         This should enable, among other things, proper JFFS2 operation on
+         these devices.
+
+config MTD_NAND_DISKONCHIP_PROBE_ADVANCED
+       bool "Advanced detection options for DiskOnChip"
+       depends on MTD_NAND_DISKONCHIP
+       help
+         This option allows you to specify nonstandard address at which to
+         probe for a DiskOnChip, or to change the detection options.  You
+         are unlikely to need any of this unless you are using LinuxBIOS.
+         Say 'N'.
+
+config MTD_NAND_DISKONCHIP_PROBE_ADDRESS
+       hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
+       depends on MTD_NAND_DISKONCHIP
+       default "0"
+       help
+         By default, the probe for DiskOnChip devices will look for a
+         DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
+         This option allows you to specify a single address at which to probe
+         for the device, which is useful if you have other devices in that
+         range which get upset when they are probed.
+
+         (Note that on PowerPC, the normal probe will only check at
+         0xE4000000.)
+
+         Normally, you should leave this set to zero, to allow the probe at
+         the normal addresses.
+
+config MTD_NAND_DISKONCHIP_PROBE_HIGH
+       bool "Probe high addresses"
+       depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED
+       help
+         By default, the probe for DiskOnChip devices will look for a
+         DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
+         This option changes to make it probe between 0xFFFC8000 and
+         0xFFFEE000.  Unless you are using LinuxBIOS, this is unlikely to be
+         useful to you.  Say 'N'.
+
+config MTD_NAND_DISKONCHIP_BBTWRITE
+       bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
+       depends on MTD_NAND_DISKONCHIP
+       help
+         On DiskOnChip devices shipped with the INFTL filesystem (Millennium
+         and 2000 TSOP/Alon), Linux reserves some space at the end of the
+         device for the Bad Block Table (BBT).  If you have existing INFTL
+         data on your device (created by non-Linux tools such as M-Systems'
+         DOS drivers), your data might overlap the area Linux wants to use for
+         the BBT.  If this is a concern for you, leave this option disabled and
+         Linux will not write BBT data into this area.
+         The downside of leaving this option disabled is that if bad blocks
+         are detected by Linux, they will not be recorded in the BBT, which
+         could cause future problems.
+         Once you enable this option, new filesystems (INFTL or others, created
+         in Linux or other operating systems) will not use the reserved area.
+         The only reason not to enable this option is to prevent damage to
+         preexisting filesystems.
+         Even if you leave this disabled, you can enable BBT writes at module
+         load time (assuming you build diskonchip as a module) with the module
+         parameter "inftl_bbt_write=1".
+
+endif # MTD_RAW_NAND
index 5a5a72f0793eb2765fe954ea3c7d1e85bb444c0f..efaf5cd25edce99c7d370edbbb7f27cc7f176830 100644 (file)
@@ -1,8 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_MTD_NAND)                 += nand.o
-obj-$(CONFIG_MTD_NAND_ECC)             += nand_ecc.o
-obj-$(CONFIG_MTD_NAND_BCH)             += nand_bch.o
+obj-$(CONFIG_MTD_RAW_NAND)             += nand.o
+obj-$(CONFIG_MTD_NAND_ECC_SW_HAMMING)  += nand_ecc.o
+nand-$(CONFIG_MTD_NAND_ECC_SW_BCH)     += nand_bch.o
 obj-$(CONFIG_MTD_SM_COMMON)            += sm_common.o
 
 obj-$(CONFIG_MTD_NAND_CAFE)            += cafe_nand.o
@@ -45,8 +45,7 @@ obj-$(CONFIG_MTD_NAND_NUC900)         += nuc900_nand.o
 obj-$(CONFIG_MTD_NAND_MPC5121_NFC)     += mpc5121_nfc.o
 obj-$(CONFIG_MTD_NAND_VF610_NFC)       += vf610_nfc.o
 obj-$(CONFIG_MTD_NAND_RICOH)           += r852.o
-obj-$(CONFIG_MTD_NAND_JZ4740)          += jz4740_nand.o
-obj-$(CONFIG_MTD_NAND_JZ4780)          += jz4780_nand.o jz4780_bch.o
+obj-y                                  += ingenic/
 obj-$(CONFIG_MTD_NAND_GPMI_NAND)       += gpmi-nand/
 obj-$(CONFIG_MTD_NAND_XWAY)            += xway_nand.o
 obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)   += bcm47xxnflash/
index 5781fcf6b76c604906e55b792ccf9f9693c6016e..8d6be90a6fe8a20652b7236361bca93fddd2b0d5 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright 2017 ATMEL
  * Copyright 2017 Free Electrons
  *   Add Nand Flash Controller support for SAMA5 SoC
  *     Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com)
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
  * A few words about the naming convention in this file. This convention
  * applies to structure and function names.
  *
@@ -65,6 +62,7 @@
 #include <linux/iopoll.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
+#include <soc/at91/atmel-sfr.h>
 
 #include "pmecc.h"
 
@@ -211,6 +209,7 @@ struct atmel_nand_controller_caps {
        bool legacy_of_bindings;
        u32 ale_offs;
        u32 cle_offs;
+       const char *ebi_csa_regmap_name;
        const struct atmel_nand_controller_ops *ops;
 };
 
@@ -231,10 +230,15 @@ to_nand_controller(struct nand_controller *ctl)
        return container_of(ctl, struct atmel_nand_controller, base);
 }
 
+struct atmel_smc_nand_ebi_csa_cfg {
+       u32 offs;
+       u32 nfd0_on_d16;
+};
+
 struct atmel_smc_nand_controller {
        struct atmel_nand_controller base;
-       struct regmap *matrix;
-       unsigned int ebi_csa_offs;
+       struct regmap *ebi_csa_regmap;
+       struct atmel_smc_nand_ebi_csa_cfg *ebi_csa;
 };
 
 static inline struct atmel_smc_nand_controller *
@@ -1068,15 +1072,15 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
                req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
        else if (chip->ecc.strength)
                req.ecc.strength = chip->ecc.strength;
-       else if (chip->ecc_strength_ds)
-               req.ecc.strength = chip->ecc_strength_ds;
+       else if (chip->base.eccreq.strength)
+               req.ecc.strength = chip->base.eccreq.strength;
        else
                req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
 
        if (chip->ecc.size)
                req.ecc.sectorsize = chip->ecc.size;
-       else if (chip->ecc_step_ds)
-               req.ecc.sectorsize = chip->ecc_step_ds;
+       else if (chip->base.eccreq.step_size)
+               req.ecc.sectorsize = chip->base.eccreq.step_size;
        else
                req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO;
 
@@ -1507,13 +1511,20 @@ static void atmel_smc_nand_init(struct atmel_nand_controller *nc,
        atmel_nand_init(nc, nand);
 
        smc_nc = to_smc_nand_controller(chip->controller);
-       if (!smc_nc->matrix)
+       if (!smc_nc->ebi_csa_regmap)
                return;
 
        /* Attach the CS to the NAND Flash logic. */
        for (i = 0; i < nand->numcs; i++)
-               regmap_update_bits(smc_nc->matrix, smc_nc->ebi_csa_offs,
+               regmap_update_bits(smc_nc->ebi_csa_regmap,
+                                  smc_nc->ebi_csa->offs,
                                   BIT(nand->cs[i].id), BIT(nand->cs[i].id));
+
+       if (smc_nc->ebi_csa->nfd0_on_d16)
+               regmap_update_bits(smc_nc->ebi_csa_regmap,
+                                  smc_nc->ebi_csa->offs,
+                                  smc_nc->ebi_csa->nfd0_on_d16,
+                                  smc_nc->ebi_csa->nfd0_on_d16);
 }
 
 static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
@@ -1797,7 +1808,7 @@ static int atmel_nand_controller_add_nands(struct atmel_nand_controller *nc)
 
        ret = of_property_read_u32(np, "#size-cells", &val);
        if (ret) {
-               dev_err(dev, "missing #address-cells property\n");
+               dev_err(dev, "missing #size-cells property\n");
                return ret;
        }
 
@@ -1833,34 +1844,71 @@ static void atmel_nand_controller_cleanup(struct atmel_nand_controller *nc)
        clk_put(nc->mck);
 }
 
-static const struct of_device_id atmel_matrix_of_ids[] = {
+static const struct atmel_smc_nand_ebi_csa_cfg at91sam9260_ebi_csa = {
+       .offs = AT91SAM9260_MATRIX_EBICSA,
+};
+
+static const struct atmel_smc_nand_ebi_csa_cfg at91sam9261_ebi_csa = {
+       .offs = AT91SAM9261_MATRIX_EBICSA,
+};
+
+static const struct atmel_smc_nand_ebi_csa_cfg at91sam9263_ebi_csa = {
+       .offs = AT91SAM9263_MATRIX_EBI0CSA,
+};
+
+static const struct atmel_smc_nand_ebi_csa_cfg at91sam9rl_ebi_csa = {
+       .offs = AT91SAM9RL_MATRIX_EBICSA,
+};
+
+static const struct atmel_smc_nand_ebi_csa_cfg at91sam9g45_ebi_csa = {
+       .offs = AT91SAM9G45_MATRIX_EBICSA,
+};
+
+static const struct atmel_smc_nand_ebi_csa_cfg at91sam9n12_ebi_csa = {
+       .offs = AT91SAM9N12_MATRIX_EBICSA,
+};
+
+static const struct atmel_smc_nand_ebi_csa_cfg at91sam9x5_ebi_csa = {
+       .offs = AT91SAM9X5_MATRIX_EBICSA,
+};
+
+static const struct atmel_smc_nand_ebi_csa_cfg sam9x60_ebi_csa = {
+       .offs = AT91_SFR_CCFG_EBICSA,
+       .nfd0_on_d16 = AT91_SFR_CCFG_NFD0_ON_D16,
+};
+
+static const struct of_device_id atmel_ebi_csa_regmap_of_ids[] = {
        {
                .compatible = "atmel,at91sam9260-matrix",
-               .data = (void *)AT91SAM9260_MATRIX_EBICSA,
+               .data = &at91sam9260_ebi_csa,
        },
        {
                .compatible = "atmel,at91sam9261-matrix",
-               .data = (void *)AT91SAM9261_MATRIX_EBICSA,
+               .data = &at91sam9261_ebi_csa,
        },
        {
                .compatible = "atmel,at91sam9263-matrix",
-               .data = (void *)AT91SAM9263_MATRIX_EBI0CSA,
+               .data = &at91sam9263_ebi_csa,
        },
        {
                .compatible = "atmel,at91sam9rl-matrix",
-               .data = (void *)AT91SAM9RL_MATRIX_EBICSA,
+               .data = &at91sam9rl_ebi_csa,
        },
        {
                .compatible = "atmel,at91sam9g45-matrix",
-               .data = (void *)AT91SAM9G45_MATRIX_EBICSA,
+               .data = &at91sam9g45_ebi_csa,
        },
        {
                .compatible = "atmel,at91sam9n12-matrix",
-               .data = (void *)AT91SAM9N12_MATRIX_EBICSA,
+               .data = &at91sam9n12_ebi_csa,
        },
        {
                .compatible = "atmel,at91sam9x5-matrix",
-               .data = (void *)AT91SAM9X5_MATRIX_EBICSA,
+               .data = &at91sam9x5_ebi_csa,
+       },
+       {
+               .compatible = "microchip,sam9x60-sfr",
+               .data = &sam9x60_ebi_csa,
        },
        { /* sentinel */ },
 };
@@ -1982,37 +2030,38 @@ atmel_smc_nand_controller_init(struct atmel_smc_nand_controller *nc)
        struct device_node *np;
        int ret;
 
-       /* We do not retrieve the matrix syscon when parsing old DTs. */
+       /* We do not retrieve the EBICSA regmap when parsing old DTs. */
        if (nc->base.caps->legacy_of_bindings)
                return 0;
 
-       np = of_parse_phandle(dev->parent->of_node, "atmel,matrix", 0);
+       np = of_parse_phandle(dev->parent->of_node,
+                             nc->base.caps->ebi_csa_regmap_name, 0);
        if (!np)
                return 0;
 
-       match = of_match_node(atmel_matrix_of_ids, np);
+       match = of_match_node(atmel_ebi_csa_regmap_of_ids, np);
        if (!match) {
                of_node_put(np);
                return 0;
        }
 
-       nc->matrix = syscon_node_to_regmap(np);
+       nc->ebi_csa_regmap = syscon_node_to_regmap(np);
        of_node_put(np);
-       if (IS_ERR(nc->matrix)) {
-               ret = PTR_ERR(nc->matrix);
-               dev_err(dev, "Could not get Matrix regmap (err = %d)\n", ret);
+       if (IS_ERR(nc->ebi_csa_regmap)) {
+               ret = PTR_ERR(nc->ebi_csa_regmap);
+               dev_err(dev, "Could not get EBICSA regmap (err = %d)\n", ret);
                return ret;
        }
 
-       nc->ebi_csa_offs = (uintptr_t)match->data;
+       nc->ebi_csa = (struct atmel_smc_nand_ebi_csa_cfg *)match->data;
 
        /*
         * The at91sam9263 has 2 EBIs, if the NAND controller is under EBI1
-        * add 4 to ->ebi_csa_offs.
+        * add 4 to ->ebi_csa->offs.
         */
        if (of_device_is_compatible(dev->parent->of_node,
                                    "atmel,at91sam9263-ebi1"))
-               nc->ebi_csa_offs += 4;
+               nc->ebi_csa->offs += 4;
 
        return 0;
 }
@@ -2341,6 +2390,7 @@ static const struct atmel_nand_controller_ops at91rm9200_nc_ops = {
 static const struct atmel_nand_controller_caps atmel_rm9200_nc_caps = {
        .ale_offs = BIT(21),
        .cle_offs = BIT(22),
+       .ebi_csa_regmap_name = "atmel,matrix",
        .ops = &at91rm9200_nc_ops,
 };
 
@@ -2355,12 +2405,14 @@ static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
 static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = {
        .ale_offs = BIT(21),
        .cle_offs = BIT(22),
+       .ebi_csa_regmap_name = "atmel,matrix",
        .ops = &atmel_smc_nc_ops,
 };
 
 static const struct atmel_nand_controller_caps atmel_sam9261_nc_caps = {
        .ale_offs = BIT(22),
        .cle_offs = BIT(21),
+       .ebi_csa_regmap_name = "atmel,matrix",
        .ops = &atmel_smc_nc_ops,
 };
 
@@ -2368,6 +2420,15 @@ static const struct atmel_nand_controller_caps atmel_sam9g45_nc_caps = {
        .has_dma = true,
        .ale_offs = BIT(21),
        .cle_offs = BIT(22),
+       .ebi_csa_regmap_name = "atmel,matrix",
+       .ops = &atmel_smc_nc_ops,
+};
+
+static const struct atmel_nand_controller_caps microchip_sam9x60_nc_caps = {
+       .has_dma = true,
+       .ale_offs = BIT(21),
+       .cle_offs = BIT(22),
+       .ebi_csa_regmap_name = "microchip,sfr",
        .ops = &atmel_smc_nc_ops,
 };
 
@@ -2415,6 +2476,10 @@ static const struct of_device_id atmel_nand_controller_of_ids[] = {
                .compatible = "atmel,sama5d3-nand-controller",
                .data = &atmel_sama5_nc_caps,
        },
+       {
+               .compatible = "microchip,sam9x60-nand-controller",
+               .data = &microchip_sam9x60_nc_caps,
+       },
        /* Support for old/deprecated bindings: */
        {
                .compatible = "atmel,at91rm9200-nand",
index 9d3997840889b2b3139e54ecbd0729cf507f74ae..cbb023bf00f7281586467169b6b0b8b09038d9e9 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright 2017 ATMEL
  * Copyright 2017 Free Electrons
  *   Add Nand Flash Controller support for SAMA5 SoC
  *     Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com)
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
  * The PMECC is an hardware assisted BCH engine, which means part of the
  * ECC algorithm is left to the software. The hardware/software repartition
  * is explained in the "PMECC Controller Functional Description" chapter in
index 808f1be0d6ad7962ac8535e94df9fa91dea92043..7851c05126cf15481856c446bbcceaa3d8470bcf 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * © Copyright 2016 ATMEL
  * © Copyright 2016 Free Electrons
  *
  *    Add Nand Flash Controller support for SAMA5 SoC
  *        © Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
  */
 
 #ifndef ATMEL_PMECC_H
index a37cbfe565677cf2d4bf6fe6e7ac5f2976dbb25e..a53ffb3d64b09ed0984c0519d250a65a4fb4e10f 100644 (file)
@@ -428,7 +428,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
        }
 
        /* Configure FLASH */
-       chipsize = b47n->nand_chip.chipsize >> 20;
+       chipsize = nanddev_target_size(&b47n->nand_chip.base) >> 20;
        tbits = ffs(chipsize); /* find first bit set */
        if (!tbits || tbits != fls(chipsize)) {
                pr_err("Invalid flash size: 0x%lX\n", chipsize);
index 482c6f093f996cb5f2f04c0ab2389d5cc49a5c61..ce0b8ffc78128d3e8d8df8ae505bdf073cd40ada 100644 (file)
@@ -1676,11 +1676,8 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
        int page = addr >> chip->page_shift;
        int ret;
 
-       if (!buf) {
-               buf = chip->data_buf;
-               /* Invalidate page cache */
-               chip->pagebuf = -1;
-       }
+       if (!buf)
+               buf = nand_get_data_buf(chip);
 
        sas = mtd->oobsize / chip->ecc.steps;
 
index 24aeafc67cd4ea9f1eeb79652074785b0b45446e..3102ddbd8abdb85d324f0c04e9625273bbeaa296 100644 (file)
@@ -3,7 +3,7 @@
  * NAND Flash Controller Device Driver
  * Copyright © 2009-2010, Intel Corporation and its suppliers.
  *
- * Copyright (c) 2017 Socionext Inc.
+ * Copyright (c) 2017-2019 Socionext Inc.
  *   Reworked by Masahiro Yamada <yamada.masahiro@socionext.com>
  */
 
 #define DENALI_BANK(denali)    ((denali)->active_bank << 24)
 
 #define DENALI_INVALID_BANK    -1
-#define DENALI_NR_BANKS                4
 
-static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
+static struct denali_chip *to_denali_chip(struct nand_chip *chip)
 {
-       return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand);
+       return container_of(chip, struct denali_chip, chip);
+}
+
+static struct denali_controller *to_denali_controller(struct nand_chip *chip)
+{
+       return container_of(chip->controller, struct denali_controller,
+                           controller);
 }
 
 /*
@@ -52,12 +57,12 @@ static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
  * type, bank, block, and page address).  The slave data is the actual data to
  * be transferred.  This mode requires 28 bits of address region allocated.
  */
-static u32 denali_direct_read(struct denali_nand_info *denali, u32 addr)
+static u32 denali_direct_read(struct denali_controller *denali, u32 addr)
 {
        return ioread32(denali->host + addr);
 }
 
-static void denali_direct_write(struct denali_nand_info *denali, u32 addr,
+static void denali_direct_write(struct denali_controller *denali, u32 addr,
                                u32 data)
 {
        iowrite32(data, denali->host + addr);
@@ -69,77 +74,62 @@ static void denali_direct_write(struct denali_nand_info *denali, u32 addr,
  * control information and transferred data are latched by the registers in
  * the translation module.
  */
-static u32 denali_indexed_read(struct denali_nand_info *denali, u32 addr)
+static u32 denali_indexed_read(struct denali_controller *denali, u32 addr)
 {
        iowrite32(addr, denali->host + DENALI_INDEXED_CTRL);
        return ioread32(denali->host + DENALI_INDEXED_DATA);
 }
 
-static void denali_indexed_write(struct denali_nand_info *denali, u32 addr,
+static void denali_indexed_write(struct denali_controller *denali, u32 addr,
                                 u32 data)
 {
        iowrite32(addr, denali->host + DENALI_INDEXED_CTRL);
        iowrite32(data, denali->host + DENALI_INDEXED_DATA);
 }
 
-/*
- * Use the configuration feature register to determine the maximum number of
- * banks that the hardware supports.
- */
-static void denali_detect_max_banks(struct denali_nand_info *denali)
-{
-       uint32_t features = ioread32(denali->reg + FEATURES);
-
-       denali->max_banks = 1 << FIELD_GET(FEATURES__N_BANKS, features);
-
-       /* the encoding changed from rev 5.0 to 5.1 */
-       if (denali->revision < 0x0501)
-               denali->max_banks <<= 1;
-}
-
-static void denali_enable_irq(struct denali_nand_info *denali)
+static void denali_enable_irq(struct denali_controller *denali)
 {
        int i;
 
-       for (i = 0; i < DENALI_NR_BANKS; i++)
+       for (i = 0; i < denali->nbanks; i++)
                iowrite32(U32_MAX, denali->reg + INTR_EN(i));
        iowrite32(GLOBAL_INT_EN_FLAG, denali->reg + GLOBAL_INT_ENABLE);
 }
 
-static void denali_disable_irq(struct denali_nand_info *denali)
+static void denali_disable_irq(struct denali_controller *denali)
 {
        int i;
 
-       for (i = 0; i < DENALI_NR_BANKS; i++)
+       for (i = 0; i < denali->nbanks; i++)
                iowrite32(0, denali->reg + INTR_EN(i));
        iowrite32(0, denali->reg + GLOBAL_INT_ENABLE);
 }
 
-static void denali_clear_irq(struct denali_nand_info *denali,
-                            int bank, uint32_t irq_status)
+static void denali_clear_irq(struct denali_controller *denali,
+                            int bank, u32 irq_status)
 {
        /* write one to clear bits */
        iowrite32(irq_status, denali->reg + INTR_STATUS(bank));
 }
 
-static void denali_clear_irq_all(struct denali_nand_info *denali)
+static void denali_clear_irq_all(struct denali_controller *denali)
 {
        int i;
 
-       for (i = 0; i < DENALI_NR_BANKS; i++)
+       for (i = 0; i < denali->nbanks; i++)
                denali_clear_irq(denali, i, U32_MAX);
 }
 
 static irqreturn_t denali_isr(int irq, void *dev_id)
 {
-       struct denali_nand_info *denali = dev_id;
+       struct denali_controller *denali = dev_id;
        irqreturn_t ret = IRQ_NONE;
-       uint32_t irq_status;
+       u32 irq_status;
        int i;
 
        spin_lock(&denali->irq_lock);
 
-       for (i = 0; i < DENALI_NR_BANKS; i++) {
+       for (i = 0; i < denali->nbanks; i++) {
                irq_status = ioread32(denali->reg + INTR_STATUS(i));
                if (irq_status)
                        ret = IRQ_HANDLED;
@@ -160,7 +150,7 @@ static irqreturn_t denali_isr(int irq, void *dev_id)
        return ret;
 }
 
-static void denali_reset_irq(struct denali_nand_info *denali)
+static void denali_reset_irq(struct denali_controller *denali)
 {
        unsigned long flags;
 
@@ -170,11 +160,10 @@ static void denali_reset_irq(struct denali_nand_info *denali)
        spin_unlock_irqrestore(&denali->irq_lock, flags);
 }
 
-static uint32_t denali_wait_for_irq(struct denali_nand_info *denali,
-                                   uint32_t irq_mask)
+static u32 denali_wait_for_irq(struct denali_controller *denali, u32 irq_mask)
 {
        unsigned long time_left, flags;
-       uint32_t irq_status;
+       u32 irq_status;
 
        spin_lock_irqsave(&denali->irq_lock, flags);
 
@@ -201,128 +190,259 @@ static uint32_t denali_wait_for_irq(struct denali_nand_info *denali,
        return denali->irq_status;
 }
 
-static void denali_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
+static void denali_select_target(struct nand_chip *chip, int cs)
 {
+       struct denali_controller *denali = to_denali_controller(chip);
+       struct denali_chip_sel *sel = &to_denali_chip(chip)->sels[cs];
        struct mtd_info *mtd = nand_to_mtd(chip);
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
-       u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
-       int i;
 
-       for (i = 0; i < len; i++)
-               buf[i] = denali->host_read(denali, addr);
+       denali->active_bank = sel->bank;
+
+       iowrite32(1 << (chip->phys_erase_shift - chip->page_shift),
+                 denali->reg + PAGES_PER_BLOCK);
+       iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0,
+                 denali->reg + DEVICE_WIDTH);
+       iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE);
+       iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE);
+       iowrite32(chip->options & NAND_ROW_ADDR_3 ?
+                 0 : TWO_ROW_ADDR_CYCLES__FLAG,
+                 denali->reg + TWO_ROW_ADDR_CYCLES);
+       iowrite32(FIELD_PREP(ECC_CORRECTION__ERASE_THRESHOLD, 1) |
+                 FIELD_PREP(ECC_CORRECTION__VALUE, chip->ecc.strength),
+                 denali->reg + ECC_CORRECTION);
+       iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE);
+       iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE);
+       iowrite32(chip->ecc.steps, denali->reg + CFG_NUM_DATA_BLOCKS);
+
+       if (chip->options & NAND_KEEP_TIMINGS)
+               return;
+
+       /* update timing registers unless NAND_KEEP_TIMINGS is set */
+       iowrite32(sel->hwhr2_and_we_2_re, denali->reg + TWHR2_AND_WE_2_RE);
+       iowrite32(sel->tcwaw_and_addr_2_data,
+                 denali->reg + TCWAW_AND_ADDR_2_DATA);
+       iowrite32(sel->re_2_we, denali->reg + RE_2_WE);
+       iowrite32(sel->acc_clks, denali->reg + ACC_CLKS);
+       iowrite32(sel->rdwr_en_lo_cnt, denali->reg + RDWR_EN_LO_CNT);
+       iowrite32(sel->rdwr_en_hi_cnt, denali->reg + RDWR_EN_HI_CNT);
+       iowrite32(sel->cs_setup_cnt, denali->reg + CS_SETUP_CNT);
+       iowrite32(sel->re_2_re, denali->reg + RE_2_RE);
 }
 
-static void denali_write_buf(struct nand_chip *chip, const uint8_t *buf,
-                            int len)
+static int denali_change_column(struct nand_chip *chip, unsigned int offset,
+                               void *buf, unsigned int len, bool write)
 {
-       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
-       u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
-       int i;
-
-       for (i = 0; i < len; i++)
-               denali->host_write(denali, addr, buf[i]);
+       if (write)
+               return nand_change_write_column_op(chip, offset, buf, len,
+                                                  false);
+       else
+               return nand_change_read_column_op(chip, offset, buf, len,
+                                                 false);
 }
 
-static void denali_read_buf16(struct nand_chip *chip, uint8_t *buf, int len)
+static int denali_payload_xfer(struct nand_chip *chip, void *buf, bool write)
 {
-       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
-       u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
-       uint16_t *buf16 = (uint16_t *)buf;
-       int i;
+       struct denali_controller *denali = to_denali_controller(chip);
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       int writesize = mtd->writesize;
+       int oob_skip = denali->oob_skip_bytes;
+       int ret, i, pos, len;
+
+       for (i = 0; i < ecc->steps; i++) {
+               pos = i * (ecc->size + ecc->bytes);
+               len = ecc->size;
+
+               if (pos >= writesize) {
+                       pos += oob_skip;
+               } else if (pos + len > writesize) {
+                       /* This chunk overwraps the BBM area. Must be split */
+                       ret = denali_change_column(chip, pos, buf,
+                                                  writesize - pos, write);
+                       if (ret)
+                               return ret;
+
+                       buf += writesize - pos;
+                       len -= writesize - pos;
+                       pos = writesize + oob_skip;
+               }
+
+               ret = denali_change_column(chip, pos, buf, len, write);
+               if (ret)
+                       return ret;
 
-       for (i = 0; i < len / 2; i++)
-               buf16[i] = denali->host_read(denali, addr);
+               buf += len;
+       }
+
+       return 0;
 }
 
-static void denali_write_buf16(struct nand_chip *chip, const uint8_t *buf,
-                              int len)
+static int denali_oob_xfer(struct nand_chip *chip, void *buf, bool write)
 {
-       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
-       u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
-       const uint16_t *buf16 = (const uint16_t *)buf;
-       int i;
+       struct denali_controller *denali = to_denali_controller(chip);
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       int writesize = mtd->writesize;
+       int oobsize = mtd->oobsize;
+       int oob_skip = denali->oob_skip_bytes;
+       int ret, i, pos, len;
 
-       for (i = 0; i < len / 2; i++)
-               denali->host_write(denali, addr, buf16[i]);
+       /* BBM at the beginning of the OOB area */
+       ret = denali_change_column(chip, writesize, buf, oob_skip, write);
+       if (ret)
+               return ret;
+
+       buf += oob_skip;
+
+       for (i = 0; i < ecc->steps; i++) {
+               pos = ecc->size + i * (ecc->size + ecc->bytes);
+
+               if (i == ecc->steps - 1)
+                       /* The last chunk includes OOB free */
+                       len = writesize + oobsize - pos - oob_skip;
+               else
+                       len = ecc->bytes;
+
+               if (pos >= writesize) {
+                       pos += oob_skip;
+               } else if (pos + len > writesize) {
+                       /* This chunk overwraps the BBM area. Must be split */
+                       ret = denali_change_column(chip, pos, buf,
+                                                  writesize - pos, write);
+                       if (ret)
+                               return ret;
+
+                       buf += writesize - pos;
+                       len -= writesize - pos;
+                       pos = writesize + oob_skip;
+               }
+
+               ret = denali_change_column(chip, pos, buf, len, write);
+               if (ret)
+                       return ret;
+
+               buf += len;
+       }
+
+       return 0;
 }
 
-static uint8_t denali_read_byte(struct nand_chip *chip)
+static int denali_read_raw(struct nand_chip *chip, void *buf, void *oob_buf,
+                          int page)
 {
-       uint8_t byte;
+       int ret;
+
+       if (!buf && !oob_buf)
+               return -EINVAL;
 
-       denali_read_buf(chip, &byte, 1);
+       ret = nand_read_page_op(chip, page, 0, NULL, 0);
+       if (ret)
+               return ret;
 
-       return byte;
+       if (buf) {
+               ret = denali_payload_xfer(chip, buf, false);
+               if (ret)
+                       return ret;
+       }
+
+       if (oob_buf) {
+               ret = denali_oob_xfer(chip, oob_buf, false);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 
-static void denali_write_byte(struct nand_chip *chip, uint8_t byte)
+static int denali_write_raw(struct nand_chip *chip, const void *buf,
+                           const void *oob_buf, int page)
 {
-       denali_write_buf(chip, &byte, 1);
+       int ret;
+
+       if (!buf && !oob_buf)
+               return -EINVAL;
+
+       ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+       if (ret)
+               return ret;
+
+       if (buf) {
+               ret = denali_payload_xfer(chip, (void *)buf, true);
+               if (ret)
+                       return ret;
+       }
+
+       if (oob_buf) {
+               ret = denali_oob_xfer(chip, (void *)oob_buf, true);
+               if (ret)
+                       return ret;
+       }
+
+       return nand_prog_page_end_op(chip);
 }
 
-static void denali_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
+static int denali_read_page_raw(struct nand_chip *chip, u8 *buf,
+                               int oob_required, int page)
 {
-       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
-       uint32_t type;
+       return denali_read_raw(chip, buf, oob_required ? chip->oob_poi : NULL,
+                              page);
+}
 
-       if (ctrl & NAND_CLE)
-               type = DENALI_MAP11_CMD;
-       else if (ctrl & NAND_ALE)
-               type = DENALI_MAP11_ADDR;
-       else
-               return;
+static int denali_write_page_raw(struct nand_chip *chip, const u8 *buf,
+                                int oob_required, int page)
+{
+       return denali_write_raw(chip, buf, oob_required ? chip->oob_poi : NULL,
+                               page);
+}
 
-       /*
-        * Some commands are followed by chip->legacy.waitfunc.
-        * irq_status must be cleared here to catch the R/B# interrupt later.
-        */
-       if (ctrl & NAND_CTRL_CHANGE)
-               denali_reset_irq(denali);
+static int denali_read_oob(struct nand_chip *chip, int page)
+{
+       return denali_read_raw(chip, NULL, chip->oob_poi, page);
+}
 
-       denali->host_write(denali, DENALI_BANK(denali) | type, dat);
+static int denali_write_oob(struct nand_chip *chip, int page)
+{
+       return denali_write_raw(chip, NULL, chip->oob_poi, page);
 }
 
-static int denali_check_erased_page(struct mtd_info *mtd,
-                                   struct nand_chip *chip, uint8_t *buf,
+static int denali_check_erased_page(struct nand_chip *chip, u8 *buf,
                                    unsigned long uncor_ecc_flags,
                                    unsigned int max_bitflips)
 {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
-       uint8_t *ecc_code = chip->oob_poi + denali->oob_skip_bytes;
-       int ecc_steps = chip->ecc.steps;
-       int ecc_size = chip->ecc.size;
-       int ecc_bytes = chip->ecc.bytes;
+       struct denali_controller *denali = to_denali_controller(chip);
+       struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats;
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       u8 *ecc_code = chip->oob_poi + denali->oob_skip_bytes;
        int i, stat;
 
-       for (i = 0; i < ecc_steps; i++) {
+       for (i = 0; i < ecc->steps; i++) {
                if (!(uncor_ecc_flags & BIT(i)))
                        continue;
 
-               stat = nand_check_erased_ecc_chunk(buf, ecc_size,
-                                                 ecc_code, ecc_bytes,
-                                                 NULL, 0,
-                                                 chip->ecc.strength);
+               stat = nand_check_erased_ecc_chunk(buf, ecc->size, ecc_code,
+                                                  ecc->bytes, NULL, 0,
+                                                  ecc->strength);
                if (stat < 0) {
-                       mtd->ecc_stats.failed++;
+                       ecc_stats->failed++;
                } else {
-                       mtd->ecc_stats.corrected += stat;
+                       ecc_stats->corrected += stat;
                        max_bitflips = max_t(unsigned int, max_bitflips, stat);
                }
 
-               buf += ecc_size;
-               ecc_code += ecc_bytes;
+               buf += ecc->size;
+               ecc_code += ecc->bytes;
        }
 
        return max_bitflips;
 }
 
-static int denali_hw_ecc_fixup(struct mtd_info *mtd,
-                              struct denali_nand_info *denali,
+static int denali_hw_ecc_fixup(struct nand_chip *chip,
                               unsigned long *uncor_ecc_flags)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct denali_controller *denali = to_denali_controller(chip);
+       struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats;
        int bank = denali->active_bank;
-       uint32_t ecc_cor;
+       u32 ecc_cor;
        unsigned int max_bitflips;
 
        ecc_cor = ioread32(denali->reg + ECC_COR_INFO(bank));
@@ -346,23 +466,24 @@ static int denali_hw_ecc_fixup(struct mtd_info *mtd,
         * Unfortunately, we can not know the total number of corrected bits in
         * the page.  Increase the stats by max_bitflips. (compromised solution)
         */
-       mtd->ecc_stats.corrected += max_bitflips;
+       ecc_stats->corrected += max_bitflips;
 
        return max_bitflips;
 }
 
-static int denali_sw_ecc_fixup(struct mtd_info *mtd,
-                              struct denali_nand_info *denali,
-                              unsigned long *uncor_ecc_flags, uint8_t *buf)
+static int denali_sw_ecc_fixup(struct nand_chip *chip,
+                              unsigned long *uncor_ecc_flags, u8 *buf)
 {
-       unsigned int ecc_size = denali->nand.ecc.size;
+       struct denali_controller *denali = to_denali_controller(chip);
+       struct mtd_ecc_stats *ecc_stats = &nand_to_mtd(chip)->ecc_stats;
+       unsigned int ecc_size = chip->ecc.size;
        unsigned int bitflips = 0;
        unsigned int max_bitflips = 0;
-       uint32_t err_addr, err_cor_info;
+       u32 err_addr, err_cor_info;
        unsigned int err_byte, err_sector, err_device;
-       uint8_t err_cor_value;
+       u8 err_cor_value;
        unsigned int prev_sector = 0;
-       uint32_t irq_status;
+       u32 irq_status;
 
        denali_reset_irq(denali);
 
@@ -404,7 +525,7 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd,
                        /* correct the ECC error */
                        flips_in_byte = hweight8(buf[offset] ^ err_cor_value);
                        buf[offset] ^= err_cor_value;
-                       mtd->ecc_stats.corrected += flips_in_byte;
+                       ecc_stats->corrected += flips_in_byte;
                        bitflips += flips_in_byte;
 
                        max_bitflips = max(max_bitflips, bitflips);
@@ -424,10 +545,10 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd,
        return max_bitflips;
 }
 
-static void denali_setup_dma64(struct denali_nand_info *denali,
-                              dma_addr_t dma_addr, int page, int write)
+static void denali_setup_dma64(struct denali_controller *denali,
+                              dma_addr_t dma_addr, int page, bool write)
 {
-       uint32_t mode;
+       u32 mode;
        const int page_count = 1;
 
        mode = DENALI_MAP10 | DENALI_BANK(denali) | page;
@@ -439,7 +560,8 @@ static void denali_setup_dma64(struct denali_nand_info *denali,
         *    burst len = 64 bytes, the number of pages
         */
        denali->host_write(denali, mode,
-                          0x01002000 | (64 << 16) | (write << 8) | page_count);
+                          0x01002000 | (64 << 16) |
+                          (write ? BIT(8) : 0) | page_count);
 
        /* 2. set memory low address */
        denali->host_write(denali, mode, lower_32_bits(dma_addr));
@@ -448,10 +570,10 @@ static void denali_setup_dma64(struct denali_nand_info *denali,
        denali->host_write(denali, mode, upper_32_bits(dma_addr));
 }
 
-static void denali_setup_dma32(struct denali_nand_info *denali,
-                              dma_addr_t dma_addr, int page, int write)
+static void denali_setup_dma32(struct denali_controller *denali,
+                              dma_addr_t dma_addr, int page, bool write)
 {
-       uint32_t mode;
+       u32 mode;
        const int page_count = 1;
 
        mode = DENALI_MAP10 | DENALI_BANK(denali);
@@ -460,7 +582,7 @@ static void denali_setup_dma32(struct denali_nand_info *denali,
 
        /* 1. setup transfer type and # of pages */
        denali->host_write(denali, mode | page,
-                          0x2000 | (write << 8) | page_count);
+                          0x2000 | (write ? BIT(8) : 0) | page_count);
 
        /* 2. set memory high address bits 23:8 */
        denali->host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200);
@@ -472,12 +594,11 @@ static void denali_setup_dma32(struct denali_nand_info *denali,
        denali->host_write(denali, mode | 0x14000, 0x2400);
 }
 
-static int denali_pio_read(struct denali_nand_info *denali, void *buf,
+static int denali_pio_read(struct denali_controller *denali, u32 *buf,
                           size_t size, int page)
 {
        u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page;
-       uint32_t *buf32 = (uint32_t *)buf;
-       uint32_t irq_status, ecc_err_mask;
+       u32 irq_status, ecc_err_mask;
        int i;
 
        if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
@@ -488,7 +609,7 @@ static int denali_pio_read(struct denali_nand_info *denali, void *buf,
        denali_reset_irq(denali);
 
        for (i = 0; i < size / 4; i++)
-               *buf32++ = denali->host_read(denali, addr);
+               buf[i] = denali->host_read(denali, addr);
 
        irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC);
        if (!(irq_status & INTR__PAGE_XFER_INC))
@@ -500,29 +621,29 @@ static int denali_pio_read(struct denali_nand_info *denali, void *buf,
        return irq_status & ecc_err_mask ? -EBADMSG : 0;
 }
 
-static int denali_pio_write(struct denali_nand_info *denali,
-                           const void *buf, size_t size, int page)
+static int denali_pio_write(struct denali_controller *denali, const u32 *buf,
+                           size_t size, int page)
 {
        u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page;
-       const uint32_t *buf32 = (uint32_t *)buf;
-       uint32_t irq_status;
+       u32 irq_status;
        int i;
 
        denali_reset_irq(denali);
 
        for (i = 0; i < size / 4; i++)
-               denali->host_write(denali, addr, *buf32++);
+               denali->host_write(denali, addr, buf[i]);
 
        irq_status = denali_wait_for_irq(denali,
-                               INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL);
+                                        INTR__PROGRAM_COMP |
+                                        INTR__PROGRAM_FAIL);
        if (!(irq_status & INTR__PROGRAM_COMP))
                return -EIO;
 
        return 0;
 }
 
-static int denali_pio_xfer(struct denali_nand_info *denali, void *buf,
-                          size_t size, int page, int write)
+static int denali_pio_xfer(struct denali_controller *denali, void *buf,
+                          size_t size, int page, bool write)
 {
        if (write)
                return denali_pio_write(denali, buf, size, page);
@@ -530,11 +651,11 @@ static int denali_pio_xfer(struct denali_nand_info *denali, void *buf,
                return denali_pio_read(denali, buf, size, page);
 }
 
-static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
-                          size_t size, int page, int write)
+static int denali_dma_xfer(struct denali_controller *denali, void *buf,
+                          size_t size, int page, bool write)
 {
        dma_addr_t dma_addr;
-       uint32_t irq_mask, irq_status, ecc_err_mask;
+       u32 irq_mask, irq_status, ecc_err_mask;
        enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
        int ret = 0;
 
@@ -587,12 +708,12 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
        return ret;
 }
 
-static int denali_data_xfer(struct denali_nand_info *denali, void *buf,
-                           size_t size, int page, int raw, int write)
+static int denali_page_xfer(struct nand_chip *chip, void *buf, size_t size,
+                           int page, bool write)
 {
-       iowrite32(raw ? 0 : ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE);
-       iowrite32(raw ? TRANSFER_SPARE_REG__FLAG : 0,
-                 denali->reg + TRANSFER_SPARE_REG);
+       struct denali_controller *denali = to_denali_controller(chip);
+
+       denali_select_target(chip, chip->cur_cs);
 
        if (denali->dma_avail)
                return denali_dma_xfer(denali, buf, size, page, write);
@@ -600,180 +721,23 @@ static int denali_data_xfer(struct denali_nand_info *denali, void *buf,
                return denali_pio_xfer(denali, buf, size, page, write);
 }
 
-static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
-                           int page, int write)
-{
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
-       int writesize = mtd->writesize;
-       int oobsize = mtd->oobsize;
-       uint8_t *bufpoi = chip->oob_poi;
-       int ecc_steps = chip->ecc.steps;
-       int ecc_size = chip->ecc.size;
-       int ecc_bytes = chip->ecc.bytes;
-       int oob_skip = denali->oob_skip_bytes;
-       size_t size = writesize + oobsize;
-       int i, pos, len;
-
-       /* BBM at the beginning of the OOB area */
-       if (write)
-               nand_prog_page_begin_op(chip, page, writesize, bufpoi,
-                                       oob_skip);
-       else
-               nand_read_page_op(chip, page, writesize, bufpoi, oob_skip);
-       bufpoi += oob_skip;
-
-       /* OOB ECC */
-       for (i = 0; i < ecc_steps; i++) {
-               pos = ecc_size + i * (ecc_size + ecc_bytes);
-               len = ecc_bytes;
-
-               if (pos >= writesize)
-                       pos += oob_skip;
-               else if (pos + len > writesize)
-                       len = writesize - pos;
-
-               if (write)
-                       nand_change_write_column_op(chip, pos, bufpoi, len,
-                                                   false);
-               else
-                       nand_change_read_column_op(chip, pos, bufpoi, len,
-                                                  false);
-               bufpoi += len;
-               if (len < ecc_bytes) {
-                       len = ecc_bytes - len;
-                       if (write)
-                               nand_change_write_column_op(chip, writesize +
-                                                           oob_skip, bufpoi,
-                                                           len, false);
-                       else
-                               nand_change_read_column_op(chip, writesize +
-                                                          oob_skip, bufpoi,
-                                                          len, false);
-                       bufpoi += len;
-               }
-       }
-
-       /* OOB free */
-       len = oobsize - (bufpoi - chip->oob_poi);
-       if (write)
-               nand_change_write_column_op(chip, size - len, bufpoi, len,
-                                           false);
-       else
-               nand_change_read_column_op(chip, size - len, bufpoi, len,
-                                          false);
-}
-
-static int denali_read_page_raw(struct nand_chip *chip, uint8_t *buf,
-                               int oob_required, int page)
-{
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
-       int writesize = mtd->writesize;
-       int oobsize = mtd->oobsize;
-       int ecc_steps = chip->ecc.steps;
-       int ecc_size = chip->ecc.size;
-       int ecc_bytes = chip->ecc.bytes;
-       void *tmp_buf = denali->buf;
-       int oob_skip = denali->oob_skip_bytes;
-       size_t size = writesize + oobsize;
-       int ret, i, pos, len;
-
-       ret = denali_data_xfer(denali, tmp_buf, size, page, 1, 0);
-       if (ret)
-               return ret;
-
-       /* Arrange the buffer for syndrome payload/ecc layout */
-       if (buf) {
-               for (i = 0; i < ecc_steps; i++) {
-                       pos = i * (ecc_size + ecc_bytes);
-                       len = ecc_size;
-
-                       if (pos >= writesize)
-                               pos += oob_skip;
-                       else if (pos + len > writesize)
-                               len = writesize - pos;
-
-                       memcpy(buf, tmp_buf + pos, len);
-                       buf += len;
-                       if (len < ecc_size) {
-                               len = ecc_size - len;
-                               memcpy(buf, tmp_buf + writesize + oob_skip,
-                                      len);
-                               buf += len;
-                       }
-               }
-       }
-
-       if (oob_required) {
-               uint8_t *oob = chip->oob_poi;
-
-               /* BBM at the beginning of the OOB area */
-               memcpy(oob, tmp_buf + writesize, oob_skip);
-               oob += oob_skip;
-
-               /* OOB ECC */
-               for (i = 0; i < ecc_steps; i++) {
-                       pos = ecc_size + i * (ecc_size + ecc_bytes);
-                       len = ecc_bytes;
-
-                       if (pos >= writesize)
-                               pos += oob_skip;
-                       else if (pos + len > writesize)
-                               len = writesize - pos;
-
-                       memcpy(oob, tmp_buf + pos, len);
-                       oob += len;
-                       if (len < ecc_bytes) {
-                               len = ecc_bytes - len;
-                               memcpy(oob, tmp_buf + writesize + oob_skip,
-                                      len);
-                               oob += len;
-                       }
-               }
-
-               /* OOB free */
-               len = oobsize - (oob - chip->oob_poi);
-               memcpy(oob, tmp_buf + size - len, len);
-       }
-
-       return 0;
-}
-
-static int denali_read_oob(struct nand_chip *chip, int page)
-{
-       struct mtd_info *mtd = nand_to_mtd(chip);
-
-       denali_oob_xfer(mtd, chip, page, 0);
-
-       return 0;
-}
-
-static int denali_write_oob(struct nand_chip *chip, int page)
-{
-       struct mtd_info *mtd = nand_to_mtd(chip);
-
-       denali_oob_xfer(mtd, chip, page, 1);
-
-       return nand_prog_page_end_op(chip);
-}
-
-static int denali_read_page(struct nand_chip *chip, uint8_t *buf,
+static int denali_read_page(struct nand_chip *chip, u8 *buf,
                            int oob_required, int page)
 {
+       struct denali_controller *denali = to_denali_controller(chip);
        struct mtd_info *mtd = nand_to_mtd(chip);
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
        unsigned long uncor_ecc_flags = 0;
        int stat = 0;
        int ret;
 
-       ret = denali_data_xfer(denali, buf, mtd->writesize, page, 0, 0);
+       ret = denali_page_xfer(chip, buf, mtd->writesize, page, false);
        if (ret && ret != -EBADMSG)
                return ret;
 
        if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
-               stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags);
+               stat = denali_hw_ecc_fixup(chip, &uncor_ecc_flags);
        else if (ret == -EBADMSG)
-               stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf);
+               stat = denali_sw_ecc_fixup(chip, &uncor_ecc_flags, buf);
 
        if (stat < 0)
                return stat;
@@ -783,130 +747,32 @@ static int denali_read_page(struct nand_chip *chip, uint8_t *buf,
                if (ret)
                        return ret;
 
-               stat = denali_check_erased_page(mtd, chip, buf,
+               stat = denali_check_erased_page(chip, buf,
                                                uncor_ecc_flags, stat);
        }
 
        return stat;
 }
 
-static int denali_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
-                                int oob_required, int page)
-{
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
-       int writesize = mtd->writesize;
-       int oobsize = mtd->oobsize;
-       int ecc_steps = chip->ecc.steps;
-       int ecc_size = chip->ecc.size;
-       int ecc_bytes = chip->ecc.bytes;
-       void *tmp_buf = denali->buf;
-       int oob_skip = denali->oob_skip_bytes;
-       size_t size = writesize + oobsize;
-       int i, pos, len;
-
-       /*
-        * Fill the buffer with 0xff first except the full page transfer.
-        * This simplifies the logic.
-        */
-       if (!buf || !oob_required)
-               memset(tmp_buf, 0xff, size);
-
-       /* Arrange the buffer for syndrome payload/ecc layout */
-       if (buf) {
-               for (i = 0; i < ecc_steps; i++) {
-                       pos = i * (ecc_size + ecc_bytes);
-                       len = ecc_size;
-
-                       if (pos >= writesize)
-                               pos += oob_skip;
-                       else if (pos + len > writesize)
-                               len = writesize - pos;
-
-                       memcpy(tmp_buf + pos, buf, len);
-                       buf += len;
-                       if (len < ecc_size) {
-                               len = ecc_size - len;
-                               memcpy(tmp_buf + writesize + oob_skip, buf,
-                                      len);
-                               buf += len;
-                       }
-               }
-       }
-
-       if (oob_required) {
-               const uint8_t *oob = chip->oob_poi;
-
-               /* BBM at the beginning of the OOB area */
-               memcpy(tmp_buf + writesize, oob, oob_skip);
-               oob += oob_skip;
-
-               /* OOB ECC */
-               for (i = 0; i < ecc_steps; i++) {
-                       pos = ecc_size + i * (ecc_size + ecc_bytes);
-                       len = ecc_bytes;
-
-                       if (pos >= writesize)
-                               pos += oob_skip;
-                       else if (pos + len > writesize)
-                               len = writesize - pos;
-
-                       memcpy(tmp_buf + pos, oob, len);
-                       oob += len;
-                       if (len < ecc_bytes) {
-                               len = ecc_bytes - len;
-                               memcpy(tmp_buf + writesize + oob_skip, oob,
-                                      len);
-                               oob += len;
-                       }
-               }
-
-               /* OOB free */
-               len = oobsize - (oob - chip->oob_poi);
-               memcpy(tmp_buf + size - len, oob, len);
-       }
-
-       return denali_data_xfer(denali, tmp_buf, size, page, 1, 1);
-}
-
-static int denali_write_page(struct nand_chip *chip, const uint8_t *buf,
+static int denali_write_page(struct nand_chip *chip, const u8 *buf,
                             int oob_required, int page)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
 
-       return denali_data_xfer(denali, (void *)buf, mtd->writesize,
-                               page, 0, 1);
-}
-
-static void denali_select_chip(struct nand_chip *chip, int cs)
-{
-       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
-
-       denali->active_bank = cs;
-}
-
-static int denali_waitfunc(struct nand_chip *chip)
-{
-       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
-       uint32_t irq_status;
-
-       /* R/B# pin transitioned from low to high? */
-       irq_status = denali_wait_for_irq(denali, INTR__INT_ACT);
-
-       return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL;
+       return denali_page_xfer(chip, (void *)buf, mtd->writesize, page, true);
 }
 
 static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
                                       const struct nand_data_interface *conf)
 {
-       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
+       struct denali_controller *denali = to_denali_controller(chip);
+       struct denali_chip_sel *sel;
        const struct nand_sdr_timings *timings;
        unsigned long t_x, mult_x;
        int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
        int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup;
        int addr_2_data_mask;
-       uint32_t tmp;
+       u32 tmp;
 
        timings = nand_get_sdr_timings(conf);
        if (IS_ERR(timings))
@@ -929,6 +795,8 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
        if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
                return 0;
 
+       sel = &to_denali_chip(chip)->sels[chipnr];
+
        /* tREA -> ACC_CLKS */
        acc_clks = DIV_ROUND_UP(timings->tREA_max, t_x);
        acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE);
@@ -936,7 +804,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
        tmp = ioread32(denali->reg + ACC_CLKS);
        tmp &= ~ACC_CLKS__VALUE;
        tmp |= FIELD_PREP(ACC_CLKS__VALUE, acc_clks);
-       iowrite32(tmp, denali->reg + ACC_CLKS);
+       sel->acc_clks = tmp;
 
        /* tRWH -> RE_2_WE */
        re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_x);
@@ -945,7 +813,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
        tmp = ioread32(denali->reg + RE_2_WE);
        tmp &= ~RE_2_WE__VALUE;
        tmp |= FIELD_PREP(RE_2_WE__VALUE, re_2_we);
-       iowrite32(tmp, denali->reg + RE_2_WE);
+       sel->re_2_we = tmp;
 
        /* tRHZ -> RE_2_RE */
        re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_x);
@@ -954,7 +822,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
        tmp = ioread32(denali->reg + RE_2_RE);
        tmp &= ~RE_2_RE__VALUE;
        tmp |= FIELD_PREP(RE_2_RE__VALUE, re_2_re);
-       iowrite32(tmp, denali->reg + RE_2_RE);
+       sel->re_2_re = tmp;
 
        /*
         * tCCS, tWHR -> WE_2_RE
@@ -968,7 +836,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
        tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE);
        tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE;
        tmp |= FIELD_PREP(TWHR2_AND_WE_2_RE__WE_2_RE, we_2_re);
-       iowrite32(tmp, denali->reg + TWHR2_AND_WE_2_RE);
+       sel->hwhr2_and_we_2_re = tmp;
 
        /* tADL -> ADDR_2_DATA */
 
@@ -983,7 +851,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
        tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA);
        tmp &= ~TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA;
        tmp |= FIELD_PREP(TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA, addr_2_data);
-       iowrite32(tmp, denali->reg + TCWAW_AND_ADDR_2_DATA);
+       sel->tcwaw_and_addr_2_data = tmp;
 
        /* tREH, tWH -> RDWR_EN_HI_CNT */
        rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min),
@@ -993,7 +861,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
        tmp = ioread32(denali->reg + RDWR_EN_HI_CNT);
        tmp &= ~RDWR_EN_HI_CNT__VALUE;
        tmp |= FIELD_PREP(RDWR_EN_HI_CNT__VALUE, rdwr_en_hi);
-       iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT);
+       sel->rdwr_en_hi_cnt = tmp;
 
        /* tRP, tWP -> RDWR_EN_LO_CNT */
        rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min), t_x);
@@ -1006,7 +874,7 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
        tmp = ioread32(denali->reg + RDWR_EN_LO_CNT);
        tmp &= ~RDWR_EN_LO_CNT__VALUE;
        tmp |= FIELD_PREP(RDWR_EN_LO_CNT__VALUE, rdwr_en_lo);
-       iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT);
+       sel->rdwr_en_lo_cnt = tmp;
 
        /* tCS, tCEA -> CS_SETUP_CNT */
        cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_x) - rdwr_en_lo,
@@ -1017,39 +885,11 @@ static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
        tmp = ioread32(denali->reg + CS_SETUP_CNT);
        tmp &= ~CS_SETUP_CNT__VALUE;
        tmp |= FIELD_PREP(CS_SETUP_CNT__VALUE, cs_setup);
-       iowrite32(tmp, denali->reg + CS_SETUP_CNT);
+       sel->cs_setup_cnt = tmp;
 
        return 0;
 }
 
-static void denali_hw_init(struct denali_nand_info *denali)
-{
-       /*
-        * The REVISION register may not be reliable.  Platforms are allowed to
-        * override it.
-        */
-       if (!denali->revision)
-               denali->revision = swab16(ioread32(denali->reg + REVISION));
-
-       /*
-        * Set how many bytes should be skipped before writing data in OOB.
-        * If a non-zero value has already been set (by firmware or something),
-        * just use it.  Otherwise, set the driver default.
-        */
-       denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES);
-       if (!denali->oob_skip_bytes) {
-               denali->oob_skip_bytes = DENALI_DEFAULT_OOB_SKIP_BYTES;
-               iowrite32(denali->oob_skip_bytes,
-                         denali->reg + SPARE_AREA_SKIP_BYTES);
-       }
-
-       denali_detect_max_banks(denali);
-       iowrite32(0x0F, denali->reg + RB_PIN_ENABLED);
-       iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE);
-
-       iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER);
-}
-
 int denali_calc_ecc_bytes(int step_size, int strength)
 {
        /* BCH code.  Denali requires ecc.bytes to be multiple of 2 */
@@ -1060,10 +900,10 @@ EXPORT_SYMBOL(denali_calc_ecc_bytes);
 static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
                                struct mtd_oob_region *oobregion)
 {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
        struct nand_chip *chip = mtd_to_nand(mtd);
+       struct denali_controller *denali = to_denali_controller(chip);
 
-       if (section)
+       if (section > 0)
                return -ERANGE;
 
        oobregion->offset = denali->oob_skip_bytes;
@@ -1075,10 +915,10 @@ static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
 static int denali_ooblayout_free(struct mtd_info *mtd, int section,
                                 struct mtd_oob_region *oobregion)
 {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
        struct nand_chip *chip = mtd_to_nand(mtd);
+       struct denali_controller *denali = to_denali_controller(chip);
 
-       if (section)
+       if (section > 0)
                return -ERANGE;
 
        oobregion->offset = chip->ecc.total + denali->oob_skip_bytes;
@@ -1092,10 +932,13 @@ static const struct mtd_ooblayout_ops denali_ooblayout_ops = {
        .free = denali_ooblayout_free,
 };
 
-static int denali_multidev_fixup(struct denali_nand_info *denali)
+static int denali_multidev_fixup(struct nand_chip *chip)
 {
-       struct nand_chip *chip = &denali->nand;
+       struct denali_controller *denali = to_denali_controller(chip);
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_memory_organization *memorg;
+
+       memorg = nanddev_get_memorg(&chip->base);
 
        /*
         * Support for multi device:
@@ -1125,11 +968,12 @@ static int denali_multidev_fixup(struct denali_nand_info *denali)
        }
 
        /* 2 chips in parallel */
+       memorg->pagesize <<= 1;
+       memorg->oobsize <<= 1;
        mtd->size <<= 1;
        mtd->erasesize <<= 1;
        mtd->writesize <<= 1;
        mtd->oobsize <<= 1;
-       chip->chipsize <<= 1;
        chip->page_shift += 1;
        chip->phys_erase_shift += 1;
        chip->bbt_erase_shift += 1;
@@ -1145,38 +989,10 @@ static int denali_multidev_fixup(struct denali_nand_info *denali)
 
 static int denali_attach_chip(struct nand_chip *chip)
 {
+       struct denali_controller *denali = to_denali_controller(chip);
        struct mtd_info *mtd = nand_to_mtd(chip);
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
        int ret;
 
-       if (ioread32(denali->reg + FEATURES) & FEATURES__DMA)
-               denali->dma_avail = 1;
-
-       if (denali->dma_avail) {
-               int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32;
-
-               ret = dma_set_mask(denali->dev, DMA_BIT_MASK(dma_bit));
-               if (ret) {
-                       dev_info(denali->dev,
-                                "Failed to set DMA mask. Disabling DMA.\n");
-                       denali->dma_avail = 0;
-               }
-       }
-
-       if (denali->dma_avail) {
-               chip->options |= NAND_USE_BOUNCE_BUFFER;
-               chip->buf_align = 16;
-               if (denali->caps & DENALI_CAP_DMA_64BIT)
-                       denali->setup_dma = denali_setup_dma64;
-               else
-                       denali->setup_dma = denali_setup_dma32;
-       }
-
-       chip->bbt_options |= NAND_BBT_USE_FLASH;
-       chip->bbt_options |= NAND_BBT_NO_OOB;
-       chip->ecc.mode = NAND_ECC_HW_SYNDROME;
-       chip->options |= NAND_NO_SUBPAGE_WRITE;
-
        ret = nand_ecc_choose_conf(chip, denali->ecc_caps,
                                   mtd->oobsize - denali->oob_skip_bytes);
        if (ret) {
@@ -1188,123 +1004,230 @@ static int denali_attach_chip(struct nand_chip *chip)
                "chosen ECC settings: step=%d, strength=%d, bytes=%d\n",
                chip->ecc.size, chip->ecc.strength, chip->ecc.bytes);
 
-       iowrite32(FIELD_PREP(ECC_CORRECTION__ERASE_THRESHOLD, 1) |
-                 FIELD_PREP(ECC_CORRECTION__VALUE, chip->ecc.strength),
-                 denali->reg + ECC_CORRECTION);
-       iowrite32(mtd->erasesize / mtd->writesize,
-                 denali->reg + PAGES_PER_BLOCK);
-       iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0,
-                 denali->reg + DEVICE_WIDTH);
-       iowrite32(chip->options & NAND_ROW_ADDR_3 ? 0 : TWO_ROW_ADDR_CYCLES__FLAG,
-                 denali->reg + TWO_ROW_ADDR_CYCLES);
-       iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE);
-       iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE);
+       ret = denali_multidev_fixup(chip);
+       if (ret)
+               return ret;
 
-       iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE);
-       iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE);
-       /* chip->ecc.steps is set by nand_scan_tail(); not available here */
-       iowrite32(mtd->writesize / chip->ecc.size,
-                 denali->reg + CFG_NUM_DATA_BLOCKS);
+       return 0;
+}
 
-       mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
+static void denali_exec_in8(struct denali_controller *denali, u32 type,
+                           u8 *buf, unsigned int len)
+{
+       int i;
 
-       if (chip->options & NAND_BUSWIDTH_16) {
-               chip->legacy.read_buf = denali_read_buf16;
-               chip->legacy.write_buf = denali_write_buf16;
-       } else {
-               chip->legacy.read_buf = denali_read_buf;
-               chip->legacy.write_buf = denali_write_buf;
+       for (i = 0; i < len; i++)
+               buf[i] = denali->host_read(denali, type | DENALI_BANK(denali));
+}
+
+static void denali_exec_in16(struct denali_controller *denali, u32 type,
+                            u8 *buf, unsigned int len)
+{
+       u32 data;
+       int i;
+
+       for (i = 0; i < len; i += 2) {
+               data = denali->host_read(denali, type | DENALI_BANK(denali));
+               /* bit 31:24 and 15:8 are used for DDR */
+               buf[i] = data;
+               buf[i + 1] = data >> 16;
        }
-       chip->ecc.read_page = denali_read_page;
-       chip->ecc.read_page_raw = denali_read_page_raw;
-       chip->ecc.write_page = denali_write_page;
-       chip->ecc.write_page_raw = denali_write_page_raw;
-       chip->ecc.read_oob = denali_read_oob;
-       chip->ecc.write_oob = denali_write_oob;
+}
 
-       ret = denali_multidev_fixup(denali);
-       if (ret)
-               return ret;
+static void denali_exec_in(struct denali_controller *denali, u32 type,
+                          u8 *buf, unsigned int len, bool width16)
+{
+       if (width16)
+               denali_exec_in16(denali, type, buf, len);
+       else
+               denali_exec_in8(denali, type, buf, len);
+}
 
-       /*
-        * This buffer is DMA-mapped by denali_{read,write}_page_raw.  Do not
-        * use devm_kmalloc() because the memory allocated by devm_ does not
-        * guarantee DMA-safe alignment.
-        */
-       denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
-       if (!denali->buf)
-               return -ENOMEM;
+static void denali_exec_out8(struct denali_controller *denali, u32 type,
+                            const u8 *buf, unsigned int len)
+{
+       int i;
 
-       return 0;
+       for (i = 0; i < len; i++)
+               denali->host_write(denali, type | DENALI_BANK(denali), buf[i]);
 }
 
-static void denali_detach_chip(struct nand_chip *chip)
+static void denali_exec_out16(struct denali_controller *denali, u32 type,
+                             const u8 *buf, unsigned int len)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       int i;
+
+       for (i = 0; i < len; i += 2)
+               denali->host_write(denali, type | DENALI_BANK(denali),
+                                  buf[i + 1] << 16 | buf[i]);
+}
 
-       kfree(denali->buf);
+static void denali_exec_out(struct denali_controller *denali, u32 type,
+                           const u8 *buf, unsigned int len, bool width16)
+{
+       if (width16)
+               denali_exec_out16(denali, type, buf, len);
+       else
+               denali_exec_out8(denali, type, buf, len);
+}
+
+static int denali_exec_waitrdy(struct denali_controller *denali)
+{
+       u32 irq_stat;
+
+       /* R/B# pin transitioned from low to high? */
+       irq_stat = denali_wait_for_irq(denali, INTR__INT_ACT);
+
+       /* Just in case nand_operation has multiple NAND_OP_WAITRDY_INSTR. */
+       denali_reset_irq(denali);
+
+       return irq_stat & INTR__INT_ACT ? 0 : -EIO;
+}
+
+static int denali_exec_instr(struct nand_chip *chip,
+                            const struct nand_op_instr *instr)
+{
+       struct denali_controller *denali = to_denali_controller(chip);
+
+       switch (instr->type) {
+       case NAND_OP_CMD_INSTR:
+               denali_exec_out8(denali, DENALI_MAP11_CMD,
+                                &instr->ctx.cmd.opcode, 1);
+               return 0;
+       case NAND_OP_ADDR_INSTR:
+               denali_exec_out8(denali, DENALI_MAP11_ADDR,
+                                instr->ctx.addr.addrs,
+                                instr->ctx.addr.naddrs);
+               return 0;
+       case NAND_OP_DATA_IN_INSTR:
+               denali_exec_in(denali, DENALI_MAP11_DATA,
+                              instr->ctx.data.buf.in,
+                              instr->ctx.data.len,
+                              !instr->ctx.data.force_8bit &&
+                              chip->options & NAND_BUSWIDTH_16);
+               return 0;
+       case NAND_OP_DATA_OUT_INSTR:
+               denali_exec_out(denali, DENALI_MAP11_DATA,
+                               instr->ctx.data.buf.out,
+                               instr->ctx.data.len,
+                               !instr->ctx.data.force_8bit &&
+                               chip->options & NAND_BUSWIDTH_16);
+               return 0;
+       case NAND_OP_WAITRDY_INSTR:
+               return denali_exec_waitrdy(denali);
+       default:
+               WARN_ONCE(1, "unsupported NAND instruction type: %d\n",
+                         instr->type);
+
+               return -EINVAL;
+       }
+}
+
+static int denali_exec_op(struct nand_chip *chip,
+                         const struct nand_operation *op, bool check_only)
+{
+       int i, ret;
+
+       if (check_only)
+               return 0;
+
+       denali_select_target(chip, op->cs);
+
+       /*
+        * Some commands contain NAND_OP_WAITRDY_INSTR.
+        * irq must be cleared here to catch the R/B# interrupt there.
+        */
+       denali_reset_irq(to_denali_controller(chip));
+
+       for (i = 0; i < op->ninstrs; i++) {
+               ret = denali_exec_instr(chip, &op->instrs[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 
 static const struct nand_controller_ops denali_controller_ops = {
        .attach_chip = denali_attach_chip,
-       .detach_chip = denali_detach_chip,
+       .exec_op = denali_exec_op,
        .setup_data_interface = denali_setup_data_interface,
 };
 
-int denali_init(struct denali_nand_info *denali)
+int denali_chip_init(struct denali_controller *denali,
+                    struct denali_chip *dchip)
 {
-       struct nand_chip *chip = &denali->nand;
+       struct nand_chip *chip = &dchip->chip;
        struct mtd_info *mtd = nand_to_mtd(chip);
-       u32 features = ioread32(denali->reg + FEATURES);
-       int ret;
+       struct denali_chip *dchip2;
+       int i, j, ret;
 
-       mtd->dev.parent = denali->dev;
-       denali_hw_init(denali);
+       chip->controller = &denali->controller;
 
-       init_completion(&denali->complete);
-       spin_lock_init(&denali->irq_lock);
+       /* sanity checks for bank numbers */
+       for (i = 0; i < dchip->nsels; i++) {
+               unsigned int bank = dchip->sels[i].bank;
 
-       denali_clear_irq_all(denali);
+               if (bank >= denali->nbanks) {
+                       dev_err(denali->dev, "unsupported bank %d\n", bank);
+                       return -EINVAL;
+               }
 
-       ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
-                              IRQF_SHARED, DENALI_NAND_NAME, denali);
-       if (ret) {
-               dev_err(denali->dev, "Unable to request IRQ\n");
-               return ret;
-       }
+               for (j = 0; j < i; j++) {
+                       if (bank == dchip->sels[j].bank) {
+                               dev_err(denali->dev,
+                                       "bank %d is assigned twice in the same chip\n",
+                                       bank);
+                               return -EINVAL;
+                       }
+               }
 
-       denali_enable_irq(denali);
+               list_for_each_entry(dchip2, &denali->chips, node) {
+                       for (j = 0; j < dchip2->nsels; j++) {
+                               if (bank == dchip2->sels[j].bank) {
+                                       dev_err(denali->dev,
+                                               "bank %d is already used\n",
+                                               bank);
+                                       return -EINVAL;
+                               }
+                       }
+               }
+       }
 
-       denali->active_bank = DENALI_INVALID_BANK;
+       mtd->dev.parent = denali->dev;
 
-       nand_set_flash_node(chip, denali->dev->of_node);
-       /* Fallback to the default name if DT did not give "label" property */
-       if (!mtd->name)
+       /*
+        * Fallback to the default name if DT did not give "label" property.
+        * Use "label" property if multiple chips are connected.
+        */
+       if (!mtd->name && list_empty(&denali->chips))
                mtd->name = "denali-nand";
 
-       chip->legacy.select_chip = denali_select_chip;
-       chip->legacy.read_byte = denali_read_byte;
-       chip->legacy.write_byte = denali_write_byte;
-       chip->legacy.cmd_ctrl = denali_cmd_ctrl;
-       chip->legacy.waitfunc = denali_waitfunc;
-
-       if (features & FEATURES__INDEX_ADDR) {
-               denali->host_read = denali_indexed_read;
-               denali->host_write = denali_indexed_write;
-       } else {
-               denali->host_read = denali_direct_read;
-               denali->host_write = denali_direct_write;
+       if (denali->dma_avail) {
+               chip->options |= NAND_USE_BOUNCE_BUFFER;
+               chip->buf_align = 16;
        }
 
        /* clk rate info is needed for setup_data_interface */
        if (!denali->clk_rate || !denali->clk_x_rate)
                chip->options |= NAND_KEEP_TIMINGS;
 
-       chip->legacy.dummy_controller.ops = &denali_controller_ops;
-       ret = nand_scan(chip, denali->max_banks);
+       chip->bbt_options |= NAND_BBT_USE_FLASH;
+       chip->bbt_options |= NAND_BBT_NO_OOB;
+       chip->options |= NAND_NO_SUBPAGE_WRITE;
+       chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+       chip->ecc.read_page = denali_read_page;
+       chip->ecc.write_page = denali_write_page;
+       chip->ecc.read_page_raw = denali_read_page_raw;
+       chip->ecc.write_page_raw = denali_write_page_raw;
+       chip->ecc.read_oob = denali_read_oob;
+       chip->ecc.write_oob = denali_write_oob;
+
+       mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
+
+       ret = nand_scan(chip, dchip->nsels);
        if (ret)
-               goto disable_irq;
+               return ret;
 
        ret = mtd_device_register(mtd, NULL, 0);
        if (ret) {
@@ -1312,20 +1235,111 @@ int denali_init(struct denali_nand_info *denali)
                goto cleanup_nand;
        }
 
+       list_add_tail(&dchip->node, &denali->chips);
+
        return 0;
 
 cleanup_nand:
        nand_cleanup(chip);
-disable_irq:
-       denali_disable_irq(denali);
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(denali_chip_init);
+
+int denali_init(struct denali_controller *denali)
+{
+       u32 features = ioread32(denali->reg + FEATURES);
+       int ret;
+
+       nand_controller_init(&denali->controller);
+       denali->controller.ops = &denali_controller_ops;
+       init_completion(&denali->complete);
+       spin_lock_init(&denali->irq_lock);
+       INIT_LIST_HEAD(&denali->chips);
+       denali->active_bank = DENALI_INVALID_BANK;
+
+       /*
+        * The REVISION register may not be reliable. Platforms are allowed to
+        * override it.
+        */
+       if (!denali->revision)
+               denali->revision = swab16(ioread32(denali->reg + REVISION));
+
+       denali->nbanks = 1 << FIELD_GET(FEATURES__N_BANKS, features);
+
+       /* the encoding changed from rev 5.0 to 5.1 */
+       if (denali->revision < 0x0501)
+               denali->nbanks <<= 1;
+
+       if (features & FEATURES__DMA)
+               denali->dma_avail = true;
+
+       if (denali->dma_avail) {
+               int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32;
+
+               ret = dma_set_mask(denali->dev, DMA_BIT_MASK(dma_bit));
+               if (ret) {
+                       dev_info(denali->dev,
+                                "Failed to set DMA mask. Disabling DMA.\n");
+                       denali->dma_avail = false;
+               }
+       }
+
+       if (denali->dma_avail) {
+               if (denali->caps & DENALI_CAP_DMA_64BIT)
+                       denali->setup_dma = denali_setup_dma64;
+               else
+                       denali->setup_dma = denali_setup_dma32;
+       }
+
+       if (features & FEATURES__INDEX_ADDR) {
+               denali->host_read = denali_indexed_read;
+               denali->host_write = denali_indexed_write;
+       } else {
+               denali->host_read = denali_direct_read;
+               denali->host_write = denali_direct_write;
+       }
+
+       /*
+        * Set how many bytes should be skipped before writing data in OOB.
+        * If a non-zero value has already been set (by firmware or something),
+        * just use it. Otherwise, set the driver's default.
+        */
+       denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES);
+       if (!denali->oob_skip_bytes) {
+               denali->oob_skip_bytes = DENALI_DEFAULT_OOB_SKIP_BYTES;
+               iowrite32(denali->oob_skip_bytes,
+                         denali->reg + SPARE_AREA_SKIP_BYTES);
+       }
+
+       iowrite32(0, denali->reg + TRANSFER_SPARE_REG);
+       iowrite32(GENMASK(denali->nbanks - 1, 0), denali->reg + RB_PIN_ENABLED);
+       iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE);
+       iowrite32(ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE);
+       iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER);
+
+       denali_clear_irq_all(denali);
+
+       ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
+                              IRQF_SHARED, DENALI_NAND_NAME, denali);
+       if (ret) {
+               dev_err(denali->dev, "Unable to request IRQ\n");
+               return ret;
+       }
+
+       denali_enable_irq(denali);
+
+       return 0;
+}
 EXPORT_SYMBOL(denali_init);
 
-void denali_remove(struct denali_nand_info *denali)
+void denali_remove(struct denali_controller *denali)
 {
-       nand_release(&denali->nand);
+       struct denali_chip *dchip;
+
+       list_for_each_entry(dchip, &denali->chips, node)
+               nand_release(&dchip->chip);
+
        denali_disable_irq(denali);
 }
 EXPORT_SYMBOL(denali_remove);
index c8c2620fc736b07b3707317fed7fefe883b5e3d6..e5cdcda56d14a2de6b5da45e128907e20c961577 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/bits.h>
 #include <linux/completion.h>
+#include <linux/list.h>
 #include <linux/mtd/rawnand.h>
 #include <linux/spinlock_types.h>
 #include <linux/types.h>
 #define     CHNL_ACTIVE__CHANNEL2                      BIT(2)
 #define     CHNL_ACTIVE__CHANNEL3                      BIT(3)
 
-struct denali_nand_info {
-       struct nand_chip nand;
-       unsigned long clk_rate;         /* core clock rate */
-       unsigned long clk_x_rate;       /* bus interface clock rate */
-       int active_bank;                /* currently selected bank */
+/**
+ * struct denali_chip_sel - per-CS data of Denali NAND
+ *
+ * @bank:                  bank id of the controller this CS is connected to
+ * @hwhr2_and_we_2_re:     value of timing register HWHR2_AND_WE_2_RE
+ * @tcwaw_and_addr_2_data: value of timing register TCWAW_AND_ADDR_2_DATA
+ * @re_2_we:               value of timing register RE_2_WE
+ * @acc_clks:              value of timing register ACC_CLKS
+ * @rdwr_en_lo_cnt:        value of timing register RDWR_EN_LO_CNT
+ * @rdwr_en_hi_cnt:        value of timing register RDWR_EN_HI_CNT
+ * @cs_setup_cnt:          value of timing register CS_SETUP_CNT
+ * @re_2_re:               value of timing register RE_2_RE
+ */
+struct denali_chip_sel {
+       int bank;
+       u32 hwhr2_and_we_2_re;
+       u32 tcwaw_and_addr_2_data;
+       u32 re_2_we;
+       u32 acc_clks;
+       u32 rdwr_en_lo_cnt;
+       u32 rdwr_en_hi_cnt;
+       u32 cs_setup_cnt;
+       u32 re_2_re;
+};
+
+/**
+ * struct denali_chip - per-chip data of Denali NAND
+ *
+ * @chip:  base NAND chip structure
+ * @node:  node to be used to associate this chip with the controller
+ * @nsels: the number of CS lines of this chip
+ * @sels:  the array of per-cs data
+ */
+struct denali_chip {
+       struct nand_chip chip;
+       struct list_head node;
+       unsigned int nsels;
+       struct denali_chip_sel sels[0];
+};
+
+/**
+ * struct denali_controller - Denali NAND controller data
+ *
+ * @controller:     base NAND controller structure
+ * @dev:            device
+ * @chips:          the list of chips attached to this controller
+ * @clk_rate:       frequency of core clock
+ * @clk_x_rate:     frequency of bus interface clock
+ * @reg:            base of Register Interface
+ * @host:           base of Host Data/Command interface
+ * @complete:       completion used to wait for interrupts
+ * @irq:            interrupt number
+ * @irq_mask:       interrupt bits the controller is waiting for
+ * @irq_status:     interrupt bits of events that have happened
+ * @irq_lock:       lock to protect @irq_mask and @irq_status
+ * @dma_avail:      set if DMA engine is available
+ * @devs_per_cs:    number of devices connected in parallel
+ * @oob_skip_bytes: number of bytes in OOB skipped by the ECC engine
+ * @active_bank:    active bank id
+ * @nbanks:         the number of banks supported by this controller
+ * @revision:       IP revision
+ * @caps:           controller capabilities that cannot be detected run-time
+ * @ecc_caps:       ECC engine capabilities
+ * @host_read:      callback for read access of Host Data/Command Interface
+ * @host_write:     callback for write access of Host Data/Command Interface
+ * @setup_dma:      callback for setup of the Data DMA
+ */
+struct denali_controller {
+       struct nand_controller controller;
        struct device *dev;
-       void __iomem *reg;              /* Register Interface */
-       void __iomem *host;             /* Host Data/Command Interface */
+       struct list_head chips;
+       unsigned long clk_rate;
+       unsigned long clk_x_rate;
+       void __iomem *reg;
+       void __iomem *host;
        struct completion complete;
-       spinlock_t irq_lock;            /* protect irq_mask and irq_status */
-       u32 irq_mask;                   /* interrupts we are waiting for */
-       u32 irq_status;                 /* interrupts that have happened */
        int irq;
-       void *buf;                      /* for syndrome layout conversion */
-       int dma_avail;                  /* can support DMA? */
-       int devs_per_cs;                /* devices connected in parallel */
-       int oob_skip_bytes;             /* number of bytes reserved for BBM */
-       int max_banks;
-       unsigned int revision;          /* IP revision */
-       unsigned int caps;              /* IP capability (or quirk) */
+       u32 irq_mask;
+       u32 irq_status;
+       spinlock_t irq_lock;
+       bool dma_avail;
+       int devs_per_cs;
+       int oob_skip_bytes;
+       int active_bank;
+       int nbanks;
+       unsigned int revision;
+       unsigned int caps;
        const struct nand_ecc_caps *ecc_caps;
-       u32 (*host_read)(struct denali_nand_info *denali, u32 addr);
-       void (*host_write)(struct denali_nand_info *denali, u32 addr, u32 data);
-       void (*setup_dma)(struct denali_nand_info *denali, dma_addr_t dma_addr,
-                         int page, int write);
+       u32 (*host_read)(struct denali_controller *denali, u32 addr);
+       void (*host_write)(struct denali_controller *denali, u32 addr,
+                          u32 data);
+       void (*setup_dma)(struct denali_controller *denali, dma_addr_t dma_addr,
+                         int page, bool write);
 };
 
 #define DENALI_CAP_HW_ECC_FIXUP                        BIT(0)
 #define DENALI_CAP_DMA_64BIT                   BIT(1)
 
 int denali_calc_ecc_bytes(int step_size, int strength);
-int denali_init(struct denali_nand_info *denali);
-void denali_remove(struct denali_nand_info *denali);
+int denali_chip_init(struct denali_controller *denali,
+                    struct denali_chip *dchip);
+int denali_init(struct denali_controller *denali);
+void denali_remove(struct denali_controller *denali);
 
 #endif /* __DENALI_H__ */
index 0b5ae2418815b66fd7379a2f3ef8f056e1e3b5bd..5e14836f6bd5af7646b8916a0035365692704a8d 100644 (file)
@@ -18,7 +18,7 @@
 #include "denali.h"
 
 struct denali_dt {
-       struct denali_nand_info denali;
+       struct denali_controller controller;
        struct clk *clk;        /* core clock */
        struct clk *clk_x;      /* bus interface clock */
        struct clk *clk_ecc;    /* ECC circuit clock */
@@ -71,19 +71,92 @@ static const struct of_device_id denali_nand_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
 
+static int denali_dt_chip_init(struct denali_controller *denali,
+                              struct device_node *chip_np)
+{
+       struct denali_chip *dchip;
+       u32 bank;
+       int nsels, i, ret;
+
+       nsels = of_property_count_u32_elems(chip_np, "reg");
+       if (nsels < 0)
+               return nsels;
+
+       dchip = devm_kzalloc(denali->dev, struct_size(dchip, sels, nsels),
+                            GFP_KERNEL);
+       if (!dchip)
+               return -ENOMEM;
+
+       dchip->nsels = nsels;
+
+       for (i = 0; i < nsels; i++) {
+               ret = of_property_read_u32_index(chip_np, "reg", i, &bank);
+               if (ret)
+                       return ret;
+
+               dchip->sels[i].bank = bank;
+
+               nand_set_flash_node(&dchip->chip, chip_np);
+       }
+
+       return denali_chip_init(denali, dchip);
+}
+
+/* Backward compatibility for old platforms */
+static int denali_dt_legacy_chip_init(struct denali_controller *denali)
+{
+       struct denali_chip *dchip;
+       int nsels, i;
+
+       nsels = denali->nbanks;
+
+       dchip = devm_kzalloc(denali->dev, struct_size(dchip, sels, nsels),
+                            GFP_KERNEL);
+       if (!dchip)
+               return -ENOMEM;
+
+       dchip->nsels = nsels;
+
+       for (i = 0; i < nsels; i++)
+               dchip->sels[i].bank = i;
+
+       nand_set_flash_node(&dchip->chip, denali->dev->of_node);
+
+       return denali_chip_init(denali, dchip);
+}
+
+/*
+ * Check the DT binding.
+ * The new binding expects chip subnodes in the controller node.
+ * So, #address-cells = <1>; #size-cells = <0>; are required.
+ * Check the #size-cells to distinguish the binding.
+ */
+static bool denali_dt_is_legacy_binding(struct device_node *np)
+{
+       u32 cells;
+       int ret;
+
+       ret = of_property_read_u32(np, "#size-cells", &cells);
+       if (ret)
+               return true;
+
+       return cells != 0;
+}
+
 static int denali_dt_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct resource *res;
        struct denali_dt *dt;
        const struct denali_dt_data *data;
-       struct denali_nand_info *denali;
+       struct denali_controller *denali;
+       struct device_node *np;
        int ret;
 
        dt = devm_kzalloc(dev, sizeof(*dt), GFP_KERNEL);
        if (!dt)
                return -ENOMEM;
-       denali = &dt->denali;
+       denali = &dt->controller;
 
        data = of_device_get_match_data(dev);
        if (data) {
@@ -140,9 +213,26 @@ static int denali_dt_probe(struct platform_device *pdev)
        if (ret)
                goto out_disable_clk_ecc;
 
+       if (denali_dt_is_legacy_binding(dev->of_node)) {
+               ret = denali_dt_legacy_chip_init(denali);
+               if (ret)
+                       goto out_remove_denali;
+       } else {
+               for_each_child_of_node(dev->of_node, np) {
+                       ret = denali_dt_chip_init(denali, np);
+                       if (ret) {
+                               of_node_put(np);
+                               goto out_remove_denali;
+                       }
+               }
+       }
+
        platform_set_drvdata(pdev, dt);
+
        return 0;
 
+out_remove_denali:
+       denali_remove(denali);
 out_disable_clk_ecc:
        clk_disable_unprepare(dt->clk_ecc);
 out_disable_clk_x:
@@ -157,7 +247,7 @@ static int denali_dt_remove(struct platform_device *pdev)
 {
        struct denali_dt *dt = platform_get_drvdata(pdev);
 
-       denali_remove(&dt->denali);
+       denali_remove(&dt->controller);
        clk_disable_unprepare(dt->clk_ecc);
        clk_disable_unprepare(dt->clk_x);
        clk_disable_unprepare(dt->clk);
index 48e9ac54ad531a884fe5d24519fbadfbb0ff2547..d62aa5271753e802f286aa431c61a36e2f6997aa 100644 (file)
@@ -29,10 +29,11 @@ NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15);
 
 static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
-       int ret;
        resource_size_t csr_base, mem_base;
        unsigned long csr_len, mem_len;
-       struct denali_nand_info *denali;
+       struct denali_controller *denali;
+       struct denali_chip *dchip;
+       int nsels, ret, i;
 
        denali = devm_kzalloc(&dev->dev, sizeof(*denali), GFP_KERNEL);
        if (!denali)
@@ -64,7 +65,6 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        denali->dev = &dev->dev;
        denali->irq = dev->irq;
        denali->ecc_caps = &denali_pci_ecc_caps;
-       denali->nand.ecc.options |= NAND_ECC_MAXIMIZE;
        denali->clk_rate = 50000000;            /* 50 MHz */
        denali->clk_x_rate = 200000000;         /* 200 MHz */
 
@@ -84,27 +84,49 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        if (!denali->host) {
                dev_err(&dev->dev, "Spectra: ioremap_nocache failed!");
                ret = -ENOMEM;
-               goto failed_remap_reg;
+               goto out_unmap_reg;
        }
 
        ret = denali_init(denali);
        if (ret)
-               goto failed_remap_mem;
+               goto out_unmap_host;
+
+       nsels = denali->nbanks;
+
+       dchip = devm_kzalloc(denali->dev, struct_size(dchip, sels, nsels),
+                            GFP_KERNEL);
+       if (!dchip) {
+               ret = -ENOMEM;
+               goto out_remove_denali;
+       }
+
+       dchip->chip.ecc.options |= NAND_ECC_MAXIMIZE;
+
+       dchip->nsels = nsels;
+
+       for (i = 0; i < nsels; i++)
+               dchip->sels[i].bank = i;
+
+       ret = denali_chip_init(denali, dchip);
+       if (ret)
+               goto out_remove_denali;
 
        pci_set_drvdata(dev, denali);
 
        return 0;
 
-failed_remap_mem:
+out_remove_denali:
+       denali_remove(denali);
+out_unmap_host:
        iounmap(denali->host);
-failed_remap_reg:
+out_unmap_reg:
        iounmap(denali->reg);
        return ret;
 }
 
 static void denali_pci_remove(struct pci_dev *dev)
 {
-       struct denali_nand_info *denali = pci_get_drvdata(dev);
+       struct denali_controller *denali = pci_get_drvdata(dev);
 
        denali_remove(denali);
        iounmap(denali->reg);
index 53f57e0f007e25654c773b73b1c0f56b35699b14..f430c4bf0323c556b84c0c354f9ab3d6f65b1811 100644 (file)
@@ -1028,6 +1028,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
 {
        struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
+       struct nand_memory_organization *memorg;
        int ret = 0;
        u_char *buf;
        struct NFTLMediaHeader *mh;
@@ -1036,6 +1037,8 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
        unsigned blocks, maxblocks;
        int offs, numheaders;
 
+       memorg = nanddev_get_memorg(&this->base);
+
        buf = kmalloc(mtd->writesize, GFP_KERNEL);
        if (!buf) {
                return 0;
@@ -1082,6 +1085,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
           implementation of the NAND layer.  */
        if (mh->UnitSizeFactor != 0xff) {
                this->bbt_erase_shift += (0xff - mh->UnitSizeFactor);
+               memorg->pages_per_eraseblock <<= (0xff - mh->UnitSizeFactor);
                mtd->erasesize <<= (0xff - mh->UnitSizeFactor);
                pr_info("Setting virtual erase size to %d\n", mtd->erasesize);
                blocks = mtd->size >> this->bbt_erase_shift;
@@ -1287,7 +1291,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
        struct doc_priv *doc = nand_get_controller_data(this);
        struct mtd_partition parts[5];
 
-       if (this->numchips > doc->chips_per_floor) {
+       if (nanddev_ntargets(&this->base) > doc->chips_per_floor) {
                pr_err("Multi-floor INFTL devices not yet supported.\n");
                return -EIO;
        }
@@ -1477,6 +1481,7 @@ static int __init doc_probe(unsigned long physadr)
                        break;
                case DOC_ChipID_DocMilPlus32:
                        pr_err("DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");
+                       /* fall through */
                default:
                        ret = -ENODEV;
                        goto notfound;
index 70f0d2b450ea1fd21a16cec5c19b1ac61e553d02..423828ff68e6cfa1ae103a43d0d939f67cca1c41 100644 (file)
@@ -355,6 +355,15 @@ static void fsl_elbc_cmdfunc(struct nand_chip *chip, unsigned int command,
                fsl_elbc_run_command(mtd);
                return;
 
+       /* RNDOUT moves the pointer inside the page */
+       case NAND_CMD_RNDOUT:
+               dev_dbg(priv->dev,
+                       "fsl_elbc_cmdfunc: NAND_CMD_RNDOUT, column: 0x%x.\n",
+                       column);
+
+               elbc_fcm_ctrl->index = column;
+               return;
+
        /* READOOB reads only the OOB because no ECC is performed. */
        case NAND_CMD_READOOB:
                dev_vdbg(priv->dev,
@@ -635,79 +644,6 @@ static int fsl_elbc_wait(struct nand_chip *chip)
        return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
 }
 
-static int fsl_elbc_attach_chip(struct nand_chip *chip)
-{
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
-       struct fsl_lbc_ctrl *ctrl = priv->ctrl;
-       struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
-       unsigned int al;
-
-       /* calculate FMR Address Length field */
-       al = 0;
-       if (chip->pagemask & 0xffff0000)
-               al++;
-       if (chip->pagemask & 0xff000000)
-               al++;
-
-       priv->fmr |= al << FMR_AL_SHIFT;
-
-       dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n",
-               chip->numchips);
-       dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
-               chip->chipsize);
-       dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
-               chip->pagemask);
-       dev_dbg(priv->dev, "fsl_elbc_init: nand->legacy.chip_delay = %d\n",
-               chip->legacy.chip_delay);
-       dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
-               chip->badblockpos);
-       dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
-               chip->chip_shift);
-       dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n",
-               chip->page_shift);
-       dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
-               chip->phys_erase_shift);
-       dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
-               chip->ecc.mode);
-       dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
-               chip->ecc.steps);
-       dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
-               chip->ecc.bytes);
-       dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
-               chip->ecc.total);
-       dev_dbg(priv->dev, "fsl_elbc_init: mtd->ooblayout = %p\n",
-               mtd->ooblayout);
-       dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
-       dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
-       dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
-               mtd->erasesize);
-       dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n",
-               mtd->writesize);
-       dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
-               mtd->oobsize);
-
-       /* adjust Option Register and ECC to match Flash page size */
-       if (mtd->writesize == 512) {
-               priv->page_size = 0;
-               clrbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
-       } else if (mtd->writesize == 2048) {
-               priv->page_size = 1;
-               setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
-       } else {
-               dev_err(priv->dev,
-                       "fsl_elbc_init: page size %d is not supported\n",
-                       mtd->writesize);
-               return -ENOTSUPP;
-       }
-
-       return 0;
-}
-
-static const struct nand_controller_ops fsl_elbc_controller_ops = {
-       .attach_chip = fsl_elbc_attach_chip,
-};
-
 static int fsl_elbc_read_page(struct nand_chip *chip, uint8_t *buf,
                              int oob_required, int page)
 {
@@ -794,27 +730,116 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
        chip->controller = &elbc_fcm_ctrl->controller;
        nand_set_controller_data(chip, priv);
 
-       chip->ecc.read_page = fsl_elbc_read_page;
-       chip->ecc.write_page = fsl_elbc_write_page;
-       chip->ecc.write_subpage = fsl_elbc_write_subpage;
-
-       /* If CS Base Register selects full hardware ECC then use it */
-       if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
-           BR_DECC_CHK_GEN) {
-               chip->ecc.mode = NAND_ECC_HW;
-               mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops);
-               chip->ecc.size = 512;
-               chip->ecc.bytes = 3;
-               chip->ecc.strength = 1;
+       return 0;
+}
+
+static int fsl_elbc_attach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+       struct fsl_lbc_ctrl *ctrl = priv->ctrl;
+       struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+       unsigned int al;
+
+       switch (chip->ecc.mode) {
+       /*
+        * if ECC was not chosen in DT, decide whether to use HW or SW ECC from
+        * CS Base Register
+        */
+       case NAND_ECC_NONE:
+               /* If CS Base Register selects full hardware ECC then use it */
+               if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
+                   BR_DECC_CHK_GEN) {
+                       chip->ecc.read_page = fsl_elbc_read_page;
+                       chip->ecc.write_page = fsl_elbc_write_page;
+                       chip->ecc.write_subpage = fsl_elbc_write_subpage;
+
+                       chip->ecc.mode = NAND_ECC_HW;
+                       mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops);
+                       chip->ecc.size = 512;
+                       chip->ecc.bytes = 3;
+                       chip->ecc.strength = 1;
+               } else {
+                       /* otherwise fall back to default software ECC */
+                       chip->ecc.mode = NAND_ECC_SOFT;
+                       chip->ecc.algo = NAND_ECC_HAMMING;
+               }
+               break;
+
+       /* if SW ECC was chosen in DT, we do not need to set anything here */
+       case NAND_ECC_SOFT:
+               break;
+
+       /* should we also implement NAND_ECC_HW to do as the code above? */
+       default:
+               return -EINVAL;
+       }
+
+       /* calculate FMR Address Length field */
+       al = 0;
+       if (chip->pagemask & 0xffff0000)
+               al++;
+       if (chip->pagemask & 0xff000000)
+               al++;
+
+       priv->fmr |= al << FMR_AL_SHIFT;
+
+       dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n",
+               nanddev_ntargets(&chip->base));
+       dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
+               nanddev_target_size(&chip->base));
+       dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
+               chip->pagemask);
+       dev_dbg(priv->dev, "fsl_elbc_init: nand->legacy.chip_delay = %d\n",
+               chip->legacy.chip_delay);
+       dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
+               chip->badblockpos);
+       dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
+               chip->chip_shift);
+       dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n",
+               chip->page_shift);
+       dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
+               chip->phys_erase_shift);
+       dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
+               chip->ecc.mode);
+       dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
+               chip->ecc.steps);
+       dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
+               chip->ecc.bytes);
+       dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
+               chip->ecc.total);
+       dev_dbg(priv->dev, "fsl_elbc_init: mtd->ooblayout = %p\n",
+               mtd->ooblayout);
+       dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
+       dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
+       dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
+               mtd->erasesize);
+       dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n",
+               mtd->writesize);
+       dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
+               mtd->oobsize);
+
+       /* adjust Option Register and ECC to match Flash page size */
+       if (mtd->writesize == 512) {
+               priv->page_size = 0;
+               clrbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
+       } else if (mtd->writesize == 2048) {
+               priv->page_size = 1;
+               setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
        } else {
-               /* otherwise fall back to default software ECC */
-               chip->ecc.mode = NAND_ECC_SOFT;
-               chip->ecc.algo = NAND_ECC_HAMMING;
+               dev_err(priv->dev,
+                       "fsl_elbc_init: page size %d is not supported\n",
+                       mtd->writesize);
+               return -ENOTSUPP;
        }
 
        return 0;
 }
 
+static const struct nand_controller_ops fsl_elbc_controller_ops = {
+       .attach_chip = fsl_elbc_attach_chip,
+};
+
 static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
 {
        struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
index e65d274399f91d213e5141c55291a1fbd094bc2e..04a3dcd675bfa298bb545f97338ec89aeb34c341 100644 (file)
@@ -722,9 +722,9 @@ static int fsl_ifc_attach_chip(struct nand_chip *chip)
        struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 
        dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
-                                                       chip->numchips);
+               nanddev_ntargets(&chip->base));
        dev_dbg(priv->dev, "%s: nand->chipsize = %lld\n", __func__,
-                                                       chip->chipsize);
+               nanddev_target_size(&chip->base));
        dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__,
                                                        chip->pagemask);
        dev_dbg(priv->dev, "%s: nand->legacy.chip_delay = %d\n", __func__,
index a4768df5083f9633a965bf85f12dce4b1d6ad35c..a8b26d2e793c21c3808a26ad857e7928c1915c4e 100644 (file)
@@ -157,8 +157,7 @@ int gpmi_init(struct gpmi_nand_data *this)
         * Reset BCH here, too. We got failures otherwise :(
         * See later BCH reset for explanation of MX23 and MX28 handling
         */
-       ret = gpmi_reset_block(r->bch_regs,
-                              GPMI_IS_MX23(this) || GPMI_IS_MX28(this));
+       ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this));
        if (ret)
                goto err_out;
 
@@ -266,8 +265,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
        * chip, otherwise it will lock up. So we skip resetting BCH on the MX23.
        * and MX28.
        */
-       ret = gpmi_reset_block(r->bch_regs,
-                              GPMI_IS_MX23(this) || GPMI_IS_MX28(this));
+       ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this));
        if (ret)
                goto err_out;
 
index ed405c9434fe531a4e961119388dafeb4922b59d..40df20d1adf518b771e6e5139c8fc9fe30055a2d 100644 (file)
@@ -171,7 +171,7 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
        struct bch_geometry *geo = &this->bch_geometry;
 
        /* Do the sanity check. */
-       if (GPMI_IS_MX23(this) || GPMI_IS_MX28(this)) {
+       if (GPMI_IS_MXS(this)) {
                /* The mx23/mx28 only support the GF13. */
                if (geo->gf_len == 14)
                        return false;
@@ -204,7 +204,8 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this,
        default:
                dev_err(this->dev,
                        "unsupported nand chip. ecc bits : %d, ecc size : %d\n",
-                       chip->ecc_strength_ds, chip->ecc_step_ds);
+                       chip->base.eccreq.strength,
+                       chip->base.eccreq.step_size);
                return -EINVAL;
        }
        geo->ecc_chunk_size = ecc_step;
@@ -417,11 +418,13 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
 
        if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
                                || legacy_set_geometry(this)) {
-               if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
+               if (!(chip->base.eccreq.strength > 0 &&
+                     chip->base.eccreq.step_size > 0))
                        return -EINVAL;
 
-               return set_geometry_by_ecc_info(this, chip->ecc_strength_ds,
-                                               chip->ecc_step_ds);
+               return set_geometry_by_ecc_info(this,
+                                               chip->base.eccreq.strength,
+                                               chip->base.eccreq.step_size);
        }
 
        return 0;
@@ -1602,7 +1605,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
        unsigned int search_area_size_in_strides;
        unsigned int stride;
        unsigned int page;
-       uint8_t *buffer = chip->data_buf;
+       u8 *buffer = nand_get_data_buf(chip);
        int saved_chip_number;
        int found_an_ncb_fingerprint = false;
 
@@ -1664,7 +1667,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
        unsigned int block;
        unsigned int stride;
        unsigned int page;
-       uint8_t      *buffer = chip->data_buf;
+       u8 *buffer = nand_get_data_buf(chip);
        int saved_chip_number;
        int status;
 
@@ -1753,7 +1756,7 @@ static int mx23_boot_init(struct gpmi_nand_data  *this)
        dev_dbg(dev, "Transcribing bad block marks...\n");
 
        /* Compute the number of blocks in the entire medium. */
-       block_count = chip->chipsize >> chip->phys_erase_shift;
+       block_count = nanddev_eraseblocks_per_target(&chip->base);
 
        /*
         * Loop over all the blocks in the medium, transcribing block marks as
index d0b79bac2728072ff359a9137cdedac4fe13b67a..a804a4a5bd46a99a3fe7fe01cb6ccafc4038515c 100644 (file)
@@ -207,4 +207,5 @@ void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
 
 #define GPMI_IS_MX6(x)         (GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x) || \
                                 GPMI_IS_MX7D(x))
+#define GPMI_IS_MXS(x)         (GPMI_IS_MX23(x) || GPMI_IS_MX28(x))
 #endif
index f3f9aa160cffefecf7d93a2f18f136014596220a..e4526fff9da4918c02468fd0f3fab5967cf91286 100644 (file)
@@ -849,7 +849,7 @@ static int hisi_nfc_resume(struct device *dev)
        struct hinfc_host *host = dev_get_drvdata(dev);
        struct nand_chip *chip = &host->chip;
 
-       for (cs = 0; cs < chip->numchips; cs++)
+       for (cs = 0; cs < nanddev_ntargets(&chip->base); cs++)
                hisi_nfc_send_cmd_reset(host, cs);
        hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
                    HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
diff --git a/drivers/mtd/nand/raw/ingenic/Kconfig b/drivers/mtd/nand/raw/ingenic/Kconfig
new file mode 100644 (file)
index 0000000..7cfc770
--- /dev/null
@@ -0,0 +1,50 @@
+config MTD_NAND_JZ4740
+       tristate "JZ4740 NAND controller"
+       depends on MACH_JZ4740 || COMPILE_TEST
+       depends on HAS_IOMEM
+       help
+         Enables support for NAND Flash on JZ4740 SoC based boards.
+
+config MTD_NAND_JZ4780
+       tristate "JZ4780 NAND controller"
+       depends on JZ4780_NEMC
+       help
+         Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
+         based boards, using the BCH controller for hardware error correction.
+
+if MTD_NAND_JZ4780
+
+config MTD_NAND_INGENIC_ECC
+       tristate
+
+config MTD_NAND_JZ4740_ECC
+       tristate "Hardware BCH support for JZ4740 SoC"
+       select MTD_NAND_INGENIC_ECC
+       help
+         Enable this driver to support the Reed-Solomon error-correction
+         hardware present on the JZ4740 SoC from Ingenic.
+
+         This driver can also be built as a module. If so, the module
+         will be called jz4740-ecc.
+
+config MTD_NAND_JZ4725B_BCH
+       tristate "Hardware BCH support for JZ4725B SoC"
+       select MTD_NAND_INGENIC_ECC
+       help
+         Enable this driver to support the BCH error-correction hardware
+         present on the JZ4725B SoC from Ingenic.
+
+         This driver can also be built as a module. If so, the module
+         will be called jz4725b-bch.
+
+config MTD_NAND_JZ4780_BCH
+       tristate "Hardware BCH support for JZ4780 SoC"
+       select MTD_NAND_INGENIC_ECC
+       help
+         Enable this driver to support the BCH error-correction hardware
+         present on the JZ4780 SoC from Ingenic.
+
+         This driver can also be built as a module. If so, the module
+         will be called jz4780-bch.
+
+endif # MTD_NAND_JZ4780
diff --git a/drivers/mtd/nand/raw/ingenic/Makefile b/drivers/mtd/nand/raw/ingenic/Makefile
new file mode 100644 (file)
index 0000000..ab2c5f4
--- /dev/null
@@ -0,0 +1,7 @@
+obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
+obj-$(CONFIG_MTD_NAND_JZ4780) += ingenic_nand.o
+
+obj-$(CONFIG_MTD_NAND_INGENIC_ECC) += ingenic_ecc.o
+obj-$(CONFIG_MTD_NAND_JZ4740_ECC) += jz4740_ecc.o
+obj-$(CONFIG_MTD_NAND_JZ4725B_BCH) += jz4725b_bch.o
+obj-$(CONFIG_MTD_NAND_JZ4780_BCH) += jz4780_bch.o
diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c
new file mode 100644 (file)
index 0000000..d3e085c
--- /dev/null
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * JZ47xx ECC common code
+ *
+ * Copyright (c) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#include "ingenic_ecc.h"
+
+/**
+ * ingenic_ecc_calculate() - calculate ECC for a data buffer
+ * @ecc: ECC device.
+ * @params: ECC parameters.
+ * @buf: input buffer with raw data.
+ * @ecc_code: output buffer with ECC.
+ *
+ * Return: 0 on success, -ETIMEDOUT if timed out while waiting for ECC
+ * controller.
+ */
+int ingenic_ecc_calculate(struct ingenic_ecc *ecc,
+                         struct ingenic_ecc_params *params,
+                         const u8 *buf, u8 *ecc_code)
+{
+       return ecc->ops->calculate(ecc, params, buf, ecc_code);
+}
+EXPORT_SYMBOL(ingenic_ecc_calculate);
+
+/**
+ * ingenic_ecc_correct() - detect and correct bit errors
+ * @ecc: ECC device.
+ * @params: ECC parameters.
+ * @buf: raw data read from the chip.
+ * @ecc_code: ECC read from the chip.
+ *
+ * Given the raw data and the ECC read from the NAND device, detects and
+ * corrects errors in the data.
+ *
+ * Return: the number of bit errors corrected, -EBADMSG if there are too many
+ * errors to correct or -ETIMEDOUT if we timed out waiting for the controller.
+ */
+int ingenic_ecc_correct(struct ingenic_ecc *ecc,
+                       struct ingenic_ecc_params *params,
+                       u8 *buf, u8 *ecc_code)
+{
+       return ecc->ops->correct(ecc, params, buf, ecc_code);
+}
+EXPORT_SYMBOL(ingenic_ecc_correct);
+
+/**
+ * ingenic_ecc_get() - get the ECC controller device
+ * @np: ECC device tree node.
+ *
+ * Gets the ECC controller device from the specified device tree node. The
+ * device must be released with ingenic_ecc_release() when it is no longer being
+ * used.
+ *
+ * Return: a pointer to ingenic_ecc, errors are encoded into the pointer.
+ * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
+ */
+static struct ingenic_ecc *ingenic_ecc_get(struct device_node *np)
+{
+       struct platform_device *pdev;
+       struct ingenic_ecc *ecc;
+
+       pdev = of_find_device_by_node(np);
+       if (!pdev || !platform_get_drvdata(pdev))
+               return ERR_PTR(-EPROBE_DEFER);
+
+       get_device(&pdev->dev);
+
+       ecc = platform_get_drvdata(pdev);
+       clk_prepare_enable(ecc->clk);
+
+       return ecc;
+}
+
+/**
+ * of_ingenic_ecc_get() - get the ECC controller from a DT node
+ * @of_node: the node that contains an ecc-engine property.
+ *
+ * Get the ecc-engine property from the given device tree
+ * node and pass it to ingenic_ecc_get to do the work.
+ *
+ * Return: a pointer to ingenic_ecc, errors are encoded into the pointer.
+ * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
+ */
+struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *of_node)
+{
+       struct ingenic_ecc *ecc = NULL;
+       struct device_node *np;
+
+       np = of_parse_phandle(of_node, "ecc-engine", 0);
+
+       /*
+        * If the ecc-engine property is not found, check for the deprecated
+        * ingenic,bch-controller property
+        */
+       if (!np)
+               np = of_parse_phandle(of_node, "ingenic,bch-controller", 0);
+
+       if (np) {
+               ecc = ingenic_ecc_get(np);
+               of_node_put(np);
+       }
+       return ecc;
+}
+EXPORT_SYMBOL(of_ingenic_ecc_get);
+
+/**
+ * ingenic_ecc_release() - release the ECC controller device
+ * @ecc: ECC device.
+ */
+void ingenic_ecc_release(struct ingenic_ecc *ecc)
+{
+       clk_disable_unprepare(ecc->clk);
+       put_device(ecc->dev);
+}
+EXPORT_SYMBOL(ingenic_ecc_release);
+
+int ingenic_ecc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ingenic_ecc *ecc;
+       struct resource *res;
+
+       ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
+       if (!ecc)
+               return -ENOMEM;
+
+       ecc->ops = device_get_match_data(dev);
+       if (!ecc->ops)
+               return -EINVAL;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ecc->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ecc->base))
+               return PTR_ERR(ecc->base);
+
+       ecc->ops->disable(ecc);
+
+       ecc->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(ecc->clk)) {
+               dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(ecc->clk));
+               return PTR_ERR(ecc->clk);
+       }
+
+       mutex_init(&ecc->lock);
+
+       ecc->dev = dev;
+       platform_set_drvdata(pdev, ecc);
+
+       return 0;
+}
+EXPORT_SYMBOL(ingenic_ecc_probe);
+
+MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
+MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
+MODULE_DESCRIPTION("Ingenic ECC common driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.h b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.h
new file mode 100644 (file)
index 0000000..2cda439
--- /dev/null
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __DRIVERS_MTD_NAND_INGENIC_ECC_INTERNAL_H__
+#define __DRIVERS_MTD_NAND_INGENIC_ECC_INTERNAL_H__
+
+#include <linux/compiler_types.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <uapi/asm-generic/errno-base.h>
+
+struct clk;
+struct device;
+struct ingenic_ecc;
+struct platform_device;
+
+/**
+ * struct ingenic_ecc_params - ECC parameters
+ * @size: data bytes per ECC step.
+ * @bytes: ECC bytes per step.
+ * @strength: number of correctable bits per ECC step.
+ */
+struct ingenic_ecc_params {
+       int size;
+       int bytes;
+       int strength;
+};
+
+#if IS_ENABLED(CONFIG_MTD_NAND_INGENIC_ECC)
+int ingenic_ecc_calculate(struct ingenic_ecc *ecc,
+                         struct ingenic_ecc_params *params,
+                         const u8 *buf, u8 *ecc_code);
+int ingenic_ecc_correct(struct ingenic_ecc *ecc,
+                       struct ingenic_ecc_params *params, u8 *buf,
+                       u8 *ecc_code);
+
+void ingenic_ecc_release(struct ingenic_ecc *ecc);
+struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np);
+#else /* CONFIG_MTD_NAND_INGENIC_ECC */
+int ingenic_ecc_calculate(struct ingenic_ecc *ecc,
+                         struct ingenic_ecc_params *params,
+                         const u8 *buf, u8 *ecc_code)
+{
+       return -ENODEV;
+}
+
+int ingenic_ecc_correct(struct ingenic_ecc *ecc,
+                       struct ingenic_ecc_params *params, u8 *buf,
+                       u8 *ecc_code)
+{
+       return -ENODEV;
+}
+
+void ingenic_ecc_release(struct ingenic_ecc *ecc)
+{
+}
+
+struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np)
+{
+       return ERR_PTR(-ENODEV);
+}
+#endif /* CONFIG_MTD_NAND_INGENIC_ECC */
+
+struct ingenic_ecc_ops {
+       void (*disable)(struct ingenic_ecc *ecc);
+       int (*calculate)(struct ingenic_ecc *ecc,
+                        struct ingenic_ecc_params *params,
+                        const u8 *buf, u8 *ecc_code);
+       int (*correct)(struct ingenic_ecc *ecc,
+                       struct ingenic_ecc_params *params,
+                       u8 *buf, u8 *ecc_code);
+};
+
+struct ingenic_ecc {
+       struct device *dev;
+       const struct ingenic_ecc_ops *ops;
+       void __iomem *base;
+       struct clk *clk;
+       struct mutex lock;
+};
+
+int ingenic_ecc_probe(struct platform_device *pdev);
+
+#endif /* __DRIVERS_MTD_NAND_INGENIC_ECC_INTERNAL_H__ */
diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand.c
new file mode 100644 (file)
index 0000000..d7b7c0f
--- /dev/null
@@ -0,0 +1,530 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Ingenic JZ47xx NAND driver
+ *
+ * Copyright (c) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/jz4780-nemc.h>
+
+#include "ingenic_ecc.h"
+
+#define DRV_NAME       "ingenic-nand"
+
+/* Command delay when there is no R/B pin. */
+#define RB_DELAY_US    100
+
+struct jz_soc_info {
+       unsigned long data_offset;
+       unsigned long addr_offset;
+       unsigned long cmd_offset;
+       const struct mtd_ooblayout_ops *oob_layout;
+};
+
+struct ingenic_nand_cs {
+       unsigned int bank;
+       void __iomem *base;
+};
+
+struct ingenic_nfc {
+       struct device *dev;
+       struct ingenic_ecc *ecc;
+       const struct jz_soc_info *soc_info;
+       struct nand_controller controller;
+       unsigned int num_banks;
+       struct list_head chips;
+       int selected;
+       struct ingenic_nand_cs cs[];
+};
+
+struct ingenic_nand {
+       struct nand_chip chip;
+       struct list_head chip_list;
+
+       struct gpio_desc *busy_gpio;
+       struct gpio_desc *wp_gpio;
+       unsigned int reading: 1;
+};
+
+static inline struct ingenic_nand *to_ingenic_nand(struct mtd_info *mtd)
+{
+       return container_of(mtd_to_nand(mtd), struct ingenic_nand, chip);
+}
+
+static inline struct ingenic_nfc *to_ingenic_nfc(struct nand_controller *ctrl)
+{
+       return container_of(ctrl, struct ingenic_nfc, controller);
+}
+
+static int qi_lb60_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                struct mtd_oob_region *oobregion)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+       if (section || !ecc->total)
+               return -ERANGE;
+
+       oobregion->length = ecc->total;
+       oobregion->offset = 12;
+
+       return 0;
+}
+
+static int qi_lb60_ooblayout_free(struct mtd_info *mtd, int section,
+                                 struct mtd_oob_region *oobregion)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+       if (section)
+               return -ERANGE;
+
+       oobregion->length = mtd->oobsize - ecc->total - 12;
+       oobregion->offset = 12 + ecc->total;
+
+       return 0;
+}
+
+const struct mtd_ooblayout_ops qi_lb60_ooblayout_ops = {
+       .ecc = qi_lb60_ooblayout_ecc,
+       .free = qi_lb60_ooblayout_free,
+};
+
+static int jz4725b_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                struct mtd_oob_region *oobregion)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+       if (section || !ecc->total)
+               return -ERANGE;
+
+       oobregion->length = ecc->total;
+       oobregion->offset = 3;
+
+       return 0;
+}
+
+static int jz4725b_ooblayout_free(struct mtd_info *mtd, int section,
+                                 struct mtd_oob_region *oobregion)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+       if (section)
+               return -ERANGE;
+
+       oobregion->length = mtd->oobsize - ecc->total - 3;
+       oobregion->offset = 3 + ecc->total;
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops jz4725b_ooblayout_ops = {
+       .ecc = jz4725b_ooblayout_ecc,
+       .free = jz4725b_ooblayout_free,
+};
+
+static void ingenic_nand_select_chip(struct nand_chip *chip, int chipnr)
+{
+       struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip));
+       struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller);
+       struct ingenic_nand_cs *cs;
+
+       /* Ensure the currently selected chip is deasserted. */
+       if (chipnr == -1 && nfc->selected >= 0) {
+               cs = &nfc->cs[nfc->selected];
+               jz4780_nemc_assert(nfc->dev, cs->bank, false);
+       }
+
+       nfc->selected = chipnr;
+}
+
+static void ingenic_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
+                                 unsigned int ctrl)
+{
+       struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip));
+       struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller);
+       struct ingenic_nand_cs *cs;
+
+       if (WARN_ON(nfc->selected < 0))
+               return;
+
+       cs = &nfc->cs[nfc->selected];
+
+       jz4780_nemc_assert(nfc->dev, cs->bank, ctrl & NAND_NCE);
+
+       if (cmd == NAND_CMD_NONE)
+               return;
+
+       if (ctrl & NAND_ALE)
+               writeb(cmd, cs->base + nfc->soc_info->addr_offset);
+       else if (ctrl & NAND_CLE)
+               writeb(cmd, cs->base + nfc->soc_info->cmd_offset);
+}
+
+static int ingenic_nand_dev_ready(struct nand_chip *chip)
+{
+       struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip));
+
+       return !gpiod_get_value_cansleep(nand->busy_gpio);
+}
+
+static void ingenic_nand_ecc_hwctl(struct nand_chip *chip, int mode)
+{
+       struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip));
+
+       nand->reading = (mode == NAND_ECC_READ);
+}
+
+static int ingenic_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat,
+                                     u8 *ecc_code)
+{
+       struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip));
+       struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller);
+       struct ingenic_ecc_params params;
+
+       /*
+        * Don't need to generate the ECC when reading, the ECC engine does it
+        * for us as part of decoding/correction.
+        */
+       if (nand->reading)
+               return 0;
+
+       params.size = nand->chip.ecc.size;
+       params.bytes = nand->chip.ecc.bytes;
+       params.strength = nand->chip.ecc.strength;
+
+       return ingenic_ecc_calculate(nfc->ecc, &params, dat, ecc_code);
+}
+
+static int ingenic_nand_ecc_correct(struct nand_chip *chip, u8 *dat,
+                                   u8 *read_ecc, u8 *calc_ecc)
+{
+       struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip));
+       struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller);
+       struct ingenic_ecc_params params;
+
+       params.size = nand->chip.ecc.size;
+       params.bytes = nand->chip.ecc.bytes;
+       params.strength = nand->chip.ecc.strength;
+
+       return ingenic_ecc_correct(nfc->ecc, &params, dat, read_ecc);
+}
+
+static int ingenic_nand_attach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct ingenic_nfc *nfc = to_ingenic_nfc(chip->controller);
+       int eccbytes;
+
+       if (chip->ecc.strength == 4) {
+               /* JZ4740 uses 9 bytes of ECC to correct maximum 4 errors */
+               chip->ecc.bytes = 9;
+       } else {
+               chip->ecc.bytes = fls((1 + 8) * chip->ecc.size) *
+                                 (chip->ecc.strength / 8);
+       }
+
+       switch (chip->ecc.mode) {
+       case NAND_ECC_HW:
+               if (!nfc->ecc) {
+                       dev_err(nfc->dev, "HW ECC selected, but ECC controller not found\n");
+                       return -ENODEV;
+               }
+
+               chip->ecc.hwctl = ingenic_nand_ecc_hwctl;
+               chip->ecc.calculate = ingenic_nand_ecc_calculate;
+               chip->ecc.correct = ingenic_nand_ecc_correct;
+               /* fall through */
+       case NAND_ECC_SOFT:
+               dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n",
+                        (nfc->ecc) ? "hardware ECC" : "software ECC",
+                        chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
+               break;
+       case NAND_ECC_NONE:
+               dev_info(nfc->dev, "not using ECC\n");
+               break;
+       default:
+               dev_err(nfc->dev, "ECC mode %d not supported\n",
+                       chip->ecc.mode);
+               return -EINVAL;
+       }
+
+       /* The NAND core will generate the ECC layout for SW ECC */
+       if (chip->ecc.mode != NAND_ECC_HW)
+               return 0;
+
+       /* Generate ECC layout. ECC codes are right aligned in the OOB area. */
+       eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
+
+       if (eccbytes > mtd->oobsize - 2) {
+               dev_err(nfc->dev,
+                       "invalid ECC config: required %d ECC bytes, but only %d are available",
+                       eccbytes, mtd->oobsize - 2);
+               return -EINVAL;
+       }
+
+       /*
+        * The generic layout for BBT markers will most likely overlap with our
+        * ECC bytes in the OOB, so move the BBT markers outside the OOB area.
+        */
+       if (chip->bbt_options & NAND_BBT_USE_FLASH)
+               chip->bbt_options |= NAND_BBT_NO_OOB;
+
+       /* For legacy reasons we use a different layout on the qi,lb60 board. */
+       if (of_machine_is_compatible("qi,lb60"))
+               mtd_set_ooblayout(mtd, &qi_lb60_ooblayout_ops);
+       else
+               mtd_set_ooblayout(mtd, nfc->soc_info->oob_layout);
+
+       return 0;
+}
+
+static const struct nand_controller_ops ingenic_nand_controller_ops = {
+       .attach_chip = ingenic_nand_attach_chip,
+};
+
+static int ingenic_nand_init_chip(struct platform_device *pdev,
+                                 struct ingenic_nfc *nfc,
+                                 struct device_node *np,
+                                 unsigned int chipnr)
+{
+       struct device *dev = &pdev->dev;
+       struct ingenic_nand *nand;
+       struct ingenic_nand_cs *cs;
+       struct resource *res;
+       struct nand_chip *chip;
+       struct mtd_info *mtd;
+       const __be32 *reg;
+       int ret = 0;
+
+       cs = &nfc->cs[chipnr];
+
+       reg = of_get_property(np, "reg", NULL);
+       if (!reg)
+               return -EINVAL;
+
+       cs->bank = be32_to_cpu(*reg);
+
+       jz4780_nemc_set_type(nfc->dev, cs->bank, JZ4780_NEMC_BANK_NAND);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, chipnr);
+       cs->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(cs->base))
+               return PTR_ERR(cs->base);
+
+       nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL);
+       if (!nand)
+               return -ENOMEM;
+
+       nand->busy_gpio = devm_gpiod_get_optional(dev, "rb", GPIOD_IN);
+
+       if (IS_ERR(nand->busy_gpio)) {
+               ret = PTR_ERR(nand->busy_gpio);
+               dev_err(dev, "failed to request busy GPIO: %d\n", ret);
+               return ret;
+       } else if (nand->busy_gpio) {
+               nand->chip.legacy.dev_ready = ingenic_nand_dev_ready;
+       }
+
+       nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW);
+
+       if (IS_ERR(nand->wp_gpio)) {
+               ret = PTR_ERR(nand->wp_gpio);
+               dev_err(dev, "failed to request WP GPIO: %d\n", ret);
+               return ret;
+       }
+
+       chip = &nand->chip;
+       mtd = nand_to_mtd(chip);
+       mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev),
+                                  cs->bank);
+       if (!mtd->name)
+               return -ENOMEM;
+       mtd->dev.parent = dev;
+
+       chip->legacy.IO_ADDR_R = cs->base + nfc->soc_info->data_offset;
+       chip->legacy.IO_ADDR_W = cs->base + nfc->soc_info->data_offset;
+       chip->legacy.chip_delay = RB_DELAY_US;
+       chip->options = NAND_NO_SUBPAGE_WRITE;
+       chip->legacy.select_chip = ingenic_nand_select_chip;
+       chip->legacy.cmd_ctrl = ingenic_nand_cmd_ctrl;
+       chip->ecc.mode = NAND_ECC_HW;
+       chip->controller = &nfc->controller;
+       nand_set_flash_node(chip, np);
+
+       chip->controller->ops = &ingenic_nand_controller_ops;
+       ret = nand_scan(chip, 1);
+       if (ret)
+               return ret;
+
+       ret = mtd_device_register(mtd, NULL, 0);
+       if (ret) {
+               nand_release(chip);
+               return ret;
+       }
+
+       list_add_tail(&nand->chip_list, &nfc->chips);
+
+       return 0;
+}
+
+static void ingenic_nand_cleanup_chips(struct ingenic_nfc *nfc)
+{
+       struct ingenic_nand *chip;
+
+       while (!list_empty(&nfc->chips)) {
+               chip = list_first_entry(&nfc->chips,
+                                       struct ingenic_nand, chip_list);
+               nand_release(&chip->chip);
+               list_del(&chip->chip_list);
+       }
+}
+
+static int ingenic_nand_init_chips(struct ingenic_nfc *nfc,
+                                  struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np;
+       int i = 0;
+       int ret;
+       int num_chips = of_get_child_count(dev->of_node);
+
+       if (num_chips > nfc->num_banks) {
+               dev_err(dev, "found %d chips but only %d banks\n",
+                       num_chips, nfc->num_banks);
+               return -EINVAL;
+       }
+
+       for_each_child_of_node(dev->of_node, np) {
+               ret = ingenic_nand_init_chip(pdev, nfc, np, i);
+               if (ret) {
+                       ingenic_nand_cleanup_chips(nfc);
+                       return ret;
+               }
+
+               i++;
+       }
+
+       return 0;
+}
+
+static int ingenic_nand_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       unsigned int num_banks;
+       struct ingenic_nfc *nfc;
+       int ret;
+
+       num_banks = jz4780_nemc_num_banks(dev);
+       if (num_banks == 0) {
+               dev_err(dev, "no banks found\n");
+               return -ENODEV;
+       }
+
+       nfc = devm_kzalloc(dev, struct_size(nfc, cs, num_banks), GFP_KERNEL);
+       if (!nfc)
+               return -ENOMEM;
+
+       nfc->soc_info = device_get_match_data(dev);
+       if (!nfc->soc_info)
+               return -EINVAL;
+
+       /*
+        * Check for ECC HW before we call nand_scan_ident, to prevent us from
+        * having to call it again if the ECC driver returns -EPROBE_DEFER.
+        */
+       nfc->ecc = of_ingenic_ecc_get(dev->of_node);
+       if (IS_ERR(nfc->ecc))
+               return PTR_ERR(nfc->ecc);
+
+       nfc->dev = dev;
+       nfc->num_banks = num_banks;
+
+       nand_controller_init(&nfc->controller);
+       INIT_LIST_HEAD(&nfc->chips);
+
+       ret = ingenic_nand_init_chips(nfc, pdev);
+       if (ret) {
+               if (nfc->ecc)
+                       ingenic_ecc_release(nfc->ecc);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, nfc);
+       return 0;
+}
+
+static int ingenic_nand_remove(struct platform_device *pdev)
+{
+       struct ingenic_nfc *nfc = platform_get_drvdata(pdev);
+
+       if (nfc->ecc)
+               ingenic_ecc_release(nfc->ecc);
+
+       ingenic_nand_cleanup_chips(nfc);
+
+       return 0;
+}
+
+static const struct jz_soc_info jz4740_soc_info = {
+       .data_offset = 0x00000000,
+       .cmd_offset = 0x00008000,
+       .addr_offset = 0x00010000,
+       .oob_layout = &nand_ooblayout_lp_ops,
+};
+
+static const struct jz_soc_info jz4725b_soc_info = {
+       .data_offset = 0x00000000,
+       .cmd_offset = 0x00008000,
+       .addr_offset = 0x00010000,
+       .oob_layout = &jz4725b_ooblayout_ops,
+};
+
+static const struct jz_soc_info jz4780_soc_info = {
+       .data_offset = 0x00000000,
+       .cmd_offset = 0x00400000,
+       .addr_offset = 0x00800000,
+       .oob_layout = &nand_ooblayout_lp_ops,
+};
+
+static const struct of_device_id ingenic_nand_dt_match[] = {
+       { .compatible = "ingenic,jz4740-nand", .data = &jz4740_soc_info },
+       { .compatible = "ingenic,jz4725b-nand", .data = &jz4725b_soc_info },
+       { .compatible = "ingenic,jz4780-nand", .data = &jz4780_soc_info },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ingenic_nand_dt_match);
+
+static struct platform_driver ingenic_nand_driver = {
+       .probe          = ingenic_nand_probe,
+       .remove         = ingenic_nand_remove,
+       .driver = {
+               .name   = DRV_NAME,
+               .of_match_table = of_match_ptr(ingenic_nand_dt_match),
+       },
+};
+module_platform_driver(ingenic_nand_driver);
+
+MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
+MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
+MODULE_DESCRIPTION("Ingenic JZ47xx NAND driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/raw/ingenic/jz4725b_bch.c b/drivers/mtd/nand/raw/ingenic/jz4725b_bch.c
new file mode 100644 (file)
index 0000000..6c852ea
--- /dev/null
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * JZ4725B BCH controller driver
+ *
+ * Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net>
+ *
+ * Based on jz4780_bch.c
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#include "ingenic_ecc.h"
+
+#define BCH_BHCR                       0x0
+#define BCH_BHCSR                      0x4
+#define BCH_BHCCR                      0x8
+#define BCH_BHCNT                      0xc
+#define BCH_BHDR                       0x10
+#define BCH_BHPAR0                     0x14
+#define BCH_BHERR0                     0x28
+#define BCH_BHINT                      0x24
+#define BCH_BHINTES                    0x3c
+#define BCH_BHINTEC                    0x40
+#define BCH_BHINTE                     0x38
+
+#define BCH_BHCR_ENCE                  BIT(3)
+#define BCH_BHCR_BSEL                  BIT(2)
+#define BCH_BHCR_INIT                  BIT(1)
+#define BCH_BHCR_BCHE                  BIT(0)
+
+#define BCH_BHCNT_DEC_COUNT_SHIFT      16
+#define BCH_BHCNT_DEC_COUNT_MASK       (0x3ff << BCH_BHCNT_DEC_COUNT_SHIFT)
+#define BCH_BHCNT_ENC_COUNT_SHIFT      0
+#define BCH_BHCNT_ENC_COUNT_MASK       (0x3ff << BCH_BHCNT_ENC_COUNT_SHIFT)
+
+#define BCH_BHERR_INDEX0_SHIFT         0
+#define BCH_BHERR_INDEX0_MASK          (0x1fff << BCH_BHERR_INDEX0_SHIFT)
+#define BCH_BHERR_INDEX1_SHIFT         16
+#define BCH_BHERR_INDEX1_MASK          (0x1fff << BCH_BHERR_INDEX1_SHIFT)
+
+#define BCH_BHINT_ERRC_SHIFT           28
+#define BCH_BHINT_ERRC_MASK            (0xf << BCH_BHINT_ERRC_SHIFT)
+#define BCH_BHINT_TERRC_SHIFT          16
+#define BCH_BHINT_TERRC_MASK           (0x7f << BCH_BHINT_TERRC_SHIFT)
+#define BCH_BHINT_ALL_0                        BIT(5)
+#define BCH_BHINT_ALL_F                        BIT(4)
+#define BCH_BHINT_DECF                 BIT(3)
+#define BCH_BHINT_ENCF                 BIT(2)
+#define BCH_BHINT_UNCOR                        BIT(1)
+#define BCH_BHINT_ERR                  BIT(0)
+
+/* Timeout for BCH calculation/correction. */
+#define BCH_TIMEOUT_US                 100000
+
+static inline void jz4725b_bch_config_set(struct ingenic_ecc *bch, u32 cfg)
+{
+       writel(cfg, bch->base + BCH_BHCSR);
+}
+
+static inline void jz4725b_bch_config_clear(struct ingenic_ecc *bch, u32 cfg)
+{
+       writel(cfg, bch->base + BCH_BHCCR);
+}
+
+static int jz4725b_bch_reset(struct ingenic_ecc *bch,
+                            struct ingenic_ecc_params *params, bool calc_ecc)
+{
+       u32 reg, max_value;
+
+       /* Clear interrupt status. */
+       writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
+
+       /* Initialise and enable BCH. */
+       jz4725b_bch_config_clear(bch, 0x1f);
+       jz4725b_bch_config_set(bch, BCH_BHCR_BCHE);
+
+       if (params->strength == 8)
+               jz4725b_bch_config_set(bch, BCH_BHCR_BSEL);
+       else
+               jz4725b_bch_config_clear(bch, BCH_BHCR_BSEL);
+
+       if (calc_ecc) /* calculate ECC from data */
+               jz4725b_bch_config_set(bch, BCH_BHCR_ENCE);
+       else /* correct data from ECC */
+               jz4725b_bch_config_clear(bch, BCH_BHCR_ENCE);
+
+       jz4725b_bch_config_set(bch, BCH_BHCR_INIT);
+
+       max_value = BCH_BHCNT_ENC_COUNT_MASK >> BCH_BHCNT_ENC_COUNT_SHIFT;
+       if (params->size > max_value)
+               return -EINVAL;
+
+       max_value = BCH_BHCNT_DEC_COUNT_MASK >> BCH_BHCNT_DEC_COUNT_SHIFT;
+       if (params->size + params->bytes > max_value)
+               return -EINVAL;
+
+       /* Set up BCH count register. */
+       reg = params->size << BCH_BHCNT_ENC_COUNT_SHIFT;
+       reg |= (params->size + params->bytes) << BCH_BHCNT_DEC_COUNT_SHIFT;
+       writel(reg, bch->base + BCH_BHCNT);
+
+       return 0;
+}
+
+static void jz4725b_bch_disable(struct ingenic_ecc *bch)
+{
+       /* Clear interrupts */
+       writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
+
+       /* Disable the hardware */
+       jz4725b_bch_config_clear(bch, BCH_BHCR_BCHE);
+}
+
+static void jz4725b_bch_write_data(struct ingenic_ecc *bch, const u8 *buf,
+                                  size_t size)
+{
+       while (size--)
+               writeb(*buf++, bch->base + BCH_BHDR);
+}
+
+static void jz4725b_bch_read_parity(struct ingenic_ecc *bch, u8 *buf,
+                                   size_t size)
+{
+       size_t size32 = size / sizeof(u32);
+       size_t size8 = size % sizeof(u32);
+       u32 *dest32;
+       u8 *dest8;
+       u32 val, offset = 0;
+
+       dest32 = (u32 *)buf;
+       while (size32--) {
+               *dest32++ = readl_relaxed(bch->base + BCH_BHPAR0 + offset);
+               offset += sizeof(u32);
+       }
+
+       dest8 = (u8 *)dest32;
+       val = readl_relaxed(bch->base + BCH_BHPAR0 + offset);
+       switch (size8) {
+       case 3:
+               dest8[2] = (val >> 16) & 0xff;
+               /* fall-through */
+       case 2:
+               dest8[1] = (val >> 8) & 0xff;
+               /* fall-through */
+       case 1:
+               dest8[0] = val & 0xff;
+               break;
+       }
+}
+
+static int jz4725b_bch_wait_complete(struct ingenic_ecc *bch, unsigned int irq,
+                                    u32 *status)
+{
+       u32 reg;
+       int ret;
+
+       /*
+        * While we could use interrupts here and sleep until the operation
+        * completes, the controller works fairly quickly (usually a few
+        * microseconds) and so the overhead of sleeping until we get an
+        * interrupt quite noticeably decreases performance.
+        */
+       ret = readl_relaxed_poll_timeout(bch->base + BCH_BHINT, reg,
+                                        reg & irq, 0, BCH_TIMEOUT_US);
+       if (ret)
+               return ret;
+
+       if (status)
+               *status = reg;
+
+       writel(reg, bch->base + BCH_BHINT);
+
+       return 0;
+}
+
+static int jz4725b_calculate(struct ingenic_ecc *bch,
+                            struct ingenic_ecc_params *params,
+                            const u8 *buf, u8 *ecc_code)
+{
+       int ret;
+
+       mutex_lock(&bch->lock);
+
+       ret = jz4725b_bch_reset(bch, params, true);
+       if (ret) {
+               dev_err(bch->dev, "Unable to init BCH with given parameters\n");
+               goto out_disable;
+       }
+
+       jz4725b_bch_write_data(bch, buf, params->size);
+
+       ret = jz4725b_bch_wait_complete(bch, BCH_BHINT_ENCF, NULL);
+       if (ret) {
+               dev_err(bch->dev, "timed out while calculating ECC\n");
+               goto out_disable;
+       }
+
+       jz4725b_bch_read_parity(bch, ecc_code, params->bytes);
+
+out_disable:
+       jz4725b_bch_disable(bch);
+       mutex_unlock(&bch->lock);
+
+       return ret;
+}
+
+static int jz4725b_correct(struct ingenic_ecc *bch,
+                          struct ingenic_ecc_params *params,
+                          u8 *buf, u8 *ecc_code)
+{
+       u32 reg, errors, bit;
+       unsigned int i;
+       int ret;
+
+       mutex_lock(&bch->lock);
+
+       ret = jz4725b_bch_reset(bch, params, false);
+       if (ret) {
+               dev_err(bch->dev, "Unable to init BCH with given parameters\n");
+               goto out;
+       }
+
+       jz4725b_bch_write_data(bch, buf, params->size);
+       jz4725b_bch_write_data(bch, ecc_code, params->bytes);
+
+       ret = jz4725b_bch_wait_complete(bch, BCH_BHINT_DECF, &reg);
+       if (ret) {
+               dev_err(bch->dev, "timed out while correcting data\n");
+               goto out;
+       }
+
+       if (reg & (BCH_BHINT_ALL_F | BCH_BHINT_ALL_0)) {
+               /* Data and ECC is all 0xff or 0x00 - nothing to correct */
+               ret = 0;
+               goto out;
+       }
+
+       if (reg & BCH_BHINT_UNCOR) {
+               /* Uncorrectable ECC error */
+               ret = -EBADMSG;
+               goto out;
+       }
+
+       errors = (reg & BCH_BHINT_ERRC_MASK) >> BCH_BHINT_ERRC_SHIFT;
+
+       /* Correct any detected errors. */
+       for (i = 0; i < errors; i++) {
+               if (i & 1) {
+                       bit = (reg & BCH_BHERR_INDEX1_MASK) >> BCH_BHERR_INDEX1_SHIFT;
+               } else {
+                       reg = readl(bch->base + BCH_BHERR0 + (i * 4));
+                       bit = (reg & BCH_BHERR_INDEX0_MASK) >> BCH_BHERR_INDEX0_SHIFT;
+               }
+
+               buf[(bit >> 3)] ^= BIT(bit & 0x7);
+       }
+
+out:
+       jz4725b_bch_disable(bch);
+       mutex_unlock(&bch->lock);
+
+       return ret;
+}
+
+static const struct ingenic_ecc_ops jz4725b_bch_ops = {
+       .disable = jz4725b_bch_disable,
+       .calculate = jz4725b_calculate,
+       .correct = jz4725b_correct,
+};
+
+static const struct of_device_id jz4725b_bch_dt_match[] = {
+       { .compatible = "ingenic,jz4725b-bch", .data = &jz4725b_bch_ops },
+       {},
+};
+MODULE_DEVICE_TABLE(of, jz4725b_bch_dt_match);
+
+static struct platform_driver jz4725b_bch_driver = {
+       .probe          = ingenic_ecc_probe,
+       .driver = {
+               .name   = "jz4725b-bch",
+               .of_match_table = jz4725b_bch_dt_match,
+       },
+};
+module_platform_driver(jz4725b_bch_driver);
+
+MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
+MODULE_DESCRIPTION("Ingenic JZ4725B BCH controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/raw/ingenic/jz4740_ecc.c b/drivers/mtd/nand/raw/ingenic/jz4740_ecc.c
new file mode 100644 (file)
index 0000000..13fea64
--- /dev/null
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * JZ4740 ECC controller driver
+ *
+ * Copyright (c) 2019 Paul Cercueil <paul@crapouillou.net>
+ *
+ * based on jz4740-nand.c
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#include "ingenic_ecc.h"
+
+#define JZ_REG_NAND_ECC_CTRL   0x00
+#define JZ_REG_NAND_DATA       0x04
+#define JZ_REG_NAND_PAR0       0x08
+#define JZ_REG_NAND_PAR1       0x0C
+#define JZ_REG_NAND_PAR2       0x10
+#define JZ_REG_NAND_IRQ_STAT   0x14
+#define JZ_REG_NAND_IRQ_CTRL   0x18
+#define JZ_REG_NAND_ERR(x)     (0x1C + ((x) << 2))
+
+#define JZ_NAND_ECC_CTRL_PAR_READY     BIT(4)
+#define JZ_NAND_ECC_CTRL_ENCODING      BIT(3)
+#define JZ_NAND_ECC_CTRL_RS            BIT(2)
+#define JZ_NAND_ECC_CTRL_RESET         BIT(1)
+#define JZ_NAND_ECC_CTRL_ENABLE                BIT(0)
+
+#define JZ_NAND_STATUS_ERR_COUNT       (BIT(31) | BIT(30) | BIT(29))
+#define JZ_NAND_STATUS_PAD_FINISH      BIT(4)
+#define JZ_NAND_STATUS_DEC_FINISH      BIT(3)
+#define JZ_NAND_STATUS_ENC_FINISH      BIT(2)
+#define JZ_NAND_STATUS_UNCOR_ERROR     BIT(1)
+#define JZ_NAND_STATUS_ERROR           BIT(0)
+
+static const uint8_t empty_block_ecc[] = {
+       0xcd, 0x9d, 0x90, 0x58, 0xf4, 0x8b, 0xff, 0xb7, 0x6f
+};
+
+static void jz4740_ecc_reset(struct ingenic_ecc *ecc, bool calc_ecc)
+{
+       uint32_t reg;
+
+       /* Clear interrupt status */
+       writel(0, ecc->base + JZ_REG_NAND_IRQ_STAT);
+
+       /* Initialize and enable ECC hardware */
+       reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL);
+       reg |= JZ_NAND_ECC_CTRL_RESET;
+       reg |= JZ_NAND_ECC_CTRL_ENABLE;
+       reg |= JZ_NAND_ECC_CTRL_RS;
+       if (calc_ecc) /* calculate ECC from data */
+               reg |= JZ_NAND_ECC_CTRL_ENCODING;
+       else /* correct data from ECC */
+               reg &= ~JZ_NAND_ECC_CTRL_ENCODING;
+
+       writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL);
+}
+
+static int jz4740_ecc_calculate(struct ingenic_ecc *ecc,
+                               struct ingenic_ecc_params *params,
+                               const u8 *buf, u8 *ecc_code)
+{
+       uint32_t reg, status;
+       unsigned int timeout = 1000;
+       int i;
+
+       jz4740_ecc_reset(ecc, true);
+
+       do {
+               status = readl(ecc->base + JZ_REG_NAND_IRQ_STAT);
+       } while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout);
+
+       if (timeout == 0)
+               return -ETIMEDOUT;
+
+       reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL);
+       reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
+       writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL);
+
+       for (i = 0; i < params->bytes; ++i)
+               ecc_code[i] = readb(ecc->base + JZ_REG_NAND_PAR0 + i);
+
+       /*
+        * If the written data is completely 0xff, we also want to write 0xff as
+        * ECC, otherwise we will get in trouble when doing subpage writes.
+        */
+       if (memcmp(ecc_code, empty_block_ecc, ARRAY_SIZE(empty_block_ecc)) == 0)
+               memset(ecc_code, 0xff, ARRAY_SIZE(empty_block_ecc));
+
+       return 0;
+}
+
+static void jz_nand_correct_data(uint8_t *buf, int index, int mask)
+{
+       int offset = index & 0x7;
+       uint16_t data;
+
+       index += (index >> 3);
+
+       data = buf[index];
+       data |= buf[index + 1] << 8;
+
+       mask ^= (data >> offset) & 0x1ff;
+       data &= ~(0x1ff << offset);
+       data |= (mask << offset);
+
+       buf[index] = data & 0xff;
+       buf[index + 1] = (data >> 8) & 0xff;
+}
+
+static int jz4740_ecc_correct(struct ingenic_ecc *ecc,
+                             struct ingenic_ecc_params *params,
+                             u8 *buf, u8 *ecc_code)
+{
+       int i, error_count, index;
+       uint32_t reg, status, error;
+       unsigned int timeout = 1000;
+
+       jz4740_ecc_reset(ecc, false);
+
+       for (i = 0; i < params->bytes; ++i)
+               writeb(ecc_code[i], ecc->base + JZ_REG_NAND_PAR0 + i);
+
+       reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL);
+       reg |= JZ_NAND_ECC_CTRL_PAR_READY;
+       writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL);
+
+       do {
+               status = readl(ecc->base + JZ_REG_NAND_IRQ_STAT);
+       } while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout);
+
+       if (timeout == 0)
+               return -ETIMEDOUT;
+
+       reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL);
+       reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
+       writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL);
+
+       if (status & JZ_NAND_STATUS_ERROR) {
+               if (status & JZ_NAND_STATUS_UNCOR_ERROR)
+                       return -EBADMSG;
+
+               error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
+
+               for (i = 0; i < error_count; ++i) {
+                       error = readl(ecc->base + JZ_REG_NAND_ERR(i));
+                       index = ((error >> 16) & 0x1ff) - 1;
+                       if (index >= 0 && index < params->size)
+                               jz_nand_correct_data(buf, index, error & 0x1ff);
+               }
+
+               return error_count;
+       }
+
+       return 0;
+}
+
+static void jz4740_ecc_disable(struct ingenic_ecc *ecc)
+{
+       u32 reg;
+
+       writel(0, ecc->base + JZ_REG_NAND_IRQ_STAT);
+       reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL);
+       reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
+       writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL);
+}
+
+static const struct ingenic_ecc_ops jz4740_ecc_ops = {
+       .disable = jz4740_ecc_disable,
+       .calculate = jz4740_ecc_calculate,
+       .correct = jz4740_ecc_correct,
+};
+
+static const struct of_device_id jz4740_ecc_dt_match[] = {
+       { .compatible = "ingenic,jz4740-ecc", .data = &jz4740_ecc_ops },
+       {},
+};
+MODULE_DEVICE_TABLE(of, jz4740_ecc_dt_match);
+
+static struct platform_driver jz4740_ecc_driver = {
+       .probe          = ingenic_ecc_probe,
+       .driver = {
+               .name   = "jz4740-ecc",
+               .of_match_table = jz4740_ecc_dt_match,
+       },
+};
+module_platform_driver(jz4740_ecc_driver);
+
+MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
+MODULE_DESCRIPTION("Ingenic JZ4740 ECC controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/raw/ingenic/jz4740_nand.c b/drivers/mtd/nand/raw/ingenic/jz4740_nand.c
new file mode 100644 (file)
index 0000000..f759f16
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ *  JZ4740 SoC NAND controller driver
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/gpio/consumer.h>
+
+#include <linux/platform_data/jz4740/jz4740_nand.h>
+
+#define JZ_REG_NAND_CTRL       0x50
+#define JZ_REG_NAND_ECC_CTRL   0x100
+#define JZ_REG_NAND_DATA       0x104
+#define JZ_REG_NAND_PAR0       0x108
+#define JZ_REG_NAND_PAR1       0x10C
+#define JZ_REG_NAND_PAR2       0x110
+#define JZ_REG_NAND_IRQ_STAT   0x114
+#define JZ_REG_NAND_IRQ_CTRL   0x118
+#define JZ_REG_NAND_ERR(x)     (0x11C + ((x) << 2))
+
+#define JZ_NAND_ECC_CTRL_PAR_READY     BIT(4)
+#define JZ_NAND_ECC_CTRL_ENCODING      BIT(3)
+#define JZ_NAND_ECC_CTRL_RS            BIT(2)
+#define JZ_NAND_ECC_CTRL_RESET         BIT(1)
+#define JZ_NAND_ECC_CTRL_ENABLE                BIT(0)
+
+#define JZ_NAND_STATUS_ERR_COUNT       (BIT(31) | BIT(30) | BIT(29))
+#define JZ_NAND_STATUS_PAD_FINISH      BIT(4)
+#define JZ_NAND_STATUS_DEC_FINISH      BIT(3)
+#define JZ_NAND_STATUS_ENC_FINISH      BIT(2)
+#define JZ_NAND_STATUS_UNCOR_ERROR     BIT(1)
+#define JZ_NAND_STATUS_ERROR           BIT(0)
+
+#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1)
+#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1)
+#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa
+
+#define JZ_NAND_MEM_CMD_OFFSET 0x08000
+#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
+
+struct jz_nand {
+       struct nand_chip chip;
+       void __iomem *base;
+       struct resource *mem;
+
+       unsigned char banks[JZ_NAND_NUM_BANKS];
+       void __iomem *bank_base[JZ_NAND_NUM_BANKS];
+       struct resource *bank_mem[JZ_NAND_NUM_BANKS];
+
+       int selected_bank;
+
+       struct gpio_desc *busy_gpio;
+       bool is_reading;
+};
+
+static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
+{
+       return container_of(mtd_to_nand(mtd), struct jz_nand, chip);
+}
+
+static void jz_nand_select_chip(struct nand_chip *chip, int chipnr)
+{
+       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
+       uint32_t ctrl;
+       int banknr;
+
+       ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
+       ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK;
+
+       if (chipnr == -1) {
+               banknr = -1;
+       } else {
+               banknr = nand->banks[chipnr] - 1;
+               chip->legacy.IO_ADDR_R = nand->bank_base[banknr];
+               chip->legacy.IO_ADDR_W = nand->bank_base[banknr];
+       }
+       writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+
+       nand->selected_bank = banknr;
+}
+
+static void jz_nand_cmd_ctrl(struct nand_chip *chip, int dat,
+                            unsigned int ctrl)
+{
+       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
+       uint32_t reg;
+       void __iomem *bank_base = nand->bank_base[nand->selected_bank];
+
+       BUG_ON(nand->selected_bank < 0);
+
+       if (ctrl & NAND_CTRL_CHANGE) {
+               BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE));
+               if (ctrl & NAND_ALE)
+                       bank_base += JZ_NAND_MEM_ADDR_OFFSET;
+               else if (ctrl & NAND_CLE)
+                       bank_base += JZ_NAND_MEM_CMD_OFFSET;
+               chip->legacy.IO_ADDR_W = bank_base;
+
+               reg = readl(nand->base + JZ_REG_NAND_CTRL);
+               if (ctrl & NAND_NCE)
+                       reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
+               else
+                       reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
+               writel(reg, nand->base + JZ_REG_NAND_CTRL);
+       }
+       if (dat != NAND_CMD_NONE)
+               writeb(dat, chip->legacy.IO_ADDR_W);
+}
+
+static int jz_nand_dev_ready(struct nand_chip *chip)
+{
+       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
+       return gpiod_get_value_cansleep(nand->busy_gpio);
+}
+
+static void jz_nand_hwctl(struct nand_chip *chip, int mode)
+{
+       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
+       uint32_t reg;
+
+       writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
+       reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+
+       reg |= JZ_NAND_ECC_CTRL_RESET;
+       reg |= JZ_NAND_ECC_CTRL_ENABLE;
+       reg |= JZ_NAND_ECC_CTRL_RS;
+
+       switch (mode) {
+       case NAND_ECC_READ:
+               reg &= ~JZ_NAND_ECC_CTRL_ENCODING;
+               nand->is_reading = true;
+               break;
+       case NAND_ECC_WRITE:
+               reg |= JZ_NAND_ECC_CTRL_ENCODING;
+               nand->is_reading = false;
+               break;
+       default:
+               break;
+       }
+
+       writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+}
+
+static int jz_nand_calculate_ecc_rs(struct nand_chip *chip, const uint8_t *dat,
+                                   uint8_t *ecc_code)
+{
+       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
+       uint32_t reg, status;
+       int i;
+       unsigned int timeout = 1000;
+       static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4,
+                                               0x8b, 0xff, 0xb7, 0x6f};
+
+       if (nand->is_reading)
+               return 0;
+
+       do {
+               status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
+       } while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout);
+
+       if (timeout == 0)
+           return -1;
+
+       reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+       reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
+       writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+
+       for (i = 0; i < 9; ++i)
+               ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i);
+
+       /* If the written data is completly 0xff, we also want to write 0xff as
+        * ecc, otherwise we will get in trouble when doing subpage writes. */
+       if (memcmp(ecc_code, empty_block_ecc, 9) == 0)
+               memset(ecc_code, 0xff, 9);
+
+       return 0;
+}
+
+static void jz_nand_correct_data(uint8_t *dat, int index, int mask)
+{
+       int offset = index & 0x7;
+       uint16_t data;
+
+       index += (index >> 3);
+
+       data = dat[index];
+       data |= dat[index+1] << 8;
+
+       mask ^= (data >> offset) & 0x1ff;
+       data &= ~(0x1ff << offset);
+       data |= (mask << offset);
+
+       dat[index] = data & 0xff;
+       dat[index+1] = (data >> 8) & 0xff;
+}
+
+static int jz_nand_correct_ecc_rs(struct nand_chip *chip, uint8_t *dat,
+                                 uint8_t *read_ecc, uint8_t *calc_ecc)
+{
+       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
+       int i, error_count, index;
+       uint32_t reg, status, error;
+       unsigned int timeout = 1000;
+
+       for (i = 0; i < 9; ++i)
+               writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i);
+
+       reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+       reg |= JZ_NAND_ECC_CTRL_PAR_READY;
+       writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+
+       do {
+               status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
+       } while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout);
+
+       if (timeout == 0)
+               return -ETIMEDOUT;
+
+       reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+       reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
+       writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+
+       if (status & JZ_NAND_STATUS_ERROR) {
+               if (status & JZ_NAND_STATUS_UNCOR_ERROR)
+                       return -EBADMSG;
+
+               error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
+
+               for (i = 0; i < error_count; ++i) {
+                       error = readl(nand->base + JZ_REG_NAND_ERR(i));
+                       index = ((error >> 16) & 0x1ff) - 1;
+                       if (index >= 0 && index < 512)
+                               jz_nand_correct_data(dat, index, error & 0x1ff);
+               }
+
+               return error_count;
+       }
+
+       return 0;
+}
+
+static int jz_nand_ioremap_resource(struct platform_device *pdev,
+       const char *name, struct resource **res, void __iomem **base)
+{
+       int ret;
+
+       *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+       if (!*res) {
+               dev_err(&pdev->dev, "Failed to get platform %s memory\n", name);
+               ret = -ENXIO;
+               goto err;
+       }
+
+       *res = request_mem_region((*res)->start, resource_size(*res),
+                               pdev->name);
+       if (!*res) {
+               dev_err(&pdev->dev, "Failed to request %s memory region\n", name);
+               ret = -EBUSY;
+               goto err;
+       }
+
+       *base = ioremap((*res)->start, resource_size(*res));
+       if (!*base) {
+               dev_err(&pdev->dev, "Failed to ioremap %s memory region\n", name);
+               ret = -EBUSY;
+               goto err_release_mem;
+       }
+
+       return 0;
+
+err_release_mem:
+       release_mem_region((*res)->start, resource_size(*res));
+err:
+       *res = NULL;
+       *base = NULL;
+       return ret;
+}
+
+static inline void jz_nand_iounmap_resource(struct resource *res,
+                                           void __iomem *base)
+{
+       iounmap(base);
+       release_mem_region(res->start, resource_size(res));
+}
+
+static int jz_nand_detect_bank(struct platform_device *pdev,
+                              struct jz_nand *nand, unsigned char bank,
+                              size_t chipnr, uint8_t *nand_maf_id,
+                              uint8_t *nand_dev_id)
+{
+       int ret;
+       char res_name[6];
+       uint32_t ctrl;
+       struct nand_chip *chip = &nand->chip;
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_memory_organization *memorg;
+       u8 id[2];
+
+       memorg = nanddev_get_memorg(&chip->base);
+
+       /* Request I/O resource. */
+       sprintf(res_name, "bank%d", bank);
+       ret = jz_nand_ioremap_resource(pdev, res_name,
+                                       &nand->bank_mem[bank - 1],
+                                       &nand->bank_base[bank - 1]);
+       if (ret)
+               return ret;
+
+       /* Enable chip in bank. */
+       ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
+       ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
+       writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+
+       if (chipnr == 0) {
+               /* Detect first chip. */
+               ret = nand_scan(chip, 1);
+               if (ret)
+                       goto notfound_id;
+
+               /* Retrieve the IDs from the first chip. */
+               nand_select_target(chip, 0);
+               nand_reset_op(chip);
+               nand_readid_op(chip, 0, id, sizeof(id));
+               *nand_maf_id = id[0];
+               *nand_dev_id = id[1];
+       } else {
+               /* Detect additional chip. */
+               nand_select_target(chip, chipnr);
+               nand_reset_op(chip);
+               nand_readid_op(chip, 0, id, sizeof(id));
+               if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) {
+                       ret = -ENODEV;
+                       goto notfound_id;
+               }
+
+               /* Update size of the MTD. */
+               memorg->ntargets++;
+               mtd->size += nanddev_target_size(&chip->base);
+       }
+
+       dev_info(&pdev->dev, "Found chip %zu on bank %i\n", chipnr, bank);
+       return 0;
+
+notfound_id:
+       dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
+       ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
+       writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+       jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+                                nand->bank_base[bank - 1]);
+       return ret;
+}
+
+static int jz_nand_attach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct device *dev = mtd->dev.parent;
+       struct jz_nand_platform_data *pdata = dev_get_platdata(dev);
+       struct platform_device *pdev = to_platform_device(dev);
+
+       if (pdata && pdata->ident_callback)
+               pdata->ident_callback(pdev, mtd, &pdata->partitions,
+                                     &pdata->num_partitions);
+
+       return 0;
+}
+
+static const struct nand_controller_ops jz_nand_controller_ops = {
+       .attach_chip = jz_nand_attach_chip,
+};
+
+static int jz_nand_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct jz_nand *nand;
+       struct nand_chip *chip;
+       struct mtd_info *mtd;
+       struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       size_t chipnr, bank_idx;
+       uint8_t nand_maf_id = 0, nand_dev_id = 0;
+
+       nand = kzalloc(sizeof(*nand), GFP_KERNEL);
+       if (!nand)
+               return -ENOMEM;
+
+       ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base);
+       if (ret)
+               goto err_free;
+
+       nand->busy_gpio = devm_gpiod_get_optional(&pdev->dev, "busy", GPIOD_IN);
+       if (IS_ERR(nand->busy_gpio)) {
+               ret = PTR_ERR(nand->busy_gpio);
+               dev_err(&pdev->dev, "Failed to request busy gpio %d\n",
+                   ret);
+               goto err_iounmap_mmio;
+       }
+
+       chip            = &nand->chip;
+       mtd             = nand_to_mtd(chip);
+       mtd->dev.parent = &pdev->dev;
+       mtd->name       = "jz4740-nand";
+
+       chip->ecc.hwctl         = jz_nand_hwctl;
+       chip->ecc.calculate     = jz_nand_calculate_ecc_rs;
+       chip->ecc.correct       = jz_nand_correct_ecc_rs;
+       chip->ecc.mode          = NAND_ECC_HW_OOB_FIRST;
+       chip->ecc.size          = 512;
+       chip->ecc.bytes         = 9;
+       chip->ecc.strength      = 4;
+       chip->ecc.options       = NAND_ECC_GENERIC_ERASED_CHECK;
+
+       chip->legacy.chip_delay = 50;
+       chip->legacy.cmd_ctrl = jz_nand_cmd_ctrl;
+       chip->legacy.select_chip = jz_nand_select_chip;
+       chip->legacy.dummy_controller.ops = &jz_nand_controller_ops;
+
+       if (nand->busy_gpio)
+               chip->legacy.dev_ready = jz_nand_dev_ready;
+
+       platform_set_drvdata(pdev, nand);
+
+       /* We are going to autodetect NAND chips in the banks specified in the
+        * platform data. Although nand_scan_ident() can detect multiple chips,
+        * it requires those chips to be numbered consecuitively, which is not
+        * always the case for external memory banks. And a fixed chip-to-bank
+        * mapping is not practical either, since for example Dingoo units
+        * produced at different times have NAND chips in different banks.
+        */
+       chipnr = 0;
+       for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) {
+               unsigned char bank;
+
+               /* If there is no platform data, look for NAND in bank 1,
+                * which is the most likely bank since it is the only one
+                * that can be booted from.
+                */
+               bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1;
+               if (bank == 0)
+                       break;
+               if (bank > JZ_NAND_NUM_BANKS) {
+                       dev_warn(&pdev->dev,
+                               "Skipping non-existing bank: %d\n", bank);
+                       continue;
+               }
+               /* The detection routine will directly or indirectly call
+                * jz_nand_select_chip(), so nand->banks has to contain the
+                * bank we're checking.
+                */
+               nand->banks[chipnr] = bank;
+               if (jz_nand_detect_bank(pdev, nand, bank, chipnr,
+                                       &nand_maf_id, &nand_dev_id) == 0)
+                       chipnr++;
+               else
+                       nand->banks[chipnr] = 0;
+       }
+       if (chipnr == 0) {
+               dev_err(&pdev->dev, "No NAND chips found\n");
+               goto err_iounmap_mmio;
+       }
+
+       ret = mtd_device_register(mtd, pdata ? pdata->partitions : NULL,
+                                 pdata ? pdata->num_partitions : 0);
+
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to add mtd device\n");
+               goto err_cleanup_nand;
+       }
+
+       dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
+
+       return 0;
+
+err_cleanup_nand:
+       nand_cleanup(chip);
+       while (chipnr--) {
+               unsigned char bank = nand->banks[chipnr];
+               jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+                                        nand->bank_base[bank - 1]);
+       }
+       writel(0, nand->base + JZ_REG_NAND_CTRL);
+err_iounmap_mmio:
+       jz_nand_iounmap_resource(nand->mem, nand->base);
+err_free:
+       kfree(nand);
+       return ret;
+}
+
+static int jz_nand_remove(struct platform_device *pdev)
+{
+       struct jz_nand *nand = platform_get_drvdata(pdev);
+       size_t i;
+
+       nand_release(&nand->chip);
+
+       /* Deassert and disable all chips */
+       writel(0, nand->base + JZ_REG_NAND_CTRL);
+
+       for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) {
+               unsigned char bank = nand->banks[i];
+               if (bank != 0) {
+                       jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+                                                nand->bank_base[bank - 1]);
+               }
+       }
+
+       jz_nand_iounmap_resource(nand->mem, nand->base);
+
+       kfree(nand);
+
+       return 0;
+}
+
+static struct platform_driver jz_nand_driver = {
+       .probe = jz_nand_probe,
+       .remove = jz_nand_remove,
+       .driver = {
+               .name = "jz4740-nand",
+       },
+};
+
+module_platform_driver(jz_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("NAND controller driver for JZ4740 SoC");
+MODULE_ALIAS("platform:jz4740-nand");
diff --git a/drivers/mtd/nand/raw/ingenic/jz4780_bch.c b/drivers/mtd/nand/raw/ingenic/jz4780_bch.c
new file mode 100644 (file)
index 0000000..079266a
--- /dev/null
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * JZ4780 BCH controller driver
+ *
+ * Copyright (c) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#include "ingenic_ecc.h"
+
+#define BCH_BHCR                       0x0
+#define BCH_BHCCR                      0x8
+#define BCH_BHCNT                      0xc
+#define BCH_BHDR                       0x10
+#define BCH_BHPAR0                     0x14
+#define BCH_BHERR0                     0x84
+#define BCH_BHINT                      0x184
+#define BCH_BHINTES                    0x188
+#define BCH_BHINTEC                    0x18c
+#define BCH_BHINTE                     0x190
+
+#define BCH_BHCR_BSEL_SHIFT            4
+#define BCH_BHCR_BSEL_MASK             (0x7f << BCH_BHCR_BSEL_SHIFT)
+#define BCH_BHCR_ENCE                  BIT(2)
+#define BCH_BHCR_INIT                  BIT(1)
+#define BCH_BHCR_BCHE                  BIT(0)
+
+#define BCH_BHCNT_PARITYSIZE_SHIFT     16
+#define BCH_BHCNT_PARITYSIZE_MASK      (0x7f << BCH_BHCNT_PARITYSIZE_SHIFT)
+#define BCH_BHCNT_BLOCKSIZE_SHIFT      0
+#define BCH_BHCNT_BLOCKSIZE_MASK       (0x7ff << BCH_BHCNT_BLOCKSIZE_SHIFT)
+
+#define BCH_BHERR_MASK_SHIFT           16
+#define BCH_BHERR_MASK_MASK            (0xffff << BCH_BHERR_MASK_SHIFT)
+#define BCH_BHERR_INDEX_SHIFT          0
+#define BCH_BHERR_INDEX_MASK           (0x7ff << BCH_BHERR_INDEX_SHIFT)
+
+#define BCH_BHINT_ERRC_SHIFT           24
+#define BCH_BHINT_ERRC_MASK            (0x7f << BCH_BHINT_ERRC_SHIFT)
+#define BCH_BHINT_TERRC_SHIFT          16
+#define BCH_BHINT_TERRC_MASK           (0x7f << BCH_BHINT_TERRC_SHIFT)
+#define BCH_BHINT_DECF                 BIT(3)
+#define BCH_BHINT_ENCF                 BIT(2)
+#define BCH_BHINT_UNCOR                        BIT(1)
+#define BCH_BHINT_ERR                  BIT(0)
+
+#define BCH_CLK_RATE                   (200 * 1000 * 1000)
+
+/* Timeout for BCH calculation/correction. */
+#define BCH_TIMEOUT_US                 100000
+
+static void jz4780_bch_reset(struct ingenic_ecc *bch,
+                            struct ingenic_ecc_params *params, bool encode)
+{
+       u32 reg;
+
+       /* Clear interrupt status. */
+       writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
+
+       /* Set up BCH count register. */
+       reg = params->size << BCH_BHCNT_BLOCKSIZE_SHIFT;
+       reg |= params->bytes << BCH_BHCNT_PARITYSIZE_SHIFT;
+       writel(reg, bch->base + BCH_BHCNT);
+
+       /* Initialise and enable BCH. */
+       reg = BCH_BHCR_BCHE | BCH_BHCR_INIT;
+       reg |= params->strength << BCH_BHCR_BSEL_SHIFT;
+       if (encode)
+               reg |= BCH_BHCR_ENCE;
+       writel(reg, bch->base + BCH_BHCR);
+}
+
+static void jz4780_bch_disable(struct ingenic_ecc *bch)
+{
+       writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
+       writel(BCH_BHCR_BCHE, bch->base + BCH_BHCCR);
+}
+
+static void jz4780_bch_write_data(struct ingenic_ecc *bch, const void *buf,
+                                 size_t size)
+{
+       size_t size32 = size / sizeof(u32);
+       size_t size8 = size % sizeof(u32);
+       const u32 *src32;
+       const u8 *src8;
+
+       src32 = (const u32 *)buf;
+       while (size32--)
+               writel(*src32++, bch->base + BCH_BHDR);
+
+       src8 = (const u8 *)src32;
+       while (size8--)
+               writeb(*src8++, bch->base + BCH_BHDR);
+}
+
+static void jz4780_bch_read_parity(struct ingenic_ecc *bch, void *buf,
+                                  size_t size)
+{
+       size_t size32 = size / sizeof(u32);
+       size_t size8 = size % sizeof(u32);
+       u32 *dest32;
+       u8 *dest8;
+       u32 val, offset = 0;
+
+       dest32 = (u32 *)buf;
+       while (size32--) {
+               *dest32++ = readl(bch->base + BCH_BHPAR0 + offset);
+               offset += sizeof(u32);
+       }
+
+       dest8 = (u8 *)dest32;
+       val = readl(bch->base + BCH_BHPAR0 + offset);
+       switch (size8) {
+       case 3:
+               dest8[2] = (val >> 16) & 0xff;
+               /* fall through */
+       case 2:
+               dest8[1] = (val >> 8) & 0xff;
+               /* fall through */
+       case 1:
+               dest8[0] = val & 0xff;
+               break;
+       }
+}
+
+static bool jz4780_bch_wait_complete(struct ingenic_ecc *bch, unsigned int irq,
+                                    u32 *status)
+{
+       u32 reg;
+       int ret;
+
+       /*
+        * While we could use interrupts here and sleep until the operation
+        * completes, the controller works fairly quickly (usually a few
+        * microseconds) and so the overhead of sleeping until we get an
+        * interrupt quite noticeably decreases performance.
+        */
+       ret = readl_poll_timeout(bch->base + BCH_BHINT, reg,
+                                (reg & irq) == irq, 0, BCH_TIMEOUT_US);
+       if (ret)
+               return false;
+
+       if (status)
+               *status = reg;
+
+       writel(reg, bch->base + BCH_BHINT);
+       return true;
+}
+
+static int jz4780_calculate(struct ingenic_ecc *bch,
+                           struct ingenic_ecc_params *params,
+                           const u8 *buf, u8 *ecc_code)
+{
+       int ret = 0;
+
+       mutex_lock(&bch->lock);
+
+       jz4780_bch_reset(bch, params, true);
+       jz4780_bch_write_data(bch, buf, params->size);
+
+       if (jz4780_bch_wait_complete(bch, BCH_BHINT_ENCF, NULL)) {
+               jz4780_bch_read_parity(bch, ecc_code, params->bytes);
+       } else {
+               dev_err(bch->dev, "timed out while calculating ECC\n");
+               ret = -ETIMEDOUT;
+       }
+
+       jz4780_bch_disable(bch);
+       mutex_unlock(&bch->lock);
+       return ret;
+}
+
+static int jz4780_correct(struct ingenic_ecc *bch,
+                         struct ingenic_ecc_params *params,
+                         u8 *buf, u8 *ecc_code)
+{
+       u32 reg, mask, index;
+       int i, ret, count;
+
+       mutex_lock(&bch->lock);
+
+       jz4780_bch_reset(bch, params, false);
+       jz4780_bch_write_data(bch, buf, params->size);
+       jz4780_bch_write_data(bch, ecc_code, params->bytes);
+
+       if (!jz4780_bch_wait_complete(bch, BCH_BHINT_DECF, &reg)) {
+               dev_err(bch->dev, "timed out while correcting data\n");
+               ret = -ETIMEDOUT;
+               goto out;
+       }
+
+       if (reg & BCH_BHINT_UNCOR) {
+               dev_warn(bch->dev, "uncorrectable ECC error\n");
+               ret = -EBADMSG;
+               goto out;
+       }
+
+       /* Correct any detected errors. */
+       if (reg & BCH_BHINT_ERR) {
+               count = (reg & BCH_BHINT_ERRC_MASK) >> BCH_BHINT_ERRC_SHIFT;
+               ret = (reg & BCH_BHINT_TERRC_MASK) >> BCH_BHINT_TERRC_SHIFT;
+
+               for (i = 0; i < count; i++) {
+                       reg = readl(bch->base + BCH_BHERR0 + (i * 4));
+                       mask = (reg & BCH_BHERR_MASK_MASK) >>
+                                               BCH_BHERR_MASK_SHIFT;
+                       index = (reg & BCH_BHERR_INDEX_MASK) >>
+                                               BCH_BHERR_INDEX_SHIFT;
+                       buf[(index * 2) + 0] ^= mask;
+                       buf[(index * 2) + 1] ^= mask >> 8;
+               }
+       } else {
+               ret = 0;
+       }
+
+out:
+       jz4780_bch_disable(bch);
+       mutex_unlock(&bch->lock);
+       return ret;
+}
+
+static int jz4780_bch_probe(struct platform_device *pdev)
+{
+       struct ingenic_ecc *bch;
+       int ret;
+
+       ret = ingenic_ecc_probe(pdev);
+       if (ret)
+               return ret;
+
+       bch = platform_get_drvdata(pdev);
+       clk_set_rate(bch->clk, BCH_CLK_RATE);
+
+       return 0;
+}
+
+static const struct ingenic_ecc_ops jz4780_bch_ops = {
+       .disable = jz4780_bch_disable,
+       .calculate = jz4780_calculate,
+       .correct = jz4780_correct,
+};
+
+static const struct of_device_id jz4780_bch_dt_match[] = {
+       { .compatible = "ingenic,jz4780-bch", .data = &jz4780_bch_ops },
+       {},
+};
+MODULE_DEVICE_TABLE(of, jz4780_bch_dt_match);
+
+static struct platform_driver jz4780_bch_driver = {
+       .probe          = jz4780_bch_probe,
+       .driver = {
+               .name   = "jz4780-bch",
+               .of_match_table = of_match_ptr(jz4780_bch_dt_match),
+       },
+};
+module_platform_driver(jz4780_bch_driver);
+
+MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
+MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
+MODULE_DESCRIPTION("Ingenic JZ4780 BCH error correction driver");
+MODULE_LICENSE("GPL v2");
index fbf6ca015cd7e9c73cc07e9c9f771d17da569ce8..cba6fe7dd8c4d163243e1ba41e5b6ffead7e3ce8 100644 (file)
@@ -76,6 +76,7 @@ extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops;
 
 /* Core functions */
 const struct nand_manufacturer *nand_get_manufacturer(u8 id);
+int nand_bbm_get_next_page(struct nand_chip *chip, int page);
 int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs);
 int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
                    int allowbbt);
@@ -110,7 +111,7 @@ static inline int nand_exec_op(struct nand_chip *chip,
        if (!nand_has_exec_op(chip))
                return -ENOTSUPP;
 
-       if (WARN_ON(op->cs >= chip->numchips))
+       if (WARN_ON(op->cs >= nanddev_ntargets(&chip->base)))
                return -EINVAL;
 
        return chip->controller->ops->exec_op(chip, op, false);
diff --git a/drivers/mtd/nand/raw/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c
deleted file mode 100644 (file)
index 9526d5b..0000000
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
- *  JZ4740 SoC NAND controller driver
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-
-#include <linux/gpio/consumer.h>
-
-#include <linux/platform_data/jz4740/jz4740_nand.h>
-
-#define JZ_REG_NAND_CTRL       0x50
-#define JZ_REG_NAND_ECC_CTRL   0x100
-#define JZ_REG_NAND_DATA       0x104
-#define JZ_REG_NAND_PAR0       0x108
-#define JZ_REG_NAND_PAR1       0x10C
-#define JZ_REG_NAND_PAR2       0x110
-#define JZ_REG_NAND_IRQ_STAT   0x114
-#define JZ_REG_NAND_IRQ_CTRL   0x118
-#define JZ_REG_NAND_ERR(x)     (0x11C + ((x) << 2))
-
-#define JZ_NAND_ECC_CTRL_PAR_READY     BIT(4)
-#define JZ_NAND_ECC_CTRL_ENCODING      BIT(3)
-#define JZ_NAND_ECC_CTRL_RS            BIT(2)
-#define JZ_NAND_ECC_CTRL_RESET         BIT(1)
-#define JZ_NAND_ECC_CTRL_ENABLE                BIT(0)
-
-#define JZ_NAND_STATUS_ERR_COUNT       (BIT(31) | BIT(30) | BIT(29))
-#define JZ_NAND_STATUS_PAD_FINISH      BIT(4)
-#define JZ_NAND_STATUS_DEC_FINISH      BIT(3)
-#define JZ_NAND_STATUS_ENC_FINISH      BIT(2)
-#define JZ_NAND_STATUS_UNCOR_ERROR     BIT(1)
-#define JZ_NAND_STATUS_ERROR           BIT(0)
-
-#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1)
-#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1)
-#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa
-
-#define JZ_NAND_MEM_CMD_OFFSET 0x08000
-#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
-
-struct jz_nand {
-       struct nand_chip chip;
-       void __iomem *base;
-       struct resource *mem;
-
-       unsigned char banks[JZ_NAND_NUM_BANKS];
-       void __iomem *bank_base[JZ_NAND_NUM_BANKS];
-       struct resource *bank_mem[JZ_NAND_NUM_BANKS];
-
-       int selected_bank;
-
-       struct gpio_desc *busy_gpio;
-       bool is_reading;
-};
-
-static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
-{
-       return container_of(mtd_to_nand(mtd), struct jz_nand, chip);
-}
-
-static void jz_nand_select_chip(struct nand_chip *chip, int chipnr)
-{
-       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
-       uint32_t ctrl;
-       int banknr;
-
-       ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
-       ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK;
-
-       if (chipnr == -1) {
-               banknr = -1;
-       } else {
-               banknr = nand->banks[chipnr] - 1;
-               chip->legacy.IO_ADDR_R = nand->bank_base[banknr];
-               chip->legacy.IO_ADDR_W = nand->bank_base[banknr];
-       }
-       writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
-
-       nand->selected_bank = banknr;
-}
-
-static void jz_nand_cmd_ctrl(struct nand_chip *chip, int dat,
-                            unsigned int ctrl)
-{
-       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
-       uint32_t reg;
-       void __iomem *bank_base = nand->bank_base[nand->selected_bank];
-
-       BUG_ON(nand->selected_bank < 0);
-
-       if (ctrl & NAND_CTRL_CHANGE) {
-               BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE));
-               if (ctrl & NAND_ALE)
-                       bank_base += JZ_NAND_MEM_ADDR_OFFSET;
-               else if (ctrl & NAND_CLE)
-                       bank_base += JZ_NAND_MEM_CMD_OFFSET;
-               chip->legacy.IO_ADDR_W = bank_base;
-
-               reg = readl(nand->base + JZ_REG_NAND_CTRL);
-               if (ctrl & NAND_NCE)
-                       reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
-               else
-                       reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
-               writel(reg, nand->base + JZ_REG_NAND_CTRL);
-       }
-       if (dat != NAND_CMD_NONE)
-               writeb(dat, chip->legacy.IO_ADDR_W);
-}
-
-static int jz_nand_dev_ready(struct nand_chip *chip)
-{
-       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
-       return gpiod_get_value_cansleep(nand->busy_gpio);
-}
-
-static void jz_nand_hwctl(struct nand_chip *chip, int mode)
-{
-       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
-       uint32_t reg;
-
-       writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
-       reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
-
-       reg |= JZ_NAND_ECC_CTRL_RESET;
-       reg |= JZ_NAND_ECC_CTRL_ENABLE;
-       reg |= JZ_NAND_ECC_CTRL_RS;
-
-       switch (mode) {
-       case NAND_ECC_READ:
-               reg &= ~JZ_NAND_ECC_CTRL_ENCODING;
-               nand->is_reading = true;
-               break;
-       case NAND_ECC_WRITE:
-               reg |= JZ_NAND_ECC_CTRL_ENCODING;
-               nand->is_reading = false;
-               break;
-       default:
-               break;
-       }
-
-       writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
-}
-
-static int jz_nand_calculate_ecc_rs(struct nand_chip *chip, const uint8_t *dat,
-                                   uint8_t *ecc_code)
-{
-       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
-       uint32_t reg, status;
-       int i;
-       unsigned int timeout = 1000;
-       static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4,
-                                               0x8b, 0xff, 0xb7, 0x6f};
-
-       if (nand->is_reading)
-               return 0;
-
-       do {
-               status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
-       } while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout);
-
-       if (timeout == 0)
-           return -1;
-
-       reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
-       reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
-       writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
-
-       for (i = 0; i < 9; ++i)
-               ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i);
-
-       /* If the written data is completly 0xff, we also want to write 0xff as
-        * ecc, otherwise we will get in trouble when doing subpage writes. */
-       if (memcmp(ecc_code, empty_block_ecc, 9) == 0)
-               memset(ecc_code, 0xff, 9);
-
-       return 0;
-}
-
-static void jz_nand_correct_data(uint8_t *dat, int index, int mask)
-{
-       int offset = index & 0x7;
-       uint16_t data;
-
-       index += (index >> 3);
-
-       data = dat[index];
-       data |= dat[index+1] << 8;
-
-       mask ^= (data >> offset) & 0x1ff;
-       data &= ~(0x1ff << offset);
-       data |= (mask << offset);
-
-       dat[index] = data & 0xff;
-       dat[index+1] = (data >> 8) & 0xff;
-}
-
-static int jz_nand_correct_ecc_rs(struct nand_chip *chip, uint8_t *dat,
-                                 uint8_t *read_ecc, uint8_t *calc_ecc)
-{
-       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
-       int i, error_count, index;
-       uint32_t reg, status, error;
-       unsigned int timeout = 1000;
-
-       for (i = 0; i < 9; ++i)
-               writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i);
-
-       reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
-       reg |= JZ_NAND_ECC_CTRL_PAR_READY;
-       writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
-
-       do {
-               status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
-       } while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout);
-
-       if (timeout == 0)
-               return -ETIMEDOUT;
-
-       reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
-       reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
-       writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
-
-       if (status & JZ_NAND_STATUS_ERROR) {
-               if (status & JZ_NAND_STATUS_UNCOR_ERROR)
-                       return -EBADMSG;
-
-               error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
-
-               for (i = 0; i < error_count; ++i) {
-                       error = readl(nand->base + JZ_REG_NAND_ERR(i));
-                       index = ((error >> 16) & 0x1ff) - 1;
-                       if (index >= 0 && index < 512)
-                               jz_nand_correct_data(dat, index, error & 0x1ff);
-               }
-
-               return error_count;
-       }
-
-       return 0;
-}
-
-static int jz_nand_ioremap_resource(struct platform_device *pdev,
-       const char *name, struct resource **res, void __iomem **base)
-{
-       int ret;
-
-       *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
-       if (!*res) {
-               dev_err(&pdev->dev, "Failed to get platform %s memory\n", name);
-               ret = -ENXIO;
-               goto err;
-       }
-
-       *res = request_mem_region((*res)->start, resource_size(*res),
-                               pdev->name);
-       if (!*res) {
-               dev_err(&pdev->dev, "Failed to request %s memory region\n", name);
-               ret = -EBUSY;
-               goto err;
-       }
-
-       *base = ioremap((*res)->start, resource_size(*res));
-       if (!*base) {
-               dev_err(&pdev->dev, "Failed to ioremap %s memory region\n", name);
-               ret = -EBUSY;
-               goto err_release_mem;
-       }
-
-       return 0;
-
-err_release_mem:
-       release_mem_region((*res)->start, resource_size(*res));
-err:
-       *res = NULL;
-       *base = NULL;
-       return ret;
-}
-
-static inline void jz_nand_iounmap_resource(struct resource *res,
-                                           void __iomem *base)
-{
-       iounmap(base);
-       release_mem_region(res->start, resource_size(res));
-}
-
-static int jz_nand_detect_bank(struct platform_device *pdev,
-                              struct jz_nand *nand, unsigned char bank,
-                              size_t chipnr, uint8_t *nand_maf_id,
-                              uint8_t *nand_dev_id)
-{
-       int ret;
-       char res_name[6];
-       uint32_t ctrl;
-       struct nand_chip *chip = &nand->chip;
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       u8 id[2];
-
-       /* Request I/O resource. */
-       sprintf(res_name, "bank%d", bank);
-       ret = jz_nand_ioremap_resource(pdev, res_name,
-                                       &nand->bank_mem[bank - 1],
-                                       &nand->bank_base[bank - 1]);
-       if (ret)
-               return ret;
-
-       /* Enable chip in bank. */
-       ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
-       ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
-       writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
-
-       if (chipnr == 0) {
-               /* Detect first chip. */
-               ret = nand_scan(chip, 1);
-               if (ret)
-                       goto notfound_id;
-
-               /* Retrieve the IDs from the first chip. */
-               nand_select_target(chip, 0);
-               nand_reset_op(chip);
-               nand_readid_op(chip, 0, id, sizeof(id));
-               *nand_maf_id = id[0];
-               *nand_dev_id = id[1];
-       } else {
-               /* Detect additional chip. */
-               nand_select_target(chip, chipnr);
-               nand_reset_op(chip);
-               nand_readid_op(chip, 0, id, sizeof(id));
-               if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) {
-                       ret = -ENODEV;
-                       goto notfound_id;
-               }
-
-               /* Update size of the MTD. */
-               chip->numchips++;
-               mtd->size += chip->chipsize;
-       }
-
-       dev_info(&pdev->dev, "Found chip %zu on bank %i\n", chipnr, bank);
-       return 0;
-
-notfound_id:
-       dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
-       ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
-       writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
-       jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
-                                nand->bank_base[bank - 1]);
-       return ret;
-}
-
-static int jz_nand_attach_chip(struct nand_chip *chip)
-{
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct device *dev = mtd->dev.parent;
-       struct jz_nand_platform_data *pdata = dev_get_platdata(dev);
-       struct platform_device *pdev = to_platform_device(dev);
-
-       if (pdata && pdata->ident_callback)
-               pdata->ident_callback(pdev, mtd, &pdata->partitions,
-                                     &pdata->num_partitions);
-
-       return 0;
-}
-
-static const struct nand_controller_ops jz_nand_controller_ops = {
-       .attach_chip = jz_nand_attach_chip,
-};
-
-static int jz_nand_probe(struct platform_device *pdev)
-{
-       int ret;
-       struct jz_nand *nand;
-       struct nand_chip *chip;
-       struct mtd_info *mtd;
-       struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
-       size_t chipnr, bank_idx;
-       uint8_t nand_maf_id = 0, nand_dev_id = 0;
-
-       nand = kzalloc(sizeof(*nand), GFP_KERNEL);
-       if (!nand)
-               return -ENOMEM;
-
-       ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base);
-       if (ret)
-               goto err_free;
-
-       nand->busy_gpio = devm_gpiod_get_optional(&pdev->dev, "busy", GPIOD_IN);
-       if (IS_ERR(nand->busy_gpio)) {
-               ret = PTR_ERR(nand->busy_gpio);
-               dev_err(&pdev->dev, "Failed to request busy gpio %d\n",
-                   ret);
-               goto err_iounmap_mmio;
-       }
-
-       chip            = &nand->chip;
-       mtd             = nand_to_mtd(chip);
-       mtd->dev.parent = &pdev->dev;
-       mtd->name       = "jz4740-nand";
-
-       chip->ecc.hwctl         = jz_nand_hwctl;
-       chip->ecc.calculate     = jz_nand_calculate_ecc_rs;
-       chip->ecc.correct       = jz_nand_correct_ecc_rs;
-       chip->ecc.mode          = NAND_ECC_HW_OOB_FIRST;
-       chip->ecc.size          = 512;
-       chip->ecc.bytes         = 9;
-       chip->ecc.strength      = 4;
-       chip->ecc.options       = NAND_ECC_GENERIC_ERASED_CHECK;
-
-       chip->legacy.chip_delay = 50;
-       chip->legacy.cmd_ctrl = jz_nand_cmd_ctrl;
-       chip->legacy.select_chip = jz_nand_select_chip;
-       chip->legacy.dummy_controller.ops = &jz_nand_controller_ops;
-
-       if (nand->busy_gpio)
-               chip->legacy.dev_ready = jz_nand_dev_ready;
-
-       platform_set_drvdata(pdev, nand);
-
-       /* We are going to autodetect NAND chips in the banks specified in the
-        * platform data. Although nand_scan_ident() can detect multiple chips,
-        * it requires those chips to be numbered consecuitively, which is not
-        * always the case for external memory banks. And a fixed chip-to-bank
-        * mapping is not practical either, since for example Dingoo units
-        * produced at different times have NAND chips in different banks.
-        */
-       chipnr = 0;
-       for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) {
-               unsigned char bank;
-
-               /* If there is no platform data, look for NAND in bank 1,
-                * which is the most likely bank since it is the only one
-                * that can be booted from.
-                */
-               bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1;
-               if (bank == 0)
-                       break;
-               if (bank > JZ_NAND_NUM_BANKS) {
-                       dev_warn(&pdev->dev,
-                               "Skipping non-existing bank: %d\n", bank);
-                       continue;
-               }
-               /* The detection routine will directly or indirectly call
-                * jz_nand_select_chip(), so nand->banks has to contain the
-                * bank we're checking.
-                */
-               nand->banks[chipnr] = bank;
-               if (jz_nand_detect_bank(pdev, nand, bank, chipnr,
-                                       &nand_maf_id, &nand_dev_id) == 0)
-                       chipnr++;
-               else
-                       nand->banks[chipnr] = 0;
-       }
-       if (chipnr == 0) {
-               dev_err(&pdev->dev, "No NAND chips found\n");
-               goto err_iounmap_mmio;
-       }
-
-       ret = mtd_device_register(mtd, pdata ? pdata->partitions : NULL,
-                                 pdata ? pdata->num_partitions : 0);
-
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to add mtd device\n");
-               goto err_cleanup_nand;
-       }
-
-       dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
-
-       return 0;
-
-err_cleanup_nand:
-       nand_cleanup(chip);
-       while (chipnr--) {
-               unsigned char bank = nand->banks[chipnr];
-               jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
-                                        nand->bank_base[bank - 1]);
-       }
-       writel(0, nand->base + JZ_REG_NAND_CTRL);
-err_iounmap_mmio:
-       jz_nand_iounmap_resource(nand->mem, nand->base);
-err_free:
-       kfree(nand);
-       return ret;
-}
-
-static int jz_nand_remove(struct platform_device *pdev)
-{
-       struct jz_nand *nand = platform_get_drvdata(pdev);
-       size_t i;
-
-       nand_release(&nand->chip);
-
-       /* Deassert and disable all chips */
-       writel(0, nand->base + JZ_REG_NAND_CTRL);
-
-       for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) {
-               unsigned char bank = nand->banks[i];
-               if (bank != 0) {
-                       jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
-                                                nand->bank_base[bank - 1]);
-               }
-       }
-
-       jz_nand_iounmap_resource(nand->mem, nand->base);
-
-       kfree(nand);
-
-       return 0;
-}
-
-static struct platform_driver jz_nand_driver = {
-       .probe = jz_nand_probe,
-       .remove = jz_nand_remove,
-       .driver = {
-               .name = "jz4740-nand",
-       },
-};
-
-module_platform_driver(jz_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("NAND controller driver for JZ4740 SoC");
-MODULE_ALIAS("platform:jz4740-nand");
diff --git a/drivers/mtd/nand/raw/jz4780_bch.c b/drivers/mtd/nand/raw/jz4780_bch.c
deleted file mode 100644 (file)
index c5f74ed..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * JZ4780 BCH controller
- *
- * Copyright (c) 2015 Imagination Technologies
- * Author: Alex Smith <alex.smith@imgtec.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- */
-
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/iopoll.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-
-#include "jz4780_bch.h"
-
-#define BCH_BHCR                       0x0
-#define BCH_BHCCR                      0x8
-#define BCH_BHCNT                      0xc
-#define BCH_BHDR                       0x10
-#define BCH_BHPAR0                     0x14
-#define BCH_BHERR0                     0x84
-#define BCH_BHINT                      0x184
-#define BCH_BHINTES                    0x188
-#define BCH_BHINTEC                    0x18c
-#define BCH_BHINTE                     0x190
-
-#define BCH_BHCR_BSEL_SHIFT            4
-#define BCH_BHCR_BSEL_MASK             (0x7f << BCH_BHCR_BSEL_SHIFT)
-#define BCH_BHCR_ENCE                  BIT(2)
-#define BCH_BHCR_INIT                  BIT(1)
-#define BCH_BHCR_BCHE                  BIT(0)
-
-#define BCH_BHCNT_PARITYSIZE_SHIFT     16
-#define BCH_BHCNT_PARITYSIZE_MASK      (0x7f << BCH_BHCNT_PARITYSIZE_SHIFT)
-#define BCH_BHCNT_BLOCKSIZE_SHIFT      0
-#define BCH_BHCNT_BLOCKSIZE_MASK       (0x7ff << BCH_BHCNT_BLOCKSIZE_SHIFT)
-
-#define BCH_BHERR_MASK_SHIFT           16
-#define BCH_BHERR_MASK_MASK            (0xffff << BCH_BHERR_MASK_SHIFT)
-#define BCH_BHERR_INDEX_SHIFT          0
-#define BCH_BHERR_INDEX_MASK           (0x7ff << BCH_BHERR_INDEX_SHIFT)
-
-#define BCH_BHINT_ERRC_SHIFT           24
-#define BCH_BHINT_ERRC_MASK            (0x7f << BCH_BHINT_ERRC_SHIFT)
-#define BCH_BHINT_TERRC_SHIFT          16
-#define BCH_BHINT_TERRC_MASK           (0x7f << BCH_BHINT_TERRC_SHIFT)
-#define BCH_BHINT_DECF                 BIT(3)
-#define BCH_BHINT_ENCF                 BIT(2)
-#define BCH_BHINT_UNCOR                        BIT(1)
-#define BCH_BHINT_ERR                  BIT(0)
-
-#define BCH_CLK_RATE                   (200 * 1000 * 1000)
-
-/* Timeout for BCH calculation/correction. */
-#define BCH_TIMEOUT_US                 100000
-
-struct jz4780_bch {
-       struct device *dev;
-       void __iomem *base;
-       struct clk *clk;
-       struct mutex lock;
-};
-
-static void jz4780_bch_init(struct jz4780_bch *bch,
-                           struct jz4780_bch_params *params, bool encode)
-{
-       u32 reg;
-
-       /* Clear interrupt status. */
-       writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
-
-       /* Set up BCH count register. */
-       reg = params->size << BCH_BHCNT_BLOCKSIZE_SHIFT;
-       reg |= params->bytes << BCH_BHCNT_PARITYSIZE_SHIFT;
-       writel(reg, bch->base + BCH_BHCNT);
-
-       /* Initialise and enable BCH. */
-       reg = BCH_BHCR_BCHE | BCH_BHCR_INIT;
-       reg |= params->strength << BCH_BHCR_BSEL_SHIFT;
-       if (encode)
-               reg |= BCH_BHCR_ENCE;
-       writel(reg, bch->base + BCH_BHCR);
-}
-
-static void jz4780_bch_disable(struct jz4780_bch *bch)
-{
-       writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
-       writel(BCH_BHCR_BCHE, bch->base + BCH_BHCCR);
-}
-
-static void jz4780_bch_write_data(struct jz4780_bch *bch, const void *buf,
-                                 size_t size)
-{
-       size_t size32 = size / sizeof(u32);
-       size_t size8 = size % sizeof(u32);
-       const u32 *src32;
-       const u8 *src8;
-
-       src32 = (const u32 *)buf;
-       while (size32--)
-               writel(*src32++, bch->base + BCH_BHDR);
-
-       src8 = (const u8 *)src32;
-       while (size8--)
-               writeb(*src8++, bch->base + BCH_BHDR);
-}
-
-static void jz4780_bch_read_parity(struct jz4780_bch *bch, void *buf,
-                                  size_t size)
-{
-       size_t size32 = size / sizeof(u32);
-       size_t size8 = size % sizeof(u32);
-       u32 *dest32;
-       u8 *dest8;
-       u32 val, offset = 0;
-
-       dest32 = (u32 *)buf;
-       while (size32--) {
-               *dest32++ = readl(bch->base + BCH_BHPAR0 + offset);
-               offset += sizeof(u32);
-       }
-
-       dest8 = (u8 *)dest32;
-       val = readl(bch->base + BCH_BHPAR0 + offset);
-       switch (size8) {
-       case 3:
-               dest8[2] = (val >> 16) & 0xff;
-               /* fall through */
-       case 2:
-               dest8[1] = (val >> 8) & 0xff;
-               /* fall through */
-       case 1:
-               dest8[0] = val & 0xff;
-               break;
-       }
-}
-
-static bool jz4780_bch_wait_complete(struct jz4780_bch *bch, unsigned int irq,
-                                    u32 *status)
-{
-       u32 reg;
-       int ret;
-
-       /*
-        * While we could use interrupts here and sleep until the operation
-        * completes, the controller works fairly quickly (usually a few
-        * microseconds) and so the overhead of sleeping until we get an
-        * interrupt quite noticeably decreases performance.
-        */
-       ret = readl_poll_timeout(bch->base + BCH_BHINT, reg,
-                                (reg & irq) == irq, 0, BCH_TIMEOUT_US);
-       if (ret)
-               return false;
-
-       if (status)
-               *status = reg;
-
-       writel(reg, bch->base + BCH_BHINT);
-       return true;
-}
-
-/**
- * jz4780_bch_calculate() - calculate ECC for a data buffer
- * @bch: BCH device.
- * @params: BCH parameters.
- * @buf: input buffer with raw data.
- * @ecc_code: output buffer with ECC.
- *
- * Return: 0 on success, -ETIMEDOUT if timed out while waiting for BCH
- * controller.
- */
-int jz4780_bch_calculate(struct jz4780_bch *bch, struct jz4780_bch_params *params,
-                        const u8 *buf, u8 *ecc_code)
-{
-       int ret = 0;
-
-       mutex_lock(&bch->lock);
-       jz4780_bch_init(bch, params, true);
-       jz4780_bch_write_data(bch, buf, params->size);
-
-       if (jz4780_bch_wait_complete(bch, BCH_BHINT_ENCF, NULL)) {
-               jz4780_bch_read_parity(bch, ecc_code, params->bytes);
-       } else {
-               dev_err(bch->dev, "timed out while calculating ECC\n");
-               ret = -ETIMEDOUT;
-       }
-
-       jz4780_bch_disable(bch);
-       mutex_unlock(&bch->lock);
-       return ret;
-}
-EXPORT_SYMBOL(jz4780_bch_calculate);
-
-/**
- * jz4780_bch_correct() - detect and correct bit errors
- * @bch: BCH device.
- * @params: BCH parameters.
- * @buf: raw data read from the chip.
- * @ecc_code: ECC read from the chip.
- *
- * Given the raw data and the ECC read from the NAND device, detects and
- * corrects errors in the data.
- *
- * Return: the number of bit errors corrected, -EBADMSG if there are too many
- * errors to correct or -ETIMEDOUT if we timed out waiting for the controller.
- */
-int jz4780_bch_correct(struct jz4780_bch *bch, struct jz4780_bch_params *params,
-                      u8 *buf, u8 *ecc_code)
-{
-       u32 reg, mask, index;
-       int i, ret, count;
-
-       mutex_lock(&bch->lock);
-
-       jz4780_bch_init(bch, params, false);
-       jz4780_bch_write_data(bch, buf, params->size);
-       jz4780_bch_write_data(bch, ecc_code, params->bytes);
-
-       if (!jz4780_bch_wait_complete(bch, BCH_BHINT_DECF, &reg)) {
-               dev_err(bch->dev, "timed out while correcting data\n");
-               ret = -ETIMEDOUT;
-               goto out;
-       }
-
-       if (reg & BCH_BHINT_UNCOR) {
-               dev_warn(bch->dev, "uncorrectable ECC error\n");
-               ret = -EBADMSG;
-               goto out;
-       }
-
-       /* Correct any detected errors. */
-       if (reg & BCH_BHINT_ERR) {
-               count = (reg & BCH_BHINT_ERRC_MASK) >> BCH_BHINT_ERRC_SHIFT;
-               ret = (reg & BCH_BHINT_TERRC_MASK) >> BCH_BHINT_TERRC_SHIFT;
-
-               for (i = 0; i < count; i++) {
-                       reg = readl(bch->base + BCH_BHERR0 + (i * 4));
-                       mask = (reg & BCH_BHERR_MASK_MASK) >>
-                                               BCH_BHERR_MASK_SHIFT;
-                       index = (reg & BCH_BHERR_INDEX_MASK) >>
-                                               BCH_BHERR_INDEX_SHIFT;
-                       buf[(index * 2) + 0] ^= mask;
-                       buf[(index * 2) + 1] ^= mask >> 8;
-               }
-       } else {
-               ret = 0;
-       }
-
-out:
-       jz4780_bch_disable(bch);
-       mutex_unlock(&bch->lock);
-       return ret;
-}
-EXPORT_SYMBOL(jz4780_bch_correct);
-
-/**
- * jz4780_bch_get() - get the BCH controller device
- * @np: BCH device tree node.
- *
- * Gets the BCH controller device from the specified device tree node. The
- * device must be released with jz4780_bch_release() when it is no longer being
- * used.
- *
- * Return: a pointer to jz4780_bch, errors are encoded into the pointer.
- * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
- */
-static struct jz4780_bch *jz4780_bch_get(struct device_node *np)
-{
-       struct platform_device *pdev;
-       struct jz4780_bch *bch;
-
-       pdev = of_find_device_by_node(np);
-       if (!pdev)
-               return ERR_PTR(-EPROBE_DEFER);
-
-       bch = platform_get_drvdata(pdev);
-       if (!bch) {
-               put_device(&pdev->dev);
-               return ERR_PTR(-EPROBE_DEFER);
-       }
-
-       clk_prepare_enable(bch->clk);
-
-       return bch;
-}
-
-/**
- * of_jz4780_bch_get() - get the BCH controller from a DT node
- * @of_node: the node that contains a bch-controller property.
- *
- * Get the bch-controller property from the given device tree
- * node and pass it to jz4780_bch_get to do the work.
- *
- * Return: a pointer to jz4780_bch, errors are encoded into the pointer.
- * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
- */
-struct jz4780_bch *of_jz4780_bch_get(struct device_node *of_node)
-{
-       struct jz4780_bch *bch = NULL;
-       struct device_node *np;
-
-       np = of_parse_phandle(of_node, "ingenic,bch-controller", 0);
-
-       if (np) {
-               bch = jz4780_bch_get(np);
-               of_node_put(np);
-       }
-       return bch;
-}
-EXPORT_SYMBOL(of_jz4780_bch_get);
-
-/**
- * jz4780_bch_release() - release the BCH controller device
- * @bch: BCH device.
- */
-void jz4780_bch_release(struct jz4780_bch *bch)
-{
-       clk_disable_unprepare(bch->clk);
-       put_device(bch->dev);
-}
-EXPORT_SYMBOL(jz4780_bch_release);
-
-static int jz4780_bch_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct jz4780_bch *bch;
-       struct resource *res;
-
-       bch = devm_kzalloc(dev, sizeof(*bch), GFP_KERNEL);
-       if (!bch)
-               return -ENOMEM;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       bch->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(bch->base))
-               return PTR_ERR(bch->base);
-
-       jz4780_bch_disable(bch);
-
-       bch->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(bch->clk)) {
-               dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(bch->clk));
-               return PTR_ERR(bch->clk);
-       }
-
-       clk_set_rate(bch->clk, BCH_CLK_RATE);
-
-       mutex_init(&bch->lock);
-
-       bch->dev = dev;
-       platform_set_drvdata(pdev, bch);
-
-       return 0;
-}
-
-static const struct of_device_id jz4780_bch_dt_match[] = {
-       { .compatible = "ingenic,jz4780-bch" },
-       {},
-};
-MODULE_DEVICE_TABLE(of, jz4780_bch_dt_match);
-
-static struct platform_driver jz4780_bch_driver = {
-       .probe          = jz4780_bch_probe,
-       .driver = {
-               .name   = "jz4780-bch",
-               .of_match_table = of_match_ptr(jz4780_bch_dt_match),
-       },
-};
-module_platform_driver(jz4780_bch_driver);
-
-MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
-MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
-MODULE_DESCRIPTION("Ingenic JZ4780 BCH error correction driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/raw/jz4780_bch.h b/drivers/mtd/nand/raw/jz4780_bch.h
deleted file mode 100644 (file)
index bf47180..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * JZ4780 BCH controller
- *
- * Copyright (c) 2015 Imagination Technologies
- * Author: Alex Smith <alex.smith@imgtec.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- */
-
-#ifndef __DRIVERS_MTD_NAND_JZ4780_BCH_H__
-#define __DRIVERS_MTD_NAND_JZ4780_BCH_H__
-
-#include <linux/types.h>
-
-struct device;
-struct device_node;
-struct jz4780_bch;
-
-/**
- * struct jz4780_bch_params - BCH parameters
- * @size: data bytes per ECC step.
- * @bytes: ECC bytes per step.
- * @strength: number of correctable bits per ECC step.
- */
-struct jz4780_bch_params {
-       int size;
-       int bytes;
-       int strength;
-};
-
-int jz4780_bch_calculate(struct jz4780_bch *bch,
-                               struct jz4780_bch_params *params,
-                               const u8 *buf, u8 *ecc_code);
-int jz4780_bch_correct(struct jz4780_bch *bch,
-                             struct jz4780_bch_params *params, u8 *buf,
-                             u8 *ecc_code);
-
-void jz4780_bch_release(struct jz4780_bch *bch);
-struct jz4780_bch *of_jz4780_bch_get(struct device_node *np);
-
-#endif /* __DRIVERS_MTD_NAND_JZ4780_BCH_H__ */
diff --git a/drivers/mtd/nand/raw/jz4780_nand.c b/drivers/mtd/nand/raw/jz4780_nand.c
deleted file mode 100644 (file)
index 22e5897..0000000
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * JZ4780 NAND driver
- *
- * Copyright (c) 2015 Imagination Technologies
- * Author: Alex Smith <alex.smith@imgtec.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- */
-
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/gpio/consumer.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-
-#include <linux/jz4780-nemc.h>
-
-#include "jz4780_bch.h"
-
-#define DRV_NAME       "jz4780-nand"
-
-#define OFFSET_DATA    0x00000000
-#define OFFSET_CMD     0x00400000
-#define OFFSET_ADDR    0x00800000
-
-/* Command delay when there is no R/B pin. */
-#define RB_DELAY_US    100
-
-struct jz4780_nand_cs {
-       unsigned int bank;
-       void __iomem *base;
-};
-
-struct jz4780_nand_controller {
-       struct device *dev;
-       struct jz4780_bch *bch;
-       struct nand_controller controller;
-       unsigned int num_banks;
-       struct list_head chips;
-       int selected;
-       struct jz4780_nand_cs cs[];
-};
-
-struct jz4780_nand_chip {
-       struct nand_chip chip;
-       struct list_head chip_list;
-
-       struct gpio_desc *busy_gpio;
-       struct gpio_desc *wp_gpio;
-       unsigned int reading: 1;
-};
-
-static inline struct jz4780_nand_chip *to_jz4780_nand_chip(struct mtd_info *mtd)
-{
-       return container_of(mtd_to_nand(mtd), struct jz4780_nand_chip, chip);
-}
-
-static inline struct jz4780_nand_controller
-*to_jz4780_nand_controller(struct nand_controller *ctrl)
-{
-       return container_of(ctrl, struct jz4780_nand_controller, controller);
-}
-
-static void jz4780_nand_select_chip(struct nand_chip *chip, int chipnr)
-{
-       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
-       struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
-       struct jz4780_nand_cs *cs;
-
-       /* Ensure the currently selected chip is deasserted. */
-       if (chipnr == -1 && nfc->selected >= 0) {
-               cs = &nfc->cs[nfc->selected];
-               jz4780_nemc_assert(nfc->dev, cs->bank, false);
-       }
-
-       nfc->selected = chipnr;
-}
-
-static void jz4780_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
-                                unsigned int ctrl)
-{
-       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
-       struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
-       struct jz4780_nand_cs *cs;
-
-       if (WARN_ON(nfc->selected < 0))
-               return;
-
-       cs = &nfc->cs[nfc->selected];
-
-       jz4780_nemc_assert(nfc->dev, cs->bank, ctrl & NAND_NCE);
-
-       if (cmd == NAND_CMD_NONE)
-               return;
-
-       if (ctrl & NAND_ALE)
-               writeb(cmd, cs->base + OFFSET_ADDR);
-       else if (ctrl & NAND_CLE)
-               writeb(cmd, cs->base + OFFSET_CMD);
-}
-
-static int jz4780_nand_dev_ready(struct nand_chip *chip)
-{
-       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
-
-       return !gpiod_get_value_cansleep(nand->busy_gpio);
-}
-
-static void jz4780_nand_ecc_hwctl(struct nand_chip *chip, int mode)
-{
-       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
-
-       nand->reading = (mode == NAND_ECC_READ);
-}
-
-static int jz4780_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat,
-                                    u8 *ecc_code)
-{
-       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
-       struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
-       struct jz4780_bch_params params;
-
-       /*
-        * Don't need to generate the ECC when reading, BCH does it for us as
-        * part of decoding/correction.
-        */
-       if (nand->reading)
-               return 0;
-
-       params.size = nand->chip.ecc.size;
-       params.bytes = nand->chip.ecc.bytes;
-       params.strength = nand->chip.ecc.strength;
-
-       return jz4780_bch_calculate(nfc->bch, &params, dat, ecc_code);
-}
-
-static int jz4780_nand_ecc_correct(struct nand_chip *chip, u8 *dat,
-                                  u8 *read_ecc, u8 *calc_ecc)
-{
-       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
-       struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
-       struct jz4780_bch_params params;
-
-       params.size = nand->chip.ecc.size;
-       params.bytes = nand->chip.ecc.bytes;
-       params.strength = nand->chip.ecc.strength;
-
-       return jz4780_bch_correct(nfc->bch, &params, dat, read_ecc);
-}
-
-static int jz4780_nand_attach_chip(struct nand_chip *chip)
-{
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller);
-       int eccbytes;
-
-       chip->ecc.bytes = fls((1 + 8) * chip->ecc.size) *
-                               (chip->ecc.strength / 8);
-
-       switch (chip->ecc.mode) {
-       case NAND_ECC_HW:
-               if (!nfc->bch) {
-                       dev_err(nfc->dev,
-                               "HW BCH selected, but BCH controller not found\n");
-                       return -ENODEV;
-               }
-
-               chip->ecc.hwctl = jz4780_nand_ecc_hwctl;
-               chip->ecc.calculate = jz4780_nand_ecc_calculate;
-               chip->ecc.correct = jz4780_nand_ecc_correct;
-               /* fall through */
-       case NAND_ECC_SOFT:
-               dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n",
-                        (nfc->bch) ? "hardware BCH" : "software ECC",
-                        chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
-               break;
-       case NAND_ECC_NONE:
-               dev_info(nfc->dev, "not using ECC\n");
-               break;
-       default:
-               dev_err(nfc->dev, "ECC mode %d not supported\n",
-                       chip->ecc.mode);
-               return -EINVAL;
-       }
-
-       /* The NAND core will generate the ECC layout for SW ECC */
-       if (chip->ecc.mode != NAND_ECC_HW)
-               return 0;
-
-       /* Generate ECC layout. ECC codes are right aligned in the OOB area. */
-       eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
-
-       if (eccbytes > mtd->oobsize - 2) {
-               dev_err(nfc->dev,
-                       "invalid ECC config: required %d ECC bytes, but only %d are available",
-                       eccbytes, mtd->oobsize - 2);
-               return -EINVAL;
-       }
-
-       mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
-
-       return 0;
-}
-
-static const struct nand_controller_ops jz4780_nand_controller_ops = {
-       .attach_chip = jz4780_nand_attach_chip,
-};
-
-static int jz4780_nand_init_chip(struct platform_device *pdev,
-                               struct jz4780_nand_controller *nfc,
-                               struct device_node *np,
-                               unsigned int chipnr)
-{
-       struct device *dev = &pdev->dev;
-       struct jz4780_nand_chip *nand;
-       struct jz4780_nand_cs *cs;
-       struct resource *res;
-       struct nand_chip *chip;
-       struct mtd_info *mtd;
-       const __be32 *reg;
-       int ret = 0;
-
-       cs = &nfc->cs[chipnr];
-
-       reg = of_get_property(np, "reg", NULL);
-       if (!reg)
-               return -EINVAL;
-
-       cs->bank = be32_to_cpu(*reg);
-
-       jz4780_nemc_set_type(nfc->dev, cs->bank, JZ4780_NEMC_BANK_NAND);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, chipnr);
-       cs->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(cs->base))
-               return PTR_ERR(cs->base);
-
-       nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL);
-       if (!nand)
-               return -ENOMEM;
-
-       nand->busy_gpio = devm_gpiod_get_optional(dev, "rb", GPIOD_IN);
-
-       if (IS_ERR(nand->busy_gpio)) {
-               ret = PTR_ERR(nand->busy_gpio);
-               dev_err(dev, "failed to request busy GPIO: %d\n", ret);
-               return ret;
-       } else if (nand->busy_gpio) {
-               nand->chip.legacy.dev_ready = jz4780_nand_dev_ready;
-       }
-
-       nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW);
-
-       if (IS_ERR(nand->wp_gpio)) {
-               ret = PTR_ERR(nand->wp_gpio);
-               dev_err(dev, "failed to request WP GPIO: %d\n", ret);
-               return ret;
-       }
-
-       chip = &nand->chip;
-       mtd = nand_to_mtd(chip);
-       mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev),
-                                  cs->bank);
-       if (!mtd->name)
-               return -ENOMEM;
-       mtd->dev.parent = dev;
-
-       chip->legacy.IO_ADDR_R = cs->base + OFFSET_DATA;
-       chip->legacy.IO_ADDR_W = cs->base + OFFSET_DATA;
-       chip->legacy.chip_delay = RB_DELAY_US;
-       chip->options = NAND_NO_SUBPAGE_WRITE;
-       chip->legacy.select_chip = jz4780_nand_select_chip;
-       chip->legacy.cmd_ctrl = jz4780_nand_cmd_ctrl;
-       chip->ecc.mode = NAND_ECC_HW;
-       chip->controller = &nfc->controller;
-       nand_set_flash_node(chip, np);
-
-       chip->controller->ops = &jz4780_nand_controller_ops;
-       ret = nand_scan(chip, 1);
-       if (ret)
-               return ret;
-
-       ret = mtd_device_register(mtd, NULL, 0);
-       if (ret) {
-               nand_release(chip);
-               return ret;
-       }
-
-       list_add_tail(&nand->chip_list, &nfc->chips);
-
-       return 0;
-}
-
-static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc)
-{
-       struct jz4780_nand_chip *chip;
-
-       while (!list_empty(&nfc->chips)) {
-               chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list);
-               nand_release(&chip->chip);
-               list_del(&chip->chip_list);
-       }
-}
-
-static int jz4780_nand_init_chips(struct jz4780_nand_controller *nfc,
-                                 struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct device_node *np;
-       int i = 0;
-       int ret;
-       int num_chips = of_get_child_count(dev->of_node);
-
-       if (num_chips > nfc->num_banks) {
-               dev_err(dev, "found %d chips but only %d banks\n", num_chips, nfc->num_banks);
-               return -EINVAL;
-       }
-
-       for_each_child_of_node(dev->of_node, np) {
-               ret = jz4780_nand_init_chip(pdev, nfc, np, i);
-               if (ret) {
-                       jz4780_nand_cleanup_chips(nfc);
-                       return ret;
-               }
-
-               i++;
-       }
-
-       return 0;
-}
-
-static int jz4780_nand_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       unsigned int num_banks;
-       struct jz4780_nand_controller *nfc;
-       int ret;
-
-       num_banks = jz4780_nemc_num_banks(dev);
-       if (num_banks == 0) {
-               dev_err(dev, "no banks found\n");
-               return -ENODEV;
-       }
-
-       nfc = devm_kzalloc(dev, struct_size(nfc, cs, num_banks), GFP_KERNEL);
-       if (!nfc)
-               return -ENOMEM;
-
-       /*
-        * Check for BCH HW before we call nand_scan_ident, to prevent us from
-        * having to call it again if the BCH driver returns -EPROBE_DEFER.
-        */
-       nfc->bch = of_jz4780_bch_get(dev->of_node);
-       if (IS_ERR(nfc->bch))
-               return PTR_ERR(nfc->bch);
-
-       nfc->dev = dev;
-       nfc->num_banks = num_banks;
-
-       nand_controller_init(&nfc->controller);
-       INIT_LIST_HEAD(&nfc->chips);
-
-       ret = jz4780_nand_init_chips(nfc, pdev);
-       if (ret) {
-               if (nfc->bch)
-                       jz4780_bch_release(nfc->bch);
-               return ret;
-       }
-
-       platform_set_drvdata(pdev, nfc);
-       return 0;
-}
-
-static int jz4780_nand_remove(struct platform_device *pdev)
-{
-       struct jz4780_nand_controller *nfc = platform_get_drvdata(pdev);
-
-       if (nfc->bch)
-               jz4780_bch_release(nfc->bch);
-
-       jz4780_nand_cleanup_chips(nfc);
-
-       return 0;
-}
-
-static const struct of_device_id jz4780_nand_dt_match[] = {
-       { .compatible = "ingenic,jz4780-nand" },
-       {},
-};
-MODULE_DEVICE_TABLE(of, jz4780_nand_dt_match);
-
-static struct platform_driver jz4780_nand_driver = {
-       .probe          = jz4780_nand_probe,
-       .remove         = jz4780_nand_remove,
-       .driver = {
-               .name   = DRV_NAME,
-               .of_match_table = of_match_ptr(jz4780_nand_dt_match),
-       },
-};
-module_platform_driver(jz4780_nand_driver);
-
-MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
-MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
-MODULE_DESCRIPTION("Ingenic JZ4780 NAND driver");
-MODULE_LICENSE("GPL v2");
index d984538980e28defc021c597029f6add135dad13..fc49e13d81ecc645a4e9c95764846cfa32e8bdd8 100644 (file)
@@ -1083,12 +1083,11 @@ static int marvell_nfc_hw_ecc_hmg_read_page(struct nand_chip *chip, u8 *buf,
  */
 static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct nand_chip *chip, int page)
 {
-       /* Invalidate page cache */
-       chip->pagebuf = -1;
+       u8 *buf = nand_get_data_buf(chip);
 
        marvell_nfc_select_target(chip, chip->cur_cs);
-       return marvell_nfc_hw_ecc_hmg_do_read_page(chip, chip->data_buf,
-                                                  chip->oob_poi, true, page);
+       return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi,
+                                                  true, page);
 }
 
 /* Hamming write helpers */
@@ -1179,15 +1178,13 @@ static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct nand_chip *chip,
                                                int page)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       u8 *buf = nand_get_data_buf(chip);
 
-       /* Invalidate page cache */
-       chip->pagebuf = -1;
-
-       memset(chip->data_buf, 0xFF, mtd->writesize);
+       memset(buf, 0xFF, mtd->writesize);
 
        marvell_nfc_select_target(chip, chip->cur_cs);
-       return marvell_nfc_hw_ecc_hmg_do_write_page(chip, chip->data_buf,
-                                                   chip->oob_poi, true, page);
+       return marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, chip->oob_poi,
+                                                   true, page);
 }
 
 /* BCH read helpers */
@@ -1434,18 +1431,16 @@ static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip,
 
 static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct nand_chip *chip, int page)
 {
-       /* Invalidate page cache */
-       chip->pagebuf = -1;
+       u8 *buf = nand_get_data_buf(chip);
 
-       return chip->ecc.read_page_raw(chip, chip->data_buf, true, page);
+       return chip->ecc.read_page_raw(chip, buf, true, page);
 }
 
 static int marvell_nfc_hw_ecc_bch_read_oob(struct nand_chip *chip, int page)
 {
-       /* Invalidate page cache */
-       chip->pagebuf = -1;
+       u8 *buf = nand_get_data_buf(chip);
 
-       return chip->ecc.read_page(chip, chip->data_buf, true, page);
+       return chip->ecc.read_page(chip, buf, true, page);
 }
 
 /* BCH write helpers */
@@ -1619,25 +1614,21 @@ static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct nand_chip *chip,
                                                int page)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       u8 *buf = nand_get_data_buf(chip);
 
-       /* Invalidate page cache */
-       chip->pagebuf = -1;
-
-       memset(chip->data_buf, 0xFF, mtd->writesize);
+       memset(buf, 0xFF, mtd->writesize);
 
-       return chip->ecc.write_page_raw(chip, chip->data_buf, true, page);
+       return chip->ecc.write_page_raw(chip, buf, true, page);
 }
 
 static int marvell_nfc_hw_ecc_bch_write_oob(struct nand_chip *chip, int page)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       u8 *buf = nand_get_data_buf(chip);
 
-       /* Invalidate page cache */
-       chip->pagebuf = -1;
-
-       memset(chip->data_buf, 0xFF, mtd->writesize);
+       memset(buf, 0xFF, mtd->writesize);
 
-       return chip->ecc.write_page(chip, chip->data_buf, true, page);
+       return chip->ecc.write_page(chip, buf, true, page);
 }
 
 /* NAND framework ->exec_op() hooks and related helpers */
@@ -2257,9 +2248,9 @@ static int marvell_nand_ecc_init(struct mtd_info *mtd,
        int ret;
 
        if (ecc->mode != NAND_ECC_NONE && (!ecc->size || !ecc->strength)) {
-               if (chip->ecc_step_ds && chip->ecc_strength_ds) {
-                       ecc->size = chip->ecc_step_ds;
-                       ecc->strength = chip->ecc_strength_ds;
+               if (chip->base.eccreq.step_size && chip->base.eccreq.strength) {
+                       ecc->size = chip->base.eccreq.step_size;
+                       ecc->strength = chip->base.eccreq.strength;
                } else {
                        dev_info(nfc->dev,
                                 "No minimum ECC strength, using 1b/512B\n");
@@ -2989,7 +2980,7 @@ static int __maybe_unused marvell_nfc_resume(struct device *dev)
 
        /*
         * Reset nfc->selected_chip so the next command will cause the timing
-        * registers to be restored in marvell_nfc_select_chip().
+        * registers to be restored in marvell_nfc_select_target().
         */
        nfc->selected_chip = NULL;
 
index 3e8aa71407b53ca1e1f6d40e2eda5cee1d595eee..ea57ddcec41ea0fe2c8367f4e07ff1d3cc4027d4 100644 (file)
@@ -400,7 +400,7 @@ static int meson_nfc_queue_rb(struct meson_nfc *nfc, int timeout_ms)
        cfg |= NFC_RB_IRQ_EN;
        writel(cfg, nfc->reg_base + NFC_REG_CFG);
 
-       init_completion(&nfc->completion);
+       reinit_completion(&nfc->completion);
 
        /* use the max erase time as the maximum clock for waiting R/B */
        cmd = NFC_CMD_RB | NFC_CMD_RB_INT
@@ -470,15 +470,15 @@ static int meson_nfc_ecc_correct(struct nand_chip *nand, u32 *bitflips,
        return ret;
 }
 
-static int meson_nfc_dma_buffer_setup(struct nand_chip *nand, u8 *databuf,
-                                     int datalen, u8 *infobuf, int infolen,
+static int meson_nfc_dma_buffer_setup(struct nand_chip *nand, void *databuf,
+                                     int datalen, void *infobuf, int infolen,
                                      enum dma_data_direction dir)
 {
        struct meson_nfc *nfc = nand_get_controller_data(nand);
        u32 cmd;
        int ret = 0;
 
-       nfc->daddr = dma_map_single(nfc->dev, (void *)databuf, datalen, dir);
+       nfc->daddr = dma_map_single(nfc->dev, databuf, datalen, dir);
        ret = dma_mapping_error(nfc->dev, nfc->daddr);
        if (ret) {
                dev_err(nfc->dev, "DMA mapping error\n");
@@ -528,10 +528,13 @@ static int meson_nfc_read_buf(struct nand_chip *nand, u8 *buf, int len)
        u8 *info;
 
        info = kzalloc(PER_INFO_BYTE, GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
        ret = meson_nfc_dma_buffer_setup(nand, buf, len, info,
                                         PER_INFO_BYTE, DMA_FROM_DEVICE);
        if (ret)
-               return ret;
+               goto out;
 
        cmd = NFC_CMD_N2M | (len & GENMASK(5, 0));
        writel(cmd, nfc->reg_base + NFC_REG_CMD);
@@ -539,6 +542,8 @@ static int meson_nfc_read_buf(struct nand_chip *nand, u8 *buf, int len)
        meson_nfc_drain_cmd(nfc);
        meson_nfc_wait_cmd_finish(nfc, 1000);
        meson_nfc_dma_buffer_release(nand, len, PER_INFO_BYTE, DMA_FROM_DEVICE);
+
+out:
        kfree(info);
 
        return ret;
@@ -640,7 +645,7 @@ static int meson_nfc_write_page_sub(struct nand_chip *nand,
                return ret;
 
        ret = meson_nfc_dma_buffer_setup(nand, meson_chip->data_buf,
-                                        data_len, (u8 *)meson_chip->info_buf,
+                                        data_len, meson_chip->info_buf,
                                         info_len, DMA_TO_DEVICE);
        if (ret)
                return ret;
@@ -724,7 +729,7 @@ static int meson_nfc_read_page_sub(struct nand_chip *nand,
                return ret;
 
        ret = meson_nfc_dma_buffer_setup(nand, meson_chip->data_buf,
-                                        data_len, (u8 *)meson_chip->info_buf,
+                                        data_len, meson_chip->info_buf,
                                         info_len, DMA_FROM_DEVICE);
        if (ret)
                return ret;
@@ -1183,6 +1188,8 @@ static int meson_nand_attach_chip(struct nand_chip *nand)
                return -EINVAL;
        }
 
+       mtd_set_ooblayout(mtd, &meson_ooblayout_ops);
+
        ret = meson_nand_bch_mode(nand);
        if (ret)
                return -EINVAL;
@@ -1226,17 +1233,13 @@ meson_nfc_nand_chip_init(struct device *dev,
        int ret, i;
        u32 tmp, nsels;
 
-       if (!of_get_property(np, "reg", &nsels))
-               return -EINVAL;
-
-       nsels /= sizeof(u32);
+       nsels = of_property_count_elems_of_size(np, "reg", sizeof(u32));
        if (!nsels || nsels > MAX_CE_NUM) {
                dev_err(dev, "invalid register property size\n");
                return -EINVAL;
        }
 
-       meson_chip = devm_kzalloc(dev,
-                                 sizeof(*meson_chip) + (nsels * sizeof(u8)),
+       meson_chip = devm_kzalloc(dev, struct_size(meson_chip, sels, nsels),
                                  GFP_KERNEL);
        if (!meson_chip)
                return -ENOMEM;
@@ -1377,6 +1380,7 @@ static int meson_nfc_probe(struct platform_device *pdev)
 
        nand_controller_init(&nfc->controller);
        INIT_LIST_HEAD(&nfc->chips);
+       init_completion(&nfc->completion);
 
        nfc->dev = dev;
 
index 2c0e091877738d2bb49ab4c483bcc848261821c7..b17619f30b1b5d85d29026b87d07ca88e7406e4a 100644 (file)
@@ -1197,8 +1197,8 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
        /* if optional dt settings not present */
        if (!nand->ecc.size || !nand->ecc.strength) {
                /* use datasheet requirements */
-               nand->ecc.strength = nand->ecc_strength_ds;
-               nand->ecc.size = nand->ecc_step_ds;
+               nand->ecc.strength = nand->base.eccreq.strength;
+               nand->ecc.size = nand->base.eccreq.step_size;
 
                /*
                 * align eccstrength and eccsize
index 890c5b43e03c53e3019151acba6f1d568466d92e..6217555c19a6b95da0fae8a717a5f3012645d1fe 100644 (file)
@@ -20,6 +20,9 @@
 static void amd_nand_decode_id(struct nand_chip *chip)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_memory_organization *memorg;
+
+       memorg = nanddev_get_memorg(&chip->base);
 
        nand_decode_ext_id(chip);
 
@@ -31,16 +34,24 @@ static void amd_nand_decode_id(struct nand_chip *chip)
         */
        if (chip->id.data[4] != 0x00 && chip->id.data[5] == 0x00 &&
            chip->id.data[6] == 0x00 && chip->id.data[7] == 0x00 &&
-           mtd->writesize == 512) {
-               mtd->erasesize = 128 * 1024;
-               mtd->erasesize <<= ((chip->id.data[3] & 0x03) << 1);
+           memorg->pagesize == 512) {
+               memorg->pages_per_eraseblock = 256;
+               memorg->pages_per_eraseblock <<= ((chip->id.data[3] & 0x03) << 1);
+               mtd->erasesize = memorg->pages_per_eraseblock *
+                                memorg->pagesize;
        }
 }
 
 static int amd_nand_init(struct nand_chip *chip)
 {
        if (nand_is_slc(chip))
-               chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+               /*
+                * According to the datasheet of some Cypress SLC NANDs,
+                * the bad block markers can be in the first, second or last
+                * page of a block. So let's check all three locations.
+                */
+               chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE |
+                                NAND_BBM_LASTPAGE;
 
        return 0;
 }
index ddd396e93e321055d425c2baba0cb634dae6c879..2cf71060d6f8459c7377ee2c29303efd5c23ec45 100644 (file)
@@ -240,10 +240,10 @@ static int check_offs_len(struct nand_chip *chip, loff_t ofs, uint64_t len)
 void nand_select_target(struct nand_chip *chip, unsigned int cs)
 {
        /*
-        * cs should always lie between 0 and chip->numchips, when that's not
-        * the case it's a bug and the caller should be fixed.
+        * cs should always lie between 0 and nanddev_ntargets(), when that's
+        * not the case it's a bug and the caller should be fixed.
         */
-       if (WARN_ON(cs > chip->numchips))
+       if (WARN_ON(cs > nanddev_ntargets(&chip->base)))
                return;
 
        chip->cur_cs = cs;
@@ -282,6 +282,31 @@ static void nand_release_device(struct nand_chip *chip)
        mutex_unlock(&chip->lock);
 }
 
+/**
+ * nand_bbm_get_next_page - Get the next page for bad block markers
+ * @chip: NAND chip object
+ * @page: First page to start checking for bad block marker usage
+ *
+ * Returns an integer that corresponds to the page offset within a block, for
+ * a page that is used to store bad block markers. If no more pages are
+ * available, -EINVAL is returned.
+ */
+int nand_bbm_get_next_page(struct nand_chip *chip, int page)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       int last_page = ((mtd->erasesize - mtd->writesize) >>
+                        chip->page_shift) & chip->pagemask;
+
+       if (page == 0 && chip->options & NAND_BBM_FIRSTPAGE)
+               return 0;
+       else if (page <= 1 && chip->options & NAND_BBM_SECONDPAGE)
+               return 1;
+       else if (page <= last_page && chip->options & NAND_BBM_LASTPAGE)
+               return last_page;
+
+       return -EINVAL;
+}
+
 /**
  * nand_block_bad - [DEFAULT] Read bad block marker from the chip
  * @chip: NAND chip object
@@ -291,18 +316,15 @@ static void nand_release_device(struct nand_chip *chip)
  */
 static int nand_block_bad(struct nand_chip *chip, loff_t ofs)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       int page, page_end, res;
+       int first_page, page_offset;
+       int res;
        u8 bad;
 
-       if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
-               ofs += mtd->erasesize - mtd->writesize;
-
-       page = (int)(ofs >> chip->page_shift) & chip->pagemask;
-       page_end = page + (chip->bbt_options & NAND_BBT_SCAN2NDPAGE ? 2 : 1);
+       first_page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+       page_offset = nand_bbm_get_next_page(chip, 0);
 
-       for (; page < page_end; page++) {
-               res = chip->ecc.read_oob(chip, page);
+       while (page_offset >= 0) {
+               res = chip->ecc.read_oob(chip, first_page + page_offset);
                if (res < 0)
                        return res;
 
@@ -314,6 +336,8 @@ static int nand_block_bad(struct nand_chip *chip, loff_t ofs)
                        res = hweight8(bad) < chip->badblockbits;
                if (res)
                        return res;
+
+               page_offset = nand_bbm_get_next_page(chip, page_offset + 1);
        }
 
        return 0;
@@ -459,8 +483,8 @@ static int nand_do_write_oob(struct nand_chip *chip, loff_t to,
        }
 
        /* Invalidate the page cache, if we write to the cached page */
-       if (page == chip->pagebuf)
-               chip->pagebuf = -1;
+       if (page == chip->pagecache.page)
+               chip->pagecache.page = -1;
 
        nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops);
 
@@ -493,7 +517,7 @@ static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs)
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct mtd_oob_ops ops;
        uint8_t buf[2] = { 0, 0 };
-       int ret = 0, res, i = 0;
+       int ret = 0, res, page_offset;
 
        memset(&ops, 0, sizeof(ops));
        ops.oobbuf = buf;
@@ -506,17 +530,18 @@ static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs)
        }
        ops.mode = MTD_OPS_PLACE_OOB;
 
-       /* Write to first/last page(s) if necessary */
-       if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
-               ofs += mtd->erasesize - mtd->writesize;
-       do {
-               res = nand_do_write_oob(chip, ofs, &ops);
+       page_offset = nand_bbm_get_next_page(chip, 0);
+
+       while (page_offset >= 0) {
+               res = nand_do_write_oob(chip,
+                                       ofs + (page_offset * mtd->writesize),
+                                       &ops);
+
                if (!ret)
                        ret = res;
 
-               i++;
-               ofs += mtd->writesize;
-       } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
+               page_offset = nand_bbm_get_next_page(chip, page_offset + 1);
+       }
 
        return ret;
 }
@@ -3173,7 +3198,7 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from,
                        use_bufpoi = 0;
 
                /* Is the current page in the buffer? */
-               if (realpage != chip->pagebuf || oob) {
+               if (realpage != chip->pagecache.page || oob) {
                        bufpoi = use_bufpoi ? chip->data_buf : buf;
 
                        if (use_bufpoi && aligned)
@@ -3199,7 +3224,7 @@ read_retry:
                        if (ret < 0) {
                                if (use_bufpoi)
                                        /* Invalidate page cache */
-                                       chip->pagebuf = -1;
+                                       chip->pagecache.page = -1;
                                break;
                        }
 
@@ -3208,11 +3233,11 @@ read_retry:
                                if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
                                    !(mtd->ecc_stats.failed - ecc_failures) &&
                                    (ops->mode != MTD_OPS_RAW)) {
-                                       chip->pagebuf = realpage;
-                                       chip->pagebuf_bitflips = ret;
+                                       chip->pagecache.page = realpage;
+                                       chip->pagecache.bitflips = ret;
                                } else {
                                        /* Invalidate page cache */
-                                       chip->pagebuf = -1;
+                                       chip->pagecache.page = -1;
                                }
                                memcpy(buf, chip->data_buf + col, bytes);
                        }
@@ -3252,7 +3277,7 @@ read_retry:
                        memcpy(buf, chip->data_buf + col, bytes);
                        buf += bytes;
                        max_bitflips = max_t(unsigned int, max_bitflips,
-                                            chip->pagebuf_bitflips);
+                                            chip->pagecache.bitflips);
                }
 
                readlen -= bytes;
@@ -3973,9 +3998,9 @@ static int nand_do_write_ops(struct nand_chip *chip, loff_t to,
        page = realpage & chip->pagemask;
 
        /* Invalidate the page cache, when we write to the cached page */
-       if (to <= ((loff_t)chip->pagebuf << chip->page_shift) &&
-           ((loff_t)chip->pagebuf << chip->page_shift) < (to + ops->len))
-               chip->pagebuf = -1;
+       if (to <= ((loff_t)chip->pagecache.page << chip->page_shift) &&
+           ((loff_t)chip->pagecache.page << chip->page_shift) < (to + ops->len))
+               chip->pagecache.page = -1;
 
        /* Don't allow multipage oob writes with offset */
        if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) {
@@ -4004,10 +4029,9 @@ static int nand_do_write_ops(struct nand_chip *chip, loff_t to,
                                         __func__, buf);
                        if (part_pagewr)
                                bytes = min_t(int, bytes - column, writelen);
-                       chip->pagebuf = -1;
-                       memset(chip->data_buf, 0xff, mtd->writesize);
-                       memcpy(&chip->data_buf[column], buf, bytes);
-                       wbuf = chip->data_buf;
+                       wbuf = nand_get_data_buf(chip);
+                       memset(wbuf, 0xff, mtd->writesize);
+                       memcpy(&wbuf[column], buf, bytes);
                }
 
                if (unlikely(oob)) {
@@ -4197,9 +4221,9 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
                 * Invalidate the page cache, if we erase the block which
                 * contains the current cached page.
                 */
-               if (page <= chip->pagebuf && chip->pagebuf <
+               if (page <= chip->pagecache.page && chip->pagecache.page <
                    (page + pages_per_block))
-                       chip->pagebuf = -1;
+                       chip->pagecache.page = -1;
 
                ret = nand_erase_op(chip, (page & chip->pagemask) >>
                                    (chip->phys_erase_shift - chip->page_shift));
@@ -4298,42 +4322,6 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
        return nand_block_markbad_lowlevel(mtd_to_nand(mtd), ofs);
 }
 
-/**
- * nand_max_bad_blocks - [MTD Interface] Max number of bad blocks for an mtd
- * @mtd: MTD device structure
- * @ofs: offset relative to mtd start
- * @len: length of mtd
- */
-static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       u32 part_start_block;
-       u32 part_end_block;
-       u32 part_start_die;
-       u32 part_end_die;
-
-       /*
-        * max_bb_per_die and blocks_per_die used to determine
-        * the maximum bad block count.
-        */
-       if (!chip->max_bb_per_die || !chip->blocks_per_die)
-               return -ENOTSUPP;
-
-       /* Get the start and end of the partition in erase blocks. */
-       part_start_block = mtd_div_by_eb(ofs, mtd);
-       part_end_block = mtd_div_by_eb(len, mtd) + part_start_block - 1;
-
-       /* Get the start and end LUNs of the partition. */
-       part_start_die = part_start_block / chip->blocks_per_die;
-       part_end_die = part_end_block / chip->blocks_per_die;
-
-       /*
-        * Look up the bad blocks per unit and multiply by the number of units
-        * that the partition spans.
-        */
-       return chip->max_bb_per_die * (part_end_die - part_start_die + 1);
-}
-
 /**
  * nand_suspend - [MTD Interface] Suspend the NAND flash
  * @mtd: MTD device structure
@@ -4485,21 +4473,29 @@ static int nand_get_bits_per_cell(u8 cellinfo)
  */
 void nand_decode_ext_id(struct nand_chip *chip)
 {
+       struct nand_memory_organization *memorg;
        struct mtd_info *mtd = nand_to_mtd(chip);
        int extid;
        u8 *id_data = chip->id.data;
+
+       memorg = nanddev_get_memorg(&chip->base);
+
        /* The 3rd id byte holds MLC / multichip data */
-       chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
+       memorg->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
        /* The 4th id byte is the important one */
        extid = id_data[3];
 
        /* Calc pagesize */
-       mtd->writesize = 1024 << (extid & 0x03);
+       memorg->pagesize = 1024 << (extid & 0x03);
+       mtd->writesize = memorg->pagesize;
        extid >>= 2;
        /* Calc oobsize */
-       mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
+       memorg->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
+       mtd->oobsize = memorg->oobsize;
        extid >>= 2;
        /* Calc blocksize. Blocksize is multiples of 64KiB */
+       memorg->pages_per_eraseblock = ((64 * 1024) << (extid & 0x03)) /
+                                      memorg->pagesize;
        mtd->erasesize = (64 * 1024) << (extid & 0x03);
        extid >>= 2;
        /* Get buswidth information */
@@ -4516,13 +4512,19 @@ EXPORT_SYMBOL_GPL(nand_decode_ext_id);
 static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_memory_organization *memorg;
+
+       memorg = nanddev_get_memorg(&chip->base);
 
+       memorg->pages_per_eraseblock = type->erasesize / type->pagesize;
        mtd->erasesize = type->erasesize;
-       mtd->writesize = type->pagesize;
-       mtd->oobsize = mtd->writesize / 32;
+       memorg->pagesize = type->pagesize;
+       mtd->writesize = memorg->pagesize;
+       memorg->oobsize = memorg->pagesize / 32;
+       mtd->oobsize = memorg->oobsize;
 
        /* All legacy ID NAND are small-page, SLC */
-       chip->bits_per_cell = 1;
+       memorg->bits_per_cell = 1;
 }
 
 /*
@@ -4536,9 +4538,9 @@ static void nand_decode_bbm_options(struct nand_chip *chip)
 
        /* Set the bad block position */
        if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
-               chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
+               chip->badblockpos = NAND_BBM_POS_LARGE;
        else
-               chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
+               chip->badblockpos = NAND_BBM_POS_SMALL;
 }
 
 static inline bool is_full_id_nand(struct nand_flash_dev *type)
@@ -4550,18 +4552,28 @@ static bool find_full_id_nand(struct nand_chip *chip,
                              struct nand_flash_dev *type)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_memory_organization *memorg;
        u8 *id_data = chip->id.data;
 
+       memorg = nanddev_get_memorg(&chip->base);
+
        if (!strncmp(type->id, id_data, type->id_len)) {
-               mtd->writesize = type->pagesize;
+               memorg->pagesize = type->pagesize;
+               mtd->writesize = memorg->pagesize;
+               memorg->pages_per_eraseblock = type->erasesize /
+                                              type->pagesize;
                mtd->erasesize = type->erasesize;
-               mtd->oobsize = type->oobsize;
-
-               chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
-               chip->chipsize = (uint64_t)type->chipsize << 20;
+               memorg->oobsize = type->oobsize;
+               mtd->oobsize = memorg->oobsize;
+
+               memorg->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
+               memorg->eraseblocks_per_lun =
+                       DIV_ROUND_DOWN_ULL((u64)type->chipsize << 20,
+                                          memorg->pagesize *
+                                          memorg->pages_per_eraseblock);
                chip->options |= type->options;
-               chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
-               chip->ecc_step_ds = NAND_ECC_STEP(type);
+               chip->base.eccreq.strength = NAND_ECC_STRENGTH(type);
+               chip->base.eccreq.step_size = NAND_ECC_STEP(type);
                chip->onfi_timing_mode_default =
                                        type->onfi_timing_mode_default;
 
@@ -4587,8 +4599,12 @@ static void nand_manufacturer_detect(struct nand_chip *chip)
         */
        if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
            chip->manufacturer.desc->ops->detect) {
+               struct nand_memory_organization *memorg;
+
+               memorg = nanddev_get_memorg(&chip->base);
+
                /* The 3rd id byte holds MLC / multichip data */
-               chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]);
+               memorg->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]);
                chip->manufacturer.desc->ops->detect(chip);
        } else {
                nand_decode_ext_id(chip);
@@ -4637,9 +4653,20 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
 {
        const struct nand_manufacturer *manufacturer;
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_memory_organization *memorg;
        int busw, ret;
        u8 *id_data = chip->id.data;
        u8 maf_id, dev_id;
+       u64 targetsize;
+
+       /*
+        * Let's start by initializing memorg fields that might be left
+        * unassigned by the ID-based detection logic.
+        */
+       memorg = nanddev_get_memorg(&chip->base);
+       memorg->planes_per_lun = 1;
+       memorg->luns_per_target = 1;
+       memorg->ntargets = 1;
 
        /*
         * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
@@ -4735,8 +4762,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
        if (!chip->parameters.model)
                return -ENOMEM;
 
-       chip->chipsize = (uint64_t)type->chipsize << 20;
-
        if (!type->pagesize)
                nand_manufacturer_detect(chip);
        else
@@ -4745,6 +4770,11 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
        /* Get chip options */
        chip->options |= type->options;
 
+       memorg->eraseblocks_per_lun =
+                       DIV_ROUND_DOWN_ULL((u64)type->chipsize << 20,
+                                          memorg->pagesize *
+                                          memorg->pages_per_eraseblock);
+
 ident_done:
        if (!mtd->name)
                mtd->name = chip->parameters.model;
@@ -4773,14 +4803,15 @@ ident_done:
        /* Calculate the address shift from the page size */
        chip->page_shift = ffs(mtd->writesize) - 1;
        /* Convert chipsize to number of pages per chip -1 */
-       chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
+       targetsize = nanddev_target_size(&chip->base);
+       chip->pagemask = (targetsize >> chip->page_shift) - 1;
 
        chip->bbt_erase_shift = chip->phys_erase_shift =
                ffs(mtd->erasesize) - 1;
-       if (chip->chipsize & 0xffffffff)
-               chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
+       if (targetsize & 0xffffffff)
+               chip->chip_shift = ffs((unsigned)targetsize) - 1;
        else {
-               chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32));
+               chip->chip_shift = ffs((unsigned)(targetsize >> 32));
                chip->chip_shift += 32 - 1;
        }
 
@@ -4796,7 +4827,7 @@ ident_done:
        pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
                chip->parameters.model);
        pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
-               (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
+               (int)(targetsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
                mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
        return 0;
 
@@ -4971,10 +5002,13 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
                           struct nand_flash_dev *table)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_memory_organization *memorg;
        int nand_maf_id, nand_dev_id;
        unsigned int i;
        int ret;
 
+       memorg = nanddev_get_memorg(&chip->base);
+
        /* Assume all dies are deselected when we enter nand_scan_ident(). */
        chip->cur_cs = -1;
 
@@ -4990,12 +5024,6 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
        if (!mtd->name && mtd->dev.parent)
                mtd->name = dev_name(mtd->dev.parent);
 
-       /*
-        * Start with chips->numchips = maxchips to let nand_select_target() do
-        * its job. chip->numchips will be adjusted after.
-        */
-       chip->numchips = maxchips;
-
        /* Set the default functions */
        nand_set_defaults(chip);
 
@@ -5042,8 +5070,8 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
                pr_info("%d chips detected\n", i);
 
        /* Store the number of chips and calc total size for mtd */
-       chip->numchips = i;
-       mtd->size = i * chip->chipsize;
+       memorg->ntargets = i;
+       mtd->size = i * nanddev_target_size(&chip->base);
 
        return 0;
 }
@@ -5078,13 +5106,13 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip)
                ecc->bytes = 3;
                ecc->strength = 1;
 
-               if (IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC))
+               if (IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC))
                        ecc->options |= NAND_ECC_SOFT_HAMMING_SM_ORDER;
 
                return 0;
        case NAND_ECC_BCH:
                if (!mtd_nand_has_bch()) {
-                       WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n");
+                       WARN(1, "CONFIG_MTD_NAND_ECC_SW_BCH not enabled\n");
                        return -EINVAL;
                }
                ecc->calculate = nand_bch_calculate_ecc;
@@ -5224,8 +5252,8 @@ nand_match_ecc_req(struct nand_chip *chip,
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
        const struct nand_ecc_step_info *stepinfo;
-       int req_step = chip->ecc_step_ds;
-       int req_strength = chip->ecc_strength_ds;
+       int req_step = chip->base.eccreq.step_size;
+       int req_strength = chip->base.eccreq.strength;
        int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total;
        int best_step, best_strength, best_ecc_bytes;
        int best_ecc_bytes_total = INT_MAX;
@@ -5418,7 +5446,7 @@ static bool nand_ecc_strength_good(struct nand_chip *chip)
        struct nand_ecc_ctrl *ecc = &chip->ecc;
        int corr, ds_corr;
 
-       if (ecc->size == 0 || chip->ecc_step_ds == 0)
+       if (ecc->size == 0 || chip->base.eccreq.step_size == 0)
                /* Not enough information */
                return true;
 
@@ -5427,11 +5455,56 @@ static bool nand_ecc_strength_good(struct nand_chip *chip)
         * the correction density.
         */
        corr = (mtd->writesize * ecc->strength) / ecc->size;
-       ds_corr = (mtd->writesize * chip->ecc_strength_ds) / chip->ecc_step_ds;
+       ds_corr = (mtd->writesize * chip->base.eccreq.strength) /
+                 chip->base.eccreq.step_size;
 
-       return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds;
+       return corr >= ds_corr && ecc->strength >= chip->base.eccreq.strength;
 }
 
+static int rawnand_erase(struct nand_device *nand, const struct nand_pos *pos)
+{
+       struct nand_chip *chip = container_of(nand, struct nand_chip,
+                                             base);
+       unsigned int eb = nanddev_pos_to_row(nand, pos);
+       int ret;
+
+       eb >>= nand->rowconv.eraseblock_addr_shift;
+
+       nand_select_target(chip, pos->target);
+       ret = nand_erase_op(chip, eb);
+       nand_deselect_target(chip);
+
+       return ret;
+}
+
+static int rawnand_markbad(struct nand_device *nand,
+                          const struct nand_pos *pos)
+{
+       struct nand_chip *chip = container_of(nand, struct nand_chip,
+                                             base);
+
+       return nand_markbad_bbm(chip, nanddev_pos_to_offs(nand, pos));
+}
+
+static bool rawnand_isbad(struct nand_device *nand, const struct nand_pos *pos)
+{
+       struct nand_chip *chip = container_of(nand, struct nand_chip,
+                                             base);
+       int ret;
+
+       nand_select_target(chip, pos->target);
+       ret = nand_isbad_bbm(chip, nanddev_pos_to_offs(nand, pos));
+       nand_deselect_target(chip);
+
+       return ret;
+}
+
+static const struct nand_ops rawnand_ops = {
+       .erase = rawnand_erase,
+       .markbad = rawnand_markbad,
+       .isbad = rawnand_isbad,
+};
+
 /**
  * nand_scan_tail - Scan for the NAND device
  * @chip: NAND chip object
@@ -5687,7 +5760,7 @@ static int nand_scan_tail(struct nand_chip *chip)
        chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
 
        /* Invalidate the pagebuffer reference */
-       chip->pagebuf = -1;
+       chip->pagecache.page = -1;
 
        /* Large page NAND with SOFT_ECC should support subpage reads */
        switch (ecc->mode) {
@@ -5700,10 +5773,15 @@ static int nand_scan_tail(struct nand_chip *chip)
                break;
        }
 
+       ret = nanddev_init(&chip->base, &rawnand_ops, mtd->owner);
+       if (ret)
+               goto err_nand_manuf_cleanup;
+
+       /* Adjust the MTD_CAP_ flags when NAND_ROM is set. */
+       if (chip->options & NAND_ROM)
+               mtd->flags = MTD_CAP_ROM;
+
        /* Fill in remaining MTD driver data */
-       mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH;
-       mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
-                                               MTD_CAP_NANDFLASH;
        mtd->_erase = nand_erase;
        mtd->_point = NULL;
        mtd->_unpoint = NULL;
@@ -5719,8 +5797,7 @@ static int nand_scan_tail(struct nand_chip *chip)
        mtd->_block_isreserved = nand_block_isreserved;
        mtd->_block_isbad = nand_block_isbad;
        mtd->_block_markbad = nand_block_markbad;
-       mtd->_max_bad_blocks = nand_max_bad_blocks;
-       mtd->writebufsize = mtd->writesize;
+       mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks;
 
        /*
         * Initialize bitflip_threshold to its default prior scan_bbt() call.
@@ -5733,13 +5810,13 @@ static int nand_scan_tail(struct nand_chip *chip)
        /* Initialize the ->data_interface field. */
        ret = nand_init_data_interface(chip);
        if (ret)
-               goto err_nand_manuf_cleanup;
+               goto err_nanddev_cleanup;
 
        /* Enter fastest possible mode on all dies. */
-       for (i = 0; i < chip->numchips; i++) {
+       for (i = 0; i < nanddev_ntargets(&chip->base); i++) {
                ret = nand_setup_data_interface(chip, i);
                if (ret)
-                       goto err_nand_manuf_cleanup;
+                       goto err_nanddev_cleanup;
        }
 
        /* Check, if we should skip the bad block table scan */
@@ -5749,11 +5826,14 @@ static int nand_scan_tail(struct nand_chip *chip)
        /* Build bad block table */
        ret = nand_create_bbt(chip);
        if (ret)
-               goto err_nand_manuf_cleanup;
+               goto err_nanddev_cleanup;
 
        return 0;
 
 
+err_nanddev_cleanup:
+       nanddev_cleanup(&chip->base);
+
 err_nand_manuf_cleanup:
        nand_manufacturer_cleanup(chip);
 
index 19a2b563acdfe63644572434efed785b78cc7692..fd3c10216eda0bbf9ecf0f434f85bed7204df232 100644 (file)
@@ -264,18 +264,19 @@ static int read_abs_bbt(struct nand_chip *this, uint8_t *buf,
                        struct nand_bbt_descr *td, int chip)
 {
        struct mtd_info *mtd = nand_to_mtd(this);
+       u64 targetsize = nanddev_target_size(&this->base);
        int res = 0, i;
 
        if (td->options & NAND_BBT_PERCHIP) {
                int offs = 0;
-               for (i = 0; i < this->numchips; i++) {
+               for (i = 0; i < nanddev_ntargets(&this->base); i++) {
                        if (chip == -1 || chip == i)
                                res = read_bbt(this, buf, td->pages[i],
-                                       this->chipsize >> this->bbt_erase_shift,
+                                       targetsize >> this->bbt_erase_shift,
                                        td, offs);
                        if (res)
                                return res;
-                       offs += this->chipsize >> this->bbt_erase_shift;
+                       offs += targetsize >> this->bbt_erase_shift;
                }
        } else {
                res = read_bbt(this, buf, td->pages[0],
@@ -415,11 +416,12 @@ static void read_abs_bbts(struct nand_chip *this, uint8_t *buf,
 
 /* Scan a given block partially */
 static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd,
-                          loff_t offs, uint8_t *buf, int numpages)
+                          loff_t offs, uint8_t *buf)
 {
        struct mtd_info *mtd = nand_to_mtd(this);
+
        struct mtd_oob_ops ops;
-       int j, ret;
+       int ret, page_offset;
 
        ops.ooblen = mtd->oobsize;
        ops.oobbuf = buf;
@@ -427,12 +429,15 @@ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd,
        ops.datbuf = NULL;
        ops.mode = MTD_OPS_PLACE_OOB;
 
-       for (j = 0; j < numpages; j++) {
+       page_offset = nand_bbm_get_next_page(this, 0);
+
+       while (page_offset >= 0) {
                /*
                 * Read the full oob until read_oob is fixed to handle single
                 * byte reads for 16 bit buswidth.
                 */
-               ret = mtd_read_oob(mtd, offs, &ops);
+               ret = mtd_read_oob(mtd, offs + (page_offset * mtd->writesize),
+                                  &ops);
                /* Ignore ECC errors when checking for BBM */
                if (ret && !mtd_is_bitflip_or_eccerr(ret))
                        return ret;
@@ -440,8 +445,9 @@ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd,
                if (check_short_pattern(buf, bd))
                        return 1;
 
-               offs += mtd->writesize;
+               page_offset = nand_bbm_get_next_page(this, page_offset + 1);
        }
+
        return 0;
 }
 
@@ -459,43 +465,35 @@ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd,
 static int create_bbt(struct nand_chip *this, uint8_t *buf,
                      struct nand_bbt_descr *bd, int chip)
 {
+       u64 targetsize = nanddev_target_size(&this->base);
        struct mtd_info *mtd = nand_to_mtd(this);
-       int i, numblocks, numpages;
-       int startblock;
+       int i, numblocks, startblock;
        loff_t from;
 
        pr_info("Scanning device for bad blocks\n");
 
-       if (bd->options & NAND_BBT_SCAN2NDPAGE)
-               numpages = 2;
-       else
-               numpages = 1;
-
        if (chip == -1) {
                numblocks = mtd->size >> this->bbt_erase_shift;
                startblock = 0;
                from = 0;
        } else {
-               if (chip >= this->numchips) {
+               if (chip >= nanddev_ntargets(&this->base)) {
                        pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n",
-                              chip + 1, this->numchips);
+                               chip + 1, nanddev_ntargets(&this->base));
                        return -EINVAL;
                }
-               numblocks = this->chipsize >> this->bbt_erase_shift;
+               numblocks = targetsize >> this->bbt_erase_shift;
                startblock = chip * numblocks;
                numblocks += startblock;
                from = (loff_t)startblock << this->bbt_erase_shift;
        }
 
-       if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
-               from += mtd->erasesize - (mtd->writesize * numpages);
-
        for (i = startblock; i < numblocks; i++) {
                int ret;
 
                BUG_ON(bd->options & NAND_BBT_NO_OOB);
 
-               ret = scan_block_fast(this, bd, from, buf, numpages);
+               ret = scan_block_fast(this, bd, from, buf);
                if (ret < 0)
                        return ret;
 
@@ -529,6 +527,7 @@ static int create_bbt(struct nand_chip *this, uint8_t *buf,
 static int search_bbt(struct nand_chip *this, uint8_t *buf,
                      struct nand_bbt_descr *td)
 {
+       u64 targetsize = nanddev_target_size(&this->base);
        struct mtd_info *mtd = nand_to_mtd(this);
        int i, chips;
        int startblock, block, dir;
@@ -547,8 +546,8 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf,
 
        /* Do we have a bbt per chip? */
        if (td->options & NAND_BBT_PERCHIP) {
-               chips = this->numchips;
-               bbtblocks = this->chipsize >> this->bbt_erase_shift;
+               chips = nanddev_ntargets(&this->base);
+               bbtblocks = targetsize >> this->bbt_erase_shift;
                startblock &= bbtblocks - 1;
        } else {
                chips = 1;
@@ -576,7 +575,7 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf,
                                break;
                        }
                }
-               startblock += this->chipsize >> this->bbt_erase_shift;
+               startblock += targetsize >> this->bbt_erase_shift;
        }
        /* Check, if we found a bbt for each requested chip */
        for (i = 0; i < chips; i++) {
@@ -626,6 +625,7 @@ static void search_read_bbts(struct nand_chip *this, uint8_t *buf,
 static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
                         struct nand_bbt_descr *md, int chip)
 {
+       u64 targetsize = nanddev_target_size(&this->base);
        int startblock, dir, page, numblocks, i;
 
        /*
@@ -637,9 +637,9 @@ static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
                return td->pages[chip] >>
                                (this->bbt_erase_shift - this->page_shift);
 
-       numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+       numblocks = (int)(targetsize >> this->bbt_erase_shift);
        if (!(td->options & NAND_BBT_PERCHIP))
-               numblocks *= this->numchips;
+               numblocks *= nanddev_ntargets(&this->base);
 
        /*
         * Automatic placement of the bad block table. Search direction
@@ -717,6 +717,7 @@ static int write_bbt(struct nand_chip *this, uint8_t *buf,
                     struct nand_bbt_descr *td, struct nand_bbt_descr *md,
                     int chipsel)
 {
+       u64 targetsize = nanddev_target_size(&this->base);
        struct mtd_info *mtd = nand_to_mtd(this);
        struct erase_info einfo;
        int i, res, chip = 0;
@@ -737,10 +738,10 @@ static int write_bbt(struct nand_chip *this, uint8_t *buf,
                rcode = 0xff;
        /* Write bad block table per chip rather than per device? */
        if (td->options & NAND_BBT_PERCHIP) {
-               numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+               numblocks = (int)(targetsize >> this->bbt_erase_shift);
                /* Full device write or specific chip? */
                if (chipsel == -1) {
-                       nrchips = this->numchips;
+                       nrchips = nanddev_ntargets(&this->base);
                } else {
                        nrchips = chipsel + 1;
                        chip = chipsel;
@@ -901,7 +902,9 @@ static int write_bbt(struct nand_chip *this, uint8_t *buf,
 static inline int nand_memory_bbt(struct nand_chip *this,
                                  struct nand_bbt_descr *bd)
 {
-       return create_bbt(this, this->data_buf, bd, -1);
+       u8 *pagebuf = nand_get_data_buf(this);
+
+       return create_bbt(this, pagebuf, bd, -1);
 }
 
 /**
@@ -925,7 +928,7 @@ static int check_create(struct nand_chip *this, uint8_t *buf,
 
        /* Do we have a bbt per chip? */
        if (td->options & NAND_BBT_PERCHIP)
-               chips = this->numchips;
+               chips = nanddev_ntargets(&this->base);
        else
                chips = 1;
 
@@ -1097,14 +1100,15 @@ static int nand_update_bbt(struct nand_chip *this, loff_t offs)
  */
 static void mark_bbt_region(struct nand_chip *this, struct nand_bbt_descr *td)
 {
+       u64 targetsize = nanddev_target_size(&this->base);
        struct mtd_info *mtd = nand_to_mtd(this);
        int i, j, chips, block, nrblocks, update;
        uint8_t oldval;
 
        /* Do we have a bbt per chip? */
        if (td->options & NAND_BBT_PERCHIP) {
-               chips = this->numchips;
-               nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+               chips = nanddev_ntargets(&this->base);
+               nrblocks = (int)(targetsize >> this->bbt_erase_shift);
        } else {
                chips = 1;
                nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
@@ -1157,6 +1161,7 @@ static void mark_bbt_region(struct nand_chip *this, struct nand_bbt_descr *td)
  */
 static void verify_bbt_descr(struct nand_chip *this, struct nand_bbt_descr *bd)
 {
+       u64 targetsize = nanddev_target_size(&this->base);
        struct mtd_info *mtd = nand_to_mtd(this);
        u32 pattern_len;
        u32 bits;
@@ -1185,7 +1190,7 @@ static void verify_bbt_descr(struct nand_chip *this, struct nand_bbt_descr *bd)
        }
 
        if (bd->options & NAND_BBT_PERCHIP)
-               table_size = this->chipsize >> this->bbt_erase_shift;
+               table_size = targetsize >> this->bbt_erase_shift;
        else
                table_size = mtd->size >> this->bbt_erase_shift;
        table_size >>= 3;
index 96f039a83bc82ec72021ce25efec2d948933e2f9..3338c68aaaf12af5c337bb8add06b43b66884085 100644 (file)
@@ -14,20 +14,20 @@ static void esmt_nand_decode_id(struct nand_chip *chip)
 
        /* Extract ECC requirements from 5th id byte. */
        if (chip->id.len >= 5 && nand_is_slc(chip)) {
-               chip->ecc_step_ds = 512;
+               chip->base.eccreq.step_size = 512;
                switch (chip->id.data[4] & 0x3) {
                case 0x0:
-                       chip->ecc_strength_ds = 4;
+                       chip->base.eccreq.strength = 4;
                        break;
                case 0x1:
-                       chip->ecc_strength_ds = 2;
+                       chip->base.eccreq.strength = 2;
                        break;
                case 0x2:
-                       chip->ecc_strength_ds = 1;
+                       chip->base.eccreq.strength = 1;
                        break;
                default:
                        WARN(1, "Could not get ECC info");
-                       chip->ecc_step_ds = 0;
+                       chip->base.eccreq.step_size = 0;
                        break;
                }
        }
@@ -36,7 +36,14 @@ static void esmt_nand_decode_id(struct nand_chip *chip)
 static int esmt_nand_init(struct nand_chip *chip)
 {
        if (nand_is_slc(chip))
-               chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+               /*
+                * It is known that some ESMT SLC NANDs have been shipped
+                * with the factory bad block markers in the first or last page
+                * of the block, instead of the first or second page. To be on
+                * the safe side, let's check all three locations.
+                */
+               chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE |
+                                NAND_BBM_LASTPAGE;
 
        return 0;
 }
index 343f477362d1d03e8c607c4f4507854875e4c48f..7c600c4d5ec8da20bd1a436a56084314d6f4bb84 100644 (file)
@@ -418,24 +418,27 @@ static void hynix_nand_extract_oobsize(struct nand_chip *chip,
                                       bool valid_jedecid)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_memory_organization *memorg;
        u8 oobsize;
 
+       memorg = nanddev_get_memorg(&chip->base);
+
        oobsize = ((chip->id.data[3] >> 2) & 0x3) |
                  ((chip->id.data[3] >> 4) & 0x4);
 
        if (valid_jedecid) {
                switch (oobsize) {
                case 0:
-                       mtd->oobsize = 2048;
+                       memorg->oobsize = 2048;
                        break;
                case 1:
-                       mtd->oobsize = 1664;
+                       memorg->oobsize = 1664;
                        break;
                case 2:
-                       mtd->oobsize = 1024;
+                       memorg->oobsize = 1024;
                        break;
                case 3:
-                       mtd->oobsize = 640;
+                       memorg->oobsize = 640;
                        break;
                default:
                        /*
@@ -450,25 +453,25 @@ static void hynix_nand_extract_oobsize(struct nand_chip *chip,
        } else {
                switch (oobsize) {
                case 0:
-                       mtd->oobsize = 128;
+                       memorg->oobsize = 128;
                        break;
                case 1:
-                       mtd->oobsize = 224;
+                       memorg->oobsize = 224;
                        break;
                case 2:
-                       mtd->oobsize = 448;
+                       memorg->oobsize = 448;
                        break;
                case 3:
-                       mtd->oobsize = 64;
+                       memorg->oobsize = 64;
                        break;
                case 4:
-                       mtd->oobsize = 32;
+                       memorg->oobsize = 32;
                        break;
                case 5:
-                       mtd->oobsize = 16;
+                       memorg->oobsize = 16;
                        break;
                case 6:
-                       mtd->oobsize = 640;
+                       memorg->oobsize = 640;
                        break;
                default:
                        /*
@@ -492,8 +495,10 @@ static void hynix_nand_extract_oobsize(struct nand_chip *chip,
                 * the actual OOB size for this chip is: 640 * 16k / 8k).
                 */
                if (chip->id.data[1] == 0xde)
-                       mtd->oobsize *= mtd->writesize / SZ_8K;
+                       memorg->oobsize *= memorg->pagesize / SZ_8K;
        }
+
+       mtd->oobsize = memorg->oobsize;
 }
 
 static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
@@ -503,30 +508,30 @@ static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
 
        if (valid_jedecid) {
                /* Reference: H27UCG8T2E datasheet */
-               chip->ecc_step_ds = 1024;
+               chip->base.eccreq.step_size = 1024;
 
                switch (ecc_level) {
                case 0:
-                       chip->ecc_step_ds = 0;
-                       chip->ecc_strength_ds = 0;
+                       chip->base.eccreq.step_size = 0;
+                       chip->base.eccreq.strength = 0;
                        break;
                case 1:
-                       chip->ecc_strength_ds = 4;
+                       chip->base.eccreq.strength = 4;
                        break;
                case 2:
-                       chip->ecc_strength_ds = 24;
+                       chip->base.eccreq.strength = 24;
                        break;
                case 3:
-                       chip->ecc_strength_ds = 32;
+                       chip->base.eccreq.strength = 32;
                        break;
                case 4:
-                       chip->ecc_strength_ds = 40;
+                       chip->base.eccreq.strength = 40;
                        break;
                case 5:
-                       chip->ecc_strength_ds = 50;
+                       chip->base.eccreq.strength = 50;
                        break;
                case 6:
-                       chip->ecc_strength_ds = 60;
+                       chip->base.eccreq.strength = 60;
                        break;
                default:
                        /*
@@ -547,14 +552,14 @@ static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
                if (nand_tech < 3) {
                        /* > 26nm, reference: H27UBG8T2A datasheet */
                        if (ecc_level < 5) {
-                               chip->ecc_step_ds = 512;
-                               chip->ecc_strength_ds = 1 << ecc_level;
+                               chip->base.eccreq.step_size = 512;
+                               chip->base.eccreq.strength = 1 << ecc_level;
                        } else if (ecc_level < 7) {
                                if (ecc_level == 5)
-                                       chip->ecc_step_ds = 2048;
+                                       chip->base.eccreq.step_size = 2048;
                                else
-                                       chip->ecc_step_ds = 1024;
-                               chip->ecc_strength_ds = 24;
+                                       chip->base.eccreq.step_size = 1024;
+                               chip->base.eccreq.strength = 24;
                        } else {
                                /*
                                 * We should never reach this case, but if that
@@ -567,14 +572,14 @@ static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
                } else {
                        /* <= 26nm, reference: H27UBG8T2B datasheet */
                        if (!ecc_level) {
-                               chip->ecc_step_ds = 0;
-                               chip->ecc_strength_ds = 0;
+                               chip->base.eccreq.step_size = 0;
+                               chip->base.eccreq.strength = 0;
                        } else if (ecc_level < 5) {
-                               chip->ecc_step_ds = 512;
-                               chip->ecc_strength_ds = 1 << (ecc_level - 1);
+                               chip->base.eccreq.step_size = 512;
+                               chip->base.eccreq.strength = 1 << (ecc_level - 1);
                        } else {
-                               chip->ecc_step_ds = 1024;
-                               chip->ecc_strength_ds = 24 +
+                               chip->base.eccreq.step_size = 1024;
+                               chip->base.eccreq.strength = 24 +
                                                        (8 * (ecc_level - 5));
                        }
                }
@@ -587,7 +592,7 @@ static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip,
        u8 nand_tech;
 
        /* We need scrambling on all TLC NANDs*/
-       if (chip->bits_per_cell > 2)
+       if (nanddev_bits_per_cell(&chip->base) > 2)
                chip->options |= NAND_NEED_SCRAMBLING;
 
        /* And on MLC NANDs with sub-3xnm process */
@@ -609,9 +614,12 @@ static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip,
 static void hynix_nand_decode_id(struct nand_chip *chip)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_memory_organization *memorg;
        bool valid_jedecid;
        u8 tmp;
 
+       memorg = nanddev_get_memorg(&chip->base);
+
        /*
         * Exclude all SLC NANDs from this advanced detection scheme.
         * According to the ranges defined in several datasheets, it might
@@ -625,7 +633,8 @@ static void hynix_nand_decode_id(struct nand_chip *chip)
        }
 
        /* Extract pagesize */
-       mtd->writesize = 2048 << (chip->id.data[3] & 0x03);
+       memorg->pagesize = 2048 << (chip->id.data[3] & 0x03);
+       mtd->writesize = memorg->pagesize;
 
        tmp = (chip->id.data[3] >> 4) & 0x3;
        /*
@@ -635,12 +644,19 @@ static void hynix_nand_decode_id(struct nand_chip *chip)
         * The only exception is when ID[3][4:5] == 3 and ID[3][7] == 0, in
         * this case the erasesize is set to 768KiB.
         */
-       if (chip->id.data[3] & 0x80)
+       if (chip->id.data[3] & 0x80) {
+               memorg->pages_per_eraseblock = (SZ_1M << tmp) /
+                                              memorg->pagesize;
                mtd->erasesize = SZ_1M << tmp;
-       else if (tmp == 3)
+       } else if (tmp == 3) {
+               memorg->pages_per_eraseblock = (SZ_512K + SZ_256K) /
+                                              memorg->pagesize;
                mtd->erasesize = SZ_512K + SZ_256K;
-       else
+       } else {
+               memorg->pages_per_eraseblock = (SZ_128K << tmp) /
+                                              memorg->pagesize;
                mtd->erasesize = SZ_128K << tmp;
+       }
 
        /*
         * Modern Toggle DDR NANDs have a valid JEDECID even though they are
@@ -672,9 +688,9 @@ static int hynix_nand_init(struct nand_chip *chip)
        int ret;
 
        if (!nand_is_slc(chip))
-               chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
+               chip->options |= NAND_BBM_LASTPAGE;
        else
-               chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+               chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
 
        hynix = kzalloc(sizeof(*hynix), GFP_KERNEL);
        if (!hynix)
index 38b5dc22cb30a6c56dec29ba71fe2b93b1362555..9b540e76f84f5202af09c0b3028d1b79399aaf55 100644 (file)
 int nand_jedec_detect(struct nand_chip *chip)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_memory_organization *memorg;
        struct nand_jedec_params *p;
        struct jedec_ecc_info *ecc;
        int jedec_version = 0;
        char id[5];
        int i, val, ret;
 
+       memorg = nanddev_get_memorg(&chip->base);
+
        /* Try JEDEC for unknown chip or LP */
        ret = nand_readid_op(chip, 0x40, id, sizeof(id));
        if (ret || strncmp(id, "JEDEC", sizeof(id)))
@@ -81,18 +84,24 @@ int nand_jedec_detect(struct nand_chip *chip)
                goto free_jedec_param_page;
        }
 
-       mtd->writesize = le32_to_cpu(p->byte_per_page);
+       memorg->pagesize = le32_to_cpu(p->byte_per_page);
+       mtd->writesize = memorg->pagesize;
 
        /* Please reference to the comment for nand_flash_detect_onfi. */
-       mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
-       mtd->erasesize *= mtd->writesize;
+       memorg->pages_per_eraseblock =
+                       1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+       mtd->erasesize = memorg->pages_per_eraseblock * memorg->pagesize;
+
+       memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+       mtd->oobsize = memorg->oobsize;
 
-       mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+       memorg->luns_per_target = p->lun_count;
+       memorg->planes_per_lun = 1 << p->multi_plane_addr;
 
        /* Please reference to the comment for nand_flash_detect_onfi. */
-       chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
-       chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
-       chip->bits_per_cell = p->bits_per_cell;
+       memorg->eraseblocks_per_lun =
+               1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
+       memorg->bits_per_cell = p->bits_per_cell;
 
        if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS)
                chip->options |= NAND_BUSWIDTH_16;
@@ -101,8 +110,8 @@ int nand_jedec_detect(struct nand_chip *chip)
        ecc = &p->ecc_info[0];
 
        if (ecc->codeword_size >= 9) {
-               chip->ecc_strength_ds = ecc->ecc_bits;
-               chip->ecc_step_ds = 1 << ecc->codeword_size;
+               chip->base.eccreq.strength = ecc->ecc_bits;
+               chip->base.eccreq.step_size = 1 << ecc->codeword_size;
        } else {
                pr_warn("Invalid codeword size\n");
        }
index 47d8cda547cfe10c87852f5d855ab9157bc6fe73..e287e71347c565a6aadb734ed22a8ff6d086c9b2 100644 (file)
@@ -62,7 +62,7 @@ static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
 static int macronix_nand_init(struct nand_chip *chip)
 {
        if (nand_is_slc(chip))
-               chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+               chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
 
        macronix_nand_fix_broken_get_timings(chip);
 
index b85e1c13b79e0fa9a0a82e5ad8bf9461bd6f8652..cbd4f09ac178a23ce2b9087db5ed5609b33a4b08 100644 (file)
@@ -385,13 +385,13 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
        if (!chip->parameters.onfi)
                return MICRON_ON_DIE_UNSUPPORTED;
 
-       if (chip->bits_per_cell != 1)
+       if (nanddev_bits_per_cell(&chip->base) != 1)
                return MICRON_ON_DIE_UNSUPPORTED;
 
        /*
         * We only support on-die ECC of 4/512 or 8/512
         */
-       if  (chip->ecc_strength_ds != 4 && chip->ecc_strength_ds != 8)
+       if  (chip->base.eccreq.strength != 4 && chip->base.eccreq.strength != 8)
                return MICRON_ON_DIE_UNSUPPORTED;
 
        /* 0x2 means on-die ECC is available. */
@@ -424,7 +424,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
        /*
         * We only support on-die ECC of 4/512 or 8/512
         */
-       if  (chip->ecc_strength_ds != 4 && chip->ecc_strength_ds != 8)
+       if  (chip->base.eccreq.strength != 4 && chip->base.eccreq.strength != 8)
                return MICRON_ON_DIE_UNSUPPORTED;
 
        return MICRON_ON_DIE_SUPPORTED;
@@ -448,7 +448,7 @@ static int micron_nand_init(struct nand_chip *chip)
                goto err_free_manuf_data;
 
        if (mtd->writesize == 2048)
-               chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+               chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
 
        ondie = micron_supports_on_die_ecc(chip);
 
@@ -479,7 +479,7 @@ static int micron_nand_init(struct nand_chip *chip)
                 * That's not needed for 8-bit ECC, because the status expose
                 * a better approximation of the number of bitflips in a page.
                 */
-               if (chip->ecc_strength_ds == 4) {
+               if (chip->base.eccreq.strength == 4) {
                        micron->ecc.rawbuf = kmalloc(mtd->writesize +
                                                     mtd->oobsize,
                                                     GFP_KERNEL);
@@ -489,16 +489,16 @@ static int micron_nand_init(struct nand_chip *chip)
                        }
                }
 
-               if (chip->ecc_strength_ds == 4)
+               if (chip->base.eccreq.strength == 4)
                        mtd_set_ooblayout(mtd,
                                          &micron_nand_on_die_4_ooblayout_ops);
                else
                        mtd_set_ooblayout(mtd,
                                          &micron_nand_on_die_8_ooblayout_ops);
 
-               chip->ecc.bytes = chip->ecc_strength_ds * 2;
+               chip->ecc.bytes = chip->base.eccreq.strength * 2;
                chip->ecc.size = 512;
-               chip->ecc.strength = chip->ecc_strength_ds;
+               chip->ecc.strength = chip->base.eccreq.strength;
                chip->ecc.algo = NAND_ECC_BCH;
                chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
                chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
index d8184cf591ada1d511f5bde67bd837132420b5b8..0b879bd0a68c839ae87fdf93c725765b1925f831 100644 (file)
@@ -94,8 +94,8 @@ static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
                goto ext_out;
        }
 
-       chip->ecc_strength_ds = ecc->ecc_bits;
-       chip->ecc_step_ds = 1 << ecc->codeword_size;
+       chip->base.eccreq.strength = ecc->ecc_bits;
+       chip->base.eccreq.step_size = 1 << ecc->codeword_size;
        ret = 0;
 
 ext_out:
@@ -140,12 +140,15 @@ static void nand_bit_wise_majority(const void **srcbufs,
 int nand_onfi_detect(struct nand_chip *chip)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_memory_organization *memorg;
        struct nand_onfi_params *p;
        struct onfi_params *onfi;
        int onfi_version = 0;
        char id[4];
        int i, ret, val;
 
+       memorg = nanddev_get_memorg(&chip->base);
+
        /* Try ONFI for unknown chip or LP */
        ret = nand_readid_op(chip, 0x20, id, sizeof(id));
        if (ret || strncmp(id, "ONFI", 4))
@@ -221,32 +224,36 @@ int nand_onfi_detect(struct nand_chip *chip)
                goto free_onfi_param_page;
        }
 
-       mtd->writesize = le32_to_cpu(p->byte_per_page);
+       memorg->pagesize = le32_to_cpu(p->byte_per_page);
+       mtd->writesize = memorg->pagesize;
 
        /*
         * pages_per_block and blocks_per_lun may not be a power-of-2 size
         * (don't ask me who thought of this...). MTD assumes that these
         * dimensions will be power-of-2, so just truncate the remaining area.
         */
-       mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
-       mtd->erasesize *= mtd->writesize;
+       memorg->pages_per_eraseblock =
+                       1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+       mtd->erasesize = memorg->pages_per_eraseblock * memorg->pagesize;
 
-       mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+       memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+       mtd->oobsize = memorg->oobsize;
 
-       /* See erasesize comment */
-       chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
-       chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
-       chip->bits_per_cell = p->bits_per_cell;
+       memorg->luns_per_target = p->lun_count;
+       memorg->planes_per_lun = 1 << p->interleaved_bits;
 
-       chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
-       chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
+       /* See erasesize comment */
+       memorg->eraseblocks_per_lun =
+               1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
+       memorg->max_bad_eraseblocks_per_lun = le32_to_cpu(p->blocks_per_lun);
+       memorg->bits_per_cell = p->bits_per_cell;
 
        if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS)
                chip->options |= NAND_BUSWIDTH_16;
 
        if (p->ecc_bits != 0xff) {
-               chip->ecc_strength_ds = p->ecc_bits;
-               chip->ecc_step_ds = 512;
+               chip->base.eccreq.strength = p->ecc_bits;
+               chip->base.eccreq.step_size = 512;
        } else if (onfi_version >= 21 &&
                (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
 
index e46d4c492ad81ab7fc44ab7d0d9d22aeec56bdfc..5552ce20ede034d05ab33fa94a62efe0bc967c1a 100644 (file)
@@ -20,6 +20,9 @@
 static void samsung_nand_decode_id(struct nand_chip *chip)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_memory_organization *memorg;
+
+       memorg = nanddev_get_memorg(&chip->base);
 
        /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
        if (chip->id.len == 6 && !nand_is_slc(chip) &&
@@ -27,29 +30,30 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
                u8 extid = chip->id.data[3];
 
                /* Get pagesize */
-               mtd->writesize = 2048 << (extid & 0x03);
+               memorg->pagesize = 2048 << (extid & 0x03);
+               mtd->writesize = memorg->pagesize;
 
                extid >>= 2;
 
                /* Get oobsize */
                switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
                case 1:
-                       mtd->oobsize = 128;
+                       memorg->oobsize = 128;
                        break;
                case 2:
-                       mtd->oobsize = 218;
+                       memorg->oobsize = 218;
                        break;
                case 3:
-                       mtd->oobsize = 400;
+                       memorg->oobsize = 400;
                        break;
                case 4:
-                       mtd->oobsize = 436;
+                       memorg->oobsize = 436;
                        break;
                case 5:
-                       mtd->oobsize = 512;
+                       memorg->oobsize = 512;
                        break;
                case 6:
-                       mtd->oobsize = 640;
+                       memorg->oobsize = 640;
                        break;
                default:
                        /*
@@ -62,31 +66,37 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
                        break;
                }
 
+               mtd->oobsize = memorg->oobsize;
+
                /* Get blocksize */
                extid >>= 2;
+               memorg->pages_per_eraseblock = (128 * 1024) <<
+                                              (((extid >> 1) & 0x04) |
+                                               (extid & 0x03)) /
+                                              memorg->pagesize;
                mtd->erasesize = (128 * 1024) <<
                                 (((extid >> 1) & 0x04) | (extid & 0x03));
 
                /* Extract ECC requirements from 5th id byte*/
                extid = (chip->id.data[4] >> 4) & 0x07;
                if (extid < 5) {
-                       chip->ecc_step_ds = 512;
-                       chip->ecc_strength_ds = 1 << extid;
+                       chip->base.eccreq.step_size = 512;
+                       chip->base.eccreq.strength = 1 << extid;
                } else {
-                       chip->ecc_step_ds = 1024;
+                       chip->base.eccreq.step_size = 1024;
                        switch (extid) {
                        case 5:
-                               chip->ecc_strength_ds = 24;
+                               chip->base.eccreq.strength = 24;
                                break;
                        case 6:
-                               chip->ecc_strength_ds = 40;
+                               chip->base.eccreq.strength = 40;
                                break;
                        case 7:
-                               chip->ecc_strength_ds = 60;
+                               chip->base.eccreq.strength = 60;
                                break;
                        default:
                                WARN(1, "Could not decode ECC info");
-                               chip->ecc_step_ds = 0;
+                               chip->base.eccreq.step_size = 0;
                        }
                }
        } else {
@@ -96,8 +106,8 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
                        switch (chip->id.data[1]) {
                        /* K9F4G08U0D-S[I|C]B0(T00) */
                        case 0xDC:
-                               chip->ecc_step_ds = 512;
-                               chip->ecc_strength_ds = 1;
+                               chip->base.eccreq.step_size = 512;
+                               chip->base.eccreq.strength = 1;
                                break;
 
                        /* K9F1G08U0E 21nm chips do not support subpage write */
@@ -121,9 +131,9 @@ static int samsung_nand_init(struct nand_chip *chip)
                chip->options |= NAND_SAMSUNG_LP_OPTIONS;
 
        if (!nand_is_slc(chip))
-               chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
+               chip->options |= NAND_BBM_LASTPAGE;
        else
-               chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+               chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
 
        return 0;
 }
index d068163b64b3ff1755f5a66d6b3227d627603b93..74ffcae4872663649b0d5d0070158e5b9600bb2e 100644 (file)
@@ -101,6 +101,9 @@ static void toshiba_nand_benand_init(struct nand_chip *chip)
 static void toshiba_nand_decode_id(struct nand_chip *chip)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_memory_organization *memorg;
+
+       memorg = nanddev_get_memorg(&chip->base);
 
        nand_decode_ext_id(chip);
 
@@ -114,8 +117,10 @@ static void toshiba_nand_decode_id(struct nand_chip *chip)
         */
        if (chip->id.len >= 6 && nand_is_slc(chip) &&
            (chip->id.data[5] & 0x7) == 0x6 /* 24nm */ &&
-           !(chip->id.data[4] & 0x80) /* !BENAND */)
-               mtd->oobsize = 32 * mtd->writesize >> 9;
+           !(chip->id.data[4] & 0x80) /* !BENAND */) {
+               memorg->oobsize = 32 * memorg->pagesize >> 9;
+               mtd->oobsize = memorg->oobsize;
+       }
 
        /*
         * Extract ECC requirements from 6th id byte.
@@ -125,20 +130,20 @@ static void toshiba_nand_decode_id(struct nand_chip *chip)
         *  - 24nm: 8 bit ECC for each 512Byte is required.
         */
        if (chip->id.len >= 6 && nand_is_slc(chip)) {
-               chip->ecc_step_ds = 512;
+               chip->base.eccreq.step_size = 512;
                switch (chip->id.data[5] & 0x7) {
                case 0x4:
-                       chip->ecc_strength_ds = 1;
+                       chip->base.eccreq.strength = 1;
                        break;
                case 0x5:
-                       chip->ecc_strength_ds = 4;
+                       chip->base.eccreq.strength = 4;
                        break;
                case 0x6:
-                       chip->ecc_strength_ds = 8;
+                       chip->base.eccreq.strength = 8;
                        break;
                default:
                        WARN(1, "Could not get ECC info");
-                       chip->ecc_step_ds = 0;
+                       chip->base.eccreq.step_size = 0;
                        break;
                }
        }
@@ -147,7 +152,7 @@ static void toshiba_nand_decode_id(struct nand_chip *chip)
 static int toshiba_nand_init(struct nand_chip *chip)
 {
        if (nand_is_slc(chip))
-               chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+               chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
 
        /* Check that chip is BENAND and ECC mode is on-die */
        if (nand_is_slc(chip) && chip->ecc.mode == NAND_ECC_ON_DIE &&
index 933d1a629c519874d3a0f35771b620cf5e5c20f7..df63fa56408288eac79e10c50b7bc2f77660db5b 100644 (file)
@@ -298,6 +298,8 @@ union ns_mem {
  * The structure which describes all the internal simulator data.
  */
 struct nandsim {
+       struct nand_chip chip;
+       struct nand_controller base;
        struct mtd_partition partitions[CONFIG_NANDSIM_MAX_PARTS];
        unsigned int nbparts;
 
@@ -644,9 +646,6 @@ static int __init init_nandsim(struct mtd_info *mtd)
                return -EIO;
        }
 
-       /* Force mtd to not do delays */
-       chip->legacy.chip_delay = 0;
-
        /* Initialize the NAND flash parameters */
        ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
        ns->geom.totsz    = mtd->size;
@@ -2076,24 +2075,6 @@ static void ns_nand_write_byte(struct nand_chip *chip, u_char byte)
        return;
 }
 
-static void ns_hwcontrol(struct nand_chip *chip, int cmd, unsigned int bitmask)
-{
-       struct nandsim *ns = nand_get_controller_data(chip);
-
-       ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
-       ns->lines.ale = bitmask & NAND_ALE ? 1 : 0;
-       ns->lines.ce = bitmask & NAND_NCE ? 1 : 0;
-
-       if (cmd != NAND_CMD_NONE)
-               ns_nand_write_byte(chip, cmd);
-}
-
-static int ns_device_ready(struct nand_chip *chip)
-{
-       NS_DBG("device_ready\n");
-       return 1;
-}
-
 static void ns_nand_write_buf(struct nand_chip *chip, const u_char *buf,
                              int len)
 {
@@ -2145,7 +2126,7 @@ static void ns_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
                int i;
 
                for (i = 0; i < len; i++)
-                       buf[i] = chip->legacy.read_byte(chip);
+                       buf[i] = ns_nand_read_byte(chip);
 
                return;
        }
@@ -2168,6 +2149,46 @@ static void ns_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
        return;
 }
 
+static int ns_exec_op(struct nand_chip *chip, const struct nand_operation *op,
+                     bool check_only)
+{
+       int i;
+       unsigned int op_id;
+       const struct nand_op_instr *instr = NULL;
+       struct nandsim *ns = nand_get_controller_data(chip);
+
+       ns->lines.ce = 1;
+
+       for (op_id = 0; op_id < op->ninstrs; op_id++) {
+               instr = &op->instrs[op_id];
+               ns->lines.cle = 0;
+               ns->lines.ale = 0;
+
+               switch (instr->type) {
+               case NAND_OP_CMD_INSTR:
+                       ns->lines.cle = 1;
+                       ns_nand_write_byte(chip, instr->ctx.cmd.opcode);
+                       break;
+               case NAND_OP_ADDR_INSTR:
+                       ns->lines.ale = 1;
+                       for (i = 0; i < instr->ctx.addr.naddrs; i++)
+                               ns_nand_write_byte(chip, instr->ctx.addr.addrs[i]);
+                       break;
+               case NAND_OP_DATA_IN_INSTR:
+                       ns_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len);
+                       break;
+               case NAND_OP_DATA_OUT_INSTR:
+                       ns_nand_write_buf(chip, instr->ctx.data.buf.out, instr->ctx.data.len);
+                       break;
+               case NAND_OP_WAITRDY_INSTR:
+                       /* we are always ready */
+                       break;
+               }
+       }
+
+       return 0;
+}
+
 static int ns_attach_chip(struct nand_chip *chip)
 {
        unsigned int eccsteps, eccbytes;
@@ -2208,6 +2229,7 @@ static int ns_attach_chip(struct nand_chip *chip)
 
 static const struct nand_controller_ops ns_controller_ops = {
        .attach_chip = ns_attach_chip,
+       .exec_op = ns_exec_op,
 };
 
 /*
@@ -2216,7 +2238,7 @@ static const struct nand_controller_ops ns_controller_ops = {
 static int __init ns_init_module(void)
 {
        struct nand_chip *chip;
-       struct nandsim *nand;
+       struct nandsim *ns;
        int retval = -ENOMEM, i;
 
        if (bus_width != 8 && bus_width != 16) {
@@ -2224,25 +2246,15 @@ static int __init ns_init_module(void)
                return -EINVAL;
        }
 
-       /* Allocate and initialize mtd_info, nand_chip and nandsim structures */
-       chip = kzalloc(sizeof(struct nand_chip) + sizeof(struct nandsim),
-                      GFP_KERNEL);
-       if (!chip) {
+       ns = kzalloc(sizeof(struct nandsim), GFP_KERNEL);
+       if (!ns) {
                NS_ERR("unable to allocate core structures.\n");
                return -ENOMEM;
        }
+       chip        = &ns->chip;
        nsmtd       = nand_to_mtd(chip);
-       nand        = (struct nandsim *)(chip + 1);
-       nand_set_controller_data(chip, (void *)nand);
+       nand_set_controller_data(chip, (void *)ns);
 
-       /*
-        * Register simulator's callbacks.
-        */
-       chip->legacy.cmd_ctrl    = ns_hwcontrol;
-       chip->legacy.read_byte  = ns_nand_read_byte;
-       chip->legacy.dev_ready  = ns_device_ready;
-       chip->legacy.write_buf  = ns_nand_write_buf;
-       chip->legacy.read_buf   = ns_nand_read_buf;
        chip->ecc.mode   = NAND_ECC_SOFT;
        chip->ecc.algo   = NAND_ECC_HAMMING;
        /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
@@ -2251,9 +2263,11 @@ static int __init ns_init_module(void)
 
        switch (bbt) {
        case 2:
-                chip->bbt_options |= NAND_BBT_NO_OOB;
+               chip->bbt_options |= NAND_BBT_NO_OOB;
+               /* fall through */
        case 1:
-                chip->bbt_options |= NAND_BBT_USE_FLASH;
+               chip->bbt_options |= NAND_BBT_USE_FLASH;
+               /* fall through */
        case 0:
                break;
        default:
@@ -2266,19 +2280,19 @@ static int __init ns_init_module(void)
         * the initial ID read command correctly
         */
        if (id_bytes[6] != 0xFF || id_bytes[7] != 0xFF)
-               nand->geom.idbytes = 8;
+               ns->geom.idbytes = 8;
        else if (id_bytes[4] != 0xFF || id_bytes[5] != 0xFF)
-               nand->geom.idbytes = 6;
+               ns->geom.idbytes = 6;
        else if (id_bytes[2] != 0xFF || id_bytes[3] != 0xFF)
-               nand->geom.idbytes = 4;
+               ns->geom.idbytes = 4;
        else
-               nand->geom.idbytes = 2;
-       nand->regs.status = NS_STATUS_OK(nand);
-       nand->nxstate = STATE_UNKNOWN;
-       nand->options |= OPT_PAGE512; /* temporary value */
-       memcpy(nand->ids, id_bytes, sizeof(nand->ids));
+               ns->geom.idbytes = 2;
+       ns->regs.status = NS_STATUS_OK(ns);
+       ns->nxstate = STATE_UNKNOWN;
+       ns->options |= OPT_PAGE512; /* temporary value */
+       memcpy(ns->ids, id_bytes, sizeof(ns->ids));
        if (bus_width == 16) {
-               nand->busw = 16;
+               ns->busw = 16;
                chip->options |= NAND_BUSWIDTH_16;
        }
 
@@ -2293,7 +2307,10 @@ static int __init ns_init_module(void)
        if ((retval = parse_gravepages()) != 0)
                goto error;
 
-       chip->legacy.dummy_controller.ops = &ns_controller_ops;
+       nand_controller_init(&ns->base);
+       ns->base.ops = &ns_controller_ops;
+       chip->controller = &ns->base;
+
        retval = nand_scan(chip, 1);
        if (retval) {
                NS_ERR("Could not scan NAND Simulator device\n");
@@ -2302,16 +2319,23 @@ static int __init ns_init_module(void)
 
        if (overridesize) {
                uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize;
+               struct nand_memory_organization *memorg;
+               u64 targetsize;
+
+               memorg = nanddev_get_memorg(&chip->base);
+
                if (new_size >> overridesize != nsmtd->erasesize) {
                        NS_ERR("overridesize is too big\n");
                        retval = -EINVAL;
                        goto err_exit;
                }
+
                /* N.B. This relies on nand_scan not doing anything with the size before we change it */
                nsmtd->size = new_size;
-               chip->chipsize = new_size;
+               memorg->eraseblocks_per_lun = 1 << overridesize;
+               targetsize = nanddev_target_size(&chip->base);
                chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1;
-               chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
+               chip->pagemask = (targetsize >> chip->page_shift) - 1;
        }
 
        if ((retval = setup_wear_reporting(nsmtd)) != 0)
@@ -2323,27 +2347,27 @@ static int __init ns_init_module(void)
        if ((retval = nand_create_bbt(chip)) != 0)
                goto err_exit;
 
-       if ((retval = parse_badblocks(nand, nsmtd)) != 0)
+       if ((retval = parse_badblocks(ns, nsmtd)) != 0)
                goto err_exit;
 
        /* Register NAND partitions */
-       retval = mtd_device_register(nsmtd, &nand->partitions[0],
-                                    nand->nbparts);
+       retval = mtd_device_register(nsmtd, &ns->partitions[0],
+                                    ns->nbparts);
        if (retval != 0)
                goto err_exit;
 
-       if ((retval = nandsim_debugfs_create(nand)) != 0)
+       if ((retval = nandsim_debugfs_create(ns)) != 0)
                goto err_exit;
 
         return 0;
 
 err_exit:
-       free_nandsim(nand);
+       free_nandsim(ns);
        nand_release(chip);
-       for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
-               kfree(nand->partitions[i].name);
+       for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
+               kfree(ns->partitions[i].name);
 error:
-       kfree(chip);
+       kfree(ns);
        free_lists();
 
        return retval;
@@ -2364,7 +2388,7 @@ static void __exit ns_cleanup_module(void)
        nand_release(chip); /* Unregister driver */
        for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
                kfree(ns->partitions[i].name);
-       kfree(mtd_to_nand(nsmtd));        /* Free other structures */
+       kfree(ns);        /* Free other structures */
        free_lists();
 }
 
index 38b1994e7ed3bd66babf350c035c3a5a0f9f2153..56fa84029482978589105fbddbbf3efc20708a25 100644 (file)
@@ -192,8 +192,9 @@ static void nuc900_nand_command_lp(struct nand_chip *chip,
                return;
 
        case NAND_CMD_READ0:
-
                write_cmd_reg(nand, NAND_CMD_READSTART);
+               /* fall through */
+
        default:
 
                if (!chip->legacy.dev_ready) {
index 8f280a2962c8b8b6cacad67a67df67a54e3ebe29..a9a275342a41e525cb1471ddccf9d2536cb68353 100644 (file)
@@ -1725,9 +1725,9 @@ static bool omap2_nand_ecc_check(struct omap_nand_info *info)
                break;
        }
 
-       if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) {
+       if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_BCH)) {
                dev_err(&info->pdev->dev,
-                       "CONFIG_MTD_NAND_ECC_BCH not enabled\n");
+                       "CONFIG_MTD_NAND_ECC_SW_BCH not enabled\n");
                return false;
        }
        if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) {
index a3f32f939cc1732a1a2938696019dfe9c7bf88a9..94c6401ef32fd81a66001e8f73f2d88e033a6784 100644 (file)
@@ -465,11 +465,13 @@ static int elm_context_save(struct elm_info *info)
                                        ELM_SYNDROME_FRAGMENT_5 + offset);
                        regs->elm_syndrome_fragment_4[i] = elm_read_reg(info,
                                        ELM_SYNDROME_FRAGMENT_4 + offset);
+                       /* fall through */
                case BCH8_ECC:
                        regs->elm_syndrome_fragment_3[i] = elm_read_reg(info,
                                        ELM_SYNDROME_FRAGMENT_3 + offset);
                        regs->elm_syndrome_fragment_2[i] = elm_read_reg(info,
                                        ELM_SYNDROME_FRAGMENT_2 + offset);
+                       /* fall through */
                case BCH4_ECC:
                        regs->elm_syndrome_fragment_1[i] = elm_read_reg(info,
                                        ELM_SYNDROME_FRAGMENT_1 + offset);
@@ -511,11 +513,13 @@ static int elm_context_restore(struct elm_info *info)
                                        regs->elm_syndrome_fragment_5[i]);
                        elm_write_reg(info, ELM_SYNDROME_FRAGMENT_4 + offset,
                                        regs->elm_syndrome_fragment_4[i]);
+                       /* fall through */
                case BCH8_ECC:
                        elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset,
                                        regs->elm_syndrome_fragment_3[i]);
                        elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset,
                                        regs->elm_syndrome_fragment_2[i]);
+                       /* fall through */
                case BCH4_ECC:
                        elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset,
                                        regs->elm_syndrome_fragment_1[i]);
index 920e7375084f4f43ec0a23e7cde9ef39cfcc6650..6ead55e05b80f38202f93def5371c5c3dbf1f326 100644 (file)
@@ -1680,14 +1680,12 @@ check_for_erased_page(struct qcom_nand_host *host, u8 *data_buf,
        u8 *cw_data_buf, *cw_oob_buf;
        int cw, data_size, oob_size, ret = 0;
 
-       if (!data_buf) {
-               data_buf = chip->data_buf;
-               chip->pagebuf = -1;
-       }
+       if (!data_buf)
+               data_buf = nand_get_data_buf(chip);
 
        if (!oob_buf) {
+               nand_get_data_buf(chip);
                oob_buf = chip->oob_poi;
-               chip->pagebuf = -1;
        }
 
        for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) {
index cf6b1be1cf9c2a95d99699f4ae1633642835e7f4..e509c93737c4f76f5eb50c863393510091d1fa0c 100644 (file)
@@ -101,14 +101,12 @@ static const struct mtd_ooblayout_ops flctl_4secc_oob_largepage_ops = {
 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
 
 static struct nand_bbt_descr flctl_4secc_smallpage = {
-       .options = NAND_BBT_SCAN2NDPAGE,
        .offs = 11,
        .len = 1,
        .pattern = scan_ff_pattern,
 };
 
 static struct nand_bbt_descr flctl_4secc_largepage = {
-       .options = NAND_BBT_SCAN2NDPAGE,
        .offs = 0,
        .len = 2,
        .pattern = scan_ff_pattern,
@@ -986,6 +984,7 @@ static void flctl_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
 
 static int flctl_chip_attach_chip(struct nand_chip *chip)
 {
+       u64 targetsize = nanddev_target_size(&chip->base);
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct sh_flctl *flctl = mtd_to_flctl(mtd);
 
@@ -998,11 +997,11 @@ static int flctl_chip_attach_chip(struct nand_chip *chip)
 
        if (mtd->writesize == 512) {
                flctl->page_size = 0;
-               if (chip->chipsize > (32 << 20)) {
+               if (targetsize > (32 << 20)) {
                        /* big than 32MB */
                        flctl->rw_ADRCNT = ADRCNT_4;
                        flctl->erase_ADRCNT = ADRCNT_3;
-               } else if (chip->chipsize > (2 << 16)) {
+               } else if (targetsize > (2 << 16)) {
                        /* big than 128KB */
                        flctl->rw_ADRCNT = ADRCNT_3;
                        flctl->erase_ADRCNT = ADRCNT_2;
@@ -1012,11 +1011,11 @@ static int flctl_chip_attach_chip(struct nand_chip *chip)
                }
        } else {
                flctl->page_size = 1;
-               if (chip->chipsize > (128 << 20)) {
+               if (targetsize > (128 << 20)) {
                        /* big than 128MB */
                        flctl->rw_ADRCNT = ADRCNT2_E;
                        flctl->erase_ADRCNT = ADRCNT_3;
-               } else if (chip->chipsize > (8 << 16)) {
+               } else if (targetsize > (8 << 16)) {
                        /* big than 512KB */
                        flctl->rw_ADRCNT = ADRCNT_4;
                        flctl->erase_ADRCNT = ADRCNT_2;
@@ -1178,6 +1177,8 @@ static int flctl_probe(struct platform_device *pdev)
        if (pdata->flcmncr_val & SEL_16BIT)
                nand->options |= NAND_BUSWIDTH_16;
 
+       nand->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
+
        pm_runtime_enable(&pdev->dev);
        pm_runtime_resume(&pdev->dev);
 
index 4282bc47776177cc95dfa7bed5805b403c352688..b021a5720b42b350d679cd43a55968796d9a8f73 100644 (file)
@@ -42,7 +42,8 @@
 #define NFC_REG_CMD            0x0024
 #define NFC_REG_RCMD_SET       0x0028
 #define NFC_REG_WCMD_SET       0x002C
-#define NFC_REG_IO_DATA                0x0030
+#define NFC_REG_A10_IO_DATA    0x0030
+#define NFC_REG_A23_IO_DATA    0x0300
 #define NFC_REG_ECC_CTL                0x0034
 #define NFC_REG_ECC_ST         0x0038
 #define NFC_REG_DEBUG          0x003C
@@ -200,6 +201,22 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
        return container_of(nand, struct sunxi_nand_chip, nand);
 }
 
+/*
+ * NAND Controller capabilities structure: stores NAND controller capabilities
+ * for distinction between compatible strings.
+ *
+ * @sram_through_ahb:  On A23, we choose to access the internal RAM through AHB
+ *                      instead of MBUS (less configuration). A10, A10s, A13 and
+ *                      A20 use the MBUS but no extra configuration is needed.
+ * @reg_io_data:       I/O data register
+ * @dma_maxburst:      DMA maxburst
+ */
+struct sunxi_nfc_caps {
+       bool sram_through_ahb;
+       unsigned int reg_io_data;
+       unsigned int dma_maxburst;
+};
+
 /**
  * struct sunxi_nfc - stores sunxi NAND controller information
  *
@@ -228,6 +245,7 @@ struct sunxi_nfc {
        struct list_head chips;
        struct completion complete;
        struct dma_chan *dmac;
+       const struct sunxi_nfc_caps *caps;
 };
 
 static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_controller *ctrl)
@@ -350,10 +368,29 @@ static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf,
                goto err_unmap_buf;
        }
 
-       writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
-              nfc->regs + NFC_REG_CTL);
+       /*
+        * On A23, we suppose the "internal RAM" (p.12 of the NFC user manual)
+        * refers to the NAND controller's internal SRAM. This memory is mapped
+        * and so is accessible from the AHB. It seems that it can also be
+        * accessed by the MBUS. MBUS accesses are mandatory when using the
+        * internal DMA instead of the external DMA engine.
+        *
+        * During DMA I/O operation, either we access this memory from the AHB
+        * by clearing the NFC_RAM_METHOD bit, or we set the bit and use the
+        * MBUS. In this case, we should also configure the MBUS DMA length
+        * NFC_REG_MDMA_CNT(0xC4) to be chunksize * nchunks. NAND I/O over MBUS
+        * are also limited to 32kiB pages.
+        */
+       if (nfc->caps->sram_through_ahb)
+               writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
+                      nfc->regs + NFC_REG_CTL);
+       else
+               writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
+                      nfc->regs + NFC_REG_CTL);
+
        writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM);
        writel(chunksize, nfc->regs + NFC_REG_CNT);
+
        dmat = dmaengine_submit(dmad);
 
        ret = dma_submit_error(dmat);
@@ -1313,20 +1350,19 @@ pio_fallback:
 
 static int sunxi_nfc_hw_ecc_read_oob(struct nand_chip *nand, int page)
 {
-       nand->pagebuf = -1;
+       u8 *buf = nand_get_data_buf(nand);
 
-       return nand->ecc.read_page(nand, nand->data_buf, 1, page);
+       return nand->ecc.read_page(nand, buf, 1, page);
 }
 
 static int sunxi_nfc_hw_ecc_write_oob(struct nand_chip *nand, int page)
 {
        struct mtd_info *mtd = nand_to_mtd(nand);
+       u8 *buf = nand_get_data_buf(nand);
        int ret;
 
-       nand->pagebuf = -1;
-
-       memset(nand->data_buf, 0xff, mtd->writesize);
-       ret = nand->ecc.write_page(nand, nand->data_buf, 1, page);
+       memset(buf, 0xff, mtd->writesize);
+       ret = nand->ecc.write_page(nand, buf, 1, page);
        if (ret)
                return ret;
 
@@ -1724,8 +1760,8 @@ static int sunxi_nand_attach_chip(struct nand_chip *nand)
        nand->options |= NAND_SUBPAGE_READ;
 
        if (!ecc->size) {
-               ecc->size = nand->ecc_step_ds;
-               ecc->strength = nand->ecc_strength_ds;
+               ecc->size = nand->base.eccreq.step_size;
+               ecc->strength = nand->base.eccreq.strength;
        }
 
        if (!ecc->size || !ecc->strength)
@@ -2088,6 +2124,12 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
                goto out_mod_clk_unprepare;
        }
 
+       nfc->caps = of_device_get_match_data(&pdev->dev);
+       if (!nfc->caps) {
+               ret = -EINVAL;
+               goto out_ahb_reset_reassert;
+       }
+
        ret = sunxi_nfc_rst(nfc);
        if (ret)
                goto out_ahb_reset_reassert;
@@ -2102,12 +2144,12 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
        if (nfc->dmac) {
                struct dma_slave_config dmac_cfg = { };
 
-               dmac_cfg.src_addr = r->start + NFC_REG_IO_DATA;
+               dmac_cfg.src_addr = r->start + nfc->caps->reg_io_data;
                dmac_cfg.dst_addr = dmac_cfg.src_addr;
                dmac_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
                dmac_cfg.dst_addr_width = dmac_cfg.src_addr_width;
-               dmac_cfg.src_maxburst = 4;
-               dmac_cfg.dst_maxburst = 4;
+               dmac_cfg.src_maxburst = nfc->caps->dma_maxburst;
+               dmac_cfg.dst_maxburst = nfc->caps->dma_maxburst;
                dmaengine_slave_config(nfc->dmac, &dmac_cfg);
        } else {
                dev_warn(dev, "failed to request rxtx DMA channel\n");
@@ -2152,8 +2194,26 @@ static int sunxi_nfc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = {
+       .reg_io_data = NFC_REG_A10_IO_DATA,
+       .dma_maxburst = 4,
+};
+
+static const struct sunxi_nfc_caps sunxi_nfc_a23_caps = {
+       .sram_through_ahb = true,
+       .reg_io_data = NFC_REG_A23_IO_DATA,
+       .dma_maxburst = 8,
+};
+
 static const struct of_device_id sunxi_nfc_ids[] = {
-       { .compatible = "allwinner,sun4i-a10-nand" },
+       {
+               .compatible = "allwinner,sun4i-a10-nand",
+               .data = &sunxi_nfc_a10_caps,
+       },
+       {
+               .compatible = "allwinner,sun8i-a23-nand-controller",
+               .data = &sunxi_nfc_a23_caps,
+       },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sunxi_nfc_ids);
index 13be32c381948f1e621368cbd26f1e2e2ee8aa9f..3cc9a4c41443aa4b2205cf5ac522d27fc799fbb5 100644 (file)
@@ -853,7 +853,7 @@ static int tegra_nand_get_strength(struct nand_chip *chip, const int *strength,
                } else {
                        strength_sel = strength[i];
 
-                       if (strength_sel < chip->ecc_strength_ds)
+                       if (strength_sel < chip->base.eccreq.strength)
                                continue;
                }
 
@@ -917,9 +917,9 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
        chip->ecc.mode = NAND_ECC_HW;
        chip->ecc.size = 512;
        chip->ecc.steps = mtd->writesize / chip->ecc.size;
-       if (chip->ecc_step_ds != 512) {
+       if (chip->base.eccreq.step_size != 512) {
                dev_err(ctrl->dev, "Unsupported step size %d\n",
-                       chip->ecc_step_ds);
+                       chip->base.eccreq.step_size);
                return -EINVAL;
        }
 
@@ -950,7 +950,7 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
                if (ret < 0) {
                        dev_err(ctrl->dev,
                                "No valid strength found, minimum %d\n",
-                               chip->ecc_strength_ds);
+                               chip->base.eccreq.strength);
                        return ret;
                }
 
index a662ca1970e587d8f8460c879d9c774772a823dc..e4fe8c4bc71121e72d8aa9bd79f29b6d5178ea1e 100644 (file)
@@ -364,7 +364,7 @@ static int vf610_nfc_cmd(struct nand_chip *chip,
 {
        const struct nand_op_instr *instr;
        struct vf610_nfc *nfc = chip_to_nfc(chip);
-       int op_id = -1, trfr_sz = 0, offset;
+       int op_id = -1, trfr_sz = 0, offset = 0;
        u32 col = 0, row = 0, cmd1 = 0, cmd2 = 0, code = 0;
        bool force8bit = false;
 
@@ -850,6 +850,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)
        }
 
        of_id = of_match_device(vf610_nfc_dt_ids, &pdev->dev);
+       if (!of_id)
+               return -ENODEV;
+
        nfc->variant = (enum vf610_nfc_variant)of_id->data;
 
        for_each_available_child_of_node(nfc->dev->of_node, child) {
index fa87ae28cdfecd21fb6fb435fac35047a3b37325..4c15bb58c6238f87f823276ec7b6399068edf8ba 100644 (file)
 #include <linux/spi/spi.h>
 #include <linux/spi/spi-mem.h>
 
-static void spinand_cache_op_adjust_colum(struct spinand_device *spinand,
-                                         const struct nand_page_io_req *req,
-                                         u16 *column)
-{
-       struct nand_device *nand = spinand_to_nand(spinand);
-       unsigned int shift;
-
-       if (nand->memorg.planes_per_lun < 2)
-               return;
-
-       /* The plane number is passed in MSB just above the column address */
-       shift = fls(nand->memorg.pagesize);
-       *column |= req->pos.plane << shift;
-}
-
 static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
 {
        struct spi_mem_op op = SPINAND_GET_FEATURE_OP(reg,
@@ -227,27 +212,21 @@ static int spinand_load_page_op(struct spinand_device *spinand,
 static int spinand_read_from_cache_op(struct spinand_device *spinand,
                                      const struct nand_page_io_req *req)
 {
-       struct spi_mem_op op = *spinand->op_templates.read_cache;
        struct nand_device *nand = spinand_to_nand(spinand);
        struct mtd_info *mtd = nanddev_to_mtd(nand);
-       struct nand_page_io_req adjreq = *req;
+       struct spi_mem_dirmap_desc *rdesc;
        unsigned int nbytes = 0;
        void *buf = NULL;
        u16 column = 0;
-       int ret;
+       ssize_t ret;
 
        if (req->datalen) {
-               adjreq.datalen = nanddev_page_size(nand);
-               adjreq.dataoffs = 0;
-               adjreq.databuf.in = spinand->databuf;
                buf = spinand->databuf;
-               nbytes = adjreq.datalen;
+               nbytes = nanddev_page_size(nand);
+               column = 0;
        }
 
        if (req->ooblen) {
-               adjreq.ooblen = nanddev_per_page_oobsize(nand);
-               adjreq.ooboffs = 0;
-               adjreq.oobbuf.in = spinand->oobbuf;
                nbytes += nanddev_per_page_oobsize(nand);
                if (!buf) {
                        buf = spinand->oobbuf;
@@ -255,28 +234,19 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
                }
        }
 
-       spinand_cache_op_adjust_colum(spinand, &adjreq, &column);
-       op.addr.val = column;
+       rdesc = spinand->dirmaps[req->pos.plane].rdesc;
 
-       /*
-        * Some controllers are limited in term of max RX data size. In this
-        * case, just repeat the READ_CACHE operation after updating the
-        * column.
-        */
        while (nbytes) {
-               op.data.buf.in = buf;
-               op.data.nbytes = nbytes;
-               ret = spi_mem_adjust_op_size(spinand->spimem, &op);
-               if (ret)
+               ret = spi_mem_dirmap_read(rdesc, column, nbytes, buf);
+               if (ret < 0)
                        return ret;
 
-               ret = spi_mem_exec_op(spinand->spimem, &op);
-               if (ret)
-                       return ret;
+               if (!ret || ret > nbytes)
+                       return -EIO;
 
-               buf += op.data.nbytes;
-               nbytes -= op.data.nbytes;
-               op.addr.val += op.data.nbytes;
+               nbytes -= ret;
+               column += ret;
+               buf += ret;
        }
 
        if (req->datalen)
@@ -300,14 +270,12 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
 static int spinand_write_to_cache_op(struct spinand_device *spinand,
                                     const struct nand_page_io_req *req)
 {
-       struct spi_mem_op op = *spinand->op_templates.write_cache;
        struct nand_device *nand = spinand_to_nand(spinand);
        struct mtd_info *mtd = nanddev_to_mtd(nand);
-       struct nand_page_io_req adjreq = *req;
+       struct spi_mem_dirmap_desc *wdesc;
+       unsigned int nbytes, column = 0;
        void *buf = spinand->databuf;
-       unsigned int nbytes;
-       u16 column = 0;
-       int ret;
+       ssize_t ret;
 
        /*
         * Looks like PROGRAM LOAD (AKA write cache) does not necessarily reset
@@ -318,12 +286,6 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,
         */
        nbytes = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
        memset(spinand->databuf, 0xff, nbytes);
-       adjreq.dataoffs = 0;
-       adjreq.datalen = nanddev_page_size(nand);
-       adjreq.databuf.out = spinand->databuf;
-       adjreq.ooblen = nanddev_per_page_oobsize(nand);
-       adjreq.ooboffs = 0;
-       adjreq.oobbuf.out = spinand->oobbuf;
 
        if (req->datalen)
                memcpy(spinand->databuf + req->dataoffs, req->databuf.out,
@@ -340,42 +302,19 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,
                               req->ooblen);
        }
 
-       spinand_cache_op_adjust_colum(spinand, &adjreq, &column);
+       wdesc = spinand->dirmaps[req->pos.plane].wdesc;
 
-       op = *spinand->op_templates.write_cache;
-       op.addr.val = column;
-
-       /*
-        * Some controllers are limited in term of max TX data size. In this
-        * case, split the operation into one LOAD CACHE and one or more
-        * LOAD RANDOM CACHE.
-        */
        while (nbytes) {
-               op.data.buf.out = buf;
-               op.data.nbytes = nbytes;
-
-               ret = spi_mem_adjust_op_size(spinand->spimem, &op);
-               if (ret)
-                       return ret;
-
-               ret = spi_mem_exec_op(spinand->spimem, &op);
-               if (ret)
+               ret = spi_mem_dirmap_write(wdesc, column, nbytes, buf);
+               if (ret < 0)
                        return ret;
 
-               buf += op.data.nbytes;
-               nbytes -= op.data.nbytes;
-               op.addr.val += op.data.nbytes;
+               if (!ret || ret > nbytes)
+                       return -EIO;
 
-               /*
-                * We need to use the RANDOM LOAD CACHE operation if there's
-                * more than one iteration, because the LOAD operation might
-                * reset the cache to 0xff.
-                */
-               if (nbytes) {
-                       column = op.addr.val;
-                       op = *spinand->op_templates.update_cache;
-                       op.addr.val = column;
-               }
+               nbytes -= ret;
+               column += ret;
+               buf += ret;
        }
 
        return 0;
@@ -755,6 +694,59 @@ static int spinand_mtd_block_isreserved(struct mtd_info *mtd, loff_t offs)
        return ret;
 }
 
+static int spinand_create_dirmap(struct spinand_device *spinand,
+                                unsigned int plane)
+{
+       struct nand_device *nand = spinand_to_nand(spinand);
+       struct spi_mem_dirmap_info info = {
+               .length = nanddev_page_size(nand) +
+                         nanddev_per_page_oobsize(nand),
+       };
+       struct spi_mem_dirmap_desc *desc;
+
+       /* The plane number is passed in MSB just above the column address */
+       info.offset = plane << fls(nand->memorg.pagesize);
+
+       info.op_tmpl = *spinand->op_templates.update_cache;
+       desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
+                                         spinand->spimem, &info);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
+       spinand->dirmaps[plane].wdesc = desc;
+
+       info.op_tmpl = *spinand->op_templates.read_cache;
+       desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
+                                         spinand->spimem, &info);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
+       spinand->dirmaps[plane].rdesc = desc;
+
+       return 0;
+}
+
+static int spinand_create_dirmaps(struct spinand_device *spinand)
+{
+       struct nand_device *nand = spinand_to_nand(spinand);
+       int i, ret;
+
+       spinand->dirmaps = devm_kzalloc(&spinand->spimem->spi->dev,
+                                       sizeof(*spinand->dirmaps) *
+                                       nand->memorg.planes_per_lun,
+                                       GFP_KERNEL);
+       if (!spinand->dirmaps)
+               return -ENOMEM;
+
+       for (i = 0; i < nand->memorg.planes_per_lun; i++) {
+               ret = spinand_create_dirmap(spinand, i);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static const struct nand_ops spinand_ops = {
        .erase = spinand_erase,
        .markbad = spinand_markbad,
@@ -1012,6 +1004,14 @@ static int spinand_init(struct spinand_device *spinand)
                goto err_free_bufs;
        }
 
+       ret = spinand_create_dirmaps(spinand);
+       if (ret) {
+               dev_err(dev,
+                       "Failed to create direct mappings for read/write operations (err = %d)\n",
+                       ret);
+               goto err_manuf_cleanup;
+       }
+
        /* After power up, all blocks are locked, so unlock them here. */
        for (i = 0; i < nand->memorg.ntargets; i++) {
                ret = spinand_select_target(spinand, i);
@@ -1037,6 +1037,7 @@ static int spinand_init(struct spinand_device *spinand)
        mtd->_block_markbad = spinand_mtd_block_markbad;
        mtd->_block_isreserved = spinand_mtd_block_isreserved;
        mtd->_erase = spinand_mtd_erase;
+       mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks;
 
        if (spinand->eccinfo.ooblayout)
                mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout);
index 0b49d8264bef0989bb77ebea93b23bb69b648b48..e5586390026ae11f1151d92556c414450de2dad7 100644 (file)
@@ -162,7 +162,7 @@ static const struct mtd_ooblayout_ops gd5fxgq4uexxg_ooblayout = {
 
 static const struct spinand_info gigadevice_spinand_table[] = {
        SPINAND_INFO("GD5F1GQ4xA", 0xF1,
-                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -171,7 +171,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
                     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
                                     gd5fxgq4xa_ecc_get_status)),
        SPINAND_INFO("GD5F2GQ4xA", 0xF2,
-                    NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -180,7 +180,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
                     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
                                     gd5fxgq4xa_ecc_get_status)),
        SPINAND_INFO("GD5F4GQ4xA", 0xF4,
-                    NAND_MEMORG(1, 2048, 64, 64, 4096, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 4096, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -189,7 +189,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
                     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
                                     gd5fxgq4xa_ecc_get_status)),
        SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
index d16b57081c95ab376d9c89afc1fa1461d48eb1a4..6502727049a8f4fa9a0432849fc1c862e0f4f81c 100644 (file)
@@ -100,7 +100,7 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
 
 static const struct spinand_info macronix_spinand_table[] = {
        SPINAND_INFO("MX35LF1GE4AB", 0x12,
-                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 40, 1, 1, 1),
                     NAND_ECCREQ(4, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -109,7 +109,7 @@ static const struct spinand_info macronix_spinand_table[] = {
                     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
                                     mx35lf1ge4ab_ecc_get_status)),
        SPINAND_INFO("MX35LF2GE4AB", 0x22,
-                    NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 2048, 20, 2, 1, 1),
                     NAND_ECCREQ(4, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
index 9c4381d6847b34d225514a990ce1ff6cc5a82b39..7d7b1f7fcf71dc3be261b89af450a0ffffa5b5c5 100644 (file)
@@ -92,7 +92,7 @@ static int mt29f2g01abagd_ecc_get_status(struct spinand_device *spinand,
 
 static const struct spinand_info micron_spinand_table[] = {
        SPINAND_INFO("MT29F2G01ABAGD", 0x24,
-                    NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
index db8021da45b5052bffce19dd7e5e4fec7557096d..1cb3760ff779f95a09c3ed58afe039ca8205acfc 100644 (file)
@@ -96,7 +96,7 @@ static int tc58cxgxsx_ecc_get_status(struct spinand_device *spinand,
 static const struct spinand_info toshiba_spinand_table[] = {
        /* 3.3V 1Gb */
        SPINAND_INFO("TC58CVG0S3", 0xC2,
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -106,7 +106,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
                                     tc58cxgxsx_ecc_get_status)),
        /* 3.3V 2Gb */
        SPINAND_INFO("TC58CVG1S3", 0xCB,
-                    NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -116,7 +116,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
                                     tc58cxgxsx_ecc_get_status)),
        /* 3.3V 4Gb */
        SPINAND_INFO("TC58CVG2S0", 0xCD,
-                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -126,7 +126,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
                                     tc58cxgxsx_ecc_get_status)),
        /* 1.8V 1Gb */
        SPINAND_INFO("TC58CYG0S3", 0xB2,
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -136,7 +136,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
                                     tc58cxgxsx_ecc_get_status)),
        /* 1.8V 2Gb */
        SPINAND_INFO("TC58CYG1S3", 0xBB,
-                    NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -146,7 +146,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
                                     tc58cxgxsx_ecc_get_status)),
        /* 1.8V 4Gb */
        SPINAND_INFO("TC58CYG2S0", 0xBD,
-                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
index 5d944580b8981c22d583d375bbe314945d1b2aa0..a6c17e0cace851aa6adefea7f78e8d928a1332a7 100644 (file)
@@ -76,7 +76,7 @@ static int w25m02gv_select_target(struct spinand_device *spinand,
 
 static const struct spinand_info winbond_spinand_table[] = {
        SPINAND_INFO("W25M02GV", 0xAB,
-                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 2),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
                     NAND_ECCREQ(1, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -85,7 +85,7 @@ static const struct spinand_info winbond_spinand_table[] = {
                     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
                     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
        SPINAND_INFO("W25N01GV", 0xAA,
-                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(1, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
index fccf1950e92de1b6ac2baabd74daddc14c75acd0..bc201327dda0070e1bb6590abd8e87a0afb81bfa 100644 (file)
@@ -1,3 +1,30 @@
+config MTD_PARSER_IMAGETAG
+       tristate "Parser for BCM963XX Image Tag format partitions"
+       depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
+       select CRC32
+       help
+         Image Tag is the firmware header used by broadcom on their xDSL line
+         of devices. It is used to describe the offsets and lengths of kernel
+         and rootfs partitions.
+         This driver adds support for parsing a partition with an Image Tag
+         header and creates up to two partitions, kernel and rootfs.
+
+config MTD_AFS_PARTS
+       tristate "ARM Firmware Suite partition parsing"
+       depends on (ARM || ARM64)
+       help
+         The ARM Firmware Suite allows the user to divide flash devices into
+         multiple 'images'. Each such image has a header containing its name
+         and offset/size etc.
+
+         If you need code which can detect and parse these tables, and
+         register MTD 'partitions' corresponding to each image detected,
+         enable this option.
+
+         You will still need the parsing functions to be called by the driver
+         for your particular device. It won't happen automatically. The
+         'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example.
+
 config MTD_PARSER_TRX
        tristate "Parser for TRX format partitions"
        depends on MTD && (BCM47XX || ARCH_BCM_5301X || COMPILE_TEST)
index d8418bf6804a118884db8634721aa28fd10e7fcc..cddc8f35a856ef3a39ce8edebdc3fed048ce484e 100644 (file)
@@ -1,3 +1,5 @@
+obj-$(CONFIG_MTD_PARSER_IMAGETAG)      += parser_imagetag.o
+obj-$(CONFIG_MTD_AFS_PARTS)            += afs.o
 obj-$(CONFIG_MTD_PARSER_TRX)           += parser_trx.o
 obj-$(CONFIG_MTD_SHARPSL_PARTS)                += sharpslpart.o
 obj-$(CONFIG_MTD_REDBOOT_PARTS)                += redboot.o
diff --git a/drivers/mtd/parsers/afs.c b/drivers/mtd/parsers/afs.c
new file mode 100644 (file)
index 0000000..0c73002
--- /dev/null
@@ -0,0 +1,410 @@
+/*======================================================================
+
+    drivers/mtd/afs.c: ARM Flash Layout/Partitioning
+
+    Copyright © 2000 ARM Limited
+    Copyright (C) 2019 Linus Walleij
+
+   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.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+   This is access code for flashes using ARM's flash partitioning
+   standards.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#define AFSV1_FOOTER_MAGIC 0xA0FFFF9F
+#define AFSV2_FOOTER_MAGIC1 0x464C5348 /* "FLSH" */
+#define AFSV2_FOOTER_MAGIC2 0x464F4F54 /* "FOOT" */
+
+struct footer_v1 {
+       u32 image_info_base;    /* Address of first word of ImageFooter  */
+       u32 image_start;        /* Start of area reserved by this footer */
+       u32 signature;          /* 'Magic' number proves it's a footer   */
+       u32 type;               /* Area type: ARM Image, SIB, customer   */
+       u32 checksum;           /* Just this structure                   */
+};
+
+struct image_info_v1 {
+       u32 bootFlags;          /* Boot flags, compression etc.          */
+       u32 imageNumber;        /* Unique number, selects for boot etc.  */
+       u32 loadAddress;        /* Address program should be loaded to   */
+       u32 length;             /* Actual size of image                  */
+       u32 address;            /* Image is executed from here           */
+       char name[16];          /* Null terminated                       */
+       u32 headerBase;         /* Flash Address of any stripped header  */
+       u32 header_length;      /* Length of header in memory            */
+       u32 headerType;         /* AIF, RLF, s-record etc.               */
+       u32 checksum;           /* Image checksum (inc. this struct)     */
+};
+
+static u32 word_sum(void *words, int num)
+{
+       u32 *p = words;
+       u32 sum = 0;
+
+       while (num--)
+               sum += *p++;
+
+       return sum;
+}
+
+static u32 word_sum_v2(u32 *p, u32 num)
+{
+       u32 sum = 0;
+       int i;
+
+       for (i = 0; i < num; i++) {
+               u32 val;
+
+               val = p[i];
+               if (val > ~sum)
+                       sum++;
+               sum += val;
+       }
+       return ~sum;
+}
+
+static bool afs_is_v1(struct mtd_info *mtd, u_int off)
+{
+       /* The magic is 12 bytes from the end of the erase block */
+       u_int ptr = off + mtd->erasesize - 12;
+       u32 magic;
+       size_t sz;
+       int ret;
+
+       ret = mtd_read(mtd, ptr, 4, &sz, (u_char *)&magic);
+       if (ret < 0) {
+               printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
+                      ptr, ret);
+               return false;
+       }
+       if (ret >= 0 && sz != 4)
+               return false;
+
+       return (magic == AFSV1_FOOTER_MAGIC);
+}
+
+static bool afs_is_v2(struct mtd_info *mtd, u_int off)
+{
+       /* The magic is the 8 last bytes of the erase block */
+       u_int ptr = off + mtd->erasesize - 8;
+       u32 foot[2];
+       size_t sz;
+       int ret;
+
+       ret = mtd_read(mtd, ptr, 8, &sz, (u_char *)foot);
+       if (ret < 0) {
+               printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
+                      ptr, ret);
+               return false;
+       }
+       if (ret >= 0 && sz != 8)
+               return false;
+
+       return (foot[0] == AFSV2_FOOTER_MAGIC1 &&
+               foot[1] == AFSV2_FOOTER_MAGIC2);
+}
+
+static int afs_parse_v1_partition(struct mtd_info *mtd,
+                                 u_int off, struct mtd_partition *part)
+{
+       struct footer_v1 fs;
+       struct image_info_v1 iis;
+       u_int mask;
+       /*
+        * Static checks cannot see that we bail out if we have an error
+        * reading the footer.
+        */
+       u_int uninitialized_var(iis_ptr);
+       u_int uninitialized_var(img_ptr);
+       u_int ptr;
+       size_t sz;
+       int ret;
+       int i;
+
+       /*
+        * This is the address mask; we use this to mask off out of
+        * range address bits.
+        */
+       mask = mtd->size - 1;
+
+       ptr = off + mtd->erasesize - sizeof(fs);
+       ret = mtd_read(mtd, ptr, sizeof(fs), &sz, (u_char *)&fs);
+       if (ret >= 0 && sz != sizeof(fs))
+               ret = -EINVAL;
+       if (ret < 0) {
+               printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
+                      ptr, ret);
+               return ret;
+       }
+       /*
+        * Check the checksum.
+        */
+       if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff)
+               return -EINVAL;
+
+       /*
+        * Hide the SIB (System Information Block)
+        */
+       if (fs.type == 2)
+               return 0;
+
+       iis_ptr = fs.image_info_base & mask;
+       img_ptr = fs.image_start & mask;
+
+       /*
+        * Check the image info base.  This can not
+        * be located after the footer structure.
+        */
+       if (iis_ptr >= ptr)
+               return 0;
+
+       /*
+        * Check the start of this image.  The image
+        * data can not be located after this block.
+        */
+       if (img_ptr > off)
+               return 0;
+
+       /* Read the image info block */
+       memset(&iis, 0, sizeof(iis));
+       ret = mtd_read(mtd, iis_ptr, sizeof(iis), &sz, (u_char *)&iis);
+       if (ret < 0) {
+               printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
+                      iis_ptr, ret);
+               return -EINVAL;
+       }
+
+       if (sz != sizeof(iis))
+               return -EINVAL;
+
+       /*
+        * Validate the name - it must be NUL terminated.
+        */
+       for (i = 0; i < sizeof(iis.name); i++)
+               if (iis.name[i] == '\0')
+                       break;
+       if (i > sizeof(iis.name))
+               return -EINVAL;
+
+       part->name = kstrdup(iis.name, GFP_KERNEL);
+       if (!part->name)
+               return -ENOMEM;
+
+       part->size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1);
+       part->offset = img_ptr;
+       part->mask_flags = 0;
+
+       printk("  mtd: at 0x%08x, %5lluKiB, %8u, %s\n",
+              img_ptr, part->size / 1024,
+              iis.imageNumber, part->name);
+
+       return 0;
+}
+
+static int afs_parse_v2_partition(struct mtd_info *mtd,
+                                 u_int off, struct mtd_partition *part)
+{
+       u_int ptr;
+       u32 footer[12];
+       u32 imginfo[36];
+       char *name;
+       u32 version;
+       u32 entrypoint;
+       u32 attributes;
+       u32 region_count;
+       u32 block_start;
+       u32 block_end;
+       u32 crc;
+       size_t sz;
+       int ret;
+       int i;
+       int pad = 0;
+
+       pr_debug("Parsing v2 partition @%08x-%08x\n",
+                off, off + mtd->erasesize);
+
+       /* First read the footer */
+       ptr = off + mtd->erasesize - sizeof(footer);
+       ret = mtd_read(mtd, ptr, sizeof(footer), &sz, (u_char *)footer);
+       if ((ret < 0) || (ret >= 0 && sz != sizeof(footer))) {
+               pr_err("AFS: mtd read failed at 0x%x: %d\n",
+                      ptr, ret);
+               return -EIO;
+       }
+       name = (char *) &footer[0];
+       version = footer[9];
+       ptr = off + mtd->erasesize - sizeof(footer) - footer[8];
+
+       pr_debug("found image \"%s\", version %08x, info @%08x\n",
+                name, version, ptr);
+
+       /* Then read the image information */
+       ret = mtd_read(mtd, ptr, sizeof(imginfo), &sz, (u_char *)imginfo);
+       if ((ret < 0) || (ret >= 0 && sz != sizeof(imginfo))) {
+               pr_err("AFS: mtd read failed at 0x%x: %d\n",
+                      ptr, ret);
+               return -EIO;
+       }
+
+       /* 32bit platforms have 4 bytes padding */
+       crc = word_sum_v2(&imginfo[1], 34);
+       if (!crc) {
+               pr_debug("Padding 1 word (4 bytes)\n");
+               pad = 1;
+       } else {
+               /* 64bit platforms have 8 bytes padding */
+               crc = word_sum_v2(&imginfo[2], 34);
+               if (!crc) {
+                       pr_debug("Padding 2 words (8 bytes)\n");
+                       pad = 2;
+               }
+       }
+       if (crc) {
+               pr_err("AFS: bad checksum on v2 image info: %08x\n", crc);
+               return -EINVAL;
+       }
+       entrypoint = imginfo[pad];
+       attributes = imginfo[pad+1];
+       region_count = imginfo[pad+2];
+       block_start = imginfo[20];
+       block_end = imginfo[21];
+
+       pr_debug("image entry=%08x, attr=%08x, regions=%08x, "
+                "bs=%08x, be=%08x\n",
+                entrypoint, attributes, region_count,
+                block_start, block_end);
+
+       for (i = 0; i < region_count; i++) {
+               u32 region_load_addr = imginfo[pad + 3 + i*4];
+               u32 region_size = imginfo[pad + 4 + i*4];
+               u32 region_offset = imginfo[pad + 5 + i*4];
+               u32 region_start;
+               u32 region_end;
+
+               pr_debug("  region %d: address: %08x, size: %08x, "
+                        "offset: %08x\n",
+                        i,
+                        region_load_addr,
+                        region_size,
+                        region_offset);
+
+               region_start = off + region_offset;
+               region_end = region_start + region_size;
+               /* Align partition to end of erase block */
+               region_end += (mtd->erasesize - 1);
+               region_end &= ~(mtd->erasesize -1);
+               pr_debug("   partition start = %08x, partition end = %08x\n",
+                        region_start, region_end);
+
+               /* Create one partition per region */
+               part->name = kstrdup(name, GFP_KERNEL);
+               if (!part->name)
+                       return -ENOMEM;
+               part->offset = region_start;
+               part->size = region_end - region_start;
+               part->mask_flags = 0;
+       }
+
+       return 0;
+}
+
+static int parse_afs_partitions(struct mtd_info *mtd,
+                               const struct mtd_partition **pparts,
+                               struct mtd_part_parser_data *data)
+{
+       struct mtd_partition *parts;
+       u_int off, sz;
+       int ret = 0;
+       int i;
+
+       /* Count the partitions by looping over all erase blocks */
+       for (i = off = sz = 0; off < mtd->size; off += mtd->erasesize) {
+               if (afs_is_v1(mtd, off)) {
+                       sz += sizeof(struct mtd_partition);
+                       i += 1;
+               }
+               if (afs_is_v2(mtd, off)) {
+                       sz += sizeof(struct mtd_partition);
+                       i += 1;
+               }
+       }
+
+       if (!i)
+               return 0;
+
+       parts = kzalloc(sz, GFP_KERNEL);
+       if (!parts)
+               return -ENOMEM;
+
+       /*
+        * Identify the partitions
+        */
+       for (i = off = 0; off < mtd->size; off += mtd->erasesize) {
+               if (afs_is_v1(mtd, off)) {
+                       ret = afs_parse_v1_partition(mtd, off, &parts[i]);
+                       if (ret)
+                               goto out_free_parts;
+                       i++;
+               }
+               if (afs_is_v2(mtd, off)) {
+                       ret = afs_parse_v2_partition(mtd, off, &parts[i]);
+                       if (ret)
+                               goto out_free_parts;
+                       i++;
+               }
+       }
+
+       *pparts = parts;
+       return i;
+
+out_free_parts:
+       while (i >= 0) {
+               if (parts[i].name)
+                       kfree(parts[i].name);
+               i--;
+       }
+       kfree(parts);
+       *pparts = NULL;
+       return ret;
+}
+
+static const struct of_device_id mtd_parser_afs_of_match_table[] = {
+       { .compatible = "arm,arm-firmware-suite" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, mtd_parser_afs_of_match_table);
+
+static struct mtd_part_parser afs_parser = {
+       .parse_fn = parse_afs_partitions,
+       .name = "afs",
+       .of_match_table = mtd_parser_afs_of_match_table,
+};
+module_mtd_part_parser(afs_parser);
+
+MODULE_AUTHOR("ARM Ltd");
+MODULE_DESCRIPTION("ARM Firmware Suite partition parser");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/parsers/parser_imagetag.c b/drivers/mtd/parsers/parser_imagetag.c
new file mode 100644 (file)
index 0000000..9537c18
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * BCM63XX CFE image tag parser
+ *
+ * Copyright © 2006-2008  Florian Fainelli <florian@openwrt.org>
+ *                       Mike Albon <malbon@openwrt.org>
+ * Copyright © 2009-2010  Daniel Dickinson <openwrt@cshore.neomailbox.net>
+ * Copyright © 2011-2013  Jonas Gorski <jonas.gorski@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.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bcm963xx_tag.h>
+#include <linux/crc32.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+
+/* Ensure strings read from flash structs are null terminated */
+#define STR_NULL_TERMINATE(x) \
+       do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0)
+
+static int bcm963xx_read_imagetag(struct mtd_info *master, const char *name,
+       loff_t tag_offset, struct bcm_tag *buf)
+{
+       int ret;
+       size_t retlen;
+       u32 computed_crc;
+
+       ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf);
+       if (ret)
+               return ret;
+
+       if (retlen != sizeof(*buf))
+               return -EIO;
+
+       computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
+                               offsetof(struct bcm_tag, header_crc));
+       if (computed_crc == buf->header_crc) {
+               STR_NULL_TERMINATE(buf->board_id);
+               STR_NULL_TERMINATE(buf->tag_version);
+
+               pr_info("%s: CFE image tag found at 0x%llx with version %s, board type %s\n",
+                       name, tag_offset, buf->tag_version, buf->board_id);
+
+               return 0;
+       }
+
+       pr_warn("%s: CFE image tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n",
+               name, tag_offset, buf->header_crc, computed_crc);
+       return -EINVAL;
+}
+
+static int bcm963xx_parse_imagetag_partitions(struct mtd_info *master,
+                                       const struct mtd_partition **pparts,
+                                       struct mtd_part_parser_data *data)
+{
+       /* CFE, NVRAM and global Linux are always present */
+       int nrparts = 0, curpart = 0;
+       struct bcm_tag *buf = NULL;
+       struct mtd_partition *parts;
+       int ret;
+       unsigned int rootfsaddr, kerneladdr, spareaddr, offset;
+       unsigned int rootfslen, kernellen, sparelen, totallen;
+       int i;
+       bool rootfs_first = false;
+
+       buf = vmalloc(sizeof(struct bcm_tag));
+       if (!buf)
+               return -ENOMEM;
+
+       /* Get the tag */
+       ret = bcm963xx_read_imagetag(master, "rootfs", 0, buf);
+       if (!ret) {
+               STR_NULL_TERMINATE(buf->flash_image_start);
+               if (kstrtouint(buf->flash_image_start, 10, &rootfsaddr) ||
+                               rootfsaddr < BCM963XX_EXTENDED_SIZE) {
+                       pr_err("invalid rootfs address: %*ph\n",
+                               (int)sizeof(buf->flash_image_start),
+                               buf->flash_image_start);
+                       goto out;
+               }
+
+               STR_NULL_TERMINATE(buf->kernel_address);
+               if (kstrtouint(buf->kernel_address, 10, &kerneladdr) ||
+                               kerneladdr < BCM963XX_EXTENDED_SIZE) {
+                       pr_err("invalid kernel address: %*ph\n",
+                               (int)sizeof(buf->kernel_address),
+                               buf->kernel_address);
+                       goto out;
+               }
+
+               STR_NULL_TERMINATE(buf->kernel_length);
+               if (kstrtouint(buf->kernel_length, 10, &kernellen)) {
+                       pr_err("invalid kernel length: %*ph\n",
+                               (int)sizeof(buf->kernel_length),
+                               buf->kernel_length);
+                       goto out;
+               }
+
+               STR_NULL_TERMINATE(buf->total_length);
+               if (kstrtouint(buf->total_length, 10, &totallen)) {
+                       pr_err("invalid total length: %*ph\n",
+                               (int)sizeof(buf->total_length),
+                               buf->total_length);
+                       goto out;
+               }
+
+               /*
+                * Addresses are flash absolute, so convert to partition
+                * relative addresses. Assume either kernel or rootfs will
+                * directly follow the image tag.
+                */
+               if (rootfsaddr < kerneladdr)
+                       offset = rootfsaddr - sizeof(struct bcm_tag);
+               else
+                       offset = kerneladdr - sizeof(struct bcm_tag);
+
+               kerneladdr = kerneladdr - offset;
+               rootfsaddr = rootfsaddr - offset;
+               spareaddr = roundup(totallen, master->erasesize);
+
+               if (rootfsaddr < kerneladdr) {
+                       /* default Broadcom layout */
+                       rootfslen = kerneladdr - rootfsaddr;
+                       rootfs_first = true;
+               } else {
+                       /* OpenWrt layout */
+                       rootfsaddr = kerneladdr + kernellen;
+                       rootfslen = spareaddr - rootfsaddr;
+               }
+       } else {
+               goto out;
+       }
+       sparelen = master->size - spareaddr;
+
+       /* Determine number of partitions */
+       if (rootfslen > 0)
+               nrparts++;
+
+       if (kernellen > 0)
+               nrparts++;
+
+       parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
+       if (!parts) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* Start building partition list */
+       if (kernellen > 0) {
+               int kernelpart = curpart;
+
+               if (rootfslen > 0 && rootfs_first)
+                       kernelpart++;
+               parts[kernelpart].name = "kernel";
+               parts[kernelpart].offset = kerneladdr;
+               parts[kernelpart].size = kernellen;
+               curpart++;
+       }
+
+       if (rootfslen > 0) {
+               int rootfspart = curpart;
+
+               if (kernellen > 0 && rootfs_first)
+                       rootfspart--;
+               parts[rootfspart].name = "rootfs";
+               parts[rootfspart].offset = rootfsaddr;
+               parts[rootfspart].size = rootfslen;
+               if (sparelen > 0  && !rootfs_first)
+                       parts[rootfspart].size += sparelen;
+               curpart++;
+       }
+
+       for (i = 0; i < nrparts; i++)
+               pr_info("Partition %d is %s offset %llx and length %llx\n", i,
+                       parts[i].name, parts[i].offset, parts[i].size);
+
+       pr_info("Spare partition is offset %x and length %x\n", spareaddr,
+               sparelen);
+
+       *pparts = parts;
+       ret = 0;
+
+out:
+       vfree(buf);
+
+       if (ret)
+               return ret;
+
+       return nrparts;
+}
+
+static const struct of_device_id parse_bcm963xx_imagetag_match_table[] = {
+       { .compatible = "brcm,bcm963xx-imagetag" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, parse_bcm963xx_imagetag_match_table);
+
+static struct mtd_part_parser bcm963xx_imagetag_parser = {
+       .parse_fn = bcm963xx_parse_imagetag_partitions,
+       .name = "bcm963xx-imagetag",
+       .of_match_table = parse_bcm963xx_imagetag_match_table,
+};
+module_mtd_part_parser(bcm963xx_imagetag_parser);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>");
+MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
+MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>");
+MODULE_AUTHOR("Jonas Gorski <jonas.gorski@gmail.com>");
+MODULE_DESCRIPTION("MTD parser for BCM963XX CFE Image Tag partitions");
index 89227b1d036afd1ab8d51a26ab070f90c56687be..e0955a98a0f4f6ced80060062394b999708a4c2a 100644 (file)
@@ -222,17 +222,17 @@ static int sm_correct_sector(uint8_t *buffer, struct sm_oob *oob)
        uint8_t ecc[3];
 
        __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc,
-                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
        if (__nand_correct_data(buffer, ecc, oob->ecc1, SM_SMALL_PAGE,
-                               IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) < 0)
+                               IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)) < 0)
                return -EIO;
 
        buffer += SM_SMALL_PAGE;
 
        __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc,
-                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
        if (__nand_correct_data(buffer, ecc, oob->ecc2, SM_SMALL_PAGE,
-                               IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) < 0)
+                               IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)) < 0)
                return -EIO;
        return 0;
 }
@@ -399,11 +399,11 @@ restart:
                if (ftl->smallpagenand) {
                        __nand_calculate_ecc(buf + boffset, SM_SMALL_PAGE,
                                        oob.ecc1,
-                                       IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+                                       IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
 
                        __nand_calculate_ecc(buf + boffset + SM_SMALL_PAGE,
                                        SM_SMALL_PAGE, oob.ecc2,
-                                       IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+                                       IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
                }
                if (!sm_write_sector(ftl, zone, block, boffset,
                                                        buf + boffset, &oob))
index 872b409226081a5933f527371c36541eafa04970..bfbfc17ed6aa10f3c48018ada5d2d974394ab4ae 100644 (file)
@@ -63,6 +63,7 @@ static void intel_spi_pci_remove(struct pci_dev *pdev)
 }
 
 static const struct pci_device_id intel_spi_pci_ids[] = {
+       { PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&bxt_info },
        { PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info },
        { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
        { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
index af0a220195163ceaf9382e78acf12926494258ba..d60cbf23d9aa05e61f51b10c62e5a13ec32fb67e 100644 (file)
@@ -632,6 +632,10 @@ static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len,
        while (len > 0) {
                block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ);
 
+               /* Read cannot cross 4K boundary */
+               block_size = min_t(loff_t, from + block_size,
+                                  round_up(from + 1, SZ_4K)) - from;
+
                writel(from, ispi->base + FADDR);
 
                val = readl(ispi->base + HSFSTS_CTL);
@@ -685,6 +689,10 @@ static ssize_t intel_spi_write(struct spi_nor *nor, loff_t to, size_t len,
        while (len > 0) {
                block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ);
 
+               /* Write cannot cross 4K boundary */
+               block_size = min_t(loff_t, to + block_size,
+                                  round_up(to + 1, SZ_4K)) - to;
+
                writel(to, ispi->base + FADDR);
 
                val = readl(ispi->base + HSFSTS_CTL);
index fae147452aff34994a7bd562c2bc74d97b5c4046..73172d7f512bc0f3ef23454dcef9ef44a9869693 100644 (file)
@@ -744,7 +744,7 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
        u8 erase_mask = region->offset & SNOR_ERASE_TYPE_MASK;
 
        /*
-        * Erase types are ordered by size, with the biggest erase type at
+        * Erase types are ordered by size, with the smallest erase type at
         * index 0.
         */
        for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
@@ -1905,7 +1905,9 @@ static const struct flash_info spi_nor_ids[] = {
                        SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
        { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, USE_CLSR) },
        { "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
-       { "s25fl512s",  INFO6(0x010220, 0x4d0080, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
+       { "s25fl512s",  INFO6(0x010220, 0x4d0080, 256 * 1024, 256,
+                       SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+                       SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | USE_CLSR) },
        { "s25fs512s",  INFO6(0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
        { "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
        { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
@@ -2071,8 +2073,8 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
                                return &spi_nor_ids[tmp];
                }
        }
-       dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
-               id[0], id[1], id[2]);
+       dev_err(nor->dev, "unrecognized JEDEC id bytes: %*ph\n",
+               SPI_NOR_MAX_ID_LEN, id);
        return ERR_PTR(-ENODEV);
 }
 
index c71523e945806c1e2f9147a6971b67679932be70..73b06304c97576a46fc175344c69361e0620c5be 100644 (file)
@@ -21,7 +21,7 @@
  * or detected.
  */
 
-#if IS_ENABLED(CONFIG_MTD_NAND)
+#if IS_ENABLED(CONFIG_MTD_RAW_NAND)
 
 struct nand_ecc_test {
        const char *name;
@@ -122,9 +122,9 @@ static int no_bit_error_verify(void *error_data, void *error_ecc,
        int ret;
 
        __nand_calculate_ecc(error_data, size, calc_ecc,
-                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
        ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
-                                 IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+                                 IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
        if (ret == 0 && !memcmp(correct_data, error_data, size))
                return 0;
 
@@ -152,9 +152,9 @@ static int single_bit_error_correct(void *error_data, void *error_ecc,
        int ret;
 
        __nand_calculate_ecc(error_data, size, calc_ecc,
-                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
        ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
-                                 IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+                                 IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
        if (ret == 1 && !memcmp(correct_data, error_data, size))
                return 0;
 
@@ -189,9 +189,9 @@ static int double_bit_error_detect(void *error_data, void *error_ecc,
        int ret;
 
        __nand_calculate_ecc(error_data, size, calc_ecc,
-                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
        ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
-                                 IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+                                 IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
 
        return (ret == -EBADMSG) ? 0 : -EINVAL;
 }
@@ -266,7 +266,7 @@ static int nand_ecc_test_run(const size_t size)
 
        prandom_bytes(correct_data, size);
        __nand_calculate_ecc(correct_data, size, correct_ecc,
-                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
 
        for (i = 0; i < ARRAY_SIZE(nand_ecc_test); i++) {
                nand_ecc_test[i].prepare(error_data, error_ecc,
index 2709dc02fc249922578d9a8c4eb63369c90469d4..1f56c655832bec1fc3ab9f6a38a9a958ff58a355 100644 (file)
@@ -1475,7 +1475,7 @@ static bool scrub_possible(struct ubi_device *ubi, struct ubi_wl_entry *e)
  */
 int ubi_bitflip_check(struct ubi_device *ubi, int pnum, int force)
 {
-       int err;
+       int err = 0;
        struct ubi_wl_entry *e;
 
        if (pnum < 0 || pnum >= ubi->peb_count) {
index da1fc17295d950ee62523aa3eb235e071dfd6a09..b996967af8d9045c16f0446c7cc0bddffd941887 100644 (file)
@@ -1098,13 +1098,6 @@ static int bond_option_arp_validate_set(struct bonding *bond,
 {
        netdev_dbg(bond->dev, "Setting arp_validate to %s (%llu)\n",
                   newval->string, newval->value);
-
-       if (bond->dev->flags & IFF_UP) {
-               if (!newval->value)
-                       bond->recv_probe = NULL;
-               else if (bond->params.arp_interval)
-                       bond->recv_probe = bond_arp_rcv;
-       }
        bond->params.arp_validate = newval->value;
 
        return 0;
index 37ebd890ef519a9fdee51bf9cc5f8d0946d9e2e5..9e06dff619c333299eda915622f7c51179ed46ca 100644 (file)
@@ -871,7 +871,7 @@ static int emac_probe(struct platform_device *pdev)
        /* Read MAC-address from DT */
        mac_addr = of_get_mac_address(np);
        if (!IS_ERR(mac_addr))
-               memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
+               ether_addr_copy(ndev->dev_addr, mac_addr);
 
        /* Check if the MAC address is valid, if not get a random one */
        if (!is_valid_ether_addr(ndev->dev_addr)) {
index 7f89ad5c336d66d9676dac2f571ed02199ecd2df..13a1d99b29c6242796736202681f6611e652ffef 100644 (file)
@@ -961,7 +961,7 @@ int arc_emac_probe(struct net_device *ndev, int interface)
        mac_addr = of_get_mac_address(dev->of_node);
 
        if (!IS_ERR(mac_addr))
-               memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
+               ether_addr_copy(ndev->dev_addr, mac_addr);
        else
                eth_hw_addr_random(ndev);
 
index 15b1130aa4aee45602c3185d6e0c9df1610b1284..0e5de88fd6e8522ac0e35e9940d1d083f170c3ea 100644 (file)
@@ -1504,7 +1504,7 @@ static int octeon_mgmt_probe(struct platform_device *pdev)
        mac = of_get_mac_address(pdev->dev.of_node);
 
        if (!IS_ERR(mac))
-               memcpy(netdev->dev_addr, mac, ETH_ALEN);
+               ether_addr_copy(netdev->dev_addr, mac);
        else
                eth_hw_addr_random(netdev);
 
index e9a0213b08c4345357c9e746181ef98ca902cc74..6238e695133607e89f2fe94dea479978fc8a69c8 100644 (file)
@@ -41,7 +41,7 @@ config CS89x0_PLATFORM
 
 config EP93XX_ETH
        tristate "EP93xx Ethernet support"
-       depends on ARM && ARCH_EP93XX
+       depends on (ARM && ARCH_EP93XX) || COMPILE_TEST
        select MII
        help
          This is a driver for the ethernet hardware included in EP93xx CPUs.
index 13dfdfca49fc7816b8fb64c55d372b19370e4a7f..a6da9873570b64bc788716791491606a1d3cef2e 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 
-#include <mach/hardware.h>
+#include <linux/platform_data/eth-ep93xx.h>
 
 #define DRV_MODULE_NAME                "ep93xx-eth"
 #define DRV_MODULE_VERSION     "0.1"
index 953ee5616801113de773a3f6fc60a4773b92e133..5e1aff9a5fd6236026544852288e9cd70698f1dd 100644 (file)
@@ -1413,7 +1413,7 @@ static struct dm9000_plat_data *dm9000_parse_dt(struct device *dev)
 
        mac_addr = of_get_mac_address(np);
        if (!IS_ERR(mac_addr))
-               memcpy(pdata->dev_addr, mac_addr, sizeof(pdata->dev_addr));
+               ether_addr_copy(pdata->dev_addr, mac_addr);
 
        return pdata;
 }
index 7b7e526869a7f8c04b262e3408581df99fc709fe..30cdb246d0201cad12b2acbd99aef8681cefca64 100644 (file)
@@ -903,7 +903,7 @@ static int mpc52xx_fec_probe(struct platform_device *op)
         */
        mac_addr = of_get_mac_address(np);
        if (!IS_ERR(mac_addr)) {
-               memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
+               ether_addr_copy(ndev->dev_addr, mac_addr);
        } else {
                struct mpc52xx_fec __iomem *fec = priv->fec;
 
index 9cd2c28d17df93390d6b57481d14eb56da6cc3db..7ab8095db1928a68a36810161d644b0b0b60c260 100644 (file)
@@ -729,7 +729,7 @@ static int mac_probe(struct platform_device *_of_dev)
                err = -EINVAL;
                goto _return_of_get_parent;
        }
-       memcpy(mac_dev->addr, mac_addr, sizeof(mac_dev->addr));
+       ether_addr_copy(mac_dev->addr, mac_addr);
 
        /* Get the port handles */
        nph = of_count_phandle_with_args(mac_node, "fsl,fman-ports", NULL);
index 90ea7a115d0fb9a140d012551959bd943084873c..5fad73b2e12386763f3ef9797b00131956a5847f 100644 (file)
@@ -1015,7 +1015,7 @@ static int fs_enet_probe(struct platform_device *ofdev)
 
        mac_addr = of_get_mac_address(ofdev->dev.of_node);
        if (!IS_ERR(mac_addr))
-               memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
+               ether_addr_copy(ndev->dev_addr, mac_addr);
 
        ret = fep->ops->allocate_bd(ndev);
        if (ret)
index df13c693b03850b23c357b98997c3f29fff289cb..e670cd293dbab9db54daf51037ac13ea58c8d8c2 100644 (file)
@@ -873,7 +873,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
        mac_addr = of_get_mac_address(np);
 
        if (!IS_ERR(mac_addr))
-               memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
+               ether_addr_copy(dev->dev_addr, mac_addr);
 
        if (model && !strcasecmp(model, "TSEC"))
                priv->device_flags |= FSL_GIANFAR_DEV_HAS_GIGABIT |
index 216e99af2b5a1dc26d336240a76985a7d56c4c8c..4d6892d2f0a4bde9d09d61e7666a86ba1b71f78d 100644 (file)
@@ -3911,7 +3911,7 @@ static int ucc_geth_probe(struct platform_device* ofdev)
 
        mac_addr = of_get_mac_address(np);
        if (!IS_ERR(mac_addr))
-               memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
+               ether_addr_copy(dev->dev_addr, mac_addr);
 
        ugeth->ug_info = ug_info;
        ugeth->dev = device;
index b398d6c94dbdef34ce94e4de309ed34cd65f20cb..3dcd9c3d8781dec039e624c9ac9d32537cca230e 100644 (file)
@@ -118,7 +118,7 @@ static int init_sub_crq_irqs(struct ibmvnic_adapter *adapter);
 static int ibmvnic_init(struct ibmvnic_adapter *);
 static int ibmvnic_reset_init(struct ibmvnic_adapter *);
 static void release_crq_queue(struct ibmvnic_adapter *);
-static int __ibmvnic_set_mac(struct net_device *netdev, struct sockaddr *p);
+static int __ibmvnic_set_mac(struct net_device *, u8 *);
 static int init_crq_queue(struct ibmvnic_adapter *adapter);
 static int send_query_phys_parms(struct ibmvnic_adapter *adapter);
 
@@ -849,11 +849,7 @@ static int ibmvnic_login(struct net_device *netdev)
                }
        } while (retry);
 
-       /* handle pending MAC address changes after successful login */
-       if (adapter->mac_change_pending) {
-               __ibmvnic_set_mac(netdev, &adapter->desired.mac);
-               adapter->mac_change_pending = false;
-       }
+       __ibmvnic_set_mac(netdev, adapter->mac_addr);
 
        return 0;
 }
@@ -1115,7 +1111,6 @@ static int ibmvnic_open(struct net_device *netdev)
        }
 
        rc = __ibmvnic_open(netdev);
-       netif_carrier_on(netdev);
 
        return rc;
 }
@@ -1686,28 +1681,40 @@ static void ibmvnic_set_multi(struct net_device *netdev)
        }
 }
 
-static int __ibmvnic_set_mac(struct net_device *netdev, struct sockaddr *p)
+static int __ibmvnic_set_mac(struct net_device *netdev, u8 *dev_addr)
 {
        struct ibmvnic_adapter *adapter = netdev_priv(netdev);
-       struct sockaddr *addr = p;
        union ibmvnic_crq crq;
        int rc;
 
-       if (!is_valid_ether_addr(addr->sa_data))
-               return -EADDRNOTAVAIL;
+       if (!is_valid_ether_addr(dev_addr)) {
+               rc = -EADDRNOTAVAIL;
+               goto err;
+       }
 
        memset(&crq, 0, sizeof(crq));
        crq.change_mac_addr.first = IBMVNIC_CRQ_CMD;
        crq.change_mac_addr.cmd = CHANGE_MAC_ADDR;
-       ether_addr_copy(&crq.change_mac_addr.mac_addr[0], addr->sa_data);
+       ether_addr_copy(&crq.change_mac_addr.mac_addr[0], dev_addr);
 
        init_completion(&adapter->fw_done);
        rc = ibmvnic_send_crq(adapter, &crq);
-       if (rc)
-               return rc;
+       if (rc) {
+               rc = -EIO;
+               goto err;
+       }
+
        wait_for_completion(&adapter->fw_done);
        /* netdev->dev_addr is changed in handle_change_mac_rsp function */
-       return adapter->fw_done_rc ? -EIO : 0;
+       if (adapter->fw_done_rc) {
+               rc = -EIO;
+               goto err;
+       }
+
+       return 0;
+err:
+       ether_addr_copy(adapter->mac_addr, netdev->dev_addr);
+       return rc;
 }
 
 static int ibmvnic_set_mac(struct net_device *netdev, void *p)
@@ -1716,13 +1723,10 @@ static int ibmvnic_set_mac(struct net_device *netdev, void *p)
        struct sockaddr *addr = p;
        int rc;
 
-       if (adapter->state == VNIC_PROBED) {
-               memcpy(&adapter->desired.mac, addr, sizeof(struct sockaddr));
-               adapter->mac_change_pending = true;
-               return 0;
-       }
-
-       rc = __ibmvnic_set_mac(netdev, addr);
+       rc = 0;
+       ether_addr_copy(adapter->mac_addr, addr->sa_data);
+       if (adapter->state != VNIC_PROBED)
+               rc = __ibmvnic_set_mac(netdev, addr->sa_data);
 
        return rc;
 }
@@ -1859,8 +1863,6 @@ static int do_reset(struct ibmvnic_adapter *adapter,
            adapter->reset_reason != VNIC_RESET_CHANGE_PARAM)
                call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, netdev);
 
-       netif_carrier_on(netdev);
-
        return 0;
 }
 
@@ -1930,8 +1932,6 @@ static int do_hard_reset(struct ibmvnic_adapter *adapter,
                return 0;
        }
 
-       netif_carrier_on(netdev);
-
        return 0;
 }
 
@@ -3937,8 +3937,8 @@ static int handle_change_mac_rsp(union ibmvnic_crq *crq,
                dev_err(dev, "Error %ld in CHANGE_MAC_ADDR_RSP\n", rc);
                goto out;
        }
-       memcpy(netdev->dev_addr, &crq->change_mac_addr_rsp.mac_addr[0],
-              ETH_ALEN);
+       ether_addr_copy(netdev->dev_addr,
+                       &crq->change_mac_addr_rsp.mac_addr[0]);
 out:
        complete(&adapter->fw_done);
        return rc;
@@ -4475,6 +4475,10 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
                    crq->link_state_indication.phys_link_state;
                adapter->logical_link_state =
                    crq->link_state_indication.logical_link_state;
+               if (adapter->phys_link_state && adapter->logical_link_state)
+                       netif_carrier_on(netdev);
+               else
+                       netif_carrier_off(netdev);
                break;
        case CHANGE_MAC_ADDR_RSP:
                netdev_dbg(netdev, "Got MAC address change Response\n");
@@ -4852,8 +4856,6 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
        init_completion(&adapter->init_done);
        adapter->resetting = false;
 
-       adapter->mac_change_pending = false;
-
        do {
                rc = init_crq_queue(adapter);
                if (rc) {
index cffdac372a33d7b3b2fc7282cec520626c6940de..dcf2eb6d92901721e4a24c25812ab7ffb2bab029 100644 (file)
@@ -969,7 +969,6 @@ struct ibmvnic_tunables {
        u64 rx_entries;
        u64 tx_entries;
        u64 mtu;
-       struct sockaddr mac;
 };
 
 struct ibmvnic_adapter {
@@ -1091,7 +1090,6 @@ struct ibmvnic_adapter {
        bool resetting;
        bool napi_enabled, from_passive_init;
 
-       bool mac_change_pending;
        bool failover_pending;
        bool force_reset_recovery;
 
index 07e254fc96effec9428f5247ebcaf6b222476d3f..409b69fd43742a590135195cb79ce072fc3517c3 100644 (file)
@@ -2750,7 +2750,7 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
 
        mac_addr = of_get_mac_address(pnp);
        if (!IS_ERR(mac_addr))
-               memcpy(ppd.mac_addr, mac_addr, ETH_ALEN);
+               ether_addr_copy(ppd.mac_addr, mac_addr);
 
        mv643xx_eth_property(pnp, "tx-queue-size", ppd.tx_queue_size);
        mv643xx_eth_property(pnp, "tx-sram-addr", ppd.tx_sram_addr);
index 8186135883ed965f62ec76586649c3eafb63786f..e758650b2c26e29fc7f5df3ae4e49e7111ec39ed 100644 (file)
@@ -4565,7 +4565,7 @@ static int mvneta_probe(struct platform_device *pdev)
        dt_mac_addr = of_get_mac_address(dn);
        if (!IS_ERR(dt_mac_addr)) {
                mac_from = "device tree";
-               memcpy(dev->dev_addr, dt_mac_addr, ETH_ALEN);
+               ether_addr_copy(dev->dev_addr, dt_mac_addr);
        } else {
                mvneta_get_mac_addr(pp, hw_mac_addr);
                if (is_valid_ether_addr(hw_mac_addr)) {
index 56d43d9b43eff9a0cdaa474be9421e9a77a75b28..d38952eb7aa98ea460d6911d8e769b36bf00a97c 100644 (file)
@@ -5058,8 +5058,10 @@ static int mvpp2_port_probe(struct platform_device *pdev,
        dev->hw_features |= features | NETIF_F_RXCSUM | NETIF_F_GRO |
                            NETIF_F_HW_VLAN_CTAG_FILTER;
 
-       if (mvpp22_rss_is_supported())
+       if (mvpp22_rss_is_supported()) {
                dev->hw_features |= NETIF_F_RXHASH;
+               dev->features |= NETIF_F_NTUPLE;
+       }
 
        if (port->pool_long->id == MVPP2_BM_JUMBO && port->id != 0) {
                dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
index 9d070cca3e9eb000925802b4ed6ff0cc95879d55..5adf307fbbfd3656c1664d95fa645b2864517e5e 100644 (file)
@@ -4805,7 +4805,7 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port,
         */
        iap = of_get_mac_address(hw->pdev->dev.of_node);
        if (!IS_ERR(iap))
-               memcpy(dev->dev_addr, iap, ETH_ALEN);
+               ether_addr_copy(dev->dev_addr, iap);
        else
                memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8,
                              ETH_ALEN);
index 5aac97847721a9f337c21fd30880fdd53efd85f5..23883d1fa22f4d5d1da4ab907c2f8c7369a564f1 100644 (file)
@@ -291,6 +291,9 @@ create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, const char *name,
        mlx5_fill_page_array(&eq->buf, pas);
 
        MLX5_SET(create_eq_in, in, opcode, MLX5_CMD_OP_CREATE_EQ);
+       if (!param->mask && MLX5_CAP_GEN(dev, log_max_uctx))
+               MLX5_SET(create_eq_in, in, uid, MLX5_SHARED_RESOURCE_UID);
+
        MLX5_SET64(create_eq_in, in, event_bitmask, param->mask);
 
        eqc = MLX5_ADDR_OF(create_eq_in, in, eq_context_entry);
index b6b3ff0fe17f5c4e3a2c3f1460e6da57da4b79d8..7ccb950aa7d4aa30f4b4adf3248488201fecb023 100644 (file)
@@ -22,7 +22,6 @@ config MLXSW_CORE_HWMON
 config MLXSW_CORE_THERMAL
        bool "Thermal zone support for Mellanox Technologies Switch ASICs"
        depends on MLXSW_CORE && THERMAL
-       depends on !(MLXSW_CORE=y && THERMAL=m)
        default y
        ---help---
         Say Y here if you want to automatically control fans speed according
index b44172a901edbeb5e899c8c9642cd1c84fbca1e3..ba4fdf1b0dea4f114bc0f882c8a1e03cb6a87f85 100644 (file)
@@ -426,7 +426,7 @@ static void ks8851_init_mac(struct ks8851_net *ks)
 
        mac_addr = of_get_mac_address(ks->spidev->dev.of_node);
        if (!IS_ERR(mac_addr)) {
-               memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
+               ether_addr_copy(dev->dev_addr, mac_addr);
                ks8851_write_mac_addr(dev);
                return;
        }
index dc76b0d152348bfb6b95abad8ef2f36e11d64c35..e5c8412c08c1da3633f687f6ecd716d3ea057591 100644 (file)
@@ -1328,7 +1328,7 @@ static int ks8851_probe(struct platform_device *pdev)
        if (pdev->dev.of_node) {
                mac = of_get_mac_address(pdev->dev.of_node);
                if (!IS_ERR(mac))
-                       memcpy(ks->mac_addr, mac, ETH_ALEN);
+                       ether_addr_copy(ks->mac_addr, mac);
        } else {
                struct ks8851_mll_platform_data *pdata;
 
index da138edddd3256905741ff146db7967429ec3ab1..fec604c4c0d3b06c81a76ccdc6591f2a3dada6b6 100644 (file)
@@ -1369,7 +1369,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
        if (!is_valid_ether_addr(ndev->dev_addr)) {
                const char *macaddr = of_get_mac_address(np);
                if (!IS_ERR(macaddr))
-                       memcpy(ndev->dev_addr, macaddr, ETH_ALEN);
+                       ether_addr_copy(ndev->dev_addr, macaddr);
        }
        if (!is_valid_ether_addr(ndev->dev_addr))
                eth_hw_addr_random(ndev);
index 549be1c76a899e1e9d2d182beeef73ad8b77a83b..2e20334b76a1b572c0382b1e0ecfb38b30c1e555 100644 (file)
@@ -6992,8 +6992,7 @@ static int r8169_mdio_register(struct rtl8169_private *tp)
        new_bus->priv = tp;
        new_bus->parent = &pdev->dev;
        new_bus->irq[0] = PHY_IGNORE_INTERRUPT;
-       snprintf(new_bus->id, MII_BUS_ID_SIZE, "r8169-%x",
-                PCI_DEVID(pdev->bus->number, pdev->devfn));
+       snprintf(new_bus->id, MII_BUS_ID_SIZE, "r8169-%x", pci_dev_id(pdev));
 
        new_bus->read = r8169_mdio_read_reg;
        new_bus->write = r8169_mdio_write_reg;
index 7c4e282242d56cbd9f92c6b0b3289b1cffc8fae2..6354f19a31ebe579068226323734236bac6e465b 100644 (file)
@@ -3193,7 +3193,7 @@ static struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev)
 
        mac_addr = of_get_mac_address(np);
        if (!IS_ERR(mac_addr))
-               memcpy(pdata->mac_addr, mac_addr, ETH_ALEN);
+               ether_addr_copy(pdata->mac_addr, mac_addr);
 
        pdata->no_ether_link =
                of_property_read_bool(np, "renesas,no-ether-link");
index 70cce63a6081698169f5737d7eda9c4d3fc069fe..696037d5ac3d5a3ecebb6aaa924ca70da02a4bf5 100644 (file)
@@ -735,6 +735,7 @@ static int sgiseeq_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, dev);
+       SET_NETDEV_DEV(dev, &pdev->dev);
        sp = netdev_priv(dev);
 
        /* Make private data page aligned */
index 5b3b06a0a3bf53e1eac9572ae8d14add0c3835e7..d466e33635b0cadf19fe1e4bc56dc4ac152fe01b 100644 (file)
@@ -15,7 +15,7 @@
  * Adopted from dwmac-sti.c
  */
 
-#include <linux/mfd/syscon.h>
+#include <linux/mfd/altera-sysmgr.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_net.h>
@@ -114,7 +114,8 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
 
        dwmac->interface = of_get_phy_mode(np);
 
-       sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon");
+       sys_mgr_base_addr =
+               altr_sysmgr_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon");
        if (IS_ERR(sys_mgr_base_addr)) {
                dev_info(dev, "No sysmgr-syscon node found\n");
                return PTR_ERR(sys_mgr_base_addr);
index 195669f550f02e7f81cdc5dc6b807d8cbf0a8435..ba124a4da79380a01ffe177a609ec7b9580478d6 100644 (file)
@@ -1015,6 +1015,8 @@ static struct mac_device_info *sun8i_dwmac_setup(void *ppriv)
        mac->mac = &sun8i_dwmac_ops;
        mac->dma = &sun8i_dwmac_dma_ops;
 
+       priv->dev->priv_flags |= IFF_UNICAST_FLT;
+
        /* The loopback bit seems to be re-set when link change
         * Simply mask it each time
         * Speed 10/100/1000 are set in BIT(2)/BIT(3)
index 26db6aa002d1975adf3e07bbc3936a2d4c43ef87..7cbc01f316facf363e68a6623ea41aaef8e02a4e 100644 (file)
@@ -208,7 +208,7 @@ static int quark_default_data(struct pci_dev *pdev,
                ret = 1;
        }
 
-       plat->bus_id = PCI_DEVID(pdev->bus->number, pdev->devfn);
+       plat->bus_id = pci_dev_id(pdev);
        plat->phy_addr = ret;
        plat->interface = PHY_INTERFACE_MODE_RMII;
 
index c3f53a40b48f20168fd9e98935ca10ab504ab8b7..ed12e1e5df2f66cd781f1cc3eb5148937fa630d5 100644 (file)
@@ -19,4 +19,4 @@ ti_cpsw-y := cpsw.o davinci_cpdma.o cpsw_ale.o cpsw_priv.o cpsw_sl.o cpsw_ethtoo
 obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o
 keystone_netcp-y := netcp_core.o cpsw_ale.o
 obj-$(CONFIG_TI_KEYSTONE_NETCP_ETHSS) += keystone_netcp_ethss.o
-keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o
+keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o cpsw_ale.o
index b18eeb05b9930feb23d563767b2ef272891406ea..634fc484a0b373bf870352224f61f20c2241b272 100644 (file)
@@ -2233,7 +2233,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
 no_phy_slave:
                mac_addr = of_get_mac_address(slave_node);
                if (!IS_ERR(mac_addr)) {
-                       memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
+                       ether_addr_copy(slave_data->mac_addr, mac_addr);
                } else {
                        ret = ti_cm_get_macid(&pdev->dev, i,
                                              slave_data->mac_addr);
index 997475c209c0da05d762b900a916b4ffdafad830..47c45152132ee2bc4519f24de9971da36b1dd263 100644 (file)
@@ -361,7 +361,7 @@ static void temac_do_set_mac_address(struct net_device *ndev)
 
 static int temac_init_mac_address(struct net_device *ndev, const void *address)
 {
-       memcpy(ndev->dev_addr, address, ETH_ALEN);
+       ether_addr_copy(ndev->dev_addr, address);
        if (!is_valid_ether_addr(ndev->dev_addr))
                eth_hw_addr_random(ndev);
        temac_do_set_mac_address(ndev);
index 69117075356327aa9904dc26f2ab8064dd9dd3fb..6886270da695925b0c5155ef8bdd66221d927e7f 100644 (file)
@@ -1167,7 +1167,7 @@ static int xemaclite_of_probe(struct platform_device *ofdev)
 
        if (!IS_ERR(mac_address)) {
                /* Set the MAC address. */
-               memcpy(ndev->dev_addr, mac_address, ETH_ALEN);
+               ether_addr_copy(ndev->dev_addr, mac_address);
        } else {
                dev_warn(dev, "No MAC address found, using random\n");
                eth_hw_addr_random(ndev);
index ed6623a9801e4c42916d1d32f399cc96bdec0547..319db3ece263d3925008007ee19aa2dc4da201e5 100644 (file)
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/net_tstamp.h>
+#include <linux/of.h>
 #include <linux/phy.h>
 #include <linux/platform_device.h>
 #include <linux/ptp_classify.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <mach/ixp46x_ts.h>
-#include <mach/npe.h>
-#include <mach/qmgr.h>
+#include <linux/soc/ixp4xx/npe.h>
+#include <linux/soc/ixp4xx/qmgr.h>
 
 #define DEBUG_DESC             0
 #define DEBUG_RX               0
@@ -1497,6 +1498,15 @@ static struct platform_driver ixp4xx_eth_driver = {
 static int __init eth_init_module(void)
 {
        int err;
+
+       /*
+        * FIXME: we bail out on device tree boot but this really needs
+        * to be fixed in a nicer way: this registers the MDIO bus before
+        * even matching the driver infrastructure, we should only probe
+        * detected hardware.
+        */
+       if (of_have_populated_dt())
+               return -ENODEV;
        if ((err = ixp4xx_mdio_register()))
                return err;
        return platform_driver_register(&ixp4xx_eth_driver);
index b2ff903a9cb6e56a47814be2559589b73325302a..b188fce3f6410edf3e3a2d3f375c86cfe1b84bba 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/ieee802154.h>
+#include <linux/io.h>
 #include <linux/kfifo.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
index 6fa29ea8e2a363f99d45eae647d78025eb831baf..6644762ff2abb39b05baa98bd80046ddc250000f 100644 (file)
@@ -33,7 +33,7 @@
 #define ETH_PLL_CTL7           0x60
 
 #define ETH_PHY_CNTL0          0x80
-#define   EPHY_G12A_ID         0x33000180
+#define   EPHY_G12A_ID         0x33010180
 #define ETH_PHY_CNTL1          0x84
 #define  PHY_CNTL1_ST_MODE     GENMASK(2, 0)
 #define  PHY_CNTL1_ST_PHYADD   GENMASK(7, 3)
index 761ce3b1e7bdba4687ef62d8c33151a99e78f5ac..a669945eb829aea82e59dd7314d1794b7cef220d 100644 (file)
@@ -217,12 +217,12 @@ static int rtl8211e_config_init(struct phy_device *phydev)
        if (oldpage < 0)
                goto err_restore_page;
 
-       ret = phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4);
+       ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4);
        if (ret)
                goto err_restore_page;
 
-       ret = phy_modify(phydev, 0x1c, RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
-                        val);
+       ret = __phy_modify(phydev, 0x1c, RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
+                          val);
 
 err_restore_page:
        return phy_restore_page(phydev, oldpage, ret);
@@ -275,6 +275,8 @@ static struct phy_driver realtek_drvs[] = {
                .config_aneg    = rtl8211_config_aneg,
                .read_mmd       = &genphy_read_mmd_unsupported,
                .write_mmd      = &genphy_write_mmd_unsupported,
+               .read_page      = rtl821x_read_page,
+               .write_page     = rtl821x_write_page,
        }, {
                PHY_ID_MATCH_EXACT(0x001cc912),
                .name           = "RTL8211B Gigabit Ethernet",
@@ -284,12 +286,16 @@ static struct phy_driver realtek_drvs[] = {
                .write_mmd      = &genphy_write_mmd_unsupported,
                .suspend        = rtl8211b_suspend,
                .resume         = rtl8211b_resume,
+               .read_page      = rtl821x_read_page,
+               .write_page     = rtl821x_write_page,
        }, {
                PHY_ID_MATCH_EXACT(0x001cc913),
                .name           = "RTL8211C Gigabit Ethernet",
                .config_init    = rtl8211c_config_init,
                .read_mmd       = &genphy_read_mmd_unsupported,
                .write_mmd      = &genphy_write_mmd_unsupported,
+               .read_page      = rtl821x_read_page,
+               .write_page     = rtl821x_write_page,
        }, {
                PHY_ID_MATCH_EXACT(0x001cc914),
                .name           = "RTL8211DN Gigabit Ethernet",
@@ -297,6 +303,8 @@ static struct phy_driver realtek_drvs[] = {
                .config_intr    = rtl8211e_config_intr,
                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
+               .read_page      = rtl821x_read_page,
+               .write_page     = rtl821x_write_page,
        }, {
                PHY_ID_MATCH_EXACT(0x001cc915),
                .name           = "RTL8211E Gigabit Ethernet",
@@ -305,6 +313,8 @@ static struct phy_driver realtek_drvs[] = {
                .config_intr    = &rtl8211e_config_intr,
                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
+               .read_page      = rtl821x_read_page,
+               .write_page     = rtl821x_write_page,
        }, {
                PHY_ID_MATCH_EXACT(0x001cc916),
                .name           = "RTL8211F Gigabit Ethernet",
index 5c60dc60a8e6f93ef158cb12fc966453548d5abd..46a05b6540b8d94701ecb2dfe502d5cefd8a1aee 100644 (file)
@@ -22,8 +22,8 @@
 #include <linux/platform_device.h>
 #include <linux/poll.h>
 #include <linux/slab.h>
-#include <mach/npe.h>
-#include <mach/qmgr.h>
+#include <linux/soc/ixp4xx/npe.h>
+#include <linux/soc/ixp4xx/qmgr.h>
 
 #define DEBUG_DESC             0
 #define DEBUG_RX               0
index 04964937a3af24c544b969c3791dd64f44e3d62e..b7a49ae6b3277e14b23543a93a4578ff80a488fe 100644 (file)
@@ -95,7 +95,7 @@ mt76_eeprom_override(struct mt76_dev *dev)
 
        mac = of_get_mac_address(np);
        if (!IS_ERR(mac))
-               memcpy(dev->macaddr, mac, ETH_ALEN);
+               ether_addr_copy(dev->macaddr, mac);
 #endif
 
        if (!is_valid_ether_addr(dev->macaddr)) {
index f3d753d3169cb4487de3ed9007a53a02cf70a8f2..2030805aa216cf6b7d4acb630737dce69de27349 100644 (file)
@@ -756,6 +756,17 @@ static const guid_t *to_abstraction_guid(enum nvdimm_claim_class claim_class,
                return &guid_null;
 }
 
+static void reap_victim(struct nd_mapping *nd_mapping,
+               struct nd_label_ent *victim)
+{
+       struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
+       u32 slot = to_slot(ndd, victim->label);
+
+       dev_dbg(ndd->dev, "free: %d\n", slot);
+       nd_label_free_slot(ndd, slot);
+       victim->label = NULL;
+}
+
 static int __pmem_label_update(struct nd_region *nd_region,
                struct nd_mapping *nd_mapping, struct nd_namespace_pmem *nspm,
                int pos, unsigned long flags)
@@ -763,9 +774,9 @@ static int __pmem_label_update(struct nd_region *nd_region,
        struct nd_namespace_common *ndns = &nspm->nsio.common;
        struct nd_interleave_set *nd_set = nd_region->nd_set;
        struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
-       struct nd_label_ent *label_ent, *victim = NULL;
        struct nd_namespace_label *nd_label;
        struct nd_namespace_index *nsindex;
+       struct nd_label_ent *label_ent;
        struct nd_label_id label_id;
        struct resource *res;
        unsigned long *free;
@@ -834,18 +845,10 @@ static int __pmem_label_update(struct nd_region *nd_region,
        list_for_each_entry(label_ent, &nd_mapping->labels, list) {
                if (!label_ent->label)
                        continue;
-               if (memcmp(nspm->uuid, label_ent->label->uuid,
-                                       NSLABEL_UUID_LEN) != 0)
-                       continue;
-               victim = label_ent;
-               list_move_tail(&victim->list, &nd_mapping->labels);
-               break;
-       }
-       if (victim) {
-               dev_dbg(ndd->dev, "free: %d\n", slot);
-               slot = to_slot(ndd, victim->label);
-               nd_label_free_slot(ndd, slot);
-               victim->label = NULL;
+               if (test_and_clear_bit(ND_LABEL_REAP, &label_ent->flags)
+                               || memcmp(nspm->uuid, label_ent->label->uuid,
+                                       NSLABEL_UUID_LEN) == 0)
+                       reap_victim(nd_mapping, label_ent);
        }
 
        /* update index */
index f293556cbbf6d747004b132a23c440296ec760f7..d0214644e3341d90d38f41589d3d58921dc1b8fd 100644 (file)
@@ -1247,12 +1247,27 @@ static int namespace_update_uuid(struct nd_region *nd_region,
        for (i = 0; i < nd_region->ndr_mappings; i++) {
                struct nd_mapping *nd_mapping = &nd_region->mapping[i];
                struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
+               struct nd_label_ent *label_ent;
                struct resource *res;
 
                for_each_dpa_resource(ndd, res)
                        if (strcmp(res->name, old_label_id.id) == 0)
                                sprintf((void *) res->name, "%s",
                                                new_label_id.id);
+
+               mutex_lock(&nd_mapping->lock);
+               list_for_each_entry(label_ent, &nd_mapping->labels, list) {
+                       struct nd_namespace_label *nd_label = label_ent->label;
+                       struct nd_label_id label_id;
+
+                       if (!nd_label)
+                               continue;
+                       nd_label_gen_id(&label_id, nd_label->uuid,
+                                       __le32_to_cpu(nd_label->flags));
+                       if (strcmp(old_label_id.id, label_id.id) == 0)
+                               set_bit(ND_LABEL_REAP, &label_ent->flags);
+               }
+               mutex_unlock(&nd_mapping->lock);
        }
        kfree(*old_uuid);
  out:
index a5ac3b240293b3567a6295b3e7488c35d4ab0bd2..191d62af0e5148cbccc6ac1b36ebc3c85b79324d 100644 (file)
@@ -113,8 +113,12 @@ struct nd_percpu_lane {
        spinlock_t lock;
 };
 
+enum nd_label_flags {
+       ND_LABEL_REAP,
+};
 struct nd_label_ent {
        struct list_head list;
+       unsigned long flags;
        struct nd_namespace_label *label;
 };
 
index a6644a2c3ef70a41f0acd010a664bddb1cae699c..7da80f3753156d90af62e1eab21b9c351d4efe30 100644 (file)
@@ -1257,10 +1257,9 @@ static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
                return 0;
        }
 
+       effects |= nvme_known_admin_effects(opcode);
        if (ctrl->effects)
                effects = le32_to_cpu(ctrl->effects->acs[opcode]);
-       else
-               effects = nvme_known_admin_effects(opcode);
 
        /*
         * For simplicity, IO to all namespaces is quiesced even if the command
@@ -2342,20 +2341,35 @@ static const struct attribute_group *nvme_subsys_attrs_groups[] = {
        NULL,
 };
 
-static int nvme_active_ctrls(struct nvme_subsystem *subsys)
+static bool nvme_validate_cntlid(struct nvme_subsystem *subsys,
+               struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
 {
-       int count = 0;
-       struct nvme_ctrl *ctrl;
+       struct nvme_ctrl *tmp;
+
+       lockdep_assert_held(&nvme_subsystems_lock);
+
+       list_for_each_entry(tmp, &subsys->ctrls, subsys_entry) {
+               if (ctrl->state == NVME_CTRL_DELETING ||
+                   ctrl->state == NVME_CTRL_DEAD)
+                       continue;
+
+               if (tmp->cntlid == ctrl->cntlid) {
+                       dev_err(ctrl->device,
+                               "Duplicate cntlid %u with %s, rejecting\n",
+                               ctrl->cntlid, dev_name(tmp->device));
+                       return false;
+               }
 
-       mutex_lock(&subsys->lock);
-       list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) {
-               if (ctrl->state != NVME_CTRL_DELETING &&
-                   ctrl->state != NVME_CTRL_DEAD)
-                       count++;
+               if ((id->cmic & (1 << 1)) ||
+                   (ctrl->opts && ctrl->opts->discovery_nqn))
+                       continue;
+
+               dev_err(ctrl->device,
+                       "Subsystem does not support multiple controllers\n");
+               return false;
        }
-       mutex_unlock(&subsys->lock);
 
-       return count;
+       return true;
 }
 
 static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
@@ -2395,22 +2409,13 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
        mutex_lock(&nvme_subsystems_lock);
        found = __nvme_find_get_subsystem(subsys->subnqn);
        if (found) {
-               /*
-                * Verify that the subsystem actually supports multiple
-                * controllers, else bail out.
-                */
-               if (!(ctrl->opts && ctrl->opts->discovery_nqn) &&
-                   nvme_active_ctrls(found) && !(id->cmic & (1 << 1))) {
-                       dev_err(ctrl->device,
-                               "ignoring ctrl due to duplicate subnqn (%s).\n",
-                               found->subnqn);
-                       nvme_put_subsystem(found);
-                       ret = -EINVAL;
-                       goto out_unlock;
-               }
-
                __nvme_release_subsystem(subsys);
                subsys = found;
+
+               if (!nvme_validate_cntlid(subsys, ctrl, id)) {
+                       ret = -EINVAL;
+                       goto out_put_subsystem;
+               }
        } else {
                ret = device_add(&subsys->dev);
                if (ret) {
@@ -2422,23 +2427,20 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
                list_add_tail(&subsys->entry, &nvme_subsystems);
        }
 
-       ctrl->subsys = subsys;
-       mutex_unlock(&nvme_subsystems_lock);
-
        if (sysfs_create_link(&subsys->dev.kobj, &ctrl->device->kobj,
                        dev_name(ctrl->device))) {
                dev_err(ctrl->device,
                        "failed to create sysfs link from subsystem.\n");
-               /* the transport driver will eventually put the subsystem */
-               return -EINVAL;
+               goto out_put_subsystem;
        }
 
-       mutex_lock(&subsys->lock);
+       ctrl->subsys = subsys;
        list_add_tail(&ctrl->subsys_entry, &subsys->ctrls);
-       mutex_unlock(&subsys->lock);
-
+       mutex_unlock(&nvme_subsystems_lock);
        return 0;
 
+out_put_subsystem:
+       nvme_put_subsystem(subsys);
 out_unlock:
        mutex_unlock(&nvme_subsystems_lock);
        put_device(&subsys->dev);
@@ -3605,19 +3607,18 @@ static void nvme_handle_aen_notice(struct nvme_ctrl *ctrl, u32 result)
 {
        u32 aer_notice_type = (result & 0xff00) >> 8;
 
+       trace_nvme_async_event(ctrl, aer_notice_type);
+
        switch (aer_notice_type) {
        case NVME_AER_NOTICE_NS_CHANGED:
-               trace_nvme_async_event(ctrl, aer_notice_type);
                set_bit(NVME_AER_NOTICE_NS_CHANGED, &ctrl->events);
                nvme_queue_scan(ctrl);
                break;
        case NVME_AER_NOTICE_FW_ACT_STARTING:
-               trace_nvme_async_event(ctrl, aer_notice_type);
                queue_work(nvme_wq, &ctrl->fw_act_work);
                break;
 #ifdef CONFIG_NVME_MULTIPATH
        case NVME_AER_NOTICE_ANA:
-               trace_nvme_async_event(ctrl, aer_notice_type);
                if (!ctrl->ana_log_buf)
                        break;
                queue_work(nvme_wq, &ctrl->ana_work);
@@ -3696,10 +3697,10 @@ static void nvme_free_ctrl(struct device *dev)
        __free_page(ctrl->discard_page);
 
        if (subsys) {
-               mutex_lock(&subsys->lock);
+               mutex_lock(&nvme_subsystems_lock);
                list_del(&ctrl->subsys_entry);
-               mutex_unlock(&subsys->lock);
                sysfs_remove_link(&subsys->dev.kobj, dev_name(ctrl->device));
+               mutex_unlock(&nvme_subsystems_lock);
        }
 
        ctrl->ops->free_ctrl(ctrl);
index 592d1e61ef7e64543cdc28d07b62e2436d589c02..5838f7cd53ac70d6ff73f9a5a58eec088d79ba57 100644 (file)
@@ -978,7 +978,7 @@ EXPORT_SYMBOL_GPL(nvmf_free_options);
                                 NVMF_OPT_DISABLE_SQFLOW)
 
 static struct nvme_ctrl *
-nvmf_create_ctrl(struct device *dev, const char *buf, size_t count)
+nvmf_create_ctrl(struct device *dev, const char *buf)
 {
        struct nvmf_ctrl_options *opts;
        struct nvmf_transport_ops *ops;
@@ -1073,7 +1073,7 @@ static ssize_t nvmf_dev_write(struct file *file, const char __user *ubuf,
                goto out_unlock;
        }
 
-       ctrl = nvmf_create_ctrl(nvmf_device, buf, count);
+       ctrl = nvmf_create_ctrl(nvmf_device, buf);
        if (IS_ERR(ctrl)) {
                ret = PTR_ERR(ctrl);
                goto out_unlock;
index 9544eb60f725b9854027608fefb1e8e3f9b1766f..dd8169bbf0d2cfa92fdf47e7f9a8c123d36bb41c 100644 (file)
@@ -202,7 +202,7 @@ static LIST_HEAD(nvme_fc_lport_list);
 static DEFINE_IDA(nvme_fc_local_port_cnt);
 static DEFINE_IDA(nvme_fc_ctrl_cnt);
 
-
+static struct workqueue_struct *nvme_fc_wq;
 
 /*
  * These items are short-term. They will eventually be moved into
@@ -2054,7 +2054,7 @@ nvme_fc_error_recovery(struct nvme_fc_ctrl *ctrl, char *errmsg)
         */
        if (ctrl->ctrl.state == NVME_CTRL_CONNECTING) {
                active = atomic_xchg(&ctrl->err_work_active, 1);
-               if (!active && !schedule_work(&ctrl->err_work)) {
+               if (!active && !queue_work(nvme_fc_wq, &ctrl->err_work)) {
                        atomic_set(&ctrl->err_work_active, 0);
                        WARN_ON(1);
                }
@@ -3399,6 +3399,10 @@ static int __init nvme_fc_init_module(void)
 {
        int ret;
 
+       nvme_fc_wq = alloc_workqueue("nvme_fc_wq", WQ_MEM_RECLAIM, 0);
+       if (!nvme_fc_wq)
+               return -ENOMEM;
+
        /*
         * NOTE:
         * It is expected that in the future the kernel will combine
@@ -3416,7 +3420,7 @@ static int __init nvme_fc_init_module(void)
        ret = class_register(&fc_class);
        if (ret) {
                pr_err("couldn't register class fc\n");
-               return ret;
+               goto out_destroy_wq;
        }
 
        /*
@@ -3440,6 +3444,9 @@ out_destroy_device:
        device_destroy(&fc_class, MKDEV(0, 0));
 out_destroy_class:
        class_unregister(&fc_class);
+out_destroy_wq:
+       destroy_workqueue(nvme_fc_wq);
+
        return ret;
 }
 
@@ -3456,6 +3463,7 @@ static void __exit nvme_fc_exit_module(void)
 
        device_destroy(&fc_class, MKDEV(0, 0));
        class_unregister(&fc_class);
+       destroy_workqueue(nvme_fc_wq);
 }
 
 module_init(nvme_fc_init_module);
index 949e29e1d78265dd08d0a83a1c028f49e3f48142..4f20a10b39d39d54e04cd7595c9254f97b933e82 100644 (file)
@@ -977,6 +977,7 @@ int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node)
        geo->csecs = 1 << ns->lba_shift;
        geo->sos = ns->ms;
        geo->ext = ns->ext;
+       geo->mdts = ns->ctrl->max_hw_sectors;
 
        dev->q = q;
        memcpy(dev->name, disk_name, DISK_NAME_LEN);
index 5c9429d41120894c4cbae01cdd6e7008a3d5c7ef..499acf07d61a7a7db1f0e64f4a91d93422eced92 100644 (file)
@@ -31,7 +31,7 @@ void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
                sprintf(disk_name, "nvme%dn%d", ctrl->instance, ns->head->instance);
        } else if (ns->head->disk) {
                sprintf(disk_name, "nvme%dc%dn%d", ctrl->subsys->instance,
-                               ctrl->cntlid, ns->head->instance);
+                               ctrl->instance, ns->head->instance);
                *flags = GENHD_FL_HIDDEN;
        } else {
                sprintf(disk_name, "nvme%dn%d", ctrl->subsys->instance,
index 3e4fb891a95aa025907dd005fbc3aad627e9ef91..2a8708c9ac18fa62b85c7333f0950b11dcf212d0 100644 (file)
@@ -1296,6 +1296,7 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
        switch (dev->ctrl.state) {
        case NVME_CTRL_DELETING:
                shutdown = true;
+               /* fall through */
        case NVME_CTRL_CONNECTING:
        case NVME_CTRL_RESETTING:
                dev_warn_ratelimited(dev->ctrl.device,
@@ -2280,8 +2281,6 @@ static int nvme_dev_add(struct nvme_dev *dev)
                        return ret;
                }
                dev->ctrl.tagset = &dev->tagset;
-
-               nvme_dbbuf_set(dev);
        } else {
                blk_mq_update_nr_hw_queues(&dev->tagset, dev->online_queues - 1);
 
@@ -2289,6 +2288,7 @@ static int nvme_dev_add(struct nvme_dev *dev)
                nvme_free_queues(dev, dev->online_queues);
        }
 
+       nvme_dbbuf_set(dev);
        return 0;
 }
 
index e1824c2e0a1c0e90be05a0c6cce072eb50a0c3a6..f383146e7d0fdfa40edb4e3671f1c208c082223c 100644 (file)
@@ -697,15 +697,6 @@ out_free_queues:
        return ret;
 }
 
-static void nvme_rdma_free_tagset(struct nvme_ctrl *nctrl,
-               struct blk_mq_tag_set *set)
-{
-       struct nvme_rdma_ctrl *ctrl = to_rdma_ctrl(nctrl);
-
-       blk_mq_free_tag_set(set);
-       nvme_rdma_dev_put(ctrl->device);
-}
-
 static struct blk_mq_tag_set *nvme_rdma_alloc_tagset(struct nvme_ctrl *nctrl,
                bool admin)
 {
@@ -744,24 +735,9 @@ static struct blk_mq_tag_set *nvme_rdma_alloc_tagset(struct nvme_ctrl *nctrl,
 
        ret = blk_mq_alloc_tag_set(set);
        if (ret)
-               goto out;
-
-       /*
-        * We need a reference on the device as long as the tag_set is alive,
-        * as the MRs in the request structures need a valid ib_device.
-        */
-       ret = nvme_rdma_dev_get(ctrl->device);
-       if (!ret) {
-               ret = -EINVAL;
-               goto out_free_tagset;
-       }
+               return ERR_PTR(ret);
 
        return set;
-
-out_free_tagset:
-       blk_mq_free_tag_set(set);
-out:
-       return ERR_PTR(ret);
 }
 
 static void nvme_rdma_destroy_admin_queue(struct nvme_rdma_ctrl *ctrl,
@@ -769,7 +745,7 @@ static void nvme_rdma_destroy_admin_queue(struct nvme_rdma_ctrl *ctrl,
 {
        if (remove) {
                blk_cleanup_queue(ctrl->ctrl.admin_q);
-               nvme_rdma_free_tagset(&ctrl->ctrl, ctrl->ctrl.admin_tagset);
+               blk_mq_free_tag_set(ctrl->ctrl.admin_tagset);
        }
        if (ctrl->async_event_sqe.data) {
                nvme_rdma_free_qe(ctrl->device->dev, &ctrl->async_event_sqe,
@@ -847,7 +823,7 @@ out_cleanup_queue:
                blk_cleanup_queue(ctrl->ctrl.admin_q);
 out_free_tagset:
        if (new)
-               nvme_rdma_free_tagset(&ctrl->ctrl, ctrl->ctrl.admin_tagset);
+               blk_mq_free_tag_set(ctrl->ctrl.admin_tagset);
 out_free_async_qe:
        nvme_rdma_free_qe(ctrl->device->dev, &ctrl->async_event_sqe,
                sizeof(struct nvme_command), DMA_TO_DEVICE);
@@ -862,7 +838,7 @@ static void nvme_rdma_destroy_io_queues(struct nvme_rdma_ctrl *ctrl,
 {
        if (remove) {
                blk_cleanup_queue(ctrl->ctrl.connect_q);
-               nvme_rdma_free_tagset(&ctrl->ctrl, ctrl->ctrl.tagset);
+               blk_mq_free_tag_set(ctrl->ctrl.tagset);
        }
        nvme_rdma_free_io_queues(ctrl);
 }
@@ -903,7 +879,7 @@ out_cleanup_connect_q:
                blk_cleanup_queue(ctrl->ctrl.connect_q);
 out_free_tag_set:
        if (new)
-               nvme_rdma_free_tagset(&ctrl->ctrl, ctrl->ctrl.tagset);
+               blk_mq_free_tag_set(ctrl->ctrl.tagset);
 out_free_io_queues:
        nvme_rdma_free_io_queues(ctrl);
        return ret;
index 97d3c77365b890e0e4dc4e02ab1c4d08bfe8a1cb..e71502d141ed1e636c48ad3f51260425b183d92b 100644 (file)
@@ -167,6 +167,7 @@ TRACE_EVENT(nvme_async_event,
                aer_name(NVME_AER_NOTICE_NS_CHANGED),
                aer_name(NVME_AER_NOTICE_ANA),
                aer_name(NVME_AER_NOTICE_FW_ACT_STARTING),
+               aer_name(NVME_AER_NOTICE_DISC_CHANGED),
                aer_name(NVME_AER_ERROR),
                aer_name(NVME_AER_SMART),
                aer_name(NVME_AER_CSS),
index 490c8fcaec80178b7a8ebd88a3fd209287334c99..5893543918c8dc1d570b0b8ce743536c8b5c95b0 100644 (file)
@@ -16,6 +16,8 @@ struct zynqmp_nvmem_data {
        struct nvmem_device *nvmem;
 };
 
+static const struct zynqmp_eemi_ops *eemi_ops;
+
 static int zynqmp_nvmem_read(void *context, unsigned int offset,
                             void *val, size_t bytes)
 {
@@ -23,9 +25,7 @@ static int zynqmp_nvmem_read(void *context, unsigned int offset,
        int idcode, version;
        struct zynqmp_nvmem_data *priv = context;
 
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
-
-       if (!eemi_ops || !eemi_ops->get_chipid)
+       if (!eemi_ops->get_chipid)
                return -ENXIO;
 
        ret = eemi_ops->get_chipid(&idcode, &version);
@@ -61,6 +61,10 @@ static int zynqmp_nvmem_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
+       eemi_ops = zynqmp_pm_get_eemi_ops();
+       if (IS_ERR(eemi_ops))
+               return PTR_ERR(eemi_ops);
+
        priv->dev = dev;
        econfig.dev = dev;
        econfig.reg_read = zynqmp_nvmem_read;
index 9649cd53e95574a26a61b65bc587788ab19846e6..6f1be80e8c4ed07658c0da4f503fb13d52280306 100644 (file)
@@ -52,39 +52,25 @@ static const void *of_get_mac_addr(struct device_node *np, const char *name)
 static const void *of_get_mac_addr_nvmem(struct device_node *np)
 {
        int ret;
-       u8 mac[ETH_ALEN];
-       struct property *pp;
+       const void *mac;
+       u8 nvmem_mac[ETH_ALEN];
        struct platform_device *pdev = of_find_device_by_node(np);
 
        if (!pdev)
                return ERR_PTR(-ENODEV);
 
-       ret = nvmem_get_mac_address(&pdev->dev, &mac);
-       if (ret)
+       ret = nvmem_get_mac_address(&pdev->dev, &nvmem_mac);
+       if (ret) {
+               put_device(&pdev->dev);
                return ERR_PTR(ret);
-
-       pp = devm_kzalloc(&pdev->dev, sizeof(*pp), GFP_KERNEL);
-       if (!pp)
-               return ERR_PTR(-ENOMEM);
-
-       pp->name = "nvmem-mac-address";
-       pp->length = ETH_ALEN;
-       pp->value = devm_kmemdup(&pdev->dev, mac, ETH_ALEN, GFP_KERNEL);
-       if (!pp->value) {
-               ret = -ENOMEM;
-               goto free;
        }
 
-       ret = of_add_property(np, pp);
-       if (ret)
-               goto free;
-
-       return pp->value;
-free:
-       devm_kfree(&pdev->dev, pp->value);
-       devm_kfree(&pdev->dev, pp);
+       mac = devm_kmemdup(&pdev->dev, nvmem_mac, ETH_ALEN, GFP_KERNEL);
+       put_device(&pdev->dev);
+       if (!mac)
+               return ERR_PTR(-ENOMEM);
 
-       return ERR_PTR(ret);
+       return mac;
 }
 
 /**
index 657d642fcc67a8a99a4fb3548550eae758c60c45..28cdd8c0213ac347f834a4b819c6c4ab0a2cf08d 100644 (file)
@@ -10,10 +10,10 @@ obj-$(CONFIG_PCI)           += access.o bus.o probe.o host-bridge.o \
 ifdef CONFIG_PCI
 obj-$(CONFIG_PROC_FS)          += proc.o
 obj-$(CONFIG_SYSFS)            += slot.o
-obj-$(CONFIG_OF)               += of.o
 obj-$(CONFIG_ACPI)             += pci-acpi.o
 endif
 
+obj-$(CONFIG_OF)               += of.o
 obj-$(CONFIG_PCI_QUIRKS)       += quirks.o
 obj-$(CONFIG_PCIEPORTBUS)      += pcie/
 obj-$(CONFIG_HOTPLUG_PCI)      += hotplug/
index 5cb40b2518f9376dbe7edd4bf11d303daf97c025..495059d923f7da4e360a7689349c46260e16e797 100644 (file)
@@ -23,7 +23,7 @@ void pci_add_resource_offset(struct list_head *resources, struct resource *res,
 
        entry = resource_list_create_entry(res, 0);
        if (!entry) {
-               printk(KERN_ERR "PCI: can't add host bridge window %pR\n", res);
+               pr_err("PCI: can't add host bridge window %pR\n", res);
                return;
        }
 
@@ -288,8 +288,7 @@ bool pci_bus_clip_resource(struct pci_dev *dev, int idx)
                res->end = end;
                res->flags &= ~IORESOURCE_UNSET;
                orig_res.flags &= ~IORESOURCE_UNSET;
-               pci_printk(KERN_DEBUG, dev, "%pR clipped to %pR\n",
-                                &orig_res, res);
+               pci_info(dev, "%pR clipped to %pR\n", &orig_res, res);
 
                return true;
        }
index 6ea74b1c0d94f1b13d7be1945f4de7a4b77539a4..a6ce1ee51b4c648295ffad07937c89f6b726d582 100644 (file)
@@ -103,15 +103,32 @@ config PCIE_SPEAR13XX
          Say Y here if you want PCIe support on SPEAr13XX SoCs.
 
 config PCI_KEYSTONE
-       bool "TI Keystone PCIe controller"
-       depends on ARCH_KEYSTONE || (ARM && COMPILE_TEST)
+       bool
+
+config PCI_KEYSTONE_HOST
+       bool "PCI Keystone Host Mode"
+       depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST)
        depends on PCI_MSI_IRQ_DOMAIN
        select PCIE_DW_HOST
+       select PCI_KEYSTONE
+       default y
        help
-         Say Y here if you want to enable PCI controller support on Keystone
-         SoCs. The PCI controller on Keystone is based on DesignWare hardware
-         and therefore the driver re-uses the DesignWare core functions to
-         implement the driver.
+         Enables support for the PCIe controller in the Keystone SoC to
+         work in host mode. The PCI controller on Keystone is based on
+         DesignWare hardware and therefore the driver re-uses the
+         DesignWare core functions to implement the driver.
+
+config PCI_KEYSTONE_EP
+       bool "PCI Keystone Endpoint Mode"
+       depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST)
+       depends on PCI_ENDPOINT
+       select PCIE_DW_EP
+       select PCI_KEYSTONE
+       help
+         Enables support for the PCIe controller in the Keystone SoC to
+         work in endpoint mode. The PCI controller on Keystone is based
+         on DesignWare hardware and therefore the driver re-uses the
+         DesignWare core functions to implement the driver.
 
 config PCI_LAYERSCAPE
        bool "Freescale Layerscape PCIe controller"
index b5f3b83cc2b3a0eb177fd0e814eadf2d06c10ad7..b085dfd4fab77247e9e0b13299326044906f5b30 100644 (file)
@@ -28,5 +28,6 @@ obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
 # depending on whether ACPI, the DT driver, or both are enabled.
 
 ifdef CONFIG_PCI
+obj-$(CONFIG_ARM64) += pcie-al.o
 obj-$(CONFIG_ARM64) += pcie-hisi.o
 endif
index ae84a69ae63a8d5df855953723ea8ad6306d2f26..419451efd58cc9ee3871279306f6d8b10af4596b 100644 (file)
@@ -247,6 +247,7 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
 
        dra7xx->irq_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
                                                   &intx_domain_ops, pp);
+       of_node_put(pcie_intc_node);
        if (!dra7xx->irq_domain) {
                dev_err(dev, "Failed to get a INTx IRQ domain\n");
                return -ENODEV;
@@ -406,7 +407,7 @@ dra7xx_pcie_get_features(struct dw_pcie_ep *ep)
        return &dra7xx_pcie_epc_features;
 }
 
-static struct dw_pcie_ep_ops pcie_ep_ops = {
+static const struct dw_pcie_ep_ops pcie_ep_ops = {
        .ep_init = dra7xx_pcie_ep_init,
        .raise_irq = dra7xx_pcie_raise_irq,
        .get_features = dra7xx_pcie_get_features,
index 3d627f94a16664d57a7eee76fc69dfdecadda19e..9b5cb5b703890f3e6e2d17fe06d1ae29b8be11bb 100644 (file)
@@ -52,6 +52,7 @@ enum imx6_pcie_variants {
 
 #define IMX6_PCIE_FLAG_IMX6_PHY                        BIT(0)
 #define IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE       BIT(1)
+#define IMX6_PCIE_FLAG_SUPPORTS_SUSPEND                BIT(2)
 
 struct imx6_pcie_drvdata {
        enum imx6_pcie_variants variant;
@@ -89,9 +90,8 @@ struct imx6_pcie {
 };
 
 /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */
-#define PHY_PLL_LOCK_WAIT_MAX_RETRIES  2000
-#define PHY_PLL_LOCK_WAIT_USLEEP_MIN   50
 #define PHY_PLL_LOCK_WAIT_USLEEP_MAX   200
+#define PHY_PLL_LOCK_WAIT_TIMEOUT      (2000 * PHY_PLL_LOCK_WAIT_USLEEP_MAX)
 
 /* PCIe Root Complex registers (memory-mapped) */
 #define PCIE_RC_IMX6_MSI_CAP                   0x50
@@ -104,34 +104,29 @@ struct imx6_pcie {
 
 /* PCIe Port Logic registers (memory-mapped) */
 #define PL_OFFSET 0x700
-#define PCIE_PL_PFLR (PL_OFFSET + 0x08)
-#define PCIE_PL_PFLR_LINK_STATE_MASK           (0x3f << 16)
-#define PCIE_PL_PFLR_FORCE_LINK                        (1 << 15)
-#define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
-#define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
 
 #define PCIE_PHY_CTRL (PL_OFFSET + 0x114)
-#define PCIE_PHY_CTRL_DATA_LOC 0
-#define PCIE_PHY_CTRL_CAP_ADR_LOC 16
-#define PCIE_PHY_CTRL_CAP_DAT_LOC 17
-#define PCIE_PHY_CTRL_WR_LOC 18
-#define PCIE_PHY_CTRL_RD_LOC 19
+#define PCIE_PHY_CTRL_DATA(x)          FIELD_PREP(GENMASK(15, 0), (x))
+#define PCIE_PHY_CTRL_CAP_ADR          BIT(16)
+#define PCIE_PHY_CTRL_CAP_DAT          BIT(17)
+#define PCIE_PHY_CTRL_WR               BIT(18)
+#define PCIE_PHY_CTRL_RD               BIT(19)
 
 #define PCIE_PHY_STAT (PL_OFFSET + 0x110)
-#define PCIE_PHY_STAT_ACK_LOC 16
+#define PCIE_PHY_STAT_ACK              BIT(16)
 
 #define PCIE_LINK_WIDTH_SPEED_CONTROL  0x80C
 
 /* PHY registers (not memory-mapped) */
 #define PCIE_PHY_ATEOVRD                       0x10
-#define  PCIE_PHY_ATEOVRD_EN                   (0x1 << 2)
+#define  PCIE_PHY_ATEOVRD_EN                   BIT(2)
 #define  PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT     0
 #define  PCIE_PHY_ATEOVRD_REF_CLKDIV_MASK      0x1
 
 #define PCIE_PHY_MPLL_OVRD_IN_LO               0x11
 #define  PCIE_PHY_MPLL_MULTIPLIER_SHIFT                2
 #define  PCIE_PHY_MPLL_MULTIPLIER_MASK         0x7f
-#define  PCIE_PHY_MPLL_MULTIPLIER_OVRD         (0x1 << 9)
+#define  PCIE_PHY_MPLL_MULTIPLIER_OVRD         BIT(9)
 
 #define PCIE_PHY_RX_ASIC_OUT 0x100D
 #define PCIE_PHY_RX_ASIC_OUT_VALID     (1 << 0)
@@ -154,19 +149,19 @@ struct imx6_pcie {
 #define PCIE_PHY_CMN_REG26_ATT_MODE    0xBC
 
 #define PHY_RX_OVRD_IN_LO 0x1005
-#define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5)
-#define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3)
+#define PHY_RX_OVRD_IN_LO_RX_DATA_EN           BIT(5)
+#define PHY_RX_OVRD_IN_LO_RX_PLL_EN            BIT(3)
 
-static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, int exp_val)
+static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, bool exp_val)
 {
        struct dw_pcie *pci = imx6_pcie->pci;
-       u32 val;
+       bool val;
        u32 max_iterations = 10;
        u32 wait_counter = 0;
 
        do {
-               val = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT);
-               val = (val >> PCIE_PHY_STAT_ACK_LOC) & 0x1;
+               val = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT) &
+                       PCIE_PHY_STAT_ACK;
                wait_counter++;
 
                if (val == exp_val)
@@ -184,27 +179,27 @@ static int pcie_phy_wait_ack(struct imx6_pcie *imx6_pcie, int addr)
        u32 val;
        int ret;
 
-       val = addr << PCIE_PHY_CTRL_DATA_LOC;
+       val = PCIE_PHY_CTRL_DATA(addr);
        dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val);
 
-       val |= (0x1 << PCIE_PHY_CTRL_CAP_ADR_LOC);
+       val |= PCIE_PHY_CTRL_CAP_ADR;
        dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val);
 
-       ret = pcie_phy_poll_ack(imx6_pcie, 1);
+       ret = pcie_phy_poll_ack(imx6_pcie, true);
        if (ret)
                return ret;
 
-       val = addr << PCIE_PHY_CTRL_DATA_LOC;
+       val = PCIE_PHY_CTRL_DATA(addr);
        dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val);
 
-       return pcie_phy_poll_ack(imx6_pcie, 0);
+       return pcie_phy_poll_ack(imx6_pcie, false);
 }
 
 /* Read from the 16-bit PCIe PHY control registers (not memory-mapped) */
-static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data)
+static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, u16 *data)
 {
        struct dw_pcie *pci = imx6_pcie->pci;
-       u32 val, phy_ctl;
+       u32 phy_ctl;
        int ret;
 
        ret = pcie_phy_wait_ack(imx6_pcie, addr);
@@ -212,23 +207,22 @@ static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data)
                return ret;
 
        /* assert Read signal */
-       phy_ctl = 0x1 << PCIE_PHY_CTRL_RD_LOC;
+       phy_ctl = PCIE_PHY_CTRL_RD;
        dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, phy_ctl);
 
-       ret = pcie_phy_poll_ack(imx6_pcie, 1);
+       ret = pcie_phy_poll_ack(imx6_pcie, true);
        if (ret)
                return ret;
 
-       val = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT);
-       *data = val & 0xffff;
+       *data = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT);
 
        /* deassert Read signal */
        dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, 0x00);
 
-       return pcie_phy_poll_ack(imx6_pcie, 0);
+       return pcie_phy_poll_ack(imx6_pcie, false);
 }
 
-static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data)
+static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, u16 data)
 {
        struct dw_pcie *pci = imx6_pcie->pci;
        u32 var;
@@ -240,41 +234,41 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data)
        if (ret)
                return ret;
 
-       var = data << PCIE_PHY_CTRL_DATA_LOC;
+       var = PCIE_PHY_CTRL_DATA(data);
        dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var);
 
        /* capture data */
-       var |= (0x1 << PCIE_PHY_CTRL_CAP_DAT_LOC);
+       var |= PCIE_PHY_CTRL_CAP_DAT;
        dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var);
 
-       ret = pcie_phy_poll_ack(imx6_pcie, 1);
+       ret = pcie_phy_poll_ack(imx6_pcie, true);
        if (ret)
                return ret;
 
        /* deassert cap data */
-       var = data << PCIE_PHY_CTRL_DATA_LOC;
+       var = PCIE_PHY_CTRL_DATA(data);
        dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var);
 
        /* wait for ack de-assertion */
-       ret = pcie_phy_poll_ack(imx6_pcie, 0);
+       ret = pcie_phy_poll_ack(imx6_pcie, false);
        if (ret)
                return ret;
 
        /* assert wr signal */
-       var = 0x1 << PCIE_PHY_CTRL_WR_LOC;
+       var = PCIE_PHY_CTRL_WR;
        dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var);
 
        /* wait for ack */
-       ret = pcie_phy_poll_ack(imx6_pcie, 1);
+       ret = pcie_phy_poll_ack(imx6_pcie, true);
        if (ret)
                return ret;
 
        /* deassert wr signal */
-       var = data << PCIE_PHY_CTRL_DATA_LOC;
+       var = PCIE_PHY_CTRL_DATA(data);
        dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var);
 
        /* wait for ack de-assertion */
-       ret = pcie_phy_poll_ack(imx6_pcie, 0);
+       ret = pcie_phy_poll_ack(imx6_pcie, false);
        if (ret)
                return ret;
 
@@ -285,7 +279,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data)
 
 static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie)
 {
-       u32 tmp;
+       u16 tmp;
 
        if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY))
                return;
@@ -455,7 +449,7 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
                 * reset time is too short, cannot meet the requirement.
                 * add one ~10us delay here.
                 */
-               udelay(10);
+               usleep_range(10, 100);
                regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
                                   IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
                break;
@@ -488,20 +482,14 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
 static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie)
 {
        u32 val;
-       unsigned int retries;
        struct device *dev = imx6_pcie->pci->dev;
 
-       for (retries = 0; retries < PHY_PLL_LOCK_WAIT_MAX_RETRIES; retries++) {
-               regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR22, &val);
-
-               if (val & IMX7D_GPR22_PCIE_PHY_PLL_LOCKED)
-                       return;
-
-               usleep_range(PHY_PLL_LOCK_WAIT_USLEEP_MIN,
-                            PHY_PLL_LOCK_WAIT_USLEEP_MAX);
-       }
-
-       dev_err(dev, "PCIe PLL lock timeout\n");
+       if (regmap_read_poll_timeout(imx6_pcie->iomuxc_gpr,
+                                    IOMUXC_GPR22, val,
+                                    val & IMX7D_GPR22_PCIE_PHY_PLL_LOCKED,
+                                    PHY_PLL_LOCK_WAIT_USLEEP_MAX,
+                                    PHY_PLL_LOCK_WAIT_TIMEOUT))
+               dev_err(dev, "PCIe PLL lock timeout\n");
 }
 
 static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
@@ -687,7 +675,7 @@ static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie)
 {
        unsigned long phy_rate = clk_get_rate(imx6_pcie->pcie_phy);
        int mult, div;
-       u32 val;
+       u16 val;
 
        if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY))
                return 0;
@@ -730,21 +718,6 @@ static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie)
        return 0;
 }
 
-static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie)
-{
-       struct dw_pcie *pci = imx6_pcie->pci;
-       struct device *dev = pci->dev;
-
-       /* check if the link is up or not */
-       if (!dw_pcie_wait_for_link(pci))
-               return 0;
-
-       dev_dbg(dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
-               dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R0),
-               dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R1));
-       return -ETIMEDOUT;
-}
-
 static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)
 {
        struct dw_pcie *pci = imx6_pcie->pci;
@@ -761,7 +734,7 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)
        }
 
        dev_err(dev, "Speed change timeout\n");
-       return -EINVAL;
+       return -ETIMEDOUT;
 }
 
 static void imx6_pcie_ltssm_enable(struct device *dev)
@@ -803,7 +776,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
        /* Start LTSSM. */
        imx6_pcie_ltssm_enable(dev);
 
-       ret = imx6_pcie_wait_for_link(imx6_pcie);
+       ret = dw_pcie_wait_for_link(pci);
        if (ret)
                goto err_reset_phy;
 
@@ -841,7 +814,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
                }
 
                /* Make sure link training is finished as well! */
-               ret = imx6_pcie_wait_for_link(imx6_pcie);
+               ret = dw_pcie_wait_for_link(pci);
                if (ret) {
                        dev_err(dev, "Failed to bring link up!\n");
                        goto err_reset_phy;
@@ -856,8 +829,8 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
 
 err_reset_phy:
        dev_dbg(dev, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n",
-               dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R0),
-               dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R1));
+               dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0),
+               dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG1));
        imx6_pcie_reset_phy(imx6_pcie);
        return ret;
 }
@@ -993,17 +966,11 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)
        }
 }
 
-static inline bool imx6_pcie_supports_suspend(struct imx6_pcie *imx6_pcie)
-{
-       return (imx6_pcie->drvdata->variant == IMX7D ||
-               imx6_pcie->drvdata->variant == IMX6SX);
-}
-
 static int imx6_pcie_suspend_noirq(struct device *dev)
 {
        struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
 
-       if (!imx6_pcie_supports_suspend(imx6_pcie))
+       if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND))
                return 0;
 
        imx6_pcie_pm_turnoff(imx6_pcie);
@@ -1019,7 +986,7 @@ static int imx6_pcie_resume_noirq(struct device *dev)
        struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
        struct pcie_port *pp = &imx6_pcie->pci->pp;
 
-       if (!imx6_pcie_supports_suspend(imx6_pcie))
+       if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND))
                return 0;
 
        imx6_pcie_assert_core_reset(imx6_pcie);
@@ -1249,7 +1216,8 @@ static const struct imx6_pcie_drvdata drvdata[] = {
        [IMX6SX] = {
                .variant = IMX6SX,
                .flags = IMX6_PCIE_FLAG_IMX6_PHY |
-                        IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE,
+                        IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE |
+                        IMX6_PCIE_FLAG_SUPPORTS_SUSPEND,
        },
        [IMX6QP] = {
                .variant = IMX6QP,
@@ -1258,6 +1226,7 @@ static const struct imx6_pcie_drvdata drvdata[] = {
        },
        [IMX7D] = {
                .variant = IMX7D,
+               .flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND,
        },
        [IMX8MQ] = {
                .variant = IMX8MQ,
@@ -1279,6 +1248,7 @@ static struct platform_driver imx6_pcie_driver = {
                .of_match_table = imx6_pcie_of_match,
                .suppress_bind_attrs = true,
                .pm = &imx6_pcie_pm_ops,
+               .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },
        .probe    = imx6_pcie_probe,
        .shutdown = imx6_pcie_shutdown,
index 14f2b0b4ed5ef3a6cf60be15c26ad66c4f72c346..af677254a0726574d1cd7c73e2ae27939011c2e0 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irqchip/chained_irq.h>
@@ -18,6 +19,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/msi.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_irq.h>
 #include <linux/of_pci.h>
 #include <linux/phy/phy.h>
@@ -26,6 +28,7 @@
 #include <linux/resource.h>
 #include <linux/signal.h>
 
+#include "../../pci.h"
 #include "pcie-designware.h"
 
 #define PCIE_VENDORID_MASK     0xffff
 #define CFG_TYPE1                      BIT(24)
 
 #define OB_SIZE                                0x030
-#define SPACE0_REMOTE_CFG_OFFSET       0x1000
 #define OB_OFFSET_INDEX(n)             (0x200 + (8 * (n)))
 #define OB_OFFSET_HI(n)                        (0x204 + (8 * (n)))
 #define OB_ENABLEN                     BIT(0)
 #define OB_WIN_SIZE                    8       /* 8MB */
 
+#define PCIE_LEGACY_IRQ_ENABLE_SET(n)  (0x188 + (0x10 * ((n) - 1)))
+#define PCIE_LEGACY_IRQ_ENABLE_CLR(n)  (0x18c + (0x10 * ((n) - 1)))
+#define PCIE_EP_IRQ_SET                        0x64
+#define PCIE_EP_IRQ_CLR                        0x68
+#define INT_ENABLE                     BIT(0)
+
 /* IRQ register defines */
 #define IRQ_EOI                                0x050
-#define IRQ_STATUS                     0x184
-#define IRQ_ENABLE_SET                 0x188
-#define IRQ_ENABLE_CLR                 0x18c
 
 #define MSI_IRQ                                0x054
-#define MSI0_IRQ_STATUS                        0x104
-#define MSI0_IRQ_ENABLE_SET            0x108
-#define MSI0_IRQ_ENABLE_CLR            0x10c
-#define IRQ_STATUS                     0x184
+#define MSI_IRQ_STATUS(n)              (0x104 + ((n) << 4))
+#define MSI_IRQ_ENABLE_SET(n)          (0x108 + ((n) << 4))
+#define MSI_IRQ_ENABLE_CLR(n)          (0x10c + ((n) << 4))
 #define MSI_IRQ_OFFSET                 4
 
+#define IRQ_STATUS(n)                  (0x184 + ((n) << 4))
+#define IRQ_ENABLE_SET(n)              (0x188 + ((n) << 4))
+#define INTx_EN                                BIT(0)
+
 #define ERR_IRQ_STATUS                 0x1c4
 #define ERR_IRQ_ENABLE_SET             0x1c8
 #define ERR_AER                                BIT(5)  /* ECRC error */
+#define AM6_ERR_AER                    BIT(4)  /* AM6 ECRC error */
 #define ERR_AXI                                BIT(4)  /* AXI tag lookup fatal error */
 #define ERR_CORR                       BIT(3)  /* Correctable error */
 #define ERR_NONFATAL                   BIT(2)  /* Non-fatal error */
 #define ERR_IRQ_ALL                    (ERR_AER | ERR_AXI | ERR_CORR | \
                                         ERR_NONFATAL | ERR_FATAL | ERR_SYS)
 
-#define MAX_MSI_HOST_IRQS              8
 /* PCIE controller device IDs */
 #define PCIE_RC_K2HK                   0xb008
 #define PCIE_RC_K2E                    0xb009
 #define PCIE_RC_K2L                    0xb00a
 #define PCIE_RC_K2G                    0xb00b
 
+#define KS_PCIE_DEV_TYPE_MASK          (0x3 << 1)
+#define KS_PCIE_DEV_TYPE(mode)         ((mode) << 1)
+
+#define EP                             0x0
+#define LEG_EP                         0x1
+#define RC                             0x2
+
+#define EXP_CAP_ID_OFFSET              0x70
+
+#define KS_PCIE_SYSCLOCKOUTEN          BIT(0)
+
+#define AM654_PCIE_DEV_TYPE_MASK       0x3
+#define AM654_WIN_SIZE                 SZ_64K
+
+#define APP_ADDR_SPACE_0               (16 * SZ_1K)
+
 #define to_keystone_pcie(x)            dev_get_drvdata((x)->dev)
 
+struct ks_pcie_of_data {
+       enum dw_pcie_device_mode mode;
+       const struct dw_pcie_host_ops *host_ops;
+       const struct dw_pcie_ep_ops *ep_ops;
+       unsigned int version;
+};
+
 struct keystone_pcie {
        struct dw_pcie          *pci;
        /* PCI Device ID */
        u32                     device_id;
-       int                     num_legacy_host_irqs;
        int                     legacy_host_irqs[PCI_NUM_INTX];
        struct                  device_node *legacy_intc_np;
 
-       int                     num_msi_host_irqs;
-       int                     msi_host_irqs[MAX_MSI_HOST_IRQS];
+       int                     msi_host_irq;
        int                     num_lanes;
        u32                     num_viewport;
        struct phy              **phy;
@@ -101,28 +130,12 @@ struct keystone_pcie {
        struct irq_domain       *legacy_irq_domain;
        struct device_node      *np;
 
-       int error_irq;
-
        /* Application register space */
        void __iomem            *va_app_base;   /* DT 1st resource */
        struct resource         app;
+       bool                    is_am6;
 };
 
-static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
-                                            u32 *bit_pos)
-{
-       *reg_offset = offset % 8;
-       *bit_pos = offset >> 3;
-}
-
-static phys_addr_t ks_pcie_get_msi_addr(struct pcie_port *pp)
-{
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-       struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
-
-       return ks_pcie->app.start + MSI_IRQ;
-}
-
 static u32 ks_pcie_app_readl(struct keystone_pcie *ks_pcie, u32 offset)
 {
        return readl(ks_pcie->va_app_base + offset);
@@ -134,81 +147,114 @@ static void ks_pcie_app_writel(struct keystone_pcie *ks_pcie, u32 offset,
        writel(val, ks_pcie->va_app_base + offset);
 }
 
-static void ks_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset)
+static void ks_pcie_msi_irq_ack(struct irq_data *data)
 {
-       struct dw_pcie *pci = ks_pcie->pci;
-       struct pcie_port *pp = &pci->pp;
-       struct device *dev = pci->dev;
-       u32 pending, vector;
-       int src, virq;
+       struct pcie_port *pp  = irq_data_get_irq_chip_data(data);
+       struct keystone_pcie *ks_pcie;
+       u32 irq = data->hwirq;
+       struct dw_pcie *pci;
+       u32 reg_offset;
+       u32 bit_pos;
 
-       pending = ks_pcie_app_readl(ks_pcie, MSI0_IRQ_STATUS + (offset << 4));
+       pci = to_dw_pcie_from_pp(pp);
+       ks_pcie = to_keystone_pcie(pci);
 
-       /*
-        * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
-        * shows 1, 9, 17, 25 and so forth
-        */
-       for (src = 0; src < 4; src++) {
-               if (BIT(src) & pending) {
-                       vector = offset + (src << 3);
-                       virq = irq_linear_revmap(pp->irq_domain, vector);
-                       dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n",
-                               src, vector, virq);
-                       generic_handle_irq(virq);
-               }
-       }
+       reg_offset = irq % 8;
+       bit_pos = irq >> 3;
+
+       ks_pcie_app_writel(ks_pcie, MSI_IRQ_STATUS(reg_offset),
+                          BIT(bit_pos));
+       ks_pcie_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET);
 }
 
-static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp)
+static void ks_pcie_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 {
-       u32 reg_offset, bit_pos;
+       struct pcie_port *pp = irq_data_get_irq_chip_data(data);
        struct keystone_pcie *ks_pcie;
        struct dw_pcie *pci;
+       u64 msi_target;
 
        pci = to_dw_pcie_from_pp(pp);
        ks_pcie = to_keystone_pcie(pci);
-       update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
 
-       ks_pcie_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4),
-                          BIT(bit_pos));
-       ks_pcie_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET);
+       msi_target = ks_pcie->app.start + MSI_IRQ;
+       msg->address_lo = lower_32_bits(msi_target);
+       msg->address_hi = upper_32_bits(msi_target);
+       msg->data = data->hwirq;
+
+       dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
+               (int)data->hwirq, msg->address_hi, msg->address_lo);
 }
 
-static void ks_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+static int ks_pcie_msi_set_affinity(struct irq_data *irq_data,
+                                   const struct cpumask *mask, bool force)
 {
-       u32 reg_offset, bit_pos;
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-       struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+       return -EINVAL;
+}
 
-       update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
-       ks_pcie_app_writel(ks_pcie, MSI0_IRQ_ENABLE_SET + (reg_offset << 4),
+static void ks_pcie_msi_mask(struct irq_data *data)
+{
+       struct pcie_port *pp = irq_data_get_irq_chip_data(data);
+       struct keystone_pcie *ks_pcie;
+       u32 irq = data->hwirq;
+       struct dw_pcie *pci;
+       unsigned long flags;
+       u32 reg_offset;
+       u32 bit_pos;
+
+       raw_spin_lock_irqsave(&pp->lock, flags);
+
+       pci = to_dw_pcie_from_pp(pp);
+       ks_pcie = to_keystone_pcie(pci);
+
+       reg_offset = irq % 8;
+       bit_pos = irq >> 3;
+
+       ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_CLR(reg_offset),
                           BIT(bit_pos));
+
+       raw_spin_unlock_irqrestore(&pp->lock, flags);
 }
 
-static void ks_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+static void ks_pcie_msi_unmask(struct irq_data *data)
 {
-       u32 reg_offset, bit_pos;
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-       struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+       struct pcie_port *pp = irq_data_get_irq_chip_data(data);
+       struct keystone_pcie *ks_pcie;
+       u32 irq = data->hwirq;
+       struct dw_pcie *pci;
+       unsigned long flags;
+       u32 reg_offset;
+       u32 bit_pos;
+
+       raw_spin_lock_irqsave(&pp->lock, flags);
 
-       update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
-       ks_pcie_app_writel(ks_pcie, MSI0_IRQ_ENABLE_CLR + (reg_offset << 4),
+       pci = to_dw_pcie_from_pp(pp);
+       ks_pcie = to_keystone_pcie(pci);
+
+       reg_offset = irq % 8;
+       bit_pos = irq >> 3;
+
+       ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_SET(reg_offset),
                           BIT(bit_pos));
+
+       raw_spin_unlock_irqrestore(&pp->lock, flags);
 }
 
+static struct irq_chip ks_pcie_msi_irq_chip = {
+       .name = "KEYSTONE-PCI-MSI",
+       .irq_ack = ks_pcie_msi_irq_ack,
+       .irq_compose_msi_msg = ks_pcie_compose_msi_msg,
+       .irq_set_affinity = ks_pcie_msi_set_affinity,
+       .irq_mask = ks_pcie_msi_mask,
+       .irq_unmask = ks_pcie_msi_unmask,
+};
+
 static int ks_pcie_msi_host_init(struct pcie_port *pp)
 {
+       pp->msi_irq_chip = &ks_pcie_msi_irq_chip;
        return dw_pcie_allocate_domains(pp);
 }
 
-static void ks_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
-{
-       int i;
-
-       for (i = 0; i < PCI_NUM_INTX; i++)
-               ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET + (i << 4), 0x1);
-}
-
 static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
                                      int offset)
 {
@@ -217,7 +263,7 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
        u32 pending;
        int virq;
 
-       pending = ks_pcie_app_readl(ks_pcie, IRQ_STATUS + (offset << 4));
+       pending = ks_pcie_app_readl(ks_pcie, IRQ_STATUS(offset));
 
        if (BIT(0) & pending) {
                virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
@@ -229,6 +275,14 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
        ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset);
 }
 
+/*
+ * Dummy function so that DW core doesn't configure MSI
+ */
+static int ks_pcie_am654_msi_host_init(struct pcie_port *pp)
+{
+       return 0;
+}
+
 static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie)
 {
        ks_pcie_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL);
@@ -255,10 +309,10 @@ static irqreturn_t ks_pcie_handle_error_irq(struct keystone_pcie *ks_pcie)
        if (reg & ERR_CORR)
                dev_dbg(dev, "Correctable Error\n");
 
-       if (reg & ERR_AXI)
+       if (!ks_pcie->is_am6 && (reg & ERR_AXI))
                dev_err(dev, "AXI tag lookup fatal Error\n");
 
-       if (reg & ERR_AER)
+       if (reg & ERR_AER || (ks_pcie->is_am6 && (reg & AM6_ERR_AER)))
                dev_err(dev, "ECRC Error\n");
 
        ks_pcie_app_writel(ks_pcie, ERR_IRQ_STATUS, reg);
@@ -356,6 +410,9 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
        dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0);
        ks_pcie_clear_dbi_mode(ks_pcie);
 
+       if (ks_pcie->is_am6)
+               return;
+
        val = ilog2(OB_WIN_SIZE);
        ks_pcie_app_writel(ks_pcie, OB_SIZE, val);
 
@@ -445,68 +502,33 @@ static int ks_pcie_link_up(struct dw_pcie *pci)
        return (val == PORT_LOGIC_LTSSM_STATE_L0);
 }
 
-static void ks_pcie_initiate_link_train(struct keystone_pcie *ks_pcie)
+static void ks_pcie_stop_link(struct dw_pcie *pci)
 {
+       struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
        u32 val;
 
        /* Disable Link training */
        val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
        val &= ~LTSSM_EN_VAL;
        ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val);
-
-       /* Initiate Link Training */
-       val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
-       ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val);
 }
 
-/**
- * ks_pcie_dw_host_init() - initialize host for v3_65 dw hardware
- *
- * Ioremap the register resources, initialize legacy irq domain
- * and call dw_pcie_v3_65_host_init() API to initialize the Keystone
- * PCI host controller.
- */
-static int __init ks_pcie_dw_host_init(struct keystone_pcie *ks_pcie)
+static int ks_pcie_start_link(struct dw_pcie *pci)
 {
-       struct dw_pcie *pci = ks_pcie->pci;
-       struct pcie_port *pp = &pci->pp;
+       struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
        struct device *dev = pci->dev;
-       struct platform_device *pdev = to_platform_device(dev);
-       struct resource *res;
-
-       /* Index 0 is the config reg. space address */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       pci->dbi_base = devm_pci_remap_cfg_resource(dev, res);
-       if (IS_ERR(pci->dbi_base))
-               return PTR_ERR(pci->dbi_base);
-
-       /*
-        * We set these same and is used in pcie rd/wr_other_conf
-        * functions
-        */
-       pp->va_cfg0_base = pci->dbi_base + SPACE0_REMOTE_CFG_OFFSET;
-       pp->va_cfg1_base = pp->va_cfg0_base;
-
-       /* Index 1 is the application reg. space address */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       ks_pcie->va_app_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(ks_pcie->va_app_base))
-               return PTR_ERR(ks_pcie->va_app_base);
-
-       ks_pcie->app = *res;
+       u32 val;
 
-       /* Create legacy IRQ domain */
-       ks_pcie->legacy_irq_domain =
-                       irq_domain_add_linear(ks_pcie->legacy_intc_np,
-                                             PCI_NUM_INTX,
-                                             &ks_pcie_legacy_irq_domain_ops,
-                                             NULL);
-       if (!ks_pcie->legacy_irq_domain) {
-               dev_err(dev, "Failed to add irq domain for legacy irqs\n");
-               return -EINVAL;
+       if (dw_pcie_link_up(pci)) {
+               dev_dbg(dev, "link is already up\n");
+               return 0;
        }
 
-       return dw_pcie_host_init(pp);
+       /* Initiate Link Training */
+       val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
+       ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val);
+
+       return 0;
 }
 
 static void ks_pcie_quirk(struct pci_dev *dev)
@@ -552,34 +574,16 @@ static void ks_pcie_quirk(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, ks_pcie_quirk);
 
-static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
-{
-       struct dw_pcie *pci = ks_pcie->pci;
-       struct device *dev = pci->dev;
-
-       if (dw_pcie_link_up(pci)) {
-               dev_info(dev, "Link already up\n");
-               return 0;
-       }
-
-       ks_pcie_initiate_link_train(ks_pcie);
-
-       /* check if the link is up or not */
-       if (!dw_pcie_wait_for_link(pci))
-               return 0;
-
-       dev_err(dev, "phy link never came up\n");
-       return -ETIMEDOUT;
-}
-
 static void ks_pcie_msi_irq_handler(struct irq_desc *desc)
 {
-       unsigned int irq = irq_desc_get_irq(desc);
+       unsigned int irq = desc->irq_data.hwirq;
        struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
-       u32 offset = irq - ks_pcie->msi_host_irqs[0];
+       u32 offset = irq - ks_pcie->msi_host_irq;
        struct dw_pcie *pci = ks_pcie->pci;
+       struct pcie_port *pp = &pci->pp;
        struct device *dev = pci->dev;
        struct irq_chip *chip = irq_desc_get_chip(desc);
+       u32 vector, virq, reg, pos;
 
        dev_dbg(dev, "%s, irq %d\n", __func__, irq);
 
@@ -589,7 +593,23 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc)
         * ack operation.
         */
        chained_irq_enter(chip, desc);
-       ks_pcie_handle_msi_irq(ks_pcie, offset);
+
+       reg = ks_pcie_app_readl(ks_pcie, MSI_IRQ_STATUS(offset));
+       /*
+        * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
+        * shows 1, 9, 17, 25 and so forth
+        */
+       for (pos = 0; pos < 4; pos++) {
+               if (!(reg & BIT(pos)))
+                       continue;
+
+               vector = offset + (pos << 3);
+               virq = irq_linear_revmap(pp->irq_domain, vector);
+               dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n", pos, vector,
+                       virq);
+               generic_handle_irq(virq);
+       }
+
        chained_irq_exit(chip, desc);
 }
 
@@ -622,89 +642,119 @@ static void ks_pcie_legacy_irq_handler(struct irq_desc *desc)
        chained_irq_exit(chip, desc);
 }
 
-static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
-                                          char *controller, int *num_irqs)
+static int ks_pcie_config_msi_irq(struct keystone_pcie *ks_pcie)
 {
-       int temp, max_host_irqs, legacy = 1, *host_irqs;
        struct device *dev = ks_pcie->pci->dev;
-       struct device_node *np_pcie = dev->of_node, **np_temp;
-
-       if (!strcmp(controller, "msi-interrupt-controller"))
-               legacy = 0;
+       struct device_node *np = ks_pcie->np;
+       struct device_node *intc_np;
+       struct irq_data *irq_data;
+       int irq_count, irq, ret, i;
 
-       if (legacy) {
-               np_temp = &ks_pcie->legacy_intc_np;
-               max_host_irqs = PCI_NUM_INTX;
-               host_irqs = &ks_pcie->legacy_host_irqs[0];
-       } else {
-               np_temp = &ks_pcie->msi_intc_np;
-               max_host_irqs = MAX_MSI_HOST_IRQS;
-               host_irqs =  &ks_pcie->msi_host_irqs[0];
-       }
+       if (!IS_ENABLED(CONFIG_PCI_MSI))
+               return 0;
 
-       /* interrupt controller is in a child node */
-       *np_temp = of_get_child_by_name(np_pcie, controller);
-       if (!(*np_temp)) {
-               dev_err(dev, "Node for %s is absent\n", controller);
+       intc_np = of_get_child_by_name(np, "msi-interrupt-controller");
+       if (!intc_np) {
+               if (ks_pcie->is_am6)
+                       return 0;
+               dev_warn(dev, "msi-interrupt-controller node is absent\n");
                return -EINVAL;
        }
 
-       temp = of_irq_count(*np_temp);
-       if (!temp) {
-               dev_err(dev, "No IRQ entries in %s\n", controller);
-               of_node_put(*np_temp);
-               return -EINVAL;
+       irq_count = of_irq_count(intc_np);
+       if (!irq_count) {
+               dev_err(dev, "No IRQ entries in msi-interrupt-controller\n");
+               ret = -EINVAL;
+               goto err;
        }
 
-       if (temp > max_host_irqs)
-               dev_warn(dev, "Too many %s interrupts defined %u\n",
-                       (legacy ? "legacy" : "MSI"), temp);
-
-       /*
-        * support upto max_host_irqs. In dt from index 0 to 3 (legacy) or 0 to
-        * 7 (MSI)
-        */
-       for (temp = 0; temp < max_host_irqs; temp++) {
-               host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp);
-               if (!host_irqs[temp])
-                       break;
-       }
+       for (i = 0; i < irq_count; i++) {
+               irq = irq_of_parse_and_map(intc_np, i);
+               if (!irq) {
+                       ret = -EINVAL;
+                       goto err;
+               }
 
-       of_node_put(*np_temp);
+               if (!ks_pcie->msi_host_irq) {
+                       irq_data = irq_get_irq_data(irq);
+                       if (!irq_data) {
+                               ret = -EINVAL;
+                               goto err;
+                       }
+                       ks_pcie->msi_host_irq = irq_data->hwirq;
+               }
 
-       if (temp) {
-               *num_irqs = temp;
-               return 0;
+               irq_set_chained_handler_and_data(irq, ks_pcie_msi_irq_handler,
+                                                ks_pcie);
        }
 
-       return -EINVAL;
+       of_node_put(intc_np);
+       return 0;
+
+err:
+       of_node_put(intc_np);
+       return ret;
 }
 
-static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
+static int ks_pcie_config_legacy_irq(struct keystone_pcie *ks_pcie)
 {
-       int i;
+       struct device *dev = ks_pcie->pci->dev;
+       struct irq_domain *legacy_irq_domain;
+       struct device_node *np = ks_pcie->np;
+       struct device_node *intc_np;
+       int irq_count, irq, ret = 0, i;
+
+       intc_np = of_get_child_by_name(np, "legacy-interrupt-controller");
+       if (!intc_np) {
+               /*
+                * Since legacy interrupts are modeled as edge-interrupts in
+                * AM6, keep it disabled for now.
+                */
+               if (ks_pcie->is_am6)
+                       return 0;
+               dev_warn(dev, "legacy-interrupt-controller node is absent\n");
+               return -EINVAL;
+       }
 
-       /* Legacy IRQ */
-       for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
-               irq_set_chained_handler_and_data(ks_pcie->legacy_host_irqs[i],
+       irq_count = of_irq_count(intc_np);
+       if (!irq_count) {
+               dev_err(dev, "No IRQ entries in legacy-interrupt-controller\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       for (i = 0; i < irq_count; i++) {
+               irq = irq_of_parse_and_map(intc_np, i);
+               if (!irq) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+               ks_pcie->legacy_host_irqs[i] = irq;
+
+               irq_set_chained_handler_and_data(irq,
                                                 ks_pcie_legacy_irq_handler,
                                                 ks_pcie);
        }
-       ks_pcie_enable_legacy_irqs(ks_pcie);
 
-       /* MSI IRQ */
-       if (IS_ENABLED(CONFIG_PCI_MSI)) {
-               for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) {
-                       irq_set_chained_handler_and_data(ks_pcie->msi_host_irqs[i],
-                                                        ks_pcie_msi_irq_handler,
-                                                        ks_pcie);
-               }
+       legacy_irq_domain =
+               irq_domain_add_linear(intc_np, PCI_NUM_INTX,
+                                     &ks_pcie_legacy_irq_domain_ops, NULL);
+       if (!legacy_irq_domain) {
+               dev_err(dev, "Failed to add irq domain for legacy irqs\n");
+               ret = -EINVAL;
+               goto err;
        }
+       ks_pcie->legacy_irq_domain = legacy_irq_domain;
+
+       for (i = 0; i < PCI_NUM_INTX; i++)
+               ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET(i), INTx_EN);
 
-       if (ks_pcie->error_irq > 0)
-               ks_pcie_enable_error_irq(ks_pcie);
+err:
+       of_node_put(intc_np);
+       return ret;
 }
 
+#ifdef CONFIG_ARM
 /*
  * When a PCI device does not exist during config cycles, keystone host gets a
  * bus error instead of returning 0xffffffff. This handler always returns 0
@@ -724,6 +774,7 @@ static int ks_pcie_fault(unsigned long addr, unsigned int fsr,
 
        return 0;
 }
+#endif
 
 static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie)
 {
@@ -742,8 +793,10 @@ static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie)
        if (ret)
                return ret;
 
+       dw_pcie_dbi_ro_wr_en(pci);
        dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, id & PCIE_VENDORID_MASK);
        dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, id >> PCIE_DEVICEID_SHIFT);
+       dw_pcie_dbi_ro_wr_dis(pci);
 
        return 0;
 }
@@ -754,11 +807,18 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
        struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
        int ret;
 
+       ret = ks_pcie_config_legacy_irq(ks_pcie);
+       if (ret)
+               return ret;
+
+       ret = ks_pcie_config_msi_irq(ks_pcie);
+       if (ret)
+               return ret;
+
        dw_pcie_setup_rc(pp);
 
-       ks_pcie_establish_link(ks_pcie);
+       ks_pcie_stop_link(pci);
        ks_pcie_setup_rc_app_regs(ks_pcie);
-       ks_pcie_setup_interrupts(ks_pcie);
        writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
                        pci->dbi_base + PCI_IO_BASE);
 
@@ -766,12 +826,17 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
        if (ret < 0)
                return ret;
 
+#ifdef CONFIG_ARM
        /*
         * PCIe access errors that result into OCP errors are caught by ARM as
         * "External aborts"
         */
        hook_fault_code(17, ks_pcie_fault, SIGBUS, 0,
                        "Asynchronous external abort");
+#endif
+
+       ks_pcie_start_link(pci);
+       dw_pcie_wait_for_link(pci);
 
        return 0;
 }
@@ -780,14 +845,15 @@ static const struct dw_pcie_host_ops ks_pcie_host_ops = {
        .rd_other_conf = ks_pcie_rd_other_conf,
        .wr_other_conf = ks_pcie_wr_other_conf,
        .host_init = ks_pcie_host_init,
-       .msi_set_irq = ks_pcie_msi_set_irq,
-       .msi_clear_irq = ks_pcie_msi_clear_irq,
-       .get_msi_addr = ks_pcie_get_msi_addr,
        .msi_host_init = ks_pcie_msi_host_init,
-       .msi_irq_ack = ks_pcie_msi_irq_ack,
        .scan_bus = ks_pcie_v3_65_scan_bus,
 };
 
+static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = {
+       .host_init = ks_pcie_host_init,
+       .msi_host_init = ks_pcie_am654_msi_host_init,
+};
+
 static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv)
 {
        struct keystone_pcie *ks_pcie = priv;
@@ -801,41 +867,17 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie,
        struct dw_pcie *pci = ks_pcie->pci;
        struct pcie_port *pp = &pci->pp;
        struct device *dev = &pdev->dev;
+       struct resource *res;
        int ret;
 
-       ret = ks_pcie_get_irq_controller_info(ks_pcie,
-                                       "legacy-interrupt-controller",
-                                       &ks_pcie->num_legacy_host_irqs);
-       if (ret)
-               return ret;
-
-       if (IS_ENABLED(CONFIG_PCI_MSI)) {
-               ret = ks_pcie_get_irq_controller_info(ks_pcie,
-                                               "msi-interrupt-controller",
-                                               &ks_pcie->num_msi_host_irqs);
-               if (ret)
-                       return ret;
-       }
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
+       pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res);
+       if (IS_ERR(pp->va_cfg0_base))
+               return PTR_ERR(pp->va_cfg0_base);
 
-       /*
-        * Index 0 is the platform interrupt for error interrupt
-        * from RC.  This is optional.
-        */
-       ks_pcie->error_irq = irq_of_parse_and_map(ks_pcie->np, 0);
-       if (ks_pcie->error_irq <= 0)
-               dev_info(dev, "no error IRQ defined\n");
-       else {
-               ret = request_irq(ks_pcie->error_irq, ks_pcie_err_irq_handler,
-                                 IRQF_SHARED, "pcie-error-irq", ks_pcie);
-               if (ret < 0) {
-                       dev_err(dev, "failed to request error IRQ %d\n",
-                               ks_pcie->error_irq);
-                       return ret;
-               }
-       }
+       pp->va_cfg1_base = pp->va_cfg0_base;
 
-       pp->ops = &ks_pcie_host_ops;
-       ret = ks_pcie_dw_host_init(ks_pcie);
+       ret = dw_pcie_host_init(pp);
        if (ret) {
                dev_err(dev, "failed to initialize host\n");
                return ret;
@@ -844,18 +886,139 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie,
        return 0;
 }
 
-static const struct of_device_id ks_pcie_of_match[] = {
-       {
-               .type = "pci",
-               .compatible = "ti,keystone-pcie",
-       },
-       { },
-};
+static u32 ks_pcie_am654_read_dbi2(struct dw_pcie *pci, void __iomem *base,
+                                  u32 reg, size_t size)
+{
+       struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+       u32 val;
+
+       ks_pcie_set_dbi_mode(ks_pcie);
+       dw_pcie_read(base + reg, size, &val);
+       ks_pcie_clear_dbi_mode(ks_pcie);
+       return val;
+}
+
+static void ks_pcie_am654_write_dbi2(struct dw_pcie *pci, void __iomem *base,
+                                    u32 reg, size_t size, u32 val)
+{
+       struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+
+       ks_pcie_set_dbi_mode(ks_pcie);
+       dw_pcie_write(base + reg, size, val);
+       ks_pcie_clear_dbi_mode(ks_pcie);
+}
 
 static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = {
+       .start_link = ks_pcie_start_link,
+       .stop_link = ks_pcie_stop_link,
        .link_up = ks_pcie_link_up,
+       .read_dbi2 = ks_pcie_am654_read_dbi2,
+       .write_dbi2 = ks_pcie_am654_write_dbi2,
+};
+
+static void ks_pcie_am654_ep_init(struct dw_pcie_ep *ep)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+       int flags;
+
+       ep->page_size = AM654_WIN_SIZE;
+       flags = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32;
+       dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_0, APP_ADDR_SPACE_0 - 1);
+       dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, flags);
+}
+
+static void ks_pcie_am654_raise_legacy_irq(struct keystone_pcie *ks_pcie)
+{
+       struct dw_pcie *pci = ks_pcie->pci;
+       u8 int_pin;
+
+       int_pin = dw_pcie_readb_dbi(pci, PCI_INTERRUPT_PIN);
+       if (int_pin == 0 || int_pin > 4)
+               return;
+
+       ks_pcie_app_writel(ks_pcie, PCIE_LEGACY_IRQ_ENABLE_SET(int_pin),
+                          INT_ENABLE);
+       ks_pcie_app_writel(ks_pcie, PCIE_EP_IRQ_SET, INT_ENABLE);
+       mdelay(1);
+       ks_pcie_app_writel(ks_pcie, PCIE_EP_IRQ_CLR, INT_ENABLE);
+       ks_pcie_app_writel(ks_pcie, PCIE_LEGACY_IRQ_ENABLE_CLR(int_pin),
+                          INT_ENABLE);
+}
+
+static int ks_pcie_am654_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
+                                  enum pci_epc_irq_type type,
+                                  u16 interrupt_num)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+       struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+
+       switch (type) {
+       case PCI_EPC_IRQ_LEGACY:
+               ks_pcie_am654_raise_legacy_irq(ks_pcie);
+               break;
+       case PCI_EPC_IRQ_MSI:
+               dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
+               break;
+       default:
+               dev_err(pci->dev, "UNKNOWN IRQ type\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct pci_epc_features ks_pcie_am654_epc_features = {
+       .linkup_notifier = false,
+       .msi_capable = true,
+       .msix_capable = false,
+       .reserved_bar = 1 << BAR_0 | 1 << BAR_1,
+       .bar_fixed_64bit = 1 << BAR_0,
+       .bar_fixed_size[2] = SZ_1M,
+       .bar_fixed_size[3] = SZ_64K,
+       .bar_fixed_size[4] = 256,
+       .bar_fixed_size[5] = SZ_1M,
+       .align = SZ_1M,
 };
 
+static const struct pci_epc_features*
+ks_pcie_am654_get_features(struct dw_pcie_ep *ep)
+{
+       return &ks_pcie_am654_epc_features;
+}
+
+static const struct dw_pcie_ep_ops ks_pcie_am654_ep_ops = {
+       .ep_init = ks_pcie_am654_ep_init,
+       .raise_irq = ks_pcie_am654_raise_irq,
+       .get_features = &ks_pcie_am654_get_features,
+};
+
+static int __init ks_pcie_add_pcie_ep(struct keystone_pcie *ks_pcie,
+                                     struct platform_device *pdev)
+{
+       int ret;
+       struct dw_pcie_ep *ep;
+       struct resource *res;
+       struct device *dev = &pdev->dev;
+       struct dw_pcie *pci = ks_pcie->pci;
+
+       ep = &pci->ep;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
+       if (!res)
+               return -EINVAL;
+
+       ep->phys_base = res->start;
+       ep->addr_size = resource_size(res);
+
+       ret = dw_pcie_ep_init(ep);
+       if (ret) {
+               dev_err(dev, "failed to initialize endpoint\n");
+               return ret;
+       }
+
+       return 0;
+}
+
 static void ks_pcie_disable_phy(struct keystone_pcie *ks_pcie)
 {
        int num_lanes = ks_pcie->num_lanes;
@@ -873,6 +1036,10 @@ static int ks_pcie_enable_phy(struct keystone_pcie *ks_pcie)
        int num_lanes = ks_pcie->num_lanes;
 
        for (i = 0; i < num_lanes; i++) {
+               ret = phy_reset(ks_pcie->phy[i]);
+               if (ret < 0)
+                       goto err_phy;
+
                ret = phy_init(ks_pcie->phy[i]);
                if (ret < 0)
                        goto err_phy;
@@ -895,20 +1062,161 @@ err_phy:
        return ret;
 }
 
+static int ks_pcie_set_mode(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct regmap *syscon;
+       u32 val;
+       u32 mask;
+       int ret = 0;
+
+       syscon = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pcie-mode");
+       if (IS_ERR(syscon))
+               return 0;
+
+       mask = KS_PCIE_DEV_TYPE_MASK | KS_PCIE_SYSCLOCKOUTEN;
+       val = KS_PCIE_DEV_TYPE(RC) | KS_PCIE_SYSCLOCKOUTEN;
+
+       ret = regmap_update_bits(syscon, 0, mask, val);
+       if (ret) {
+               dev_err(dev, "failed to set pcie mode\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ks_pcie_am654_set_mode(struct device *dev,
+                                 enum dw_pcie_device_mode mode)
+{
+       struct device_node *np = dev->of_node;
+       struct regmap *syscon;
+       u32 val;
+       u32 mask;
+       int ret = 0;
+
+       syscon = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pcie-mode");
+       if (IS_ERR(syscon))
+               return 0;
+
+       mask = AM654_PCIE_DEV_TYPE_MASK;
+
+       switch (mode) {
+       case DW_PCIE_RC_TYPE:
+               val = RC;
+               break;
+       case DW_PCIE_EP_TYPE:
+               val = EP;
+               break;
+       default:
+               dev_err(dev, "INVALID device type %d\n", mode);
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(syscon, 0, mask, val);
+       if (ret) {
+               dev_err(dev, "failed to set pcie mode\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void ks_pcie_set_link_speed(struct dw_pcie *pci, int link_speed)
+{
+       u32 val;
+
+       dw_pcie_dbi_ro_wr_en(pci);
+
+       val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP);
+       if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) {
+               val &= ~((u32)PCI_EXP_LNKCAP_SLS);
+               val |= link_speed;
+               dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP,
+                                  val);
+       }
+
+       val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2);
+       if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) {
+               val &= ~((u32)PCI_EXP_LNKCAP_SLS);
+               val |= link_speed;
+               dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2,
+                                  val);
+       }
+
+       dw_pcie_dbi_ro_wr_dis(pci);
+}
+
+static const struct ks_pcie_of_data ks_pcie_rc_of_data = {
+       .host_ops = &ks_pcie_host_ops,
+       .version = 0x365A,
+};
+
+static const struct ks_pcie_of_data ks_pcie_am654_rc_of_data = {
+       .host_ops = &ks_pcie_am654_host_ops,
+       .mode = DW_PCIE_RC_TYPE,
+       .version = 0x490A,
+};
+
+static const struct ks_pcie_of_data ks_pcie_am654_ep_of_data = {
+       .ep_ops = &ks_pcie_am654_ep_ops,
+       .mode = DW_PCIE_EP_TYPE,
+       .version = 0x490A,
+};
+
+static const struct of_device_id ks_pcie_of_match[] = {
+       {
+               .type = "pci",
+               .data = &ks_pcie_rc_of_data,
+               .compatible = "ti,keystone-pcie",
+       },
+       {
+               .data = &ks_pcie_am654_rc_of_data,
+               .compatible = "ti,am654-pcie-rc",
+       },
+       {
+               .data = &ks_pcie_am654_ep_of_data,
+               .compatible = "ti,am654-pcie-ep",
+       },
+       { },
+};
+
 static int __init ks_pcie_probe(struct platform_device *pdev)
 {
+       const struct dw_pcie_host_ops *host_ops;
+       const struct dw_pcie_ep_ops *ep_ops;
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
+       const struct ks_pcie_of_data *data;
+       const struct of_device_id *match;
+       enum dw_pcie_device_mode mode;
        struct dw_pcie *pci;
        struct keystone_pcie *ks_pcie;
        struct device_link **link;
+       struct gpio_desc *gpiod;
+       void __iomem *atu_base;
+       struct resource *res;
+       unsigned int version;
+       void __iomem *base;
        u32 num_viewport;
        struct phy **phy;
+       int link_speed;
        u32 num_lanes;
        char name[10];
        int ret;
+       int irq;
        int i;
 
+       match = of_match_device(of_match_ptr(ks_pcie_of_match), dev);
+       data = (struct ks_pcie_of_data *)match->data;
+       if (!data)
+               return -EINVAL;
+
+       version = data->version;
+       host_ops = data->host_ops;
+       ep_ops = data->ep_ops;
+       mode = data->mode;
+
        ks_pcie = devm_kzalloc(dev, sizeof(*ks_pcie), GFP_KERNEL);
        if (!ks_pcie)
                return -ENOMEM;
@@ -917,12 +1225,38 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
        if (!pci)
                return -ENOMEM;
 
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "app");
+       ks_pcie->va_app_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ks_pcie->va_app_base))
+               return PTR_ERR(ks_pcie->va_app_base);
+
+       ks_pcie->app = *res;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbics");
+       base = devm_pci_remap_cfg_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       if (of_device_is_compatible(np, "ti,am654-pcie-rc"))
+               ks_pcie->is_am6 = true;
+
+       pci->dbi_base = base;
+       pci->dbi_base2 = base;
        pci->dev = dev;
        pci->ops = &ks_pcie_dw_pcie_ops;
+       pci->version = version;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "missing IRQ resource: %d\n", irq);
+               return irq;
+       }
 
-       ret = of_property_read_u32(np, "num-viewport", &num_viewport);
+       ret = request_irq(irq, ks_pcie_err_irq_handler, IRQF_SHARED,
+                         "ks-pcie-error-irq", ks_pcie);
        if (ret < 0) {
-               dev_err(dev, "unable to read *num-viewport* property\n");
+               dev_err(dev, "failed to request error IRQ %d\n",
+                       irq);
                return ret;
        }
 
@@ -960,9 +1294,17 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
        ks_pcie->pci = pci;
        ks_pcie->link = link;
        ks_pcie->num_lanes = num_lanes;
-       ks_pcie->num_viewport = num_viewport;
        ks_pcie->phy = phy;
 
+       gpiod = devm_gpiod_get_optional(dev, "reset",
+                                       GPIOD_OUT_LOW);
+       if (IS_ERR(gpiod)) {
+               ret = PTR_ERR(gpiod);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to get reset GPIO\n");
+               goto err_link;
+       }
+
        ret = ks_pcie_enable_phy(ks_pcie);
        if (ret) {
                dev_err(dev, "failed to enable phy\n");
@@ -977,9 +1319,79 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
                goto err_get_sync;
        }
 
-       ret = ks_pcie_add_pcie_port(ks_pcie, pdev);
-       if (ret < 0)
-               goto err_get_sync;
+       if (pci->version >= 0x480A) {
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu");
+               atu_base = devm_ioremap_resource(dev, res);
+               if (IS_ERR(atu_base)) {
+                       ret = PTR_ERR(atu_base);
+                       goto err_get_sync;
+               }
+
+               pci->atu_base = atu_base;
+
+               ret = ks_pcie_am654_set_mode(dev, mode);
+               if (ret < 0)
+                       goto err_get_sync;
+       } else {
+               ret = ks_pcie_set_mode(dev);
+               if (ret < 0)
+                       goto err_get_sync;
+       }
+
+       link_speed = of_pci_get_max_link_speed(np);
+       if (link_speed < 0)
+               link_speed = 2;
+
+       ks_pcie_set_link_speed(pci, link_speed);
+
+       switch (mode) {
+       case DW_PCIE_RC_TYPE:
+               if (!IS_ENABLED(CONFIG_PCI_KEYSTONE_HOST)) {
+                       ret = -ENODEV;
+                       goto err_get_sync;
+               }
+
+               ret = of_property_read_u32(np, "num-viewport", &num_viewport);
+               if (ret < 0) {
+                       dev_err(dev, "unable to read *num-viewport* property\n");
+                       return ret;
+               }
+
+               /*
+                * "Power Sequencing and Reset Signal Timings" table in
+                * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0
+                * indicates PERST# should be deasserted after minimum of 100us
+                * once REFCLK is stable. The REFCLK to the connector in RC
+                * mode is selected while enabling the PHY. So deassert PERST#
+                * after 100 us.
+                */
+               if (gpiod) {
+                       usleep_range(100, 200);
+                       gpiod_set_value_cansleep(gpiod, 1);
+               }
+
+               ks_pcie->num_viewport = num_viewport;
+               pci->pp.ops = host_ops;
+               ret = ks_pcie_add_pcie_port(ks_pcie, pdev);
+               if (ret < 0)
+                       goto err_get_sync;
+               break;
+       case DW_PCIE_EP_TYPE:
+               if (!IS_ENABLED(CONFIG_PCI_KEYSTONE_EP)) {
+                       ret = -ENODEV;
+                       goto err_get_sync;
+               }
+
+               pci->ep.ops = ep_ops;
+               ret = ks_pcie_add_pcie_ep(ks_pcie, pdev);
+               if (ret < 0)
+                       goto err_get_sync;
+               break;
+       default:
+               dev_err(dev, "INVALID device type %d\n", mode);
+       }
+
+       ks_pcie_enable_error_irq(ks_pcie);
 
        return 0;
 
index a42c9c3ae1cc11bcf74f5de3af0101aab5fae1eb..be61d96cc95ed036e765d05afc0ab37b2707c742 100644 (file)
@@ -79,7 +79,7 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
        }
 }
 
-static struct dw_pcie_ep_ops pcie_ep_ops = {
+static const struct dw_pcie_ep_ops pcie_ep_ops = {
        .ep_init = ls_pcie_ep_init,
        .raise_irq = ls_pcie_ep_raise_irq,
        .get_features = ls_pcie_ep_get_features,
index ce45bde29bf888d3bd4d80710105b8c5fd970274..3a5fa26d5e5675f9eabc7273598fc7c620106771 100644 (file)
@@ -201,6 +201,7 @@ static int ls_pcie_msi_host_init(struct pcie_port *pp)
                return -EINVAL;
        }
 
+       of_node_put(msi_node);
        return 0;
 }
 
diff --git a/drivers/pci/controller/dwc/pcie-al.c b/drivers/pci/controller/dwc/pcie-al.c
new file mode 100644 (file)
index 0000000..3ab58f0
--- /dev/null
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCIe host controller driver for Amazon's Annapurna Labs IP (used in chips
+ * such as Graviton and Alpine)
+ *
+ * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Author: Jonathan Chocron <jonnyc@amazon.com>
+ */
+
+#include <linux/pci.h>
+#include <linux/pci-ecam.h>
+#include <linux/pci-acpi.h>
+#include "../../pci.h"
+
+#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
+
+struct al_pcie_acpi  {
+       void __iomem *dbi_base;
+};
+
+static void __iomem *al_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
+                                    int where)
+{
+       struct pci_config_window *cfg = bus->sysdata;
+       struct al_pcie_acpi *pcie = cfg->priv;
+       void __iomem *dbi_base = pcie->dbi_base;
+
+       if (bus->number == cfg->busr.start) {
+               /*
+                * The DW PCIe core doesn't filter out transactions to other
+                * devices/functions on the root bus num, so we do this here.
+                */
+               if (PCI_SLOT(devfn) > 0)
+                       return NULL;
+               else
+                       return dbi_base + where;
+       }
+
+       return pci_ecam_map_bus(bus, devfn, where);
+}
+
+static int al_pcie_init(struct pci_config_window *cfg)
+{
+       struct device *dev = cfg->parent;
+       struct acpi_device *adev = to_acpi_device(dev);
+       struct acpi_pci_root *root = acpi_driver_data(adev);
+       struct al_pcie_acpi *al_pcie;
+       struct resource *res;
+       int ret;
+
+       al_pcie = devm_kzalloc(dev, sizeof(*al_pcie), GFP_KERNEL);
+       if (!al_pcie)
+               return -ENOMEM;
+
+       res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
+       if (!res)
+               return -ENOMEM;
+
+       ret = acpi_get_rc_resources(dev, "AMZN0001", root->segment, res);
+       if (ret) {
+               dev_err(dev, "can't get rc dbi base address for SEG %d\n",
+                       root->segment);
+               return ret;
+       }
+
+       dev_dbg(dev, "Root port dbi res: %pR\n", res);
+
+       al_pcie->dbi_base = devm_pci_remap_cfg_resource(dev, res);
+       if (IS_ERR(al_pcie->dbi_base)) {
+               long err = PTR_ERR(al_pcie->dbi_base);
+
+               dev_err(dev, "couldn't remap dbi base %pR (err:%ld)\n",
+                       res, err);
+               return err;
+       }
+
+       cfg->priv = al_pcie;
+
+       return 0;
+}
+
+struct pci_ecam_ops al_pcie_ops = {
+       .bus_shift    = 20,
+       .init         =  al_pcie_init,
+       .pci_ops      = {
+               .map_bus    = al_pcie_map_bus,
+               .read       = pci_generic_config_read,
+               .write      = pci_generic_config_write,
+       }
+};
+
+#endif /* defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) */
index dba83abfe7649ccfa2ffd7675f500fb646ed7129..d00252bd8faeeb5f6bbda8472a66aa0a67dcb5ab 100644 (file)
@@ -444,7 +444,7 @@ static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
        return 0;
 }
 
-static struct dw_pcie_ep_ops pcie_ep_ops = {
+static const struct dw_pcie_ep_ops pcie_ep_ops = {
        .ep_init = artpec6_pcie_ep_init,
        .raise_irq = artpec6_pcie_raise_irq,
 };
index 24f5a775ad3496bcd1b82bf02adc91ebdb047278..2bf5a35c0570085a308c166ec39a41275cfafbab 100644 (file)
@@ -46,16 +46,19 @@ static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie *pci, u8 cap_ptr,
        u8 cap_id, next_cap_ptr;
        u16 reg;
 
+       if (!cap_ptr)
+               return 0;
+
        reg = dw_pcie_readw_dbi(pci, cap_ptr);
-       next_cap_ptr = (reg & 0xff00) >> 8;
        cap_id = (reg & 0x00ff);
 
-       if (!next_cap_ptr || cap_id > PCI_CAP_ID_MAX)
+       if (cap_id > PCI_CAP_ID_MAX)
                return 0;
 
        if (cap_id == cap)
                return cap_ptr;
 
+       next_cap_ptr = (reg & 0xff00) >> 8;
        return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap);
 }
 
@@ -67,9 +70,6 @@ static u8 dw_pcie_ep_find_capability(struct dw_pcie *pci, u8 cap)
        reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST);
        next_cap_ptr = (reg & 0x00ff);
 
-       if (!next_cap_ptr)
-               return 0;
-
        return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap);
 }
 
@@ -397,6 +397,7 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
 {
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
        struct pci_epc *epc = ep->epc;
+       unsigned int aligned_offset;
        u16 msg_ctrl, msg_data;
        u32 msg_addr_lower, msg_addr_upper, reg;
        u64 msg_addr;
@@ -422,13 +423,15 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
                reg = ep->msi_cap + PCI_MSI_DATA_32;
                msg_data = dw_pcie_readw_dbi(pci, reg);
        }
-       msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
+       aligned_offset = msg_addr_lower & (epc->mem->page_size - 1);
+       msg_addr = ((u64)msg_addr_upper) << 32 |
+                       (msg_addr_lower & ~aligned_offset);
        ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
                                  epc->mem->page_size);
        if (ret)
                return ret;
 
-       writel(msg_data | (interrupt_num - 1), ep->msi_mem);
+       writel(msg_data | (interrupt_num - 1), ep->msi_mem + aligned_offset);
 
        dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys);
 
@@ -504,10 +507,32 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
        pci_epc_mem_exit(epc);
 }
 
+static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap)
+{
+       u32 header;
+       int pos = PCI_CFG_SPACE_SIZE;
+
+       while (pos) {
+               header = dw_pcie_readl_dbi(pci, pos);
+               if (PCI_EXT_CAP_ID(header) == cap)
+                       return pos;
+
+               pos = PCI_EXT_CAP_NEXT(header);
+               if (!pos)
+                       break;
+       }
+
+       return 0;
+}
+
 int dw_pcie_ep_init(struct dw_pcie_ep *ep)
 {
+       int i;
        int ret;
+       u32 reg;
        void *addr;
+       unsigned int nbars;
+       unsigned int offset;
        struct pci_epc *epc;
        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
        struct device *dev = pci->dev;
@@ -517,10 +542,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
                dev_err(dev, "dbi_base/dbi_base2 is not populated\n");
                return -EINVAL;
        }
-       if (pci->iatu_unroll_enabled && !pci->atu_base) {
-               dev_err(dev, "atu_base is not populated\n");
-               return -EINVAL;
-       }
 
        ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows);
        if (ret < 0) {
@@ -595,6 +616,18 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
 
        ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX);
 
+       offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
+       if (offset) {
+               reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL);
+               nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >>
+                       PCI_REBAR_CTRL_NBAR_SHIFT;
+
+               dw_pcie_dbi_ro_wr_en(pci);
+               for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL)
+                       dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, 0x0);
+               dw_pcie_dbi_ro_wr_dis(pci);
+       }
+
        dw_pcie_setup(pci);
 
        return 0;
index 25087d3c9a8238d65bfad46b57c3486ac5aa5f51..77db325293199aaf1df4dd7193b49bf44f1d6375 100644 (file)
@@ -126,18 +126,12 @@ static void dw_pci_setup_msi_msg(struct irq_data *d, struct msi_msg *msg)
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        u64 msi_target;
 
-       if (pp->ops->get_msi_addr)
-               msi_target = pp->ops->get_msi_addr(pp);
-       else
-               msi_target = (u64)pp->msi_data;
+       msi_target = (u64)pp->msi_data;
 
        msg->address_lo = lower_32_bits(msi_target);
        msg->address_hi = upper_32_bits(msi_target);
 
-       if (pp->ops->get_msi_data)
-               msg->data = pp->ops->get_msi_data(pp, d->hwirq);
-       else
-               msg->data = d->hwirq;
+       msg->data = d->hwirq;
 
        dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
                (int)d->hwirq, msg->address_hi, msg->address_lo);
@@ -157,17 +151,13 @@ static void dw_pci_bottom_mask(struct irq_data *d)
 
        raw_spin_lock_irqsave(&pp->lock, flags);
 
-       if (pp->ops->msi_clear_irq) {
-               pp->ops->msi_clear_irq(pp, d->hwirq);
-       } else {
-               ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
-               res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
-               bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
+       ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
+       res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
+       bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
 
-               pp->irq_mask[ctrl] |= BIT(bit);
-               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
-                                   pp->irq_mask[ctrl]);
-       }
+       pp->irq_mask[ctrl] |= BIT(bit);
+       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
+                           pp->irq_mask[ctrl]);
 
        raw_spin_unlock_irqrestore(&pp->lock, flags);
 }
@@ -180,17 +170,13 @@ static void dw_pci_bottom_unmask(struct irq_data *d)
 
        raw_spin_lock_irqsave(&pp->lock, flags);
 
-       if (pp->ops->msi_set_irq) {
-               pp->ops->msi_set_irq(pp, d->hwirq);
-       } else {
-               ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
-               res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
-               bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
+       ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
+       res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
+       bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
 
-               pp->irq_mask[ctrl] &= ~BIT(bit);
-               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
-                                   pp->irq_mask[ctrl]);
-       }
+       pp->irq_mask[ctrl] &= ~BIT(bit);
+       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
+                           pp->irq_mask[ctrl]);
 
        raw_spin_unlock_irqrestore(&pp->lock, flags);
 }
@@ -199,20 +185,12 @@ static void dw_pci_bottom_ack(struct irq_data *d)
 {
        struct pcie_port *pp  = irq_data_get_irq_chip_data(d);
        unsigned int res, bit, ctrl;
-       unsigned long flags;
 
        ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
        res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
        bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
 
-       raw_spin_lock_irqsave(&pp->lock, flags);
-
        dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, BIT(bit));
-
-       if (pp->ops->msi_irq_ack)
-               pp->ops->msi_irq_ack(d->hwirq, pp);
-
-       raw_spin_unlock_irqrestore(&pp->lock, flags);
 }
 
 static struct irq_chip dw_pci_msi_bottom_irq_chip = {
@@ -245,7 +223,7 @@ static int dw_pcie_irq_domain_alloc(struct irq_domain *domain,
 
        for (i = 0; i < nr_irqs; i++)
                irq_domain_set_info(domain, virq + i, bit + i,
-                                   &dw_pci_msi_bottom_irq_chip,
+                                   pp->msi_irq_chip,
                                    pp, handle_edge_irq,
                                    NULL, NULL);
 
@@ -298,25 +276,31 @@ int dw_pcie_allocate_domains(struct pcie_port *pp)
 
 void dw_pcie_free_msi(struct pcie_port *pp)
 {
-       irq_set_chained_handler(pp->msi_irq, NULL);
-       irq_set_handler_data(pp->msi_irq, NULL);
+       if (pp->msi_irq) {
+               irq_set_chained_handler(pp->msi_irq, NULL);
+               irq_set_handler_data(pp->msi_irq, NULL);
+       }
 
        irq_domain_remove(pp->msi_domain);
        irq_domain_remove(pp->irq_domain);
+
+       if (pp->msi_page)
+               __free_page(pp->msi_page);
 }
 
 void dw_pcie_msi_init(struct pcie_port *pp)
 {
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        struct device *dev = pci->dev;
-       struct page *page;
        u64 msi_target;
 
-       page = alloc_page(GFP_KERNEL);
-       pp->msi_data = dma_map_page(dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE);
+       pp->msi_page = alloc_page(GFP_KERNEL);
+       pp->msi_data = dma_map_page(dev, pp->msi_page, 0, PAGE_SIZE,
+                                   DMA_FROM_DEVICE);
        if (dma_mapping_error(dev, pp->msi_data)) {
                dev_err(dev, "Failed to map MSI data\n");
-               __free_page(page);
+               __free_page(pp->msi_page);
+               pp->msi_page = NULL;
                return;
        }
        msi_target = (u64)pp->msi_data;
@@ -335,7 +319,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
        struct device_node *np = dev->of_node;
        struct platform_device *pdev = to_platform_device(dev);
        struct resource_entry *win, *tmp;
-       struct pci_bus *bus, *child;
+       struct pci_bus *child;
        struct pci_host_bridge *bridge;
        struct resource *cfg_res;
        int ret;
@@ -352,7 +336,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
                dev_err(dev, "Missing *config* reg space\n");
        }
 
-       bridge = pci_alloc_host_bridge(0);
+       bridge = devm_pci_alloc_host_bridge(dev, 0);
        if (!bridge)
                return -ENOMEM;
 
@@ -363,7 +347,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
 
        ret = devm_request_pci_bus_resources(dev, &bridge->windows);
        if (ret)
-               goto error;
+               return ret;
 
        /* Get the I/O and memory ranges from DT */
        resource_list_for_each_entry_safe(win, tmp, &bridge->windows) {
@@ -407,8 +391,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
                                                resource_size(pp->cfg));
                if (!pci->dbi_base) {
                        dev_err(dev, "Error with ioremap\n");
-                       ret = -ENOMEM;
-                       goto error;
+                       return -ENOMEM;
                }
        }
 
@@ -419,8 +402,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
                                        pp->cfg0_base, pp->cfg0_size);
                if (!pp->va_cfg0_base) {
                        dev_err(dev, "Error with ioremap in function\n");
-                       ret = -ENOMEM;
-                       goto error;
+                       return -ENOMEM;
                }
        }
 
@@ -430,8 +412,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
                                                pp->cfg1_size);
                if (!pp->va_cfg1_base) {
                        dev_err(dev, "Error with ioremap\n");
-                       ret = -ENOMEM;
-                       goto error;
+                       return -ENOMEM;
                }
        }
 
@@ -439,7 +420,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
        if (ret)
                pci->num_viewport = 2;
 
-       if (IS_ENABLED(CONFIG_PCI_MSI) && pci_msi_enabled()) {
+       if (pci_msi_enabled()) {
                /*
                 * If a specific SoC driver needs to change the
                 * default number of vectors, it needs to implement
@@ -454,14 +435,16 @@ int dw_pcie_host_init(struct pcie_port *pp)
                            pp->num_vectors == 0) {
                                dev_err(dev,
                                        "Invalid number of vectors\n");
-                               goto error;
+                               return -EINVAL;
                        }
                }
 
                if (!pp->ops->msi_host_init) {
+                       pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip;
+
                        ret = dw_pcie_allocate_domains(pp);
                        if (ret)
-                               goto error;
+                               return ret;
 
                        if (pp->msi_irq)
                                irq_set_chained_handler_and_data(pp->msi_irq,
@@ -470,14 +453,14 @@ int dw_pcie_host_init(struct pcie_port *pp)
                } else {
                        ret = pp->ops->msi_host_init(pp);
                        if (ret < 0)
-                               goto error;
+                               return ret;
                }
        }
 
        if (pp->ops->host_init) {
                ret = pp->ops->host_init(pp);
                if (ret)
-                       goto error;
+                       goto err_free_msi;
        }
 
        pp->root_bus_nr = pp->busn->start;
@@ -491,24 +474,25 @@ int dw_pcie_host_init(struct pcie_port *pp)
 
        ret = pci_scan_root_bus_bridge(bridge);
        if (ret)
-               goto error;
+               goto err_free_msi;
 
-       bus = bridge->bus;
+       pp->root_bus = bridge->bus;
 
        if (pp->ops->scan_bus)
                pp->ops->scan_bus(pp);
 
-       pci_bus_size_bridges(bus);
-       pci_bus_assign_resources(bus);
+       pci_bus_size_bridges(pp->root_bus);
+       pci_bus_assign_resources(pp->root_bus);
 
-       list_for_each_entry(child, &bus->children, node)
+       list_for_each_entry(child, &pp->root_bus->children, node)
                pcie_bus_configure_settings(child);
 
-       pci_bus_add_devices(bus);
+       pci_bus_add_devices(pp->root_bus);
        return 0;
 
-error:
-       pci_free_host_bridge(bridge);
+err_free_msi:
+       if (pci_msi_enabled() && !pp->ops->msi_host_init)
+               dw_pcie_free_msi(pp);
        return ret;
 }
 
@@ -628,17 +612,6 @@ static struct pci_ops dw_pcie_ops = {
        .write = dw_pcie_wr_conf,
 };
 
-static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
-{
-       u32 val;
-
-       val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT);
-       if (val == 0xffffffff)
-               return 1;
-
-       return 0;
-}
-
 void dw_pcie_setup_rc(struct pcie_port *pp)
 {
        u32 val, ctrl, num_ctrls;
@@ -646,17 +619,19 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
 
        dw_pcie_setup(pci);
 
-       num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
-
-       /* Initialize IRQ Status array */
-       for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
-               pp->irq_mask[ctrl] = ~0;
-               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
-                                       (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
-                                   4, pp->irq_mask[ctrl]);
-               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
-                                       (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
-                                   4, ~0);
+       if (!pp->ops->msi_host_init) {
+               num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
+
+               /* Initialize IRQ Status array */
+               for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
+                       pp->irq_mask[ctrl] = ~0;
+                       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
+                                           (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
+                                           4, pp->irq_mask[ctrl]);
+                       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
+                                           (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
+                                           4, ~0);
+               }
        }
 
        /* Setup RC BARs */
@@ -690,14 +665,6 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
         * we should not program the ATU here.
         */
        if (!pp->ops->rd_other_conf) {
-               /* Get iATU unroll support */
-               pci->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pci);
-               dev_dbg(pci->dev, "iATU unroll: %s\n",
-                       pci->iatu_unroll_enabled ? "enabled" : "disabled");
-
-               if (pci->iatu_unroll_enabled && !pci->atu_base)
-                       pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
-
                dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
                                          PCIE_ATU_TYPE_MEM, pp->mem_base,
                                          pp->mem_bus_addr, pp->mem_size);
index 932dbd0b34b62e6e00c82b1ab22b9ae28859e0ca..b58fdcbc664b85b97b06ee14a4d2c8f0850a15ab 100644 (file)
@@ -106,7 +106,7 @@ dw_plat_pcie_get_features(struct dw_pcie_ep *ep)
        return &dw_plat_pcie_epc_features;
 }
 
-static struct dw_pcie_ep_ops pcie_ep_ops = {
+static const struct dw_pcie_ep_ops pcie_ep_ops = {
        .ep_init = dw_plat_pcie_ep_init,
        .raise_irq = dw_plat_pcie_ep_raise_irq,
        .get_features = dw_plat_pcie_get_features,
index 31f6331ca46f1791733365b07438232a222493d1..9d7c51c32b3b0a232f4cd7864ddb06b967944a7c 100644 (file)
 
 #include "pcie-designware.h"
 
-/* PCIe Port Logic registers */
-#define PLR_OFFSET                     0x700
-#define PCIE_PHY_DEBUG_R1              (PLR_OFFSET + 0x2c)
-#define PCIE_PHY_DEBUG_R1_LINK_UP      (0x1 << 4)
-#define PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING     (0x1 << 29)
-
 int dw_pcie_read(void __iomem *addr, int size, u32 *val)
 {
        if (!IS_ALIGNED((uintptr_t)addr, size)) {
@@ -89,6 +83,37 @@ void __dw_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
                dev_err(pci->dev, "Write DBI address failed\n");
 }
 
+u32 __dw_pcie_read_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg,
+                       size_t size)
+{
+       int ret;
+       u32 val;
+
+       if (pci->ops->read_dbi2)
+               return pci->ops->read_dbi2(pci, base, reg, size);
+
+       ret = dw_pcie_read(base + reg, size, &val);
+       if (ret)
+               dev_err(pci->dev, "read DBI address failed\n");
+
+       return val;
+}
+
+void __dw_pcie_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg,
+                         size_t size, u32 val)
+{
+       int ret;
+
+       if (pci->ops->write_dbi2) {
+               pci->ops->write_dbi2(pci, base, reg, size, val);
+               return;
+       }
+
+       ret = dw_pcie_write(base + reg, size, val);
+       if (ret)
+               dev_err(pci->dev, "write DBI address failed\n");
+}
+
 static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg)
 {
        u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
@@ -334,9 +359,20 @@ int dw_pcie_link_up(struct dw_pcie *pci)
        if (pci->ops->link_up)
                return pci->ops->link_up(pci);
 
-       val = readl(pci->dbi_base + PCIE_PHY_DEBUG_R1);
-       return ((val & PCIE_PHY_DEBUG_R1_LINK_UP) &&
-               (!(val & PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING)));
+       val = readl(pci->dbi_base + PCIE_PORT_DEBUG1);
+       return ((val & PCIE_PORT_DEBUG1_LINK_UP) &&
+               (!(val & PCIE_PORT_DEBUG1_LINK_IN_TRAINING)));
+}
+
+static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
+{
+       u32 val;
+
+       val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT);
+       if (val == 0xffffffff)
+               return 1;
+
+       return 0;
 }
 
 void dw_pcie_setup(struct dw_pcie *pci)
@@ -347,6 +383,16 @@ void dw_pcie_setup(struct dw_pcie *pci)
        struct device *dev = pci->dev;
        struct device_node *np = dev->of_node;
 
+       if (pci->version >= 0x480A || (!pci->version &&
+                                      dw_pcie_iatu_unroll_enabled(pci))) {
+               pci->iatu_unroll_enabled = true;
+               if (!pci->atu_base)
+                       pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
+       }
+       dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
+               "enabled" : "disabled");
+
+
        ret = of_property_read_u32(np, "num-lanes", &lanes);
        if (ret)
                lanes = 0;
index 377f4c0b52da5a78ba9de309267e6d19acd6867f..b8993f2b78df8f003b3fb1735eb9504428b04d03 100644 (file)
@@ -41,6 +41,9 @@
 #define PCIE_PORT_DEBUG0               0x728
 #define PORT_LOGIC_LTSSM_STATE_MASK    0x1f
 #define PORT_LOGIC_LTSSM_STATE_L0      0x11
+#define PCIE_PORT_DEBUG1               0x72C
+#define PCIE_PORT_DEBUG1_LINK_UP               BIT(4)
+#define PCIE_PORT_DEBUG1_LINK_IN_TRAINING      BIT(29)
 
 #define PCIE_LINK_WIDTH_SPEED_CONTROL  0x80C
 #define PORT_LOGIC_SPEED_CHANGE                BIT(17)
@@ -145,14 +148,9 @@ struct dw_pcie_host_ops {
        int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
                             unsigned int devfn, int where, int size, u32 val);
        int (*host_init)(struct pcie_port *pp);
-       void (*msi_set_irq)(struct pcie_port *pp, int irq);
-       void (*msi_clear_irq)(struct pcie_port *pp, int irq);
-       phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
-       u32 (*get_msi_data)(struct pcie_port *pp, int pos);
        void (*scan_bus)(struct pcie_port *pp);
        void (*set_num_vectors)(struct pcie_port *pp);
        int (*msi_host_init)(struct pcie_port *pp);
-       void (*msi_irq_ack)(int irq, struct pcie_port *pp);
 };
 
 struct pcie_port {
@@ -179,8 +177,11 @@ struct pcie_port {
        struct irq_domain       *irq_domain;
        struct irq_domain       *msi_domain;
        dma_addr_t              msi_data;
+       struct page             *msi_page;
+       struct irq_chip         *msi_irq_chip;
        u32                     num_vectors;
        u32                     irq_mask[MAX_MSI_CTRLS];
+       struct pci_bus          *root_bus;
        raw_spinlock_t          lock;
        DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
 };
@@ -200,7 +201,7 @@ struct dw_pcie_ep_ops {
 
 struct dw_pcie_ep {
        struct pci_epc          *epc;
-       struct dw_pcie_ep_ops   *ops;
+       const struct dw_pcie_ep_ops *ops;
        phys_addr_t             phys_base;
        size_t                  addr_size;
        size_t                  page_size;
@@ -222,6 +223,10 @@ struct dw_pcie_ops {
                            size_t size);
        void    (*write_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
                             size_t size, u32 val);
+       u32     (*read_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
+                            size_t size);
+       void    (*write_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
+                             size_t size, u32 val);
        int     (*link_up)(struct dw_pcie *pcie);
        int     (*start_link)(struct dw_pcie *pcie);
        void    (*stop_link)(struct dw_pcie *pcie);
@@ -238,6 +243,7 @@ struct dw_pcie {
        struct pcie_port        pp;
        struct dw_pcie_ep       ep;
        const struct dw_pcie_ops *ops;
+       unsigned int            version;
 };
 
 #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
@@ -252,6 +258,10 @@ u32 __dw_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
                       size_t size);
 void __dw_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
                         size_t size, u32 val);
+u32 __dw_pcie_read_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg,
+                       size_t size);
+void __dw_pcie_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg,
+                         size_t size, u32 val);
 int dw_pcie_link_up(struct dw_pcie *pci);
 int dw_pcie_wait_for_link(struct dw_pcie *pci);
 void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
@@ -295,12 +305,12 @@ static inline u8 dw_pcie_readb_dbi(struct dw_pcie *pci, u32 reg)
 
 static inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, u32 reg, u32 val)
 {
-       __dw_pcie_write_dbi(pci, pci->dbi_base2, reg, 0x4, val);
+       __dw_pcie_write_dbi2(pci, pci->dbi_base2, reg, 0x4, val);
 }
 
 static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg)
 {
-       return __dw_pcie_read_dbi(pci, pci->dbi_base2, reg, 0x4);
+       return __dw_pcie_read_dbi2(pci, pci->dbi_base2, reg, 0x4);
 }
 
 static inline void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
index a7f70355679024772895eb96275c10d4007464c1..0ed235d560e32fd07b23648eefca61e98dd7ea14 100644 (file)
@@ -1129,25 +1129,8 @@ err_deinit:
        return ret;
 }
 
-static int qcom_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
-                                u32 *val)
-{
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-
-       /* the device class is not reported correctly from the register */
-       if (where == PCI_CLASS_REVISION && size == 4) {
-               *val = readl(pci->dbi_base + PCI_CLASS_REVISION);
-               *val &= 0xff;   /* keep revision id */
-               *val |= PCI_CLASS_BRIDGE_PCI << 16;
-               return PCIBIOS_SUCCESSFUL;
-       }
-
-       return dw_pcie_read(pci->dbi_base + where, size, val);
-}
-
 static const struct dw_pcie_host_ops qcom_pcie_dw_ops = {
        .host_init = qcom_pcie_host_init,
-       .rd_own_conf = qcom_pcie_rd_own_conf,
 };
 
 /* Qcom IP rev.: 2.1.0 Synopsys IP rev.: 4.01a */
@@ -1309,6 +1292,12 @@ static const struct of_device_id qcom_pcie_match[] = {
        { }
 };
 
+static void qcom_fixup_class(struct pci_dev *dev)
+{
+       dev->class = PCI_CLASS_BRIDGE_PCI << 8;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, PCI_ANY_ID, qcom_fixup_class);
+
 static struct platform_driver qcom_pcie_driver = {
        .probe = qcom_pcie_probe,
        .driver = {
index d5dc40289cce14c4ea62764bbb33b49991b6d2a7..3f30ee4a00b3838ae2e56fdf789942bddb2eaa33 100644 (file)
@@ -270,6 +270,7 @@ static int uniphier_pcie_config_legacy_irq(struct pcie_port *pp)
        struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
        struct device_node *np = pci->dev->of_node;
        struct device_node *np_intc;
+       int ret = 0;
 
        np_intc = of_get_child_by_name(np, "legacy-interrupt-controller");
        if (!np_intc) {
@@ -280,20 +281,24 @@ static int uniphier_pcie_config_legacy_irq(struct pcie_port *pp)
        pp->irq = irq_of_parse_and_map(np_intc, 0);
        if (!pp->irq) {
                dev_err(pci->dev, "Failed to get an IRQ entry in legacy-interrupt-controller\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_put_node;
        }
 
        priv->legacy_irq_domain = irq_domain_add_linear(np_intc, PCI_NUM_INTX,
                                                &uniphier_intx_domain_ops, pp);
        if (!priv->legacy_irq_domain) {
                dev_err(pci->dev, "Failed to get INTx domain\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto out_put_node;
        }
 
        irq_set_chained_handler_and_data(pp->irq, uniphier_pcie_irq_handler,
                                         pp);
 
-       return 0;
+out_put_node:
+       of_node_put(np_intc);
+       return ret;
 }
 
 static int uniphier_pcie_host_init(struct pcie_port *pp)
index eb58dfdaba1bf8a23bc7251594d68638b81aac88..134e0306ff00bb46b1fcfe6ca782dcabf0cf9469 100644 (file)
@@ -794,6 +794,7 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie)
        struct device_node *node = dev->of_node;
        struct device_node *pcie_intc_node;
        struct irq_chip *irq_chip;
+       int ret = 0;
 
        pcie_intc_node =  of_get_next_child(node, NULL);
        if (!pcie_intc_node) {
@@ -806,8 +807,8 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie)
        irq_chip->name = devm_kasprintf(dev, GFP_KERNEL, "%s-irq",
                                        dev_name(dev));
        if (!irq_chip->name) {
-               of_node_put(pcie_intc_node);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out_put_node;
        }
 
        irq_chip->irq_mask = advk_pcie_irq_mask;
@@ -819,11 +820,13 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie)
                                      &advk_pcie_irq_domain_ops, pcie);
        if (!pcie->irq_domain) {
                dev_err(dev, "Failed to get a INTx IRQ domain\n");
-               of_node_put(pcie_intc_node);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out_put_node;
        }
 
-       return 0;
+out_put_node:
+       of_node_put(pcie_intc_node);
+       return ret;
 }
 
 static void advk_pcie_remove_irq_domain(struct advk_pcie *pcie)
index dea3ec7592a231052010e4935d85ee1073352c6f..75a2fb930d4bd2af088362a9491c8363056e835e 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Simple, generic PCI host controller driver targetting firmware-initialised
+ * Simple, generic PCI host controller driver targeting firmware-initialised
  * systems and virtual machines (e.g. the PCI emulation provided by kvmtool).
  *
  * Copyright (C) 2014 ARM Limited
index 95441a35ecebbcdee6e12ffe3be17cff963dcb3f..82acd6155adf3d0d8670033a718854a52eac9a23 100644 (file)
@@ -1486,6 +1486,21 @@ static void hv_pci_assign_slots(struct hv_pcibus_device *hbus)
        }
 }
 
+/*
+ * Remove entries in sysfs pci slot directory.
+ */
+static void hv_pci_remove_slots(struct hv_pcibus_device *hbus)
+{
+       struct hv_pci_dev *hpdev;
+
+       list_for_each_entry(hpdev, &hbus->children, list_entry) {
+               if (!hpdev->pci_slot)
+                       continue;
+               pci_destroy_slot(hpdev->pci_slot);
+               hpdev->pci_slot = NULL;
+       }
+}
+
 /**
  * create_root_hv_pci_bus() - Expose a new root PCI bus
  * @hbus:      Root PCI bus, as understood by this driver
@@ -1761,6 +1776,10 @@ static void pci_devices_present_work(struct work_struct *work)
                hpdev = list_first_entry(&removed, struct hv_pci_dev,
                                         list_entry);
                list_del(&hpdev->list_entry);
+
+               if (hpdev->pci_slot)
+                       pci_destroy_slot(hpdev->pci_slot);
+
                put_pcichild(hpdev);
        }
 
@@ -1900,6 +1919,9 @@ static void hv_eject_device_work(struct work_struct *work)
                         sizeof(*ejct_pkt), (unsigned long)&ctxt.pkt,
                         VM_PKT_DATA_INBAND, 0);
 
+       /* For the get_pcichild() in hv_pci_eject_device() */
+       put_pcichild(hpdev);
+       /* For the two refs got in new_pcichild_device() */
        put_pcichild(hpdev);
        put_pcichild(hpdev);
        put_hvpcibus(hpdev->hbus);
@@ -2677,6 +2699,7 @@ static int hv_pci_remove(struct hv_device *hdev)
                pci_lock_rescan_remove();
                pci_stop_root_bus(hbus->pci_bus);
                pci_remove_root_bus(hbus->pci_bus);
+               hv_pci_remove_slots(hbus);
                pci_unlock_rescan_remove();
                hbus->state = hv_pcibus_removed;
        }
index f4f53d092e00526cd4dec08e575334fd9f400c1e..464ba2538d52606eff261d6982455734f5724838 100644 (file)
@@ -231,9 +231,9 @@ struct tegra_msi {
        struct msi_controller chip;
        DECLARE_BITMAP(used, INT_PCI_MSI_NR);
        struct irq_domain *domain;
-       unsigned long pages;
        struct mutex lock;
-       u64 phys;
+       void *virt;
+       dma_addr_t phys;
        int irq;
 };
 
@@ -1536,7 +1536,7 @@ static int tegra_pcie_msi_setup(struct tegra_pcie *pcie)
        err = platform_get_irq_byname(pdev, "msi");
        if (err < 0) {
                dev_err(dev, "failed to get IRQ: %d\n", err);
-               goto err;
+               goto free_irq_domain;
        }
 
        msi->irq = err;
@@ -1545,17 +1545,35 @@ static int tegra_pcie_msi_setup(struct tegra_pcie *pcie)
                          tegra_msi_irq_chip.name, pcie);
        if (err < 0) {
                dev_err(dev, "failed to request IRQ: %d\n", err);
-               goto err;
+               goto free_irq_domain;
+       }
+
+       /* Though the PCIe controller can address >32-bit address space, to
+        * facilitate endpoints that support only 32-bit MSI target address,
+        * the mask is set to 32-bit to make sure that MSI target address is
+        * always a 32-bit address
+        */
+       err = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+       if (err < 0) {
+               dev_err(dev, "failed to set DMA coherent mask: %d\n", err);
+               goto free_irq;
+       }
+
+       msi->virt = dma_alloc_attrs(dev, PAGE_SIZE, &msi->phys, GFP_KERNEL,
+                                   DMA_ATTR_NO_KERNEL_MAPPING);
+       if (!msi->virt) {
+               dev_err(dev, "failed to allocate DMA memory for MSI\n");
+               err = -ENOMEM;
+               goto free_irq;
        }
 
-       /* setup AFI/FPCI range */
-       msi->pages = __get_free_pages(GFP_KERNEL, 0);
-       msi->phys = virt_to_phys((void *)msi->pages);
        host->msi = &msi->chip;
 
        return 0;
 
-err:
+free_irq:
+       free_irq(msi->irq, pcie);
+free_irq_domain:
        irq_domain_remove(msi->domain);
        return err;
 }
@@ -1592,7 +1610,8 @@ static void tegra_pcie_msi_teardown(struct tegra_pcie *pcie)
        struct tegra_msi *msi = &pcie->msi;
        unsigned int i, irq;
 
-       free_pages(msi->pages, 0);
+       dma_free_attrs(pcie->dev, PAGE_SIZE, msi->virt, msi->phys,
+                      DMA_ATTR_NO_KERNEL_MAPPING);
 
        if (msi->irq > 0)
                free_irq(msi->irq, pcie);
index cb3401a931f89523db1bbc6fc1421bf955e999bf..0a3f61be5625b27453ef735f60d358856d1bdf64 100644 (file)
@@ -367,7 +367,7 @@ static void iproc_msi_handler(struct irq_desc *desc)
 
                /*
                 * Now go read the tail pointer again to see if there are new
-                * oustanding events that came in during the above window.
+                * outstanding events that came in during the above window.
                 */
        } while (true);
 
index c20fd6bd68fd80e19fcfe51e7c7268ff8847662e..e3ca464974701dfaef078b9791bf2ee65d4edbd4 100644 (file)
 #define APB_ERR_EN_SHIFT               0
 #define APB_ERR_EN                     BIT(APB_ERR_EN_SHIFT)
 
+#define CFG_RD_SUCCESS                 0
+#define CFG_RD_UR                      1
+#define CFG_RD_CRS                     2
+#define CFG_RD_CA                      3
 #define CFG_RETRY_STATUS               0xffff0001
 #define CFG_RETRY_STATUS_TIMEOUT_US    500000 /* 500 milliseconds */
 
@@ -289,6 +293,9 @@ enum iproc_pcie_reg {
        IPROC_PCIE_IARR4,
        IPROC_PCIE_IMAP4,
 
+       /* config read status */
+       IPROC_PCIE_CFG_RD_STATUS,
+
        /* link status */
        IPROC_PCIE_LINK_STATUS,
 
@@ -350,6 +357,7 @@ static const u16 iproc_pcie_reg_paxb_v2[] = {
        [IPROC_PCIE_IMAP3]              = 0xe08,
        [IPROC_PCIE_IARR4]              = 0xe68,
        [IPROC_PCIE_IMAP4]              = 0xe70,
+       [IPROC_PCIE_CFG_RD_STATUS]      = 0xee0,
        [IPROC_PCIE_LINK_STATUS]        = 0xf0c,
        [IPROC_PCIE_APB_ERR_EN]         = 0xf40,
 };
@@ -474,10 +482,12 @@ static void __iomem *iproc_pcie_map_ep_cfg_reg(struct iproc_pcie *pcie,
        return (pcie->base + offset);
 }
 
-static unsigned int iproc_pcie_cfg_retry(void __iomem *cfg_data_p)
+static unsigned int iproc_pcie_cfg_retry(struct iproc_pcie *pcie,
+                                        void __iomem *cfg_data_p)
 {
        int timeout = CFG_RETRY_STATUS_TIMEOUT_US;
        unsigned int data;
+       u32 status;
 
        /*
         * As per PCIe spec r3.1, sec 2.3.2, CRS Software Visibility only
@@ -498,6 +508,15 @@ static unsigned int iproc_pcie_cfg_retry(void __iomem *cfg_data_p)
         */
        data = readl(cfg_data_p);
        while (data == CFG_RETRY_STATUS && timeout--) {
+               /*
+                * CRS state is set in CFG_RD status register
+                * This will handle the case where CFG_RETRY_STATUS is
+                * valid config data.
+                */
+               status = iproc_pcie_read_reg(pcie, IPROC_PCIE_CFG_RD_STATUS);
+               if (status != CFG_RD_CRS)
+                       return data;
+
                udelay(1);
                data = readl(cfg_data_p);
        }
@@ -576,7 +595,7 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
        if (!cfg_data_p)
                return PCIBIOS_DEVICE_NOT_FOUND;
 
-       data = iproc_pcie_cfg_retry(cfg_data_p);
+       data = iproc_pcie_cfg_retry(pcie, cfg_data_p);
 
        *val = data;
        if (size <= 2)
@@ -936,8 +955,25 @@ static int iproc_pcie_setup_ob(struct iproc_pcie *pcie, u64 axi_addr,
                        resource_size_t window_size =
                                ob_map->window_sizes[size_idx] * SZ_1M;
 
-                       if (size < window_size)
-                               continue;
+                       /*
+                        * Keep iterating until we reach the last window and
+                        * with the minimal window size at index zero. In this
+                        * case, we take a compromise by mapping it using the
+                        * minimum window size that can be supported
+                        */
+                       if (size < window_size) {
+                               if (size_idx > 0 || window_idx > 0)
+                                       continue;
+
+                               /*
+                                * For the corner case of reaching the minimal
+                                * window size that can be supported on the
+                                * last window
+                                */
+                               axi_addr = ALIGN_DOWN(axi_addr, window_size);
+                               pci_addr = ALIGN_DOWN(pci_addr, window_size);
+                               size = window_size;
+                       }
 
                        if (!IS_ALIGNED(axi_addr, window_size) ||
                            !IS_ALIGNED(pci_addr, window_size)) {
@@ -1146,11 +1182,43 @@ err_ib:
        return ret;
 }
 
+static int iproc_pcie_add_dma_range(struct device *dev,
+                                   struct list_head *resources,
+                                   struct of_pci_range *range)
+{
+       struct resource *res;
+       struct resource_entry *entry, *tmp;
+       struct list_head *head = resources;
+
+       res = devm_kzalloc(dev, sizeof(struct resource), GFP_KERNEL);
+       if (!res)
+               return -ENOMEM;
+
+       resource_list_for_each_entry(tmp, resources) {
+               if (tmp->res->start < range->cpu_addr)
+                       head = &tmp->node;
+       }
+
+       res->start = range->cpu_addr;
+       res->end = res->start + range->size - 1;
+
+       entry = resource_list_create_entry(res, 0);
+       if (!entry)
+               return -ENOMEM;
+
+       entry->offset = res->start - range->cpu_addr;
+       resource_list_add(entry, head);
+
+       return 0;
+}
+
 static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie)
 {
+       struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
        struct of_pci_range range;
        struct of_pci_range_parser parser;
        int ret;
+       LIST_HEAD(resources);
 
        /* Get the dma-ranges from DT */
        ret = of_pci_dma_range_parser_init(&parser, pcie->dev->of_node);
@@ -1158,13 +1226,23 @@ static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie)
                return ret;
 
        for_each_of_pci_range(&parser, &range) {
+               ret = iproc_pcie_add_dma_range(pcie->dev,
+                                              &resources,
+                                              &range);
+               if (ret)
+                       goto out;
                /* Each range entry corresponds to an inbound mapping region */
                ret = iproc_pcie_setup_ib(pcie, &range, IPROC_PCIE_IB_MAP_MEM);
                if (ret)
-                       return ret;
+                       goto out;
        }
 
+       list_splice_init(&resources, &host->dma_ranges);
+
        return 0;
+out:
+       pci_free_resource_list(&resources);
+       return ret;
 }
 
 static int iproce_pcie_get_msi(struct iproc_pcie *pcie,
@@ -1320,14 +1398,18 @@ static int iproc_pcie_msi_enable(struct iproc_pcie *pcie)
        if (pcie->need_msi_steer) {
                ret = iproc_pcie_msi_steer(pcie, msi_node);
                if (ret)
-                       return ret;
+                       goto out_put_node;
        }
 
        /*
         * If another MSI controller is being used, the call below should fail
         * but that is okay
         */
-       return iproc_msi_init(pcie, msi_node);
+       ret = iproc_msi_init(pcie, msi_node);
+
+out_put_node:
+       of_node_put(msi_node);
+       return ret;
 }
 
 static void iproc_pcie_msi_disable(struct iproc_pcie *pcie)
@@ -1347,7 +1429,6 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie)
                break;
        case IPROC_PCIE_PAXB:
                regs = iproc_pcie_reg_paxb;
-               pcie->iproc_cfg_read = true;
                pcie->has_apb_err_disable = true;
                if (pcie->need_ob_cfg) {
                        pcie->ob_map = paxb_ob_map;
@@ -1356,6 +1437,7 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie)
                break;
        case IPROC_PCIE_PAXB_V2:
                regs = iproc_pcie_reg_paxb_v2;
+               pcie->iproc_cfg_read = true;
                pcie->has_apb_err_disable = true;
                if (pcie->need_ob_cfg) {
                        pcie->ob_map = paxb_v2_ob_map;
index 0b6c72804e03b77816c7bef286d7e350651c38d4..80601e1b939eba94f29daa8b5437e54f77b19947 100644 (file)
@@ -578,6 +578,7 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port,
 
        port->irq_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
                                                 &intx_domain_ops, port);
+       of_node_put(pcie_intc_node);
        if (!port->irq_domain) {
                dev_err(dev, "failed to get INTx IRQ domain\n");
                return -ENODEV;
@@ -915,49 +916,29 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie,
 
        /* sys_ck might be divided into the following parts in some chips */
        snprintf(name, sizeof(name), "ahb_ck%d", slot);
-       port->ahb_ck = devm_clk_get(dev, name);
-       if (IS_ERR(port->ahb_ck)) {
-               if (PTR_ERR(port->ahb_ck) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               port->ahb_ck = NULL;
-       }
+       port->ahb_ck = devm_clk_get_optional(dev, name);
+       if (IS_ERR(port->ahb_ck))
+               return PTR_ERR(port->ahb_ck);
 
        snprintf(name, sizeof(name), "axi_ck%d", slot);
-       port->axi_ck = devm_clk_get(dev, name);
-       if (IS_ERR(port->axi_ck)) {
-               if (PTR_ERR(port->axi_ck) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               port->axi_ck = NULL;
-       }
+       port->axi_ck = devm_clk_get_optional(dev, name);
+       if (IS_ERR(port->axi_ck))
+               return PTR_ERR(port->axi_ck);
 
        snprintf(name, sizeof(name), "aux_ck%d", slot);
-       port->aux_ck = devm_clk_get(dev, name);
-       if (IS_ERR(port->aux_ck)) {
-               if (PTR_ERR(port->aux_ck) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               port->aux_ck = NULL;
-       }
+       port->aux_ck = devm_clk_get_optional(dev, name);
+       if (IS_ERR(port->aux_ck))
+               return PTR_ERR(port->aux_ck);
 
        snprintf(name, sizeof(name), "obff_ck%d", slot);
-       port->obff_ck = devm_clk_get(dev, name);
-       if (IS_ERR(port->obff_ck)) {
-               if (PTR_ERR(port->obff_ck) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               port->obff_ck = NULL;
-       }
+       port->obff_ck = devm_clk_get_optional(dev, name);
+       if (IS_ERR(port->obff_ck))
+               return PTR_ERR(port->obff_ck);
 
        snprintf(name, sizeof(name), "pipe_ck%d", slot);
-       port->pipe_ck = devm_clk_get(dev, name);
-       if (IS_ERR(port->pipe_ck)) {
-               if (PTR_ERR(port->pipe_ck) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               port->pipe_ck = NULL;
-       }
+       port->pipe_ck = devm_clk_get_optional(dev, name);
+       if (IS_ERR(port->pipe_ck))
+               return PTR_ERR(port->pipe_ck);
 
        snprintf(name, sizeof(name), "pcie-rst%d", slot);
        port->reset = devm_reset_control_get_optional_exclusive(dev, name);
index c8febb009454cdcfc0ed473f4cdb9540af0de59e..f6a669a9af414392cc0735c554edc7569ad2fe64 100644 (file)
 
 /* Transfer control */
 #define PCIETCTLR              0x02000
-#define  CFINIT                        1
+#define  DL_DOWN               BIT(3)
+#define  CFINIT                        BIT(0)
 #define PCIETSTR               0x02004
-#define  DATA_LINK_ACTIVE      1
+#define  DATA_LINK_ACTIVE      BIT(0)
 #define PCIEERRFR              0x02020
 #define  UNSUPPORTED_REQUEST   BIT(4)
 #define PCIEMSIFR              0x02044
 #define PCIEMSIALR             0x02048
-#define  MSIFE                 1
+#define  MSIFE                 BIT(0)
 #define PCIEMSIAUR             0x0204c
 #define PCIEMSIIER             0x02050
 
@@ -94,6 +95,7 @@
 #define MACCTLR                        0x011058
 #define  SPEED_CHANGE          BIT(24)
 #define  SCRAMBLE_DISABLE      BIT(27)
+#define PMSR                   0x01105c
 #define MACS2R                 0x011078
 #define MACCGSPSETR            0x011084
 #define  SPCNGRSN              BIT(31)
@@ -152,14 +154,13 @@ struct rcar_pcie {
        struct                  rcar_msi msi;
 };
 
-static void rcar_pci_write_reg(struct rcar_pcie *pcie, unsigned long val,
-                              unsigned long reg)
+static void rcar_pci_write_reg(struct rcar_pcie *pcie, u32 val,
+                              unsigned int reg)
 {
        writel(val, pcie->base + reg);
 }
 
-static unsigned long rcar_pci_read_reg(struct rcar_pcie *pcie,
-                                      unsigned long reg)
+static u32 rcar_pci_read_reg(struct rcar_pcie *pcie, unsigned int reg)
 {
        return readl(pcie->base + reg);
 }
@@ -171,7 +172,7 @@ enum {
 
 static void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data)
 {
-       int shift = 8 * (where & 3);
+       unsigned int shift = BITS_PER_BYTE * (where & 3);
        u32 val = rcar_pci_read_reg(pcie, where & ~3);
 
        val &= ~(mask << shift);
@@ -181,7 +182,7 @@ static void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data)
 
 static u32 rcar_read_conf(struct rcar_pcie *pcie, int where)
 {
-       int shift = 8 * (where & 3);
+       unsigned int shift = BITS_PER_BYTE * (where & 3);
        u32 val = rcar_pci_read_reg(pcie, where & ~3);
 
        return val >> shift;
@@ -192,7 +193,7 @@ static int rcar_pcie_config_access(struct rcar_pcie *pcie,
                unsigned char access_type, struct pci_bus *bus,
                unsigned int devfn, int where, u32 *data)
 {
-       int dev, func, reg, index;
+       unsigned int dev, func, reg, index;
 
        dev = PCI_SLOT(devfn);
        func = PCI_FUNC(devfn);
@@ -281,12 +282,12 @@ static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
        }
 
        if (size == 1)
-               *val = (*val >> (8 * (where & 3))) & 0xff;
+               *val = (*val >> (BITS_PER_BYTE * (where & 3))) & 0xff;
        else if (size == 2)
-               *val = (*val >> (8 * (where & 2))) & 0xffff;
+               *val = (*val >> (BITS_PER_BYTE * (where & 2))) & 0xffff;
 
-       dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08lx\n",
-               bus->number, devfn, where, size, (unsigned long)*val);
+       dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08x\n",
+               bus->number, devfn, where, size, *val);
 
        return ret;
 }
@@ -296,23 +297,24 @@ static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
                                int where, int size, u32 val)
 {
        struct rcar_pcie *pcie = bus->sysdata;
-       int shift, ret;
+       unsigned int shift;
        u32 data;
+       int ret;
 
        ret = rcar_pcie_config_access(pcie, RCAR_PCI_ACCESS_READ,
                                      bus, devfn, where, &data);
        if (ret != PCIBIOS_SUCCESSFUL)
                return ret;
 
-       dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08lx\n",
-               bus->number, devfn, where, size, (unsigned long)val);
+       dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08x\n",
+               bus->number, devfn, where, size, val);
 
        if (size == 1) {
-               shift = 8 * (where & 3);
+               shift = BITS_PER_BYTE * (where & 3);
                data &= ~(0xff << shift);
                data |= ((val & 0xff) << shift);
        } else if (size == 2) {
-               shift = 8 * (where & 2);
+               shift = BITS_PER_BYTE * (where & 2);
                data &= ~(0xffff << shift);
                data |= ((val & 0xffff) << shift);
        } else
@@ -507,10 +509,10 @@ static int phy_wait_for_ack(struct rcar_pcie *pcie)
 }
 
 static void phy_write_reg(struct rcar_pcie *pcie,
-                                unsigned int rate, unsigned int addr,
-                                unsigned int lane, unsigned int data)
+                         unsigned int rate, u32 addr,
+                         unsigned int lane, u32 data)
 {
-       unsigned long phyaddr;
+       u32 phyaddr;
 
        phyaddr = WRITE_CMD |
                ((rate & 1) << RATE_POS) |
@@ -738,15 +740,15 @@ static irqreturn_t rcar_pcie_msi_irq(int irq, void *data)
 
        while (reg) {
                unsigned int index = find_first_bit(&reg, 32);
-               unsigned int irq;
+               unsigned int msi_irq;
 
                /* clear the interrupt */
                rcar_pci_write_reg(pcie, 1 << index, PCIEMSIFR);
 
-               irq = irq_find_mapping(msi->domain, index);
-               if (irq) {
+               msi_irq = irq_find_mapping(msi->domain, index);
+               if (msi_irq) {
                        if (test_bit(index, msi->used))
-                               generic_handle_irq(irq);
+                               generic_handle_irq(msi_irq);
                        else
                                dev_info(dev, "unhandled MSI\n");
                } else {
@@ -890,7 +892,7 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)
 {
        struct device *dev = pcie->dev;
        struct rcar_msi *msi = &pcie->msi;
-       unsigned long base;
+       phys_addr_t base;
        int err, i;
 
        mutex_init(&msi->lock);
@@ -929,10 +931,14 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)
 
        /* setup MSI data target */
        msi->pages = __get_free_pages(GFP_KERNEL, 0);
+       if (!msi->pages) {
+               err = -ENOMEM;
+               goto err;
+       }
        base = virt_to_phys((void *)msi->pages);
 
-       rcar_pci_write_reg(pcie, base | MSIFE, PCIEMSIALR);
-       rcar_pci_write_reg(pcie, 0, PCIEMSIAUR);
+       rcar_pci_write_reg(pcie, lower_32_bits(base) | MSIFE, PCIEMSIALR);
+       rcar_pci_write_reg(pcie, upper_32_bits(base), PCIEMSIAUR);
 
        /* enable all MSI interrupts */
        rcar_pci_write_reg(pcie, 0xffffffff, PCIEMSIIER);
@@ -1118,7 +1124,7 @@ static int rcar_pcie_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct rcar_pcie *pcie;
-       unsigned int data;
+       u32 data;
        int err;
        int (*phy_init_fn)(struct rcar_pcie *);
        struct pci_host_bridge *bridge;
@@ -1130,6 +1136,7 @@ static int rcar_pcie_probe(struct platform_device *pdev)
        pcie = pci_host_bridge_priv(bridge);
 
        pcie->dev = dev;
+       platform_set_drvdata(pdev, pcie);
 
        err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, NULL);
        if (err)
@@ -1221,10 +1228,28 @@ err_free_bridge:
        return err;
 }
 
+static int rcar_pcie_resume_noirq(struct device *dev)
+{
+       struct rcar_pcie *pcie = dev_get_drvdata(dev);
+
+       if (rcar_pci_read_reg(pcie, PMSR) &&
+           !(rcar_pci_read_reg(pcie, PCIETCTLR) & DL_DOWN))
+               return 0;
+
+       /* Re-establish the PCIe link */
+       rcar_pci_write_reg(pcie, CFINIT, PCIETCTLR);
+       return rcar_pcie_wait_for_dl(pcie);
+}
+
+static const struct dev_pm_ops rcar_pcie_pm_ops = {
+       .resume_noirq = rcar_pcie_resume_noirq,
+};
+
 static struct platform_driver rcar_pcie_driver = {
        .driver = {
                .name = "rcar-pcie",
                .of_match_table = rcar_pcie_of_match,
+               .pm = &rcar_pcie_pm_ops,
                .suppress_bind_attrs = true,
        },
        .probe = rcar_pcie_probe,
index a5d799e2dff21c169c59e933dd1a19f10be215ce..d743b0a4898866eb9bf486bc554c64cfebe71a68 100644 (file)
@@ -350,7 +350,7 @@ static void rockchip_pcie_ep_assert_intx(struct rockchip_pcie_ep *ep, u8 fn,
        struct rockchip_pcie *rockchip = &ep->rockchip;
        u32 r = ep->max_regions - 1;
        u32 offset;
-       u16 status;
+       u32 status;
        u8 msg_code;
 
        if (unlikely(ep->irq_pci_addr != ROCKCHIP_PCIE_EP_PCI_LEGACY_IRQ_ADDR ||
index 1372d270764f9e8c863007260191a27ec65b39d7..8d20f1793a61837e7f2bdbe58a17474ceafafb6f 100644 (file)
@@ -724,6 +724,7 @@ static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip)
 
        rockchip->irq_domain = irq_domain_add_linear(intc, PCI_NUM_INTX,
                                                    &intx_domain_ops, rockchip);
+       of_node_put(intc);
        if (!rockchip->irq_domain) {
                dev_err(dev, "failed to get a INTx IRQ domain\n");
                return -EINVAL;
index 81538d77f79094906fad2c5c94095f7fc30879da..3b031f00a94abd02e0deef8b84a1eb12ec0b10ac 100644 (file)
@@ -438,11 +438,10 @@ static const struct irq_domain_ops legacy_domain_ops = {
 #ifdef CONFIG_PCI_MSI
 static struct irq_chip nwl_msi_irq_chip = {
        .name = "nwl_pcie:msi",
-       .irq_enable = unmask_msi_irq,
-       .irq_disable = mask_msi_irq,
-       .irq_mask = mask_msi_irq,
-       .irq_unmask = unmask_msi_irq,
-
+       .irq_enable = pci_msi_unmask_irq,
+       .irq_disable = pci_msi_mask_irq,
+       .irq_mask = pci_msi_mask_irq,
+       .irq_unmask = pci_msi_unmask_irq,
 };
 
 static struct msi_domain_info nwl_msi_domain_info = {
index 9bd1a35cd5d86970c53c22a20d70ecadcbd7b7d3..5bf3af3b28e6984f7d3e39fc62452339a7e29aef 100644 (file)
@@ -336,14 +336,19 @@ static const struct irq_domain_ops msi_domain_ops = {
  * xilinx_pcie_enable_msi - Enable MSI support
  * @port: PCIe port information
  */
-static void xilinx_pcie_enable_msi(struct xilinx_pcie_port *port)
+static int xilinx_pcie_enable_msi(struct xilinx_pcie_port *port)
 {
        phys_addr_t msg_addr;
 
        port->msi_pages = __get_free_pages(GFP_KERNEL, 0);
+       if (!port->msi_pages)
+               return -ENOMEM;
+
        msg_addr = virt_to_phys((void *)port->msi_pages);
        pcie_write(port, 0x0, XILINX_PCIE_REG_MSIBASE1);
        pcie_write(port, msg_addr, XILINX_PCIE_REG_MSIBASE2);
+
+       return 0;
 }
 
 /* INTx Functions */
@@ -498,6 +503,7 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port)
        struct device *dev = port->dev;
        struct device_node *node = dev->of_node;
        struct device_node *pcie_intc_node;
+       int ret;
 
        /* Setup INTx */
        pcie_intc_node = of_get_next_child(node, NULL);
@@ -526,7 +532,9 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port)
                        return -ENODEV;
                }
 
-               xilinx_pcie_enable_msi(port);
+               ret = xilinx_pcie_enable_msi(port);
+               if (ret)
+                       return ret;
        }
 
        return 0;
index d0b91da49bf4a731e6340ec1deaa882fef02a1a7..27806987e93bbcadd53d93f1d3508c74b924cde7 100644 (file)
@@ -438,7 +438,7 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
        epc_features = epf_test->epc_features;
 
        base = pci_epf_alloc_space(epf, sizeof(struct pci_epf_test_reg),
-                                  test_reg_bar);
+                                  test_reg_bar, epc_features->align);
        if (!base) {
                dev_err(dev, "Failed to allocated register space\n");
                return -ENOMEM;
@@ -453,7 +453,8 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
                if (!!(epc_features->reserved_bar & (1 << bar)))
                        continue;
 
-               base = pci_epf_alloc_space(epf, bar_size[bar], bar);
+               base = pci_epf_alloc_space(epf, bar_size[bar], bar,
+                                          epc_features->align);
                if (!base)
                        dev_err(dev, "Failed to allocate space for BAR%d\n",
                                bar);
@@ -591,6 +592,11 @@ static int __init pci_epf_test_init(void)
 
        kpcitest_workqueue = alloc_workqueue("kpcitest",
                                             WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
+       if (!kpcitest_workqueue) {
+               pr_err("Failed to allocate the kpcitest work queue\n");
+               return -ENOMEM;
+       }
+
        ret = pci_epf_register_driver(&test_driver);
        if (ret) {
                pr_err("Failed to register pci epf test driver --> %d\n", ret);
index 8bfdcd2911960bbb56fd94f3fcd7a7ea584b6305..fb1306de8f40867774a0a623ed3221d4540c13b4 100644 (file)
@@ -109,10 +109,12 @@ EXPORT_SYMBOL_GPL(pci_epf_free_space);
  * pci_epf_alloc_space() - allocate memory for the PCI EPF register space
  * @size: the size of the memory that has to be allocated
  * @bar: the BAR number corresponding to the allocated register space
+ * @align: alignment size for the allocation region
  *
  * Invoke to allocate memory for the PCI EPF register space.
  */
-void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar)
+void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
+                         size_t align)
 {
        void *space;
        struct device *dev = epf->epc->dev.parent;
@@ -120,7 +122,11 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar)
 
        if (size < 128)
                size = 128;
-       size = roundup_pow_of_two(size);
+
+       if (align)
+               size = ALIGN(size, align);
+       else
+               size = roundup_pow_of_two(size);
 
        space = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL);
        if (!space) {
index 506e1d923a1ffc74d27ce4e608bf6cc5744e89bc..8c51a04b8083e1d1d7a4894b90a95b8231214199 100644 (file)
 
 #include "../pcie/portdrv.h"
 
-#define MY_NAME        "pciehp"
-
 extern bool pciehp_poll_mode;
 extern int pciehp_poll_time;
-extern bool pciehp_debug;
-
-#define dbg(format, arg...)                                            \
-do {                                                                   \
-       if (pciehp_debug)                                               \
-               printk(KERN_DEBUG "%s: " format, MY_NAME, ## arg);      \
-} while (0)
-#define err(format, arg...)                                            \
-       printk(KERN_ERR "%s: " format, MY_NAME, ## arg)
-#define info(format, arg...)                                           \
-       printk(KERN_INFO "%s: " format, MY_NAME, ## arg)
-#define warn(format, arg...)                                           \
-       printk(KERN_WARNING "%s: " format, MY_NAME, ## arg)
 
+/*
+ * Set CONFIG_DYNAMIC_DEBUG=y and boot with 'dyndbg="file pciehp* +p"' to
+ * enable debug messages.
+ */
 #define ctrl_dbg(ctrl, format, arg...)                                 \
-       do {                                                            \
-               if (pciehp_debug)                                       \
-                       dev_printk(KERN_DEBUG, &ctrl->pcie->device,     \
-                                       format, ## arg);                \
-       } while (0)
+       pci_dbg(ctrl->pcie->port, format, ## arg)
 #define ctrl_err(ctrl, format, arg...)                                 \
-       dev_err(&ctrl->pcie->device, format, ## arg)
+       pci_err(ctrl->pcie->port, format, ## arg)
 #define ctrl_info(ctrl, format, arg...)                                        \
-       dev_info(&ctrl->pcie->device, format, ## arg)
+       pci_info(ctrl->pcie->port, format, ## arg)
 #define ctrl_warn(ctrl, format, arg...)                                        \
-       dev_warn(&ctrl->pcie->device, format, ## arg)
+       pci_warn(ctrl->pcie->port, format, ## arg)
 
 #define SLOT_NAME_SIZE 10
 
index fc5366b50e9565cc4ad0d9d193ab42d926d1dfef..6ad0d86762cb5b48a4280384ae3ecbf133bf171e 100644 (file)
@@ -17,6 +17,9 @@
  *   Dely Sy <dely.l.sy@intel.com>"
  */
 
+#define pr_fmt(fmt) "pciehp: " fmt
+#define dev_fmt pr_fmt
+
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -27,7 +30,6 @@
 #include "../pci.h"
 
 /* Global variables */
-bool pciehp_debug;
 bool pciehp_poll_mode;
 int pciehp_poll_time;
 
@@ -35,15 +37,11 @@ int pciehp_poll_time;
  * not really modular, but the easiest way to keep compat with existing
  * bootargs behaviour is to continue using module_param here.
  */
-module_param(pciehp_debug, bool, 0644);
 module_param(pciehp_poll_mode, bool, 0644);
 module_param(pciehp_poll_time, int, 0644);
-MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
 MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
 MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
 
-#define PCIE_MODULE_NAME "pciehp"
-
 static int set_attention_status(struct hotplug_slot *slot, u8 value);
 static int get_power_status(struct hotplug_slot *slot, u8 *value);
 static int get_latch_status(struct hotplug_slot *slot, u8 *value);
@@ -182,14 +180,14 @@ static int pciehp_probe(struct pcie_device *dev)
 
        if (!dev->port->subordinate) {
                /* Can happen if we run out of bus numbers during probe */
-               dev_err(&dev->device,
+               pci_err(dev->port,
                        "Hotplug bridge without secondary bus, ignoring\n");
                return -ENODEV;
        }
 
        ctrl = pcie_init(dev);
        if (!ctrl) {
-               dev_err(&dev->device, "Controller initialization failed\n");
+               pci_err(dev->port, "Controller initialization failed\n");
                return -ENODEV;
        }
        set_service_data(dev, ctrl);
@@ -307,7 +305,7 @@ static int pciehp_runtime_resume(struct pcie_device *dev)
 #endif /* PM */
 
 static struct pcie_port_service_driver hpdriver_portdrv = {
-       .name           = PCIE_MODULE_NAME,
+       .name           = "pciehp",
        .port_type      = PCIE_ANY_PORT,
        .service        = PCIE_PORT_SERVICE_HP,
 
@@ -328,9 +326,9 @@ int __init pcie_hp_init(void)
        int retval = 0;
 
        retval = pcie_port_service_register(&hpdriver_portdrv);
-       dbg("pcie_port_service_register = %d\n", retval);
+       pr_debug("pcie_port_service_register = %d\n", retval);
        if (retval)
-               dbg("Failure to register service\n");
+               pr_debug("Failure to register service\n");
 
        return retval;
 }
index 905282a8ddaaeda2f8df06570bfb3716e2b2479c..631ced0ab28a0be5fd83f7bedeb279ca3bbc1988 100644 (file)
@@ -13,6 +13,8 @@
  *
  */
 
+#define dev_fmt(fmt) "pciehp: " fmt
+
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pm_runtime.h>
index 6a2365cd794e1e28a93f2028c1f40a7e3caaa39f..bd990e3371e31afa9ba130134c7741c765931b26 100644 (file)
@@ -12,6 +12,8 @@
  * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com>
  */
 
+#define dev_fmt(fmt) "pciehp: " fmt
+
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/jiffies.h>
@@ -46,7 +48,7 @@ static inline int pciehp_request_irq(struct controller *ctrl)
 
        /* Installs the interrupt handler */
        retval = request_threaded_irq(irq, pciehp_isr, pciehp_ist,
-                                     IRQF_SHARED, MY_NAME, ctrl);
+                                     IRQF_SHARED, "pciehp", ctrl);
        if (retval)
                ctrl_err(ctrl, "Cannot get irq %d for the hotplug controller\n",
                         irq);
@@ -232,8 +234,8 @@ static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
                delay -= step;
        } while (delay > 0);
 
-       if (count > 1 && pciehp_debug)
-               printk(KERN_DEBUG "pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n",
+       if (count > 1)
+               pr_debug("pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n",
                        pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
                        PCI_FUNC(devfn), count, step, l);
 
@@ -822,14 +824,11 @@ static inline void dbg_ctrl(struct controller *ctrl)
        struct pci_dev *pdev = ctrl->pcie->port;
        u16 reg16;
 
-       if (!pciehp_debug)
-               return;
-
-       ctrl_info(ctrl, "Slot Capabilities      : 0x%08x\n", ctrl->slot_cap);
+       ctrl_dbg(ctrl, "Slot Capabilities      : 0x%08x\n", ctrl->slot_cap);
        pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &reg16);
-       ctrl_info(ctrl, "Slot Status            : 0x%04x\n", reg16);
+       ctrl_dbg(ctrl, "Slot Status            : 0x%04x\n", reg16);
        pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &reg16);
-       ctrl_info(ctrl, "Slot Control           : 0x%04x\n", reg16);
+       ctrl_dbg(ctrl, "Slot Control           : 0x%04x\n", reg16);
 }
 
 #define FLAG(x, y)     (((x) & (y)) ? '+' : '-')
index b9c1396db6fe9575065ba28188f4eef59bd1a3b5..d17f3bf36f70913f7f12713389aa4faab324105f 100644 (file)
@@ -13,6 +13,8 @@
  *
  */
 
+#define dev_fmt(fmt) "pciehp: " fmt
+
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pci.h>
index e2356a9c7088a4202a41dd76898751947ff6b62f..182f9e3443eef83a4a6b455161f6e00d2029b4fe 100644 (file)
@@ -51,6 +51,7 @@ static struct device_node *find_vio_slot_node(char *drc_name)
                if (rc == 0)
                        break;
        }
+       of_node_put(parent);
 
        return dn;
 }
@@ -71,6 +72,7 @@ static struct device_node *find_php_slot_pci_node(char *drc_name,
        return np;
 }
 
+/* Returns a device_node with its reference count incremented */
 static struct device_node *find_dlpar_node(char *drc_name, int *node_type)
 {
        struct device_node *dn;
@@ -306,6 +308,7 @@ int dlpar_add_slot(char *drc_name)
                        rc = dlpar_add_phb(drc_name, dn);
                        break;
        }
+       of_node_put(dn);
 
        printk(KERN_INFO "%s: slot %s added\n", DLPAR_MODULE_NAME, drc_name);
 exit:
@@ -439,6 +442,7 @@ int dlpar_remove_slot(char *drc_name)
                        rc = dlpar_remove_pci_slot(drc_name, dn);
                        break;
        }
+       of_node_put(dn);
        vm_unmap_aliases();
 
        printk(KERN_INFO "%s: slot %s removed\n", DLPAR_MODULE_NAME, drc_name);
index 5282aa3e33c506aa7995cd36132545ea354a01d7..93b4a945c55d9b03da1fdc8e866b37ed17dc3729 100644 (file)
@@ -21,6 +21,7 @@
 /* free up the memory used by a slot */
 void dealloc_slot_struct(struct slot *slot)
 {
+       of_node_put(slot->dn);
        kfree(slot->name);
        kfree(slot);
 }
@@ -36,7 +37,7 @@ struct slot *alloc_slot_struct(struct device_node *dn,
        slot->name = kstrdup(drc_name, GFP_KERNEL);
        if (!slot->name)
                goto error_slot;
-       slot->dn = dn;
+       slot->dn = of_node_get(dn);
        slot->index = drc_index;
        slot->power_domain = power_domain;
        slot->hotplug_slot.ops = &rpaphp_hotplug_slot_ops;
index 73986825d22116ccd72219f2ebf84a22bad7db96..e039b740fe743d5f25421f9ca4982f725566399d 100644 (file)
@@ -1338,7 +1338,7 @@ irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev,
                                          struct msi_desc *desc)
 {
        return (irq_hw_number_t)desc->msi_attrib.entry_nr |
-               PCI_DEVID(dev->bus->number, dev->devfn) << 11 |
+               pci_dev_id(dev) << 11 |
                (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27;
 }
 
@@ -1508,7 +1508,7 @@ static int get_msi_id_cb(struct pci_dev *pdev, u16 alias, void *data)
 u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
 {
        struct device_node *of_node;
-       u32 rid = PCI_DEVID(pdev->bus->number, pdev->devfn);
+       u32 rid = pci_dev_id(pdev);
 
        pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
 
@@ -1531,7 +1531,7 @@ u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
 struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
 {
        struct irq_domain *dom;
-       u32 rid = PCI_DEVID(pdev->bus->number, pdev->devfn);
+       u32 rid = pci_dev_id(pdev);
 
        pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
        dom = of_msi_map_get_device_domain(&pdev->dev, rid);
index 3d32da15c215d039d4c9b01d830c48460305d1df..73d5adec0a28d74b20e12dbbb16fc851fdb12bbf 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/of_pci.h>
 #include "pci.h"
 
+#ifdef CONFIG_PCI
 void pci_set_of_node(struct pci_dev *dev)
 {
        if (!dev->bus->dev.of_node)
@@ -31,10 +32,16 @@ void pci_release_of_node(struct pci_dev *dev)
 
 void pci_set_bus_of_node(struct pci_bus *bus)
 {
-       if (bus->self == NULL)
-               bus->dev.of_node = pcibios_get_phb_of_node(bus);
-       else
-               bus->dev.of_node = of_node_get(bus->self->dev.of_node);
+       struct device_node *node;
+
+       if (bus->self == NULL) {
+               node = pcibios_get_phb_of_node(bus);
+       } else {
+               node = of_node_get(bus->self->dev.of_node);
+               if (node && of_property_read_bool(node, "external-facing"))
+                       bus->self->untrusted = true;
+       }
+       bus->dev.of_node = node;
 }
 
 void pci_release_bus_of_node(struct pci_bus *bus)
@@ -196,27 +203,6 @@ int of_get_pci_domain_nr(struct device_node *node)
 }
 EXPORT_SYMBOL_GPL(of_get_pci_domain_nr);
 
-/**
- * This function will try to find the limitation of link speed by finding
- * a property called "max-link-speed" of the given device node.
- *
- * @node: device tree node with the max link speed information
- *
- * Returns the associated max link speed from DT, or a negative value if the
- * required property is not found or is invalid.
- */
-int of_pci_get_max_link_speed(struct device_node *node)
-{
-       u32 max_link_speed;
-
-       if (of_property_read_u32(node, "max-link-speed", &max_link_speed) ||
-           max_link_speed > 4)
-               return -EINVAL;
-
-       return max_link_speed;
-}
-EXPORT_SYMBOL_GPL(of_pci_get_max_link_speed);
-
 /**
  * of_pci_check_probe_only - Setup probe only mode if linux,pci-probe-only
  *                           is present and valid
@@ -537,3 +523,25 @@ int pci_parse_request_of_pci_ranges(struct device *dev,
        return err;
 }
 
+#endif /* CONFIG_PCI */
+
+/**
+ * This function will try to find the limitation of link speed by finding
+ * a property called "max-link-speed" of the given device node.
+ *
+ * @node: device tree node with the max link speed information
+ *
+ * Returns the associated max link speed from DT, or a negative value if the
+ * required property is not found or is invalid.
+ */
+int of_pci_get_max_link_speed(struct device_node *node)
+{
+       u32 max_link_speed;
+
+       if (of_property_read_u32(node, "max-link-speed", &max_link_speed) ||
+           max_link_speed > 4)
+               return -EINVAL;
+
+       return max_link_speed;
+}
+EXPORT_SYMBOL_GPL(of_pci_get_max_link_speed);
index c52298d76e64debef6ea1c02d984e4dadd58f3c8..742928d0053ec79bf886a24939db4cdc799096d8 100644 (file)
@@ -274,6 +274,30 @@ static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *pdev)
        seq_buf_printf(buf, "%s;", pci_name(pdev));
 }
 
+/*
+ * If we can't find a common upstream bridge take a look at the root
+ * complex and compare it to a whitelist of known good hardware.
+ */
+static bool root_complex_whitelist(struct pci_dev *dev)
+{
+       struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
+       struct pci_dev *root = pci_get_slot(host->bus, PCI_DEVFN(0, 0));
+       unsigned short vendor, device;
+
+       if (!root)
+               return false;
+
+       vendor = root->vendor;
+       device = root->device;
+       pci_dev_put(root);
+
+       /* AMD ZEN host bridges can do peer to peer */
+       if (vendor == PCI_VENDOR_ID_AMD && device == 0x1450)
+               return true;
+
+       return false;
+}
+
 /*
  * Find the distance through the nearest common upstream bridge between
  * two PCI devices.
@@ -317,13 +341,13 @@ static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *pdev)
  * In this case, a list of all infringing bridge addresses will be
  * populated in acs_list (assuming it's non-null) for printk purposes.
  */
-static int upstream_bridge_distance(struct pci_dev *a,
-                                   struct pci_dev *b,
+static int upstream_bridge_distance(struct pci_dev *provider,
+                                   struct pci_dev *client,
                                    struct seq_buf *acs_list)
 {
+       struct pci_dev *a = provider, *b = client, *bb;
        int dist_a = 0;
        int dist_b = 0;
-       struct pci_dev *bb = NULL;
        int acs_cnt = 0;
 
        /*
@@ -354,6 +378,14 @@ static int upstream_bridge_distance(struct pci_dev *a,
                dist_a++;
        }
 
+       /*
+        * Allow the connection if both devices are on a whitelisted root
+        * complex, but add an arbitary large value to the distance.
+        */
+       if (root_complex_whitelist(provider) &&
+           root_complex_whitelist(client))
+               return 0x1000 + dist_a + dist_b;
+
        return -1;
 
 check_b_path_acs:
index e1949f7efd9c05eeb400f69fa34ee4416cbfee37..c5e1a097d7e331c38e2aa83914349407e9812d05 100644 (file)
@@ -119,7 +119,7 @@ phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
 }
 
 static acpi_status decode_type0_hpx_record(union acpi_object *record,
-                                          struct hotplug_params *hpx)
+                                          struct hpp_type0 *hpx0)
 {
        int i;
        union acpi_object *fields = record->package.elements;
@@ -132,16 +132,14 @@ static acpi_status decode_type0_hpx_record(union acpi_object *record,
                for (i = 2; i < 6; i++)
                        if (fields[i].type != ACPI_TYPE_INTEGER)
                                return AE_ERROR;
-               hpx->t0 = &hpx->type0_data;
-               hpx->t0->revision        = revision;
-               hpx->t0->cache_line_size = fields[2].integer.value;
-               hpx->t0->latency_timer   = fields[3].integer.value;
-               hpx->t0->enable_serr     = fields[4].integer.value;
-               hpx->t0->enable_perr     = fields[5].integer.value;
+               hpx0->revision        = revision;
+               hpx0->cache_line_size = fields[2].integer.value;
+               hpx0->latency_timer   = fields[3].integer.value;
+               hpx0->enable_serr     = fields[4].integer.value;
+               hpx0->enable_perr     = fields[5].integer.value;
                break;
        default:
-               printk(KERN_WARNING
-                      "%s: Type 0 Revision %d record not supported\n",
+               pr_warn("%s: Type 0 Revision %d record not supported\n",
                       __func__, revision);
                return AE_ERROR;
        }
@@ -149,7 +147,7 @@ static acpi_status decode_type0_hpx_record(union acpi_object *record,
 }
 
 static acpi_status decode_type1_hpx_record(union acpi_object *record,
-                                          struct hotplug_params *hpx)
+                                          struct hpp_type1 *hpx1)
 {
        int i;
        union acpi_object *fields = record->package.elements;
@@ -162,15 +160,13 @@ static acpi_status decode_type1_hpx_record(union acpi_object *record,
                for (i = 2; i < 5; i++)
                        if (fields[i].type != ACPI_TYPE_INTEGER)
                                return AE_ERROR;
-               hpx->t1 = &hpx->type1_data;
-               hpx->t1->revision      = revision;
-               hpx->t1->max_mem_read  = fields[2].integer.value;
-               hpx->t1->avg_max_split = fields[3].integer.value;
-               hpx->t1->tot_max_split = fields[4].integer.value;
+               hpx1->revision      = revision;
+               hpx1->max_mem_read  = fields[2].integer.value;
+               hpx1->avg_max_split = fields[3].integer.value;
+               hpx1->tot_max_split = fields[4].integer.value;
                break;
        default:
-               printk(KERN_WARNING
-                      "%s: Type 1 Revision %d record not supported\n",
+               pr_warn("%s: Type 1 Revision %d record not supported\n",
                       __func__, revision);
                return AE_ERROR;
        }
@@ -178,7 +174,7 @@ static acpi_status decode_type1_hpx_record(union acpi_object *record,
 }
 
 static acpi_status decode_type2_hpx_record(union acpi_object *record,
-                                          struct hotplug_params *hpx)
+                                          struct hpp_type2 *hpx2)
 {
        int i;
        union acpi_object *fields = record->package.elements;
@@ -191,45 +187,102 @@ static acpi_status decode_type2_hpx_record(union acpi_object *record,
                for (i = 2; i < 18; i++)
                        if (fields[i].type != ACPI_TYPE_INTEGER)
                                return AE_ERROR;
-               hpx->t2 = &hpx->type2_data;
-               hpx->t2->revision      = revision;
-               hpx->t2->unc_err_mask_and      = fields[2].integer.value;
-               hpx->t2->unc_err_mask_or       = fields[3].integer.value;
-               hpx->t2->unc_err_sever_and     = fields[4].integer.value;
-               hpx->t2->unc_err_sever_or      = fields[5].integer.value;
-               hpx->t2->cor_err_mask_and      = fields[6].integer.value;
-               hpx->t2->cor_err_mask_or       = fields[7].integer.value;
-               hpx->t2->adv_err_cap_and       = fields[8].integer.value;
-               hpx->t2->adv_err_cap_or        = fields[9].integer.value;
-               hpx->t2->pci_exp_devctl_and    = fields[10].integer.value;
-               hpx->t2->pci_exp_devctl_or     = fields[11].integer.value;
-               hpx->t2->pci_exp_lnkctl_and    = fields[12].integer.value;
-               hpx->t2->pci_exp_lnkctl_or     = fields[13].integer.value;
-               hpx->t2->sec_unc_err_sever_and = fields[14].integer.value;
-               hpx->t2->sec_unc_err_sever_or  = fields[15].integer.value;
-               hpx->t2->sec_unc_err_mask_and  = fields[16].integer.value;
-               hpx->t2->sec_unc_err_mask_or   = fields[17].integer.value;
+               hpx2->revision      = revision;
+               hpx2->unc_err_mask_and      = fields[2].integer.value;
+               hpx2->unc_err_mask_or       = fields[3].integer.value;
+               hpx2->unc_err_sever_and     = fields[4].integer.value;
+               hpx2->unc_err_sever_or      = fields[5].integer.value;
+               hpx2->cor_err_mask_and      = fields[6].integer.value;
+               hpx2->cor_err_mask_or       = fields[7].integer.value;
+               hpx2->adv_err_cap_and       = fields[8].integer.value;
+               hpx2->adv_err_cap_or        = fields[9].integer.value;
+               hpx2->pci_exp_devctl_and    = fields[10].integer.value;
+               hpx2->pci_exp_devctl_or     = fields[11].integer.value;
+               hpx2->pci_exp_lnkctl_and    = fields[12].integer.value;
+               hpx2->pci_exp_lnkctl_or     = fields[13].integer.value;
+               hpx2->sec_unc_err_sever_and = fields[14].integer.value;
+               hpx2->sec_unc_err_sever_or  = fields[15].integer.value;
+               hpx2->sec_unc_err_mask_and  = fields[16].integer.value;
+               hpx2->sec_unc_err_mask_or   = fields[17].integer.value;
                break;
        default:
-               printk(KERN_WARNING
-                      "%s: Type 2 Revision %d record not supported\n",
+               pr_warn("%s: Type 2 Revision %d record not supported\n",
                       __func__, revision);
                return AE_ERROR;
        }
        return AE_OK;
 }
 
-static acpi_status acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx)
+static void parse_hpx3_register(struct hpx_type3 *hpx3_reg,
+                               union acpi_object *reg_fields)
+{
+       hpx3_reg->device_type            = reg_fields[0].integer.value;
+       hpx3_reg->function_type          = reg_fields[1].integer.value;
+       hpx3_reg->config_space_location  = reg_fields[2].integer.value;
+       hpx3_reg->pci_exp_cap_id         = reg_fields[3].integer.value;
+       hpx3_reg->pci_exp_cap_ver        = reg_fields[4].integer.value;
+       hpx3_reg->pci_exp_vendor_id      = reg_fields[5].integer.value;
+       hpx3_reg->dvsec_id               = reg_fields[6].integer.value;
+       hpx3_reg->dvsec_rev              = reg_fields[7].integer.value;
+       hpx3_reg->match_offset           = reg_fields[8].integer.value;
+       hpx3_reg->match_mask_and         = reg_fields[9].integer.value;
+       hpx3_reg->match_value            = reg_fields[10].integer.value;
+       hpx3_reg->reg_offset             = reg_fields[11].integer.value;
+       hpx3_reg->reg_mask_and           = reg_fields[12].integer.value;
+       hpx3_reg->reg_mask_or            = reg_fields[13].integer.value;
+}
+
+static acpi_status program_type3_hpx_record(struct pci_dev *dev,
+                                          union acpi_object *record,
+                                          const struct hotplug_program_ops *hp_ops)
+{
+       union acpi_object *fields = record->package.elements;
+       u32 desc_count, expected_length, revision;
+       union acpi_object *reg_fields;
+       struct hpx_type3 hpx3;
+       int i;
+
+       revision = fields[1].integer.value;
+       switch (revision) {
+       case 1:
+               desc_count = fields[2].integer.value;
+               expected_length = 3 + desc_count * 14;
+
+               if (record->package.count != expected_length)
+                       return AE_ERROR;
+
+               for (i = 2; i < expected_length; i++)
+                       if (fields[i].type != ACPI_TYPE_INTEGER)
+                               return AE_ERROR;
+
+               for (i = 0; i < desc_count; i++) {
+                       reg_fields = fields + 3 + i * 14;
+                       parse_hpx3_register(&hpx3, reg_fields);
+                       hp_ops->program_type3(dev, &hpx3);
+               }
+
+               break;
+       default:
+               printk(KERN_WARNING
+                       "%s: Type 3 Revision %d record not supported\n",
+                       __func__, revision);
+               return AE_ERROR;
+       }
+       return AE_OK;
+}
+
+static acpi_status acpi_run_hpx(struct pci_dev *dev, acpi_handle handle,
+                               const struct hotplug_program_ops *hp_ops)
 {
        acpi_status status;
        struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
        union acpi_object *package, *record, *fields;
+       struct hpp_type0 hpx0;
+       struct hpp_type1 hpx1;
+       struct hpp_type2 hpx2;
        u32 type;
        int i;
 
-       /* Clear the return buffer with zeros */
-       memset(hpx, 0, sizeof(struct hotplug_params));
-
        status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer);
        if (ACPI_FAILURE(status))
                return status;
@@ -257,22 +310,33 @@ static acpi_status acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx)
                type = fields[0].integer.value;
                switch (type) {
                case 0:
-                       status = decode_type0_hpx_record(record, hpx);
+                       memset(&hpx0, 0, sizeof(hpx0));
+                       status = decode_type0_hpx_record(record, &hpx0);
                        if (ACPI_FAILURE(status))
                                goto exit;
+                       hp_ops->program_type0(dev, &hpx0);
                        break;
                case 1:
-                       status = decode_type1_hpx_record(record, hpx);
+                       memset(&hpx1, 0, sizeof(hpx1));
+                       status = decode_type1_hpx_record(record, &hpx1);
                        if (ACPI_FAILURE(status))
                                goto exit;
+                       hp_ops->program_type1(dev, &hpx1);
                        break;
                case 2:
-                       status = decode_type2_hpx_record(record, hpx);
+                       memset(&hpx2, 0, sizeof(hpx2));
+                       status = decode_type2_hpx_record(record, &hpx2);
+                       if (ACPI_FAILURE(status))
+                               goto exit;
+                       hp_ops->program_type2(dev, &hpx2);
+                       break;
+               case 3:
+                       status = program_type3_hpx_record(dev, record, hp_ops);
                        if (ACPI_FAILURE(status))
                                goto exit;
                        break;
                default:
-                       printk(KERN_ERR "%s: Type %d record not supported\n",
+                       pr_err("%s: Type %d record not supported\n",
                               __func__, type);
                        status = AE_ERROR;
                        goto exit;
@@ -283,14 +347,16 @@ static acpi_status acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx)
        return status;
 }
 
-static acpi_status acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
+static acpi_status acpi_run_hpp(struct pci_dev *dev, acpi_handle handle,
+                               const struct hotplug_program_ops *hp_ops)
 {
        acpi_status status;
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *package, *fields;
+       struct hpp_type0 hpp0;
        int i;
 
-       memset(hpp, 0, sizeof(struct hotplug_params));
+       memset(&hpp0, 0, sizeof(hpp0));
 
        status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer);
        if (ACPI_FAILURE(status))
@@ -311,12 +377,13 @@ static acpi_status acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
                }
        }
 
-       hpp->t0 = &hpp->type0_data;
-       hpp->t0->revision        = 1;
-       hpp->t0->cache_line_size = fields[0].integer.value;
-       hpp->t0->latency_timer   = fields[1].integer.value;
-       hpp->t0->enable_serr     = fields[2].integer.value;
-       hpp->t0->enable_perr     = fields[3].integer.value;
+       hpp0.revision        = 1;
+       hpp0.cache_line_size = fields[0].integer.value;
+       hpp0.latency_timer   = fields[1].integer.value;
+       hpp0.enable_serr     = fields[2].integer.value;
+       hpp0.enable_perr     = fields[3].integer.value;
+
+       hp_ops->program_type0(dev, &hpp0);
 
 exit:
        kfree(buffer.pointer);
@@ -328,7 +395,8 @@ exit:
  * @dev - the pci_dev for which we want parameters
  * @hpp - allocated by the caller
  */
-int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp)
+int pci_acpi_program_hp_params(struct pci_dev *dev,
+                              const struct hotplug_program_ops *hp_ops)
 {
        acpi_status status;
        acpi_handle handle, phandle;
@@ -351,10 +419,10 @@ int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp)
         * this pci dev.
         */
        while (handle) {
-               status = acpi_run_hpx(handle, hpp);
+               status = acpi_run_hpx(dev, handle, hp_ops);
                if (ACPI_SUCCESS(status))
                        return 0;
-               status = acpi_run_hpp(handle, hpp);
+               status = acpi_run_hpp(dev, handle, hp_ops);
                if (ACPI_SUCCESS(status))
                        return 0;
                if (acpi_is_root_bridge(handle))
@@ -366,7 +434,6 @@ int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp)
        }
        return -ENODEV;
 }
-EXPORT_SYMBOL_GPL(pci_get_hp_params);
 
 /**
  * pciehp_is_native - Check whether a hotplug port is handled by the OS
index 66f8a59fadbd90496196f0e6ba4eef3baeee75be..e408099fea5257dfe3218282d138615d966ab2f0 100644 (file)
@@ -66,20 +66,18 @@ static int __init pci_stub_init(void)
                                &class, &class_mask);
 
                if (fields < 2) {
-                       printk(KERN_WARNING
-                              "pci-stub: invalid id string \"%s\"\n", id);
+                       pr_warn("pci-stub: invalid ID string \"%s\"\n", id);
                        continue;
                }
 
-               printk(KERN_INFO
-                      "pci-stub: add %04X:%04X sub=%04X:%04X cls=%08X/%08X\n",
+               pr_info("pci-stub: add %04X:%04X sub=%04X:%04X cls=%08X/%08X\n",
                       vendor, device, subvendor, subdevice, class, class_mask);
 
                rc = pci_add_dynid(&stub_driver, vendor, device,
                                   subvendor, subdevice, class, class_mask, 0);
                if (rc)
-                       printk(KERN_WARNING
-                              "pci-stub: failed to add dynamic id (%d)\n", rc);
+                       pr_warn("pci-stub: failed to add dynamic ID (%d)\n",
+                               rc);
        }
 
        return 0;
index 25794c27c7a4b960b5ed2e0293638d69d4ac9969..6d27475e39b2b9ab77f95c7e7b6e3f67d2881991 100644 (file)
@@ -1111,8 +1111,7 @@ legacy_io_err:
        kfree(b->legacy_io);
        b->legacy_io = NULL;
 kzalloc_err:
-       printk(KERN_WARNING "pci: warning: could not create legacy I/O port and ISA memory resources to sysfs\n");
-       return;
+       dev_warn(&b->dev, "could not create legacy I/O port and ISA memory resources in sysfs\n");
 }
 
 void pci_remove_legacy_files(struct pci_bus *b)
index 766f5779db929fca76738a91df9793fc6af3fedb..8abc843b1615ecf94a24a1fc1db03dfd00d03dc5 100644 (file)
@@ -197,8 +197,8 @@ EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar);
 
 /**
  * pci_dev_str_match_path - test if a path string matches a device
- * @dev:    the PCI device to test
- * @path:   string to match the device against
+ * @dev: the PCI device to test
+ * @path: string to match the device against
  * @endptr: pointer to the string after the match
  *
  * Test if a string (typically from a kernel parameter) formatted as a
@@ -280,8 +280,8 @@ free_and_exit:
 
 /**
  * pci_dev_str_match - test if a string matches a device
- * @dev:    the PCI device to test
- * @p:      string to match the device against
+ * @dev: the PCI device to test
+ * @p: string to match the device against
  * @endptr: pointer to the string after the match
  *
  * Test if a string (typically from a kernel parameter) matches a specified
@@ -341,7 +341,7 @@ static int pci_dev_str_match(struct pci_dev *dev, const char *p,
        } else {
                /*
                 * PCI Bus, Device, Function IDs are specified
-                *  (optionally, may include a path of devfns following it)
+                * (optionally, may include a path of devfns following it)
                 */
                ret = pci_dev_str_match_path(dev, p, &p);
                if (ret < 0)
@@ -425,7 +425,7 @@ static int __pci_bus_find_cap_start(struct pci_bus *bus,
  * Tell if a device supports a given PCI capability.
  * Returns the address of the requested capability structure within the
  * device's PCI configuration space or 0 in case the device does not
- * support it.  Possible values for @cap:
+ * support it.  Possible values for @cap include:
  *
  *  %PCI_CAP_ID_PM           Power Management
  *  %PCI_CAP_ID_AGP          Accelerated Graphics Port
@@ -450,11 +450,11 @@ EXPORT_SYMBOL(pci_find_capability);
 
 /**
  * pci_bus_find_capability - query for devices' capabilities
- * @bus:   the PCI bus to query
+ * @bus: the PCI bus to query
  * @devfn: PCI device to query
- * @cap:   capability code
+ * @cap: capability code
  *
- * Like pci_find_capability() but works for pci devices that do not have a
+ * Like pci_find_capability() but works for PCI devices that do not have a
  * pci_dev structure set up yet.
  *
  * Returns the address of the requested capability structure within the
@@ -535,7 +535,7 @@ EXPORT_SYMBOL_GPL(pci_find_next_ext_capability);
  *
  * Returns the address of the requested extended capability structure
  * within the device's PCI configuration space or 0 if the device does
- * not support it.  Possible values for @cap:
+ * not support it.  Possible values for @cap include:
  *
  *  %PCI_EXT_CAP_ID_ERR                Advanced Error Reporting
  *  %PCI_EXT_CAP_ID_VC         Virtual Channel
@@ -618,12 +618,13 @@ int pci_find_ht_capability(struct pci_dev *dev, int ht_cap)
 EXPORT_SYMBOL_GPL(pci_find_ht_capability);
 
 /**
- * pci_find_parent_resource - return resource region of parent bus of given region
+ * pci_find_parent_resource - return resource region of parent bus of given
+ *                           region
  * @dev: PCI device structure contains resources to be searched
  * @res: child resource record for which parent is sought
  *
- *  For given resource region of given device, return the resource
- *  region of parent bus the given region is contained in.
+ * For given resource region of given device, return the resource region of
+ * parent bus the given region is contained in.
  */
 struct resource *pci_find_parent_resource(const struct pci_dev *dev,
                                          struct resource *res)
@@ -800,7 +801,7 @@ static inline bool platform_pci_bridge_d3(struct pci_dev *dev)
 
 /**
  * pci_raw_set_power_state - Use PCI PM registers to set the power state of
- *                           given PCI device
+ *                          given PCI device
  * @dev: PCI device to handle.
  * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
  *
@@ -826,7 +827,8 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
        if (state < PCI_D0 || state > PCI_D3hot)
                return -EINVAL;
 
-       /* Validate current state:
+       /*
+        * Validate current state:
         * Can enter D0 from any state, but if we can only go deeper
         * to sleep if we're already in a low power state
         */
@@ -837,14 +839,15 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
                return -EINVAL;
        }
 
-       /* check if this device supports the desired state */
+       /* Check if this device supports the desired state */
        if ((state == PCI_D1 && !dev->d1_support)
           || (state == PCI_D2 && !dev->d2_support))
                return -EIO;
 
        pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
 
-       /* If we're (effectively) in D3, force entire word to 0.
+       /*
+        * If we're (effectively) in D3, force entire word to 0.
         * This doesn't affect PME_Status, disables PME_En, and
         * sets PowerState to 0.
         */
@@ -867,11 +870,13 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
                break;
        }
 
-       /* enter specified state */
+       /* Enter specified state */
        pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
 
-       /* Mandatory power management transition delays */
-       /* see PCI PM 1.1 5.6.1 table 18 */
+       /*
+        * Mandatory power management transition delays; see PCI PM 1.1
+        * 5.6.1 table 18
+        */
        if (state == PCI_D3hot || dev->current_state == PCI_D3hot)
                pci_dev_d3_sleep(dev);
        else if (state == PCI_D2 || dev->current_state == PCI_D2)
@@ -1085,16 +1090,18 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 {
        int error;
 
-       /* bound the state we're entering */
+       /* Bound the state we're entering */
        if (state > PCI_D3cold)
                state = PCI_D3cold;
        else if (state < PCI_D0)
                state = PCI_D0;
        else if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
+
                /*
-                * If the device or the parent bridge do not support PCI PM,
-                * ignore the request if we're doing anything other than putting
-                * it into D0 (which would only happen on boot).
+                * If the device or the parent bridge do not support PCI
+                * PM, ignore the request if we're doing anything other
+                * than putting it into D0 (which would only happen on
+                * boot).
                 */
                return 0;
 
@@ -1104,8 +1111,10 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 
        __pci_start_power_transition(dev, state);
 
-       /* This device is quirked not to be put into D3, so
-          don't put it in D3 */
+       /*
+        * This device is quirked not to be put into D3, so don't put it in
+        * D3
+        */
        if (state >= PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3))
                return 0;
 
@@ -1127,12 +1136,11 @@ EXPORT_SYMBOL(pci_set_power_state);
  * pci_choose_state - Choose the power state of a PCI device
  * @dev: PCI device to be suspended
  * @state: target sleep state for the whole system. This is the value
- *     that is passed to suspend() function.
+ *        that is passed to suspend() function.
  *
  * Returns PCI power state suitable for given device and given system
  * message.
  */
-
 pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
 {
        pci_power_t ret;
@@ -1310,8 +1318,9 @@ static void pci_restore_ltr_state(struct pci_dev *dev)
 }
 
 /**
- * pci_save_state - save the PCI configuration space of a device before suspending
- * @dev: - PCI device that we're dealing with
+ * pci_save_state - save the PCI configuration space of a device before
+ *                 suspending
+ * @dev: PCI device that we're dealing with
  */
 int pci_save_state(struct pci_dev *dev)
 {
@@ -1422,7 +1431,7 @@ static void pci_restore_rebar_state(struct pci_dev *pdev)
 
 /**
  * pci_restore_state - Restore the saved state of a PCI device
- * @dev: PCI device that we're dealing with
+ * @dev: PCI device that we're dealing with
  */
 void pci_restore_state(struct pci_dev *dev)
 {
@@ -1599,8 +1608,8 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
  * pci_reenable_device - Resume abandoned device
  * @dev: PCI device to be resumed
  *
- *  Note this function is a backend of pci_default_resume and is not supposed
- *  to be called by normal code, write proper resume handler and use it instead.
+ * NOTE: This function is a backend of pci_default_resume() and is not supposed
+ * to be called by normal code, write proper resume handler and use it instead.
  */
 int pci_reenable_device(struct pci_dev *dev)
 {
@@ -1675,9 +1684,9 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
  * pci_enable_device_io - Initialize a device for use with IO space
  * @dev: PCI device to be initialized
  *
- *  Initialize device before it's used by a driver. Ask low-level code
- *  to enable I/O resources. Wake up the device if it was suspended.
- *  Beware, this function can fail.
+ * Initialize device before it's used by a driver. Ask low-level code
+ * to enable I/O resources. Wake up the device if it was suspended.
+ * Beware, this function can fail.
  */
 int pci_enable_device_io(struct pci_dev *dev)
 {
@@ -1689,9 +1698,9 @@ EXPORT_SYMBOL(pci_enable_device_io);
  * pci_enable_device_mem - Initialize a device for use with Memory space
  * @dev: PCI device to be initialized
  *
- *  Initialize device before it's used by a driver. Ask low-level code
- *  to enable Memory resources. Wake up the device if it was suspended.
- *  Beware, this function can fail.
+ * Initialize device before it's used by a driver. Ask low-level code
+ * to enable Memory resources. Wake up the device if it was suspended.
+ * Beware, this function can fail.
  */
 int pci_enable_device_mem(struct pci_dev *dev)
 {
@@ -1703,12 +1712,12 @@ EXPORT_SYMBOL(pci_enable_device_mem);
  * pci_enable_device - Initialize device before it's used by a driver.
  * @dev: PCI device to be initialized
  *
- *  Initialize device before it's used by a driver. Ask low-level code
- *  to enable I/O and memory. Wake up the device if it was suspended.
- *  Beware, this function can fail.
+ * Initialize device before it's used by a driver. Ask low-level code
+ * to enable I/O and memory. Wake up the device if it was suspended.
+ * Beware, this function can fail.
  *
- *  Note we don't actually enable the device many times if we call
- *  this function repeatedly (we just increment the count).
+ * Note we don't actually enable the device many times if we call
+ * this function repeatedly (we just increment the count).
  */
 int pci_enable_device(struct pci_dev *dev)
 {
@@ -1717,8 +1726,8 @@ int pci_enable_device(struct pci_dev *dev)
 EXPORT_SYMBOL(pci_enable_device);
 
 /*
- * Managed PCI resources.  This manages device on/off, intx/msi/msix
- * on/off and BAR regions.  pci_dev itself records msi/msix status, so
+ * Managed PCI resources.  This manages device on/off, INTx/MSI/MSI-X
+ * on/off and BAR regions.  pci_dev itself records MSI/MSI-X status, so
  * there's no need to track it separately.  pci_devres is initialized
  * when a device is enabled using managed PCI device enable interface.
  */
@@ -1836,7 +1845,8 @@ int __weak pcibios_add_device(struct pci_dev *dev)
 }
 
 /**
- * pcibios_release_device - provide arch specific hooks when releasing device dev
+ * pcibios_release_device - provide arch specific hooks when releasing
+ *                         device dev
  * @dev: the PCI device being released
  *
  * Permits the platform to provide architecture specific functionality when
@@ -1927,8 +1937,7 @@ EXPORT_SYMBOL(pci_disable_device);
  * @dev: the PCIe device reset
  * @state: Reset state to enter into
  *
- *
- * Sets the PCIe reset state for the device. This is the default
+ * Set the PCIe reset state for the device. This is the default
  * implementation. Architecture implementations can override this.
  */
 int __weak pcibios_set_pcie_reset_state(struct pci_dev *dev,
@@ -1942,7 +1951,6 @@ int __weak pcibios_set_pcie_reset_state(struct pci_dev *dev,
  * @dev: the PCIe device reset
  * @state: Reset state to enter into
  *
- *
  * Sets the PCI reset state for the device.
  */
 int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
@@ -2339,7 +2347,8 @@ static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup)
 }
 
 /**
- * pci_prepare_to_sleep - prepare PCI device for system-wide transition into a sleep state
+ * pci_prepare_to_sleep - prepare PCI device for system-wide transition
+ *                       into a sleep state
  * @dev: Device to handle.
  *
  * Choose the power state appropriate for the device depending on whether
@@ -2367,7 +2376,8 @@ int pci_prepare_to_sleep(struct pci_dev *dev)
 EXPORT_SYMBOL(pci_prepare_to_sleep);
 
 /**
- * pci_back_from_sleep - turn PCI device on during system-wide transition into working state
+ * pci_back_from_sleep - turn PCI device on during system-wide transition
+ *                      into working state
  * @dev: Device to handle.
  *
  * Disable device's system wake-up capability and put it into D0.
@@ -2777,14 +2787,14 @@ void pci_pm_init(struct pci_dev *dev)
                        dev->d2_support = true;
 
                if (dev->d1_support || dev->d2_support)
-                       pci_printk(KERN_DEBUG, dev, "supports%s%s\n",
+                       pci_info(dev, "supports%s%s\n",
                                   dev->d1_support ? " D1" : "",
                                   dev->d2_support ? " D2" : "");
        }
 
        pmc &= PCI_PM_CAP_PME_MASK;
        if (pmc) {
-               pci_printk(KERN_DEBUG, dev, "PME# supported from%s%s%s%s%s\n",
+               pci_info(dev, "PME# supported from%s%s%s%s%s\n",
                         (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "",
                         (pmc & PCI_PM_CAP_PME_D1) ? " D1" : "",
                         (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "",
@@ -2952,16 +2962,16 @@ static int pci_ea_read(struct pci_dev *dev, int offset)
        res->flags = flags;
 
        if (bei <= PCI_EA_BEI_BAR5)
-               pci_printk(KERN_DEBUG, dev, "BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
+               pci_info(dev, "BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
                           bei, res, prop);
        else if (bei == PCI_EA_BEI_ROM)
-               pci_printk(KERN_DEBUG, dev, "ROM: %pR (from Enhanced Allocation, properties %#02x)\n",
+               pci_info(dev, "ROM: %pR (from Enhanced Allocation, properties %#02x)\n",
                           res, prop);
        else if (bei >= PCI_EA_BEI_VF_BAR0 && bei <= PCI_EA_BEI_VF_BAR5)
-               pci_printk(KERN_DEBUG, dev, "VF BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
+               pci_info(dev, "VF BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
                           bei - PCI_EA_BEI_VF_BAR0, res, prop);
        else
-               pci_printk(KERN_DEBUG, dev, "BEI %d res: %pR (from Enhanced Allocation, properties %#02x)\n",
+               pci_info(dev, "BEI %d res: %pR (from Enhanced Allocation, properties %#02x)\n",
                           bei, res, prop);
 
 out:
@@ -3005,7 +3015,7 @@ static void pci_add_saved_cap(struct pci_dev *pci_dev,
 
 /**
  * _pci_add_cap_save_buffer - allocate buffer for saving given
- *                            capability registers
+ *                           capability registers
  * @dev: the PCI device
  * @cap: the capability to allocate the buffer for
  * @extended: Standard or Extended capability ID
@@ -3186,7 +3196,7 @@ static void pci_disable_acs_redir(struct pci_dev *dev)
 }
 
 /**
- * pci_std_enable_acs - enable ACS on devices using standard ACS capabilites
+ * pci_std_enable_acs - enable ACS on devices using standard ACS capabilities
  * @dev: the PCI device
  */
 static void pci_std_enable_acs(struct pci_dev *dev)
@@ -3609,13 +3619,14 @@ u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)
 EXPORT_SYMBOL_GPL(pci_common_swizzle);
 
 /**
- *     pci_release_region - Release a PCI bar
- *     @pdev: PCI device whose resources were previously reserved by pci_request_region
- *     @bar: BAR to release
+ * pci_release_region - Release a PCI bar
+ * @pdev: PCI device whose resources were previously reserved by
+ *       pci_request_region()
+ * @bar: BAR to release
  *
- *     Releases the PCI I/O and memory resources previously reserved by a
- *     successful call to pci_request_region.  Call this function only
- *     after all use of the PCI regions has ceased.
+ * Releases the PCI I/O and memory resources previously reserved by a
+ * successful call to pci_request_region().  Call this function only
+ * after all use of the PCI regions has ceased.
  */
 void pci_release_region(struct pci_dev *pdev, int bar)
 {
@@ -3637,23 +3648,23 @@ void pci_release_region(struct pci_dev *pdev, int bar)
 EXPORT_SYMBOL(pci_release_region);
 
 /**
- *     __pci_request_region - Reserved PCI I/O and memory resource
- *     @pdev: PCI device whose resources are to be reserved
- *     @bar: BAR to be reserved
- *     @res_name: Name to be associated with resource.
- *     @exclusive: whether the region access is exclusive or not
+ * __pci_request_region - Reserved PCI I/O and memory resource
+ * @pdev: PCI device whose resources are to be reserved
+ * @bar: BAR to be reserved
+ * @res_name: Name to be associated with resource.
+ * @exclusive: whether the region access is exclusive or not
  *
- *     Mark the PCI region associated with PCI device @pdev BR @bar as
- *     being reserved by owner @res_name.  Do not access any
- *     address inside the PCI regions unless this call returns
- *     successfully.
+ * Mark the PCI region associated with PCI device @pdev BAR @bar as
+ * being reserved by owner @res_name.  Do not access any
+ * address inside the PCI regions unless this call returns
+ * successfully.
  *
- *     If @exclusive is set, then the region is marked so that userspace
- *     is explicitly not allowed to map the resource via /dev/mem or
- *     sysfs MMIO access.
+ * If @exclusive is set, then the region is marked so that userspace
+ * is explicitly not allowed to map the resource via /dev/mem or
+ * sysfs MMIO access.
  *
- *     Returns 0 on success, or %EBUSY on error.  A warning
- *     message is also printed on failure.
+ * Returns 0 on success, or %EBUSY on error.  A warning
+ * message is also printed on failure.
  */
 static int __pci_request_region(struct pci_dev *pdev, int bar,
                                const char *res_name, int exclusive)
@@ -3687,18 +3698,18 @@ err_out:
 }
 
 /**
- *     pci_request_region - Reserve PCI I/O and memory resource
- *     @pdev: PCI device whose resources are to be reserved
- *     @bar: BAR to be reserved
- *     @res_name: Name to be associated with resource
+ * pci_request_region - Reserve PCI I/O and memory resource
+ * @pdev: PCI device whose resources are to be reserved
+ * @bar: BAR to be reserved
+ * @res_name: Name to be associated with resource
  *
- *     Mark the PCI region associated with PCI device @pdev BAR @bar as
- *     being reserved by owner @res_name.  Do not access any
- *     address inside the PCI regions unless this call returns
- *     successfully.
+ * Mark the PCI region associated with PCI device @pdev BAR @bar as
+ * being reserved by owner @res_name.  Do not access any
+ * address inside the PCI regions unless this call returns
+ * successfully.
  *
- *     Returns 0 on success, or %EBUSY on error.  A warning
- *     message is also printed on failure.
+ * Returns 0 on success, or %EBUSY on error.  A warning
+ * message is also printed on failure.
  */
 int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
 {
@@ -3706,31 +3717,6 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
 }
 EXPORT_SYMBOL(pci_request_region);
 
-/**
- *     pci_request_region_exclusive - Reserved PCI I/O and memory resource
- *     @pdev: PCI device whose resources are to be reserved
- *     @bar: BAR to be reserved
- *     @res_name: Name to be associated with resource.
- *
- *     Mark the PCI region associated with PCI device @pdev BR @bar as
- *     being reserved by owner @res_name.  Do not access any
- *     address inside the PCI regions unless this call returns
- *     successfully.
- *
- *     Returns 0 on success, or %EBUSY on error.  A warning
- *     message is also printed on failure.
- *
- *     The key difference that _exclusive makes it that userspace is
- *     explicitly not allowed to map the resource via /dev/mem or
- *     sysfs.
- */
-int pci_request_region_exclusive(struct pci_dev *pdev, int bar,
-                                const char *res_name)
-{
-       return __pci_request_region(pdev, bar, res_name, IORESOURCE_EXCLUSIVE);
-}
-EXPORT_SYMBOL(pci_request_region_exclusive);
-
 /**
  * pci_release_selected_regions - Release selected PCI I/O and memory resources
  * @pdev: PCI device whose resources were previously reserved
@@ -3791,12 +3777,13 @@ int pci_request_selected_regions_exclusive(struct pci_dev *pdev, int bars,
 EXPORT_SYMBOL(pci_request_selected_regions_exclusive);
 
 /**
- *     pci_release_regions - Release reserved PCI I/O and memory resources
- *     @pdev: PCI device whose resources were previously reserved by pci_request_regions
+ * pci_release_regions - Release reserved PCI I/O and memory resources
+ * @pdev: PCI device whose resources were previously reserved by
+ *       pci_request_regions()
  *
- *     Releases all PCI I/O and memory resources previously reserved by a
- *     successful call to pci_request_regions.  Call this function only
- *     after all use of the PCI regions has ceased.
+ * Releases all PCI I/O and memory resources previously reserved by a
+ * successful call to pci_request_regions().  Call this function only
+ * after all use of the PCI regions has ceased.
  */
 
 void pci_release_regions(struct pci_dev *pdev)
@@ -3806,17 +3793,17 @@ void pci_release_regions(struct pci_dev *pdev)
 EXPORT_SYMBOL(pci_release_regions);
 
 /**
- *     pci_request_regions - Reserved PCI I/O and memory resources
- *     @pdev: PCI device whose resources are to be reserved
- *     @res_name: Name to be associated with resource.
+ * pci_request_regions - Reserve PCI I/O and memory resources
+ * @pdev: PCI device whose resources are to be reserved
+ * @res_name: Name to be associated with resource.
  *
- *     Mark all PCI regions associated with PCI device @pdev as
- *     being reserved by owner @res_name.  Do not access any
- *     address inside the PCI regions unless this call returns
- *     successfully.
+ * Mark all PCI regions associated with PCI device @pdev as
+ * being reserved by owner @res_name.  Do not access any
+ * address inside the PCI regions unless this call returns
+ * successfully.
  *
- *     Returns 0 on success, or %EBUSY on error.  A warning
- *     message is also printed on failure.
+ * Returns 0 on success, or %EBUSY on error.  A warning
+ * message is also printed on failure.
  */
 int pci_request_regions(struct pci_dev *pdev, const char *res_name)
 {
@@ -3825,20 +3812,19 @@ int pci_request_regions(struct pci_dev *pdev, const char *res_name)
 EXPORT_SYMBOL(pci_request_regions);
 
 /**
- *     pci_request_regions_exclusive - Reserved PCI I/O and memory resources
- *     @pdev: PCI device whose resources are to be reserved
- *     @res_name: Name to be associated with resource.
+ * pci_request_regions_exclusive - Reserve PCI I/O and memory resources
+ * @pdev: PCI device whose resources are to be reserved
+ * @res_name: Name to be associated with resource.
  *
- *     Mark all PCI regions associated with PCI device @pdev as
- *     being reserved by owner @res_name.  Do not access any
- *     address inside the PCI regions unless this call returns
- *     successfully.
+ * Mark all PCI regions associated with PCI device @pdev as being reserved
+ * by owner @res_name.  Do not access any address inside the PCI regions
+ * unless this call returns successfully.
  *
- *     pci_request_regions_exclusive() will mark the region so that
- *     /dev/mem and the sysfs MMIO access will not be allowed.
+ * pci_request_regions_exclusive() will mark the region so that /dev/mem
+ * and the sysfs MMIO access will not be allowed.
  *
- *     Returns 0 on success, or %EBUSY on error.  A warning
- *     message is also printed on failure.
+ * Returns 0 on success, or %EBUSY on error.  A warning message is also
+ * printed on failure.
  */
 int pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name)
 {
@@ -3849,7 +3835,7 @@ EXPORT_SYMBOL(pci_request_regions_exclusive);
 
 /*
  * Record the PCI IO range (expressed as CPU physical address + size).
- * Return a negative value if an error has occured, zero otherwise
+ * Return a negative value if an error has occurred, zero otherwise
  */
 int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr,
                        resource_size_t size)
@@ -3905,14 +3891,14 @@ unsigned long __weak pci_address_to_pio(phys_addr_t address)
 }
 
 /**
- *     pci_remap_iospace - Remap the memory mapped I/O space
- *     @res: Resource describing the I/O space
- *     @phys_addr: physical address of range to be mapped
+ * pci_remap_iospace - Remap the memory mapped I/O space
+ * @res: Resource describing the I/O space
+ * @phys_addr: physical address of range to be mapped
  *
- *     Remap the memory mapped I/O space described by the @res
- *     and the CPU physical address @phys_addr into virtual address space.
- *     Only architectures that have memory mapped IO functions defined
- *     (and the PCI_IOBASE value defined) should call this function.
+ * Remap the memory mapped I/O space described by the @res and the CPU
+ * physical address @phys_addr into virtual address space.  Only
+ * architectures that have memory mapped IO functions defined (and the
+ * PCI_IOBASE value defined) should call this function.
  */
 int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
 {
@@ -3928,8 +3914,10 @@ int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
        return ioremap_page_range(vaddr, vaddr + resource_size(res), phys_addr,
                                  pgprot_device(PAGE_KERNEL));
 #else
-       /* this architecture does not have memory mapped I/O space,
-          so this function should never be called */
+       /*
+        * This architecture does not have memory mapped I/O space,
+        * so this function should never be called
+        */
        WARN_ONCE(1, "This architecture does not support memory mapped I/O\n");
        return -ENODEV;
 #endif
@@ -3937,12 +3925,12 @@ int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
 EXPORT_SYMBOL(pci_remap_iospace);
 
 /**
- *     pci_unmap_iospace - Unmap the memory mapped I/O space
- *     @res: resource to be unmapped
+ * pci_unmap_iospace - Unmap the memory mapped I/O space
+ * @res: resource to be unmapped
  *
- *     Unmap the CPU virtual address @res from virtual address space.
- *     Only architectures that have memory mapped IO functions defined
- *     (and the PCI_IOBASE value defined) should call this function.
+ * Unmap the CPU virtual address @res from virtual address space.  Only
+ * architectures that have memory mapped IO functions defined (and the
+ * PCI_IOBASE value defined) should call this function.
  */
 void pci_unmap_iospace(struct resource *res)
 {
@@ -4185,7 +4173,7 @@ int pci_set_cacheline_size(struct pci_dev *dev)
        if (cacheline_size == pci_cache_line_size)
                return 0;
 
-       pci_printk(KERN_DEBUG, dev, "cache line size of %d is not supported\n",
+       pci_info(dev, "cache line size of %d is not supported\n",
                   pci_cache_line_size << 2);
 
        return -EINVAL;
@@ -4288,7 +4276,7 @@ EXPORT_SYMBOL(pci_clear_mwi);
  * @pdev: the PCI device to operate on
  * @enable: boolean: whether to enable or disable PCI INTx
  *
- * Enables/disables PCI INTx for device dev
+ * Enables/disables PCI INTx for device @pdev
  */
 void pci_intx(struct pci_dev *pdev, int enable)
 {
@@ -4364,9 +4352,8 @@ done:
  * pci_check_and_mask_intx - mask INTx on pending interrupt
  * @dev: the PCI device to operate on
  *
- * Check if the device dev has its INTx line asserted, mask it and
- * return true in that case. False is returned if no interrupt was
- * pending.
+ * Check if the device dev has its INTx line asserted, mask it and return
+ * true in that case. False is returned if no interrupt was pending.
  */
 bool pci_check_and_mask_intx(struct pci_dev *dev)
 {
@@ -4378,9 +4365,9 @@ EXPORT_SYMBOL_GPL(pci_check_and_mask_intx);
  * pci_check_and_unmask_intx - unmask INTx if no interrupt is pending
  * @dev: the PCI device to operate on
  *
- * Check if the device dev has its INTx line asserted, unmask it if not
- * and return true. False is returned and the mask remains active if
- * there was still an interrupt pending.
+ * Check if the device dev has its INTx line asserted, unmask it if not and
+ * return true. False is returned and the mask remains active if there was
+ * still an interrupt pending.
  */
 bool pci_check_and_unmask_intx(struct pci_dev *dev)
 {
@@ -4389,7 +4376,7 @@ bool pci_check_and_unmask_intx(struct pci_dev *dev)
 EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);
 
 /**
- * pci_wait_for_pending_transaction - waits for pending transaction
+ * pci_wait_for_pending_transaction - wait for pending transaction
  * @dev: the PCI device to operate on
  *
  * Return 0 if transaction is pending 1 otherwise.
@@ -4447,7 +4434,7 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
 
 /**
  * pcie_has_flr - check if a device supports function level resets
- * @dev:       device to check
+ * @dev: device to check
  *
  * Returns true if the device advertises support for PCIe function level
  * resets.
@@ -4466,7 +4453,7 @@ EXPORT_SYMBOL_GPL(pcie_has_flr);
 
 /**
  * pcie_flr - initiate a PCIe function level reset
- * @dev:       device to reset
+ * @dev: device to reset
  *
  * Initiate a function level reset on @dev.  The caller should ensure the
  * device supports FLR before calling this function, e.g. by using the
@@ -4810,6 +4797,7 @@ static void pci_dev_restore(struct pci_dev *dev)
  *
  * The device function is presumed to be unused and the caller is holding
  * the device mutex lock when this function is called.
+ *
  * Resetting the device will make the contents of PCI configuration space
  * random, so any caller of this must be prepared to reinitialise the
  * device including MSI, bus mastering, BARs, decoding IO and memory spaces,
@@ -5373,8 +5361,8 @@ EXPORT_SYMBOL_GPL(pci_reset_bus);
  * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
  * @dev: PCI device to query
  *
- * Returns mmrbc: maximum designed memory read count in bytes
- *    or appropriate error value.
+ * Returns mmrbc: maximum designed memory read count in bytes or
+ * appropriate error value.
  */
 int pcix_get_max_mmrbc(struct pci_dev *dev)
 {
@@ -5396,8 +5384,8 @@ EXPORT_SYMBOL(pcix_get_max_mmrbc);
  * pcix_get_mmrbc - get PCI-X maximum memory read byte count
  * @dev: PCI device to query
  *
- * Returns mmrbc: maximum memory read count in bytes
- *    or appropriate error value.
+ * Returns mmrbc: maximum memory read count in bytes or appropriate error
+ * value.
  */
 int pcix_get_mmrbc(struct pci_dev *dev)
 {
@@ -5421,7 +5409,7 @@ EXPORT_SYMBOL(pcix_get_mmrbc);
  * @mmrbc: maximum memory read count in bytes
  *    valid values are 512, 1024, 2048, 4096
  *
- * If possible sets maximum memory read byte count, some bridges have erratas
+ * If possible sets maximum memory read byte count, some bridges have errata
  * that prevent this.
  */
 int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc)
@@ -5466,8 +5454,7 @@ EXPORT_SYMBOL(pcix_set_mmrbc);
  * pcie_get_readrq - get PCI Express read request size
  * @dev: PCI device to query
  *
- * Returns maximum memory read request in bytes
- *    or appropriate error value.
+ * Returns maximum memory read request in bytes or appropriate error value.
  */
 int pcie_get_readrq(struct pci_dev *dev)
 {
@@ -5495,10 +5482,9 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
                return -EINVAL;
 
        /*
-        * If using the "performance" PCIe config, we clamp the
-        * read rq size to the max packet size to prevent the
-        * host bridge generating requests larger than we can
-        * cope with
+        * If using the "performance" PCIe config, we clamp the read rq
+        * size to the max packet size to keep the host bridge from
+        * generating requests larger than we can cope with.
         */
        if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
                int mps = pcie_get_mps(dev);
@@ -6144,6 +6130,7 @@ static int of_pci_bus_find_domain_nr(struct device *parent)
 
        if (parent)
                domain = of_get_pci_domain_nr(parent->of_node);
+
        /*
         * Check DT domain and use_dt_domains values.
         *
@@ -6264,8 +6251,7 @@ static int __init pci_setup(char *str)
                        } else if (!strncmp(str, "disable_acs_redir=", 18)) {
                                disable_acs_redir_param = str + 18;
                        } else {
-                               printk(KERN_ERR "PCI: Unknown option `%s'\n",
-                                               str);
+                               pr_err("PCI: Unknown option `%s'\n", str);
                        }
                }
                str = k;
index d994839a3e24b5ec8c1452f3489c47d8fa7aba20..9cb99380c61e31d7ceab08f662df9feb2c162b4d 100644 (file)
@@ -597,7 +597,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev);
 void pci_aer_clear_device_status(struct pci_dev *dev);
 #else
 static inline void pci_no_aer(void) { }
-static inline int pci_aer_init(struct pci_dev *d) { return -ENODEV; }
+static inline void pci_aer_init(struct pci_dev *d) { }
 static inline void pci_aer_exit(struct pci_dev *d) { }
 static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
 static inline void pci_aer_clear_device_status(struct pci_dev *dev) { }
index f8fc2114ad3961d5a3de49c12e43648b0691e712..b45bc47d04fe418ce8ca00007bb00fad11d01808 100644 (file)
@@ -12,6 +12,9 @@
  *    Andrew Patterson <andrew.patterson@hp.com>
  */
 
+#define pr_fmt(fmt) "AER: " fmt
+#define dev_fmt pr_fmt
+
 #include <linux/cper.h>
 #include <linux/pci.h>
 #include <linux/pci-acpi.h>
@@ -779,10 +782,11 @@ static void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info)
        u8 bus = info->id >> 8;
        u8 devfn = info->id & 0xff;
 
-       pci_info(dev, "AER: %s%s error received: %04x:%02x:%02x.%d\n",
-               info->multi_error_valid ? "Multiple " : "",
-               aer_error_severity_string[info->severity],
-               pci_domain_nr(dev->bus), bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+       pci_info(dev, "%s%s error received: %04x:%02x:%02x.%d\n",
+                info->multi_error_valid ? "Multiple " : "",
+                aer_error_severity_string[info->severity],
+                pci_domain_nr(dev->bus), bus, PCI_SLOT(devfn),
+                PCI_FUNC(devfn));
 }
 
 #ifdef CONFIG_ACPI_APEI_PCIEAER
@@ -964,8 +968,7 @@ static bool find_source_device(struct pci_dev *parent,
        pci_walk_bus(parent->subordinate, find_device_iter, e_info);
 
        if (!e_info->error_dev_num) {
-               pci_printk(KERN_DEBUG, parent, "can't find device of ID%04x\n",
-                          e_info->id);
+               pci_info(parent, "can't find device of ID%04x\n", e_info->id);
                return false;
        }
        return true;
@@ -1377,25 +1380,24 @@ static int aer_probe(struct pcie_device *dev)
        int status;
        struct aer_rpc *rpc;
        struct device *device = &dev->device;
+       struct pci_dev *port = dev->port;
 
        rpc = devm_kzalloc(device, sizeof(struct aer_rpc), GFP_KERNEL);
-       if (!rpc) {
-               dev_printk(KERN_DEBUG, device, "alloc AER rpc failed\n");
+       if (!rpc)
                return -ENOMEM;
-       }
-       rpc->rpd = dev->port;
+
+       rpc->rpd = port;
        set_service_data(dev, rpc);
 
        status = devm_request_threaded_irq(device, dev->irq, aer_irq, aer_isr,
                                           IRQF_SHARED, "aerdrv", dev);
        if (status) {
-               dev_printk(KERN_DEBUG, device, "request AER IRQ %d failed\n",
-                          dev->irq);
+               pci_err(port, "request AER IRQ %d failed\n", dev->irq);
                return status;
        }
 
        aer_enable_rootport(rpc);
-       dev_info(device, "AER enabled with IRQ %d\n", dev->irq);
+       pci_info(port, "enabled with IRQ %d\n", dev->irq);
        return 0;
 }
 
@@ -1419,7 +1421,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
        pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
 
        rc = pci_bus_error_reset(dev);
-       pci_printk(KERN_DEBUG, dev, "Root Port link has been reset\n");
+       pci_info(dev, "Root Port link has been reset\n");
 
        /* Clear Root Error Status */
        pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32);
index 95d4759664b304b27328b7af656f066aad540ea3..043b8b0cfcc510a921e79a124a1e0475eabffb6b 100644 (file)
@@ -12,6 +12,8 @@
  *     Huang Ying <ying.huang@intel.com>
  */
 
+#define dev_fmt(fmt) "aer_inject: " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/irq.h>
@@ -332,14 +334,14 @@ static int aer_inject(struct aer_error_inj *einj)
                return -ENODEV;
        rpdev = pcie_find_root_port(dev);
        if (!rpdev) {
-               pci_err(dev, "aer_inject: Root port not found\n");
+               pci_err(dev, "Root port not found\n");
                ret = -ENODEV;
                goto out_put;
        }
 
        pos_cap_err = dev->aer_cap;
        if (!pos_cap_err) {
-               pci_err(dev, "aer_inject: Device doesn't support AER\n");
+               pci_err(dev, "Device doesn't support AER\n");
                ret = -EPROTONOSUPPORT;
                goto out_put;
        }
@@ -350,7 +352,7 @@ static int aer_inject(struct aer_error_inj *einj)
 
        rp_pos_cap_err = rpdev->aer_cap;
        if (!rp_pos_cap_err) {
-               pci_err(rpdev, "aer_inject: Root port doesn't support AER\n");
+               pci_err(rpdev, "Root port doesn't support AER\n");
                ret = -EPROTONOSUPPORT;
                goto out_put;
        }
@@ -398,14 +400,14 @@ static int aer_inject(struct aer_error_inj *einj)
        if (!aer_mask_override && einj->cor_status &&
            !(einj->cor_status & ~cor_mask)) {
                ret = -EINVAL;
-               pci_warn(dev, "aer_inject: The correctable error(s) is masked by device\n");
+               pci_warn(dev, "The correctable error(s) is masked by device\n");
                spin_unlock_irqrestore(&inject_lock, flags);
                goto out_put;
        }
        if (!aer_mask_override && einj->uncor_status &&
            !(einj->uncor_status & ~uncor_mask)) {
                ret = -EINVAL;
-               pci_warn(dev, "aer_inject: The uncorrectable error(s) is masked by device\n");
+               pci_warn(dev, "The uncorrectable error(s) is masked by device\n");
                spin_unlock_irqrestore(&inject_lock, flags);
                goto out_put;
        }
@@ -460,19 +462,17 @@ static int aer_inject(struct aer_error_inj *einj)
        if (device) {
                edev = to_pcie_device(device);
                if (!get_service_data(edev)) {
-                       dev_warn(&edev->device,
-                                "aer_inject: AER service is not initialized\n");
+                       pci_warn(edev->port, "AER service is not initialized\n");
                        ret = -EPROTONOSUPPORT;
                        goto out_put;
                }
-               dev_info(&edev->device,
-                        "aer_inject: Injecting errors %08x/%08x into device %s\n",
+               pci_info(edev->port, "Injecting errors %08x/%08x into device %s\n",
                         einj->cor_status, einj->uncor_status, pci_name(dev));
                local_irq_disable();
                generic_handle_irq(edev->irq);
                local_irq_enable();
        } else {
-               pci_err(rpdev, "aer_inject: AER device not found\n");
+               pci_err(rpdev, "AER device not found\n");
                ret = -ENODEV;
        }
 out_put:
index 727e3c1ef9a4173a1f36841946b3ee8dab4598e7..fd4cb75088f9b5432c68c8db0b75bd169291cb8d 100644 (file)
@@ -196,6 +196,36 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
        link->clkpm_capable = (blacklist) ? 0 : capable;
 }
 
+static bool pcie_retrain_link(struct pcie_link_state *link)
+{
+       struct pci_dev *parent = link->pdev;
+       unsigned long end_jiffies;
+       u16 reg16;
+
+       pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &reg16);
+       reg16 |= PCI_EXP_LNKCTL_RL;
+       pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
+       if (parent->clear_retrain_link) {
+               /*
+                * Due to an erratum in some devices the Retrain Link bit
+                * needs to be cleared again manually to allow the link
+                * training to succeed.
+                */
+               reg16 &= ~PCI_EXP_LNKCTL_RL;
+               pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
+       }
+
+       /* Wait for link training end. Break out after waiting for timeout */
+       end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT;
+       do {
+               pcie_capability_read_word(parent, PCI_EXP_LNKSTA, &reg16);
+               if (!(reg16 & PCI_EXP_LNKSTA_LT))
+                       break;
+               msleep(1);
+       } while (time_before(jiffies, end_jiffies));
+       return !(reg16 & PCI_EXP_LNKSTA_LT);
+}
+
 /*
  * pcie_aspm_configure_common_clock: check if the 2 ends of a link
  *   could use common clock. If they are, configure them to use the
@@ -205,7 +235,6 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
 {
        int same_clock = 1;
        u16 reg16, parent_reg, child_reg[8];
-       unsigned long start_jiffies;
        struct pci_dev *child, *parent = link->pdev;
        struct pci_bus *linkbus = parent->subordinate;
        /*
@@ -263,21 +292,7 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
                reg16 &= ~PCI_EXP_LNKCTL_CCC;
        pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
 
-       /* Retrain link */
-       reg16 |= PCI_EXP_LNKCTL_RL;
-       pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
-
-       /* Wait for link training end. Break out after waiting for timeout */
-       start_jiffies = jiffies;
-       for (;;) {
-               pcie_capability_read_word(parent, PCI_EXP_LNKSTA, &reg16);
-               if (!(reg16 & PCI_EXP_LNKSTA_LT))
-                       break;
-               if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT))
-                       break;
-               msleep(1);
-       }
-       if (!(reg16 & PCI_EXP_LNKSTA_LT))
+       if (pcie_retrain_link(link))
                return;
 
        /* Training failed. Restore common clock configurations */
index 4fa9e3523ee1a22bc763aa5ea0f162dc00ab09dd..77e685771487411e28af60c2b41e3bc5d4a56e22 100644 (file)
@@ -107,11 +107,25 @@ static void pcie_bandwidth_notification_remove(struct pcie_device *srv)
        free_irq(srv->irq, srv);
 }
 
+static int pcie_bandwidth_notification_suspend(struct pcie_device *srv)
+{
+       pcie_disable_link_bandwidth_notification(srv->port);
+       return 0;
+}
+
+static int pcie_bandwidth_notification_resume(struct pcie_device *srv)
+{
+       pcie_enable_link_bandwidth_notification(srv->port);
+       return 0;
+}
+
 static struct pcie_port_service_driver pcie_bandwidth_notification_driver = {
        .name           = "pcie_bw_notification",
        .port_type      = PCIE_ANY_PORT,
        .service        = PCIE_PORT_SERVICE_BWNOTIF,
        .probe          = pcie_bandwidth_notification_probe,
+       .suspend        = pcie_bandwidth_notification_suspend,
+       .resume         = pcie_bandwidth_notification_resume,
        .remove         = pcie_bandwidth_notification_remove,
 };
 
index 7b77754a82de4a0e1727c5bf5fd1124edcf1d301..a32ec3487a8d0009cb699bbf4efe60e0f6953371 100644 (file)
@@ -6,6 +6,8 @@
  * Copyright (C) 2016 Intel Corp.
  */
 
+#define dev_fmt(fmt) "DPC: " fmt
+
 #include <linux/aer.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -100,7 +102,6 @@ static int dpc_wait_rp_inactive(struct dpc_dev *dpc)
 {
        unsigned long timeout = jiffies + HZ;
        struct pci_dev *pdev = dpc->dev->port;
-       struct device *dev = &dpc->dev->device;
        u16 cap = dpc->cap_pos, status;
 
        pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status);
@@ -110,7 +111,7 @@ static int dpc_wait_rp_inactive(struct dpc_dev *dpc)
                pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status);
        }
        if (status & PCI_EXP_DPC_RP_BUSY) {
-               dev_warn(dev, "DPC root port still busy\n");
+               pci_warn(pdev, "root port still busy\n");
                return -EBUSY;
        }
        return 0;
@@ -148,7 +149,6 @@ static pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
 
 static void dpc_process_rp_pio_error(struct dpc_dev *dpc)
 {
-       struct device *dev = &dpc->dev->device;
        struct pci_dev *pdev = dpc->dev->port;
        u16 cap = dpc->cap_pos, dpc_status, first_error;
        u32 status, mask, sev, syserr, exc, dw0, dw1, dw2, dw3, log, prefix;
@@ -156,13 +156,13 @@ static void dpc_process_rp_pio_error(struct dpc_dev *dpc)
 
        pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, &status);
        pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_MASK, &mask);
-       dev_err(dev, "rp_pio_status: %#010x, rp_pio_mask: %#010x\n",
+       pci_err(pdev, "rp_pio_status: %#010x, rp_pio_mask: %#010x\n",
                status, mask);
 
        pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_SEVERITY, &sev);
        pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_SYSERROR, &syserr);
        pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_EXCEPTION, &exc);
-       dev_err(dev, "RP PIO severity=%#010x, syserror=%#010x, exception=%#010x\n",
+       pci_err(pdev, "RP PIO severity=%#010x, syserror=%#010x, exception=%#010x\n",
                sev, syserr, exc);
 
        /* Get First Error Pointer */
@@ -171,7 +171,7 @@ static void dpc_process_rp_pio_error(struct dpc_dev *dpc)
 
        for (i = 0; i < ARRAY_SIZE(rp_pio_error_string); i++) {
                if ((status & ~mask) & (1 << i))
-                       dev_err(dev, "[%2d] %s%s\n", i, rp_pio_error_string[i],
+                       pci_err(pdev, "[%2d] %s%s\n", i, rp_pio_error_string[i],
                                first_error == i ? " (First)" : "");
        }
 
@@ -185,18 +185,18 @@ static void dpc_process_rp_pio_error(struct dpc_dev *dpc)
                              &dw2);
        pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 12,
                              &dw3);
-       dev_err(dev, "TLP Header: %#010x %#010x %#010x %#010x\n",
+       pci_err(pdev, "TLP Header: %#010x %#010x %#010x %#010x\n",
                dw0, dw1, dw2, dw3);
 
        if (dpc->rp_log_size < 5)
                goto clear_status;
        pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_IMPSPEC_LOG, &log);
-       dev_err(dev, "RP PIO ImpSpec Log %#010x\n", log);
+       pci_err(pdev, "RP PIO ImpSpec Log %#010x\n", log);
 
        for (i = 0; i < dpc->rp_log_size - 5; i++) {
                pci_read_config_dword(pdev,
                        cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG, &prefix);
-               dev_err(dev, "TLP Prefix Header: dw%d, %#010x\n", i, prefix);
+               pci_err(pdev, "TLP Prefix Header: dw%d, %#010x\n", i, prefix);
        }
  clear_status:
        pci_write_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, status);
@@ -229,18 +229,17 @@ static irqreturn_t dpc_handler(int irq, void *context)
        struct aer_err_info info;
        struct dpc_dev *dpc = context;
        struct pci_dev *pdev = dpc->dev->port;
-       struct device *dev = &dpc->dev->device;
        u16 cap = dpc->cap_pos, status, source, reason, ext_reason;
 
        pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status);
        pci_read_config_word(pdev, cap + PCI_EXP_DPC_SOURCE_ID, &source);
 
-       dev_info(dev, "DPC containment event, status:%#06x source:%#06x\n",
+       pci_info(pdev, "containment event, status:%#06x source:%#06x\n",
                 status, source);
 
        reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN) >> 1;
        ext_reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT) >> 5;
-       dev_warn(dev, "DPC %s detected\n",
+       pci_warn(pdev, "%s detected\n",
                 (reason == 0) ? "unmasked uncorrectable error" :
                 (reason == 1) ? "ERR_NONFATAL" :
                 (reason == 2) ? "ERR_FATAL" :
@@ -307,7 +306,7 @@ static int dpc_probe(struct pcie_device *dev)
                                           dpc_handler, IRQF_SHARED,
                                           "pcie-dpc", dpc);
        if (status) {
-               dev_warn(device, "request IRQ%d failed: %d\n", dev->irq,
+               pci_warn(pdev, "request IRQ%d failed: %d\n", dev->irq,
                         status);
                return status;
        }
@@ -319,7 +318,7 @@ static int dpc_probe(struct pcie_device *dev)
        if (dpc->rp_extensions) {
                dpc->rp_log_size = (cap & PCI_EXP_DPC_RP_PIO_LOG_SIZE) >> 8;
                if (dpc->rp_log_size < 4 || dpc->rp_log_size > 9) {
-                       dev_err(device, "RP PIO log size %u is invalid\n",
+                       pci_err(pdev, "RP PIO log size %u is invalid\n",
                                dpc->rp_log_size);
                        dpc->rp_log_size = 0;
                }
@@ -328,11 +327,11 @@ static int dpc_probe(struct pcie_device *dev)
        ctl = (ctl & 0xfff4) | PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN;
        pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl);
 
-       dev_info(device, "DPC error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n",
-               cap & PCI_EXP_DPC_IRQ, FLAG(cap, PCI_EXP_DPC_CAP_RP_EXT),
-               FLAG(cap, PCI_EXP_DPC_CAP_POISONED_TLP),
-               FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), dpc->rp_log_size,
-               FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE));
+       pci_info(pdev, "error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n",
+                cap & PCI_EXP_DPC_IRQ, FLAG(cap, PCI_EXP_DPC_CAP_RP_EXT),
+                FLAG(cap, PCI_EXP_DPC_CAP_POISONED_TLP),
+                FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), dpc->rp_log_size,
+                FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE));
 
        pci_add_ext_cap_save_buffer(pdev, PCI_EXT_CAP_ID_DPC, sizeof(u16));
        return status;
index 54d593d10396ff9716c76a0b01eecb5a632f984c..f38e6c19dd501e135d4da31cc52f2e682fb985ff 100644 (file)
@@ -7,6 +7,8 @@
  * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
  */
 
+#define dev_fmt(fmt) "PME: " fmt
+
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -194,14 +196,14 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id)
                 * assuming that the PME was reported by a PCIe-PCI bridge that
                 * used devfn different from zero.
                 */
-               pci_dbg(port, "PME interrupt generated for non-existent device %02x:%02x.%d\n",
-                       busnr, PCI_SLOT(devfn), PCI_FUNC(devfn));
+               pci_info(port, "interrupt generated for non-existent device %02x:%02x.%d\n",
+                        busnr, PCI_SLOT(devfn), PCI_FUNC(devfn));
                found = pcie_pme_from_pci_bridge(bus, 0);
        }
 
  out:
        if (!found)
-               pci_dbg(port, "Spurious native PME interrupt!\n");
+               pci_info(port, "Spurious native interrupt!\n");
 }
 
 /**
@@ -341,7 +343,7 @@ static int pcie_pme_probe(struct pcie_device *srv)
                return ret;
        }
 
-       pci_info(port, "Signaling PME with IRQ %d\n", srv->irq);
+       pci_info(port, "Signaling with IRQ %d\n", srv->irq);
 
        pcie_pme_mark_devices(port);
        pcie_pme_interrupt_enable(port, true);
index 7e12d016386394ab9b401f3e5dcb8da8b917484c..0e8e2c186f508df22739534e464a37b1f3a89225 100644 (file)
@@ -317,7 +317,7 @@ fail:
        res->flags = 0;
 out:
        if (res->flags)
-               pci_printk(KERN_DEBUG, dev, "reg 0x%x: %pR\n", pos, res);
+               pci_info(dev, "reg 0x%x: %pR\n", pos, res);
 
        return (res->flags & IORESOURCE_MEM_64) ? 1 : 0;
 }
@@ -435,7 +435,7 @@ static void pci_read_bridge_io(struct pci_bus *child)
                region.start = base;
                region.end = limit + io_granularity - 1;
                pcibios_bus_to_resource(dev->bus, res, &region);
-               pci_printk(KERN_DEBUG, dev, "  bridge window %pR\n", res);
+               pci_info(dev, "  bridge window %pR\n", res);
        }
 }
 
@@ -457,7 +457,7 @@ static void pci_read_bridge_mmio(struct pci_bus *child)
                region.start = base;
                region.end = limit + 0xfffff;
                pcibios_bus_to_resource(dev->bus, res, &region);
-               pci_printk(KERN_DEBUG, dev, "  bridge window %pR\n", res);
+               pci_info(dev, "  bridge window %pR\n", res);
        }
 }
 
@@ -510,7 +510,7 @@ static void pci_read_bridge_mmio_pref(struct pci_bus *child)
                region.start = base;
                region.end = limit + 0xfffff;
                pcibios_bus_to_resource(dev->bus, res, &region);
-               pci_printk(KERN_DEBUG, dev, "  bridge window %pR\n", res);
+               pci_info(dev, "  bridge window %pR\n", res);
        }
 }
 
@@ -540,8 +540,7 @@ void pci_read_bridge_bases(struct pci_bus *child)
                        if (res && res->flags) {
                                pci_bus_add_resource(child, res,
                                                     PCI_SUBTRACTIVE_DECODE);
-                               pci_printk(KERN_DEBUG, dev,
-                                          "  bridge window %pR (subtractive decode)\n",
+                               pci_info(dev, "  bridge window %pR (subtractive decode)\n",
                                           res);
                        }
                }
@@ -586,16 +585,10 @@ static void pci_release_host_bridge_dev(struct device *dev)
        kfree(to_pci_host_bridge(dev));
 }
 
-struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
+static void pci_init_host_bridge(struct pci_host_bridge *bridge)
 {
-       struct pci_host_bridge *bridge;
-
-       bridge = kzalloc(sizeof(*bridge) + priv, GFP_KERNEL);
-       if (!bridge)
-               return NULL;
-
        INIT_LIST_HEAD(&bridge->windows);
-       bridge->dev.release = pci_release_host_bridge_dev;
+       INIT_LIST_HEAD(&bridge->dma_ranges);
 
        /*
         * We assume we can manage these PCIe features.  Some systems may
@@ -608,6 +601,18 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
        bridge->native_shpc_hotplug = 1;
        bridge->native_pme = 1;
        bridge->native_ltr = 1;
+}
+
+struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
+{
+       struct pci_host_bridge *bridge;
+
+       bridge = kzalloc(sizeof(*bridge) + priv, GFP_KERNEL);
+       if (!bridge)
+               return NULL;
+
+       pci_init_host_bridge(bridge);
+       bridge->dev.release = pci_release_host_bridge_dev;
 
        return bridge;
 }
@@ -622,7 +627,7 @@ struct pci_host_bridge *devm_pci_alloc_host_bridge(struct device *dev,
        if (!bridge)
                return NULL;
 
-       INIT_LIST_HEAD(&bridge->windows);
+       pci_init_host_bridge(bridge);
        bridge->dev.release = devm_pci_release_host_bridge_dev;
 
        return bridge;
@@ -632,6 +637,7 @@ EXPORT_SYMBOL(devm_pci_alloc_host_bridge);
 void pci_free_host_bridge(struct pci_host_bridge *bridge)
 {
        pci_free_resource_list(&bridge->windows);
+       pci_free_resource_list(&bridge->dma_ranges);
 
        kfree(bridge);
 }
@@ -1081,6 +1087,36 @@ static void pci_enable_crs(struct pci_dev *pdev)
 
 static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
                                              unsigned int available_buses);
+/**
+ * pci_ea_fixed_busnrs() - Read fixed Secondary and Subordinate bus
+ * numbers from EA capability.
+ * @dev: Bridge
+ * @sec: updated with secondary bus number from EA
+ * @sub: updated with subordinate bus number from EA
+ *
+ * If @dev is a bridge with EA capability, update @sec and @sub with
+ * fixed bus numbers from the capability and return true.  Otherwise,
+ * return false.
+ */
+static bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub)
+{
+       int ea, offset;
+       u32 dw;
+
+       if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
+               return false;
+
+       /* find PCI EA capability in list */
+       ea = pci_find_capability(dev, PCI_CAP_ID_EA);
+       if (!ea)
+               return false;
+
+       offset = ea + PCI_EA_FIRST_ENT;
+       pci_read_config_dword(dev, offset, &dw);
+       *sec =  dw & PCI_EA_SEC_BUS_MASK;
+       *sub = (dw & PCI_EA_SUB_BUS_MASK) >> PCI_EA_SUB_BUS_SHIFT;
+       return true;
+}
 
 /*
  * pci_scan_bridge_extend() - Scan buses behind a bridge
@@ -1115,6 +1151,9 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
        u16 bctl;
        u8 primary, secondary, subordinate;
        int broken = 0;
+       bool fixed_buses;
+       u8 fixed_sec, fixed_sub;
+       int next_busnr;
 
        /*
         * Make sure the bridge is powered on to be able to access config
@@ -1214,17 +1253,24 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
                /* Clear errors */
                pci_write_config_word(dev, PCI_STATUS, 0xffff);
 
+               /* Read bus numbers from EA Capability (if present) */
+               fixed_buses = pci_ea_fixed_busnrs(dev, &fixed_sec, &fixed_sub);
+               if (fixed_buses)
+                       next_busnr = fixed_sec;
+               else
+                       next_busnr = max + 1;
+
                /*
                 * Prevent assigning a bus number that already exists.
                 * This can happen when a bridge is hot-plugged, so in this
                 * case we only re-scan this bus.
                 */
-               child = pci_find_bus(pci_domain_nr(bus), max+1);
+               child = pci_find_bus(pci_domain_nr(bus), next_busnr);
                if (!child) {
-                       child = pci_add_new_bus(bus, dev, max+1);
+                       child = pci_add_new_bus(bus, dev, next_busnr);
                        if (!child)
                                goto out;
-                       pci_bus_insert_busn_res(child, max+1,
+                       pci_bus_insert_busn_res(child, next_busnr,
                                                bus->busn_res.end);
                }
                max++;
@@ -1285,7 +1331,13 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
                        max += i;
                }
 
-               /* Set subordinate bus number to its real value */
+               /*
+                * Set subordinate bus number to its real value.
+                * If fixed subordinate bus number exists from EA
+                * capability then use it.
+                */
+               if (fixed_buses)
+                       max = fixed_sub;
                pci_bus_update_busn_res_end(child, max);
                pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
        }
@@ -1690,7 +1742,7 @@ int pci_setup_device(struct pci_dev *dev)
        dev->revision = class & 0xff;
        dev->class = class >> 8;                    /* upper 3 bytes */
 
-       pci_printk(KERN_DEBUG, dev, "[%04x:%04x] type %02x class %#08x\n",
+       pci_info(dev, "[%04x:%04x] type %02x class %#08x\n",
                   dev->vendor, dev->device, dev->hdr_type, dev->class);
 
        if (pci_early_dump)
@@ -2026,6 +2078,119 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
         */
 }
 
+static u16 hpx3_device_type(struct pci_dev *dev)
+{
+       u16 pcie_type = pci_pcie_type(dev);
+       const int pcie_to_hpx3_type[] = {
+               [PCI_EXP_TYPE_ENDPOINT]    = HPX_TYPE_ENDPOINT,
+               [PCI_EXP_TYPE_LEG_END]     = HPX_TYPE_LEG_END,
+               [PCI_EXP_TYPE_RC_END]      = HPX_TYPE_RC_END,
+               [PCI_EXP_TYPE_RC_EC]       = HPX_TYPE_RC_EC,
+               [PCI_EXP_TYPE_ROOT_PORT]   = HPX_TYPE_ROOT_PORT,
+               [PCI_EXP_TYPE_UPSTREAM]    = HPX_TYPE_UPSTREAM,
+               [PCI_EXP_TYPE_DOWNSTREAM]  = HPX_TYPE_DOWNSTREAM,
+               [PCI_EXP_TYPE_PCI_BRIDGE]  = HPX_TYPE_PCI_BRIDGE,
+               [PCI_EXP_TYPE_PCIE_BRIDGE] = HPX_TYPE_PCIE_BRIDGE,
+       };
+
+       if (pcie_type >= ARRAY_SIZE(pcie_to_hpx3_type))
+               return 0;
+
+       return pcie_to_hpx3_type[pcie_type];
+}
+
+static u8 hpx3_function_type(struct pci_dev *dev)
+{
+       if (dev->is_virtfn)
+               return HPX_FN_SRIOV_VIRT;
+       else if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV) > 0)
+               return HPX_FN_SRIOV_PHYS;
+       else
+               return HPX_FN_NORMAL;
+}
+
+static bool hpx3_cap_ver_matches(u8 pcie_cap_id, u8 hpx3_cap_id)
+{
+       u8 cap_ver = hpx3_cap_id & 0xf;
+
+       if ((hpx3_cap_id & BIT(4)) && cap_ver >= pcie_cap_id)
+               return true;
+       else if (cap_ver == pcie_cap_id)
+               return true;
+
+       return false;
+}
+
+static void program_hpx_type3_register(struct pci_dev *dev,
+                                      const struct hpx_type3 *reg)
+{
+       u32 match_reg, write_reg, header, orig_value;
+       u16 pos;
+
+       if (!(hpx3_device_type(dev) & reg->device_type))
+               return;
+
+       if (!(hpx3_function_type(dev) & reg->function_type))
+               return;
+
+       switch (reg->config_space_location) {
+       case HPX_CFG_PCICFG:
+               pos = 0;
+               break;
+       case HPX_CFG_PCIE_CAP:
+               pos = pci_find_capability(dev, reg->pci_exp_cap_id);
+               if (pos == 0)
+                       return;
+
+               break;
+       case HPX_CFG_PCIE_CAP_EXT:
+               pos = pci_find_ext_capability(dev, reg->pci_exp_cap_id);
+               if (pos == 0)
+                       return;
+
+               pci_read_config_dword(dev, pos, &header);
+               if (!hpx3_cap_ver_matches(PCI_EXT_CAP_VER(header),
+                                         reg->pci_exp_cap_ver))
+                       return;
+
+               break;
+       case HPX_CFG_VEND_CAP:  /* Fall through */
+       case HPX_CFG_DVSEC:     /* Fall through */
+       default:
+               pci_warn(dev, "Encountered _HPX type 3 with unsupported config space location");
+               return;
+       }
+
+       pci_read_config_dword(dev, pos + reg->match_offset, &match_reg);
+
+       if ((match_reg & reg->match_mask_and) != reg->match_value)
+               return;
+
+       pci_read_config_dword(dev, pos + reg->reg_offset, &write_reg);
+       orig_value = write_reg;
+       write_reg &= reg->reg_mask_and;
+       write_reg |= reg->reg_mask_or;
+
+       if (orig_value == write_reg)
+               return;
+
+       pci_write_config_dword(dev, pos + reg->reg_offset, write_reg);
+
+       pci_dbg(dev, "Applied _HPX3 at [0x%x]: 0x%08x -> 0x%08x",
+               pos, orig_value, write_reg);
+}
+
+static void program_hpx_type3(struct pci_dev *dev, struct hpx_type3 *hpx3)
+{
+       if (!hpx3)
+               return;
+
+       if (!pci_is_pcie(dev))
+               return;
+
+       program_hpx_type3_register(dev, hpx3);
+}
+
 int pci_configure_extended_tags(struct pci_dev *dev, void *ign)
 {
        struct pci_host_bridge *host;
@@ -2206,8 +2371,12 @@ static void pci_configure_serr(struct pci_dev *dev)
 
 static void pci_configure_device(struct pci_dev *dev)
 {
-       struct hotplug_params hpp;
-       int ret;
+       static const struct hotplug_program_ops hp_ops = {
+               .program_type0 = program_hpp_type0,
+               .program_type1 = program_hpp_type1,
+               .program_type2 = program_hpp_type2,
+               .program_type3 = program_hpx_type3,
+       };
 
        pci_configure_mps(dev);
        pci_configure_extended_tags(dev, NULL);
@@ -2216,14 +2385,7 @@ static void pci_configure_device(struct pci_dev *dev)
        pci_configure_eetlp_prefix(dev);
        pci_configure_serr(dev);
 
-       memset(&hpp, 0, sizeof(hpp));
-       ret = pci_get_hp_params(dev, &hpp);
-       if (ret)
-               return;
-
-       program_hpp_type2(dev, hpp.t2);
-       program_hpp_type1(dev, hpp.t1);
-       program_hpp_type0(dev, hpp.t0);
+       pci_acpi_program_hp_params(dev, &hp_ops);
 }
 
 static void pci_release_capabilities(struct pci_dev *dev)
@@ -3086,7 +3248,7 @@ int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
        conflict = request_resource_conflict(parent_res, res);
 
        if (conflict)
-               dev_printk(KERN_DEBUG, &b->dev,
+               dev_info(&b->dev,
                           "busn_res: can not insert %pR under %s%pR (conflicts with %s %pR)\n",
                            res, pci_is_root_bus(b) ? "domain " : "",
                            parent_res, conflict->name, conflict);
@@ -3106,8 +3268,7 @@ int pci_bus_update_busn_res_end(struct pci_bus *b, int bus_max)
 
        size = bus_max - res->start + 1;
        ret = adjust_resource(res, res->start, size);
-       dev_printk(KERN_DEBUG, &b->dev,
-                       "busn_res: %pR end %s updated to %02x\n",
+       dev_info(&b->dev, "busn_res: %pR end %s updated to %02x\n",
                        &old_res, ret ? "can not be" : "is", bus_max);
 
        if (!ret && !res->parent)
@@ -3125,8 +3286,7 @@ void pci_bus_release_busn_res(struct pci_bus *b)
                return;
 
        ret = release_resource(res);
-       dev_printk(KERN_DEBUG, &b->dev,
-                       "busn_res: %pR %s released\n",
+       dev_info(&b->dev, "busn_res: %pR %s released\n",
                        res, ret ? "can not be" : "is");
 }
 
index 6fa1627ce08d35360bca82b8059ad968423574a1..445b51db75b0030e287860b6e9363a08a9a85d4e 100644 (file)
@@ -222,6 +222,7 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
                }
                /* If arch decided it can't, fall through... */
 #endif /* HAVE_PCI_MMAP */
+               /* fall through */
        default:
                ret = -EINVAL;
                break;
index eb0afc275901df10e54a82c82fcc7c72dca31b48..0f16acc323c6bc743a917f3e47c4dfa4b8474c23 100644 (file)
@@ -159,8 +159,7 @@ static int __init pci_apply_final_quirks(void)
        u8 tmp;
 
        if (pci_cache_line_size)
-               printk(KERN_DEBUG "PCI: CLS %u bytes\n",
-                      pci_cache_line_size << 2);
+               pr_info("PCI: CLS %u bytes\n", pci_cache_line_size << 2);
 
        pci_apply_fixup_final_quirks = true;
        for_each_pci_dev(dev) {
@@ -177,16 +176,16 @@ static int __init pci_apply_final_quirks(void)
                        if (!tmp || cls == tmp)
                                continue;
 
-                       printk(KERN_DEBUG "PCI: CLS mismatch (%u != %u), using %u bytes\n",
-                              cls << 2, tmp << 2,
-                              pci_dfl_cache_line_size << 2);
+                       pci_info(dev, "CLS mismatch (%u != %u), using %u bytes\n",
+                                cls << 2, tmp << 2,
+                                pci_dfl_cache_line_size << 2);
                        pci_cache_line_size = pci_dfl_cache_line_size;
                }
        }
 
        if (!pci_cache_line_size) {
-               printk(KERN_DEBUG "PCI: CLS %u bytes, default %u\n",
-                      cls << 2, pci_dfl_cache_line_size << 2);
+               pr_info("PCI: CLS %u bytes, default %u\n", cls << 2,
+                       pci_dfl_cache_line_size << 2);
                pci_cache_line_size = cls ? cls : pci_dfl_cache_line_size;
        }
 
@@ -2245,6 +2244,23 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10f1, quirk_disable_aspm_l0s);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10f4, quirk_disable_aspm_l0s);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1508, quirk_disable_aspm_l0s);
 
+/*
+ * Some Pericom PCIe-to-PCI bridges in reverse mode need the PCIe Retrain
+ * Link bit cleared after starting the link retrain process to allow this
+ * process to finish.
+ *
+ * Affected devices: PI7C9X110, PI7C9X111SL, PI7C9X130.  See also the
+ * Pericom Errata Sheet PI7C9X111SLB_errata_rev1.2_102711.pdf.
+ */
+static void quirk_enable_clear_retrain_link(struct pci_dev *dev)
+{
+       dev->clear_retrain_link = 1;
+       pci_info(dev, "Enable PCIe Retrain Link quirk\n");
+}
+DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe110, quirk_enable_clear_retrain_link);
+DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe111, quirk_enable_clear_retrain_link);
+DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe130, quirk_enable_clear_retrain_link);
+
 static void fixup_rev1_53c810(struct pci_dev *dev)
 {
        u32 class = dev->class;
@@ -2596,7 +2612,7 @@ static void nvbridge_check_legacy_irq_routing(struct pci_dev *dev)
        pci_read_config_dword(dev, 0x74, &cfg);
 
        if (cfg & ((1 << 2) | (1 << 15))) {
-               printk(KERN_INFO "Rewriting IRQ routing register on MCP55\n");
+               pr_info("Rewriting IRQ routing register on MCP55\n");
                cfg &= ~((1 << 2) | (1 << 15));
                pci_write_config_dword(dev, 0x74, cfg);
        }
@@ -3408,6 +3424,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032, quirk_no_bus_reset);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c, quirk_no_bus_reset);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0033, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0034, quirk_no_bus_reset);
 
 /*
  * Root port on some Cavium CN8xxx chips do not successfully complete a bus
@@ -4905,6 +4922,7 @@ static void quirk_no_ats(struct pci_dev *pdev)
 
 /* AMD Stoney platform GPU */
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x98e4, quirk_no_ats);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x6900, quirk_no_ats);
 #endif /* CONFIG_PCI_ATS */
 
 /* Freescale PCIe doesn't support MSI in RC mode */
@@ -5122,3 +5140,61 @@ SWITCHTEC_QUIRK(0x8573);  /* PFXI 48XG3 */
 SWITCHTEC_QUIRK(0x8574);  /* PFXI 64XG3 */
 SWITCHTEC_QUIRK(0x8575);  /* PFXI 80XG3 */
 SWITCHTEC_QUIRK(0x8576);  /* PFXI 96XG3 */
+
+/*
+ * On Lenovo Thinkpad P50 SKUs with a Nvidia Quadro M1000M, the BIOS does
+ * not always reset the secondary Nvidia GPU between reboots if the system
+ * is configured to use Hybrid Graphics mode.  This results in the GPU
+ * being left in whatever state it was in during the *previous* boot, which
+ * causes spurious interrupts from the GPU, which in turn causes us to
+ * disable the wrong IRQ and end up breaking the touchpad.  Unsurprisingly,
+ * this also completely breaks nouveau.
+ *
+ * Luckily, it seems a simple reset of the Nvidia GPU brings it back to a
+ * clean state and fixes all these issues.
+ *
+ * When the machine is configured in Dedicated display mode, the issue
+ * doesn't occur.  Fortunately the GPU advertises NoReset+ when in this
+ * mode, so we can detect that and avoid resetting it.
+ */
+static void quirk_reset_lenovo_thinkpad_p50_nvgpu(struct pci_dev *pdev)
+{
+       void __iomem *map;
+       int ret;
+
+       if (pdev->subsystem_vendor != PCI_VENDOR_ID_LENOVO ||
+           pdev->subsystem_device != 0x222e ||
+           !pdev->reset_fn)
+               return;
+
+       if (pci_enable_device_mem(pdev))
+               return;
+
+       /*
+        * Based on nvkm_device_ctor() in
+        * drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+        */
+       map = pci_iomap(pdev, 0, 0x23000);
+       if (!map) {
+               pci_err(pdev, "Can't map MMIO space\n");
+               goto out_disable;
+       }
+
+       /*
+        * Make sure the GPU looks like it's been POSTed before resetting
+        * it.
+        */
+       if (ioread32(map + 0x2240c) & 0x2) {
+               pci_info(pdev, FW_BUG "GPU left initialized by EFI, resetting\n");
+               ret = pci_reset_function(pdev);
+               if (ret < 0)
+                       pci_err(pdev, "Failed to reset GPU: %d\n", ret);
+       }
+
+       iounmap(map);
+out_disable:
+       pci_disable_device(pdev);
+}
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, 0x13b1,
+                             PCI_CLASS_DISPLAY_VGA, 8,
+                             quirk_reset_lenovo_thinkpad_p50_nvgpu);
index 2b5f720862d37e70a2b6f75c8264dd042cb332ee..5c7922612733ec668f7583b33939752cc5cab1e6 100644 (file)
@@ -33,7 +33,7 @@ int pci_for_each_dma_alias(struct pci_dev *pdev,
        struct pci_bus *bus;
        int ret;
 
-       ret = fn(pdev, PCI_DEVID(pdev->bus->number, pdev->devfn), data);
+       ret = fn(pdev, pci_dev_id(pdev), data);
        if (ret)
                return ret;
 
@@ -88,9 +88,7 @@ int pci_for_each_dma_alias(struct pci_dev *pdev,
                                        return ret;
                                continue;
                        case PCI_EXP_TYPE_PCIE_BRIDGE:
-                               ret = fn(tmp,
-                                        PCI_DEVID(tmp->bus->number,
-                                                  tmp->devfn), data);
+                               ret = fn(tmp, pci_dev_id(tmp), data);
                                if (ret)
                                        return ret;
                                continue;
@@ -101,9 +99,7 @@ int pci_for_each_dma_alias(struct pci_dev *pdev,
                                         PCI_DEVID(tmp->subordinate->number,
                                                   PCI_DEVFN(0, 0)), data);
                        else
-                               ret = fn(tmp,
-                                        PCI_DEVID(tmp->bus->number,
-                                                  tmp->devfn), data);
+                               ret = fn(tmp, pci_dev_id(tmp), data);
                        if (ret)
                                return ret;
                }
index ec44a0f3a7acf735c9456b00078d585a9c1907b8..0cdd5ff389de91ff4a011ab976155fa88a9b30e4 100644 (file)
@@ -49,17 +49,15 @@ static void free_list(struct list_head *head)
 }
 
 /**
- * add_to_list() - add a new resource tracker to the list
+ * add_to_list() - Add a new resource tracker to the list
  * @head:      Head of the list
- * @dev:       device corresponding to which the resource
- *             belongs
- * @res:       The resource to be tracked
- * @add_size:  additional size to be optionally added
- *              to the resource
+ * @dev:       Device to which the resource belongs
+ * @res:       Resource to be tracked
+ * @add_size:  Additional size to be optionally added to the resource
  */
-static int add_to_list(struct list_head *head,
-                struct pci_dev *dev, struct resource *res,
-                resource_size_t add_size, resource_size_t min_align)
+static int add_to_list(struct list_head *head, struct pci_dev *dev,
+                      struct resource *res, resource_size_t add_size,
+                      resource_size_t min_align)
 {
        struct pci_dev_resource *tmp;
 
@@ -80,8 +78,7 @@ static int add_to_list(struct list_head *head,
        return 0;
 }
 
-static void remove_from_list(struct list_head *head,
-                                struct resource *res)
+static void remove_from_list(struct list_head *head, struct resource *res)
 {
        struct pci_dev_resource *dev_res, *tmp;
 
@@ -158,7 +155,7 @@ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head)
                tmp->res = r;
                tmp->dev = dev;
 
-               /* fallback is smallest one or list is empty*/
+               /* Fallback is smallest one or list is empty */
                n = head;
                list_for_each_entry(dev_res, head, list) {
                        resource_size_t align;
@@ -171,21 +168,20 @@ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head)
                                break;
                        }
                }
-               /* Insert it just before n*/
+               /* Insert it just before n */
                list_add_tail(&tmp->list, n);
        }
 }
 
-static void __dev_sort_resources(struct pci_dev *dev,
-                                struct list_head *head)
+static void __dev_sort_resources(struct pci_dev *dev, struct list_head *head)
 {
        u16 class = dev->class >> 8;
 
-       /* Don't touch classless devices or host bridges or ioapics.  */
+       /* Don't touch classless devices or host bridges or IOAPICs */
        if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST)
                return;
 
-       /* Don't touch ioapic devices already enabled by firmware */
+       /* Don't touch IOAPIC devices already enabled by firmware */
        if (class == PCI_CLASS_SYSTEM_PIC) {
                u16 command;
                pci_read_config_word(dev, PCI_COMMAND, &command);
@@ -204,19 +200,18 @@ static inline void reset_resource(struct resource *res)
 }
 
 /**
- * reassign_resources_sorted() - satisfy any additional resource requests
+ * reassign_resources_sorted() - Satisfy any additional resource requests
  *
- * @realloc_head : head of the list tracking requests requiring additional
- *             resources
- * @head     : head of the list tracking requests with allocated
- *             resources
+ * @realloc_head:      Head of the list tracking requests requiring
+ *                     additional resources
+ * @head:              Head of the list tracking requests with allocated
+ *                     resources
  *
- * Walk through each element of the realloc_head and try to procure
- * additional resources for the element, provided the element
- * is in the head list.
+ * Walk through each element of the realloc_head and try to procure additional
+ * resources for the element, provided the element is in the head list.
  */
 static void reassign_resources_sorted(struct list_head *realloc_head,
-               struct list_head *head)
+                                     struct list_head *head)
 {
        struct resource *res;
        struct pci_dev_resource *add_res, *tmp;
@@ -228,18 +223,18 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
                bool found_match = false;
 
                res = add_res->res;
-               /* skip resource that has been reset */
+               /* Skip resource that has been reset */
                if (!res->flags)
                        goto out;
 
-               /* skip this resource if not found in head list */
+               /* Skip this resource if not found in head list */
                list_for_each_entry(dev_res, head, list) {
                        if (dev_res->res == res) {
                                found_match = true;
                                break;
                        }
                }
-               if (!found_match)/* just skip */
+               if (!found_match) /* Just skip */
                        continue;
 
                idx = res - &add_res->dev->resource[0];
@@ -255,10 +250,9 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
                                 (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
                        if (pci_reassign_resource(add_res->dev, idx,
                                                  add_size, align))
-                               pci_printk(KERN_DEBUG, add_res->dev,
-                                          "failed to add %llx res[%d]=%pR\n",
-                                          (unsigned long long)add_size,
-                                          idx, res);
+                               pci_info(add_res->dev, "failed to add %llx res[%d]=%pR\n",
+                                        (unsigned long long) add_size, idx,
+                                        res);
                }
 out:
                list_del(&add_res->list);
@@ -267,14 +261,14 @@ out:
 }
 
 /**
- * assign_requested_resources_sorted() - satisfy resource requests
+ * assign_requested_resources_sorted() - Satisfy resource requests
  *
- * @head : head of the list tracking requests for resources
- * @fail_head : head of the list tracking requests that could
- *             not be allocated
+ * @head:      Head of the list tracking requests for resources
+ * @fail_head: Head of the list tracking requests that could not be
+ *             allocated
  *
- * Satisfy resource requests of each element in the list. Add
- * requests that could not satisfied to the failed_list.
+ * Satisfy resource requests of each element in the list.  Add requests that
+ * could not be satisfied to the failed_list.
  */
 static void assign_requested_resources_sorted(struct list_head *head,
                                 struct list_head *fail_head)
@@ -290,8 +284,9 @@ static void assign_requested_resources_sorted(struct list_head *head,
                    pci_assign_resource(dev_res->dev, idx)) {
                        if (fail_head) {
                                /*
-                                * if the failed res is for ROM BAR, and it will
-                                * be enabled later, don't add it to the list
+                                * If the failed resource is a ROM BAR and
+                                * it will be enabled later, don't add it
+                                * to the list.
                                 */
                                if (!((idx == PCI_ROM_RESOURCE) &&
                                      (!(res->flags & IORESOURCE_ROM_ENABLE))))
@@ -310,15 +305,14 @@ static unsigned long pci_fail_res_type_mask(struct list_head *fail_head)
        struct pci_dev_resource *fail_res;
        unsigned long mask = 0;
 
-       /* check failed type */
+       /* Check failed type */
        list_for_each_entry(fail_res, fail_head, list)
                mask |= fail_res->flags;
 
        /*
-        * one pref failed resource will set IORESOURCE_MEM,
-        * as we can allocate pref in non-pref range.
-        * Will release all assigned non-pref sibling resources
-        * according to that bit.
+        * One pref failed resource will set IORESOURCE_MEM, as we can
+        * allocate pref in non-pref range.  Will release all assigned
+        * non-pref sibling resources according to that bit.
         */
        return mask & (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH);
 }
@@ -328,11 +322,11 @@ static bool pci_need_to_release(unsigned long mask, struct resource *res)
        if (res->flags & IORESOURCE_IO)
                return !!(mask & IORESOURCE_IO);
 
-       /* check pref at first */
+       /* Check pref at first */
        if (res->flags & IORESOURCE_PREFETCH) {
                if (mask & IORESOURCE_PREFETCH)
                        return true;
-               /* count pref if its parent is non-pref */
+               /* Count pref if its parent is non-pref */
                else if ((mask & IORESOURCE_MEM) &&
                         !(res->parent->flags & IORESOURCE_PREFETCH))
                        return true;
@@ -343,33 +337,33 @@ static bool pci_need_to_release(unsigned long mask, struct resource *res)
        if (res->flags & IORESOURCE_MEM)
                return !!(mask & IORESOURCE_MEM);
 
-       return false;   /* should not get here */
+       return false;   /* Should not get here */
 }
 
 static void __assign_resources_sorted(struct list_head *head,
-                                struct list_head *realloc_head,
-                                struct list_head *fail_head)
+                                     struct list_head *realloc_head,
+                                     struct list_head *fail_head)
 {
        /*
-        * Should not assign requested resources at first.
-        *   they could be adjacent, so later reassign can not reallocate
-        *   them one by one in parent resource window.
-        * Try to assign requested + add_size at beginning
-        *  if could do that, could get out early.
-        *  if could not do that, we still try to assign requested at first,
-        *    then try to reassign add_size for some resources.
+        * Should not assign requested resources at first.  They could be
+        * adjacent, so later reassign can not reallocate them one by one in
+        * parent resource window.
+        *
+        * Try to assign requested + add_size at beginning.  If could do that,
+        * could get out early.  If could not do that, we still try to assign
+        * requested at first, then try to reassign add_size for some resources.
         *
         * Separate three resource type checking if we need to release
         * assigned resource after requested + add_size try.
-        *      1. if there is io port assign fail, will release assigned
-        *         io port.
-        *      2. if there is pref mmio assign fail, release assigned
-        *         pref mmio.
-        *         if assigned pref mmio's parent is non-pref mmio and there
-        *         is non-pref mmio assign fail, will release that assigned
-        *         pref mmio.
-        *      3. if there is non-pref mmio assign fail or pref mmio
-        *         assigned fail, will release assigned non-pref mmio.
+        *
+        *      1. If IO port assignment fails, will release assigned IO
+        *         port.
+        *      2. If pref MMIO assignment fails, release assigned pref
+        *         MMIO.  If assigned pref MMIO's parent is non-pref MMIO
+        *         and non-pref MMIO assignment fails, will release that
+        *         assigned pref MMIO.
+        *      3. If non-pref MMIO assignment fails or pref MMIO
+        *         assignment fails, will release assigned non-pref MMIO.
         */
        LIST_HEAD(save_head);
        LIST_HEAD(local_fail_head);
@@ -398,7 +392,7 @@ static void __assign_resources_sorted(struct list_head *head,
                /*
                 * There are two kinds of additional resources in the list:
                 * 1. bridge resource  -- IORESOURCE_STARTALIGN
-                * 2. SR-IOV resource   -- IORESOURCE_SIZEALIGN
+                * 2. SR-IOV resource  -- IORESOURCE_SIZEALIGN
                 * Here just fix the additional alignment for bridge
                 */
                if (!(dev_res->res->flags & IORESOURCE_STARTALIGN))
@@ -407,10 +401,10 @@ static void __assign_resources_sorted(struct list_head *head,
                add_align = get_res_add_align(realloc_head, dev_res->res);
 
                /*
-                * The "head" list is sorted by the alignment to make sure
-                * resources with bigger alignment will be assigned first.
-                * After we change the alignment of a dev_res in "head" list,
-                * we need to reorder the list by alignment to make it
+                * The "head" list is sorted by alignment so resources with
+                * bigger alignment will be assigned first.  After we
+                * change the alignment of a dev_res in "head" list, we
+                * need to reorder the list by alignment to make it
                 * consistent.
                 */
                if (add_align > dev_res->res->start) {
@@ -435,7 +429,7 @@ static void __assign_resources_sorted(struct list_head *head,
        /* Try updated head list with add_size added */
        assign_requested_resources_sorted(head, &local_fail_head);
 
-       /* all assigned with add_size ? */
+       /* All assigned with add_size? */
        if (list_empty(&local_fail_head)) {
                /* Remove head list from realloc_head list */
                list_for_each_entry(dev_res, head, list)
@@ -445,13 +439,13 @@ static void __assign_resources_sorted(struct list_head *head,
                return;
        }
 
-       /* check failed type */
+       /* Check failed type */
        fail_type = pci_fail_res_type_mask(&local_fail_head);
-       /* remove not need to be released assigned res from head list etc */
+       /* Remove not need to be released assigned res from head list etc */
        list_for_each_entry_safe(dev_res, tmp_res, head, list)
                if (dev_res->res->parent &&
                    !pci_need_to_release(fail_type, dev_res->res)) {
-                       /* remove it from realloc_head list */
+                       /* Remove it from realloc_head list */
                        remove_from_list(realloc_head, dev_res->res);
                        remove_from_list(&save_head, dev_res->res);
                        list_del(&dev_res->list);
@@ -477,16 +471,15 @@ requested_and_reassign:
        /* Satisfy the must-have resource requests */
        assign_requested_resources_sorted(head, fail_head);
 
-       /* Try to satisfy any additional optional resource
-               requests */
+       /* Try to satisfy any additional optional resource requests */
        if (realloc_head)
                reassign_resources_sorted(realloc_head, head);
        free_list(head);
 }
 
 static void pdev_assign_resources_sorted(struct pci_dev *dev,
-                                struct list_head *add_head,
-                                struct list_head *fail_head)
+                                        struct list_head *add_head,
+                                        struct list_head *fail_head)
 {
        LIST_HEAD(head);
 
@@ -563,17 +556,19 @@ void pci_setup_cardbus(struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pci_setup_cardbus);
 
-/* Initialize bridges with base/limit values we have collected.
-   PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998)
-   requires that if there is no I/O ports or memory behind the
-   bridge, corresponding range must be turned off by writing base
-   value greater than limit to the bridge's base/limit registers.
-
-   Note: care must be taken when updating I/O base/limit registers
-   of bridges which support 32-bit I/O. This update requires two
-   config space writes, so it's quite possible that an I/O window of
-   the bridge will have some undesirable address (e.g. 0) after the
-   first write. Ditto 64-bit prefetchable MMIO.  */
+/*
+ * Initialize bridges with base/limit values we have collected.  PCI-to-PCI
+ * Bridge Architecture Specification rev. 1.1 (1998) requires that if there
+ * are no I/O ports or memory behind the bridge, the corresponding range
+ * must be turned off by writing base value greater than limit to the
+ * bridge's base/limit registers.
+ *
+ * Note: care must be taken when updating I/O base/limit registers of
+ * bridges which support 32-bit I/O.  This update requires two config space
+ * writes, so it's quite possible that an I/O window of the bridge will
+ * have some undesirable address (e.g. 0) after the first write.  Ditto
+ * 64-bit prefetchable MMIO.
+ */
 static void pci_setup_bridge_io(struct pci_dev *bridge)
 {
        struct resource *res;
@@ -587,7 +582,7 @@ static void pci_setup_bridge_io(struct pci_dev *bridge)
        if (bridge->io_window_1k)
                io_mask = PCI_IO_1K_RANGE_MASK;
 
-       /* Set up the top and bottom of the PCI I/O segment for this bus. */
+       /* Set up the top and bottom of the PCI I/O segment for this bus */
        res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0];
        pcibios_resource_to_bus(bridge->bus, &region, res);
        if (res->flags & IORESOURCE_IO) {
@@ -595,19 +590,19 @@ static void pci_setup_bridge_io(struct pci_dev *bridge)
                io_base_lo = (region.start >> 8) & io_mask;
                io_limit_lo = (region.end >> 8) & io_mask;
                l = ((u16) io_limit_lo << 8) | io_base_lo;
-               /* Set up upper 16 bits of I/O base/limit. */
+               /* Set up upper 16 bits of I/O base/limit */
                io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
                pci_info(bridge, "  bridge window %pR\n", res);
        } else {
-               /* Clear upper 16 bits of I/O base/limit. */
+               /* Clear upper 16 bits of I/O base/limit */
                io_upper16 = 0;
                l = 0x00f0;
        }
-       /* Temporarily disable the I/O range before updating PCI_IO_BASE. */
+       /* Temporarily disable the I/O range before updating PCI_IO_BASE */
        pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff);
-       /* Update lower 16 bits of I/O base/limit. */
+       /* Update lower 16 bits of I/O base/limit */
        pci_write_config_word(bridge, PCI_IO_BASE, l);
-       /* Update upper 16 bits of I/O base/limit. */
+       /* Update upper 16 bits of I/O base/limit */
        pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16);
 }
 
@@ -617,7 +612,7 @@ static void pci_setup_bridge_mmio(struct pci_dev *bridge)
        struct pci_bus_region region;
        u32 l;
 
-       /* Set up the top and bottom of the PCI Memory segment for this bus. */
+       /* Set up the top and bottom of the PCI Memory segment for this bus */
        res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
        pcibios_resource_to_bus(bridge->bus, &region, res);
        if (res->flags & IORESOURCE_MEM) {
@@ -636,12 +631,14 @@ static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge)
        struct pci_bus_region region;
        u32 l, bu, lu;
 
-       /* Clear out the upper 32 bits of PREF limit.
-          If PCI_PREF_BASE_UPPER32 was non-zero, this temporarily
-          disables PREF range, which is ok. */
+       /*
+        * Clear out the upper 32 bits of PREF limit.  If
+        * PCI_PREF_BASE_UPPER32 was non-zero, this temporarily disables
+        * PREF range, which is ok.
+        */
        pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
 
-       /* Set up PREF base/limit. */
+       /* Set up PREF base/limit */
        bu = lu = 0;
        res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2];
        pcibios_resource_to_bus(bridge->bus, &region, res);
@@ -658,7 +655,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge)
        }
        pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
 
-       /* Set the upper 32 bits of PREF base & limit. */
+       /* Set the upper 32 bits of PREF base & limit */
        pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
        pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
 }
@@ -702,13 +699,13 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i)
                return 0;
 
        if (pci_claim_resource(bridge, i) == 0)
-               return 0;       /* claimed the window */
+               return 0;       /* Claimed the window */
 
        if ((bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI)
                return 0;
 
        if (!pci_bus_clip_resource(bridge, i))
-               return -EINVAL; /* clipping didn't change anything */
+               return -EINVAL; /* Clipping didn't change anything */
 
        switch (i - PCI_BRIDGE_RESOURCES) {
        case 0:
@@ -725,14 +722,16 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i)
        }
 
        if (pci_claim_resource(bridge, i) == 0)
-               return 0;       /* claimed a smaller window */
+               return 0;       /* Claimed a smaller window */
 
        return -EINVAL;
 }
 
-/* Check whether the bridge supports optional I/O and
-   prefetchable memory ranges. If not, the respective
-   base/limit registers must be read-only and read as 0. */
+/*
+ * Check whether the bridge supports optional I/O and prefetchable memory
+ * ranges.  If not, the respective base/limit registers must be read-only
+ * and read as 0.
+ */
 static void pci_bridge_check_ranges(struct pci_bus *bus)
 {
        struct pci_dev *bridge = bus->self;
@@ -752,12 +751,14 @@ static void pci_bridge_check_ranges(struct pci_bus *bus)
        }
 }
 
-/* Helper function for sizing routines: find first available
-   bus resource of a given type. Note: we intentionally skip
-   the bus resources which have already been assigned (that is,
-   have non-NULL parent resource). */
+/*
+ * Helper function for sizing routines: find first available bus resource
+ * of a given type.  Note: we intentionally skip the bus resources which
+ * have already been assigned (that is, have non-NULL parent resource).
+ */
 static struct resource *find_free_bus_resource(struct pci_bus *bus,
-                        unsigned long type_mask, unsigned long type)
+                                              unsigned long type_mask,
+                                              unsigned long type)
 {
        int i;
        struct resource *r;
@@ -772,19 +773,21 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus,
 }
 
 static resource_size_t calculate_iosize(resource_size_t size,
-               resource_size_t min_size,
-               resource_size_t size1,
-               resource_size_t add_size,
-               resource_size_t children_add_size,
-               resource_size_t old_size,
-               resource_size_t align)
+                                       resource_size_t min_size,
+                                       resource_size_t size1,
+                                       resource_size_t add_size,
+                                       resource_size_t children_add_size,
+                                       resource_size_t old_size,
+                                       resource_size_t align)
 {
        if (size < min_size)
                size = min_size;
        if (old_size == 1)
                old_size = 0;
-       /* To be fixed in 2.5: we should have sort of HAVE_ISA
-          flag in the struct pci_bus. */
+       /*
+        * To be fixed in 2.5: we should have sort of HAVE_ISA flag in the
+        * struct pci_bus.
+        */
 #if defined(CONFIG_ISA) || defined(CONFIG_EISA)
        size = (size & 0xff) + ((size & ~0xffUL) << 2);
 #endif
@@ -797,11 +800,11 @@ static resource_size_t calculate_iosize(resource_size_t size,
 }
 
 static resource_size_t calculate_memsize(resource_size_t size,
-               resource_size_t min_size,
-               resource_size_t add_size,
-               resource_size_t children_add_size,
-               resource_size_t old_size,
-               resource_size_t align)
+                                        resource_size_t min_size,
+                                        resource_size_t add_size,
+                                        resource_size_t children_add_size,
+                                        resource_size_t old_size,
+                                        resource_size_t align)
 {
        if (size < min_size)
                size = min_size;
@@ -824,8 +827,7 @@ resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus,
 #define PCI_P2P_DEFAULT_IO_ALIGN       0x1000          /* 4KiB */
 #define PCI_P2P_DEFAULT_IO_ALIGN_1K    0x400           /* 1KiB */
 
-static resource_size_t window_alignment(struct pci_bus *bus,
-                                       unsigned long type)
+static resource_size_t window_alignment(struct pci_bus *bus, unsigned long type)
 {
        resource_size_t align = 1, arch_align;
 
@@ -833,8 +835,8 @@ static resource_size_t window_alignment(struct pci_bus *bus,
                align = PCI_P2P_DEFAULT_MEM_ALIGN;
        else if (type & IORESOURCE_IO) {
                /*
-                * Per spec, I/O windows are 4K-aligned, but some
-                * bridges have an extension to support 1K alignment.
+                * Per spec, I/O windows are 4K-aligned, but some bridges have
+                * an extension to support 1K alignment.
                 */
                if (bus->self->io_window_1k)
                        align = PCI_P2P_DEFAULT_IO_ALIGN_1K;
@@ -847,20 +849,21 @@ static resource_size_t window_alignment(struct pci_bus *bus,
 }
 
 /**
- * pbus_size_io() - size the io window of a given bus
+ * pbus_size_io() - Size the I/O window of a given bus
  *
- * @bus : the bus
- * @min_size : the minimum io window that must to be allocated
- * @add_size : additional optional io window
- * @realloc_head : track the additional io window on this list
+ * @bus:               The bus
+ * @min_size:          The minimum I/O window that must be allocated
+ * @add_size:          Additional optional I/O window
+ * @realloc_head:      Track the additional I/O window on this list
  *
- * Sizing the IO windows of the PCI-PCI bridge is trivial,
- * since these windows have 1K or 4K granularity and the IO ranges
- * of non-bridge PCI devices are limited to 256 bytes.
- * We must be careful with the ISA aliasing though.
+ * Sizing the I/O windows of the PCI-PCI bridge is trivial, since these
+ * windows have 1K or 4K granularity and the I/O ranges of non-bridge PCI
+ * devices are limited to 256 bytes.  We must be careful with the ISA
+ * aliasing though.
  */
 static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
-               resource_size_t add_size, struct list_head *realloc_head)
+                        resource_size_t add_size,
+                        struct list_head *realloc_head)
 {
        struct pci_dev *dev;
        struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO,
@@ -918,9 +921,9 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
        if (size1 > size0 && realloc_head) {
                add_to_list(realloc_head, bus->self, b_res, size1-size0,
                            min_align);
-               pci_printk(KERN_DEBUG, bus->self, "bridge window %pR to %pR add_size %llx\n",
-                          b_res, &bus->busn_res,
-                          (unsigned long long)size1-size0);
+               pci_info(bus->self, "bridge window %pR to %pR add_size %llx\n",
+                        b_res, &bus->busn_res,
+                        (unsigned long long) size1 - size0);
        }
 }
 
@@ -947,33 +950,33 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns,
 }
 
 /**
- * pbus_size_mem() - size the memory window of a given bus
+ * pbus_size_mem() - Size the memory window of a given bus
  *
- * @bus : the bus
- * @mask: mask the resource flag, then compare it with type
- * @type: the type of free resource from bridge
- * @type2: second match type
- * @type3: third match type
- * @min_size : the minimum memory window that must to be allocated
- * @add_size : additional optional memory window
- * @realloc_head : track the additional memory window on this list
+ * @bus:               The bus
+ * @mask:              Mask the resource flag, then compare it with type
+ * @type:              The type of free resource from bridge
+ * @type2:             Second match type
+ * @type3:             Third match type
+ * @min_size:          The minimum memory window that must be allocated
+ * @add_size:          Additional optional memory window
+ * @realloc_head:      Track the additional memory window on this list
  *
- * Calculate the size of the bus and minimal alignment which
- * guarantees that all child resources fit in this size.
+ * Calculate the size of the bus and minimal alignment which guarantees
+ * that all child resources fit in this size.
  *
- * Returns -ENOSPC if there's no available bus resource of the desired type.
- * Otherwise, sets the bus resource start/end to indicate the required
- * size, adds things to realloc_head (if supplied), and returns 0.
+ * Return -ENOSPC if there's no available bus resource of the desired
+ * type.  Otherwise, set the bus resource start/end to indicate the
+ * required size, add things to realloc_head (if supplied), and return 0.
  */
 static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
                         unsigned long type, unsigned long type2,
-                        unsigned long type3,
-                        resource_size_t min_size, resource_size_t add_size,
+                        unsigned long type3, resource_size_t min_size,
+                        resource_size_t add_size,
                         struct list_head *realloc_head)
 {
        struct pci_dev *dev;
        resource_size_t min_align, align, size, size0, size1;
-       resource_size_t aligns[18];     /* Alignments from 1Mb to 128Gb */
+       resource_size_t aligns[18]; /* Alignments from 1MB to 128GB */
        int order, max_order;
        struct resource *b_res = find_free_bus_resource(bus,
                                        mask | IORESOURCE_PREFETCH, type);
@@ -1002,12 +1005,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
                                continue;
                        r_size = resource_size(r);
 #ifdef CONFIG_PCI_IOV
-                       /* put SRIOV requested res to the optional list */
+                       /* Put SRIOV requested res to the optional list */
                        if (realloc_head && i >= PCI_IOV_RESOURCES &&
                                        i <= PCI_IOV_RESOURCE_END) {
                                add_align = max(pci_resource_alignment(dev, r), add_align);
                                r->end = r->start - 1;
-                               add_to_list(realloc_head, dev, r, r_size, 0/* don't care */);
+                               add_to_list(realloc_head, dev, r, r_size, 0 /* Don't care */);
                                children_add_size += r_size;
                                continue;
                        }
@@ -1029,8 +1032,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
                                continue;
                        }
                        size += max(r_size, align);
-                       /* Exclude ranges with size > align from
-                          calculation of the alignment. */
+                       /*
+                        * Exclude ranges with size > align from calculation of
+                        * the alignment.
+                        */
                        if (r_size <= align)
                                aligns[order] += align;
                        if (order > max_order)
@@ -1063,7 +1068,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
        b_res->flags |= IORESOURCE_STARTALIGN;
        if (size1 > size0 && realloc_head) {
                add_to_list(realloc_head, bus->self, b_res, size1-size0, add_align);
-               pci_printk(KERN_DEBUG, bus->self, "bridge window %pR to %pR add_size %llx add_align %llx\n",
+               pci_info(bus->self, "bridge window %pR to %pR add_size %llx add_align %llx\n",
                           b_res, &bus->busn_res,
                           (unsigned long long) (size1 - size0),
                           (unsigned long long) add_align);
@@ -1081,7 +1086,7 @@ unsigned long pci_cardbus_resource_alignment(struct resource *res)
 }
 
 static void pci_bus_size_cardbus(struct pci_bus *bus,
-                       struct list_head *realloc_head)
+                                struct list_head *realloc_head)
 {
        struct pci_dev *bridge = bus->self;
        struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
@@ -1091,8 +1096,8 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
        if (b_res[0].parent)
                goto handle_b_res_1;
        /*
-        * Reserve some resources for CardBus.  We reserve
-        * a fixed amount of bus space for CardBus bridges.
+        * Reserve some resources for CardBus.  We reserve a fixed amount
+        * of bus space for CardBus bridges.
         */
        b_res[0].start = pci_cardbus_io_size;
        b_res[0].end = b_res[0].start + pci_cardbus_io_size - 1;
@@ -1116,7 +1121,7 @@ handle_b_res_1:
        }
 
 handle_b_res_2:
-       /* MEM1 must not be pref mmio */
+       /* MEM1 must not be pref MMIO */
        pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
        if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) {
                ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1;
@@ -1124,10 +1129,7 @@ handle_b_res_2:
                pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
        }
 
-       /*
-        * Check whether prefetchable memory is supported
-        * by this bridge.
-        */
+       /* Check whether prefetchable memory is supported by this bridge. */
        pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
        if (!(ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)) {
                ctrl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0;
@@ -1138,9 +1140,8 @@ handle_b_res_2:
        if (b_res[2].parent)
                goto handle_b_res_3;
        /*
-        * If we have prefetchable memory support, allocate
-        * two regions.  Otherwise, allocate one region of
-        * twice the size.
+        * If we have prefetchable memory support, allocate two regions.
+        * Otherwise, allocate one region of twice the size.
         */
        if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
                b_res[2].start = pci_cardbus_mem_size;
@@ -1153,7 +1154,7 @@ handle_b_res_2:
                                 pci_cardbus_mem_size, pci_cardbus_mem_size);
                }
 
-               /* reduce that to half */
+               /* Reduce that to half */
                b_res_3_size = pci_cardbus_mem_size;
        }
 
@@ -1204,7 +1205,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
 
        switch (bus->self->hdr_type) {
        case PCI_HEADER_TYPE_CARDBUS:
-               /* don't size cardbuses yet. */
+               /* Don't size CardBuses yet */
                break;
 
        case PCI_HEADER_TYPE_BRIDGE:
@@ -1271,18 +1272,17 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
 
                /*
                 * Compute the size required to put everything else in the
-                * non-prefetchable window.  This includes:
+                * non-prefetchable window. This includes:
                 *
                 *   - all non-prefetchable resources
                 *   - 32-bit prefetchable resources if there's a 64-bit
                 *     prefetchable window or no prefetchable window at all
-                *   - 64-bit prefetchable resources if there's no
-                *     prefetchable window at all
+                *   - 64-bit prefetchable resources if there's no prefetchable
+                *     window at all
                 *
-                * Note that the strategy in __pci_assign_resource() must
-                * match that used here.  Specifically, we cannot put a
-                * 32-bit prefetchable resource in a 64-bit prefetchable
-                * window.
+                * Note that the strategy in __pci_assign_resource() must match
+                * that used here. Specifically, we cannot put a 32-bit
+                * prefetchable resource in a 64-bit prefetchable window.
                 */
                pbus_size_mem(bus, mask, IORESOURCE_MEM, type2, type3,
                                realloc_head ? 0 : additional_mem_size,
@@ -1315,8 +1315,8 @@ static void assign_fixed_resource_on_bus(struct pci_bus *b, struct resource *r)
 }
 
 /*
- * Try to assign any resources marked as IORESOURCE_PCI_FIXED, as they
- * are skipped by pbus_assign_resources_sorted().
+ * Try to assign any resources marked as IORESOURCE_PCI_FIXED, as they are
+ * skipped by pbus_assign_resources_sorted().
  */
 static void pdev_assign_fixed_resources(struct pci_dev *dev)
 {
@@ -1427,10 +1427,9 @@ static void pci_bus_allocate_resources(struct pci_bus *b)
        struct pci_bus *child;
 
        /*
-        * Carry out a depth-first search on the PCI bus
-        * tree to allocate bridge apertures. Read the
-        * programmed bridge bases and recursively claim
-        * the respective bridge resources.
+        * Carry out a depth-first search on the PCI bus tree to allocate
+        * bridge apertures.  Read the programmed bridge bases and
+        * recursively claim the respective bridge resources.
         */
        if (b->self) {
                pci_read_bridge_bases(b);
@@ -1484,7 +1483,7 @@ static void __pci_bridge_assign_resources(const struct pci_dev *bridge,
         IORESOURCE_MEM_64)
 
 static void pci_bridge_release_resources(struct pci_bus *bus,
-                                         unsigned long type)
+                                        unsigned long type)
 {
        struct pci_dev *dev = bus->self;
        struct resource *r;
@@ -1495,16 +1494,14 @@ static void pci_bridge_release_resources(struct pci_bus *bus,
        b_res = &dev->resource[PCI_BRIDGE_RESOURCES];
 
        /*
-        *     1. if there is io port assign fail, will release bridge
-        *        io port.
-        *     2. if there is non pref mmio assign fail, release bridge
-        *        nonpref mmio.
-        *     3. if there is 64bit pref mmio assign fail, and bridge pref
-        *        is 64bit, release bridge pref mmio.
-        *     4. if there is pref mmio assign fail, and bridge pref is
-        *        32bit mmio, release bridge pref mmio
-        *     5. if there is pref mmio assign fail, and bridge pref is not
-        *        assigned, release bridge nonpref mmio.
+        * 1. If IO port assignment fails, release bridge IO port.
+        * 2. If non pref MMIO assignment fails, release bridge nonpref MMIO.
+        * 3. If 64bit pref MMIO assignment fails, and bridge pref is 64bit,
+        *    release bridge pref MMIO.
+        * 4. If pref MMIO assignment fails, and bridge pref is 32bit,
+        *    release bridge pref MMIO.
+        * 5. If pref MMIO assignment fails, and bridge pref is not
+        *    assigned, release bridge nonpref MMIO.
         */
        if (type & IORESOURCE_IO)
                idx = 0;
@@ -1524,25 +1521,22 @@ static void pci_bridge_release_resources(struct pci_bus *bus,
        if (!r->parent)
                return;
 
-       /*
-        * if there are children under that, we should release them
-        *  all
-        */
+       /* If there are children, release them all */
        release_child_resources(r);
        if (!release_resource(r)) {
                type = old_flags = r->flags & PCI_RES_TYPE_MASK;
-               pci_printk(KERN_DEBUG, dev, "resource %d %pR released\n",
-                                       PCI_BRIDGE_RESOURCES + idx, r);
-               /* keep the old size */
+               pci_info(dev, "resource %d %pR released\n",
+                        PCI_BRIDGE_RESOURCES + idx, r);
+               /* Keep the old size */
                r->end = resource_size(r) - 1;
                r->start = 0;
                r->flags = 0;
 
-               /* avoiding touch the one without PREF */
+               /* Avoiding touch the one without PREF */
                if (type & IORESOURCE_PREFETCH)
                        type = IORESOURCE_PREFETCH;
                __pci_setup_bridge(bus, type);
-               /* for next child res under same bridge */
+               /* For next child res under same bridge */
                r->flags = old_flags;
        }
 }
@@ -1551,9 +1545,10 @@ enum release_type {
        leaf_only,
        whole_subtree,
 };
+
 /*
- * try to release pci bridge resources that is from leaf bridge,
- * so we can allocate big new one later
+ * Try to release PCI bridge resources from leaf bridge, so we can allocate
+ * a larger window later.
  */
 static void pci_bus_release_bridge_resources(struct pci_bus *bus,
                                             unsigned long type,
@@ -1596,7 +1591,7 @@ static void pci_bus_dump_res(struct pci_bus *bus)
                if (!res || !res->end || !res->flags)
                        continue;
 
-               dev_printk(KERN_DEBUG, &bus->dev, "resource %d %pR\n", i, res);
+               dev_info(&bus->dev, "resource %d %pR\n", i, res);
        }
 }
 
@@ -1678,7 +1673,7 @@ static int iov_resources_unassigned(struct pci_dev *dev, void *data)
                pcibios_resource_to_bus(dev->bus, &region, r);
                if (!region.start) {
                        *unassigned = true;
-                       return 1; /* return early from pci_walk_bus() */
+                       return 1; /* Return early from pci_walk_bus() */
                }
        }
 
@@ -1686,7 +1681,7 @@ static int iov_resources_unassigned(struct pci_dev *dev, void *data)
 }
 
 static enum enable_type pci_realloc_detect(struct pci_bus *bus,
-                        enum enable_type enable_local)
+                                          enum enable_type enable_local)
 {
        bool unassigned = false;
 
@@ -1701,21 +1696,21 @@ static enum enable_type pci_realloc_detect(struct pci_bus *bus,
 }
 #else
 static enum enable_type pci_realloc_detect(struct pci_bus *bus,
-                        enum enable_type enable_local)
+                                          enum enable_type enable_local)
 {
        return enable_local;
 }
 #endif
 
 /*
- * first try will not touch pci bridge res
- * second and later try will clear small leaf bridge res
- * will stop till to the max depth if can not find good one
+ * First try will not touch PCI bridge res.
+ * Second and later try will clear small leaf bridge res.
+ * Will stop till to the max depth if can not find good one.
  */
 void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)
 {
-       LIST_HEAD(realloc_head); /* list of resources that
-                                       want additional resources */
+       LIST_HEAD(realloc_head);
+       /* List of resources that want additional resources */
        struct list_head *add_list = NULL;
        int tried_times = 0;
        enum release_type rel_type = leaf_only;
@@ -1724,26 +1719,26 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)
        int pci_try_num = 1;
        enum enable_type enable_local;
 
-       /* don't realloc if asked to do so */
+       /* Don't realloc if asked to do so */
        enable_local = pci_realloc_detect(bus, pci_realloc_enable);
        if (pci_realloc_enabled(enable_local)) {
                int max_depth = pci_bus_get_depth(bus);
 
                pci_try_num = max_depth + 1;
-               dev_printk(KERN_DEBUG, &bus->dev,
-                          "max bus depth: %d pci_try_num: %d\n",
-                          max_depth, pci_try_num);
+               dev_info(&bus->dev, "max bus depth: %d pci_try_num: %d\n",
+                        max_depth, pci_try_num);
        }
 
 again:
        /*
-        * last try will use add_list, otherwise will try good to have as
-        * must have, so can realloc parent bridge resource
+        * Last try will use add_list, otherwise will try good to have as must
+        * have, so can realloc parent bridge resource
         */
        if (tried_times + 1 == pci_try_num)
                add_list = &realloc_head;
-       /* Depth first, calculate sizes and alignments of all
-          subordinate buses. */
+       /*
+        * Depth first, calculate sizes and alignments of all subordinate buses.
+        */
        __pci_bus_size_bridges(bus, add_list);
 
        /* Depth last, allocate resources and update the hardware. */
@@ -1752,7 +1747,7 @@ again:
                BUG_ON(!list_empty(add_list));
        tried_times++;
 
-       /* any device complain? */
+       /* Any device complain? */
        if (list_empty(&fail_head))
                goto dump;
 
@@ -1766,23 +1761,23 @@ again:
                goto dump;
        }
 
-       dev_printk(KERN_DEBUG, &bus->dev,
-                  "No. %d try to assign unassigned res\n", tried_times + 1);
+       dev_info(&bus->dev, "No. %d try to assign unassigned res\n",
+                tried_times + 1);
 
-       /* third times and later will not check if it is leaf */
+       /* Third times and later will not check if it is leaf */
        if ((tried_times + 1) > 2)
                rel_type = whole_subtree;
 
        /*
         * Try to release leaf bridge's resources that doesn't fit resource of
-        * child device under that bridge
+        * child device under that bridge.
         */
        list_for_each_entry(fail_res, &fail_head, list)
                pci_bus_release_bridge_resources(fail_res->dev->bus,
                                                 fail_res->flags & PCI_RES_TYPE_MASK,
                                                 rel_type);
 
-       /* restore size and flags */
+       /* Restore size and flags */
        list_for_each_entry(fail_res, &fail_head, list) {
                struct resource *res = fail_res->res;
 
@@ -1797,7 +1792,7 @@ again:
        goto again;
 
 dump:
-       /* dump the resource on buses */
+       /* Dump the resource on buses */
        pci_bus_dump_resources(bus);
 }
 
@@ -1808,14 +1803,15 @@ void __init pci_assign_unassigned_resources(void)
        list_for_each_entry(root_bus, &pci_root_buses, node) {
                pci_assign_unassigned_root_bus_resources(root_bus);
 
-               /* Make sure the root bridge has a companion ACPI device: */
+               /* Make sure the root bridge has a companion ACPI device */
                if (ACPI_HANDLE(root_bus->bridge))
                        acpi_ioapic_add(ACPI_HANDLE(root_bus->bridge));
        }
 }
 
 static void extend_bridge_window(struct pci_dev *bridge, struct resource *res,
-                       struct list_head *add_list, resource_size_t available)
+                                struct list_head *add_list,
+                                resource_size_t available)
 {
        struct pci_dev_resource *dev_res;
 
@@ -1839,8 +1835,10 @@ static void extend_bridge_window(struct pci_dev *bridge, struct resource *res,
 }
 
 static void pci_bus_distribute_available_resources(struct pci_bus *bus,
-       struct list_head *add_list, resource_size_t available_io,
-       resource_size_t available_mmio, resource_size_t available_mmio_pref)
+                                           struct list_head *add_list,
+                                           resource_size_t available_io,
+                                           resource_size_t available_mmio,
+                                           resource_size_t available_mmio_pref)
 {
        resource_size_t remaining_io, remaining_mmio, remaining_mmio_pref;
        unsigned int normal_bridges = 0, hotplug_bridges = 0;
@@ -1864,7 +1862,7 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
 
        /*
         * Calculate the total amount of extra resource space we can
-        * pass to bridges below this one. This is basically the
+        * pass to bridges below this one.  This is basically the
         * extra space reduced by the minimal required space for the
         * non-hotplug bridges.
         */
@@ -1874,7 +1872,7 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
 
        /*
         * Calculate how many hotplug bridges and normal bridges there
-        * are on this bus. We will distribute the additional available
+        * are on this bus.  We will distribute the additional available
         * resources between hotplug bridges.
         */
        for_each_pci_bridge(dev, bus) {
@@ -1909,8 +1907,8 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
 
        /*
         * There is only one bridge on the bus so it gets all available
-        * resources which it can then distribute to the possible
-        * hotplug bridges below.
+        * resources which it can then distribute to the possible hotplug
+        * bridges below.
         */
        if (hotplug_bridges + normal_bridges == 1) {
                dev = list_first_entry(&bus->devices, struct pci_dev, bus_list);
@@ -1961,9 +1959,8 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
        }
 }
 
-static void
-pci_bridge_distribute_available_resources(struct pci_dev *bridge,
-                                         struct list_head *add_list)
+static void pci_bridge_distribute_available_resources(struct pci_dev *bridge,
+                                                    struct list_head *add_list)
 {
        resource_size_t available_io, available_mmio, available_mmio_pref;
        const struct resource *res;
@@ -1980,14 +1977,17 @@ pci_bridge_distribute_available_resources(struct pci_dev *bridge,
        available_mmio_pref = resource_size(res);
 
        pci_bus_distribute_available_resources(bridge->subordinate,
-               add_list, available_io, available_mmio, available_mmio_pref);
+                                              add_list, available_io,
+                                              available_mmio,
+                                              available_mmio_pref);
 }
 
 void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
 {
        struct pci_bus *parent = bridge->subordinate;
-       LIST_HEAD(add_list); /* list of resources that
-                                       want additional resources */
+       /* List of resources that want additional resources */
+       LIST_HEAD(add_list);
+
        int tried_times = 0;
        LIST_HEAD(fail_head);
        struct pci_dev_resource *fail_res;
@@ -1997,9 +1997,9 @@ again:
        __pci_bus_size_bridges(parent, &add_list);
 
        /*
-        * Distribute remaining resources (if any) equally between
-        * hotplug bridges below. This makes it possible to extend the
-        * hierarchy later without running out of resources.
+        * Distribute remaining resources (if any) equally between hotplug
+        * bridges below.  This makes it possible to extend the hierarchy
+        * later without running out of resources.
         */
        pci_bridge_distribute_available_resources(bridge, &add_list);
 
@@ -2011,7 +2011,7 @@ again:
                goto enable_all;
 
        if (tried_times >= 2) {
-               /* still fail, don't need to try more */
+               /* Still fail, don't need to try more */
                free_list(&fail_head);
                goto enable_all;
        }
@@ -2020,15 +2020,15 @@ again:
                         tried_times + 1);
 
        /*
-        * Try to release leaf bridge's resources that doesn't fit resource of
-        * child device under that bridge
+        * Try to release leaf bridge's resources that aren't big enough
+        * to contain child device resources.
         */
        list_for_each_entry(fail_res, &fail_head, list)
                pci_bus_release_bridge_resources(fail_res->dev->bus,
                                                 fail_res->flags & PCI_RES_TYPE_MASK,
                                                 whole_subtree);
 
-       /* restore size and flags */
+       /* Restore size and flags */
        list_for_each_entry(fail_res, &fail_head, list) {
                struct resource *res = fail_res->res;
 
@@ -2107,7 +2107,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
        }
 
        list_for_each_entry(dev_res, &saved, list) {
-               /* Skip the bridge we just assigned resources for. */
+               /* Skip the bridge we just assigned resources for */
                if (bridge == dev_res->dev)
                        continue;
 
@@ -2119,7 +2119,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
        return 0;
 
 cleanup:
-       /* restore size and flags */
+       /* Restore size and flags */
        list_for_each_entry(dev_res, &failed, list) {
                struct resource *res = dev_res->res;
 
@@ -2151,8 +2151,8 @@ cleanup:
 void pci_assign_unassigned_bus_resources(struct pci_bus *bus)
 {
        struct pci_dev *dev;
-       LIST_HEAD(add_list); /* list of resources that
-                                       want additional resources */
+       /* List of resources that want additional resources */
+       LIST_HEAD(add_list);
 
        down_read(&pci_bus_sem);
        for_each_pci_bridge(dev, bus)
index c46d5e1ff53692ebeafaee1d4e745d4743a4c78a..f4d92b1afe7b02c7ebf783826331f950a0063e9d 100644 (file)
@@ -403,7 +403,7 @@ static int pci_slot_init(void)
        pci_slots_kset = kset_create_and_add("slots", NULL,
                                                &pci_bus_kset->kobj);
        if (!pci_slots_kset) {
-               printk(KERN_ERR "PCI: Slot initialization failure\n");
+               pr_err("PCI: Slot initialization failure\n");
                return -ENOMEM;
        }
        return 0;
index 0f7b80144863a8f236781ba0e6e2f95d44cd9ae9..bebbde4ebec08883243b47583b8bde2dee865159 100644 (file)
@@ -658,19 +658,25 @@ static int ioctl_flash_part_info(struct switchtec_dev *stdev,
 
 static int ioctl_event_summary(struct switchtec_dev *stdev,
        struct switchtec_user *stuser,
-       struct switchtec_ioctl_event_summary __user *usum)
+       struct switchtec_ioctl_event_summary __user *usum,
+       size_t size)
 {
-       struct switchtec_ioctl_event_summary s = {0};
+       struct switchtec_ioctl_event_summary *s;
        int i;
        u32 reg;
+       int ret = 0;
 
-       s.global = ioread32(&stdev->mmio_sw_event->global_summary);
-       s.part_bitmap = ioread32(&stdev->mmio_sw_event->part_event_bitmap);
-       s.local_part = ioread32(&stdev->mmio_part_cfg->part_event_summary);
+       s = kzalloc(sizeof(*s), GFP_KERNEL);
+       if (!s)
+               return -ENOMEM;
+
+       s->global = ioread32(&stdev->mmio_sw_event->global_summary);
+       s->part_bitmap = ioread32(&stdev->mmio_sw_event->part_event_bitmap);
+       s->local_part = ioread32(&stdev->mmio_part_cfg->part_event_summary);
 
        for (i = 0; i < stdev->partition_count; i++) {
                reg = ioread32(&stdev->mmio_part_cfg_all[i].part_event_summary);
-               s.part[i] = reg;
+               s->part[i] = reg;
        }
 
        for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) {
@@ -679,15 +685,19 @@ static int ioctl_event_summary(struct switchtec_dev *stdev,
                        break;
 
                reg = ioread32(&stdev->mmio_pff_csr[i].pff_event_summary);
-               s.pff[i] = reg;
+               s->pff[i] = reg;
        }
 
-       if (copy_to_user(usum, &s, sizeof(s)))
-               return -EFAULT;
+       if (copy_to_user(usum, s, size)) {
+               ret = -EFAULT;
+               goto error_case;
+       }
 
        stuser->event_cnt = atomic_read(&stdev->event_cnt);
 
-       return 0;
+error_case:
+       kfree(s);
+       return ret;
 }
 
 static u32 __iomem *global_ev_reg(struct switchtec_dev *stdev,
@@ -977,8 +987,9 @@ static long switchtec_dev_ioctl(struct file *filp, unsigned int cmd,
        case SWITCHTEC_IOCTL_FLASH_PART_INFO:
                rc = ioctl_flash_part_info(stdev, argp);
                break;
-       case SWITCHTEC_IOCTL_EVENT_SUMMARY:
-               rc = ioctl_event_summary(stdev, stuser, argp);
+       case SWITCHTEC_IOCTL_EVENT_SUMMARY_LEGACY:
+               rc = ioctl_event_summary(stdev, stuser, argp,
+                                        sizeof(struct switchtec_ioctl_event_summary_legacy));
                break;
        case SWITCHTEC_IOCTL_EVENT_CTL:
                rc = ioctl_event_ctl(stdev, argp);
@@ -989,6 +1000,10 @@ static long switchtec_dev_ioctl(struct file *filp, unsigned int cmd,
        case SWITCHTEC_IOCTL_PORT_TO_PFF:
                rc = ioctl_port_to_pff(stdev, argp);
                break;
+       case SWITCHTEC_IOCTL_EVENT_SUMMARY:
+               rc = ioctl_event_summary(stdev, stuser, argp,
+                                        sizeof(struct switchtec_ioctl_event_summary));
+               break;
        default:
                rc = -ENOTTY;
                break;
@@ -1162,7 +1177,8 @@ static int mask_event(struct switchtec_dev *stdev, int eid, int idx)
        if (!(hdr & SWITCHTEC_EVENT_OCCURRED && hdr & SWITCHTEC_EVENT_EN_IRQ))
                return 0;
 
-       if (eid == SWITCHTEC_IOCTL_EVENT_LINK_STATE)
+       if (eid == SWITCHTEC_IOCTL_EVENT_LINK_STATE ||
+           eid == SWITCHTEC_IOCTL_EVENT_MRPC_COMP)
                return 0;
 
        dev_dbg(&stdev->dev, "%s: %d %d %x\n", __func__, eid, idx, hdr);
index eba6e33147a2fd355ff5de0efa6654885b36f939..d1b16cf3403f45c0819704551ecb6d3e75b7d8ab 100644 (file)
@@ -291,8 +291,7 @@ static int pci_frontend_enable_msix(struct pci_dev *dev,
                                vector[i] = op.msix_entries[i].vector;
                        }
                } else {
-                       printk(KERN_DEBUG "enable msix get value %x\n",
-                               op.value);
+                       pr_info("enable msix get value %x\n", op.value);
                        err = op.value;
                }
        } else {
@@ -364,12 +363,12 @@ static void pci_frontend_disable_msi(struct pci_dev *dev)
        err = do_pci_op(pdev, &op);
        if (err == XEN_PCI_ERR_dev_not_found) {
                /* XXX No response from backend, what shall we do? */
-               printk(KERN_DEBUG "get no response from backend for disable MSI\n");
+               pr_info("get no response from backend for disable MSI\n");
                return;
        }
        if (err)
                /* how can pciback notify us fail? */
-               printk(KERN_DEBUG "get fake response frombackend\n");
+               pr_info("get fake response from backend\n");
 }
 
 static struct xen_pci_frontend_ops pci_frontend_ops = {
@@ -1104,7 +1103,7 @@ static void __ref pcifront_backend_changed(struct xenbus_device *xdev,
        case XenbusStateClosed:
                if (xdev->state == XenbusStateClosed)
                        break;
-               /* Missed the backend's CLOSING state -- fallthrough */
+               /* fall through - Missed the backend's CLOSING state. */
        case XenbusStateClosing:
                dev_warn(&xdev->dev, "backend going away!\n");
                pcifront_try_disconnect(pdev);
index c2a17a79f0b2ff86fa1fc5cd29a2ce49289bc669..267fb875e40f87da0d14e7ca8c6971d216d5a370 100644 (file)
@@ -22,7 +22,7 @@
 
 #include <mach/hardware.h>
 #include <asm/io.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #include <mach/mux.h>
 #include <mach/tc.h>
index 19d8af9a36a282fe9046daae152c2db84d28ab6c..ea798548b0125d20b696f2dbeac99d6ef48031fc 100644 (file)
@@ -273,6 +273,20 @@ config PINCTRL_ST
        select PINCONF
        select GPIOLIB_IRQCHIP
 
+config PINCTRL_STMFX
+       tristate "STMicroelectronics STMFX GPIO expander pinctrl driver"
+       depends on I2C
+       depends on OF || COMPILE_TEST
+       select GENERIC_PINCONF
+       select GPIOLIB_IRQCHIP
+       select MFD_STMFX
+       help
+         Driver for STMicroelectronics Multi-Function eXpander (STMFX)
+         GPIO expander.
+         This provides a GPIO interface supporting inputs and outputs,
+         and configuring push-pull, open-drain, and can also be used as
+         interrupt-controller.
+
 config PINCTRL_U300
        bool "U300 pin controller driver"
        depends on ARCH_U300
index 62df40647e023e4b72a76b494038008f221fa79f..ac537fdbc9989996a775a897db6be03db2c166ee 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_PINCTRL_LANTIQ)  += pinctrl-lantiq.o
 obj-$(CONFIG_PINCTRL_LPC18XX)  += pinctrl-lpc18xx.o
 obj-$(CONFIG_PINCTRL_TB10X)    += pinctrl-tb10x.o
 obj-$(CONFIG_PINCTRL_ST)       += pinctrl-st.o
+obj-$(CONFIG_PINCTRL_STMFX)    += pinctrl-stmfx.o
 obj-$(CONFIG_PINCTRL_ZYNQ)     += pinctrl-zynq.o
 obj-$(CONFIG_PINCTRL_INGENIC)  += pinctrl-ingenic.o
 obj-$(CONFIG_PINCTRL_RK805)    += pinctrl-rk805.o
index fd9d6f026d7000c89bdc6234a2d13e953cd1f55b..f0cdb5234e497fa9275b09b020b87542996c7d27 100644 (file)
@@ -655,115 +655,6 @@ static int mcp23s08_irqchip_setup(struct mcp23s08 *mcp)
 
 /*----------------------------------------------------------------------*/
 
-#ifdef CONFIG_DEBUG_FS
-
-#include <linux/seq_file.h>
-
-/*
- * This compares the chip's registers with the register
- * cache and corrects any incorrectly set register. This
- * can be used to fix state for MCP23xxx, that temporary
- * lost its power supply.
- */
-#define MCP23S08_CONFIG_REGS 7
-static int __check_mcp23s08_reg_cache(struct mcp23s08 *mcp)
-{
-       int cached[MCP23S08_CONFIG_REGS];
-       int err = 0, i;
-
-       /* read cached config registers */
-       for (i = 0; i < MCP23S08_CONFIG_REGS; i++) {
-               err = mcp_read(mcp, i, &cached[i]);
-               if (err)
-                       goto out;
-       }
-
-       regcache_cache_bypass(mcp->regmap, true);
-
-       for (i = 0; i < MCP23S08_CONFIG_REGS; i++) {
-               int uncached;
-               err = mcp_read(mcp, i, &uncached);
-               if (err)
-                       goto out;
-
-               if (uncached != cached[i]) {
-                       dev_err(mcp->dev, "restoring reg 0x%02x from 0x%04x to 0x%04x (power-loss?)\n",
-                               i, uncached, cached[i]);
-                       mcp_write(mcp, i, cached[i]);
-               }
-       }
-
-out:
-       if (err)
-               dev_err(mcp->dev, "read error: reg=%02x, err=%d", i, err);
-       regcache_cache_bypass(mcp->regmap, false);
-       return err;
-}
-
-/*
- * This shows more info than the generic gpio dump code:
- * pullups, deglitching, open drain drive.
- */
-static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip)
-{
-       struct mcp23s08 *mcp;
-       char            bank;
-       int             t;
-       unsigned        mask;
-       int iodir, gpio, gppu;
-
-       mcp = gpiochip_get_data(chip);
-
-       /* NOTE: we only handle one bank for now ... */
-       bank = '0' + ((mcp->addr >> 1) & 0x7);
-
-       mutex_lock(&mcp->lock);
-
-       t = __check_mcp23s08_reg_cache(mcp);
-       if (t) {
-               seq_printf(s, " I/O Error\n");
-               goto done;
-       }
-       t = mcp_read(mcp, MCP_IODIR, &iodir);
-       if (t) {
-               seq_printf(s, " I/O Error\n");
-               goto done;
-       }
-       t = mcp_read(mcp, MCP_GPIO, &gpio);
-       if (t) {
-               seq_printf(s, " I/O Error\n");
-               goto done;
-       }
-       t = mcp_read(mcp, MCP_GPPU, &gppu);
-       if (t) {
-               seq_printf(s, " I/O Error\n");
-               goto done;
-       }
-
-       for (t = 0, mask = BIT(0); t < chip->ngpio; t++, mask <<= 1) {
-               const char *label;
-
-               label = gpiochip_is_requested(chip, t);
-               if (!label)
-                       continue;
-
-               seq_printf(s, " gpio-%-3d P%c.%d (%-12s) %s %s %s\n",
-                          chip->base + t, bank, t, label,
-                          (iodir & mask) ? "in " : "out",
-                          (gpio & mask) ? "hi" : "lo",
-                          (gppu & mask) ? "up" : "  ");
-               /* NOTE:  ignoring the irq-related registers */
-       }
-done:
-       mutex_unlock(&mcp->lock);
-}
-
-#else
-#define mcp23s08_dbg_show      NULL
-#endif
-
-/*----------------------------------------------------------------------*/
-
 static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
                              void *data, unsigned addr, unsigned type,
                              unsigned int base, int cs)
@@ -784,7 +675,6 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
        mcp->chip.get = mcp23s08_get;
        mcp->chip.direction_output = mcp23s08_direction_output;
        mcp->chip.set = mcp23s08_set;
-       mcp->chip.dbg_show = mcp23s08_dbg_show;
 #ifdef CONFIG_OF_GPIO
        mcp->chip.of_gpio_n_cells = 2;
        mcp->chip.of_node = dev->of_node;
diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c
new file mode 100644 (file)
index 0000000..eba872c
--- /dev/null
@@ -0,0 +1,819 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander
+ *
+ * Copyright (C) 2019 STMicroelectronics
+ * Author(s): Amelie Delaunay <amelie.delaunay@st.com>.
+ */
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/stmfx.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "core.h"
+#include "pinctrl-utils.h"
+
+/* GPIOs expander */
+/* GPIO_STATE1 0x10, GPIO_STATE2 0x11, GPIO_STATE3 0x12 */
+#define STMFX_REG_GPIO_STATE           STMFX_REG_GPIO_STATE1 /* R */
+/* GPIO_DIR1 0x60, GPIO_DIR2 0x61, GPIO_DIR3 0x63 */
+#define STMFX_REG_GPIO_DIR             STMFX_REG_GPIO_DIR1 /* RW */
+/* GPIO_TYPE1 0x64, GPIO_TYPE2 0x65, GPIO_TYPE3 0x66 */
+#define STMFX_REG_GPIO_TYPE            STMFX_REG_GPIO_TYPE1 /* RW */
+/* GPIO_PUPD1 0x68, GPIO_PUPD2 0x69, GPIO_PUPD3 0x6A */
+#define STMFX_REG_GPIO_PUPD            STMFX_REG_GPIO_PUPD1 /* RW */
+/* GPO_SET1 0x6C, GPO_SET2 0x6D, GPO_SET3 0x6E */
+#define STMFX_REG_GPO_SET              STMFX_REG_GPO_SET1 /* RW */
+/* GPO_CLR1 0x70, GPO_CLR2 0x71, GPO_CLR3 0x72 */
+#define STMFX_REG_GPO_CLR              STMFX_REG_GPO_CLR1 /* RW */
+/* IRQ_GPI_SRC1 0x48, IRQ_GPI_SRC2 0x49, IRQ_GPI_SRC3 0x4A */
+#define STMFX_REG_IRQ_GPI_SRC          STMFX_REG_IRQ_GPI_SRC1 /* RW */
+/* IRQ_GPI_EVT1 0x4C, IRQ_GPI_EVT2 0x4D, IRQ_GPI_EVT3 0x4E */
+#define STMFX_REG_IRQ_GPI_EVT          STMFX_REG_IRQ_GPI_EVT1 /* RW */
+/* IRQ_GPI_TYPE1 0x50, IRQ_GPI_TYPE2 0x51, IRQ_GPI_TYPE3 0x52 */
+#define STMFX_REG_IRQ_GPI_TYPE         STMFX_REG_IRQ_GPI_TYPE1 /* RW */
+/* IRQ_GPI_PENDING1 0x0C, IRQ_GPI_PENDING2 0x0D, IRQ_GPI_PENDING3 0x0E*/
+#define STMFX_REG_IRQ_GPI_PENDING      STMFX_REG_IRQ_GPI_PENDING1 /* R */
+/* IRQ_GPI_ACK1 0x54, IRQ_GPI_ACK2 0x55, IRQ_GPI_ACK3 0x56 */
+#define STMFX_REG_IRQ_GPI_ACK          STMFX_REG_IRQ_GPI_ACK1 /* RW */
+
+#define NR_GPIO_REGS                   3
+#define NR_GPIOS_PER_REG               8
+#define get_reg(offset)                        ((offset) / NR_GPIOS_PER_REG)
+#define get_shift(offset)              ((offset) % NR_GPIOS_PER_REG)
+#define get_mask(offset)               (BIT(get_shift(offset)))
+
+/*
+ * STMFX pinctrl can have up to 24 pins if STMFX other functions are not used.
+ * Pins availability is managed thanks to gpio-ranges property.
+ */
+static const struct pinctrl_pin_desc stmfx_pins[] = {
+       PINCTRL_PIN(0, "gpio0"),
+       PINCTRL_PIN(1, "gpio1"),
+       PINCTRL_PIN(2, "gpio2"),
+       PINCTRL_PIN(3, "gpio3"),
+       PINCTRL_PIN(4, "gpio4"),
+       PINCTRL_PIN(5, "gpio5"),
+       PINCTRL_PIN(6, "gpio6"),
+       PINCTRL_PIN(7, "gpio7"),
+       PINCTRL_PIN(8, "gpio8"),
+       PINCTRL_PIN(9, "gpio9"),
+       PINCTRL_PIN(10, "gpio10"),
+       PINCTRL_PIN(11, "gpio11"),
+       PINCTRL_PIN(12, "gpio12"),
+       PINCTRL_PIN(13, "gpio13"),
+       PINCTRL_PIN(14, "gpio14"),
+       PINCTRL_PIN(15, "gpio15"),
+       PINCTRL_PIN(16, "agpio0"),
+       PINCTRL_PIN(17, "agpio1"),
+       PINCTRL_PIN(18, "agpio2"),
+       PINCTRL_PIN(19, "agpio3"),
+       PINCTRL_PIN(20, "agpio4"),
+       PINCTRL_PIN(21, "agpio5"),
+       PINCTRL_PIN(22, "agpio6"),
+       PINCTRL_PIN(23, "agpio7"),
+};
+
+struct stmfx_pinctrl {
+       struct device *dev;
+       struct stmfx *stmfx;
+       struct pinctrl_dev *pctl_dev;
+       struct pinctrl_desc pctl_desc;
+       struct gpio_chip gpio_chip;
+       struct irq_chip irq_chip;
+       struct mutex lock; /* IRQ bus lock */
+       unsigned long gpio_valid_mask;
+       /* Cache of IRQ_GPI_* registers for bus_lock */
+       u8 irq_gpi_src[NR_GPIO_REGS];
+       u8 irq_gpi_type[NR_GPIO_REGS];
+       u8 irq_gpi_evt[NR_GPIO_REGS];
+       u8 irq_toggle_edge[NR_GPIO_REGS];
+#ifdef CONFIG_PM
+       /* Backup of GPIO_* registers for suspend/resume */
+       u8 bkp_gpio_state[NR_GPIO_REGS];
+       u8 bkp_gpio_dir[NR_GPIO_REGS];
+       u8 bkp_gpio_type[NR_GPIO_REGS];
+       u8 bkp_gpio_pupd[NR_GPIO_REGS];
+#endif
+};
+
+static int stmfx_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+       struct stmfx_pinctrl *pctl = gpiochip_get_data(gc);
+       u32 reg = STMFX_REG_GPIO_STATE + get_reg(offset);
+       u32 mask = get_mask(offset);
+       u32 value;
+       int ret;
+
+       ret = regmap_read(pctl->stmfx->map, reg, &value);
+
+       return ret ? ret : !!(value & mask);
+}
+
+static void stmfx_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+       struct stmfx_pinctrl *pctl = gpiochip_get_data(gc);
+       u32 reg = value ? STMFX_REG_GPO_SET : STMFX_REG_GPO_CLR;
+       u32 mask = get_mask(offset);
+
+       regmap_write_bits(pctl->stmfx->map, reg + get_reg(offset),
+                         mask, mask);
+}
+
+static int stmfx_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+       struct stmfx_pinctrl *pctl = gpiochip_get_data(gc);
+       u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset);
+       u32 mask = get_mask(offset);
+       u32 val;
+       int ret;
+
+       ret = regmap_read(pctl->stmfx->map, reg, &val);
+       /*
+        * On stmfx, gpio pins direction is (0)input, (1)output.
+        * .get_direction returns 0=out, 1=in
+        */
+
+       return ret ? ret : !(val & mask);
+}
+
+static int stmfx_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
+{
+       struct stmfx_pinctrl *pctl = gpiochip_get_data(gc);
+       u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset);
+       u32 mask = get_mask(offset);
+
+       return regmap_write_bits(pctl->stmfx->map, reg, mask, 0);
+}
+
+static int stmfx_gpio_direction_output(struct gpio_chip *gc,
+                                      unsigned int offset, int value)
+{
+       struct stmfx_pinctrl *pctl = gpiochip_get_data(gc);
+       u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset);
+       u32 mask = get_mask(offset);
+
+       stmfx_gpio_set(gc, offset, value);
+
+       return regmap_write_bits(pctl->stmfx->map, reg, mask, mask);
+}
+
+static int stmfx_pinconf_get_pupd(struct stmfx_pinctrl *pctl,
+                                 unsigned int offset)
+{
+       u32 reg = STMFX_REG_GPIO_PUPD + get_reg(offset);
+       u32 pupd, mask = get_mask(offset);
+       int ret;
+
+       ret = regmap_read(pctl->stmfx->map, reg, &pupd);
+       if (ret)
+               return ret;
+
+       return !!(pupd & mask);
+}
+
+static int stmfx_pinconf_set_pupd(struct stmfx_pinctrl *pctl,
+                                 unsigned int offset, u32 pupd)
+{
+       u32 reg = STMFX_REG_GPIO_PUPD + get_reg(offset);
+       u32 mask = get_mask(offset);
+
+       return regmap_write_bits(pctl->stmfx->map, reg, mask, pupd ? mask : 0);
+}
+
+static int stmfx_pinconf_get_type(struct stmfx_pinctrl *pctl,
+                                 unsigned int offset)
+{
+       u32 reg = STMFX_REG_GPIO_TYPE + get_reg(offset);
+       u32 type, mask = get_mask(offset);
+       int ret;
+
+       ret = regmap_read(pctl->stmfx->map, reg, &type);
+       if (ret)
+               return ret;
+
+       return !!(type & mask);
+}
+
+static int stmfx_pinconf_set_type(struct stmfx_pinctrl *pctl,
+                                 unsigned int offset, u32 type)
+{
+       u32 reg = STMFX_REG_GPIO_TYPE + get_reg(offset);
+       u32 mask = get_mask(offset);
+
+       return regmap_write_bits(pctl->stmfx->map, reg, mask, type ? mask : 0);
+}
+
+static int stmfx_pinconf_get(struct pinctrl_dev *pctldev,
+                            unsigned int pin, unsigned long *config)
+{
+       struct stmfx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       u32 param = pinconf_to_config_param(*config);
+       struct pinctrl_gpio_range *range;
+       u32 arg = 0;
+       int ret, dir, type, pupd;
+
+       range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin);
+       if (!range)
+               return -EINVAL;
+
+       dir = stmfx_gpio_get_direction(&pctl->gpio_chip, pin);
+       if (dir < 0)
+               return dir;
+       type = stmfx_pinconf_get_type(pctl, pin);
+       if (type < 0)
+               return type;
+       pupd = stmfx_pinconf_get_pupd(pctl, pin);
+       if (pupd < 0)
+               return pupd;
+
+       switch (param) {
+       case PIN_CONFIG_BIAS_DISABLE:
+               if ((!dir && (!type || !pupd)) || (dir && !type))
+                       arg = 1;
+               break;
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               if (dir && type && !pupd)
+                       arg = 1;
+               break;
+       case PIN_CONFIG_BIAS_PULL_UP:
+               if (type && pupd)
+                       arg = 1;
+               break;
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+               if ((!dir && type) || (dir && !type))
+                       arg = 1;
+               break;
+       case PIN_CONFIG_DRIVE_PUSH_PULL:
+               if ((!dir && !type) || (dir && type))
+                       arg = 1;
+               break;
+       case PIN_CONFIG_OUTPUT:
+               if (dir)
+                       return -EINVAL;
+
+               ret = stmfx_gpio_get(&pctl->gpio_chip, pin);
+               if (ret < 0)
+                       return ret;
+
+               arg = ret;
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       *config = pinconf_to_config_packed(param, arg);
+
+       return 0;
+}
+
+static int stmfx_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+                            unsigned long *configs, unsigned int num_configs)
+{
+       struct stmfx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct pinctrl_gpio_range *range;
+       enum pin_config_param param;
+       u32 arg;
+       int dir, i, ret;
+
+       range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin);
+       if (!range) {
+               dev_err(pctldev->dev, "pin %d is not available\n", pin);
+               return -EINVAL;
+       }
+
+       dir = stmfx_gpio_get_direction(&pctl->gpio_chip, pin);
+       if (dir < 0)
+               return dir;
+
+       for (i = 0; i < num_configs; i++) {
+               param = pinconf_to_config_param(configs[i]);
+               arg = pinconf_to_config_argument(configs[i]);
+
+               switch (param) {
+               case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+               case PIN_CONFIG_BIAS_DISABLE:
+               case PIN_CONFIG_BIAS_PULL_DOWN:
+                       ret = stmfx_pinconf_set_pupd(pctl, pin, 0);
+                       if (ret)
+                               return ret;
+                       break;
+               case PIN_CONFIG_BIAS_PULL_UP:
+                       ret = stmfx_pinconf_set_pupd(pctl, pin, 1);
+                       if (ret)
+                               return ret;
+                       break;
+               case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+                       if (!dir)
+                               ret = stmfx_pinconf_set_type(pctl, pin, 1);
+                       else
+                               ret = stmfx_pinconf_set_type(pctl, pin, 0);
+                       if (ret)
+                               return ret;
+                       break;
+               case PIN_CONFIG_DRIVE_PUSH_PULL:
+                       if (!dir)
+                               ret = stmfx_pinconf_set_type(pctl, pin, 0);
+                       else
+                               ret = stmfx_pinconf_set_type(pctl, pin, 1);
+                       if (ret)
+                               return ret;
+                       break;
+               case PIN_CONFIG_OUTPUT:
+                       ret = stmfx_gpio_direction_output(&pctl->gpio_chip,
+                                                         pin, arg);
+                       if (ret)
+                               return ret;
+                       break;
+               default:
+                       return -ENOTSUPP;
+               }
+       }
+
+       return 0;
+}
+
+static void stmfx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+                                  struct seq_file *s, unsigned int offset)
+{
+       struct stmfx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       struct pinctrl_gpio_range *range;
+       int dir, type, pupd, val;
+
+       range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, offset);
+       if (!range)
+               return;
+
+       dir = stmfx_gpio_get_direction(&pctl->gpio_chip, offset);
+       if (dir < 0)
+               return;
+       type = stmfx_pinconf_get_type(pctl, offset);
+       if (type < 0)
+               return;
+       pupd = stmfx_pinconf_get_pupd(pctl, offset);
+       if (pupd < 0)
+               return;
+       val = stmfx_gpio_get(&pctl->gpio_chip, offset);
+       if (val < 0)
+               return;
+
+       if (!dir) {
+               seq_printf(s, "output %s ", val ? "high" : "low");
+               if (type)
+                       seq_printf(s, "open drain %s internal pull-up ",
+                                  pupd ? "with" : "without");
+               else
+                       seq_puts(s, "push pull no pull ");
+       } else {
+               seq_printf(s, "input %s ", val ? "high" : "low");
+               if (type)
+                       seq_printf(s, "with internal pull-%s ",
+                                  pupd ? "up" : "down");
+               else
+                       seq_printf(s, "%s ", pupd ? "floating" : "analog");
+       }
+}
+
+static const struct pinconf_ops stmfx_pinconf_ops = {
+       .pin_config_get         = stmfx_pinconf_get,
+       .pin_config_set         = stmfx_pinconf_set,
+       .pin_config_dbg_show    = stmfx_pinconf_dbg_show,
+};
+
+static int stmfx_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       return 0;
+}
+
+static const char *stmfx_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+                                               unsigned int selector)
+{
+       return NULL;
+}
+
+static int stmfx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+                                       unsigned int selector,
+                                       const unsigned int **pins,
+                                       unsigned int *num_pins)
+{
+       return -ENOTSUPP;
+}
+
+static const struct pinctrl_ops stmfx_pinctrl_ops = {
+       .get_groups_count = stmfx_pinctrl_get_groups_count,
+       .get_group_name = stmfx_pinctrl_get_group_name,
+       .get_group_pins = stmfx_pinctrl_get_group_pins,
+       .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+       .dt_free_map = pinctrl_utils_free_map,
+};
+
+static void stmfx_pinctrl_irq_mask(struct irq_data *data)
+{
+       struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
+       struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip);
+       u32 reg = get_reg(data->hwirq);
+       u32 mask = get_mask(data->hwirq);
+
+       pctl->irq_gpi_src[reg] &= ~mask;
+}
+
+static void stmfx_pinctrl_irq_unmask(struct irq_data *data)
+{
+       struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
+       struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip);
+       u32 reg = get_reg(data->hwirq);
+       u32 mask = get_mask(data->hwirq);
+
+       pctl->irq_gpi_src[reg] |= mask;
+}
+
+static int stmfx_pinctrl_irq_set_type(struct irq_data *data, unsigned int type)
+{
+       struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
+       struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip);
+       u32 reg = get_reg(data->hwirq);
+       u32 mask = get_mask(data->hwirq);
+
+       if (type == IRQ_TYPE_NONE)
+               return -EINVAL;
+
+       if (type & IRQ_TYPE_EDGE_BOTH) {
+               pctl->irq_gpi_evt[reg] |= mask;
+               irq_set_handler_locked(data, handle_edge_irq);
+       } else {
+               pctl->irq_gpi_evt[reg] &= ~mask;
+               irq_set_handler_locked(data, handle_level_irq);
+       }
+
+       if ((type & IRQ_TYPE_EDGE_RISING) || (type & IRQ_TYPE_LEVEL_HIGH))
+               pctl->irq_gpi_type[reg] |= mask;
+       else
+               pctl->irq_gpi_type[reg] &= ~mask;
+
+       /*
+        * In case of (type & IRQ_TYPE_EDGE_BOTH), we need to know current
+        * GPIO value to set the right edge trigger. But in atomic context
+        * here we can't access registers over I2C. That's why (type &
+        * IRQ_TYPE_EDGE_BOTH) will be managed in .irq_sync_unlock.
+        */
+
+       if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+               pctl->irq_toggle_edge[reg] |= mask;
+       else
+               pctl->irq_toggle_edge[reg] &= mask;
+
+       return 0;
+}
+
+static void stmfx_pinctrl_irq_bus_lock(struct irq_data *data)
+{
+       struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
+       struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip);
+
+       mutex_lock(&pctl->lock);
+}
+
+static void stmfx_pinctrl_irq_bus_sync_unlock(struct irq_data *data)
+{
+       struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
+       struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip);
+       u32 reg = get_reg(data->hwirq);
+       u32 mask = get_mask(data->hwirq);
+
+       /*
+        * In case of IRQ_TYPE_EDGE_BOTH), read the current GPIO value
+        * (this couldn't be done in .irq_set_type because of atomic context)
+        * to set the right irq trigger type.
+        */
+       if (pctl->irq_toggle_edge[reg] & mask) {
+               if (stmfx_gpio_get(gpio_chip, data->hwirq))
+                       pctl->irq_gpi_type[reg] &= ~mask;
+               else
+                       pctl->irq_gpi_type[reg] |= mask;
+       }
+
+       regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_EVT,
+                         pctl->irq_gpi_evt, NR_GPIO_REGS);
+       regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_TYPE,
+                         pctl->irq_gpi_type, NR_GPIO_REGS);
+       regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC,
+                         pctl->irq_gpi_src, NR_GPIO_REGS);
+
+       mutex_unlock(&pctl->lock);
+}
+
+static void stmfx_pinctrl_irq_toggle_trigger(struct stmfx_pinctrl *pctl,
+                                            unsigned int offset)
+{
+       u32 reg = get_reg(offset);
+       u32 mask = get_mask(offset);
+       int val;
+
+       if (!(pctl->irq_toggle_edge[reg] & mask))
+               return;
+
+       val = stmfx_gpio_get(&pctl->gpio_chip, offset);
+       if (val < 0)
+               return;
+
+       if (val) {
+               pctl->irq_gpi_type[reg] &= mask;
+               regmap_write_bits(pctl->stmfx->map,
+                                 STMFX_REG_IRQ_GPI_TYPE + reg,
+                                 mask, 0);
+
+       } else {
+               pctl->irq_gpi_type[reg] |= mask;
+               regmap_write_bits(pctl->stmfx->map,
+                                 STMFX_REG_IRQ_GPI_TYPE + reg,
+                                 mask, mask);
+       }
+}
+
+static irqreturn_t stmfx_pinctrl_irq_thread_fn(int irq, void *dev_id)
+{
+       struct stmfx_pinctrl *pctl = (struct stmfx_pinctrl *)dev_id;
+       struct gpio_chip *gc = &pctl->gpio_chip;
+       u8 pending[NR_GPIO_REGS];
+       u8 src[NR_GPIO_REGS] = {0, 0, 0};
+       unsigned long n, status;
+       int ret;
+
+       ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_IRQ_GPI_PENDING,
+                              &pending, NR_GPIO_REGS);
+       if (ret)
+               return IRQ_NONE;
+
+       regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC,
+                         src, NR_GPIO_REGS);
+
+       status = *(unsigned long *)pending;
+       for_each_set_bit(n, &status, gc->ngpio) {
+               handle_nested_irq(irq_find_mapping(gc->irq.domain, n));
+               stmfx_pinctrl_irq_toggle_trigger(pctl, n);
+       }
+
+       regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC,
+                         pctl->irq_gpi_src, NR_GPIO_REGS);
+
+       return IRQ_HANDLED;
+}
+
+static int stmfx_pinctrl_gpio_function_enable(struct stmfx_pinctrl *pctl)
+{
+       struct pinctrl_gpio_range *gpio_range;
+       struct pinctrl_dev *pctl_dev = pctl->pctl_dev;
+       u32 func = STMFX_FUNC_GPIO;
+
+       pctl->gpio_valid_mask = GENMASK(15, 0);
+
+       gpio_range = pinctrl_find_gpio_range_from_pin(pctl_dev, 16);
+       if (gpio_range) {
+               func |= STMFX_FUNC_ALTGPIO_LOW;
+               pctl->gpio_valid_mask |= GENMASK(19, 16);
+       }
+
+       gpio_range = pinctrl_find_gpio_range_from_pin(pctl_dev, 20);
+       if (gpio_range) {
+               func |= STMFX_FUNC_ALTGPIO_HIGH;
+               pctl->gpio_valid_mask |= GENMASK(23, 20);
+       }
+
+       return stmfx_function_enable(pctl->stmfx, func);
+}
+
+static int stmfx_pinctrl_probe(struct platform_device *pdev)
+{
+       struct stmfx *stmfx = dev_get_drvdata(pdev->dev.parent);
+       struct device_node *np = pdev->dev.of_node;
+       struct stmfx_pinctrl *pctl;
+       u32 n;
+       int irq, ret;
+
+       pctl = devm_kzalloc(stmfx->dev, sizeof(*pctl), GFP_KERNEL);
+       if (!pctl)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, pctl);
+
+       pctl->dev = &pdev->dev;
+       pctl->stmfx = stmfx;
+
+       if (!of_find_property(np, "gpio-ranges", NULL)) {
+               dev_err(pctl->dev, "missing required gpio-ranges property\n");
+               return -EINVAL;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(pctl->dev, "failed to get irq\n");
+               return -ENXIO;
+       }
+
+       mutex_init(&pctl->lock);
+
+       /* Register pin controller */
+       pctl->pctl_desc.name = "stmfx-pinctrl";
+       pctl->pctl_desc.pctlops = &stmfx_pinctrl_ops;
+       pctl->pctl_desc.confops = &stmfx_pinconf_ops;
+       pctl->pctl_desc.pins = stmfx_pins;
+       pctl->pctl_desc.npins = ARRAY_SIZE(stmfx_pins);
+       pctl->pctl_desc.owner = THIS_MODULE;
+
+       ret = devm_pinctrl_register_and_init(pctl->dev, &pctl->pctl_desc,
+                                            pctl, &pctl->pctl_dev);
+       if (ret) {
+               dev_err(pctl->dev, "pinctrl registration failed\n");
+               return ret;
+       }
+
+       ret = pinctrl_enable(pctl->pctl_dev);
+       if (ret) {
+               dev_err(pctl->dev, "pinctrl enable failed\n");
+               return ret;
+       }
+
+       /* Register gpio controller */
+       pctl->gpio_chip.label = "stmfx-gpio";
+       pctl->gpio_chip.parent = pctl->dev;
+       pctl->gpio_chip.get_direction = stmfx_gpio_get_direction;
+       pctl->gpio_chip.direction_input = stmfx_gpio_direction_input;
+       pctl->gpio_chip.direction_output = stmfx_gpio_direction_output;
+       pctl->gpio_chip.get = stmfx_gpio_get;
+       pctl->gpio_chip.set = stmfx_gpio_set;
+       pctl->gpio_chip.set_config = gpiochip_generic_config;
+       pctl->gpio_chip.base = -1;
+       pctl->gpio_chip.ngpio = pctl->pctl_desc.npins;
+       pctl->gpio_chip.can_sleep = true;
+       pctl->gpio_chip.of_node = np;
+       pctl->gpio_chip.need_valid_mask = true;
+
+       ret = devm_gpiochip_add_data(pctl->dev, &pctl->gpio_chip, pctl);
+       if (ret) {
+               dev_err(pctl->dev, "gpio_chip registration failed\n");
+               return ret;
+       }
+
+       ret = stmfx_pinctrl_gpio_function_enable(pctl);
+       if (ret)
+               return ret;
+
+       pctl->irq_chip.name = dev_name(pctl->dev);
+       pctl->irq_chip.irq_mask = stmfx_pinctrl_irq_mask;
+       pctl->irq_chip.irq_unmask = stmfx_pinctrl_irq_unmask;
+       pctl->irq_chip.irq_set_type = stmfx_pinctrl_irq_set_type;
+       pctl->irq_chip.irq_bus_lock = stmfx_pinctrl_irq_bus_lock;
+       pctl->irq_chip.irq_bus_sync_unlock = stmfx_pinctrl_irq_bus_sync_unlock;
+       for_each_clear_bit(n, &pctl->gpio_valid_mask, pctl->gpio_chip.ngpio)
+               clear_bit(n, pctl->gpio_chip.valid_mask);
+
+       ret = gpiochip_irqchip_add_nested(&pctl->gpio_chip, &pctl->irq_chip,
+                                         0, handle_bad_irq, IRQ_TYPE_NONE);
+       if (ret) {
+               dev_err(pctl->dev, "cannot add irqchip to gpiochip\n");
+               return ret;
+       }
+
+       ret = devm_request_threaded_irq(pctl->dev, irq, NULL,
+                                       stmfx_pinctrl_irq_thread_fn,
+                                       IRQF_ONESHOT,
+                                       pctl->irq_chip.name, pctl);
+       if (ret) {
+               dev_err(pctl->dev, "cannot request irq%d\n", irq);
+               return ret;
+       }
+
+       gpiochip_set_nested_irqchip(&pctl->gpio_chip, &pctl->irq_chip, irq);
+
+       dev_info(pctl->dev,
+                "%ld GPIOs available\n", hweight_long(pctl->gpio_valid_mask));
+
+       return 0;
+}
+
+static int stmfx_pinctrl_remove(struct platform_device *pdev)
+{
+       struct stmfx *stmfx = dev_get_platdata(&pdev->dev);
+
+       return stmfx_function_disable(stmfx,
+                                     STMFX_FUNC_GPIO |
+                                     STMFX_FUNC_ALTGPIO_LOW |
+                                     STMFX_FUNC_ALTGPIO_HIGH);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stmfx_pinctrl_backup_regs(struct stmfx_pinctrl *pctl)
+{
+       int ret;
+
+       ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_STATE,
+                              &pctl->bkp_gpio_state, NR_GPIO_REGS);
+       if (ret)
+               return ret;
+       ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_DIR,
+                              &pctl->bkp_gpio_dir, NR_GPIO_REGS);
+       if (ret)
+               return ret;
+       ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_TYPE,
+                              &pctl->bkp_gpio_type, NR_GPIO_REGS);
+       if (ret)
+               return ret;
+       ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_PUPD,
+                              &pctl->bkp_gpio_pupd, NR_GPIO_REGS);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int stmfx_pinctrl_restore_regs(struct stmfx_pinctrl *pctl)
+{
+       int ret;
+
+       ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPIO_DIR,
+                               pctl->bkp_gpio_dir, NR_GPIO_REGS);
+       if (ret)
+               return ret;
+       ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPIO_TYPE,
+                               pctl->bkp_gpio_type, NR_GPIO_REGS);
+       if (ret)
+               return ret;
+       ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPIO_PUPD,
+                               pctl->bkp_gpio_pupd, NR_GPIO_REGS);
+       if (ret)
+               return ret;
+       ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPO_SET,
+                               pctl->bkp_gpio_state, NR_GPIO_REGS);
+       if (ret)
+               return ret;
+       ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_EVT,
+                               pctl->irq_gpi_evt, NR_GPIO_REGS);
+       if (ret)
+               return ret;
+       ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_TYPE,
+                               pctl->irq_gpi_type, NR_GPIO_REGS);
+       if (ret)
+               return ret;
+       ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC,
+                               pctl->irq_gpi_src, NR_GPIO_REGS);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int stmfx_pinctrl_suspend(struct device *dev)
+{
+       struct stmfx_pinctrl *pctl = dev_get_drvdata(dev);
+       int ret;
+
+       ret = stmfx_pinctrl_backup_regs(pctl);
+       if (ret) {
+               dev_err(pctl->dev, "registers backup failure\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int stmfx_pinctrl_resume(struct device *dev)
+{
+       struct stmfx_pinctrl *pctl = dev_get_drvdata(dev);
+       int ret;
+
+       ret = stmfx_pinctrl_restore_regs(pctl);
+       if (ret) {
+               dev_err(pctl->dev, "registers restoration failure\n");
+               return ret;
+       }
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(stmfx_pinctrl_dev_pm_ops,
+                        stmfx_pinctrl_suspend, stmfx_pinctrl_resume);
+
+static const struct of_device_id stmfx_pinctrl_of_match[] = {
+       { .compatible = "st,stmfx-0300-pinctrl", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, stmfx_pinctrl_of_match);
+
+static struct platform_driver stmfx_pinctrl_driver = {
+       .driver = {
+               .name = "stmfx-pinctrl",
+               .of_match_table = stmfx_pinctrl_of_match,
+               .pm = &stmfx_pinctrl_dev_pm_ops,
+       },
+       .probe = stmfx_pinctrl_probe,
+       .remove = stmfx_pinctrl_remove,
+};
+module_platform_driver(stmfx_pinctrl_driver);
+
+MODULE_DESCRIPTION("STMFX pinctrl/GPIO driver");
+MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
+MODULE_LICENSE("GPL v2");
index 9186d81a51cc1347b0c733a5caa2622088d10ccf..997317d2f2b9daae50c3b30de16baaca85fd7bb0 100644 (file)
@@ -59,6 +59,18 @@ config CROS_EC_I2C
          a checksum. Failing accesses will be retried three times to
          improve reliability.
 
+config CROS_EC_RPMSG
+       tristate "ChromeOS Embedded Controller (rpmsg)"
+       depends on MFD_CROS_EC && RPMSG && OF
+       help
+         If you say Y here, you get support for talking to the ChromeOS EC
+         through rpmsg. This uses a simple byte-level protocol with a
+         checksum. Also since there's no addition EC-to-host interrupt, this
+         use a byte in message to distinguish host event from host command.
+
+         To compile this driver as a module, choose M here: the
+         module will be called cros_ec_rpmsg.
+
 config CROS_EC_SPI
        tristate "ChromeOS Embedded Controller (SPI)"
        depends on MFD_CROS_EC && SPI
@@ -152,6 +164,18 @@ config CROS_EC_SYSFS
          To compile this driver as a module, choose M here: the
          module will be called cros_ec_sysfs.
 
+config CROS_USBPD_LOGGER
+       tristate "Logging driver for USB PD charger"
+       depends on CHARGER_CROS_USBPD
+       default y
+       select RTC_LIB
+       help
+         This option enables support for logging event data for the USB PD charger
+         available in the Embedded Controller on ChromeOS systems.
+
+         To compile this driver as a module, choose M here: the
+         module will be called cros_usbpd_logger.
+
 source "drivers/platform/chrome/wilco_ec/Kconfig"
 
 endif # CHROMEOS_PLATFORMS
index 1e2f0029b5971f2a045814e9b5193eba3e25938e..1b2f1dcfcd5cc54a624dea7697a7aaf3f63ba887 100644 (file)
@@ -1,18 +1,23 @@
 # SPDX-License-Identifier: GPL-2.0
 
+# tell define_trace.h where to find the cros ec trace header
+CFLAGS_cros_ec_trace.o:=               -I$(src)
+
 obj-$(CONFIG_CHROMEOS_LAPTOP)          += chromeos_laptop.o
 obj-$(CONFIG_CHROMEOS_PSTORE)          += chromeos_pstore.o
 obj-$(CONFIG_CHROMEOS_TBMC)            += chromeos_tbmc.o
 obj-$(CONFIG_CROS_EC_I2C)              += cros_ec_i2c.o
+obj-$(CONFIG_CROS_EC_RPMSG)            += cros_ec_rpmsg.o
 obj-$(CONFIG_CROS_EC_SPI)              += cros_ec_spi.o
 cros_ec_lpcs-objs                      := cros_ec_lpc.o cros_ec_lpc_reg.o
 cros_ec_lpcs-$(CONFIG_CROS_EC_LPC_MEC) += cros_ec_lpc_mec.o
 obj-$(CONFIG_CROS_EC_LPC)              += cros_ec_lpcs.o
-obj-$(CONFIG_CROS_EC_PROTO)            += cros_ec_proto.o
+obj-$(CONFIG_CROS_EC_PROTO)            += cros_ec_proto.o cros_ec_trace.o
 obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT)   += cros_kbd_led_backlight.o
 obj-$(CONFIG_CROS_EC_LIGHTBAR)         += cros_ec_lightbar.o
 obj-$(CONFIG_CROS_EC_VBC)              += cros_ec_vbc.o
 obj-$(CONFIG_CROS_EC_DEBUGFS)          += cros_ec_debugfs.o
 obj-$(CONFIG_CROS_EC_SYSFS)            += cros_ec_sysfs.o
+obj-$(CONFIG_CROS_USBPD_LOGGER)                += cros_usbpd_logger.o
 
 obj-$(CONFIG_WILCO_EC)                 += wilco_ec/
index 24326eecd7876ab0f62008e44cf47f5e74e283ec..7abbb6167766eec972cbaee3f22e38ba8646ce9a 100644 (file)
@@ -125,7 +125,7 @@ static bool chromeos_laptop_match_adapter_devid(struct device *dev, u32 devid)
                return false;
 
        pdev = to_pci_dev(dev);
-       return devid == PCI_DEVID(pdev->bus->number, pdev->devfn);
+       return devid == pci_dev_id(pdev);
 }
 
 static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter)
index 2b8e8a01a739a28829dd20d2184c737105c7e345..4c2a27f6a6d09c5886e5e9dbe9b747f6204b61cd 100644 (file)
@@ -72,15 +72,9 @@ static void cros_ec_console_log_work(struct work_struct *__work)
        int buf_space;
        int ret;
 
-       ret = cros_ec_cmd_xfer(ec->ec_dev, &snapshot_msg);
-       if (ret < 0) {
-               dev_err(ec->dev, "EC communication failed\n");
-               goto resched;
-       }
-       if (snapshot_msg.result != EC_RES_SUCCESS) {
-               dev_err(ec->dev, "EC failed to snapshot the console log\n");
+       ret = cros_ec_cmd_xfer_status(ec->ec_dev, &snapshot_msg);
+       if (ret < 0)
                goto resched;
-       }
 
        /* Loop until we have read everything, or there's an error. */
        mutex_lock(&debug_info->log_mutex);
@@ -95,16 +89,10 @@ static void cros_ec_console_log_work(struct work_struct *__work)
 
                memset(read_params, '\0', sizeof(*read_params));
                read_params->subcmd = CONSOLE_READ_RECENT;
-               ret = cros_ec_cmd_xfer(ec->ec_dev, debug_info->read_msg);
-               if (ret < 0) {
-                       dev_err(ec->dev, "EC communication failed\n");
-                       break;
-               }
-               if (debug_info->read_msg->result != EC_RES_SUCCESS) {
-                       dev_err(ec->dev,
-                               "EC failed to read the console log\n");
+               ret = cros_ec_cmd_xfer_status(ec->ec_dev,
+                                             debug_info->read_msg);
+               if (ret < 0)
                        break;
-               }
 
                /* If the buffer is empty, we're done here. */
                if (ret == 0 || ec_buffer[0] == '\0')
@@ -290,9 +278,8 @@ static int ec_read_version_supported(struct cros_ec_dev *ec)
        params->cmd = EC_CMD_CONSOLE_READ;
        response = (struct ec_response_get_cmd_versions *)msg->data;
 
-       ret = cros_ec_cmd_xfer(ec->ec_dev, msg) >= 0 &&
-               msg->result == EC_RES_SUCCESS &&
-               (response->version_mask & EC_VER_MASK(1));
+       ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg) >= 0 &&
+             response->version_mask & EC_VER_MASK(1);
 
        kfree(msg);
 
@@ -306,11 +293,12 @@ static int cros_ec_create_console_log(struct cros_ec_debugfs *debug_info)
        int read_params_size;
        int read_response_size;
 
-       if (!ec_read_version_supported(ec)) {
-               dev_warn(ec->dev,
-                       "device does not support reading the console log\n");
+       /*
+        * If the console log feature is not supported return silently and
+        * don't create the console_log entry.
+        */
+       if (!ec_read_version_supported(ec))
                return 0;
-       }
 
        buf = devm_kzalloc(ec->dev, LOG_SIZE, GFP_KERNEL);
        if (!buf)
@@ -336,12 +324,8 @@ static int cros_ec_create_console_log(struct cros_ec_debugfs *debug_info)
        mutex_init(&debug_info->log_mutex);
        init_waitqueue_head(&debug_info->log_wq);
 
-       if (!debugfs_create_file("console_log",
-                                S_IFREG | 0444,
-                                debug_info->dir,
-                                debug_info,
-                                &cros_ec_console_log_fops))
-               return -ENOMEM;
+       debugfs_create_file("console_log", S_IFREG | 0444, debug_info->dir,
+                           debug_info, &cros_ec_console_log_fops);
 
        INIT_DELAYED_WORK(&debug_info->log_poll_work,
                          cros_ec_console_log_work);
@@ -375,9 +359,8 @@ static int cros_ec_create_panicinfo(struct cros_ec_debugfs *debug_info)
        msg->command = EC_CMD_GET_PANIC_INFO;
        msg->insize = insize;
 
-       ret = cros_ec_cmd_xfer(ec_dev, msg);
+       ret = cros_ec_cmd_xfer_status(ec_dev, msg);
        if (ret < 0) {
-               dev_warn(debug_info->ec->dev, "Cannot read panicinfo.\n");
                ret = 0;
                goto free;
        }
@@ -389,13 +372,8 @@ static int cros_ec_create_panicinfo(struct cros_ec_debugfs *debug_info)
        debug_info->panicinfo_blob.data = msg->data;
        debug_info->panicinfo_blob.size = ret;
 
-       if (!debugfs_create_blob("panicinfo",
-                                S_IFREG | 0444,
-                                debug_info->dir,
-                                &debug_info->panicinfo_blob)) {
-               ret = -ENOMEM;
-               goto free;
-       }
+       debugfs_create_blob("panicinfo", S_IFREG | 0444, debug_info->dir,
+                           &debug_info->panicinfo_blob);
 
        return 0;
 
@@ -404,15 +382,6 @@ free:
        return ret;
 }
 
-static int cros_ec_create_pdinfo(struct cros_ec_debugfs *debug_info)
-{
-       if (!debugfs_create_file("pdinfo", 0444, debug_info->dir, debug_info,
-                                &cros_ec_pdinfo_fops))
-               return -ENOMEM;
-
-       return 0;
-}
-
 static int cros_ec_debugfs_probe(struct platform_device *pd)
 {
        struct cros_ec_dev *ec = dev_get_drvdata(pd->dev.parent);
@@ -427,8 +396,6 @@ static int cros_ec_debugfs_probe(struct platform_device *pd)
 
        debug_info->ec = ec;
        debug_info->dir = debugfs_create_dir(name, NULL);
-       if (!debug_info->dir)
-               return -ENOMEM;
 
        ret = cros_ec_create_panicinfo(debug_info);
        if (ret)
@@ -438,9 +405,8 @@ static int cros_ec_debugfs_probe(struct platform_device *pd)
        if (ret)
                goto remove_debugfs;
 
-       ret = cros_ec_create_pdinfo(debug_info);
-       if (ret)
-               goto remove_log;
+       debugfs_create_file("pdinfo", 0444, debug_info->dir, debug_info,
+                           &cros_ec_pdinfo_fops);
 
        ec->debug_info = debug_info;
 
@@ -448,8 +414,6 @@ static int cros_ec_debugfs_probe(struct platform_device *pd)
 
        return 0;
 
-remove_log:
-       cros_ec_cleanup_console_log(debug_info);
 remove_debugfs:
        debugfs_remove_recursive(debug_info->dir);
        return ret;
index 97a068dff192d41541b60ad8a2e951acb42da4e8..3d2325197a68b889022fd0bcb9fab2c262abe3d8 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/slab.h>
 #include <asm/unaligned.h>
 
+#include "cros_ec_trace.h"
+
 #define EC_COMMAND_RETRIES     50
 
 static int prepare_packet(struct cros_ec_device *ec_dev,
@@ -51,11 +53,24 @@ static int send_command(struct cros_ec_device *ec_dev,
        int ret;
        int (*xfer_fxn)(struct cros_ec_device *ec, struct cros_ec_command *msg);
 
+       trace_cros_ec_cmd(msg);
+
        if (ec_dev->proto_version > 2)
                xfer_fxn = ec_dev->pkt_xfer;
        else
                xfer_fxn = ec_dev->cmd_xfer;
 
+       if (!xfer_fxn) {
+               /*
+                * This error can happen if a communication error happened and
+                * the EC is trying to use protocol v2, on an underlying
+                * communication mechanism that does not support v2.
+                */
+               dev_err_once(ec_dev->dev,
+                            "missing EC transfer API, cannot send command\n");
+               return -EIO;
+       }
+
        ret = (*xfer_fxn)(ec_dev, msg);
        if (msg->result == EC_RES_IN_PROGRESS) {
                int i;
@@ -414,6 +429,12 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
        else
                ec_dev->mkbp_event_supported = 1;
 
+       /* Probe if host sleep v1 is supported for S0ix failure detection. */
+       ret = cros_ec_get_host_command_version_mask(ec_dev,
+                                                   EC_CMD_HOST_SLEEP_EVENT,
+                                                   &ver_mask);
+       ec_dev->host_sleep_v1 = (ret >= 0 && (ver_mask & EC_VER_MASK(1)));
+
        /*
         * Get host event wake mask, assume all events are wake events
         * if unavailable.
diff --git a/drivers/platform/chrome/cros_ec_rpmsg.c b/drivers/platform/chrome/cros_ec_rpmsg.c
new file mode 100644 (file)
index 0000000..5d3fb2a
--- /dev/null
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright 2018 Google LLC.
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/rpmsg.h>
+#include <linux/slab.h>
+
+#define EC_MSG_TIMEOUT_MS      200
+#define HOST_COMMAND_MARK      1
+#define HOST_EVENT_MARK                2
+
+/**
+ * struct cros_ec_rpmsg_response - rpmsg message format from from EC.
+ *
+ * @type:      The type of message, should be either HOST_COMMAND_MARK or
+ *             HOST_EVENT_MARK, representing that the message is a response to
+ *             host command, or a host event.
+ * @data:      ec_host_response for host command.
+ */
+struct cros_ec_rpmsg_response {
+       u8 type;
+       u8 data[] __aligned(4);
+};
+
+/**
+ * struct cros_ec_rpmsg - information about a EC over rpmsg.
+ *
+ * @rpdev:     rpmsg device we are connected to
+ * @xfer_ack:  completion for host command transfer.
+ * @host_event_work:   Work struct for pending host event.
+ */
+struct cros_ec_rpmsg {
+       struct rpmsg_device *rpdev;
+       struct completion xfer_ack;
+       struct work_struct host_event_work;
+};
+
+/**
+ * cros_ec_cmd_xfer_rpmsg - Transfer a message over rpmsg and receive the reply
+ *
+ * @ec_dev: ChromeOS EC device
+ * @ec_msg: Message to transfer
+ *
+ * This is only used for old EC proto version, and is not supported for this
+ * driver.
+ *
+ * Return: -EINVAL
+ */
+static int cros_ec_cmd_xfer_rpmsg(struct cros_ec_device *ec_dev,
+                                 struct cros_ec_command *ec_msg)
+{
+       return -EINVAL;
+}
+
+/**
+ * cros_ec_pkt_xfer_rpmsg - Transfer a packet over rpmsg and receive the reply
+ *
+ * @ec_dev: ChromeOS EC device
+ * @ec_msg: Message to transfer
+ *
+ * Return: number of bytes of the reply on success or negative error code.
+ */
+static int cros_ec_pkt_xfer_rpmsg(struct cros_ec_device *ec_dev,
+                                 struct cros_ec_command *ec_msg)
+{
+       struct cros_ec_rpmsg *ec_rpmsg = ec_dev->priv;
+       struct rpmsg_device *rpdev = ec_rpmsg->rpdev;
+       struct ec_host_response *response;
+       unsigned long timeout;
+       int len;
+       int ret;
+       u8 sum;
+       int i;
+
+       ec_msg->result = 0;
+       len = cros_ec_prepare_tx(ec_dev, ec_msg);
+       dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
+
+       reinit_completion(&ec_rpmsg->xfer_ack);
+       ret = rpmsg_send(rpdev->ept, ec_dev->dout, len);
+       if (ret) {
+               dev_err(ec_dev->dev, "rpmsg send failed\n");
+               return ret;
+       }
+
+       timeout = msecs_to_jiffies(EC_MSG_TIMEOUT_MS);
+       ret = wait_for_completion_timeout(&ec_rpmsg->xfer_ack, timeout);
+       if (!ret) {
+               dev_err(ec_dev->dev, "rpmsg send timeout\n");
+               return -EIO;
+       }
+
+       /* check response error code */
+       response = (struct ec_host_response *)ec_dev->din;
+       ec_msg->result = response->result;
+
+       ret = cros_ec_check_result(ec_dev, ec_msg);
+       if (ret)
+               goto exit;
+
+       if (response->data_len > ec_msg->insize) {
+               dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)",
+                       response->data_len, ec_msg->insize);
+               ret = -EMSGSIZE;
+               goto exit;
+       }
+
+       /* copy response packet payload and compute checksum */
+       memcpy(ec_msg->data, ec_dev->din + sizeof(*response),
+              response->data_len);
+
+       sum = 0;
+       for (i = 0; i < sizeof(*response) + response->data_len; i++)
+               sum += ec_dev->din[i];
+
+       if (sum) {
+               dev_err(ec_dev->dev, "bad packet checksum, calculated %x\n",
+                       sum);
+               ret = -EBADMSG;
+               goto exit;
+       }
+
+       ret = response->data_len;
+exit:
+       if (ec_msg->command == EC_CMD_REBOOT_EC)
+               msleep(EC_REBOOT_DELAY_MS);
+
+       return ret;
+}
+
+static void
+cros_ec_rpmsg_host_event_function(struct work_struct *host_event_work)
+{
+       struct cros_ec_rpmsg *ec_rpmsg = container_of(host_event_work,
+                                                     struct cros_ec_rpmsg,
+                                                     host_event_work);
+       struct cros_ec_device *ec_dev = dev_get_drvdata(&ec_rpmsg->rpdev->dev);
+       bool wake_event = true;
+       int ret;
+
+       ret = cros_ec_get_next_event(ec_dev, &wake_event);
+
+       /*
+        * Signal only if wake host events or any interrupt if
+        * cros_ec_get_next_event() returned an error (default value for
+        * wake_event is true)
+        */
+       if (wake_event && device_may_wakeup(ec_dev->dev))
+               pm_wakeup_event(ec_dev->dev, 0);
+
+       if (ret > 0)
+               blocking_notifier_call_chain(&ec_dev->event_notifier,
+                                            0, ec_dev);
+}
+
+static int cros_ec_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
+                                 int len, void *priv, u32 src)
+{
+       struct cros_ec_device *ec_dev = dev_get_drvdata(&rpdev->dev);
+       struct cros_ec_rpmsg *ec_rpmsg = ec_dev->priv;
+       struct cros_ec_rpmsg_response *resp;
+
+       if (!len) {
+               dev_warn(ec_dev->dev, "rpmsg received empty response");
+               return -EINVAL;
+       }
+
+       resp = data;
+       len -= offsetof(struct cros_ec_rpmsg_response, data);
+       if (resp->type == HOST_COMMAND_MARK) {
+               if (len > ec_dev->din_size) {
+                       dev_warn(ec_dev->dev,
+                                "received length %d > din_size %d, truncating",
+                                len, ec_dev->din_size);
+                       len = ec_dev->din_size;
+               }
+
+               memcpy(ec_dev->din, resp->data, len);
+               complete(&ec_rpmsg->xfer_ack);
+       } else if (resp->type == HOST_EVENT_MARK) {
+               schedule_work(&ec_rpmsg->host_event_work);
+       } else {
+               dev_warn(ec_dev->dev, "rpmsg received invalid type = %d",
+                        resp->type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cros_ec_rpmsg_probe(struct rpmsg_device *rpdev)
+{
+       struct device *dev = &rpdev->dev;
+       struct cros_ec_rpmsg *ec_rpmsg;
+       struct cros_ec_device *ec_dev;
+
+       ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
+       if (!ec_dev)
+               return -ENOMEM;
+
+       ec_rpmsg = devm_kzalloc(dev, sizeof(*ec_rpmsg), GFP_KERNEL);
+       if (!ec_rpmsg)
+               return -ENOMEM;
+
+       ec_dev->dev = dev;
+       ec_dev->priv = ec_rpmsg;
+       ec_dev->cmd_xfer = cros_ec_cmd_xfer_rpmsg;
+       ec_dev->pkt_xfer = cros_ec_pkt_xfer_rpmsg;
+       ec_dev->phys_name = dev_name(&rpdev->dev);
+       ec_dev->din_size = sizeof(struct ec_host_response) +
+                          sizeof(struct ec_response_get_protocol_info);
+       ec_dev->dout_size = sizeof(struct ec_host_request);
+       dev_set_drvdata(dev, ec_dev);
+
+       ec_rpmsg->rpdev = rpdev;
+       init_completion(&ec_rpmsg->xfer_ack);
+       INIT_WORK(&ec_rpmsg->host_event_work,
+                 cros_ec_rpmsg_host_event_function);
+
+       return cros_ec_register(ec_dev);
+}
+
+static void cros_ec_rpmsg_remove(struct rpmsg_device *rpdev)
+{
+       struct cros_ec_device *ec_dev = dev_get_drvdata(&rpdev->dev);
+       struct cros_ec_rpmsg *ec_rpmsg = ec_dev->priv;
+
+       cancel_work_sync(&ec_rpmsg->host_event_work);
+}
+
+static const struct of_device_id cros_ec_rpmsg_of_match[] = {
+       { .compatible = "google,cros-ec-rpmsg", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, cros_ec_rpmsg_of_match);
+
+static struct rpmsg_driver cros_ec_driver_rpmsg = {
+       .drv = {
+               .name   = "cros-ec-rpmsg",
+               .of_match_table = cros_ec_rpmsg_of_match,
+       },
+       .probe          = cros_ec_rpmsg_probe,
+       .remove         = cros_ec_rpmsg_remove,
+       .callback       = cros_ec_rpmsg_callback,
+};
+
+module_rpmsg_driver(cros_ec_driver_rpmsg);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ChromeOS EC multi function device (rpmsg)");
index ffc38f9d482994ff404f61ad3665241f31cbceeb..8e9451720e73f59746642e6636d533b8ded46cef 100644 (file)
@@ -75,6 +75,27 @@ struct cros_ec_spi {
        unsigned int end_of_msg_delay;
 };
 
+typedef int (*cros_ec_xfer_fn_t) (struct cros_ec_device *ec_dev,
+                                 struct cros_ec_command *ec_msg);
+
+/**
+ * struct cros_ec_xfer_work_params - params for our high priority workers
+ *
+ * @work: The work_struct needed to queue work
+ * @fn: The function to use to transfer
+ * @ec_dev: ChromeOS EC device
+ * @ec_msg: Message to transfer
+ * @ret: The return value of the function
+ */
+
+struct cros_ec_xfer_work_params {
+       struct work_struct work;
+       cros_ec_xfer_fn_t fn;
+       struct cros_ec_device *ec_dev;
+       struct cros_ec_command *ec_msg;
+       int ret;
+};
+
 static void debug_packet(struct device *dev, const char *name, u8 *ptr,
                         int len)
 {
@@ -350,13 +371,13 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
 }
 
 /**
- * cros_ec_pkt_xfer_spi - Transfer a packet over SPI and receive the reply
+ * do_cros_ec_pkt_xfer_spi - Transfer a packet over SPI and receive the reply
  *
  * @ec_dev: ChromeOS EC device
  * @ec_msg: Message to transfer
  */
-static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
-                               struct cros_ec_command *ec_msg)
+static int do_cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
+                                  struct cros_ec_command *ec_msg)
 {
        struct ec_host_response *response;
        struct cros_ec_spi *ec_spi = ec_dev->priv;
@@ -493,13 +514,13 @@ exit:
 }
 
 /**
- * cros_ec_cmd_xfer_spi - Transfer a message over SPI and receive the reply
+ * do_cros_ec_cmd_xfer_spi - Transfer a message over SPI and receive the reply
  *
  * @ec_dev: ChromeOS EC device
  * @ec_msg: Message to transfer
  */
-static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev,
-                               struct cros_ec_command *ec_msg)
+static int do_cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev,
+                                  struct cros_ec_command *ec_msg)
 {
        struct cros_ec_spi *ec_spi = ec_dev->priv;
        struct spi_transfer trans;
@@ -611,6 +632,53 @@ exit:
        return ret;
 }
 
+static void cros_ec_xfer_high_pri_work(struct work_struct *work)
+{
+       struct cros_ec_xfer_work_params *params;
+
+       params = container_of(work, struct cros_ec_xfer_work_params, work);
+       params->ret = params->fn(params->ec_dev, params->ec_msg);
+}
+
+static int cros_ec_xfer_high_pri(struct cros_ec_device *ec_dev,
+                                struct cros_ec_command *ec_msg,
+                                cros_ec_xfer_fn_t fn)
+{
+       struct cros_ec_xfer_work_params params;
+
+       INIT_WORK_ONSTACK(&params.work, cros_ec_xfer_high_pri_work);
+       params.ec_dev = ec_dev;
+       params.ec_msg = ec_msg;
+       params.fn = fn;
+
+       /*
+        * This looks a bit ridiculous.  Why do the work on a
+        * different thread if we're just going to block waiting for
+        * the thread to finish?  The key here is that the thread is
+        * running at high priority but the calling context might not
+        * be.  We need to be at high priority to avoid getting
+        * context switched out for too long and the EC giving up on
+        * the transfer.
+        */
+       queue_work(system_highpri_wq, &params.work);
+       flush_work(&params.work);
+       destroy_work_on_stack(&params.work);
+
+       return params.ret;
+}
+
+static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
+                               struct cros_ec_command *ec_msg)
+{
+       return cros_ec_xfer_high_pri(ec_dev, ec_msg, do_cros_ec_pkt_xfer_spi);
+}
+
+static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev,
+                               struct cros_ec_command *ec_msg)
+{
+       return cros_ec_xfer_high_pri(ec_dev, ec_msg, do_cros_ec_cmd_xfer_spi);
+}
+
 static void cros_ec_spi_dt_probe(struct cros_ec_spi *ec_spi, struct device *dev)
 {
        struct device_node *np = dev->of_node;
diff --git a/drivers/platform/chrome/cros_ec_trace.c b/drivers/platform/chrome/cros_ec_trace.c
new file mode 100644 (file)
index 0000000..0a76412
--- /dev/null
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+// Trace events for the ChromeOS Embedded Controller
+//
+// Copyright 2019 Google LLC.
+
+#define TRACE_SYMBOL(a) {a, #a}
+
+// Generate the list using the following script:
+// sed -n 's/^#define \(EC_CMD_[[:alnum:]_]*\)\s.*/\tTRACE_SYMBOL(\1), \\/p' include/linux/mfd/cros_ec_commands.h
+#define EC_CMDS \
+       TRACE_SYMBOL(EC_CMD_PROTO_VERSION), \
+       TRACE_SYMBOL(EC_CMD_HELLO), \
+       TRACE_SYMBOL(EC_CMD_GET_VERSION), \
+       TRACE_SYMBOL(EC_CMD_READ_TEST), \
+       TRACE_SYMBOL(EC_CMD_GET_BUILD_INFO), \
+       TRACE_SYMBOL(EC_CMD_GET_CHIP_INFO), \
+       TRACE_SYMBOL(EC_CMD_GET_BOARD_VERSION), \
+       TRACE_SYMBOL(EC_CMD_READ_MEMMAP), \
+       TRACE_SYMBOL(EC_CMD_GET_CMD_VERSIONS), \
+       TRACE_SYMBOL(EC_CMD_GET_COMMS_STATUS), \
+       TRACE_SYMBOL(EC_CMD_TEST_PROTOCOL), \
+       TRACE_SYMBOL(EC_CMD_GET_PROTOCOL_INFO), \
+       TRACE_SYMBOL(EC_CMD_GSV_PAUSE_IN_S5), \
+       TRACE_SYMBOL(EC_CMD_GET_FEATURES), \
+       TRACE_SYMBOL(EC_CMD_FLASH_INFO), \
+       TRACE_SYMBOL(EC_CMD_FLASH_READ), \
+       TRACE_SYMBOL(EC_CMD_FLASH_WRITE), \
+       TRACE_SYMBOL(EC_CMD_FLASH_ERASE), \
+       TRACE_SYMBOL(EC_CMD_FLASH_PROTECT), \
+       TRACE_SYMBOL(EC_CMD_FLASH_REGION_INFO), \
+       TRACE_SYMBOL(EC_CMD_VBNV_CONTEXT), \
+       TRACE_SYMBOL(EC_CMD_PWM_GET_FAN_TARGET_RPM), \
+       TRACE_SYMBOL(EC_CMD_PWM_SET_FAN_TARGET_RPM), \
+       TRACE_SYMBOL(EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT), \
+       TRACE_SYMBOL(EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT), \
+       TRACE_SYMBOL(EC_CMD_PWM_SET_FAN_DUTY), \
+       TRACE_SYMBOL(EC_CMD_PWM_SET_DUTY), \
+       TRACE_SYMBOL(EC_CMD_PWM_GET_DUTY), \
+       TRACE_SYMBOL(EC_CMD_LIGHTBAR_CMD), \
+       TRACE_SYMBOL(EC_CMD_LED_CONTROL), \
+       TRACE_SYMBOL(EC_CMD_VBOOT_HASH), \
+       TRACE_SYMBOL(EC_CMD_MOTION_SENSE_CMD), \
+       TRACE_SYMBOL(EC_CMD_USB_CHARGE_SET_MODE), \
+       TRACE_SYMBOL(EC_CMD_PSTORE_INFO), \
+       TRACE_SYMBOL(EC_CMD_PSTORE_READ), \
+       TRACE_SYMBOL(EC_CMD_PSTORE_WRITE), \
+       TRACE_SYMBOL(EC_CMD_RTC_GET_VALUE), \
+       TRACE_SYMBOL(EC_CMD_RTC_GET_ALARM), \
+       TRACE_SYMBOL(EC_CMD_RTC_SET_VALUE), \
+       TRACE_SYMBOL(EC_CMD_RTC_SET_ALARM), \
+       TRACE_SYMBOL(EC_CMD_PORT80_LAST_BOOT), \
+       TRACE_SYMBOL(EC_CMD_PORT80_READ), \
+       TRACE_SYMBOL(EC_CMD_THERMAL_SET_THRESHOLD), \
+       TRACE_SYMBOL(EC_CMD_THERMAL_GET_THRESHOLD), \
+       TRACE_SYMBOL(EC_CMD_THERMAL_AUTO_FAN_CTRL), \
+       TRACE_SYMBOL(EC_CMD_TMP006_GET_CALIBRATION), \
+       TRACE_SYMBOL(EC_CMD_TMP006_SET_CALIBRATION), \
+       TRACE_SYMBOL(EC_CMD_TMP006_GET_RAW), \
+       TRACE_SYMBOL(EC_CMD_MKBP_STATE), \
+       TRACE_SYMBOL(EC_CMD_MKBP_INFO), \
+       TRACE_SYMBOL(EC_CMD_MKBP_SIMULATE_KEY), \
+       TRACE_SYMBOL(EC_CMD_MKBP_SET_CONFIG), \
+       TRACE_SYMBOL(EC_CMD_MKBP_GET_CONFIG), \
+       TRACE_SYMBOL(EC_CMD_KEYSCAN_SEQ_CTRL), \
+       TRACE_SYMBOL(EC_CMD_GET_NEXT_EVENT), \
+       TRACE_SYMBOL(EC_CMD_TEMP_SENSOR_GET_INFO), \
+       TRACE_SYMBOL(EC_CMD_HOST_EVENT_GET_B), \
+       TRACE_SYMBOL(EC_CMD_HOST_EVENT_GET_SMI_MASK), \
+       TRACE_SYMBOL(EC_CMD_HOST_EVENT_GET_SCI_MASK), \
+       TRACE_SYMBOL(EC_CMD_HOST_EVENT_GET_WAKE_MASK), \
+       TRACE_SYMBOL(EC_CMD_HOST_EVENT_SET_SMI_MASK), \
+       TRACE_SYMBOL(EC_CMD_HOST_EVENT_SET_SCI_MASK), \
+       TRACE_SYMBOL(EC_CMD_HOST_EVENT_CLEAR), \
+       TRACE_SYMBOL(EC_CMD_HOST_EVENT_SET_WAKE_MASK), \
+       TRACE_SYMBOL(EC_CMD_HOST_EVENT_CLEAR_B), \
+       TRACE_SYMBOL(EC_CMD_SWITCH_ENABLE_BKLIGHT), \
+       TRACE_SYMBOL(EC_CMD_SWITCH_ENABLE_WIRELESS), \
+       TRACE_SYMBOL(EC_CMD_GPIO_SET), \
+       TRACE_SYMBOL(EC_CMD_GPIO_GET), \
+       TRACE_SYMBOL(EC_CMD_I2C_READ), \
+       TRACE_SYMBOL(EC_CMD_I2C_WRITE), \
+       TRACE_SYMBOL(EC_CMD_CHARGE_CONTROL), \
+       TRACE_SYMBOL(EC_CMD_CONSOLE_SNAPSHOT), \
+       TRACE_SYMBOL(EC_CMD_CONSOLE_READ), \
+       TRACE_SYMBOL(EC_CMD_BATTERY_CUT_OFF), \
+       TRACE_SYMBOL(EC_CMD_USB_MUX), \
+       TRACE_SYMBOL(EC_CMD_LDO_SET), \
+       TRACE_SYMBOL(EC_CMD_LDO_GET), \
+       TRACE_SYMBOL(EC_CMD_POWER_INFO), \
+       TRACE_SYMBOL(EC_CMD_I2C_PASSTHRU), \
+       TRACE_SYMBOL(EC_CMD_HANG_DETECT), \
+       TRACE_SYMBOL(EC_CMD_CHARGE_STATE), \
+       TRACE_SYMBOL(EC_CMD_CHARGE_CURRENT_LIMIT), \
+       TRACE_SYMBOL(EC_CMD_EXTERNAL_POWER_LIMIT), \
+       TRACE_SYMBOL(EC_CMD_HOST_SLEEP_EVENT), \
+       TRACE_SYMBOL(EC_CMD_SB_READ_WORD), \
+       TRACE_SYMBOL(EC_CMD_SB_WRITE_WORD), \
+       TRACE_SYMBOL(EC_CMD_SB_READ_BLOCK), \
+       TRACE_SYMBOL(EC_CMD_SB_WRITE_BLOCK), \
+       TRACE_SYMBOL(EC_CMD_BATTERY_VENDOR_PARAM), \
+       TRACE_SYMBOL(EC_CMD_CODEC_I2S), \
+       TRACE_SYMBOL(EC_CMD_REBOOT_EC), \
+       TRACE_SYMBOL(EC_CMD_GET_PANIC_INFO), \
+       TRACE_SYMBOL(EC_CMD_ACPI_READ), \
+       TRACE_SYMBOL(EC_CMD_ACPI_WRITE), \
+       TRACE_SYMBOL(EC_CMD_ACPI_QUERY_EVENT), \
+       TRACE_SYMBOL(EC_CMD_CEC_WRITE_MSG), \
+       TRACE_SYMBOL(EC_CMD_CEC_SET), \
+       TRACE_SYMBOL(EC_CMD_CEC_GET), \
+       TRACE_SYMBOL(EC_CMD_REBOOT), \
+       TRACE_SYMBOL(EC_CMD_RESEND_RESPONSE), \
+       TRACE_SYMBOL(EC_CMD_VERSION0), \
+       TRACE_SYMBOL(EC_CMD_PD_EXCHANGE_STATUS), \
+       TRACE_SYMBOL(EC_CMD_USB_PD_CONTROL), \
+       TRACE_SYMBOL(EC_CMD_USB_PD_PORTS), \
+       TRACE_SYMBOL(EC_CMD_USB_PD_POWER_INFO), \
+       TRACE_SYMBOL(EC_CMD_CHARGE_PORT_COUNT), \
+       TRACE_SYMBOL(EC_CMD_USB_PD_DISCOVERY), \
+       TRACE_SYMBOL(EC_CMD_PD_CHARGE_PORT_OVERRIDE), \
+       TRACE_SYMBOL(EC_CMD_PD_GET_LOG_ENTRY), \
+       TRACE_SYMBOL(EC_CMD_USB_PD_MUX_INFO)
+
+#define CREATE_TRACE_POINTS
+#include "cros_ec_trace.h"
diff --git a/drivers/platform/chrome/cros_ec_trace.h b/drivers/platform/chrome/cros_ec_trace.h
new file mode 100644 (file)
index 0000000..7ae3b89
--- /dev/null
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Trace events for the ChromeOS Embedded Controller
+ *
+ * Copyright 2019 Google LLC.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM cros_ec
+
+#if !defined(_CROS_EC_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _CROS_EC_TRACE_H_
+
+#include <linux/types.h>
+#include <linux/mfd/cros_ec.h>
+
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(cros_ec_cmd_class,
+       TP_PROTO(struct cros_ec_command *cmd),
+       TP_ARGS(cmd),
+       TP_STRUCT__entry(
+               __field(uint32_t, version)
+               __field(uint32_t, command)
+       ),
+       TP_fast_assign(
+               __entry->version = cmd->version;
+               __entry->command = cmd->command;
+       ),
+       TP_printk("version: %u, command: %s", __entry->version,
+                 __print_symbolic(__entry->command, EC_CMDS))
+);
+
+
+DEFINE_EVENT(cros_ec_cmd_class, cros_ec_cmd,
+       TP_PROTO(struct cros_ec_command *cmd),
+       TP_ARGS(cmd)
+);
+
+
+#endif /* _CROS_EC_TRACE_H_ */
+
+/* this part must be outside header guard */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE cros_ec_trace
+
+#include <trace/define_trace.h>
diff --git a/drivers/platform/chrome/cros_usbpd_logger.c b/drivers/platform/chrome/cros_usbpd_logger.c
new file mode 100644 (file)
index 0000000..7c7b267
--- /dev/null
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Logging driver for ChromeOS EC based USBPD Charger.
+ *
+ * Copyright 2018 Google LLC.
+ */
+
+#include <linux/ktime.h>
+#include <linux/math64.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#define DRV_NAME "cros-usbpd-logger"
+
+#define CROS_USBPD_MAX_LOG_ENTRIES     30
+#define CROS_USBPD_LOG_UPDATE_DELAY    msecs_to_jiffies(60000)
+#define CROS_USBPD_DATA_SIZE           16
+#define CROS_USBPD_LOG_RESP_SIZE       (sizeof(struct ec_response_pd_log) + \
+                                        CROS_USBPD_DATA_SIZE)
+#define CROS_USBPD_BUFFER_SIZE         (sizeof(struct cros_ec_command) + \
+                                        CROS_USBPD_LOG_RESP_SIZE)
+/* Buffer for building the PDLOG string */
+#define BUF_SIZE       80
+
+struct logger_data {
+       struct device *dev;
+       struct cros_ec_dev *ec_dev;
+       u8 ec_buffer[CROS_USBPD_BUFFER_SIZE];
+       struct delayed_work log_work;
+       struct workqueue_struct *log_workqueue;
+};
+
+static const char * const chg_type_names[] = {
+       "None", "PD", "Type-C", "Proprietary", "DCP", "CDP", "SDP",
+       "Other", "VBUS"
+};
+
+static const char * const role_names[] = {
+       "Disconnected", "SRC", "SNK", "SNK (not charging)"
+};
+
+static const char * const fault_names[] = {
+       "---", "OCP", "fast OCP", "OVP", "Discharge"
+};
+
+static int append_str(char *buf, int pos, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i = vsnprintf(buf + pos, BUF_SIZE - pos, fmt, args);
+       va_end(args);
+
+       return i;
+}
+
+static struct ec_response_pd_log *ec_get_log_entry(struct logger_data *logger)
+{
+       struct cros_ec_dev *ec_dev = logger->ec_dev;
+       struct cros_ec_command *msg;
+       int ret;
+
+       msg = (struct cros_ec_command *)logger->ec_buffer;
+
+       msg->command = ec_dev->cmd_offset + EC_CMD_PD_GET_LOG_ENTRY;
+       msg->insize = CROS_USBPD_LOG_RESP_SIZE;
+
+       ret = cros_ec_cmd_xfer_status(ec_dev->ec_dev, msg);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       return (struct ec_response_pd_log *)msg->data;
+}
+
+static void cros_usbpd_print_log_entry(struct ec_response_pd_log *r,
+                                      ktime_t tstamp)
+{
+       const char *fault, *role, *chg_type;
+       struct usb_chg_measures *meas;
+       struct mcdp_info *minfo;
+       int role_idx, type_idx;
+       char buf[BUF_SIZE + 1];
+       struct rtc_time rt;
+       int len = 0;
+       s32 rem;
+       int i;
+
+       /* The timestamp is the number of 1024th of seconds in the past */
+       tstamp = ktime_sub_us(tstamp, r->timestamp << PD_LOG_TIMESTAMP_SHIFT);
+       rt = rtc_ktime_to_tm(tstamp);
+
+       switch (r->type) {
+       case PD_EVENT_MCU_CHARGE:
+               if (r->data & CHARGE_FLAGS_OVERRIDE)
+                       len += append_str(buf, len, "override ");
+
+               if (r->data & CHARGE_FLAGS_DELAYED_OVERRIDE)
+                       len += append_str(buf, len, "pending_override ");
+
+               role_idx = r->data & CHARGE_FLAGS_ROLE_MASK;
+               role = role_idx < ARRAY_SIZE(role_names) ?
+                       role_names[role_idx] : "Unknown";
+
+               type_idx = (r->data & CHARGE_FLAGS_TYPE_MASK)
+                        >> CHARGE_FLAGS_TYPE_SHIFT;
+
+               chg_type = type_idx < ARRAY_SIZE(chg_type_names) ?
+                       chg_type_names[type_idx] : "???";
+
+               if (role_idx == USB_PD_PORT_POWER_DISCONNECTED ||
+                   role_idx == USB_PD_PORT_POWER_SOURCE) {
+                       len += append_str(buf, len, "%s", role);
+                       break;
+               }
+
+               meas = (struct usb_chg_measures *)r->payload;
+               len += append_str(buf, len, "%s %s %s %dmV max %dmV / %dmA",
+                                 role, r->data & CHARGE_FLAGS_DUAL_ROLE ?
+                                 "DRP" : "Charger",
+                                 chg_type, meas->voltage_now,
+                                 meas->voltage_max, meas->current_max);
+               break;
+       case PD_EVENT_ACC_RW_FAIL:
+               len += append_str(buf, len, "RW signature check failed");
+               break;
+       case PD_EVENT_PS_FAULT:
+               fault = r->data < ARRAY_SIZE(fault_names) ? fault_names[r->data]
+                                                         : "???";
+               len += append_str(buf, len, "Power supply fault: %s", fault);
+               break;
+       case PD_EVENT_VIDEO_DP_MODE:
+               len += append_str(buf, len, "DP mode %sabled", r->data == 1 ?
+                                 "en" : "dis");
+               break;
+       case PD_EVENT_VIDEO_CODEC:
+               minfo = (struct mcdp_info *)r->payload;
+               len += append_str(buf, len, "HDMI info: family:%04x chipid:%04x ",
+                                 MCDP_FAMILY(minfo->family),
+                                 MCDP_CHIPID(minfo->chipid));
+               len += append_str(buf, len, "irom:%d.%d.%d fw:%d.%d.%d",
+                                 minfo->irom.major, minfo->irom.minor,
+                                 minfo->irom.build, minfo->fw.major,
+                                 minfo->fw.minor, minfo->fw.build);
+               break;
+       default:
+               len += append_str(buf, len, "Event %02x (%04x) [", r->type,
+                                 r->data);
+
+               for (i = 0; i < PD_LOG_SIZE(r->size_port); i++)
+                       len += append_str(buf, len, "%02x ", r->payload[i]);
+
+               len += append_str(buf, len, "]");
+               break;
+       }
+
+       div_s64_rem(ktime_to_ms(tstamp), MSEC_PER_SEC, &rem);
+       pr_info("PDLOG %d/%02d/%02d %02d:%02d:%02d.%03d P%d %s\n",
+               rt.tm_year + 1900, rt.tm_mon + 1, rt.tm_mday,
+               rt.tm_hour, rt.tm_min, rt.tm_sec, rem,
+               PD_LOG_PORT(r->size_port), buf);
+}
+
+static void cros_usbpd_log_check(struct work_struct *work)
+{
+       struct logger_data *logger = container_of(to_delayed_work(work),
+                                                 struct logger_data,
+                                                 log_work);
+       struct device *dev = logger->dev;
+       struct ec_response_pd_log *r;
+       int entries = 0;
+       ktime_t now;
+
+       while (entries++ < CROS_USBPD_MAX_LOG_ENTRIES) {
+               r = ec_get_log_entry(logger);
+               now = ktime_get_real();
+               if (IS_ERR(r)) {
+                       dev_dbg(dev, "Cannot get PD log %ld\n", PTR_ERR(r));
+                       break;
+               }
+               if (r->type == PD_EVENT_NO_ENTRY)
+                       break;
+
+               cros_usbpd_print_log_entry(r, now);
+       }
+
+       queue_delayed_work(logger->log_workqueue, &logger->log_work,
+                          CROS_USBPD_LOG_UPDATE_DELAY);
+}
+
+static int cros_usbpd_logger_probe(struct platform_device *pd)
+{
+       struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
+       struct device *dev = &pd->dev;
+       struct logger_data *logger;
+
+       logger = devm_kzalloc(dev, sizeof(*logger), GFP_KERNEL);
+       if (!logger)
+               return -ENOMEM;
+
+       logger->dev = dev;
+       logger->ec_dev = ec_dev;
+
+       platform_set_drvdata(pd, logger);
+
+       /* Retrieve PD event logs periodically */
+       INIT_DELAYED_WORK(&logger->log_work, cros_usbpd_log_check);
+       logger->log_workqueue = create_singlethread_workqueue("cros_usbpd_log");
+       queue_delayed_work(logger->log_workqueue, &logger->log_work,
+                          CROS_USBPD_LOG_UPDATE_DELAY);
+
+       return 0;
+}
+
+static int cros_usbpd_logger_remove(struct platform_device *pd)
+{
+       struct logger_data *logger = platform_get_drvdata(pd);
+
+       cancel_delayed_work_sync(&logger->log_work);
+
+       return 0;
+}
+
+static int __maybe_unused cros_usbpd_logger_resume(struct device *dev)
+{
+       struct logger_data *logger = dev_get_drvdata(dev);
+
+       queue_delayed_work(logger->log_workqueue, &logger->log_work,
+                          CROS_USBPD_LOG_UPDATE_DELAY);
+
+       return 0;
+}
+
+static int __maybe_unused cros_usbpd_logger_suspend(struct device *dev)
+{
+       struct logger_data *logger = dev_get_drvdata(dev);
+
+       cancel_delayed_work_sync(&logger->log_work);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(cros_usbpd_logger_pm_ops, cros_usbpd_logger_suspend,
+                        cros_usbpd_logger_resume);
+
+static struct platform_driver cros_usbpd_logger_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .pm = &cros_usbpd_logger_pm_ops,
+       },
+       .probe = cros_usbpd_logger_probe,
+       .remove = cros_usbpd_logger_remove,
+};
+
+module_platform_driver(cros_usbpd_logger_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Logging driver for ChromeOS EC USBPD Charger.");
+MODULE_ALIAS("platform:" DRV_NAME);
index c090db2cd5be9a7463a44309f5dc4353eed04cde..f163476d080d25978bce23feeb848a6e98ebeff2 100644 (file)
@@ -4,31 +4,7 @@
  *
  * Copyright 2019 Google LLC
  *
- * There is only one attribute used for debugging, called raw.
- * You can write a hexadecimal sentence to raw, and that series of bytes
- * will be sent to the EC. Then, you can read the bytes of response
- * by reading from raw.
- *
- * For writing:
- * Bytes 0-1 indicate the message type:
- *         00 F0 = Execute Legacy Command
- *         00 F2 = Read/Write NVRAM Property
- * Byte 2 provides the command code
- * Bytes 3+ consist of the data passed in the request
- *
- * When referencing the EC interface spec, byte 2 corresponds to MBOX[0],
- * byte 3 corresponds to MBOX[1], etc.
- *
- * At least three bytes are required, for the msg type and command,
- * with additional bytes optional for additional data.
- *
- * Example:
- * // Request EC info type 3 (EC firmware build date)
- * $ echo 00 f0 38 00 03 00 > raw
- * // View the result. The decoded ASCII result "12/21/18" is
- * // included after the raw hex.
- * $ cat raw
- * 00 31 32 2f 32 31 2f 31 38 00 38 00 01 00 2f 00  .12/21/18.8...
+ * See Documentation/ABI/testing/debugfs-wilco-ec for usage.
  */
 
 #include <linux/ctype.h>
@@ -136,18 +112,15 @@ static ssize_t raw_write(struct file *file, const char __user *user_buf,
        ret = parse_hex_sentence(buf, kcount, request_data, TYPE_AND_DATA_SIZE);
        if (ret < 0)
                return ret;
-       /* Need at least two bytes for message type and one for command */
+       /* Need at least two bytes for message type and one byte of data */
        if (ret < 3)
                return -EINVAL;
 
-       /* Clear response data buffer */
-       memset(debug_info->raw_data, '\0', EC_MAILBOX_DATA_SIZE_EXTENDED);
-
        msg.type = request_data[0] << 8 | request_data[1];
-       msg.flags = WILCO_EC_FLAG_RAW;
-       msg.command = request_data[2];
-       msg.request_data = ret > 3 ? request_data + 3 : 0;
-       msg.request_size = ret - 3;
+       msg.flags = 0;
+       msg.request_data = request_data + 2;
+       msg.request_size = ret - 2;
+       memset(debug_info->raw_data, 0, sizeof(debug_info->raw_data));
        msg.response_data = debug_info->raw_data;
        msg.response_size = EC_MAILBOX_DATA_SIZE;
 
@@ -174,7 +147,8 @@ static ssize_t raw_read(struct file *file, char __user *user_buf, size_t count,
                fmt_len = hex_dump_to_buffer(debug_info->raw_data,
                                             debug_info->response_size,
                                             16, 1, debug_info->formatted_data,
-                                            FORMATTED_BUFFER_SIZE, true);
+                                            sizeof(debug_info->formatted_data),
+                                            true);
                /* Only return response the first time it is read */
                debug_info->response_size = 0;
        }
@@ -190,6 +164,51 @@ static const struct file_operations fops_raw = {
        .llseek = no_llseek,
 };
 
+#define CMD_KB_CHROME          0x88
+#define SUB_CMD_H1_GPIO                0x0A
+
+struct h1_gpio_status_request {
+       u8 cmd;         /* Always CMD_KB_CHROME */
+       u8 reserved;
+       u8 sub_cmd;     /* Always SUB_CMD_H1_GPIO */
+} __packed;
+
+struct hi_gpio_status_response {
+       u8 status;      /* 0 if allowed */
+       u8 val;         /* BIT(0)=ENTRY_TO_FACT_MODE, BIT(1)=SPI_CHROME_SEL */
+} __packed;
+
+static int h1_gpio_get(void *arg, u64 *val)
+{
+       struct wilco_ec_device *ec = arg;
+       struct h1_gpio_status_request rq;
+       struct hi_gpio_status_response rs;
+       struct wilco_ec_message msg;
+       int ret;
+
+       memset(&rq, 0, sizeof(rq));
+       rq.cmd = CMD_KB_CHROME;
+       rq.sub_cmd = SUB_CMD_H1_GPIO;
+
+       memset(&msg, 0, sizeof(msg));
+       msg.type = WILCO_EC_MSG_LEGACY;
+       msg.request_data = &rq;
+       msg.request_size = sizeof(rq);
+       msg.response_data = &rs;
+       msg.response_size = sizeof(rs);
+       ret = wilco_ec_mailbox(ec, &msg);
+       if (ret < 0)
+               return ret;
+       if (rs.status)
+               return -EIO;
+
+       *val = rs.val;
+
+       return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_h1_gpio, h1_gpio_get, NULL, "0x%02llx\n");
+
 /**
  * wilco_ec_debugfs_probe() - Create the debugfs node
  * @pdev: The platform device, probably created in core.c
@@ -211,6 +230,8 @@ static int wilco_ec_debugfs_probe(struct platform_device *pdev)
        if (!debug_info->dir)
                return 0;
        debugfs_create_file("raw", 0644, debug_info->dir, NULL, &fops_raw);
+       debugfs_create_file("h1_gpio", 0444, debug_info->dir, ec,
+                           &fops_h1_gpio);
 
        return 0;
 }
index 14355668ddfa3146e88074132737a757a075090a..7fb58b48796371cf59d497ef66cf7b094353c52b 100644 (file)
@@ -92,21 +92,10 @@ static void wilco_ec_prepare(struct wilco_ec_message *msg,
                             struct wilco_ec_request *rq)
 {
        memset(rq, 0, sizeof(*rq));
-
-       /* Handle messages without trimming bytes from the request */
-       if (msg->request_size && msg->flags & WILCO_EC_FLAG_RAW_REQUEST) {
-               rq->reserved_raw = *(u8 *)msg->request_data;
-               msg->request_size--;
-               memmove(msg->request_data, msg->request_data + 1,
-                       msg->request_size);
-       }
-
-       /* Fill in request packet */
        rq->struct_version = EC_MAILBOX_PROTO_VERSION;
        rq->mailbox_id = msg->type;
        rq->mailbox_version = EC_MAILBOX_VERSION;
-       rq->data_size = msg->request_size + EC_MAILBOX_DATA_EXTRA;
-       rq->command = msg->command;
+       rq->data_size = msg->request_size;
 
        /* Checksum header and data */
        rq->checksum = wilco_ec_checksum(rq, sizeof(*rq));
@@ -159,6 +148,12 @@ static int wilco_ec_transfer(struct wilco_ec_device *ec,
                return -EIO;
        }
 
+       /*
+        * The EC always returns either EC_MAILBOX_DATA_SIZE or
+        * EC_MAILBOX_DATA_SIZE_EXTENDED bytes of data, so we need to
+        * calculate the checksum on **all** of this data, even if we
+        * won't use all of it.
+        */
        if (msg->flags & WILCO_EC_FLAG_EXTENDED_DATA)
                size = EC_MAILBOX_DATA_SIZE_EXTENDED;
        else
@@ -173,33 +168,26 @@ static int wilco_ec_transfer(struct wilco_ec_device *ec,
                return -EBADMSG;
        }
 
-       /* Check that the EC reported success */
-       msg->result = rs->result;
-       if (msg->result) {
-               dev_dbg(ec->dev, "bad response: 0x%02x\n", msg->result);
+       if (rs->result) {
+               dev_dbg(ec->dev, "EC reported failure: 0x%02x\n", rs->result);
                return -EBADMSG;
        }
 
-       /* Check the returned data size, skipping the header */
        if (rs->data_size != size) {
                dev_dbg(ec->dev, "unexpected packet size (%u != %zu)",
                        rs->data_size, size);
                return -EMSGSIZE;
        }
 
-       /* Skip 1 response data byte unless specified */
-       size = (msg->flags & WILCO_EC_FLAG_RAW_RESPONSE) ? 0 : 1;
-       if ((ssize_t) rs->data_size - size < msg->response_size) {
-               dev_dbg(ec->dev, "response data too short (%zd < %zu)",
-                       (ssize_t) rs->data_size - size, msg->response_size);
+       if (rs->data_size < msg->response_size) {
+               dev_dbg(ec->dev, "EC didn't return enough data (%u < %zu)",
+                       rs->data_size, msg->response_size);
                return -EMSGSIZE;
        }
 
-       /* Ignore response data bytes as requested */
-       memcpy(msg->response_data, rs->data + size, msg->response_size);
+       memcpy(msg->response_data, rs->data, msg->response_size);
 
-       /* Return actual amount of data received */
-       return msg->response_size;
+       return rs->data_size;
 }
 
 /**
@@ -207,10 +195,12 @@ static int wilco_ec_transfer(struct wilco_ec_device *ec,
  * @ec: EC device.
  * @msg: EC message data for request and response.
  *
- * On entry msg->type, msg->flags, msg->command, msg->request_size,
- * msg->response_size, and msg->request_data should all be filled in.
+ * On entry msg->type, msg->request_size, and msg->request_data should all be
+ * filled in. If desired, msg->flags can be set.
  *
- * On exit msg->result and msg->response_data will be filled.
+ * If a response is expected, msg->response_size should be set, and
+ * msg->response_data should point to a buffer with enough space. On exit
+ * msg->response_data will be filled.
  *
  * Return: number of bytes received or negative error code on failure.
  */
@@ -219,9 +209,8 @@ int wilco_ec_mailbox(struct wilco_ec_device *ec, struct wilco_ec_message *msg)
        struct wilco_ec_request *rq;
        int ret;
 
-       dev_dbg(ec->dev, "cmd=%02x type=%04x flags=%02x rslen=%zu rqlen=%zu\n",
-               msg->command, msg->type, msg->flags, msg->response_size,
-               msg->request_size);
+       dev_dbg(ec->dev, "type=%04x flags=%02x rslen=%zu rqlen=%zu\n",
+               msg->type, msg->flags, msg->response_size, msg->request_size);
 
        mutex_lock(&ec->mailbox_lock);
        /* Prepare request packet */
index 321bc673c4173d2d3613619cf05bc9275b650285..cef0133aa47a801e5753a5ad6e1f154e44572991 100644 (file)
@@ -274,7 +274,8 @@ static int pin_user_pages(unsigned long first_page,
                *iter_last_page_size = last_page_size;
        }
 
-       ret = get_user_pages_fast(first_page, requested_pages, !is_write,
+       ret = get_user_pages_fast(first_page, requested_pages,
+                                 !is_write ? FOLL_WRITE : 0,
                                  pages);
        if (ret <= 0)
                return -EFAULT;
index cd8a908460633c315813e9363fe7bd0b67fa49fa..530fe7e31397eea130e4567ed7d7840ec5a7b487 100644 (file)
@@ -5,7 +5,7 @@
 
 menuconfig MELLANOX_PLATFORM
        bool "Platform support for Mellanox hardware"
-       depends on X86 || ARM || COMPILE_TEST
+       depends on X86 || ARM || ARM64 || COMPILE_TEST
        ---help---
          Say Y here to get to see options for platform support for
          Mellanox systems. This option alone does not add any kernel code.
@@ -34,4 +34,14 @@ config MLXREG_IO
          to system resets operation, system reset causes monitoring and some
          kinds of mux selection.
 
+config MLXBF_TMFIFO
+       tristate "Mellanox BlueField SoC TmFifo platform driver"
+       depends on ARM64
+       depends on ACPI
+       depends on VIRTIO_CONSOLE && VIRTIO_NET
+       help
+         Say y here to enable TmFifo support. The TmFifo driver provides
+          platform driver support for the TmFifo which supports console
+          and networking based on the virtio framework.
+
 endif # MELLANOX_PLATFORM
index 57074d9c722c7ada0c06378a1c0dcc5cb19cef38..a229bda18fd9c8d77b6e818b266b288a5137db2f 100644 (file)
@@ -3,5 +3,6 @@
 # Makefile for linux/drivers/platform/mellanox
 # Mellanox Platform-Specific Drivers
 #
+obj-$(CONFIG_MLXBF_TMFIFO)     += mlxbf-tmfifo.o
 obj-$(CONFIG_MLXREG_HOTPLUG)   += mlxreg-hotplug.o
 obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o
diff --git a/drivers/platform/mellanox/mlxbf-tmfifo-regs.h b/drivers/platform/mellanox/mlxbf-tmfifo-regs.h
new file mode 100644 (file)
index 0000000..e4f0d2e
--- /dev/null
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019, Mellanox Technologies. All rights reserved.
+ */
+
+#ifndef __MLXBF_TMFIFO_REGS_H__
+#define __MLXBF_TMFIFO_REGS_H__
+
+#include <linux/types.h>
+#include <linux/bits.h>
+
+#define MLXBF_TMFIFO_TX_DATA                           0x00
+#define MLXBF_TMFIFO_TX_STS                            0x08
+#define MLXBF_TMFIFO_TX_STS__LENGTH                    0x0001
+#define MLXBF_TMFIFO_TX_STS__COUNT_SHIFT               0
+#define MLXBF_TMFIFO_TX_STS__COUNT_WIDTH               9
+#define MLXBF_TMFIFO_TX_STS__COUNT_RESET_VAL           0
+#define MLXBF_TMFIFO_TX_STS__COUNT_RMASK               GENMASK_ULL(8, 0)
+#define MLXBF_TMFIFO_TX_STS__COUNT_MASK                        GENMASK_ULL(8, 0)
+#define MLXBF_TMFIFO_TX_CTL                            0x10
+#define MLXBF_TMFIFO_TX_CTL__LENGTH                    0x0001
+#define MLXBF_TMFIFO_TX_CTL__LWM_SHIFT                 0
+#define MLXBF_TMFIFO_TX_CTL__LWM_WIDTH                 8
+#define MLXBF_TMFIFO_TX_CTL__LWM_RESET_VAL             128
+#define MLXBF_TMFIFO_TX_CTL__LWM_RMASK                 GENMASK_ULL(7, 0)
+#define MLXBF_TMFIFO_TX_CTL__LWM_MASK                  GENMASK_ULL(7, 0)
+#define MLXBF_TMFIFO_TX_CTL__HWM_SHIFT                 8
+#define MLXBF_TMFIFO_TX_CTL__HWM_WIDTH                 8
+#define MLXBF_TMFIFO_TX_CTL__HWM_RESET_VAL             128
+#define MLXBF_TMFIFO_TX_CTL__HWM_RMASK                 GENMASK_ULL(7, 0)
+#define MLXBF_TMFIFO_TX_CTL__HWM_MASK                  GENMASK_ULL(15, 8)
+#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_SHIFT         32
+#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_WIDTH         9
+#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_RESET_VAL     256
+#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_RMASK         GENMASK_ULL(8, 0)
+#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_MASK          GENMASK_ULL(40, 32)
+#define MLXBF_TMFIFO_RX_DATA                           0x00
+#define MLXBF_TMFIFO_RX_STS                            0x08
+#define MLXBF_TMFIFO_RX_STS__LENGTH                    0x0001
+#define MLXBF_TMFIFO_RX_STS__COUNT_SHIFT               0
+#define MLXBF_TMFIFO_RX_STS__COUNT_WIDTH               9
+#define MLXBF_TMFIFO_RX_STS__COUNT_RESET_VAL           0
+#define MLXBF_TMFIFO_RX_STS__COUNT_RMASK               GENMASK_ULL(8, 0)
+#define MLXBF_TMFIFO_RX_STS__COUNT_MASK                        GENMASK_ULL(8, 0)
+#define MLXBF_TMFIFO_RX_CTL                            0x10
+#define MLXBF_TMFIFO_RX_CTL__LENGTH                    0x0001
+#define MLXBF_TMFIFO_RX_CTL__LWM_SHIFT                 0
+#define MLXBF_TMFIFO_RX_CTL__LWM_WIDTH                 8
+#define MLXBF_TMFIFO_RX_CTL__LWM_RESET_VAL             128
+#define MLXBF_TMFIFO_RX_CTL__LWM_RMASK                 GENMASK_ULL(7, 0)
+#define MLXBF_TMFIFO_RX_CTL__LWM_MASK                  GENMASK_ULL(7, 0)
+#define MLXBF_TMFIFO_RX_CTL__HWM_SHIFT                 8
+#define MLXBF_TMFIFO_RX_CTL__HWM_WIDTH                 8
+#define MLXBF_TMFIFO_RX_CTL__HWM_RESET_VAL             128
+#define MLXBF_TMFIFO_RX_CTL__HWM_RMASK                 GENMASK_ULL(7, 0)
+#define MLXBF_TMFIFO_RX_CTL__HWM_MASK                  GENMASK_ULL(15, 8)
+#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_SHIFT         32
+#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_WIDTH         9
+#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_RESET_VAL     256
+#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_RMASK         GENMASK_ULL(8, 0)
+#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK          GENMASK_ULL(40, 32)
+
+#endif /* !defined(__MLXBF_TMFIFO_REGS_H__) */
diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c
new file mode 100644 (file)
index 0000000..9a5c9fd
--- /dev/null
@@ -0,0 +1,1281 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Mellanox BlueField SoC TmFifo driver
+ *
+ * Copyright (C) 2019 Mellanox Technologies
+ */
+
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/circ_buf.h>
+#include <linux/efi.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#include <linux/virtio_config.h>
+#include <linux/virtio_console.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_net.h>
+#include <linux/virtio_ring.h>
+
+#include "mlxbf-tmfifo-regs.h"
+
+/* Vring size. */
+#define MLXBF_TMFIFO_VRING_SIZE                        SZ_1K
+
+/* Console Tx buffer size. */
+#define MLXBF_TMFIFO_CON_TX_BUF_SIZE           SZ_32K
+
+/* Console Tx buffer reserved space. */
+#define MLXBF_TMFIFO_CON_TX_BUF_RSV_SIZE       8
+
+/* House-keeping timer interval. */
+#define MLXBF_TMFIFO_TIMER_INTERVAL            (HZ / 10)
+
+/* Virtual devices sharing the TM FIFO. */
+#define MLXBF_TMFIFO_VDEV_MAX          (VIRTIO_ID_CONSOLE + 1)
+
+/*
+ * Reserve 1/16 of TmFifo space, so console messages are not starved by
+ * the networking traffic.
+ */
+#define MLXBF_TMFIFO_RESERVE_RATIO             16
+
+/* Message with data needs at least two words (for header & data). */
+#define MLXBF_TMFIFO_DATA_MIN_WORDS            2
+
+struct mlxbf_tmfifo;
+
+/**
+ * mlxbf_tmfifo_vring - Structure of the TmFifo virtual ring
+ * @va: virtual address of the ring
+ * @dma: dma address of the ring
+ * @vq: pointer to the virtio virtqueue
+ * @desc: current descriptor of the pending packet
+ * @desc_head: head descriptor of the pending packet
+ * @cur_len: processed length of the current descriptor
+ * @rem_len: remaining length of the pending packet
+ * @pkt_len: total length of the pending packet
+ * @next_avail: next avail descriptor id
+ * @num: vring size (number of descriptors)
+ * @align: vring alignment size
+ * @index: vring index
+ * @vdev_id: vring virtio id (VIRTIO_ID_xxx)
+ * @fifo: pointer to the tmfifo structure
+ */
+struct mlxbf_tmfifo_vring {
+       void *va;
+       dma_addr_t dma;
+       struct virtqueue *vq;
+       struct vring_desc *desc;
+       struct vring_desc *desc_head;
+       int cur_len;
+       int rem_len;
+       u32 pkt_len;
+       u16 next_avail;
+       int num;
+       int align;
+       int index;
+       int vdev_id;
+       struct mlxbf_tmfifo *fifo;
+};
+
+/* Interrupt types. */
+enum {
+       MLXBF_TM_RX_LWM_IRQ,
+       MLXBF_TM_RX_HWM_IRQ,
+       MLXBF_TM_TX_LWM_IRQ,
+       MLXBF_TM_TX_HWM_IRQ,
+       MLXBF_TM_MAX_IRQ
+};
+
+/* Ring types (Rx & Tx). */
+enum {
+       MLXBF_TMFIFO_VRING_RX,
+       MLXBF_TMFIFO_VRING_TX,
+       MLXBF_TMFIFO_VRING_MAX
+};
+
+/**
+ * mlxbf_tmfifo_vdev - Structure of the TmFifo virtual device
+ * @vdev: virtio device, in which the vdev.id.device field has the
+ *        VIRTIO_ID_xxx id to distinguish the virtual device.
+ * @status: status of the device
+ * @features: supported features of the device
+ * @vrings: array of tmfifo vrings of this device
+ * @config.cons: virtual console config -
+ *               select if vdev.id.device is VIRTIO_ID_CONSOLE
+ * @config.net: virtual network config -
+ *              select if vdev.id.device is VIRTIO_ID_NET
+ * @tx_buf: tx buffer used to buffer data before writing into the FIFO
+ */
+struct mlxbf_tmfifo_vdev {
+       struct virtio_device vdev;
+       u8 status;
+       u64 features;
+       struct mlxbf_tmfifo_vring vrings[MLXBF_TMFIFO_VRING_MAX];
+       union {
+               struct virtio_console_config cons;
+               struct virtio_net_config net;
+       } config;
+       struct circ_buf tx_buf;
+};
+
+/**
+ * mlxbf_tmfifo_irq_info - Structure of the interrupt information
+ * @fifo: pointer to the tmfifo structure
+ * @irq: interrupt number
+ * @index: index into the interrupt array
+ */
+struct mlxbf_tmfifo_irq_info {
+       struct mlxbf_tmfifo *fifo;
+       int irq;
+       int index;
+};
+
+/**
+ * mlxbf_tmfifo - Structure of the TmFifo
+ * @vdev: array of the virtual devices running over the TmFifo
+ * @lock: lock to protect the TmFifo access
+ * @rx_base: mapped register base address for the Rx FIFO
+ * @tx_base: mapped register base address for the Tx FIFO
+ * @rx_fifo_size: number of entries of the Rx FIFO
+ * @tx_fifo_size: number of entries of the Tx FIFO
+ * @pend_events: pending bits for deferred events
+ * @irq_info: interrupt information
+ * @work: work struct for deferred process
+ * @timer: background timer
+ * @vring: Tx/Rx ring
+ * @spin_lock: spin lock
+ * @is_ready: ready flag
+ */
+struct mlxbf_tmfifo {
+       struct mlxbf_tmfifo_vdev *vdev[MLXBF_TMFIFO_VDEV_MAX];
+       struct mutex lock;              /* TmFifo lock */
+       void __iomem *rx_base;
+       void __iomem *tx_base;
+       int rx_fifo_size;
+       int tx_fifo_size;
+       unsigned long pend_events;
+       struct mlxbf_tmfifo_irq_info irq_info[MLXBF_TM_MAX_IRQ];
+       struct work_struct work;
+       struct timer_list timer;
+       struct mlxbf_tmfifo_vring *vring[2];
+       spinlock_t spin_lock;           /* spin lock */
+       bool is_ready;
+};
+
+/**
+ * mlxbf_tmfifo_msg_hdr - Structure of the TmFifo message header
+ * @type: message type
+ * @len: payload length in network byte order. Messages sent into the FIFO
+ *       will be read by the other side as data stream in the same byte order.
+ *       The length needs to be encoded into network order so both sides
+ *       could understand it.
+ */
+struct mlxbf_tmfifo_msg_hdr {
+       u8 type;
+       __be16 len;
+       u8 unused[5];
+} __packed __aligned(sizeof(u64));
+
+/*
+ * Default MAC.
+ * This MAC address will be read from EFI persistent variable if configured.
+ * It can also be reconfigured with standard Linux tools.
+ */
+static u8 mlxbf_tmfifo_net_default_mac[ETH_ALEN] = {
+       0x00, 0x1A, 0xCA, 0xFF, 0xFF, 0x01
+};
+
+/* EFI variable name of the MAC address. */
+static efi_char16_t mlxbf_tmfifo_efi_name[] = L"RshimMacAddr";
+
+/* Maximum L2 header length. */
+#define MLXBF_TMFIFO_NET_L2_OVERHEAD   36
+
+/* Supported virtio-net features. */
+#define MLXBF_TMFIFO_NET_FEATURES \
+       (BIT_ULL(VIRTIO_NET_F_MTU) | BIT_ULL(VIRTIO_NET_F_STATUS) | \
+        BIT_ULL(VIRTIO_NET_F_MAC))
+
+#define mlxbf_vdev_to_tmfifo(d) container_of(d, struct mlxbf_tmfifo_vdev, vdev)
+
+/* Free vrings of the FIFO device. */
+static void mlxbf_tmfifo_free_vrings(struct mlxbf_tmfifo *fifo,
+                                    struct mlxbf_tmfifo_vdev *tm_vdev)
+{
+       struct mlxbf_tmfifo_vring *vring;
+       int i, size;
+
+       for (i = 0; i < ARRAY_SIZE(tm_vdev->vrings); i++) {
+               vring = &tm_vdev->vrings[i];
+               if (vring->va) {
+                       size = vring_size(vring->num, vring->align);
+                       dma_free_coherent(tm_vdev->vdev.dev.parent, size,
+                                         vring->va, vring->dma);
+                       vring->va = NULL;
+                       if (vring->vq) {
+                               vring_del_virtqueue(vring->vq);
+                               vring->vq = NULL;
+                       }
+               }
+       }
+}
+
+/* Allocate vrings for the FIFO. */
+static int mlxbf_tmfifo_alloc_vrings(struct mlxbf_tmfifo *fifo,
+                                    struct mlxbf_tmfifo_vdev *tm_vdev)
+{
+       struct mlxbf_tmfifo_vring *vring;
+       struct device *dev;
+       dma_addr_t dma;
+       int i, size;
+       void *va;
+
+       for (i = 0; i < ARRAY_SIZE(tm_vdev->vrings); i++) {
+               vring = &tm_vdev->vrings[i];
+               vring->fifo = fifo;
+               vring->num = MLXBF_TMFIFO_VRING_SIZE;
+               vring->align = SMP_CACHE_BYTES;
+               vring->index = i;
+               vring->vdev_id = tm_vdev->vdev.id.device;
+               dev = &tm_vdev->vdev.dev;
+
+               size = vring_size(vring->num, vring->align);
+               va = dma_alloc_coherent(dev->parent, size, &dma, GFP_KERNEL);
+               if (!va) {
+                       mlxbf_tmfifo_free_vrings(fifo, tm_vdev);
+                       dev_err(dev->parent, "dma_alloc_coherent failed\n");
+                       return -ENOMEM;
+               }
+
+               vring->va = va;
+               vring->dma = dma;
+       }
+
+       return 0;
+}
+
+/* Disable interrupts of the FIFO device. */
+static void mlxbf_tmfifo_disable_irqs(struct mlxbf_tmfifo *fifo)
+{
+       int i, irq;
+
+       for (i = 0; i < MLXBF_TM_MAX_IRQ; i++) {
+               irq = fifo->irq_info[i].irq;
+               fifo->irq_info[i].irq = 0;
+               disable_irq(irq);
+       }
+}
+
+/* Interrupt handler. */
+static irqreturn_t mlxbf_tmfifo_irq_handler(int irq, void *arg)
+{
+       struct mlxbf_tmfifo_irq_info *irq_info = arg;
+
+       if (!test_and_set_bit(irq_info->index, &irq_info->fifo->pend_events))
+               schedule_work(&irq_info->fifo->work);
+
+       return IRQ_HANDLED;
+}
+
+/* Get the next packet descriptor from the vring. */
+static struct vring_desc *
+mlxbf_tmfifo_get_next_desc(struct mlxbf_tmfifo_vring *vring)
+{
+       const struct vring *vr = virtqueue_get_vring(vring->vq);
+       struct virtio_device *vdev = vring->vq->vdev;
+       unsigned int idx, head;
+
+       if (vring->next_avail == virtio16_to_cpu(vdev, vr->avail->idx))
+               return NULL;
+
+       idx = vring->next_avail % vr->num;
+       head = virtio16_to_cpu(vdev, vr->avail->ring[idx]);
+       if (WARN_ON(head >= vr->num))
+               return NULL;
+
+       vring->next_avail++;
+
+       return &vr->desc[head];
+}
+
+/* Release virtio descriptor. */
+static void mlxbf_tmfifo_release_desc(struct mlxbf_tmfifo_vring *vring,
+                                     struct vring_desc *desc, u32 len)
+{
+       const struct vring *vr = virtqueue_get_vring(vring->vq);
+       struct virtio_device *vdev = vring->vq->vdev;
+       u16 idx, vr_idx;
+
+       vr_idx = virtio16_to_cpu(vdev, vr->used->idx);
+       idx = vr_idx % vr->num;
+       vr->used->ring[idx].id = cpu_to_virtio32(vdev, desc - vr->desc);
+       vr->used->ring[idx].len = cpu_to_virtio32(vdev, len);
+
+       /*
+        * Virtio could poll and check the 'idx' to decide whether the desc is
+        * done or not. Add a memory barrier here to make sure the update above
+        * completes before updating the idx.
+        */
+       mb();
+       vr->used->idx = cpu_to_virtio16(vdev, vr_idx + 1);
+}
+
+/* Get the total length of the descriptor chain. */
+static u32 mlxbf_tmfifo_get_pkt_len(struct mlxbf_tmfifo_vring *vring,
+                                   struct vring_desc *desc)
+{
+       const struct vring *vr = virtqueue_get_vring(vring->vq);
+       struct virtio_device *vdev = vring->vq->vdev;
+       u32 len = 0, idx;
+
+       while (desc) {
+               len += virtio32_to_cpu(vdev, desc->len);
+               if (!(virtio16_to_cpu(vdev, desc->flags) & VRING_DESC_F_NEXT))
+                       break;
+               idx = virtio16_to_cpu(vdev, desc->next);
+               desc = &vr->desc[idx];
+       }
+
+       return len;
+}
+
+static void mlxbf_tmfifo_release_pending_pkt(struct mlxbf_tmfifo_vring *vring)
+{
+       struct vring_desc *desc_head;
+       u32 len = 0;
+
+       if (vring->desc_head) {
+               desc_head = vring->desc_head;
+               len = vring->pkt_len;
+       } else {
+               desc_head = mlxbf_tmfifo_get_next_desc(vring);
+               len = mlxbf_tmfifo_get_pkt_len(vring, desc_head);
+       }
+
+       if (desc_head)
+               mlxbf_tmfifo_release_desc(vring, desc_head, len);
+
+       vring->pkt_len = 0;
+       vring->desc = NULL;
+       vring->desc_head = NULL;
+}
+
+static void mlxbf_tmfifo_init_net_desc(struct mlxbf_tmfifo_vring *vring,
+                                      struct vring_desc *desc, bool is_rx)
+{
+       struct virtio_device *vdev = vring->vq->vdev;
+       struct virtio_net_hdr *net_hdr;
+
+       net_hdr = phys_to_virt(virtio64_to_cpu(vdev, desc->addr));
+       memset(net_hdr, 0, sizeof(*net_hdr));
+}
+
+/* Get and initialize the next packet. */
+static struct vring_desc *
+mlxbf_tmfifo_get_next_pkt(struct mlxbf_tmfifo_vring *vring, bool is_rx)
+{
+       struct vring_desc *desc;
+
+       desc = mlxbf_tmfifo_get_next_desc(vring);
+       if (desc && is_rx && vring->vdev_id == VIRTIO_ID_NET)
+               mlxbf_tmfifo_init_net_desc(vring, desc, is_rx);
+
+       vring->desc_head = desc;
+       vring->desc = desc;
+
+       return desc;
+}
+
+/* House-keeping timer. */
+static void mlxbf_tmfifo_timer(struct timer_list *t)
+{
+       struct mlxbf_tmfifo *fifo = container_of(t, struct mlxbf_tmfifo, timer);
+       int rx, tx;
+
+       rx = !test_and_set_bit(MLXBF_TM_RX_HWM_IRQ, &fifo->pend_events);
+       tx = !test_and_set_bit(MLXBF_TM_TX_LWM_IRQ, &fifo->pend_events);
+
+       if (rx || tx)
+               schedule_work(&fifo->work);
+
+       mod_timer(&fifo->timer, jiffies + MLXBF_TMFIFO_TIMER_INTERVAL);
+}
+
+/* Copy one console packet into the output buffer. */
+static void mlxbf_tmfifo_console_output_one(struct mlxbf_tmfifo_vdev *cons,
+                                           struct mlxbf_tmfifo_vring *vring,
+                                           struct vring_desc *desc)
+{
+       const struct vring *vr = virtqueue_get_vring(vring->vq);
+       struct virtio_device *vdev = &cons->vdev;
+       u32 len, idx, seg;
+       void *addr;
+
+       while (desc) {
+               addr = phys_to_virt(virtio64_to_cpu(vdev, desc->addr));
+               len = virtio32_to_cpu(vdev, desc->len);
+
+               seg = CIRC_SPACE_TO_END(cons->tx_buf.head, cons->tx_buf.tail,
+                                       MLXBF_TMFIFO_CON_TX_BUF_SIZE);
+               if (len <= seg) {
+                       memcpy(cons->tx_buf.buf + cons->tx_buf.head, addr, len);
+               } else {
+                       memcpy(cons->tx_buf.buf + cons->tx_buf.head, addr, seg);
+                       addr += seg;
+                       memcpy(cons->tx_buf.buf, addr, len - seg);
+               }
+               cons->tx_buf.head = (cons->tx_buf.head + len) %
+                       MLXBF_TMFIFO_CON_TX_BUF_SIZE;
+
+               if (!(virtio16_to_cpu(vdev, desc->flags) & VRING_DESC_F_NEXT))
+                       break;
+               idx = virtio16_to_cpu(vdev, desc->next);
+               desc = &vr->desc[idx];
+       }
+}
+
+/* Copy console data into the output buffer. */
+static void mlxbf_tmfifo_console_output(struct mlxbf_tmfifo_vdev *cons,
+                                       struct mlxbf_tmfifo_vring *vring)
+{
+       struct vring_desc *desc;
+       u32 len, avail;
+
+       desc = mlxbf_tmfifo_get_next_desc(vring);
+       while (desc) {
+               /* Release the packet if not enough space. */
+               len = mlxbf_tmfifo_get_pkt_len(vring, desc);
+               avail = CIRC_SPACE(cons->tx_buf.head, cons->tx_buf.tail,
+                                  MLXBF_TMFIFO_CON_TX_BUF_SIZE);
+               if (len + MLXBF_TMFIFO_CON_TX_BUF_RSV_SIZE > avail) {
+                       mlxbf_tmfifo_release_desc(vring, desc, len);
+                       break;
+               }
+
+               mlxbf_tmfifo_console_output_one(cons, vring, desc);
+               mlxbf_tmfifo_release_desc(vring, desc, len);
+               desc = mlxbf_tmfifo_get_next_desc(vring);
+       }
+}
+
+/* Get the number of available words in Rx FIFO for receiving. */
+static int mlxbf_tmfifo_get_rx_avail(struct mlxbf_tmfifo *fifo)
+{
+       u64 sts;
+
+       sts = readq(fifo->rx_base + MLXBF_TMFIFO_RX_STS);
+       return FIELD_GET(MLXBF_TMFIFO_RX_STS__COUNT_MASK, sts);
+}
+
+/* Get the number of available words in the TmFifo for sending. */
+static int mlxbf_tmfifo_get_tx_avail(struct mlxbf_tmfifo *fifo, int vdev_id)
+{
+       int tx_reserve;
+       u32 count;
+       u64 sts;
+
+       /* Reserve some room in FIFO for console messages. */
+       if (vdev_id == VIRTIO_ID_NET)
+               tx_reserve = fifo->tx_fifo_size / MLXBF_TMFIFO_RESERVE_RATIO;
+       else
+               tx_reserve = 1;
+
+       sts = readq(fifo->tx_base + MLXBF_TMFIFO_TX_STS);
+       count = FIELD_GET(MLXBF_TMFIFO_TX_STS__COUNT_MASK, sts);
+       return fifo->tx_fifo_size - tx_reserve - count;
+}
+
+/* Console Tx (move data from the output buffer into the TmFifo). */
+static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail)
+{
+       struct mlxbf_tmfifo_msg_hdr hdr;
+       struct mlxbf_tmfifo_vdev *cons;
+       unsigned long flags;
+       int size, seg;
+       void *addr;
+       u64 data;
+
+       /* Return if not enough space available. */
+       if (avail < MLXBF_TMFIFO_DATA_MIN_WORDS)
+               return;
+
+       cons = fifo->vdev[VIRTIO_ID_CONSOLE];
+       if (!cons || !cons->tx_buf.buf)
+               return;
+
+       /* Return if no data to send. */
+       size = CIRC_CNT(cons->tx_buf.head, cons->tx_buf.tail,
+                       MLXBF_TMFIFO_CON_TX_BUF_SIZE);
+       if (size == 0)
+               return;
+
+       /* Adjust the size to available space. */
+       if (size + sizeof(hdr) > avail * sizeof(u64))
+               size = avail * sizeof(u64) - sizeof(hdr);
+
+       /* Write header. */
+       hdr.type = VIRTIO_ID_CONSOLE;
+       hdr.len = htons(size);
+       writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
+
+       /* Use spin-lock to protect the 'cons->tx_buf'. */
+       spin_lock_irqsave(&fifo->spin_lock, flags);
+
+       while (size > 0) {
+               addr = cons->tx_buf.buf + cons->tx_buf.tail;
+
+               seg = CIRC_CNT_TO_END(cons->tx_buf.head, cons->tx_buf.tail,
+                                     MLXBF_TMFIFO_CON_TX_BUF_SIZE);
+               if (seg >= sizeof(u64)) {
+                       memcpy(&data, addr, sizeof(u64));
+               } else {
+                       memcpy(&data, addr, seg);
+                       memcpy((u8 *)&data + seg, cons->tx_buf.buf,
+                              sizeof(u64) - seg);
+               }
+               writeq(data, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
+
+               if (size >= sizeof(u64)) {
+                       cons->tx_buf.tail = (cons->tx_buf.tail + sizeof(u64)) %
+                               MLXBF_TMFIFO_CON_TX_BUF_SIZE;
+                       size -= sizeof(u64);
+               } else {
+                       cons->tx_buf.tail = (cons->tx_buf.tail + size) %
+                               MLXBF_TMFIFO_CON_TX_BUF_SIZE;
+                       size = 0;
+               }
+       }
+
+       spin_unlock_irqrestore(&fifo->spin_lock, flags);
+}
+
+/* Rx/Tx one word in the descriptor buffer. */
+static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring,
+                                  struct vring_desc *desc,
+                                  bool is_rx, int len)
+{
+       struct virtio_device *vdev = vring->vq->vdev;
+       struct mlxbf_tmfifo *fifo = vring->fifo;
+       void *addr;
+       u64 data;
+
+       /* Get the buffer address of this desc. */
+       addr = phys_to_virt(virtio64_to_cpu(vdev, desc->addr));
+
+       /* Read a word from FIFO for Rx. */
+       if (is_rx)
+               data = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA);
+
+       if (vring->cur_len + sizeof(u64) <= len) {
+               /* The whole word. */
+               if (is_rx)
+                       memcpy(addr + vring->cur_len, &data, sizeof(u64));
+               else
+                       memcpy(&data, addr + vring->cur_len, sizeof(u64));
+               vring->cur_len += sizeof(u64);
+       } else {
+               /* Leftover bytes. */
+               if (is_rx)
+                       memcpy(addr + vring->cur_len, &data,
+                              len - vring->cur_len);
+               else
+                       memcpy(&data, addr + vring->cur_len,
+                              len - vring->cur_len);
+               vring->cur_len = len;
+       }
+
+       /* Write the word into FIFO for Tx. */
+       if (!is_rx)
+               writeq(data, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
+}
+
+/*
+ * Rx/Tx packet header.
+ *
+ * In Rx case, the packet might be found to belong to a different vring since
+ * the TmFifo is shared by different services. In such case, the 'vring_change'
+ * flag is set.
+ */
+static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring,
+                                    struct vring_desc *desc,
+                                    bool is_rx, bool *vring_change)
+{
+       struct mlxbf_tmfifo *fifo = vring->fifo;
+       struct virtio_net_config *config;
+       struct mlxbf_tmfifo_msg_hdr hdr;
+       int vdev_id, hdr_len;
+
+       /* Read/Write packet header. */
+       if (is_rx) {
+               /* Drain one word from the FIFO. */
+               *(u64 *)&hdr = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA);
+
+               /* Skip the length 0 packets (keepalive). */
+               if (hdr.len == 0)
+                       return;
+
+               /* Check packet type. */
+               if (hdr.type == VIRTIO_ID_NET) {
+                       vdev_id = VIRTIO_ID_NET;
+                       hdr_len = sizeof(struct virtio_net_hdr);
+                       config = &fifo->vdev[vdev_id]->config.net;
+                       if (ntohs(hdr.len) > config->mtu +
+                           MLXBF_TMFIFO_NET_L2_OVERHEAD)
+                               return;
+               } else {
+                       vdev_id = VIRTIO_ID_CONSOLE;
+                       hdr_len = 0;
+               }
+
+               /*
+                * Check whether the new packet still belongs to this vring.
+                * If not, update the pkt_len of the new vring.
+                */
+               if (vdev_id != vring->vdev_id) {
+                       struct mlxbf_tmfifo_vdev *tm_dev2 = fifo->vdev[vdev_id];
+
+                       if (!tm_dev2)
+                               return;
+                       vring->desc = desc;
+                       vring = &tm_dev2->vrings[MLXBF_TMFIFO_VRING_RX];
+                       *vring_change = true;
+               }
+               vring->pkt_len = ntohs(hdr.len) + hdr_len;
+       } else {
+               /* Network virtio has an extra header. */
+               hdr_len = (vring->vdev_id == VIRTIO_ID_NET) ?
+                          sizeof(struct virtio_net_hdr) : 0;
+               vring->pkt_len = mlxbf_tmfifo_get_pkt_len(vring, desc);
+               hdr.type = (vring->vdev_id == VIRTIO_ID_NET) ?
+                           VIRTIO_ID_NET : VIRTIO_ID_CONSOLE;
+               hdr.len = htons(vring->pkt_len - hdr_len);
+               writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
+       }
+
+       vring->cur_len = hdr_len;
+       vring->rem_len = vring->pkt_len;
+       fifo->vring[is_rx] = vring;
+}
+
+/*
+ * Rx/Tx one descriptor.
+ *
+ * Return true to indicate more data available.
+ */
+static bool mlxbf_tmfifo_rxtx_one_desc(struct mlxbf_tmfifo_vring *vring,
+                                      bool is_rx, int *avail)
+{
+       const struct vring *vr = virtqueue_get_vring(vring->vq);
+       struct mlxbf_tmfifo *fifo = vring->fifo;
+       struct virtio_device *vdev;
+       bool vring_change = false;
+       struct vring_desc *desc;
+       unsigned long flags;
+       u32 len, idx;
+
+       vdev = &fifo->vdev[vring->vdev_id]->vdev;
+
+       /* Get the descriptor of the next packet. */
+       if (!vring->desc) {
+               desc = mlxbf_tmfifo_get_next_pkt(vring, is_rx);
+               if (!desc)
+                       return false;
+       } else {
+               desc = vring->desc;
+       }
+
+       /* Beginning of a packet. Start to Rx/Tx packet header. */
+       if (vring->pkt_len == 0) {
+               mlxbf_tmfifo_rxtx_header(vring, desc, is_rx, &vring_change);
+               (*avail)--;
+
+               /* Return if new packet is for another ring. */
+               if (vring_change)
+                       return false;
+               goto mlxbf_tmfifo_desc_done;
+       }
+
+       /* Get the length of this desc. */
+       len = virtio32_to_cpu(vdev, desc->len);
+       if (len > vring->rem_len)
+               len = vring->rem_len;
+
+       /* Rx/Tx one word (8 bytes) if not done. */
+       if (vring->cur_len < len) {
+               mlxbf_tmfifo_rxtx_word(vring, desc, is_rx, len);
+               (*avail)--;
+       }
+
+       /* Check again whether it's done. */
+       if (vring->cur_len == len) {
+               vring->cur_len = 0;
+               vring->rem_len -= len;
+
+               /* Get the next desc on the chain. */
+               if (vring->rem_len > 0 &&
+                   (virtio16_to_cpu(vdev, desc->flags) & VRING_DESC_F_NEXT)) {
+                       idx = virtio16_to_cpu(vdev, desc->next);
+                       desc = &vr->desc[idx];
+                       goto mlxbf_tmfifo_desc_done;
+               }
+
+               /* Done and release the pending packet. */
+               mlxbf_tmfifo_release_pending_pkt(vring);
+               desc = NULL;
+               fifo->vring[is_rx] = NULL;
+
+               /* Notify upper layer that packet is done. */
+               spin_lock_irqsave(&fifo->spin_lock, flags);
+               vring_interrupt(0, vring->vq);
+               spin_unlock_irqrestore(&fifo->spin_lock, flags);
+       }
+
+mlxbf_tmfifo_desc_done:
+       /* Save the current desc. */
+       vring->desc = desc;
+
+       return true;
+}
+
+/* Rx & Tx processing of a queue. */
+static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
+{
+       int avail = 0, devid = vring->vdev_id;
+       struct mlxbf_tmfifo *fifo;
+       bool more;
+
+       fifo = vring->fifo;
+
+       /* Return if vdev is not ready. */
+       if (!fifo->vdev[devid])
+               return;
+
+       /* Return if another vring is running. */
+       if (fifo->vring[is_rx] && fifo->vring[is_rx] != vring)
+               return;
+
+       /* Only handle console and network for now. */
+       if (WARN_ON(devid != VIRTIO_ID_NET && devid != VIRTIO_ID_CONSOLE))
+               return;
+
+       do {
+               /* Get available FIFO space. */
+               if (avail == 0) {
+                       if (is_rx)
+                               avail = mlxbf_tmfifo_get_rx_avail(fifo);
+                       else
+                               avail = mlxbf_tmfifo_get_tx_avail(fifo, devid);
+                       if (avail <= 0)
+                               break;
+               }
+
+               /* Console output always comes from the Tx buffer. */
+               if (!is_rx && devid == VIRTIO_ID_CONSOLE) {
+                       mlxbf_tmfifo_console_tx(fifo, avail);
+                       break;
+               }
+
+               /* Handle one descriptor. */
+               more = mlxbf_tmfifo_rxtx_one_desc(vring, is_rx, &avail);
+       } while (more);
+}
+
+/* Handle Rx or Tx queues. */
+static void mlxbf_tmfifo_work_rxtx(struct mlxbf_tmfifo *fifo, int queue_id,
+                                  int irq_id, bool is_rx)
+{
+       struct mlxbf_tmfifo_vdev *tm_vdev;
+       struct mlxbf_tmfifo_vring *vring;
+       int i;
+
+       if (!test_and_clear_bit(irq_id, &fifo->pend_events) ||
+           !fifo->irq_info[irq_id].irq)
+               return;
+
+       for (i = 0; i < MLXBF_TMFIFO_VDEV_MAX; i++) {
+               tm_vdev = fifo->vdev[i];
+               if (tm_vdev) {
+                       vring = &tm_vdev->vrings[queue_id];
+                       if (vring->vq)
+                               mlxbf_tmfifo_rxtx(vring, is_rx);
+               }
+       }
+}
+
+/* Work handler for Rx and Tx case. */
+static void mlxbf_tmfifo_work_handler(struct work_struct *work)
+{
+       struct mlxbf_tmfifo *fifo;
+
+       fifo = container_of(work, struct mlxbf_tmfifo, work);
+       if (!fifo->is_ready)
+               return;
+
+       mutex_lock(&fifo->lock);
+
+       /* Tx (Send data to the TmFifo). */
+       mlxbf_tmfifo_work_rxtx(fifo, MLXBF_TMFIFO_VRING_TX,
+                              MLXBF_TM_TX_LWM_IRQ, false);
+
+       /* Rx (Receive data from the TmFifo). */
+       mlxbf_tmfifo_work_rxtx(fifo, MLXBF_TMFIFO_VRING_RX,
+                              MLXBF_TM_RX_HWM_IRQ, true);
+
+       mutex_unlock(&fifo->lock);
+}
+
+/* The notify function is called when new buffers are posted. */
+static bool mlxbf_tmfifo_virtio_notify(struct virtqueue *vq)
+{
+       struct mlxbf_tmfifo_vring *vring = vq->priv;
+       struct mlxbf_tmfifo_vdev *tm_vdev;
+       struct mlxbf_tmfifo *fifo;
+       unsigned long flags;
+
+       fifo = vring->fifo;
+
+       /*
+        * Virtio maintains vrings in pairs, even number ring for Rx
+        * and odd number ring for Tx.
+        */
+       if (vring->index & BIT(0)) {
+               /*
+                * Console could make blocking call with interrupts disabled.
+                * In such case, the vring needs to be served right away. For
+                * other cases, just set the TX LWM bit to start Tx in the
+                * worker handler.
+                */
+               if (vring->vdev_id == VIRTIO_ID_CONSOLE) {
+                       spin_lock_irqsave(&fifo->spin_lock, flags);
+                       tm_vdev = fifo->vdev[VIRTIO_ID_CONSOLE];
+                       mlxbf_tmfifo_console_output(tm_vdev, vring);
+                       spin_unlock_irqrestore(&fifo->spin_lock, flags);
+               } else if (test_and_set_bit(MLXBF_TM_TX_LWM_IRQ,
+                                           &fifo->pend_events)) {
+                       return true;
+               }
+       } else {
+               if (test_and_set_bit(MLXBF_TM_RX_HWM_IRQ, &fifo->pend_events))
+                       return true;
+       }
+
+       schedule_work(&fifo->work);
+
+       return true;
+}
+
+/* Get the array of feature bits for this device. */
+static u64 mlxbf_tmfifo_virtio_get_features(struct virtio_device *vdev)
+{
+       struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
+
+       return tm_vdev->features;
+}
+
+/* Confirm device features to use. */
+static int mlxbf_tmfifo_virtio_finalize_features(struct virtio_device *vdev)
+{
+       struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
+
+       tm_vdev->features = vdev->features;
+
+       return 0;
+}
+
+/* Free virtqueues found by find_vqs(). */
+static void mlxbf_tmfifo_virtio_del_vqs(struct virtio_device *vdev)
+{
+       struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
+       struct mlxbf_tmfifo_vring *vring;
+       struct virtqueue *vq;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(tm_vdev->vrings); i++) {
+               vring = &tm_vdev->vrings[i];
+
+               /* Release the pending packet. */
+               if (vring->desc)
+                       mlxbf_tmfifo_release_pending_pkt(vring);
+               vq = vring->vq;
+               if (vq) {
+                       vring->vq = NULL;
+                       vring_del_virtqueue(vq);
+               }
+       }
+}
+
+/* Create and initialize the virtual queues. */
+static int mlxbf_tmfifo_virtio_find_vqs(struct virtio_device *vdev,
+                                       unsigned int nvqs,
+                                       struct virtqueue *vqs[],
+                                       vq_callback_t *callbacks[],
+                                       const char * const names[],
+                                       const bool *ctx,
+                                       struct irq_affinity *desc)
+{
+       struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
+       struct mlxbf_tmfifo_vring *vring;
+       struct virtqueue *vq;
+       int i, ret, size;
+
+       if (nvqs > ARRAY_SIZE(tm_vdev->vrings))
+               return -EINVAL;
+
+       for (i = 0; i < nvqs; ++i) {
+               if (!names[i]) {
+                       ret = -EINVAL;
+                       goto error;
+               }
+               vring = &tm_vdev->vrings[i];
+
+               /* zero vring */
+               size = vring_size(vring->num, vring->align);
+               memset(vring->va, 0, size);
+               vq = vring_new_virtqueue(i, vring->num, vring->align, vdev,
+                                        false, false, vring->va,
+                                        mlxbf_tmfifo_virtio_notify,
+                                        callbacks[i], names[i]);
+               if (!vq) {
+                       dev_err(&vdev->dev, "vring_new_virtqueue failed\n");
+                       ret = -ENOMEM;
+                       goto error;
+               }
+
+               vqs[i] = vq;
+               vring->vq = vq;
+               vq->priv = vring;
+       }
+
+       return 0;
+
+error:
+       mlxbf_tmfifo_virtio_del_vqs(vdev);
+       return ret;
+}
+
+/* Read the status byte. */
+static u8 mlxbf_tmfifo_virtio_get_status(struct virtio_device *vdev)
+{
+       struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
+
+       return tm_vdev->status;
+}
+
+/* Write the status byte. */
+static void mlxbf_tmfifo_virtio_set_status(struct virtio_device *vdev,
+                                          u8 status)
+{
+       struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
+
+       tm_vdev->status = status;
+}
+
+/* Reset the device. Not much here for now. */
+static void mlxbf_tmfifo_virtio_reset(struct virtio_device *vdev)
+{
+       struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
+
+       tm_vdev->status = 0;
+}
+
+/* Read the value of a configuration field. */
+static void mlxbf_tmfifo_virtio_get(struct virtio_device *vdev,
+                                   unsigned int offset,
+                                   void *buf,
+                                   unsigned int len)
+{
+       struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
+
+       if ((u64)offset + len > sizeof(tm_vdev->config))
+               return;
+
+       memcpy(buf, (u8 *)&tm_vdev->config + offset, len);
+}
+
+/* Write the value of a configuration field. */
+static void mlxbf_tmfifo_virtio_set(struct virtio_device *vdev,
+                                   unsigned int offset,
+                                   const void *buf,
+                                   unsigned int len)
+{
+       struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
+
+       if ((u64)offset + len > sizeof(tm_vdev->config))
+               return;
+
+       memcpy((u8 *)&tm_vdev->config + offset, buf, len);
+}
+
+static void tmfifo_virtio_dev_release(struct device *device)
+{
+       struct virtio_device *vdev =
+                       container_of(device, struct virtio_device, dev);
+       struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev);
+
+       kfree(tm_vdev);
+}
+
+/* Virtio config operations. */
+static const struct virtio_config_ops mlxbf_tmfifo_virtio_config_ops = {
+       .get_features = mlxbf_tmfifo_virtio_get_features,
+       .finalize_features = mlxbf_tmfifo_virtio_finalize_features,
+       .find_vqs = mlxbf_tmfifo_virtio_find_vqs,
+       .del_vqs = mlxbf_tmfifo_virtio_del_vqs,
+       .reset = mlxbf_tmfifo_virtio_reset,
+       .set_status = mlxbf_tmfifo_virtio_set_status,
+       .get_status = mlxbf_tmfifo_virtio_get_status,
+       .get = mlxbf_tmfifo_virtio_get,
+       .set = mlxbf_tmfifo_virtio_set,
+};
+
+/* Create vdev for the FIFO. */
+static int mlxbf_tmfifo_create_vdev(struct device *dev,
+                                   struct mlxbf_tmfifo *fifo,
+                                   int vdev_id, u64 features,
+                                   void *config, u32 size)
+{
+       struct mlxbf_tmfifo_vdev *tm_vdev, *reg_dev = NULL;
+       int ret;
+
+       mutex_lock(&fifo->lock);
+
+       tm_vdev = fifo->vdev[vdev_id];
+       if (tm_vdev) {
+               dev_err(dev, "vdev %d already exists\n", vdev_id);
+               ret = -EEXIST;
+               goto fail;
+       }
+
+       tm_vdev = kzalloc(sizeof(*tm_vdev), GFP_KERNEL);
+       if (!tm_vdev) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       tm_vdev->vdev.id.device = vdev_id;
+       tm_vdev->vdev.config = &mlxbf_tmfifo_virtio_config_ops;
+       tm_vdev->vdev.dev.parent = dev;
+       tm_vdev->vdev.dev.release = tmfifo_virtio_dev_release;
+       tm_vdev->features = features;
+       if (config)
+               memcpy(&tm_vdev->config, config, size);
+
+       if (mlxbf_tmfifo_alloc_vrings(fifo, tm_vdev)) {
+               dev_err(dev, "unable to allocate vring\n");
+               ret = -ENOMEM;
+               goto vdev_fail;
+       }
+
+       /* Allocate an output buffer for the console device. */
+       if (vdev_id == VIRTIO_ID_CONSOLE)
+               tm_vdev->tx_buf.buf = devm_kmalloc(dev,
+                                                  MLXBF_TMFIFO_CON_TX_BUF_SIZE,
+                                                  GFP_KERNEL);
+       fifo->vdev[vdev_id] = tm_vdev;
+
+       /* Register the virtio device. */
+       ret = register_virtio_device(&tm_vdev->vdev);
+       reg_dev = tm_vdev;
+       if (ret) {
+               dev_err(dev, "register_virtio_device failed\n");
+               goto vdev_fail;
+       }
+
+       mutex_unlock(&fifo->lock);
+       return 0;
+
+vdev_fail:
+       mlxbf_tmfifo_free_vrings(fifo, tm_vdev);
+       fifo->vdev[vdev_id] = NULL;
+       if (reg_dev)
+               put_device(&tm_vdev->vdev.dev);
+       else
+               kfree(tm_vdev);
+fail:
+       mutex_unlock(&fifo->lock);
+       return ret;
+}
+
+/* Delete vdev for the FIFO. */
+static int mlxbf_tmfifo_delete_vdev(struct mlxbf_tmfifo *fifo, int vdev_id)
+{
+       struct mlxbf_tmfifo_vdev *tm_vdev;
+
+       mutex_lock(&fifo->lock);
+
+       /* Unregister vdev. */
+       tm_vdev = fifo->vdev[vdev_id];
+       if (tm_vdev) {
+               unregister_virtio_device(&tm_vdev->vdev);
+               mlxbf_tmfifo_free_vrings(fifo, tm_vdev);
+               fifo->vdev[vdev_id] = NULL;
+       }
+
+       mutex_unlock(&fifo->lock);
+
+       return 0;
+}
+
+/* Read the configured network MAC address from efi variable. */
+static void mlxbf_tmfifo_get_cfg_mac(u8 *mac)
+{
+       efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID;
+       unsigned long size = ETH_ALEN;
+       u8 buf[ETH_ALEN];
+       efi_status_t rc;
+
+       rc = efi.get_variable(mlxbf_tmfifo_efi_name, &guid, NULL, &size, buf);
+       if (rc == EFI_SUCCESS && size == ETH_ALEN)
+               ether_addr_copy(mac, buf);
+       else
+               ether_addr_copy(mac, mlxbf_tmfifo_net_default_mac);
+}
+
+/* Set TmFifo thresolds which is used to trigger interrupts. */
+static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo)
+{
+       u64 ctl;
+
+       /* Get Tx FIFO size and set the low/high watermark. */
+       ctl = readq(fifo->tx_base + MLXBF_TMFIFO_TX_CTL);
+       fifo->tx_fifo_size =
+               FIELD_GET(MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_MASK, ctl);
+       ctl = (ctl & ~MLXBF_TMFIFO_TX_CTL__LWM_MASK) |
+               FIELD_PREP(MLXBF_TMFIFO_TX_CTL__LWM_MASK,
+                          fifo->tx_fifo_size / 2);
+       ctl = (ctl & ~MLXBF_TMFIFO_TX_CTL__HWM_MASK) |
+               FIELD_PREP(MLXBF_TMFIFO_TX_CTL__HWM_MASK,
+                          fifo->tx_fifo_size - 1);
+       writeq(ctl, fifo->tx_base + MLXBF_TMFIFO_TX_CTL);
+
+       /* Get Rx FIFO size and set the low/high watermark. */
+       ctl = readq(fifo->rx_base + MLXBF_TMFIFO_RX_CTL);
+       fifo->rx_fifo_size =
+               FIELD_GET(MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK, ctl);
+       ctl = (ctl & ~MLXBF_TMFIFO_RX_CTL__LWM_MASK) |
+               FIELD_PREP(MLXBF_TMFIFO_RX_CTL__LWM_MASK, 0);
+       ctl = (ctl & ~MLXBF_TMFIFO_RX_CTL__HWM_MASK) |
+               FIELD_PREP(MLXBF_TMFIFO_RX_CTL__HWM_MASK, 1);
+       writeq(ctl, fifo->rx_base + MLXBF_TMFIFO_RX_CTL);
+}
+
+static void mlxbf_tmfifo_cleanup(struct mlxbf_tmfifo *fifo)
+{
+       int i;
+
+       fifo->is_ready = false;
+       del_timer_sync(&fifo->timer);
+       mlxbf_tmfifo_disable_irqs(fifo);
+       cancel_work_sync(&fifo->work);
+       for (i = 0; i < MLXBF_TMFIFO_VDEV_MAX; i++)
+               mlxbf_tmfifo_delete_vdev(fifo, i);
+}
+
+/* Probe the TMFIFO. */
+static int mlxbf_tmfifo_probe(struct platform_device *pdev)
+{
+       struct virtio_net_config net_config;
+       struct device *dev = &pdev->dev;
+       struct mlxbf_tmfifo *fifo;
+       int i, rc;
+
+       fifo = devm_kzalloc(dev, sizeof(*fifo), GFP_KERNEL);
+       if (!fifo)
+               return -ENOMEM;
+
+       spin_lock_init(&fifo->spin_lock);
+       INIT_WORK(&fifo->work, mlxbf_tmfifo_work_handler);
+       mutex_init(&fifo->lock);
+
+       /* Get the resource of the Rx FIFO. */
+       fifo->rx_base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(fifo->rx_base))
+               return PTR_ERR(fifo->rx_base);
+
+       /* Get the resource of the Tx FIFO. */
+       fifo->tx_base = devm_platform_ioremap_resource(pdev, 1);
+       if (IS_ERR(fifo->tx_base))
+               return PTR_ERR(fifo->tx_base);
+
+       platform_set_drvdata(pdev, fifo);
+
+       timer_setup(&fifo->timer, mlxbf_tmfifo_timer, 0);
+
+       for (i = 0; i < MLXBF_TM_MAX_IRQ; i++) {
+               fifo->irq_info[i].index = i;
+               fifo->irq_info[i].fifo = fifo;
+               fifo->irq_info[i].irq = platform_get_irq(pdev, i);
+               rc = devm_request_irq(dev, fifo->irq_info[i].irq,
+                                     mlxbf_tmfifo_irq_handler, 0,
+                                     "tmfifo", &fifo->irq_info[i]);
+               if (rc) {
+                       dev_err(dev, "devm_request_irq failed\n");
+                       fifo->irq_info[i].irq = 0;
+                       return rc;
+               }
+       }
+
+       mlxbf_tmfifo_set_threshold(fifo);
+
+       /* Create the console vdev. */
+       rc = mlxbf_tmfifo_create_vdev(dev, fifo, VIRTIO_ID_CONSOLE, 0, NULL, 0);
+       if (rc)
+               goto fail;
+
+       /* Create the network vdev. */
+       memset(&net_config, 0, sizeof(net_config));
+       net_config.mtu = ETH_DATA_LEN;
+       net_config.status = VIRTIO_NET_S_LINK_UP;
+       mlxbf_tmfifo_get_cfg_mac(net_config.mac);
+       rc = mlxbf_tmfifo_create_vdev(dev, fifo, VIRTIO_ID_NET,
+                                     MLXBF_TMFIFO_NET_FEATURES, &net_config,
+                                     sizeof(net_config));
+       if (rc)
+               goto fail;
+
+       mod_timer(&fifo->timer, jiffies + MLXBF_TMFIFO_TIMER_INTERVAL);
+
+       fifo->is_ready = true;
+       return 0;
+
+fail:
+       mlxbf_tmfifo_cleanup(fifo);
+       return rc;
+}
+
+/* Device remove function. */
+static int mlxbf_tmfifo_remove(struct platform_device *pdev)
+{
+       struct mlxbf_tmfifo *fifo = platform_get_drvdata(pdev);
+
+       mlxbf_tmfifo_cleanup(fifo);
+
+       return 0;
+}
+
+static const struct acpi_device_id mlxbf_tmfifo_acpi_match[] = {
+       { "MLNXBF01", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(acpi, mlxbf_tmfifo_acpi_match);
+
+static struct platform_driver mlxbf_tmfifo_driver = {
+       .probe = mlxbf_tmfifo_probe,
+       .remove = mlxbf_tmfifo_remove,
+       .driver = {
+               .name = "bf-tmfifo",
+               .acpi_match_table = mlxbf_tmfifo_acpi_match,
+       },
+};
+
+module_platform_driver(mlxbf_tmfifo_driver);
+
+MODULE_DESCRIPTION("Mellanox BlueField SoC TmFifo Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Mellanox Technologies");
index a1ed131835595f621e344792a975cff6d55faba9..85b92a95e4c88566a0b3be8eaa00fc4796f46770 100644 (file)
@@ -1263,6 +1263,17 @@ config INTEL_CHTDC_TI_PWRBTN
          To compile this driver as a module, choose M here: the module
          will be called intel_chtdc_ti_pwrbtn.
 
+config INTEL_MRFLD_PWRBTN
+       tristate "Intel Merrifield Basin Cove power button driver"
+       depends on INTEL_SOC_PMIC_MRFLD
+       depends on INPUT
+       ---help---
+         This option adds a power button driver for Basin Cove PMIC
+         on Intel Merrifield devices.
+
+         To compile this driver as a module, choose M here: the module
+         will be called intel_mrfld_pwrbtn.
+
 config I2C_MULTI_INSTANTIATE
        tristate "I2C multi instantiate pseudo device driver"
        depends on I2C && ACPI
index 86cb76677bc8b7d1ecd31a9ec05ff72820d43a5a..87b0069bd781ee9a165d35879a8645f58aa359c7 100644 (file)
@@ -94,6 +94,7 @@ obj-$(CONFIG_PMC_ATOM)                += pmc_atom.o
 obj-$(CONFIG_MLX_PLATFORM)     += mlx-platform.o
 obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
 obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN)    += intel_chtdc_ti_pwrbtn.o
+obj-$(CONFIG_INTEL_MRFLD_PWRBTN)       += intel_mrfld_pwrbtn.o
 obj-$(CONFIG_I2C_MULTI_INSTANTIATE)    += i2c-multi-instantiate.o
 obj-$(CONFIG_INTEL_ATOMISP2_PM)        += intel_atomisp2_pm.o
 obj-$(CONFIG_PCENGINES_APU2)   += pcengines-apuv2.o
index f10af5c383c551d7632d0e66b751792ae9dc7abd..83fd7677af24c1f7f82aa0295eca0afcc0101d0b 100644 (file)
@@ -522,23 +522,22 @@ static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args,
 
        input.length = (acpi_size) sizeof(*in_args);
        input.pointer = in_args;
-       if (out_data != NULL) {
+       if (out_data) {
                output.length = ACPI_ALLOCATE_BUFFER;
                output.pointer = NULL;
                status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
                                             command, &input, &output);
-       } else
+               if (ACPI_SUCCESS(status)) {
+                       obj = (union acpi_object *)output.pointer;
+                       if (obj && obj->type == ACPI_TYPE_INTEGER)
+                               *out_data = (u32)obj->integer.value;
+               }
+               kfree(output.pointer);
+       } else {
                status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
                                             command, &input, NULL);
-
-       if (ACPI_SUCCESS(status) && out_data != NULL) {
-               obj = (union acpi_object *)output.pointer;
-               if (obj && obj->type == ACPI_TYPE_INTEGER)
-                       *out_data = (u32) obj->integer.value;
        }
-       kfree(output.pointer);
        return status;
-
 }
 
 /*
@@ -588,7 +587,7 @@ static ssize_t show_hdmi_source(struct device *dev,
                        return scnprintf(buf, PAGE_SIZE,
                                         "input [gpu] unknown\n");
        }
-       pr_err("alienware-wmi: unknown HDMI source status: %d\n", out_data);
+       pr_err("alienware-wmi: unknown HDMI source status: %u\n", status);
        return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n");
 }
 
index ee1fa93708ec7ba970a0a166938ee97c1a4287de..f94691615881e68515215242fd957d7dff6df393 100644 (file)
@@ -66,10 +66,13 @@ MODULE_LICENSE("GPL");
 #define NOTIFY_BRNUP_MAX               0x1f
 #define NOTIFY_BRNDOWN_MIN             0x20
 #define NOTIFY_BRNDOWN_MAX             0x2e
+#define NOTIFY_FNLOCK_TOGGLE           0x4e
 #define NOTIFY_KBD_BRTUP               0xc4
 #define NOTIFY_KBD_BRTDWN              0xc5
 #define NOTIFY_KBD_BRTTOGGLE           0xc7
 
+#define ASUS_WMI_FNLOCK_BIOS_DISABLED  BIT(0)
+
 #define ASUS_FAN_DESC                  "cpu_fan"
 #define ASUS_FAN_MFUN                  0x13
 #define ASUS_FAN_SFUN_READ             0x06
@@ -177,6 +180,8 @@ struct asus_wmi {
        struct workqueue_struct *hotplug_workqueue;
        struct work_struct hotplug_work;
 
+       bool fnlock_locked;
+
        struct asus_wmi_debug debug;
 
        struct asus_wmi_driver *driver;
@@ -1619,6 +1624,23 @@ static int is_display_toggle(int code)
        return 0;
 }
 
+static bool asus_wmi_has_fnlock_key(struct asus_wmi *asus)
+{
+       u32 result;
+
+       asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FNLOCK, &result);
+
+       return (result & ASUS_WMI_DSTS_PRESENCE_BIT) &&
+               !(result & ASUS_WMI_FNLOCK_BIOS_DISABLED);
+}
+
+static void asus_wmi_fnlock_update(struct asus_wmi *asus)
+{
+       int mode = asus->fnlock_locked;
+
+       asus_wmi_set_devstate(ASUS_WMI_DEVID_FNLOCK, mode, NULL);
+}
+
 static void asus_wmi_notify(u32 value, void *context)
 {
        struct asus_wmi *asus = context;
@@ -1680,6 +1702,12 @@ static void asus_wmi_notify(u32 value, void *context)
                goto exit;
        }
 
+       if (code == NOTIFY_FNLOCK_TOGGLE) {
+               asus->fnlock_locked = !asus->fnlock_locked;
+               asus_wmi_fnlock_update(asus);
+               goto exit;
+       }
+
        if (is_display_toggle(code) &&
            asus->driver->quirks->no_display_toggle)
                goto exit;
@@ -2134,6 +2162,11 @@ static int asus_wmi_add(struct platform_device *pdev)
        } else
                err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL);
 
+       if (asus_wmi_has_fnlock_key(asus)) {
+               asus->fnlock_locked = true;
+               asus_wmi_fnlock_update(asus);
+       }
+
        status = wmi_install_notify_handler(asus->driver->event_guid,
                                            asus_wmi_notify, asus);
        if (ACPI_FAILURE(status)) {
@@ -2213,6 +2246,8 @@ static int asus_hotk_resume(struct device *device)
        if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
                kbd_led_update(asus);
 
+       if (asus_wmi_has_fnlock_key(asus))
+               asus_wmi_fnlock_update(asus);
        return 0;
 }
 
@@ -2249,6 +2284,8 @@ static int asus_hotk_restore(struct device *device)
        if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
                kbd_led_update(asus);
 
+       if (asus_wmi_has_fnlock_key(asus))
+               asus_wmi_fnlock_update(asus);
        return 0;
 }
 
index 95e6ca116e00e2932e8dbcce678ca3489c31b5dc..a561f653cf134ceae3ca4c4fc02236fd16d5b01e 100644 (file)
@@ -531,7 +531,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data)
                return;
        }
 
-       dell_fill_request(&buffer, 0, 0x2, 0, 0);
+       dell_fill_request(&buffer, 0x2, 0, 0, 0);
        ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
        hwswitch = buffer.output[1];
 
@@ -562,7 +562,7 @@ static int dell_debugfs_show(struct seq_file *s, void *data)
                return ret;
        status = buffer.output[1];
 
-       dell_fill_request(&buffer, 0, 0x2, 0, 0);
+       dell_fill_request(&buffer, 0x2, 0, 0, 0);
        hwswitch_ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
        if (hwswitch_ret)
                return hwswitch_ret;
@@ -647,7 +647,7 @@ static void dell_update_rfkill(struct work_struct *ignored)
        if (ret != 0)
                return;
 
-       dell_fill_request(&buffer, 0, 0x2, 0, 0);
+       dell_fill_request(&buffer, 0x2, 0, 0, 0);
        ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
 
        if (ret == 0 && (status & BIT(0)))
index f3afe778001ef868279f1b1a83dc124ffcfc2424..56535d7222ddc1b94e4d201aead0bca933133828 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/rfkill.h>
 #include <linux/input.h>
 
+#include "dell-rbtn.h"
+
 enum rbtn_type {
        RBTN_UNKNOWN,
        RBTN_TOGGLE,
index c53ae86b59c795c6e49aafaf8055561f04eba82a..2d94536dea88736dfc73ac7c3aeda3a1ebdd105d 100644 (file)
@@ -980,312 +980,21 @@ static void ideapad_wmi_notify(u32 value, void *context)
 #endif
 
 /*
- * Some ideapads don't have a hardware rfkill switch, reading VPCCMD_R_RF
- * always results in 0 on these models, causing ideapad_laptop to wrongly
- * report all radios as hardware-blocked.
+ * Some ideapads have a hardware rfkill switch, but most do not have one.
+ * Reading VPCCMD_R_RF always results in 0 on models without a hardware rfkill,
+ * switch causing ideapad_laptop to wrongly report all radios as hw-blocked.
+ * There used to be a long list of DMI ids for models without a hw rfkill
+ * switch here, but that resulted in playing whack a mole.
+ * More importantly wrongly reporting the wifi radio as hw-blocked, results in
+ * non working wifi. Whereas not reporting it hw-blocked, when it actually is
+ * hw-blocked results in an empty SSID list, which is a much more benign
+ * failure mode.
+ * So the default now is the much safer option of assuming there is no
+ * hardware rfkill switch. This default also actually matches most hardware,
+ * since having a hw rfkill switch is quite rare on modern hardware, so this
+ * also leads to a much shorter list.
  */
-static const struct dmi_system_id no_hw_rfkill_list[] = {
-       {
-               .ident = "Lenovo RESCUER R720-15IKBN",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo R720-15IKBN"),
-               },
-       },
-       {
-               .ident = "Lenovo G40-30",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G40-30"),
-               },
-       },
-       {
-               .ident = "Lenovo G50-30",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"),
-               },
-       },
-       {
-               .ident = "Lenovo V310-14IKB",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-14IKB"),
-               },
-       },
-       {
-               .ident = "Lenovo V310-14ISK",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-14ISK"),
-               },
-       },
-       {
-               .ident = "Lenovo V310-15IKB",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15IKB"),
-               },
-       },
-       {
-               .ident = "Lenovo V310-15ISK",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15ISK"),
-               },
-       },
-       {
-               .ident = "Lenovo V510-15IKB",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V510-15IKB"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad 300-15IBR",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300-15IBR"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad 300-15IKB",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300-15IKB"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad 300S-11IBR",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300S-11BR"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad 310-15ABR",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15ABR"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad 310-15IAP",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15IAP"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad 310-15IKB",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15IKB"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad 310-15ISK",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15ISK"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad 330-15ICH",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 330-15ICH"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad 530S-14ARR",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 530S-14ARR"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad S130-14IGM",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad S130-14IGM"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad Y700-14ISK",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-14ISK"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad Y700-15ACZ",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ACZ"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad Y700-15ISK",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ISK"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad Y700 Touch-15ISK",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700 Touch-15ISK"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad Y700-17ISK",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-17ISK"),
-               },
-       },
-       {
-               .ident = "Lenovo ideapad MIIX 720-12IKB",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "MIIX 720-12IKB"),
-               },
-       },
-       {
-               .ident = "Lenovo Legion Y520-15IKB",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKB"),
-               },
-       },
-       {
-               .ident = "Lenovo Y520-15IKBM",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBM"),
-               },
-       },
-       {
-               .ident = "Lenovo Legion Y530-15ICH",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion Y530-15ICH"),
-               },
-       },
-       {
-               .ident = "Lenovo Legion Y530-15ICH-1060",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion Y530-15ICH-1060"),
-               },
-       },
-       {
-               .ident = "Lenovo Legion Y720-15IKB",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKB"),
-               },
-       },
-       {
-               .ident = "Lenovo Legion Y720-15IKBN",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKBN"),
-               },
-       },
-       {
-               .ident = "Lenovo Y720-15IKBM",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKBM"),
-               },
-       },
-       {
-               .ident = "Lenovo Yoga 2 11 / 13 / Pro",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2"),
-               },
-       },
-       {
-               .ident = "Lenovo Yoga 2 11 / 13 / Pro",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_BOARD_NAME, "Yoga2"),
-               },
-       },
-       {
-               .ident = "Lenovo Yoga 2 13",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Yoga 2 13"),
-               },
-       },
-       {
-               .ident = "Lenovo Yoga 3 1170 / 1470",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 3"),
-               },
-       },
-       {
-               .ident = "Lenovo Yoga 3 Pro 1370",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 3"),
-               },
-       },
-       {
-               .ident = "Lenovo Yoga 700",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 700"),
-               },
-       },
-       {
-               .ident = "Lenovo Yoga 900",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 900"),
-               },
-       },
-       {
-               .ident = "Lenovo Yoga 900",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_BOARD_NAME, "VIUU4"),
-               },
-       },
-       {
-               .ident = "Lenovo YOGA 910-13IKB",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 910-13IKB"),
-               },
-       },
-       {
-               .ident = "Lenovo YOGA 920-13IKB",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 920-13IKB"),
-               },
-       },
-       {
-               .ident = "Lenovo YOGA C930-13IKB",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA C930-13IKB"),
-               },
-       },
-       {
-               .ident = "Lenovo Zhaoyang E42-80",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "ZHAOYANG E42-80"),
-               },
-       },
+static const struct dmi_system_id hw_rfkill_list[] = {
        {}
 };
 
@@ -1311,7 +1020,7 @@ static int ideapad_acpi_add(struct platform_device *pdev)
        priv->cfg = cfg;
        priv->adev = adev;
        priv->platform_device = pdev;
-       priv->has_hw_rfkill_switch = !dmi_check_system(no_hw_rfkill_list);
+       priv->has_hw_rfkill_switch = dmi_check_system(hw_rfkill_list);
 
        ret = ideapad_sysfs_init(priv);
        if (ret)
diff --git a/drivers/platform/x86/intel_mrfld_pwrbtn.c b/drivers/platform/x86/intel_mrfld_pwrbtn.c
new file mode 100644 (file)
index 0000000..d58fea5
--- /dev/null
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Power-button driver for Basin Cove PMIC
+ *
+ * Copyright (c) 2019, Intel Corporation.
+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ */
+
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/mfd/intel_soc_pmic_mrfld.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/slab.h>
+
+#define BCOVE_PBSTATUS         0x27
+#define BCOVE_PBSTATUS_PBLVL   BIT(4)  /* 1 - release, 0 - press */
+
+static irqreturn_t mrfld_pwrbtn_interrupt(int irq, void *dev_id)
+{
+       struct input_dev *input = dev_id;
+       struct device *dev = input->dev.parent;
+       struct regmap *regmap = dev_get_drvdata(dev);
+       unsigned int state;
+       int ret;
+
+       ret = regmap_read(regmap, BCOVE_PBSTATUS, &state);
+       if (ret)
+               return IRQ_NONE;
+
+       dev_dbg(dev, "PBSTATUS=0x%x\n", state);
+       input_report_key(input, KEY_POWER, !(state & BCOVE_PBSTATUS_PBLVL));
+       input_sync(input);
+
+       regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_PWRBTN, 0);
+       return IRQ_HANDLED;
+}
+
+static int mrfld_pwrbtn_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent);
+       struct input_dev *input;
+       int irq, ret;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       input = devm_input_allocate_device(dev);
+       if (!input)
+               return -ENOMEM;
+       input->name = pdev->name;
+       input->phys = "power-button/input0";
+       input->id.bustype = BUS_HOST;
+       input->dev.parent = dev;
+       input_set_capability(input, EV_KEY, KEY_POWER);
+       ret = input_register_device(input);
+       if (ret)
+               return ret;
+
+       dev_set_drvdata(dev, pmic->regmap);
+
+       ret = devm_request_threaded_irq(dev, irq, NULL, mrfld_pwrbtn_interrupt,
+                                       IRQF_ONESHOT | IRQF_SHARED, pdev->name,
+                                       input);
+       if (ret)
+               return ret;
+
+       regmap_update_bits(pmic->regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_PWRBTN, 0);
+       regmap_update_bits(pmic->regmap, BCOVE_MPBIRQ, BCOVE_PBIRQ_PBTN, 0);
+
+       device_init_wakeup(dev, true);
+       dev_pm_set_wake_irq(dev, irq);
+       return 0;
+}
+
+static int mrfld_pwrbtn_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+
+       dev_pm_clear_wake_irq(dev);
+       device_init_wakeup(dev, false);
+       return 0;
+}
+
+static const struct platform_device_id mrfld_pwrbtn_id_table[] = {
+       { .name = "mrfld_bcove_pwrbtn" },
+       {}
+};
+MODULE_DEVICE_TABLE(platform, mrfld_pwrbtn_id_table);
+
+static struct platform_driver mrfld_pwrbtn_driver = {
+       .driver = {
+               .name   = "mrfld_bcove_pwrbtn",
+       },
+       .probe          = mrfld_pwrbtn_probe,
+       .remove         = mrfld_pwrbtn_remove,
+       .id_table       = mrfld_pwrbtn_id_table,
+};
+module_platform_driver(mrfld_pwrbtn_driver);
+
+MODULE_DESCRIPTION("Power-button driver for Basin Cove PMIC");
+MODULE_LICENSE("GPL v2");
index f2c621b55f497116cb3c8f3d9bfb81b797c44955..1d902230ba611535c5ce0d85a6ac7b7b05e21040 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/suspend.h>
 #include <linux/uaccess.h>
 
 #include <asm/cpu_device_id.h>
@@ -828,7 +830,7 @@ static const struct pci_device_id pmc_pci_ids[] = {
  * the platform BIOS enforces 24Mhx Crystal to shutdown
  * before PMC can assert SLP_S0#.
  */
-int quirk_xtal_ignore(const struct dmi_system_id *id)
+static int quirk_xtal_ignore(const struct dmi_system_id *id)
 {
        struct pmc_dev *pmcdev = &pmc;
        u32 value;
@@ -854,13 +856,17 @@ static const struct dmi_system_id pmc_core_dmi_table[]  = {
        {}
 };
 
-static int __init pmc_core_probe(void)
+static int pmc_core_probe(struct platform_device *pdev)
 {
+       static bool device_initialized;
        struct pmc_dev *pmcdev = &pmc;
        const struct x86_cpu_id *cpu_id;
        u64 slp_s0_addr;
        int err;
 
+       if (device_initialized)
+               return -ENODEV;
+
        cpu_id = x86_match_cpu(intel_pmc_core_ids);
        if (!cpu_id)
                return -ENODEV;
@@ -886,30 +892,178 @@ static int __init pmc_core_probe(void)
                return -ENOMEM;
 
        mutex_init(&pmcdev->lock);
+       platform_set_drvdata(pdev, pmcdev);
        pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit();
+       dmi_check_system(pmc_core_dmi_table);
 
        err = pmc_core_dbgfs_register(pmcdev);
        if (err < 0) {
-               pr_warn(" debugfs register failed.\n");
+               dev_warn(&pdev->dev, "debugfs register failed.\n");
                iounmap(pmcdev->regbase);
                return err;
        }
 
-       dmi_check_system(pmc_core_dmi_table);
-       pr_info(" initialized\n");
+       device_initialized = true;
+       dev_info(&pdev->dev, " initialized\n");
+
        return 0;
 }
-module_init(pmc_core_probe)
 
-static void __exit pmc_core_remove(void)
+static int pmc_core_remove(struct platform_device *pdev)
 {
-       struct pmc_dev *pmcdev = &pmc;
+       struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
 
        pmc_core_dbgfs_unregister(pmcdev);
+       platform_set_drvdata(pdev, NULL);
        mutex_destroy(&pmcdev->lock);
        iounmap(pmcdev->regbase);
+       return 0;
 }
-module_exit(pmc_core_remove)
+
+#ifdef CONFIG_PM_SLEEP
+
+static bool warn_on_s0ix_failures;
+module_param(warn_on_s0ix_failures, bool, 0644);
+MODULE_PARM_DESC(warn_on_s0ix_failures, "Check and warn for S0ix failures");
+
+static int pmc_core_suspend(struct device *dev)
+{
+       struct pmc_dev *pmcdev = dev_get_drvdata(dev);
+
+       pmcdev->check_counters = false;
+
+       /* No warnings on S0ix failures */
+       if (!warn_on_s0ix_failures)
+               return 0;
+
+       /* Check if the syspend will actually use S0ix */
+       if (pm_suspend_via_firmware())
+               return 0;
+
+       /* Save PC10 residency for checking later */
+       if (rdmsrl_safe(MSR_PKG_C10_RESIDENCY, &pmcdev->pc10_counter))
+               return -EIO;
+
+       /* Save S0ix residency for checking later */
+       if (pmc_core_dev_state_get(pmcdev, &pmcdev->s0ix_counter))
+               return -EIO;
+
+       pmcdev->check_counters = true;
+       return 0;
+}
+
+static inline bool pmc_core_is_pc10_failed(struct pmc_dev *pmcdev)
+{
+       u64 pc10_counter;
+
+       if (rdmsrl_safe(MSR_PKG_C10_RESIDENCY, &pc10_counter))
+               return false;
+
+       if (pc10_counter == pmcdev->pc10_counter)
+               return true;
+
+       return false;
+}
+
+static inline bool pmc_core_is_s0ix_failed(struct pmc_dev *pmcdev)
+{
+       u64 s0ix_counter;
+
+       if (pmc_core_dev_state_get(pmcdev, &s0ix_counter))
+               return false;
+
+       if (s0ix_counter == pmcdev->s0ix_counter)
+               return true;
+
+       return false;
+}
+
+static int pmc_core_resume(struct device *dev)
+{
+       struct pmc_dev *pmcdev = dev_get_drvdata(dev);
+       const struct pmc_bit_map **maps = pmcdev->map->slps0_dbg_maps;
+       int offset = pmcdev->map->slps0_dbg_offset;
+       const struct pmc_bit_map *map;
+       u32 data;
+
+       if (!pmcdev->check_counters)
+               return 0;
+
+       if (!pmc_core_is_s0ix_failed(pmcdev))
+               return 0;
+
+       if (pmc_core_is_pc10_failed(pmcdev)) {
+               /* S0ix failed because of PC10 entry failure */
+               dev_info(dev, "CPU did not enter PC10!!! (PC10 cnt=0x%llx)\n",
+                        pmcdev->pc10_counter);
+               return 0;
+       }
+
+       /* The real interesting case - S0ix failed - lets ask PMC why. */
+       dev_warn(dev, "CPU did not enter SLP_S0!!! (S0ix cnt=%llu)\n",
+                pmcdev->s0ix_counter);
+       while (*maps) {
+               map = *maps;
+               data = pmc_core_reg_read(pmcdev, offset);
+               offset += 4;
+               while (map->name) {
+                       dev_dbg(dev, "SLP_S0_DBG: %-32s\tState: %s\n",
+                               map->name,
+                               data & map->bit_mask ? "Yes" : "No");
+                       map++;
+               }
+               maps++;
+       }
+       return 0;
+}
+
+#endif
+
+static const struct dev_pm_ops pmc_core_pm_ops = {
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(pmc_core_suspend, pmc_core_resume)
+};
+
+static struct platform_driver pmc_core_driver = {
+       .driver = {
+               .name = "intel_pmc_core",
+               .pm = &pmc_core_pm_ops,
+       },
+       .probe = pmc_core_probe,
+       .remove = pmc_core_remove,
+};
+
+static struct platform_device pmc_core_device = {
+       .name = "intel_pmc_core",
+};
+
+static int __init pmc_core_init(void)
+{
+       int ret;
+
+       if (!x86_match_cpu(intel_pmc_core_ids))
+               return -ENODEV;
+
+       ret = platform_driver_register(&pmc_core_driver);
+       if (ret)
+               return ret;
+
+       ret = platform_device_register(&pmc_core_device);
+       if (ret) {
+               platform_driver_unregister(&pmc_core_driver);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void __exit pmc_core_exit(void)
+{
+       platform_device_unregister(&pmc_core_device);
+       platform_driver_unregister(&pmc_core_driver);
+}
+
+module_init(pmc_core_init)
+module_exit(pmc_core_exit)
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Intel PMC Core Driver");
index 88d9c0653a5fc721cf2624f3ee472a93e8d87c35..fdee5772e5322a9112a3c40d0f7cf494841f98ee 100644 (file)
@@ -241,6 +241,9 @@ struct pmc_reg_map {
  * @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers
  *                     used to read MPHY PG and PLL status are available
  * @mutex_lock:                mutex to complete one transcation
+ * @check_counters:    On resume, check if counters are getting incremented
+ * @pc10_counter:      PC10 residency counter
+ * @s0ix_counter:      S0ix residency (step adjusted)
  *
  * pmc_dev contains info about power management controller device.
  */
@@ -253,6 +256,10 @@ struct pmc_dev {
 #endif /* CONFIG_DEBUG_FS */
        int pmc_xram_read_bit;
        struct mutex lock; /* generic mutex lock for PMC Core */
+
+       bool check_counters; /* Check for counter increments on resume */
+       u64 pc10_counter;
+       u64 s0ix_counter;
 };
 
 #endif /* PMC_CORE_H */
index 7964ba22ef8d997d31e3cd83af9a56feb90dd088..55037ff258f8ad2d3fdb4d1ef3eea67d82cca797 100644 (file)
  * The ARC handles the interrupt and services it, writing optional data to
  * the IPC1 registers, updates the IPC_STS response register with the status.
  */
-#define IPC_CMD                        0x0
-#define                IPC_CMD_MSI             0x100
+#define IPC_CMD                        0x00
+#define                IPC_CMD_MSI             BIT(8)
 #define                IPC_CMD_SIZE            16
 #define                IPC_CMD_SUBCMD          12
 #define IPC_STATUS             0x04
-#define                IPC_STATUS_IRQ          0x4
-#define                IPC_STATUS_ERR          0x2
-#define                IPC_STATUS_BUSY         0x1
+#define                IPC_STATUS_IRQ          BIT(2)
+#define                IPC_STATUS_ERR          BIT(1)
+#define                IPC_STATUS_BUSY         BIT(0)
 #define IPC_SPTR               0x08
 #define IPC_DPTR               0x0C
 #define IPC_WRITE_BUFFER       0x80
 #define TELEM_SSRAM_SIZE               240
 #define TELEM_PMC_SSRAM_OFFSET         0x1B00
 #define TELEM_PUNIT_SSRAM_OFFSET       0x1A00
-#define TCO_PMC_OFFSET                 0x8
-#define TCO_PMC_SIZE                   0x4
+#define TCO_PMC_OFFSET                 0x08
+#define TCO_PMC_SIZE                   0x04
 
 /* PMC register bit definitions */
 
 /* PMC_CFG_REG bit masks */
-#define PMC_CFG_NO_REBOOT_MASK         (1 << 4)
+#define PMC_CFG_NO_REBOOT_MASK         BIT_MASK(4)
 #define PMC_CFG_NO_REBOOT_EN           (1 << 4)
 #define PMC_CFG_NO_REBOOT_DIS          (0 << 4)
 
@@ -131,6 +131,7 @@ static struct intel_pmc_ipc_dev {
 
        /* punit */
        struct platform_device *punit_dev;
+       unsigned int punit_res_count;
 
        /* Telemetry */
        resource_size_t telem_pmc_ssram_base;
@@ -682,7 +683,7 @@ static int ipc_create_punit_device(void)
                .name = PUNIT_DEVICE_NAME,
                .id = -1,
                .res = punit_res_array,
-               .num_res = ARRAY_SIZE(punit_res_array),
+               .num_res = ipcdev.punit_res_count,
                };
 
        pdev = platform_device_register_full(&pdevinfo);
@@ -771,13 +772,17 @@ static int ipc_create_pmc_devices(void)
        if (ret) {
                dev_err(ipcdev.dev, "Failed to add punit platform device\n");
                platform_device_unregister(ipcdev.tco_dev);
+               return ret;
        }
 
        if (!ipcdev.telem_res_inval) {
                ret = ipc_create_telemetry_device();
-               if (ret)
+               if (ret) {
                        dev_warn(ipcdev.dev,
                                "Failed to add telemetry platform device\n");
+                       platform_device_unregister(ipcdev.punit_dev);
+                       platform_device_unregister(ipcdev.tco_dev);
+               }
        }
 
        return ret;
@@ -785,7 +790,7 @@ static int ipc_create_pmc_devices(void)
 
 static int ipc_plat_get_res(struct platform_device *pdev)
 {
-       struct resource *res, *punit_res;
+       struct resource *res, *punit_res = punit_res_array;
        void __iomem *addr;
        int size;
 
@@ -800,7 +805,8 @@ static int ipc_plat_get_res(struct platform_device *pdev)
        ipcdev.acpi_io_size = size;
        dev_info(&pdev->dev, "io res: %pR\n", res);
 
-       punit_res = punit_res_array;
+       ipcdev.punit_res_count = 0;
+
        /* This is index 0 to cover BIOS data register */
        res = platform_get_resource(pdev, IORESOURCE_MEM,
                                    PLAT_RESOURCE_BIOS_DATA_INDEX);
@@ -808,7 +814,7 @@ static int ipc_plat_get_res(struct platform_device *pdev)
                dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n");
                return -ENXIO;
        }
-       *punit_res = *res;
+       punit_res[ipcdev.punit_res_count++] = *res;
        dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res);
 
        /* This is index 1 to cover BIOS interface register */
@@ -818,42 +824,38 @@ static int ipc_plat_get_res(struct platform_device *pdev)
                dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n");
                return -ENXIO;
        }
-       *++punit_res = *res;
+       punit_res[ipcdev.punit_res_count++] = *res;
        dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res);
 
        /* This is index 2 to cover ISP data register, optional */
        res = platform_get_resource(pdev, IORESOURCE_MEM,
                                    PLAT_RESOURCE_ISP_DATA_INDEX);
-       ++punit_res;
        if (res) {
-               *punit_res = *res;
+               punit_res[ipcdev.punit_res_count++] = *res;
                dev_info(&pdev->dev, "punit ISP data res: %pR\n", res);
        }
 
        /* This is index 3 to cover ISP interface register, optional */
        res = platform_get_resource(pdev, IORESOURCE_MEM,
                                    PLAT_RESOURCE_ISP_IFACE_INDEX);
-       ++punit_res;
        if (res) {
-               *punit_res = *res;
+               punit_res[ipcdev.punit_res_count++] = *res;
                dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res);
        }
 
        /* This is index 4 to cover GTD data register, optional */
        res = platform_get_resource(pdev, IORESOURCE_MEM,
                                    PLAT_RESOURCE_GTD_DATA_INDEX);
-       ++punit_res;
        if (res) {
-               *punit_res = *res;
+               punit_res[ipcdev.punit_res_count++] = *res;
                dev_info(&pdev->dev, "punit GTD data res: %pR\n", res);
        }
 
        /* This is index 5 to cover GTD interface register, optional */
        res = platform_get_resource(pdev, IORESOURCE_MEM,
                                    PLAT_RESOURCE_GTD_IFACE_INDEX);
-       ++punit_res;
        if (res) {
-               *punit_res = *res;
+               punit_res[ipcdev.punit_res_count++] = *res;
                dev_info(&pdev->dev, "punit GTD interface res: %pR\n", res);
        }
 
index 79671927f4ef6ada5833419c58a8aeb23fd1621f..ab7ae19508676d60387e17c191b79ce3e1e34034 100644 (file)
@@ -252,28 +252,28 @@ static int intel_punit_get_bars(struct platform_device *pdev)
         * - GTDRIVER_IPC BASE_IFACE
         */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-       if (res && resource_size(res) > 1) {
+       if (res) {
                addr = devm_ioremap_resource(&pdev->dev, res);
                if (!IS_ERR(addr))
                        punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
-       if (res && resource_size(res) > 1) {
+       if (res) {
                addr = devm_ioremap_resource(&pdev->dev, res);
                if (!IS_ERR(addr))
                        punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
-       if (res && resource_size(res) > 1) {
+       if (res) {
                addr = devm_ioremap_resource(&pdev->dev, res);
                if (!IS_ERR(addr))
                        punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
-       if (res && resource_size(res) > 1) {
+       if (res) {
                addr = devm_ioremap_resource(&pdev->dev, res);
                if (!IS_ERR(addr))
                        punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;
index 48fa7573e29b29f7966339b1f00868e036aa8fc7..cee039f574994133b02e2e24400f73e134931968 100644 (file)
 #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET                0x88
 #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET  0x89
 #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET   0x8a
+#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET   0xc7
+#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET        0xc8
+#define MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET    0xc9
+#define MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET    0xcb
+#define MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET    0xcd
+#define MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET  0xce
+#define MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET    0xcf
+#define MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET    0xd1
+#define MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET  0xd2
+#define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET    0xd3
 #define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET       0xe3
 #define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET     0xe4
 #define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET     0xe5
@@ -72,6 +82,7 @@
 #define MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET   0xf5
 #define MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET   0xf6
 #define MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET        0xf7
+#define MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET        0xf8
 #define MLXPLAT_CPLD_LPC_IO_RANGE              0x100
 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF           0xdb
 #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF           0xda
 #define MLXPLAT_CPLD_FAN3_DEFAULT_NR           13
 #define MLXPLAT_CPLD_FAN4_DEFAULT_NR           14
 
+/* Masks and default values for watchdogs */
+#define MLXPLAT_CPLD_WD1_CLEAR_MASK    GENMASK(7, 1)
+#define MLXPLAT_CPLD_WD2_CLEAR_MASK    (GENMASK(7, 0) & ~BIT(1))
+
+#define MLXPLAT_CPLD_WD_TYPE1_TO_MASK  GENMASK(7, 4)
+#define MLXPLAT_CPLD_WD_TYPE2_TO_MASK  0
+#define MLXPLAT_CPLD_WD_RESET_ACT_MASK GENMASK(7, 1)
+#define MLXPLAT_CPLD_WD_FAN_ACT_MASK   (GENMASK(7, 0) & ~BIT(4))
+#define MLXPLAT_CPLD_WD_COUNT_ACT_MASK (GENMASK(7, 0) & ~BIT(7))
+#define MLXPLAT_CPLD_WD_DFLT_TIMEOUT   30
+#define MLXPLAT_CPLD_WD_MAX_DEVS       2
+
 /* mlxplat_priv - platform private data
  * @pdev_i2c - i2c controller platform device
  * @pdev_mux - array of mux platform devices
  * @pdev_led - led platform devices
  * @pdev_io_regs - register access platform devices
  * @pdev_fan - FAN platform devices
+ * @pdev_wd - array of watchdog platform devices
  */
 struct mlxplat_priv {
        struct platform_device *pdev_i2c;
@@ -143,6 +167,7 @@ struct mlxplat_priv {
        struct platform_device *pdev_led;
        struct platform_device *pdev_io_regs;
        struct platform_device *pdev_fan;
+       struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS];
 };
 
 /* Regions for LPC I2C controller and LPC base register space */
@@ -1339,6 +1364,10 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
                .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET,
                .bit = BIT(3),
        },
+       {
+               .label = "conf",
+               .capability = MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET,
+       },
 };
 
 static struct mlxreg_core_platform_data mlxplat_default_fan_data = {
@@ -1346,6 +1375,148 @@ static struct mlxreg_core_platform_data mlxplat_default_fan_data = {
                .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data),
 };
 
+/* Watchdog type1: hardware implementation version1
+ * (MSN2700, MSN2410, MSN2740, MSN2100 and MSN2140 systems).
+ */
+static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type1[] = {
+       {
+               .label = "action",
+               .reg = MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET,
+               .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK,
+               .bit = 0,
+       },
+       {
+               .label = "timeout",
+               .reg = MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET,
+               .mask = MLXPLAT_CPLD_WD_TYPE1_TO_MASK,
+               .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT,
+       },
+       {
+               .label = "ping",
+               .reg = MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET,
+               .mask = MLXPLAT_CPLD_WD1_CLEAR_MASK,
+               .bit = 0,
+       },
+       {
+               .label = "reset",
+               .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(6),
+               .bit = 6,
+       },
+};
+
+static struct mlxreg_core_data mlxplat_mlxcpld_wd_aux_regs_type1[] = {
+       {
+               .label = "action",
+               .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET,
+               .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK,
+               .bit = 4,
+       },
+       {
+               .label = "timeout",
+               .reg = MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET,
+               .mask = MLXPLAT_CPLD_WD_TYPE1_TO_MASK,
+               .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT,
+       },
+       {
+               .label = "ping",
+               .reg = MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET,
+               .mask = MLXPLAT_CPLD_WD1_CLEAR_MASK,
+               .bit = 1,
+       },
+};
+
+static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type1[] = {
+       {
+               .data = mlxplat_mlxcpld_wd_main_regs_type1,
+               .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type1),
+               .version = MLX_WDT_TYPE1,
+               .identity = "mlx-wdt-main",
+       },
+       {
+               .data = mlxplat_mlxcpld_wd_aux_regs_type1,
+               .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type1),
+               .version = MLX_WDT_TYPE1,
+               .identity = "mlx-wdt-aux",
+       },
+};
+
+/* Watchdog type2: hardware implementation version 2
+ * (all systems except (MSN2700, MSN2410, MSN2740, MSN2100 and MSN2140).
+ */
+static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type2[] = {
+       {
+               .label = "action",
+               .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET,
+               .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK,
+               .bit = 0,
+       },
+       {
+               .label = "timeout",
+               .reg = MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET,
+               .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK,
+               .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT,
+       },
+       {
+               .label = "timeleft",
+               .reg = MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET,
+               .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK,
+       },
+       {
+               .label = "ping",
+               .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET,
+               .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK,
+               .bit = 0,
+       },
+       {
+               .label = "reset",
+               .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
+               .mask = GENMASK(7, 0) & ~BIT(6),
+               .bit = 6,
+       },
+};
+
+static struct mlxreg_core_data mlxplat_mlxcpld_wd_aux_regs_type2[] = {
+       {
+               .label = "action",
+               .reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET,
+               .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK,
+               .bit = 4,
+       },
+       {
+               .label = "timeout",
+               .reg = MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET,
+               .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK,
+               .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT,
+       },
+       {
+               .label = "timeleft",
+               .reg = MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET,
+               .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK,
+       },
+       {
+               .label = "ping",
+               .reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET,
+               .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK,
+               .bit = 4,
+       },
+};
+
+static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type2[] = {
+       {
+               .data = mlxplat_mlxcpld_wd_main_regs_type2,
+               .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type2),
+               .version = MLX_WDT_TYPE2,
+               .identity = "mlx-wdt-main",
+       },
+       {
+               .data = mlxplat_mlxcpld_wd_aux_regs_type2,
+               .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type2),
+               .version = MLX_WDT_TYPE2,
+               .identity = "mlx-wdt-aux",
+       },
+};
+
 static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -1368,6 +1539,14 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
        case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET:
                return true;
@@ -1411,6 +1590,16 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
        case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET:
@@ -1428,6 +1617,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
        case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET:
                return true;
        }
        return false;
@@ -1467,6 +1657,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
        case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET:
@@ -1484,6 +1678,7 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
        case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET:
                return true;
        }
        return false;
@@ -1493,6 +1688,7 @@ static const struct reg_default mlxplat_mlxcpld_regmap_default[] = {
        { MLXPLAT_CPLD_LPC_REG_WP1_OFFSET, 0x00 },
        { MLXPLAT_CPLD_LPC_REG_WP2_OFFSET, 0x00 },
        { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 },
+       { MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 },
 };
 
 struct mlxplat_mlxcpld_regmap_context {
@@ -1542,6 +1738,8 @@ static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
 static struct mlxreg_core_platform_data *mlxplat_led;
 static struct mlxreg_core_platform_data *mlxplat_regs_io;
 static struct mlxreg_core_platform_data *mlxplat_fan;
+static struct mlxreg_core_platform_data
+       *mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS];
 
 static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
 {
@@ -1557,6 +1755,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
                mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
        mlxplat_led = &mlxplat_default_led_data;
        mlxplat_regs_io = &mlxplat_default_regs_io_data;
+       mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
 
        return 1;
 };
@@ -1575,6 +1774,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
                mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
        mlxplat_led = &mlxplat_msn21xx_led_data;
        mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
+       mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
 
        return 1;
 };
@@ -1593,6 +1793,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
                mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
        mlxplat_led = &mlxplat_default_led_data;
        mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
+       mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
 
        return 1;
 };
@@ -1611,6 +1812,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
                mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
        mlxplat_led = &mlxplat_msn21xx_led_data;
        mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
+       mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
 
        return 1;
 };
@@ -1630,6 +1832,8 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
        mlxplat_led = &mlxplat_default_ng_led_data;
        mlxplat_regs_io = &mlxplat_default_ng_regs_io_data;
        mlxplat_fan = &mlxplat_default_fan_data;
+       for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++)
+               mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i];
 
        return 1;
 };
@@ -1912,15 +2116,33 @@ static int __init mlxplat_init(void)
                }
        }
 
+       /* Add WD drivers. */
+       for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) {
+               if (mlxplat_wd_data[j]) {
+                       mlxplat_wd_data[j]->regmap = mlxplat_hotplug->regmap;
+                       priv->pdev_wd[j] = platform_device_register_resndata(
+                                               &mlxplat_dev->dev, "mlx-wdt",
+                                               j, NULL, 0,
+                                               mlxplat_wd_data[j],
+                                               sizeof(*mlxplat_wd_data[j]));
+                       if (IS_ERR(priv->pdev_wd[j])) {
+                               err = PTR_ERR(priv->pdev_wd[j]);
+                               goto fail_platform_wd_register;
+                       }
+               }
+       }
+
        /* Sync registers with hardware. */
        regcache_mark_dirty(mlxplat_hotplug->regmap);
        err = regcache_sync(mlxplat_hotplug->regmap);
        if (err)
-               goto fail_platform_fan_register;
+               goto fail_platform_wd_register;
 
        return 0;
 
-fail_platform_fan_register:
+fail_platform_wd_register:
+       while (--j >= 0)
+               platform_device_unregister(priv->pdev_wd[j]);
        if (mlxplat_fan)
                platform_device_unregister(priv->pdev_fan);
 fail_platform_io_regs_register:
@@ -1946,6 +2168,8 @@ static void __exit mlxplat_exit(void)
        struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
        int i;
 
+       for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--)
+               platform_device_unregister(priv->pdev_wd[i]);
        if (priv->pdev_fan)
                platform_device_unregister(priv->pdev_fan);
        if (priv->pdev_io_regs)
index 4bfbfa3f78e6d38b74745194a8066155d8652232..2058445fc456d99d4f794c1a45c0873358ed192c 100644 (file)
@@ -4424,14 +4424,16 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
                        }
                        return AE_OK;
                }
+
+       case ACPI_RESOURCE_TYPE_END_TAG:
+               return AE_OK;
+
        default:
                dprintk("Resource %d isn't an IRQ nor an IO port\n",
                        resource->type);
+               return AE_CTRL_TERMINATE;
 
-       case ACPI_RESOURCE_TYPE_END_TAG:
-               return AE_OK;
        }
-       return AE_CTRL_TERMINATE;
 }
 
 static int sony_pic_possible_resources(struct acpi_device *device)
index 726341f2b638636c4672c4a9ff9be7cb0003cc5d..71cfaf26efd13480a125b90586bf35d272dc289e 100644 (file)
@@ -79,7 +79,7 @@
 #include <linux/jiffies.h>
 #include <linux/workqueue.h>
 #include <linux/acpi.h>
-#include <linux/pci_ids.h>
+#include <linux/pci.h>
 #include <linux/power_supply.h>
 #include <sound/core.h>
 #include <sound/control.h>
@@ -4212,7 +4212,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                                known_ev = true;
                                break;
                        }
-                       /* fallthrough to default */
+                       /* fallthrough to default */
                default:
                        known_ev = false;
                }
@@ -4501,6 +4501,74 @@ static void bluetooth_exit(void)
        bluetooth_shutdown();
 }
 
+static const struct dmi_system_id bt_fwbug_list[] __initconst = {
+       {
+               .ident = "ThinkPad E485",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_BOARD_NAME, "20KU"),
+               },
+       },
+       {
+               .ident = "ThinkPad E585",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_BOARD_NAME, "20KV"),
+               },
+       },
+       {
+               .ident = "ThinkPad A285 - 20MW",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_BOARD_NAME, "20MW"),
+               },
+       },
+       {
+               .ident = "ThinkPad A285 - 20MX",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_BOARD_NAME, "20MX"),
+               },
+       },
+       {
+               .ident = "ThinkPad A485 - 20MU",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_BOARD_NAME, "20MU"),
+               },
+       },
+       {
+               .ident = "ThinkPad A485 - 20MV",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_BOARD_NAME, "20MV"),
+               },
+       },
+       {}
+};
+
+static const struct pci_device_id fwbug_cards_ids[] __initconst = {
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24F3) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24FD) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2526) },
+       {}
+};
+
+
+static int __init have_bt_fwbug(void)
+{
+       /*
+        * Some AMD based ThinkPads have a firmware bug that calling
+        * "GBDC" will cause bluetooth on Intel wireless cards blocked
+        */
+       if (dmi_check_system(bt_fwbug_list) && pci_dev_present(fwbug_cards_ids)) {
+               vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
+                       FW_BUG "disable bluetooth subdriver for Intel cards\n");
+               return 1;
+       } else
+               return 0;
+}
+
 static int __init bluetooth_init(struct ibm_init_struct *iibm)
 {
        int res;
@@ -4513,7 +4581,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
 
        /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
           G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
-       tp_features.bluetooth = hkey_handle &&
+       tp_features.bluetooth = !have_bt_fwbug() && hkey_handle &&
            acpi_evalf(hkey_handle, &status, "GBDC", "qd");
 
        vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
@@ -5808,7 +5876,7 @@ static int led_set_status(const unsigned int led,
                        return -EPERM;
                if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
                                (1 << led), led_sled_arg1[ledstatus]))
-                       rc = -EIO;
+                       return -EIO;
                break;
        case TPACPI_LED_OLD:
                /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
@@ -5832,10 +5900,10 @@ static int led_set_status(const unsigned int led,
                        return -EPERM;
                if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
                                led, led_led_arg1[ledstatus]))
-                       rc = -EIO;
+                       return -EIO;
                break;
        default:
-               rc = -ENXIO;
+               return -ENXIO;
        }
 
        if (!rc)
@@ -6249,8 +6317,8 @@ static int thermal_get_sensor(int idx, s32 *value)
                        t = TP_EC_THERMAL_TMP8;
                        idx -= 8;
                }
-               /* fallthrough */
 #endif
+               /* fallthrough */
        case TPACPI_THERMAL_TPEC_8:
                if (idx <= 7) {
                        if (!acpi_ec_read(t + idx, &tmp))
@@ -9890,6 +9958,37 @@ invalid:
        return '\0';
 }
 
+static void find_new_ec_fwstr(const struct dmi_header *dm, void *private)
+{
+       char *ec_fw_string = (char *) private;
+       const char *dmi_data = (const char *)dm;
+       /*
+        * ThinkPad Embedded Controller Program Table on newer models
+        *
+        * Offset |  Name                | Width  | Description
+        * ----------------------------------------------------
+        *  0x00  | Type                 | BYTE   | 0x8C
+        *  0x01  | Length               | BYTE   |
+        *  0x02  | Handle               | WORD   | Varies
+        *  0x04  | Signature            | BYTEx6 | ASCII for "LENOVO"
+        *  0x0A  | OEM struct offset    | BYTE   | 0x0B
+        *  0x0B  | OEM struct number    | BYTE   | 0x07, for this structure
+        *  0x0C  | OEM struct revision  | BYTE   | 0x01, for this format
+        *  0x0D  | ECP version ID       | STR ID |
+        *  0x0E  | ECP release date     | STR ID |
+        */
+
+       /* Return if data structure not match */
+       if (dm->type != 140 || dm->length < 0x0F ||
+       memcmp(dmi_data + 4, "LENOVO", 6) != 0 ||
+       dmi_data[0x0A] != 0x0B || dmi_data[0x0B] != 0x07 ||
+       dmi_data[0x0C] != 0x01)
+               return;
+
+       /* fwstr is the first 8byte string  */
+       strncpy(ec_fw_string, dmi_data + 0x0F, 8);
+}
+
 /* returns 0 - probe ok, or < 0 - probe error.
  * Probe ok doesn't mean thinkpad found.
  * On error, kfree() cleanup on tp->* is not performed, caller must do it */
@@ -9897,7 +9996,7 @@ static int __must_check __init get_thinkpad_model_data(
                                                struct thinkpad_id_data *tp)
 {
        const struct dmi_device *dev = NULL;
-       char ec_fw_string[18];
+       char ec_fw_string[18] = {0};
        char const *s;
        char t;
 
@@ -9937,20 +10036,25 @@ static int __must_check __init get_thinkpad_model_data(
                           ec_fw_string) == 1) {
                        ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
                        ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
+                       break;
+               }
+       }
 
-                       tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
-                       if (!tp->ec_version_str)
-                               return -ENOMEM;
+       /* Newer ThinkPads have different EC program info table */
+       if (!ec_fw_string[0])
+               dmi_walk(find_new_ec_fwstr, &ec_fw_string);
 
-                       t = tpacpi_parse_fw_id(ec_fw_string,
-                                              &tp->ec_model, &tp->ec_release);
-                       if (t != 'H') {
-                               pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n",
-                                         ec_fw_string);
-                               pr_notice("please report this to %s\n",
-                                         TPACPI_MAIL);
-                       }
-                       break;
+       if (ec_fw_string[0]) {
+               tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
+               if (!tp->ec_version_str)
+                       return -ENOMEM;
+
+               t = tpacpi_parse_fw_id(ec_fw_string,
+                        &tp->ec_model, &tp->ec_release);
+               if (t != 'H') {
+                       pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n",
+                                 ec_fw_string);
+                       pr_notice("please report this to %s\n", TPACPI_MAIL);
                }
        }
 
@@ -10165,7 +10269,7 @@ MODULE_PARM_DESC(volume_mode,
 
 module_param_named(volume_capabilities, volume_capabilities, uint, 0444);
 MODULE_PARM_DESC(volume_capabilities,
-                "Selects the mixer capabilites: 0=auto, 1=volume and mute, 2=mute only");
+                "Selects the mixer capabilities: 0=auto, 1=volume and mute, 2=mute only");
 
 module_param_named(volume_control, volume_control_allowed, bool, 0444);
 MODULE_PARM_DESC(volume_control,
index 2d56ff7c8230dea5c1542bc9843569b61ea90353..bd0856d2e82554a2bc3abb9b3ab959e9fd67c0ba 100644 (file)
@@ -249,6 +249,21 @@ static const struct ts_dmi_data jumper_ezpad_6_pro_data = {
        .properties     = jumper_ezpad_6_pro_props,
 };
 
+static const struct property_entry jumper_ezpad_6_pro_b_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1980),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1500),
+       PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-jumper-ezpad-6-pro-b.fw"),
+       PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+       PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       PROPERTY_ENTRY_BOOL("silead,home-button"),
+       { }
+};
+
+static const struct ts_dmi_data jumper_ezpad_6_pro_b_data = {
+       .acpi_name      = "MSSL1680:00",
+       .properties     = jumper_ezpad_6_pro_b_props,
+};
+
 static const struct property_entry jumper_ezpad_mini3_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-min-x", 23),
        PROPERTY_ENTRY_U32("touchscreen-min-y", 16),
@@ -265,6 +280,23 @@ static const struct ts_dmi_data jumper_ezpad_mini3_data = {
        .properties     = jumper_ezpad_mini3_props,
 };
 
+static const struct property_entry myria_my8307_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1720),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
+       PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
+       PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+       PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+       PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-myria-my8307.fw"),
+       PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       PROPERTY_ENTRY_BOOL("silead,home-button"),
+       { }
+};
+
+static const struct ts_dmi_data myria_my8307_data = {
+       .acpi_name      = "MSSL1680:00",
+       .properties     = myria_my8307_props,
+};
+
 static const struct property_entry onda_obook_20_plus_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
        PROPERTY_ENTRY_U32("touchscreen-size-y", 1148),
@@ -673,6 +705,17 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
                        DMI_MATCH(DMI_BIOS_DATE, "08/18/2017"),
                },
        },
+       {
+               /* Jumper EZpad 6 Pro B */
+               .driver_data = (void *)&jumper_ezpad_6_pro_b_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Jumper"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "EZpad"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "5.12"),
+                       /* Above matches are too generic, add bios-date match */
+                       DMI_MATCH(DMI_BIOS_DATE, "04/24/2018"),
+               },
+       },
        {
                /* Jumper EZpad mini3 */
                .driver_data = (void *)&jumper_ezpad_mini3_data,
@@ -690,6 +733,14 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"),
                },
        },
+       {
+               /* Myria MY8307 */
+               .driver_data = (void *)&myria_my8307_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Complet Electro Serv"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MY8307"),
+               },
+       },
        {
                /* Onda oBook 20 Plus */
                .driver_data = (void *)&onda_obook_20_plus_data,
index 2b686c55b7175081387bb27c98dc39729db3b7b6..e341cc5c0ea6f1253772d5a48772aa183e395b31 100644 (file)
 
 #define SHDW_WK_PIN(reg, cfg)  ((reg) & AT91_SHDW_WKUPIS((cfg)->wkup_pin_input))
 #define SHDW_RTCWK(reg, cfg)   (((reg) >> ((cfg)->sr_rtcwk_shift)) & 0x1)
+#define SHDW_RTTWK(reg, cfg)   (((reg) >> ((cfg)->sr_rttwk_shift)) & 0x1)
 #define SHDW_RTCWKEN(cfg)      (1 << ((cfg)->mr_rtcwk_shift))
+#define SHDW_RTTWKEN(cfg)      (1 << ((cfg)->mr_rttwk_shift))
 
 #define DBC_PERIOD_US(x)       DIV_ROUND_UP_ULL((1000000 * (x)), \
                                                        SLOW_CLOCK_FREQ)
 
+#define SHDW_CFG_NOT_USED      (32)
+
 struct shdwc_config {
        u8 wkup_pin_input;
        u8 mr_rtcwk_shift;
+       u8 mr_rttwk_shift;
        u8 sr_rtcwk_shift;
+       u8 sr_rttwk_shift;
 };
 
 struct shdwc {
@@ -104,6 +110,8 @@ static void __init at91_wakeup_status(struct platform_device *pdev)
                reason = "WKUP pin";
        else if (SHDW_RTCWK(reg, shdw->cfg))
                reason = "RTC";
+       else if (SHDW_RTTWK(reg, shdw->cfg))
+               reason = "RTT";
 
        pr_info("AT91: Wake-Up source: %s\n", reason);
 }
@@ -221,6 +229,9 @@ static void at91_shdwc_dt_configure(struct platform_device *pdev)
        if (of_property_read_bool(np, "atmel,wakeup-rtc-timer"))
                mode |= SHDW_RTCWKEN(shdw->cfg);
 
+       if (of_property_read_bool(np, "atmel,wakeup-rtt-timer"))
+               mode |= SHDW_RTTWKEN(shdw->cfg);
+
        dev_dbg(&pdev->dev, "%s: mode = %#x\n", __func__, mode);
        writel(mode, shdw->shdwc_base + AT91_SHDW_MR);
 
@@ -231,13 +242,27 @@ static void at91_shdwc_dt_configure(struct platform_device *pdev)
 static const struct shdwc_config sama5d2_shdwc_config = {
        .wkup_pin_input = 0,
        .mr_rtcwk_shift = 17,
+       .mr_rttwk_shift = SHDW_CFG_NOT_USED,
        .sr_rtcwk_shift = 5,
+       .sr_rttwk_shift = SHDW_CFG_NOT_USED,
+};
+
+static const struct shdwc_config sam9x60_shdwc_config = {
+       .wkup_pin_input = 0,
+       .mr_rtcwk_shift = 17,
+       .mr_rttwk_shift = 16,
+       .sr_rtcwk_shift = 5,
+       .sr_rttwk_shift = 4,
 };
 
 static const struct of_device_id at91_shdwc_of_match[] = {
        {
                .compatible = "atmel,sama5d2-shdwc",
                .data = &sama5d2_shdwc_config,
+       },
+       {
+               .compatible = "microchip,sam9x60-shdwc",
+               .data = &sam9x60_shdwc_config,
        }, {
                /*sentinel*/
        }
index 7d0d269a0837c0b84e9f72eeabbab354159a3b8e..5a6bb638c331f58277ee7a0b657686ea9867fd32 100644 (file)
@@ -27,6 +27,7 @@
 struct syscon_reboot_context {
        struct regmap *map;
        u32 offset;
+       u32 value;
        u32 mask;
        struct notifier_block restart_handler;
 };
@@ -39,7 +40,7 @@ static int syscon_restart_handle(struct notifier_block *this,
                                        restart_handler);
 
        /* Issue the reboot */
-       regmap_write(ctx->map, ctx->offset, ctx->mask);
+       regmap_update_bits(ctx->map, ctx->offset, ctx->mask, ctx->value);
 
        mdelay(1000);
 
@@ -51,6 +52,7 @@ static int syscon_reboot_probe(struct platform_device *pdev)
 {
        struct syscon_reboot_context *ctx;
        struct device *dev = &pdev->dev;
+       int mask_err, value_err;
        int err;
 
        ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
@@ -64,8 +66,21 @@ static int syscon_reboot_probe(struct platform_device *pdev)
        if (of_property_read_u32(pdev->dev.of_node, "offset", &ctx->offset))
                return -EINVAL;
 
-       if (of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask))
+       value_err = of_property_read_u32(pdev->dev.of_node, "value", &ctx->value);
+       mask_err = of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask);
+       if (value_err && mask_err) {
+               dev_err(dev, "unable to read 'value' and 'mask'");
                return -EINVAL;
+       }
+
+       if (value_err) {
+               /* support old binding */
+               ctx->value = ctx->mask;
+               ctx->mask = 0xFFFFFFFF;
+       } else if (mask_err) {
+               /* support value without mask*/
+               ctx->mask = 0xFFFFFFFF;
+       }
 
        ctx->restart_handler.notifier_call = syscon_restart_handle;
        ctx->restart_handler.priority = 192;
index e901b9879e7e70ce917af7bd740a41c74a651420..26dacdab03ccbec8e57c2e2cc25aa5856d628387 100644 (file)
@@ -169,6 +169,17 @@ config BATTERY_COLLIE
          Say Y to enable support for the battery on the Sharp Zaurus
          SL-5500 (collie) models.
 
+config BATTERY_INGENIC
+       tristate "Ingenic JZ47xx SoCs battery driver"
+       depends on MIPS || COMPILE_TEST
+       depends on INGENIC_ADC
+       help
+         Choose this option if you want to monitor battery status on
+         Ingenic JZ47xx SoC based devices.
+
+         This driver can also be built as a module. If so, the module will be
+         called ingenic-battery.
+
 config BATTERY_IPAQ_MICRO
        tristate "iPAQ Atmel Micro ASIC battery driver"
        depends on MFD_IPAQ_MICRO
@@ -475,12 +486,12 @@ config CHARGER_MANAGER
           runtime and in suspend-to-RAM by waking up the system periodically
           with help of suspend_again support.
 
-config CHARGER_LTC3651
-       tristate "LTC3651 charger"
+config CHARGER_LT3651
+       tristate "Analog Devices LT3651 charger"
        depends on GPIOLIB
        help
-         Say Y to include support for the LTC3651 battery charger which reports
-         its status via GPIO lines.
+         Say Y to include support for the Analog Devices (Linear Technology)
+         LT3651 battery charger which reports its status via GPIO lines.
 
 config CHARGER_MAX14577
        tristate "Maxim MAX14577/77836 battery charger driver"
@@ -499,6 +510,13 @@ config CHARGER_DETECTOR_MAX14656
          Revision 1.2 and can be found e.g. in Kindle 4/5th generation
          readers and certain LG devices.
 
+config CHARGER_MAX77650
+       tristate "Maxim MAX77650 battery charger driver"
+       depends on MFD_MAX77650
+       help
+         Say Y to enable support for the battery charger control of MAX77650
+         PMICs.
+
 config CHARGER_MAX77693
        tristate "Maxim MAX77693 battery charger driver"
        depends on MFD_MAX77693
@@ -660,4 +678,14 @@ config FUEL_GAUGE_SC27XX
         Say Y here to enable support for fuel gauge with SC27XX
         PMIC chips.
 
+config CHARGER_UCS1002
+       tristate "Microchip UCS1002 USB Port Power Controller"
+       depends on I2C
+       depends on OF
+       depends on REGULATOR
+       select REGMAP_I2C
+       help
+         Say Y to enable support for Microchip UCS1002 Programmable
+         USB Port Power Controller with Charger Emulation.
+
 endif # POWER_SUPPLY
index b731c2a9b695c59e62239bcb6b1f6b4f7cdd3002..f208273f9686b6278c22548dac59d216d568ffea 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_BATTERY_PMU)     += pmu_battery.o
 obj-$(CONFIG_BATTERY_OLPC)     += olpc_battery.o
 obj-$(CONFIG_BATTERY_TOSA)     += tosa_battery.o
 obj-$(CONFIG_BATTERY_COLLIE)   += collie_battery.o
+obj-$(CONFIG_BATTERY_INGENIC)  += ingenic-battery.o
 obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o
 obj-$(CONFIG_BATTERY_WM97XX)   += wm97xx_battery.o
 obj-$(CONFIG_BATTERY_SBS)      += sbs-battery.o
@@ -67,9 +68,10 @@ obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o
 obj-$(CONFIG_CHARGER_LP8788)   += lp8788-charger.o
 obj-$(CONFIG_CHARGER_GPIO)     += gpio-charger.o
 obj-$(CONFIG_CHARGER_MANAGER)  += charger-manager.o
-obj-$(CONFIG_CHARGER_LTC3651)  += ltc3651-charger.o
+obj-$(CONFIG_CHARGER_LT3651)   += lt3651-charger.o
 obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
 obj-$(CONFIG_CHARGER_DETECTOR_MAX14656)        += max14656_charger_detector.o
+obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o
 obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
 obj-$(CONFIG_CHARGER_MAX8997)  += max8997_charger.o
 obj-$(CONFIG_CHARGER_MAX8998)  += max8998_charger.o
@@ -87,3 +89,4 @@ obj-$(CONFIG_AXP288_CHARGER)  += axp288_charger.o
 obj-$(CONFIG_CHARGER_CROS_USBPD)       += cros_usbpd-charger.o
 obj-$(CONFIG_CHARGER_SC2731)   += sc2731_charger.o
 obj-$(CONFIG_FUEL_GAUGE_SC27XX)        += sc27xx_fuel_gauge.o
+obj-$(CONFIG_CHARGER_UCS1002)  += ucs1002_power.o
index 7b2b69916f48c7004b5545c07dd015952babd679..f6a66979cbb5238882a7dc7b41eb8d93383b9c97 100644 (file)
@@ -508,6 +508,7 @@ int ab8500_bm_of_probe(struct device *dev,
        btech = of_get_property(battery_node, "stericsson,battery-type", NULL);
        if (!btech) {
                dev_warn(dev, "missing property battery-name/type\n");
+               of_node_put(battery_node);
                return -EINVAL;
        }
 
index f52fe77edb6f8fb4d48135da9fb6dfc1a0588c3d..d2b1255ee1cc464f5e86f105f2ecaef4ebe362a5 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/iio/consumer.h>
+#include <linux/workqueue.h>
 
 #define DRVNAME "axp20x-usb-power-supply"
 
 #define AXP20X_VBUS_VHOLD_MASK         GENMASK(5, 3)
 #define AXP20X_VBUS_VHOLD_OFFSET       3
 #define AXP20X_VBUS_CLIMIT_MASK                3
-#define AXP20X_VBUC_CLIMIT_900mA       0
-#define AXP20X_VBUC_CLIMIT_500mA       1
-#define AXP20X_VBUC_CLIMIT_100mA       2
-#define AXP20X_VBUC_CLIMIT_NONE                3
+#define AXP20X_VBUS_CLIMIT_900mA       0
+#define AXP20X_VBUS_CLIMIT_500mA       1
+#define AXP20X_VBUS_CLIMIT_100mA       2
+#define AXP20X_VBUS_CLIMIT_NONE                3
+
+#define AXP813_VBUS_CLIMIT_900mA       0
+#define AXP813_VBUS_CLIMIT_1500mA      1
+#define AXP813_VBUS_CLIMIT_2000mA      2
+#define AXP813_VBUS_CLIMIT_2500mA      3
 
 #define AXP20X_ADC_EN1_VBUS_CURR       BIT(2)
 #define AXP20X_ADC_EN1_VBUS_VOLT       BIT(3)
 
 #define AXP20X_VBUS_MON_VBUS_VALID     BIT(3)
 
+/*
+ * Note do not raise the debounce time, we must report Vusb high within
+ * 100ms otherwise we get Vbus errors in musb.
+ */
+#define DEBOUNCE_TIME                  msecs_to_jiffies(50)
+
 struct axp20x_usb_power {
        struct device_node *np;
        struct regmap *regmap;
@@ -53,6 +65,8 @@ struct axp20x_usb_power {
        enum axp20x_variants axp20x_id;
        struct iio_channel *vbus_v;
        struct iio_channel *vbus_i;
+       struct delayed_work vbus_detect;
+       unsigned int old_status;
 };
 
 static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
@@ -64,6 +78,89 @@ static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
        return IRQ_HANDLED;
 }
 
+static void axp20x_usb_power_poll_vbus(struct work_struct *work)
+{
+       struct axp20x_usb_power *power =
+               container_of(work, struct axp20x_usb_power, vbus_detect.work);
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &val);
+       if (ret)
+               goto out;
+
+       val &= (AXP20X_PWR_STATUS_VBUS_PRESENT | AXP20X_PWR_STATUS_VBUS_USED);
+       if (val != power->old_status)
+               power_supply_changed(power->supply);
+
+       power->old_status = val;
+
+out:
+       mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
+}
+
+static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power)
+{
+       if (power->axp20x_id >= AXP221_ID)
+               return true;
+
+       return false;
+}
+
+static int axp20x_get_current_max(struct axp20x_usb_power *power, int *val)
+{
+       unsigned int v;
+       int ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v);
+
+       if (ret)
+               return ret;
+
+       switch (v & AXP20X_VBUS_CLIMIT_MASK) {
+       case AXP20X_VBUS_CLIMIT_100mA:
+               if (power->axp20x_id == AXP221_ID)
+                       *val = -1; /* No 100mA limit */
+               else
+                       *val = 100000;
+               break;
+       case AXP20X_VBUS_CLIMIT_500mA:
+               *val = 500000;
+               break;
+       case AXP20X_VBUS_CLIMIT_900mA:
+               *val = 900000;
+               break;
+       case AXP20X_VBUS_CLIMIT_NONE:
+               *val = -1;
+               break;
+       }
+
+       return 0;
+}
+
+static int axp813_get_current_max(struct axp20x_usb_power *power, int *val)
+{
+       unsigned int v;
+       int ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v);
+
+       if (ret)
+               return ret;
+
+       switch (v & AXP20X_VBUS_CLIMIT_MASK) {
+       case AXP813_VBUS_CLIMIT_900mA:
+               *val = 900000;
+               break;
+       case AXP813_VBUS_CLIMIT_1500mA:
+               *val = 1500000;
+               break;
+       case AXP813_VBUS_CLIMIT_2000mA:
+               *val = 2000000;
+               break;
+       case AXP813_VBUS_CLIMIT_2500mA:
+               *val = 2500000;
+               break;
+       }
+       return 0;
+}
+
 static int axp20x_usb_power_get_property(struct power_supply *psy,
        enum power_supply_property psp, union power_supply_propval *val)
 {
@@ -102,28 +199,9 @@ static int axp20x_usb_power_get_property(struct power_supply *psy,
                val->intval = ret * 1700; /* 1 step = 1.7 mV */
                return 0;
        case POWER_SUPPLY_PROP_CURRENT_MAX:
-               ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v);
-               if (ret)
-                       return ret;
-
-               switch (v & AXP20X_VBUS_CLIMIT_MASK) {
-               case AXP20X_VBUC_CLIMIT_100mA:
-                       if (power->axp20x_id == AXP221_ID)
-                               val->intval = -1; /* No 100mA limit */
-                       else
-                               val->intval = 100000;
-                       break;
-               case AXP20X_VBUC_CLIMIT_500mA:
-                       val->intval = 500000;
-                       break;
-               case AXP20X_VBUC_CLIMIT_900mA:
-                       val->intval = 900000;
-                       break;
-               case AXP20X_VBUC_CLIMIT_NONE:
-                       val->intval = -1;
-                       break;
-               }
-               return 0;
+               if (power->axp20x_id == AXP813_ID)
+                       return axp813_get_current_max(power, &val->intval);
+               return axp20x_get_current_max(power, &val->intval);
        case POWER_SUPPLY_PROP_CURRENT_NOW:
                if (IS_ENABLED(CONFIG_AXP20X_ADC)) {
                        ret = iio_read_channel_processed(power->vbus_i,
@@ -214,6 +292,31 @@ static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power,
        return -EINVAL;
 }
 
+static int axp813_usb_power_set_current_max(struct axp20x_usb_power *power,
+                                           int intval)
+{
+       int val;
+
+       switch (intval) {
+       case 900000:
+               return regmap_update_bits(power->regmap,
+                                         AXP20X_VBUS_IPSOUT_MGMT,
+                                         AXP20X_VBUS_CLIMIT_MASK,
+                                         AXP813_VBUS_CLIMIT_900mA);
+       case 1500000:
+       case 2000000:
+       case 2500000:
+               val = (intval - 1000000) / 500000;
+               return regmap_update_bits(power->regmap,
+                                         AXP20X_VBUS_IPSOUT_MGMT,
+                                         AXP20X_VBUS_CLIMIT_MASK, val);
+       default:
+               return -EINVAL;
+       }
+
+       return -EINVAL;
+}
+
 static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power,
                                            int intval)
 {
@@ -248,6 +351,9 @@ static int axp20x_usb_power_set_property(struct power_supply *psy,
                return axp20x_usb_power_set_voltage_min(power, val->intval);
 
        case POWER_SUPPLY_PROP_CURRENT_MAX:
+               if (power->axp20x_id == AXP813_ID)
+                       return axp813_usb_power_set_current_max(power,
+                                                               val->intval);
                return axp20x_usb_power_set_current_max(power, val->intval);
 
        default:
@@ -357,6 +463,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
        if (!power)
                return -ENOMEM;
 
+       platform_set_drvdata(pdev, power);
        power->axp20x_id = (enum axp20x_variants)of_device_get_match_data(
                                                                &pdev->dev);
 
@@ -382,7 +489,8 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
                usb_power_desc = &axp20x_usb_power_desc;
                irq_names = axp20x_irq_names;
        } else if (power->axp20x_id == AXP221_ID ||
-                  power->axp20x_id == AXP223_ID) {
+                  power->axp20x_id == AXP223_ID ||
+                  power->axp20x_id == AXP813_ID) {
                usb_power_desc = &axp22x_usb_power_desc;
                irq_names = axp22x_irq_names;
        } else {
@@ -415,6 +523,19 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
                                 irq_names[i], ret);
        }
 
+       INIT_DELAYED_WORK(&power->vbus_detect, axp20x_usb_power_poll_vbus);
+       if (axp20x_usb_vbus_needs_polling(power))
+               queue_delayed_work(system_wq, &power->vbus_detect, 0);
+
+       return 0;
+}
+
+static int axp20x_usb_power_remove(struct platform_device *pdev)
+{
+       struct axp20x_usb_power *power = platform_get_drvdata(pdev);
+
+       cancel_delayed_work_sync(&power->vbus_detect);
+
        return 0;
 }
 
@@ -428,12 +549,16 @@ static const struct of_device_id axp20x_usb_power_match[] = {
        }, {
                .compatible = "x-powers,axp223-usb-power-supply",
                .data = (void *)AXP223_ID,
+       }, {
+               .compatible = "x-powers,axp813-usb-power-supply",
+               .data = (void *)AXP813_ID,
        }, { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, axp20x_usb_power_match);
 
 static struct platform_driver axp20x_usb_power_driver = {
        .probe = axp20x_usb_power_probe,
+       .remove = axp20x_usb_power_remove,
        .driver = {
                .name = DRVNAME,
                .of_match_table = axp20x_usb_power_match,
index f8c6da9277b3e061e080c21d0fc520b31d2daed2..00b961890a383ed6d31b71c4c7d66268555fc2fc 100644 (file)
@@ -833,6 +833,10 @@ static int axp288_charger_probe(struct platform_device *pdev)
        /* Register charger interrupts */
        for (i = 0; i < CHRG_INTR_END; i++) {
                pirq = platform_get_irq(info->pdev, i);
+               if (pirq < 0) {
+                       dev_err(&pdev->dev, "Failed to get IRQ: %d\n", pirq);
+                       return pirq;
+               }
                info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq);
                if (info->irq[i] < 0) {
                        dev_warn(&info->pdev->dev,
index 9ff2461820d805c3abd7de964f04f4fc1cb217bc..368281bc0d2bcfbbdc98a6a3ba3a45486d6851d9 100644 (file)
@@ -685,6 +685,26 @@ intr_failed:
  * detection reports one despite it not being there.
  */
 static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = {
+       {
+               /* ACEPC T8 Cherry Trail Z8350 mini PC */
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "T8"),
+                       /* also match on somewhat unique bios-version */
+                       DMI_EXACT_MATCH(DMI_BIOS_VERSION, "1.000"),
+               },
+       },
+       {
+               /* ACEPC T11 Cherry Trail Z8350 mini PC */
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "T11"),
+                       /* also match on somewhat unique bios-version */
+                       DMI_EXACT_MATCH(DMI_BIOS_VERSION, "1.000"),
+               },
+       },
        {
                /* Intel Cherry Trail Compute Stick, Windows version */
                .matches = {
index 29b3a40568650695990c0dcb9e5a0f1ca1192cc0..195c18c2f426e6d4d675c92ca5336fcf0166e83a 100644 (file)
@@ -1612,7 +1612,8 @@ void bq27xxx_battery_update(struct bq27xxx_device_info *di)
                        di->charge_design_full = bq27xxx_battery_read_dcap(di);
        }
 
-       if (di->cache.capacity != cache.capacity)
+       if ((di->cache.capacity != cache.capacity) ||
+           (di->cache.flags != cache.flags))
                power_supply_changed(di->bat);
 
        if (memcmp(&di->cache, &cache, sizeof(cache)) != 0)
index 2e8db5e6de0bcb6af1bec0cc46ec106312ca796b..a6900aa0d2edd39768aa001ae0855fca550d4dfe 100644 (file)
@@ -1987,6 +1987,9 @@ static struct platform_driver charger_manager_driver = {
 static int __init charger_manager_init(void)
 {
        cm_wq = create_freezable_workqueue("charger_manager");
+       if (unlikely(!cm_wq))
+               return -ENOMEM;
+
        INIT_DELAYED_WORK(&cm_monitor_work, cm_monitor_poller);
 
        return platform_driver_register(&charger_manager_driver);
index 6887870ba32c38b075145500b173052f45226206..61d6447d1966f4c02fbc89904bf2382c67304b20 100644 (file)
@@ -82,9 +82,9 @@ struct cpcap_battery_config {
 };
 
 struct cpcap_coulomb_counter_data {
-       s32 sample;             /* 24-bits */
+       s32 sample;             /* 24 or 32 bits */
        s32 accumulator;
-       s16 offset;             /* 10-bits */
+       s16 offset;             /* bits */
 };
 
 enum cpcap_battery_state {
@@ -213,7 +213,7 @@ static int cpcap_battery_get_current(struct cpcap_battery_ddata *ddata)
  * TI or ST coulomb counter in the PMIC.
  */
 static int cpcap_battery_cc_raw_div(struct cpcap_battery_ddata *ddata,
-                                   u32 sample, s32 accumulator,
+                                   s32 sample, s32 accumulator,
                                    s16 offset, u32 divider)
 {
        s64 acc;
@@ -224,9 +224,6 @@ static int cpcap_battery_cc_raw_div(struct cpcap_battery_ddata *ddata,
        if (!divider)
                return 0;
 
-       sample &= 0xffffff;             /* 24-bits, unsigned */
-       offset &= 0x7ff;                /* 10-bits, signed */
-
        switch (ddata->vendor) {
        case CPCAP_VENDOR_ST:
                cc_lsb = 95374;         /* μAms per LSB */
@@ -259,7 +256,7 @@ static int cpcap_battery_cc_raw_div(struct cpcap_battery_ddata *ddata,
 
 /* 3600000μAms = 1μAh */
 static int cpcap_battery_cc_to_uah(struct cpcap_battery_ddata *ddata,
-                                  u32 sample, s32 accumulator,
+                                  s32 sample, s32 accumulator,
                                   s16 offset)
 {
        return cpcap_battery_cc_raw_div(ddata, sample,
@@ -268,7 +265,7 @@ static int cpcap_battery_cc_to_uah(struct cpcap_battery_ddata *ddata,
 }
 
 static int cpcap_battery_cc_to_ua(struct cpcap_battery_ddata *ddata,
-                                 u32 sample, s32 accumulator,
+                                 s32 sample, s32 accumulator,
                                  s16 offset)
 {
        return cpcap_battery_cc_raw_div(ddata, sample,
@@ -312,17 +309,19 @@ cpcap_battery_read_accumulated(struct cpcap_battery_ddata *ddata,
        /* Sample value CPCAP_REG_CCS1 & 2 */
        ccd->sample = (buf[1] & 0x0fff) << 16;
        ccd->sample |= buf[0];
+       if (ddata->vendor == CPCAP_VENDOR_TI)
+               ccd->sample = sign_extend32(24, ccd->sample);
 
        /* Accumulator value CPCAP_REG_CCA1 & 2 */
        ccd->accumulator = ((s16)buf[3]) << 16;
        ccd->accumulator |= buf[2];
 
-       /* Offset value CPCAP_REG_CCO */
-       ccd->offset = buf[5];
-
-       /* Adjust offset based on mode value CPCAP_REG_CCM? */
-       if (buf[4] >= 0x200)
-               ccd->offset |= 0xfc00;
+       /*
+        * Coulomb counter calibration offset is CPCAP_REG_CCM,
+        * REG_CCO seems unused
+        */
+       ccd->offset = buf[4];
+       ccd->offset = sign_extend32(ccd->offset, 9);
 
        return cpcap_battery_cc_to_uah(ddata,
                                       ccd->sample,
@@ -477,11 +476,11 @@ static int cpcap_battery_get_property(struct power_supply *psy,
                val->intval = ddata->config.info.voltage_min_design;
                break;
        case POWER_SUPPLY_PROP_CURRENT_AVG:
-               if (cached) {
+               sample = latest->cc.sample - previous->cc.sample;
+               if (!sample) {
                        val->intval = cpcap_battery_cc_get_avg_current(ddata);
                        break;
                }
-               sample = latest->cc.sample - previous->cc.sample;
                accumulator = latest->cc.accumulator - previous->cc.accumulator;
                val->intval = cpcap_battery_cc_to_ua(ddata, sample,
                                                     accumulator,
@@ -498,13 +497,13 @@ static int cpcap_battery_get_property(struct power_supply *psy,
                val->intval = div64_s64(tmp, 100);
                break;
        case POWER_SUPPLY_PROP_POWER_AVG:
-               if (cached) {
+               sample = latest->cc.sample - previous->cc.sample;
+               if (!sample) {
                        tmp = cpcap_battery_cc_get_avg_current(ddata);
                        tmp *= (latest->voltage / 10000);
                        val->intval = div64_s64(tmp, 100);
                        break;
                }
-               sample = latest->cc.sample - previous->cc.sample;
                accumulator = latest->cc.accumulator - previous->cc.accumulator;
                tmp = cpcap_battery_cc_to_ua(ddata, sample, accumulator,
                                             latest->cc.offset);
@@ -562,11 +561,11 @@ static irqreturn_t cpcap_battery_irq_thread(int irq, void *data)
 
        switch (d->action) {
        case CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW:
-               if (latest->counter_uah >= 0)
+               if (latest->current_ua >= 0)
                        dev_warn(ddata->dev, "Battery low at 3.3V!\n");
                break;
        case CPCAP_BATTERY_IRQ_ACTION_POWEROFF:
-               if (latest->counter_uah >= 0) {
+               if (latest->current_ua >= 0) {
                        dev_emerg(ddata->dev,
                                  "Battery empty at 3.1V, powering off\n");
                        orderly_poweroff(true);
@@ -670,8 +669,9 @@ static int cpcap_battery_init_iio(struct cpcap_battery_ddata *ddata)
        return 0;
 
 out_err:
-       dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n",
-               error);
+       if (error != -EPROBE_DEFER)
+               dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n",
+                       error);
 
        return error;
 }
index c3ed7b476676dd069ce22efa0df02c3200aaa5b3..b4781b5d1e10fade2afce0bf846660df9ed98cfd 100644 (file)
@@ -574,8 +574,9 @@ static int cpcap_charger_init_iio(struct cpcap_charger_ddata *ddata)
        return 0;
 
 out_err:
-       dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n",
-               error);
+       if (error != -EPROBE_DEFER)
+               dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n",
+                       error);
 
        return error;
 }
index 7e4f11d5a23029dcbc04f65a0d05bc441d47268b..f99e8f1eef23367646d1f5ccc375452834078ad9 100644 (file)
 
 struct gpio_charger {
        unsigned int irq;
+       unsigned int charge_status_irq;
        bool wakeup_enabled;
 
        struct power_supply *charger;
        struct power_supply_desc charger_desc;
        struct gpio_desc *gpiod;
+       struct gpio_desc *charge_status;
 };
 
 static irqreturn_t gpio_charger_irq(int irq, void *devid)
@@ -59,6 +61,12 @@ static int gpio_charger_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_ONLINE:
                val->intval = gpiod_get_value_cansleep(gpio_charger->gpiod);
                break;
+       case POWER_SUPPLY_PROP_STATUS:
+               if (gpiod_get_value_cansleep(gpio_charger->charge_status))
+                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
+               else
+                       val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               break;
        default:
                return -EINVAL;
        }
@@ -93,8 +101,29 @@ static enum power_supply_type gpio_charger_get_type(struct device *dev)
        return POWER_SUPPLY_TYPE_UNKNOWN;
 }
 
+static int gpio_charger_get_irq(struct device *dev, void *dev_id,
+                               struct gpio_desc *gpio)
+{
+       int ret, irq = gpiod_to_irq(gpio);
+
+       if (irq > 0) {
+               ret = devm_request_any_context_irq(dev, irq, gpio_charger_irq,
+                                                  IRQF_TRIGGER_RISING |
+                                                  IRQF_TRIGGER_FALLING,
+                                                  dev_name(dev),
+                                                  dev_id);
+               if (ret < 0) {
+                       dev_warn(dev, "Failed to request irq: %d\n", ret);
+                       irq = 0;
+               }
+       }
+
+       return irq;
+}
+
 static enum power_supply_property gpio_charger_properties[] = {
        POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_STATUS /* Must always be last in the array. */
 };
 
 static int gpio_charger_probe(struct platform_device *pdev)
@@ -104,8 +133,10 @@ static int gpio_charger_probe(struct platform_device *pdev)
        struct power_supply_config psy_cfg = {};
        struct gpio_charger *gpio_charger;
        struct power_supply_desc *charger_desc;
+       struct gpio_desc *charge_status;
+       int charge_status_irq;
        unsigned long flags;
-       int irq, ret;
+       int ret;
 
        if (!pdata && !dev->of_node) {
                dev_err(dev, "No platform data\n");
@@ -151,9 +182,17 @@ static int gpio_charger_probe(struct platform_device *pdev)
                return PTR_ERR(gpio_charger->gpiod);
        }
 
+       charge_status = devm_gpiod_get_optional(dev, "charge-status", GPIOD_IN);
+       gpio_charger->charge_status = charge_status;
+       if (IS_ERR(gpio_charger->charge_status))
+               return PTR_ERR(gpio_charger->charge_status);
+
        charger_desc = &gpio_charger->charger_desc;
        charger_desc->properties = gpio_charger_properties;
        charger_desc->num_properties = ARRAY_SIZE(gpio_charger_properties);
+       /* Remove POWER_SUPPLY_PROP_STATUS from the supported properties. */
+       if (!gpio_charger->charge_status)
+               charger_desc->num_properties -= 1;
        charger_desc->get_property = gpio_charger_get_property;
 
        psy_cfg.of_node = dev->of_node;
@@ -180,16 +219,12 @@ static int gpio_charger_probe(struct platform_device *pdev)
                return ret;
        }
 
-       irq = gpiod_to_irq(gpio_charger->gpiod);
-       if (irq > 0) {
-               ret = devm_request_any_context_irq(dev, irq, gpio_charger_irq,
-                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                               dev_name(dev), gpio_charger->charger);
-               if (ret < 0)
-                       dev_warn(dev, "Failed to request irq: %d\n", ret);
-               else
-                       gpio_charger->irq = irq;
-       }
+       gpio_charger->irq = gpio_charger_get_irq(dev, gpio_charger->charger,
+                                                gpio_charger->gpiod);
+
+       charge_status_irq = gpio_charger_get_irq(dev, gpio_charger->charger,
+                                                gpio_charger->charge_status);
+       gpio_charger->charge_status_irq = charge_status_irq;
 
        platform_set_drvdata(pdev, gpio_charger);
 
diff --git a/drivers/power/supply/ingenic-battery.c b/drivers/power/supply/ingenic-battery.c
new file mode 100644 (file)
index 0000000..35816d4
--- /dev/null
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Battery driver for the Ingenic JZ47xx SoCs
+ * Copyright (c) 2019 Artur Rojek <contact@artur-rojek.eu>
+ *
+ * based on drivers/power/supply/jz4740-battery.c
+ */
+
+#include <linux/iio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/property.h>
+
+struct ingenic_battery {
+       struct device *dev;
+       struct iio_channel *channel;
+       struct power_supply_desc desc;
+       struct power_supply *battery;
+       struct power_supply_battery_info info;
+};
+
+static int ingenic_battery_get_property(struct power_supply *psy,
+                                       enum power_supply_property psp,
+                                       union power_supply_propval *val)
+{
+       struct ingenic_battery *bat = power_supply_get_drvdata(psy);
+       struct power_supply_battery_info *info = &bat->info;
+       int ret;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_HEALTH:
+               ret = iio_read_channel_processed(bat->channel, &val->intval);
+               val->intval *= 1000;
+               if (val->intval < info->voltage_min_design_uv)
+                       val->intval = POWER_SUPPLY_HEALTH_DEAD;
+               else if (val->intval > info->voltage_max_design_uv)
+                       val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+               else
+                       val->intval = POWER_SUPPLY_HEALTH_GOOD;
+               return ret;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               ret = iio_read_channel_processed(bat->channel, &val->intval);
+               val->intval *= 1000;
+               return ret;
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+               val->intval = info->voltage_min_design_uv;
+               return 0;
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+               val->intval = info->voltage_max_design_uv;
+               return 0;
+       default:
+               return -EINVAL;
+       };
+}
+
+/* Set the most appropriate IIO channel voltage reference scale
+ * based on the battery's max voltage.
+ */
+static int ingenic_battery_set_scale(struct ingenic_battery *bat)
+{
+       const int *scale_raw;
+       int scale_len, scale_type, best_idx = -1, best_mV, max_raw, i, ret;
+       u64 max_mV;
+
+       ret = iio_read_max_channel_raw(bat->channel, &max_raw);
+       if (ret) {
+               dev_err(bat->dev, "Unable to read max raw channel value\n");
+               return ret;
+       }
+
+       ret = iio_read_avail_channel_attribute(bat->channel, &scale_raw,
+                                              &scale_type, &scale_len,
+                                              IIO_CHAN_INFO_SCALE);
+       if (ret < 0) {
+               dev_err(bat->dev, "Unable to read channel avail scale\n");
+               return ret;
+       }
+       if (ret != IIO_AVAIL_LIST || scale_type != IIO_VAL_FRACTIONAL_LOG2)
+               return -EINVAL;
+
+       max_mV = bat->info.voltage_max_design_uv / 1000;
+
+       for (i = 0; i < scale_len; i += 2) {
+               u64 scale_mV = (max_raw * scale_raw[i]) >> scale_raw[i + 1];
+
+               if (scale_mV < max_mV)
+                       continue;
+
+               if (best_idx >= 0 && scale_mV > best_mV)
+                       continue;
+
+               best_mV = scale_mV;
+               best_idx = i;
+       }
+
+       if (best_idx < 0) {
+               dev_err(bat->dev, "Unable to find matching voltage scale\n");
+               return -EINVAL;
+       }
+
+       return iio_write_channel_attribute(bat->channel,
+                                          scale_raw[best_idx],
+                                          scale_raw[best_idx + 1],
+                                          IIO_CHAN_INFO_SCALE);
+}
+
+static enum power_supply_property ingenic_battery_properties[] = {
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+};
+
+static int ingenic_battery_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ingenic_battery *bat;
+       struct power_supply_config psy_cfg = {};
+       struct power_supply_desc *desc;
+       int ret;
+
+       bat = devm_kzalloc(dev, sizeof(*bat), GFP_KERNEL);
+       if (!bat)
+               return -ENOMEM;
+
+       bat->dev = dev;
+       bat->channel = devm_iio_channel_get(dev, "battery");
+       if (IS_ERR(bat->channel))
+               return PTR_ERR(bat->channel);
+
+       desc = &bat->desc;
+       desc->name = "jz-battery";
+       desc->type = POWER_SUPPLY_TYPE_BATTERY;
+       desc->properties = ingenic_battery_properties;
+       desc->num_properties = ARRAY_SIZE(ingenic_battery_properties);
+       desc->get_property = ingenic_battery_get_property;
+       psy_cfg.drv_data = bat;
+       psy_cfg.of_node = dev->of_node;
+
+       bat->battery = devm_power_supply_register(dev, desc, &psy_cfg);
+       if (IS_ERR(bat->battery)) {
+               dev_err(dev, "Unable to register battery\n");
+               return PTR_ERR(bat->battery);
+       }
+
+       ret = power_supply_get_battery_info(bat->battery, &bat->info);
+       if (ret) {
+               dev_err(dev, "Unable to get battery info: %d\n", ret);
+               return ret;
+       }
+       if (bat->info.voltage_min_design_uv < 0) {
+               dev_err(dev, "Unable to get voltage min design\n");
+               return bat->info.voltage_min_design_uv;
+       }
+       if (bat->info.voltage_max_design_uv < 0) {
+               dev_err(dev, "Unable to get voltage max design\n");
+               return bat->info.voltage_max_design_uv;
+       }
+
+       return ingenic_battery_set_scale(bat);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id ingenic_battery_of_match[] = {
+       { .compatible = "ingenic,jz4740-battery", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, ingenic_battery_of_match);
+#endif
+
+static struct platform_driver ingenic_battery_driver = {
+       .driver = {
+               .name = "ingenic-battery",
+               .of_match_table = of_match_ptr(ingenic_battery_of_match),
+       },
+       .probe = ingenic_battery_probe,
+};
+module_platform_driver(ingenic_battery_driver);
+
+MODULE_DESCRIPTION("Battery driver for Ingenic JZ47xx SoCs");
+MODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/supply/lt3651-charger.c b/drivers/power/supply/lt3651-charger.c
new file mode 100644 (file)
index 0000000..8de500f
--- /dev/null
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  Driver for Analog Devices (Linear Technology) LT3651 charger IC.
+ *  Copyright (C) 2017, Topic Embedded Products
+ */
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+struct lt3651_charger {
+       struct power_supply *charger;
+       struct power_supply_desc charger_desc;
+       struct gpio_desc *acpr_gpio;
+       struct gpio_desc *fault_gpio;
+       struct gpio_desc *chrg_gpio;
+};
+
+static irqreturn_t lt3651_charger_irq(int irq, void *devid)
+{
+       struct power_supply *charger = devid;
+
+       power_supply_changed(charger);
+
+       return IRQ_HANDLED;
+}
+
+static inline struct lt3651_charger *psy_to_lt3651_charger(
+       struct power_supply *psy)
+{
+       return power_supply_get_drvdata(psy);
+}
+
+static int lt3651_charger_get_property(struct power_supply *psy,
+               enum power_supply_property psp, union power_supply_propval *val)
+{
+       struct lt3651_charger *lt3651_charger = psy_to_lt3651_charger(psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               if (!lt3651_charger->chrg_gpio) {
+                       val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+                       break;
+               }
+               if (gpiod_get_value(lt3651_charger->chrg_gpio))
+                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
+               else
+                       val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = gpiod_get_value(lt3651_charger->acpr_gpio);
+               break;
+       case POWER_SUPPLY_PROP_HEALTH:
+               if (!lt3651_charger->fault_gpio) {
+                       val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
+                       break;
+               }
+               if (!gpiod_get_value(lt3651_charger->fault_gpio)) {
+                       val->intval = POWER_SUPPLY_HEALTH_GOOD;
+                       break;
+               }
+               /*
+                * If the fault pin is active, the chrg pin explains the type
+                * of failure.
+                */
+               if (!lt3651_charger->chrg_gpio) {
+                       val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+                       break;
+               }
+               val->intval = gpiod_get_value(lt3651_charger->chrg_gpio) ?
+                               POWER_SUPPLY_HEALTH_OVERHEAT :
+                               POWER_SUPPLY_HEALTH_DEAD;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static enum power_supply_property lt3651_charger_properties[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_HEALTH,
+};
+
+static int lt3651_charger_probe(struct platform_device *pdev)
+{
+       struct power_supply_config psy_cfg = {};
+       struct lt3651_charger *lt3651_charger;
+       struct power_supply_desc *charger_desc;
+       int ret;
+
+       lt3651_charger = devm_kzalloc(&pdev->dev, sizeof(*lt3651_charger),
+                                       GFP_KERNEL);
+       if (!lt3651_charger)
+               return -ENOMEM;
+
+       lt3651_charger->acpr_gpio = devm_gpiod_get(&pdev->dev,
+                                       "lltc,acpr", GPIOD_IN);
+       if (IS_ERR(lt3651_charger->acpr_gpio)) {
+               ret = PTR_ERR(lt3651_charger->acpr_gpio);
+               dev_err(&pdev->dev, "Failed to acquire acpr GPIO: %d\n", ret);
+               return ret;
+       }
+       lt3651_charger->fault_gpio = devm_gpiod_get_optional(&pdev->dev,
+                                       "lltc,fault", GPIOD_IN);
+       if (IS_ERR(lt3651_charger->fault_gpio)) {
+               ret = PTR_ERR(lt3651_charger->fault_gpio);
+               dev_err(&pdev->dev, "Failed to acquire fault GPIO: %d\n", ret);
+               return ret;
+       }
+       lt3651_charger->chrg_gpio = devm_gpiod_get_optional(&pdev->dev,
+                                       "lltc,chrg", GPIOD_IN);
+       if (IS_ERR(lt3651_charger->chrg_gpio)) {
+               ret = PTR_ERR(lt3651_charger->chrg_gpio);
+               dev_err(&pdev->dev, "Failed to acquire chrg GPIO: %d\n", ret);
+               return ret;
+       }
+
+       charger_desc = &lt3651_charger->charger_desc;
+       charger_desc->name = pdev->dev.of_node->name;
+       charger_desc->type = POWER_SUPPLY_TYPE_MAINS;
+       charger_desc->properties = lt3651_charger_properties;
+       charger_desc->num_properties = ARRAY_SIZE(lt3651_charger_properties);
+       charger_desc->get_property = lt3651_charger_get_property;
+       psy_cfg.of_node = pdev->dev.of_node;
+       psy_cfg.drv_data = lt3651_charger;
+
+       lt3651_charger->charger = devm_power_supply_register(&pdev->dev,
+                                                     charger_desc, &psy_cfg);
+       if (IS_ERR(lt3651_charger->charger)) {
+               ret = PTR_ERR(lt3651_charger->charger);
+               dev_err(&pdev->dev, "Failed to register power supply: %d\n",
+                       ret);
+               return ret;
+       }
+
+       /*
+        * Acquire IRQs for the GPIO pins if possible. If the system does not
+        * support IRQs on these pins, userspace will have to poll the sysfs
+        * files manually.
+        */
+       if (lt3651_charger->acpr_gpio) {
+               ret = gpiod_to_irq(lt3651_charger->acpr_gpio);
+               if (ret >= 0)
+                       ret = devm_request_any_context_irq(&pdev->dev, ret,
+                               lt3651_charger_irq,
+                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                               dev_name(&pdev->dev), lt3651_charger->charger);
+               if (ret < 0)
+                       dev_warn(&pdev->dev, "Failed to request acpr irq\n");
+       }
+       if (lt3651_charger->fault_gpio) {
+               ret = gpiod_to_irq(lt3651_charger->fault_gpio);
+               if (ret >= 0)
+                       ret = devm_request_any_context_irq(&pdev->dev, ret,
+                               lt3651_charger_irq,
+                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                               dev_name(&pdev->dev), lt3651_charger->charger);
+               if (ret < 0)
+                       dev_warn(&pdev->dev, "Failed to request fault irq\n");
+       }
+       if (lt3651_charger->chrg_gpio) {
+               ret = gpiod_to_irq(lt3651_charger->chrg_gpio);
+               if (ret >= 0)
+                       ret = devm_request_any_context_irq(&pdev->dev, ret,
+                               lt3651_charger_irq,
+                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                               dev_name(&pdev->dev), lt3651_charger->charger);
+               if (ret < 0)
+                       dev_warn(&pdev->dev, "Failed to request chrg irq\n");
+       }
+
+       platform_set_drvdata(pdev, lt3651_charger);
+
+       return 0;
+}
+
+static const struct of_device_id lt3651_charger_match[] = {
+       { .compatible = "lltc,ltc3651-charger" }, /* DEPRECATED */
+       { .compatible = "lltc,lt3651-charger" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, lt3651_charger_match);
+
+static struct platform_driver lt3651_charger_driver = {
+       .probe = lt3651_charger_probe,
+       .driver = {
+               .name = "lt3651-charger",
+               .of_match_table = lt3651_charger_match,
+       },
+};
+
+module_platform_driver(lt3651_charger_driver);
+
+MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
+MODULE_DESCRIPTION("Driver for LT3651 charger");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lt3651-charger");
diff --git a/drivers/power/supply/ltc3651-charger.c b/drivers/power/supply/ltc3651-charger.c
deleted file mode 100644 (file)
index eea63ff..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- *  Copyright (C) 2017, Topic Embedded Products
- *  Driver for LTC3651 charger IC.
- *
- *  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.
- */
-
-#include <linux/device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/power_supply.h>
-#include <linux/slab.h>
-#include <linux/of.h>
-
-struct ltc3651_charger {
-       struct power_supply *charger;
-       struct power_supply_desc charger_desc;
-       struct gpio_desc *acpr_gpio;
-       struct gpio_desc *fault_gpio;
-       struct gpio_desc *chrg_gpio;
-};
-
-static irqreturn_t ltc3651_charger_irq(int irq, void *devid)
-{
-       struct power_supply *charger = devid;
-
-       power_supply_changed(charger);
-
-       return IRQ_HANDLED;
-}
-
-static inline struct ltc3651_charger *psy_to_ltc3651_charger(
-       struct power_supply *psy)
-{
-       return power_supply_get_drvdata(psy);
-}
-
-static int ltc3651_charger_get_property(struct power_supply *psy,
-               enum power_supply_property psp, union power_supply_propval *val)
-{
-       struct ltc3651_charger *ltc3651_charger = psy_to_ltc3651_charger(psy);
-
-       switch (psp) {
-       case POWER_SUPPLY_PROP_STATUS:
-               if (!ltc3651_charger->chrg_gpio) {
-                       val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
-                       break;
-               }
-               if (gpiod_get_value(ltc3651_charger->chrg_gpio))
-                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
-               else
-                       val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
-               break;
-       case POWER_SUPPLY_PROP_ONLINE:
-               val->intval = gpiod_get_value(ltc3651_charger->acpr_gpio);
-               break;
-       case POWER_SUPPLY_PROP_HEALTH:
-               if (!ltc3651_charger->fault_gpio) {
-                       val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
-                       break;
-               }
-               if (!gpiod_get_value(ltc3651_charger->fault_gpio)) {
-                       val->intval = POWER_SUPPLY_HEALTH_GOOD;
-                       break;
-               }
-               /*
-                * If the fault pin is active, the chrg pin explains the type
-                * of failure.
-                */
-               if (!ltc3651_charger->chrg_gpio) {
-                       val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
-                       break;
-               }
-               val->intval = gpiod_get_value(ltc3651_charger->chrg_gpio) ?
-                               POWER_SUPPLY_HEALTH_OVERHEAT :
-                               POWER_SUPPLY_HEALTH_DEAD;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static enum power_supply_property ltc3651_charger_properties[] = {
-       POWER_SUPPLY_PROP_STATUS,
-       POWER_SUPPLY_PROP_ONLINE,
-       POWER_SUPPLY_PROP_HEALTH,
-};
-
-static int ltc3651_charger_probe(struct platform_device *pdev)
-{
-       struct power_supply_config psy_cfg = {};
-       struct ltc3651_charger *ltc3651_charger;
-       struct power_supply_desc *charger_desc;
-       int ret;
-
-       ltc3651_charger = devm_kzalloc(&pdev->dev, sizeof(*ltc3651_charger),
-                                       GFP_KERNEL);
-       if (!ltc3651_charger)
-               return -ENOMEM;
-
-       ltc3651_charger->acpr_gpio = devm_gpiod_get(&pdev->dev,
-                                       "lltc,acpr", GPIOD_IN);
-       if (IS_ERR(ltc3651_charger->acpr_gpio)) {
-               ret = PTR_ERR(ltc3651_charger->acpr_gpio);
-               dev_err(&pdev->dev, "Failed to acquire acpr GPIO: %d\n", ret);
-               return ret;
-       }
-       ltc3651_charger->fault_gpio = devm_gpiod_get_optional(&pdev->dev,
-                                       "lltc,fault", GPIOD_IN);
-       if (IS_ERR(ltc3651_charger->fault_gpio)) {
-               ret = PTR_ERR(ltc3651_charger->fault_gpio);
-               dev_err(&pdev->dev, "Failed to acquire fault GPIO: %d\n", ret);
-               return ret;
-       }
-       ltc3651_charger->chrg_gpio = devm_gpiod_get_optional(&pdev->dev,
-                                       "lltc,chrg", GPIOD_IN);
-       if (IS_ERR(ltc3651_charger->chrg_gpio)) {
-               ret = PTR_ERR(ltc3651_charger->chrg_gpio);
-               dev_err(&pdev->dev, "Failed to acquire chrg GPIO: %d\n", ret);
-               return ret;
-       }
-
-       charger_desc = &ltc3651_charger->charger_desc;
-       charger_desc->name = pdev->dev.of_node->name;
-       charger_desc->type = POWER_SUPPLY_TYPE_MAINS;
-       charger_desc->properties = ltc3651_charger_properties;
-       charger_desc->num_properties = ARRAY_SIZE(ltc3651_charger_properties);
-       charger_desc->get_property = ltc3651_charger_get_property;
-       psy_cfg.of_node = pdev->dev.of_node;
-       psy_cfg.drv_data = ltc3651_charger;
-
-       ltc3651_charger->charger = devm_power_supply_register(&pdev->dev,
-                                                     charger_desc, &psy_cfg);
-       if (IS_ERR(ltc3651_charger->charger)) {
-               ret = PTR_ERR(ltc3651_charger->charger);
-               dev_err(&pdev->dev, "Failed to register power supply: %d\n",
-                       ret);
-               return ret;
-       }
-
-       /*
-        * Acquire IRQs for the GPIO pins if possible. If the system does not
-        * support IRQs on these pins, userspace will have to poll the sysfs
-        * files manually.
-        */
-       if (ltc3651_charger->acpr_gpio) {
-               ret = gpiod_to_irq(ltc3651_charger->acpr_gpio);
-               if (ret >= 0)
-                       ret = devm_request_any_context_irq(&pdev->dev, ret,
-                               ltc3651_charger_irq,
-                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                               dev_name(&pdev->dev), ltc3651_charger->charger);
-               if (ret < 0)
-                       dev_warn(&pdev->dev, "Failed to request acpr irq\n");
-       }
-       if (ltc3651_charger->fault_gpio) {
-               ret = gpiod_to_irq(ltc3651_charger->fault_gpio);
-               if (ret >= 0)
-                       ret = devm_request_any_context_irq(&pdev->dev, ret,
-                               ltc3651_charger_irq,
-                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                               dev_name(&pdev->dev), ltc3651_charger->charger);
-               if (ret < 0)
-                       dev_warn(&pdev->dev, "Failed to request fault irq\n");
-       }
-       if (ltc3651_charger->chrg_gpio) {
-               ret = gpiod_to_irq(ltc3651_charger->chrg_gpio);
-               if (ret >= 0)
-                       ret = devm_request_any_context_irq(&pdev->dev, ret,
-                               ltc3651_charger_irq,
-                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                               dev_name(&pdev->dev), ltc3651_charger->charger);
-               if (ret < 0)
-                       dev_warn(&pdev->dev, "Failed to request chrg irq\n");
-       }
-
-       platform_set_drvdata(pdev, ltc3651_charger);
-
-       return 0;
-}
-
-static const struct of_device_id ltc3651_charger_match[] = {
-       { .compatible = "lltc,ltc3651-charger" },
-       { }
-};
-MODULE_DEVICE_TABLE(of, ltc3651_charger_match);
-
-static struct platform_driver ltc3651_charger_driver = {
-       .probe = ltc3651_charger_probe,
-       .driver = {
-               .name = "ltc3651-charger",
-               .of_match_table = ltc3651_charger_match,
-       },
-};
-
-module_platform_driver(ltc3651_charger_driver);
-
-MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
-MODULE_DESCRIPTION("Driver for LTC3651 charger");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:ltc3651-charger");
index b91b1d2999dc6d11ca4112ed160957947192843d..9e6472834e373010f34b3489895bfb88353b3885 100644 (file)
@@ -240,6 +240,14 @@ static enum power_supply_property max14656_battery_props[] = {
        POWER_SUPPLY_PROP_MANUFACTURER,
 };
 
+static void stop_irq_work(void *data)
+{
+       struct max14656_chip *chip = data;
+
+       cancel_delayed_work_sync(&chip->irq_work);
+}
+
+
 static int max14656_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
@@ -278,7 +286,19 @@ static int max14656_probe(struct i2c_client *client,
        if (ret)
                return -ENODEV;
 
+       chip->detect_psy = devm_power_supply_register(dev,
+                      &chip->psy_desc, &psy_cfg);
+       if (IS_ERR(chip->detect_psy)) {
+               dev_err(dev, "power_supply_register failed\n");
+               return -EINVAL;
+       }
+
        INIT_DELAYED_WORK(&chip->irq_work, max14656_irq_worker);
+       ret = devm_add_action(dev, stop_irq_work, chip);
+       if (ret) {
+               dev_err(dev, "devm_add_action %d failed\n", ret);
+               return ret;
+       }
 
        ret = devm_request_irq(dev, chip->irq, max14656_irq,
                               IRQF_TRIGGER_FALLING,
@@ -289,13 +309,6 @@ static int max14656_probe(struct i2c_client *client,
        }
        enable_irq_wake(chip->irq);
 
-       chip->detect_psy = devm_power_supply_register(dev,
-                      &chip->psy_desc, &psy_cfg);
-       if (IS_ERR(chip->detect_psy)) {
-               dev_err(dev, "power_supply_register failed\n");
-               return -EINVAL;
-       }
-
        schedule_delayed_work(&chip->irq_work, msecs_to_jiffies(2000));
 
        return 0;
diff --git a/drivers/power/supply/max77650-charger.c b/drivers/power/supply/max77650-charger.c
new file mode 100644 (file)
index 0000000..e34714c
--- /dev/null
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 BayLibre SAS
+// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+//
+// Battery charger driver for MAXIM 77650/77651 charger/power-supply.
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/max77650.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+
+#define MAX77650_CHARGER_ENABLED               BIT(0)
+#define MAX77650_CHARGER_DISABLED              0x00
+#define MAX77650_CHARGER_CHG_EN_MASK           BIT(0)
+
+#define MAX77650_CHG_DETAILS_MASK              GENMASK(7, 4)
+#define MAX77650_CHG_DETAILS_BITS(_reg) \
+               (((_reg) & MAX77650_CHG_DETAILS_MASK) >> 4)
+
+/* Charger is OFF. */
+#define MAX77650_CHG_OFF                       0x00
+/* Charger is in prequalification mode. */
+#define MAX77650_CHG_PREQ                      0x01
+/* Charger is in fast-charge constant current mode. */
+#define MAX77650_CHG_ON_CURR                   0x02
+/* Charger is in JEITA modified fast-charge constant-current mode. */
+#define MAX77650_CHG_ON_CURR_JEITA             0x03
+/* Charger is in fast-charge constant-voltage mode. */
+#define MAX77650_CHG_ON_VOLT                   0x04
+/* Charger is in JEITA modified fast-charge constant-voltage mode. */
+#define MAX77650_CHG_ON_VOLT_JEITA             0x05
+/* Charger is in top-off mode. */
+#define MAX77650_CHG_ON_TOPOFF                 0x06
+/* Charger is in JEITA modified top-off mode. */
+#define MAX77650_CHG_ON_TOPOFF_JEITA           0x07
+/* Charger is done. */
+#define MAX77650_CHG_DONE                      0x08
+/* Charger is JEITA modified done. */
+#define MAX77650_CHG_DONE_JEITA                        0x09
+/* Charger is suspended due to a prequalification timer fault. */
+#define MAX77650_CHG_SUSP_PREQ_TIM_FAULT       0x0a
+/* Charger is suspended due to a fast-charge timer fault. */
+#define MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT   0x0b
+/* Charger is suspended due to a battery temperature fault. */
+#define MAX77650_CHG_SUSP_BATT_TEMP_FAULT      0x0c
+
+#define MAX77650_CHGIN_DETAILS_MASK            GENMASK(3, 2)
+#define MAX77650_CHGIN_DETAILS_BITS(_reg) \
+               (((_reg) & MAX77650_CHGIN_DETAILS_MASK) >> 2)
+
+#define MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT    0x00
+#define MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT     0x01
+#define MAX77650_CHGIN_OKAY                    0x11
+
+#define MAX77650_CHARGER_CHG_MASK      BIT(1)
+#define MAX77650_CHARGER_CHG_CHARGING(_reg) \
+               (((_reg) & MAX77650_CHARGER_CHG_MASK) > 1)
+
+#define MAX77650_CHARGER_VCHGIN_MIN_MASK       0xc0
+#define MAX77650_CHARGER_VCHGIN_MIN_SHIFT(_val)        ((_val) << 5)
+
+#define MAX77650_CHARGER_ICHGIN_LIM_MASK       0x1c
+#define MAX77650_CHARGER_ICHGIN_LIM_SHIFT(_val)        ((_val) << 2)
+
+struct max77650_charger_data {
+       struct regmap *map;
+       struct device *dev;
+};
+
+static enum power_supply_property max77650_charger_properties[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_CHARGE_TYPE
+};
+
+static const unsigned int max77650_charger_vchgin_min_table[] = {
+       4000000, 4100000, 4200000, 4300000, 4400000, 4500000, 4600000, 4700000
+};
+
+static const unsigned int max77650_charger_ichgin_lim_table[] = {
+       95000, 190000, 285000, 380000, 475000
+};
+
+static int max77650_charger_set_vchgin_min(struct max77650_charger_data *chg,
+                                          unsigned int val)
+{
+       int i, rv;
+
+       for (i = 0; i < ARRAY_SIZE(max77650_charger_vchgin_min_table); i++) {
+               if (val == max77650_charger_vchgin_min_table[i]) {
+                       rv = regmap_update_bits(chg->map,
+                                       MAX77650_REG_CNFG_CHG_B,
+                                       MAX77650_CHARGER_VCHGIN_MIN_MASK,
+                                       MAX77650_CHARGER_VCHGIN_MIN_SHIFT(i));
+                       if (rv)
+                               return rv;
+
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int max77650_charger_set_ichgin_lim(struct max77650_charger_data *chg,
+                                          unsigned int val)
+{
+       int i, rv;
+
+       for (i = 0; i < ARRAY_SIZE(max77650_charger_ichgin_lim_table); i++) {
+               if (val == max77650_charger_ichgin_lim_table[i]) {
+                       rv = regmap_update_bits(chg->map,
+                                       MAX77650_REG_CNFG_CHG_B,
+                                       MAX77650_CHARGER_ICHGIN_LIM_MASK,
+                                       MAX77650_CHARGER_ICHGIN_LIM_SHIFT(i));
+                       if (rv)
+                               return rv;
+
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int max77650_charger_enable(struct max77650_charger_data *chg)
+{
+       int rv;
+
+       rv = regmap_update_bits(chg->map,
+                               MAX77650_REG_CNFG_CHG_B,
+                               MAX77650_CHARGER_CHG_EN_MASK,
+                               MAX77650_CHARGER_ENABLED);
+       if (rv)
+               dev_err(chg->dev, "unable to enable the charger: %d\n", rv);
+
+       return rv;
+}
+
+static int max77650_charger_disable(struct max77650_charger_data *chg)
+{
+       int rv;
+
+       rv = regmap_update_bits(chg->map,
+                               MAX77650_REG_CNFG_CHG_B,
+                               MAX77650_CHARGER_CHG_EN_MASK,
+                               MAX77650_CHARGER_DISABLED);
+       if (rv)
+               dev_err(chg->dev, "unable to disable the charger: %d\n", rv);
+
+       return rv;
+}
+
+static irqreturn_t max77650_charger_check_status(int irq, void *data)
+{
+       struct max77650_charger_data *chg = data;
+       int rv, reg;
+
+       rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, &reg);
+       if (rv) {
+               dev_err(chg->dev,
+                       "unable to read the charger status: %d\n", rv);
+               return IRQ_HANDLED;
+       }
+
+       switch (MAX77650_CHGIN_DETAILS_BITS(reg)) {
+       case MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT:
+               dev_err(chg->dev, "undervoltage lockout detected, disabling charger\n");
+               max77650_charger_disable(chg);
+               break;
+       case MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT:
+               dev_err(chg->dev, "overvoltage lockout detected, disabling charger\n");
+               max77650_charger_disable(chg);
+               break;
+       case MAX77650_CHGIN_OKAY:
+               max77650_charger_enable(chg);
+               break;
+       default:
+               /* May be 0x10 - debouncing */
+               break;
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int max77650_charger_get_property(struct power_supply *psy,
+                                        enum power_supply_property psp,
+                                        union power_supply_propval *val)
+{
+       struct max77650_charger_data *chg = power_supply_get_drvdata(psy);
+       int rv, reg;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, &reg);
+               if (rv)
+                       return rv;
+
+               if (MAX77650_CHARGER_CHG_CHARGING(reg)) {
+                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
+                       break;
+               }
+
+               switch (MAX77650_CHG_DETAILS_BITS(reg)) {
+               case MAX77650_CHG_OFF:
+               case MAX77650_CHG_SUSP_PREQ_TIM_FAULT:
+               case MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT:
+               case MAX77650_CHG_SUSP_BATT_TEMP_FAULT:
+                       val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                       break;
+               case MAX77650_CHG_PREQ:
+               case MAX77650_CHG_ON_CURR:
+               case MAX77650_CHG_ON_CURR_JEITA:
+               case MAX77650_CHG_ON_VOLT:
+               case MAX77650_CHG_ON_VOLT_JEITA:
+               case MAX77650_CHG_ON_TOPOFF:
+               case MAX77650_CHG_ON_TOPOFF_JEITA:
+                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
+                       break;
+               case MAX77650_CHG_DONE:
+                       val->intval = POWER_SUPPLY_STATUS_FULL;
+                       break;
+               default:
+                       val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+               }
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, &reg);
+               if (rv)
+                       return rv;
+
+               val->intval = MAX77650_CHARGER_CHG_CHARGING(reg);
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_TYPE:
+               rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, &reg);
+               if (rv)
+                       return rv;
+
+               if (!MAX77650_CHARGER_CHG_CHARGING(reg)) {
+                       val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+                       break;
+               }
+
+               switch (MAX77650_CHG_DETAILS_BITS(reg)) {
+               case MAX77650_CHG_PREQ:
+               case MAX77650_CHG_ON_CURR:
+               case MAX77650_CHG_ON_CURR_JEITA:
+               case MAX77650_CHG_ON_VOLT:
+               case MAX77650_CHG_ON_VOLT_JEITA:
+                       val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+                       break;
+               case MAX77650_CHG_ON_TOPOFF:
+               case MAX77650_CHG_ON_TOPOFF_JEITA:
+                       val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+                       break;
+               default:
+                       val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct power_supply_desc max77650_battery_desc = {
+       .name           = "max77650",
+       .type           = POWER_SUPPLY_TYPE_USB,
+       .get_property   = max77650_charger_get_property,
+       .properties     = max77650_charger_properties,
+       .num_properties = ARRAY_SIZE(max77650_charger_properties),
+};
+
+static int max77650_charger_probe(struct platform_device *pdev)
+{
+       struct power_supply_config pscfg = {};
+       struct max77650_charger_data *chg;
+       struct power_supply *battery;
+       struct device *dev, *parent;
+       int rv, chg_irq, chgin_irq;
+       unsigned int prop;
+
+       dev = &pdev->dev;
+       parent = dev->parent;
+
+       chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL);
+       if (!chg)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, chg);
+
+       chg->map = dev_get_regmap(parent, NULL);
+       if (!chg->map)
+               return -ENODEV;
+
+       chg->dev = dev;
+
+       pscfg.of_node = dev->of_node;
+       pscfg.drv_data = chg;
+
+       chg_irq = platform_get_irq_byname(pdev, "CHG");
+       if (chg_irq < 0)
+               return chg_irq;
+
+       chgin_irq = platform_get_irq_byname(pdev, "CHGIN");
+       if (chgin_irq < 0)
+               return chgin_irq;
+
+       rv = devm_request_any_context_irq(dev, chg_irq,
+                                         max77650_charger_check_status,
+                                         IRQF_ONESHOT, "chg", chg);
+       if (rv < 0)
+               return rv;
+
+       rv = devm_request_any_context_irq(dev, chgin_irq,
+                                         max77650_charger_check_status,
+                                         IRQF_ONESHOT, "chgin", chg);
+       if (rv < 0)
+               return rv;
+
+       battery = devm_power_supply_register(dev,
+                                            &max77650_battery_desc, &pscfg);
+       if (IS_ERR(battery))
+               return PTR_ERR(battery);
+
+       rv = of_property_read_u32(dev->of_node,
+                                 "input-voltage-min-microvolt", &prop);
+       if (rv == 0) {
+               rv = max77650_charger_set_vchgin_min(chg, prop);
+               if (rv)
+                       return rv;
+       }
+
+       rv = of_property_read_u32(dev->of_node,
+                                 "input-current-limit-microamp", &prop);
+       if (rv == 0) {
+               rv = max77650_charger_set_ichgin_lim(chg, prop);
+               if (rv)
+                       return rv;
+       }
+
+       return max77650_charger_enable(chg);
+}
+
+static int max77650_charger_remove(struct platform_device *pdev)
+{
+       struct max77650_charger_data *chg = platform_get_drvdata(pdev);
+
+       return max77650_charger_disable(chg);
+}
+
+static struct platform_driver max77650_charger_driver = {
+       .driver = {
+               .name = "max77650-charger",
+       },
+       .probe = max77650_charger_probe,
+       .remove = max77650_charger_remove,
+};
+module_platform_driver(max77650_charger_driver);
+
+MODULE_DESCRIPTION("MAXIM 77650/77651 charger driver");
+MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
+MODULE_LICENSE("GPL v2");
index 5a97e42a35473d56d5acfb70ee63379a375ef541..7720e4c2ac0bee899432ab3e54e724b2b76c2c79 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 #include <linux/err.h>
 #include <linux/device.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
 #include <linux/jiffies.h>
 
 #define BAT_ADDR_MFR_TYPE      0x5F
 
+struct olpc_battery_data {
+       struct power_supply *olpc_ac;
+       struct power_supply *olpc_bat;
+       char bat_serial[17];
+       bool new_proto;
+       bool little_endian;
+};
+
 /*********************************************************************
  *             Power
  *********************************************************************/
@@ -90,13 +99,10 @@ static const struct power_supply_desc olpc_ac_desc = {
        .get_property = olpc_ac_get_prop,
 };
 
-static struct power_supply *olpc_ac;
-
-static char bat_serial[17]; /* Ick */
-
-static int olpc_bat_get_status(union power_supply_propval *val, uint8_t ec_byte)
+static int olpc_bat_get_status(struct olpc_battery_data *data,
+               union power_supply_propval *val, uint8_t ec_byte)
 {
-       if (olpc_platform_info.ecver > 0x44) {
+       if (data->new_proto) {
                if (ec_byte & (BAT_STAT_CHARGING | BAT_STAT_TRICKLE))
                        val->intval = POWER_SUPPLY_STATUS_CHARGING;
                else if (ec_byte & BAT_STAT_DISCHARGING)
@@ -318,6 +324,14 @@ static int olpc_bat_get_voltage_max_design(union power_supply_propval *val)
        return ret;
 }
 
+static u16 ecword_to_cpu(struct olpc_battery_data *data, u16 ec_word)
+{
+       if (data->little_endian)
+               return le16_to_cpu((__force __le16)ec_word);
+       else
+               return be16_to_cpu((__force __be16)ec_word);
+}
+
 /*********************************************************************
  *             Battery properties
  *********************************************************************/
@@ -325,8 +339,9 @@ static int olpc_bat_get_property(struct power_supply *psy,
                                 enum power_supply_property psp,
                                 union power_supply_propval *val)
 {
+       struct olpc_battery_data *data = power_supply_get_drvdata(psy);
        int ret = 0;
-       __be16 ec_word;
+       u16 ec_word;
        uint8_t ec_byte;
        __be64 ser_buf;
 
@@ -346,7 +361,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
 
        switch (psp) {
        case POWER_SUPPLY_PROP_STATUS:
-               ret = olpc_bat_get_status(val, ec_byte);
+               ret = olpc_bat_get_status(data, val, ec_byte);
                if (ret)
                        return ret;
                break;
@@ -389,7 +404,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
                if (ret)
                        return ret;
 
-               val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32;
+               val->intval = ecword_to_cpu(data, ec_word) * 9760L / 32;
                break;
        case POWER_SUPPLY_PROP_CURRENT_AVG:
        case POWER_SUPPLY_PROP_CURRENT_NOW:
@@ -397,7 +412,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
                if (ret)
                        return ret;
 
-               val->intval = (s16)be16_to_cpu(ec_word) * 15625L / 120;
+               val->intval = ecword_to_cpu(data, ec_word) * 15625L / 120;
                break;
        case POWER_SUPPLY_PROP_CAPACITY:
                ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1);
@@ -428,29 +443,29 @@ static int olpc_bat_get_property(struct power_supply *psy,
                if (ret)
                        return ret;
 
-               val->intval = (s16)be16_to_cpu(ec_word) * 10 / 256;
+               val->intval = ecword_to_cpu(data, ec_word) * 10 / 256;
                break;
        case POWER_SUPPLY_PROP_TEMP_AMBIENT:
                ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
                if (ret)
                        return ret;
 
-               val->intval = (int)be16_to_cpu(ec_word) * 10 / 256;
+               val->intval = (int)ecword_to_cpu(data, ec_word) * 10 / 256;
                break;
        case POWER_SUPPLY_PROP_CHARGE_COUNTER:
                ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2);
                if (ret)
                        return ret;
 
-               val->intval = (s16)be16_to_cpu(ec_word) * 6250 / 15;
+               val->intval = ecword_to_cpu(data, ec_word) * 6250 / 15;
                break;
        case POWER_SUPPLY_PROP_SERIAL_NUMBER:
                ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8);
                if (ret)
                        return ret;
 
-               sprintf(bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf));
-               val->strval = bat_serial;
+               sprintf(data->bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf));
+               val->strval = data->bat_serial;
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
                ret = olpc_bat_get_voltage_max_design(val);
@@ -536,7 +551,7 @@ static ssize_t olpc_bat_eeprom_read(struct file *filp, struct kobject *kobj,
        return count;
 }
 
-static const struct bin_attribute olpc_bat_eeprom = {
+static struct bin_attribute olpc_bat_eeprom = {
        .attr = {
                .name = "eeprom",
                .mode = S_IRUGO,
@@ -560,7 +575,7 @@ static ssize_t olpc_bat_error_read(struct device *dev,
        return sprintf(buf, "%d\n", ec_byte);
 }
 
-static const struct device_attribute olpc_bat_error = {
+static struct device_attribute olpc_bat_error = {
        .attr = {
                .name = "error",
                .mode = S_IRUGO,
@@ -568,6 +583,27 @@ static const struct device_attribute olpc_bat_error = {
        .show = olpc_bat_error_read,
 };
 
+static struct attribute *olpc_bat_sysfs_attrs[] = {
+       &olpc_bat_error.attr,
+       NULL
+};
+
+static struct bin_attribute *olpc_bat_sysfs_bin_attrs[] = {
+       &olpc_bat_eeprom,
+       NULL
+};
+
+static const struct attribute_group olpc_bat_sysfs_group = {
+       .attrs = olpc_bat_sysfs_attrs,
+       .bin_attrs = olpc_bat_sysfs_bin_attrs,
+
+};
+
+static const struct attribute_group *olpc_bat_sysfs_groups[] = {
+       &olpc_bat_sysfs_group,
+       NULL
+};
+
 /*********************************************************************
  *             Initialisation
  *********************************************************************/
@@ -578,17 +614,17 @@ static struct power_supply_desc olpc_bat_desc = {
        .use_for_apm = 1,
 };
 
-static struct power_supply *olpc_bat;
-
 static int olpc_battery_suspend(struct platform_device *pdev,
                                pm_message_t state)
 {
-       if (device_may_wakeup(&olpc_ac->dev))
+       struct olpc_battery_data *data = platform_get_drvdata(pdev);
+
+       if (device_may_wakeup(&data->olpc_ac->dev))
                olpc_ec_wakeup_set(EC_SCI_SRC_ACPWR);
        else
                olpc_ec_wakeup_clear(EC_SCI_SRC_ACPWR);
 
-       if (device_may_wakeup(&olpc_bat->dev))
+       if (device_may_wakeup(&data->olpc_bat->dev))
                olpc_ec_wakeup_set(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC
                                   | EC_SCI_SRC_BATERR);
        else
@@ -600,16 +636,37 @@ static int olpc_battery_suspend(struct platform_device *pdev,
 
 static int olpc_battery_probe(struct platform_device *pdev)
 {
-       int ret;
+       struct power_supply_config bat_psy_cfg = {};
+       struct power_supply_config ac_psy_cfg = {};
+       struct olpc_battery_data *data;
        uint8_t status;
+       uint8_t ecver;
+       int ret;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, data);
 
-       /*
-        * We've seen a number of EC protocol changes; this driver requires
-        * the latest EC protocol, supported by 0x44 and above.
-        */
-       if (olpc_platform_info.ecver < 0x44) {
+       /* See if the EC is already there and get the EC revision */
+       ret = olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, &ecver, 1);
+       if (ret)
+               return ret;
+
+       if (of_find_compatible_node(NULL, NULL, "olpc,xo1.75-ec")) {
+               /* XO 1.75 */
+               data->new_proto = true;
+               data->little_endian = true;
+       } else if (ecver > 0x44) {
+               /* XO 1 or 1.5 with a new EC firmware. */
+               data->new_proto = true;
+       } else if (ecver < 0x44) {
+               /*
+                * We've seen a number of EC protocol changes; this driver
+                * requires the latest EC protocol, supported by 0x44 and above.
+                */
                printk(KERN_NOTICE "OLPC EC version 0x%02x too old for "
-                       "battery driver.\n", olpc_platform_info.ecver);
+                       "battery driver.\n", ecver);
                return -ENXIO;
        }
 
@@ -619,59 +676,44 @@ static int olpc_battery_probe(struct platform_device *pdev)
 
        /* Ignore the status. It doesn't actually matter */
 
-       olpc_ac = power_supply_register(&pdev->dev, &olpc_ac_desc, NULL);
-       if (IS_ERR(olpc_ac))
-               return PTR_ERR(olpc_ac);
+       ac_psy_cfg.of_node = pdev->dev.of_node;
+       ac_psy_cfg.drv_data = data;
+
+       data->olpc_ac = devm_power_supply_register(&pdev->dev, &olpc_ac_desc,
+                                                               &ac_psy_cfg);
+       if (IS_ERR(data->olpc_ac))
+               return PTR_ERR(data->olpc_ac);
 
-       if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */
+       if (of_device_is_compatible(pdev->dev.of_node, "olpc,xo1.5-battery")) {
+               /* XO-1.5 */
                olpc_bat_desc.properties = olpc_xo15_bat_props;
                olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
-       } else { /* XO-1 */
+       } else {
+               /* XO-1 */
                olpc_bat_desc.properties = olpc_xo1_bat_props;
                olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
        }
 
-       olpc_bat = power_supply_register(&pdev->dev, &olpc_bat_desc, NULL);
-       if (IS_ERR(olpc_bat)) {
-               ret = PTR_ERR(olpc_bat);
-               goto battery_failed;
-       }
-
-       ret = device_create_bin_file(&olpc_bat->dev, &olpc_bat_eeprom);
-       if (ret)
-               goto eeprom_failed;
+       bat_psy_cfg.of_node = pdev->dev.of_node;
+       bat_psy_cfg.drv_data = data;
+       bat_psy_cfg.attr_grp = olpc_bat_sysfs_groups;
 
-       ret = device_create_file(&olpc_bat->dev, &olpc_bat_error);
-       if (ret)
-               goto error_failed;
+       data->olpc_bat = devm_power_supply_register(&pdev->dev, &olpc_bat_desc,
+                                                               &bat_psy_cfg);
+       if (IS_ERR(data->olpc_bat))
+               return PTR_ERR(data->olpc_bat);
 
        if (olpc_ec_wakeup_available()) {
-               device_set_wakeup_capable(&olpc_ac->dev, true);
-               device_set_wakeup_capable(&olpc_bat->dev, true);
+               device_set_wakeup_capable(&data->olpc_ac->dev, true);
+               device_set_wakeup_capable(&data->olpc_bat->dev, true);
        }
 
        return 0;
-
-error_failed:
-       device_remove_bin_file(&olpc_bat->dev, &olpc_bat_eeprom);
-eeprom_failed:
-       power_supply_unregister(olpc_bat);
-battery_failed:
-       power_supply_unregister(olpc_ac);
-       return ret;
-}
-
-static int olpc_battery_remove(struct platform_device *pdev)
-{
-       device_remove_file(&olpc_bat->dev, &olpc_bat_error);
-       device_remove_bin_file(&olpc_bat->dev, &olpc_bat_eeprom);
-       power_supply_unregister(olpc_bat);
-       power_supply_unregister(olpc_ac);
-       return 0;
 }
 
 static const struct of_device_id olpc_battery_ids[] = {
        { .compatible = "olpc,xo1-battery" },
+       { .compatible = "olpc,xo1.5-battery" },
        {}
 };
 MODULE_DEVICE_TABLE(of, olpc_battery_ids);
@@ -682,7 +724,6 @@ static struct platform_driver olpc_battery_driver = {
                .of_match_table = olpc_battery_ids,
        },
        .probe = olpc_battery_probe,
-       .remove = olpc_battery_remove,
        .suspend = olpc_battery_suspend,
 };
 
index c917a8b43b2bc29ef29a538c80eb433bb1e6266f..f7033ecf6d0b71549a424f1c667e39e31107dff4 100644 (file)
@@ -598,10 +598,12 @@ int power_supply_get_battery_info(struct power_supply *psy,
 
        err = of_property_read_string(battery_np, "compatible", &value);
        if (err)
-               return err;
+               goto out_put_node;
 
-       if (strcmp("simple-battery", value))
-               return -ENODEV;
+       if (strcmp("simple-battery", value)) {
+               err = -ENODEV;
+               goto out_put_node;
+       }
 
        /* The property and field names below must correspond to elements
         * in enum power_supply_property. For reasoning, see
@@ -620,19 +622,21 @@ int power_supply_get_battery_info(struct power_supply *psy,
                             &info->precharge_current_ua);
        of_property_read_u32(battery_np, "charge-term-current-microamp",
                             &info->charge_term_current_ua);
-       of_property_read_u32(battery_np, "constant_charge_current_max_microamp",
+       of_property_read_u32(battery_np, "constant-charge-current-max-microamp",
                             &info->constant_charge_current_max_ua);
-       of_property_read_u32(battery_np, "constant_charge_voltage_max_microvolt",
+       of_property_read_u32(battery_np, "constant-charge-voltage-max-microvolt",
                             &info->constant_charge_voltage_max_uv);
        of_property_read_u32(battery_np, "factory-internal-resistance-micro-ohms",
                             &info->factory_internal_resistance_uohm);
 
        len = of_property_count_u32_elems(battery_np, "ocv-capacity-celsius");
        if (len < 0 && len != -EINVAL) {
-               return len;
+               err = len;
+               goto out_put_node;
        } else if (len > POWER_SUPPLY_OCV_TEMP_MAX) {
                dev_err(&psy->dev, "Too many temperature values\n");
-               return -EINVAL;
+               err = -EINVAL;
+               goto out_put_node;
        } else if (len > 0) {
                of_property_read_u32_array(battery_np, "ocv-capacity-celsius",
                                           info->ocv_temp, len);
@@ -650,7 +654,8 @@ int power_supply_get_battery_info(struct power_supply *psy,
                        dev_err(&psy->dev, "failed to get %s\n", propname);
                        kfree(propname);
                        power_supply_put_battery_info(psy, info);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto out_put_node;
                }
 
                kfree(propname);
@@ -661,16 +666,21 @@ int power_supply_get_battery_info(struct power_supply *psy,
                        devm_kcalloc(&psy->dev, tab_len, sizeof(*table), GFP_KERNEL);
                if (!info->ocv_table[index]) {
                        power_supply_put_battery_info(psy, info);
-                       return -ENOMEM;
+                       err = -ENOMEM;
+                       goto out_put_node;
                }
 
                for (i = 0; i < tab_len; i++) {
-                       table[i].ocv = be32_to_cpu(*list++);
-                       table[i].capacity = be32_to_cpu(*list++);
+                       table[i].ocv = be32_to_cpu(*list);
+                       list++;
+                       table[i].capacity = be32_to_cpu(*list);
+                       list++;
                }
        }
 
-       return 0;
+out_put_node:
+       of_node_put(battery_np);
+       return err;
 }
 EXPORT_SYMBOL_GPL(power_supply_get_battery_info);
 
@@ -899,7 +909,7 @@ static int ps_get_max_charge_cntl_limit(struct thermal_cooling_device *tcd,
        return ret;
 }
 
-static int ps_get_cur_chrage_cntl_limit(struct thermal_cooling_device *tcd,
+static int ps_get_cur_charge_cntl_limit(struct thermal_cooling_device *tcd,
                                        unsigned long *state)
 {
        struct power_supply *psy;
@@ -934,7 +944,7 @@ static int ps_set_cur_charge_cntl_limit(struct thermal_cooling_device *tcd,
 
 static const struct thermal_cooling_device_ops psy_tcd_ops = {
        .get_max_state = ps_get_max_charge_cntl_limit,
-       .get_cur_state = ps_get_cur_chrage_cntl_limit,
+       .get_cur_state = ps_get_cur_charge_cntl_limit,
        .set_cur_state = ps_set_cur_charge_cntl_limit,
 };
 
index 5358a80d854f99e0157a38bea979eb1b0912f46b..a704a76d7529a565c8df8132ebc71bd6e66802d3 100644 (file)
@@ -56,13 +56,13 @@ static const char * const power_supply_status_text[] = {
 };
 
 static const char * const power_supply_charge_type_text[] = {
-       "Unknown", "N/A", "Trickle", "Fast"
+       "Unknown", "N/A", "Trickle", "Fast", "Standard", "Adaptive", "Custom"
 };
 
 static const char * const power_supply_health_text[] = {
        "Unknown", "Good", "Overheat", "Dead", "Over voltage",
        "Unspecified failure", "Cold", "Watchdog timer expire",
-       "Safety timer expire"
+       "Safety timer expire", "Over current"
 };
 
 static const char * const power_supply_technology_text[] = {
@@ -274,6 +274,8 @@ static struct device_attribute power_supply_attrs[] = {
        POWER_SUPPLY_ATTR(constant_charge_voltage_max),
        POWER_SUPPLY_ATTR(charge_control_limit),
        POWER_SUPPLY_ATTR(charge_control_limit_max),
+       POWER_SUPPLY_ATTR(charge_control_start_threshold),
+       POWER_SUPPLY_ATTR(charge_control_end_threshold),
        POWER_SUPPLY_ATTR(input_current_limit),
        POWER_SUPPLY_ATTR(energy_full_design),
        POWER_SUPPLY_ATTR(energy_empty_design),
diff --git a/drivers/power/supply/ucs1002_power.c b/drivers/power/supply/ucs1002_power.c
new file mode 100644 (file)
index 0000000..1c89d03
--- /dev/null
@@ -0,0 +1,646 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for UCS1002 Programmable USB Port Power Controller
+ *
+ * Copyright (C) 2019 Zodiac Inflight Innovations
+ */
+#include <linux/bits.h>
+#include <linux/freezer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+/* UCS1002 Registers */
+#define UCS1002_REG_CURRENT_MEASUREMENT        0x00
+
+/*
+ * The Total Accumulated Charge registers store the total accumulated
+ * charge delivered from the VS source to a portable device. The total
+ * value is calculated using four registers, from 01h to 04h. The bit
+ * weighting of the registers is given in mA/hrs.
+ */
+#define UCS1002_REG_TOTAL_ACC_CHARGE   0x01
+
+/* Other Status Register */
+#define UCS1002_REG_OTHER_STATUS       0x0f
+#  define F_ADET_PIN                   BIT(4)
+#  define F_CHG_ACT                    BIT(3)
+
+/* Interrupt Status */
+#define UCS1002_REG_INTERRUPT_STATUS   0x10
+#  define F_DISCHARGE_ERR              BIT(6)
+#  define F_RESET                      BIT(5)
+#  define F_MIN_KEEP_OUT               BIT(4)
+#  define F_TSD                                BIT(3)
+#  define F_OVER_VOLT                  BIT(2)
+#  define F_BACK_VOLT                  BIT(1)
+#  define F_OVER_ILIM                  BIT(0)
+
+/* Pin Status Register */
+#define UCS1002_REG_PIN_STATUS         0x14
+#  define UCS1002_PWR_STATE_MASK       0x03
+#  define F_PWR_EN_PIN                 BIT(6)
+#  define F_M2_PIN                     BIT(5)
+#  define F_M1_PIN                     BIT(4)
+#  define F_EM_EN_PIN                  BIT(3)
+#  define F_SEL_PIN                    BIT(2)
+#  define F_ACTIVE_MODE_MASK           GENMASK(5, 3)
+#  define F_ACTIVE_MODE_PASSTHROUGH    F_M2_PIN
+#  define F_ACTIVE_MODE_DEDICATED      F_EM_EN_PIN
+#  define F_ACTIVE_MODE_BC12_DCP       (F_M2_PIN | F_EM_EN_PIN)
+#  define F_ACTIVE_MODE_BC12_SDP       F_M1_PIN
+#  define F_ACTIVE_MODE_BC12_CDP       (F_M1_PIN | F_M2_PIN | F_EM_EN_PIN)
+
+/* General Configuration Register */
+#define UCS1002_REG_GENERAL_CFG                0x15
+#  define F_RATION_EN                  BIT(3)
+
+/* Emulation Configuration Register */
+#define UCS1002_REG_EMU_CFG            0x16
+
+/* Switch Configuration Register */
+#define UCS1002_REG_SWITCH_CFG         0x17
+#  define F_PIN_IGNORE                 BIT(7)
+#  define F_EM_EN_SET                  BIT(5)
+#  define F_M2_SET                     BIT(4)
+#  define F_M1_SET                     BIT(3)
+#  define F_S0_SET                     BIT(2)
+#  define F_PWR_EN_SET                 BIT(1)
+#  define F_LATCH_SET                  BIT(0)
+#  define V_SET_ACTIVE_MODE_MASK       GENMASK(5, 3)
+#  define V_SET_ACTIVE_MODE_PASSTHROUGH        F_M2_SET
+#  define V_SET_ACTIVE_MODE_DEDICATED  F_EM_EN_SET
+#  define V_SET_ACTIVE_MODE_BC12_DCP   (F_M2_SET | F_EM_EN_SET)
+#  define V_SET_ACTIVE_MODE_BC12_SDP   F_M1_SET
+#  define V_SET_ACTIVE_MODE_BC12_CDP   (F_M1_SET | F_M2_SET | F_EM_EN_SET)
+
+/* Current Limit Register */
+#define UCS1002_REG_ILIMIT             0x19
+#  define UCS1002_ILIM_SW_MASK         GENMASK(3, 0)
+
+/* Product ID */
+#define UCS1002_REG_PRODUCT_ID         0xfd
+#  define UCS1002_PRODUCT_ID           0x4e
+
+/* Manufacture name */
+#define UCS1002_MANUFACTURER           "SMSC"
+
+struct ucs1002_info {
+       struct power_supply *charger;
+       struct i2c_client *client;
+       struct regmap *regmap;
+       struct regulator_desc *regulator_descriptor;
+       bool present;
+};
+
+static enum power_supply_property ucs1002_props[] = {
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_CHARGE_NOW,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
+       POWER_SUPPLY_PROP_CURRENT_MAX,
+       POWER_SUPPLY_PROP_PRESENT, /* the presence of PED */
+       POWER_SUPPLY_PROP_MANUFACTURER,
+       POWER_SUPPLY_PROP_USB_TYPE,
+       POWER_SUPPLY_PROP_HEALTH,
+};
+
+static int ucs1002_get_online(struct ucs1002_info *info,
+                             union power_supply_propval *val)
+{
+       unsigned int reg;
+       int ret;
+
+       ret = regmap_read(info->regmap, UCS1002_REG_OTHER_STATUS, &reg);
+       if (ret)
+               return ret;
+
+       val->intval = !!(reg & F_CHG_ACT);
+
+       return 0;
+}
+
+static int ucs1002_get_charge(struct ucs1002_info *info,
+                             union power_supply_propval *val)
+{
+       /*
+        * To fit within 32 bits some values are rounded (uA/h)
+        *
+        * For Total Accumulated Charge Middle Low Byte register, addr
+        * 03h, byte 2
+        *
+        *   B0: 0.01084 mA/h rounded to 11 uA/h
+        *   B1: 0.02169 mA/h rounded to 22 uA/h
+        *   B2: 0.04340 mA/h rounded to 43 uA/h
+        *   B3: 0.08676 mA/h rounded to 87 uA/h
+        *   B4: 0.17350 mA/h rounded to 173 uÁ/h
+        *
+        * For Total Accumulated Charge Low Byte register, addr 04h,
+        * byte 3
+        *
+        *   B6: 0.00271 mA/h rounded to 3 uA/h
+        *   B7: 0.005422 mA/h rounded to 5 uA/h
+        */
+       static const int bit_weights_uAh[BITS_PER_TYPE(u32)] = {
+               /*
+                * Bit corresponding to low byte (offset 0x04)
+                * B0 B1 B2 B3 B4 B5 B6 B7
+                */
+               0, 0, 0, 0, 0, 0, 3, 5,
+               /*
+                * Bit corresponding to middle low byte (offset 0x03)
+                * B0 B1 B2 B3 B4 B5 B6 B7
+                */
+               11, 22, 43, 87, 173, 347, 694, 1388,
+               /*
+                * Bit corresponding to middle high byte (offset 0x02)
+                * B0 B1 B2 B3 B4 B5 B6 B7
+                */
+               2776, 5552, 11105, 22210, 44420, 88840, 177700, 355400,
+               /*
+                * Bit corresponding to high byte (offset 0x01)
+                * B0 B1 B2 B3 B4 B5 B6 B7
+                */
+               710700, 1421000, 2843000, 5685000, 11371000, 22742000,
+               45484000, 90968000,
+       };
+       unsigned long total_acc_charger;
+       unsigned int reg;
+       int i, ret;
+
+       ret = regmap_bulk_read(info->regmap, UCS1002_REG_TOTAL_ACC_CHARGE,
+                              &reg, sizeof(u32));
+       if (ret)
+               return ret;
+
+       total_acc_charger = be32_to_cpu(reg); /* BE as per offsets above */
+       val->intval = 0;
+
+       for_each_set_bit(i, &total_acc_charger, ARRAY_SIZE(bit_weights_uAh))
+               val->intval += bit_weights_uAh[i];
+
+       return 0;
+}
+
+static int ucs1002_get_current(struct ucs1002_info *info,
+                              union power_supply_propval *val)
+{
+       /*
+        * The Current Measurement register stores the measured
+        * current value delivered to the portable device. The range
+        * is from 9.76 mA to 2.5 A.
+        */
+       static const int bit_weights_uA[BITS_PER_TYPE(u8)] = {
+               9760, 19500, 39000, 78100, 156200, 312300, 624600, 1249300,
+       };
+       unsigned long current_measurement;
+       unsigned int reg;
+       int i, ret;
+
+       ret = regmap_read(info->regmap, UCS1002_REG_CURRENT_MEASUREMENT, &reg);
+       if (ret)
+               return ret;
+
+       current_measurement = reg;
+       val->intval = 0;
+
+       for_each_set_bit(i, &current_measurement, ARRAY_SIZE(bit_weights_uA))
+               val->intval += bit_weights_uA[i];
+
+       return 0;
+}
+
+/*
+ * The Current Limit register stores the maximum current used by the
+ * port switch. The range is from 500mA to 2.5 A.
+ */
+static const u32 ucs1002_current_limit_uA[] = {
+       500000, 900000, 1000000, 1200000, 1500000, 1800000, 2000000, 2500000,
+};
+
+static int ucs1002_get_max_current(struct ucs1002_info *info,
+                                  union power_supply_propval *val)
+{
+       unsigned int reg;
+       int ret;
+
+       ret = regmap_read(info->regmap, UCS1002_REG_ILIMIT, &reg);
+       if (ret)
+               return ret;
+
+       val->intval = ucs1002_current_limit_uA[reg & UCS1002_ILIM_SW_MASK];
+
+       return 0;
+}
+
+static int ucs1002_set_max_current(struct ucs1002_info *info, u32 val)
+{
+       unsigned int reg;
+       int ret, idx;
+
+       for (idx = 0; idx < ARRAY_SIZE(ucs1002_current_limit_uA); idx++) {
+               if (val == ucs1002_current_limit_uA[idx])
+                       break;
+       }
+
+       if (idx == ARRAY_SIZE(ucs1002_current_limit_uA))
+               return -EINVAL;
+
+       ret = regmap_write(info->regmap, UCS1002_REG_ILIMIT, idx);
+       if (ret)
+               return ret;
+       /*
+        * Any current limit setting exceeding the one set via ILIM
+        * pin will be rejected, so we read out freshly changed limit
+        * to make sure that it took effect.
+        */
+       ret = regmap_read(info->regmap, UCS1002_REG_ILIMIT, &reg);
+       if (ret)
+               return ret;
+
+       if (reg != idx)
+               return -EINVAL;
+
+       return 0;
+}
+
+static enum power_supply_usb_type ucs1002_usb_types[] = {
+       POWER_SUPPLY_USB_TYPE_PD,
+       POWER_SUPPLY_USB_TYPE_SDP,
+       POWER_SUPPLY_USB_TYPE_DCP,
+       POWER_SUPPLY_USB_TYPE_CDP,
+       POWER_SUPPLY_USB_TYPE_UNKNOWN,
+};
+
+static int ucs1002_set_usb_type(struct ucs1002_info *info, int val)
+{
+       unsigned int mode;
+
+       if (val < 0 || val >= ARRAY_SIZE(ucs1002_usb_types))
+               return -EINVAL;
+
+       switch (ucs1002_usb_types[val]) {
+       case POWER_SUPPLY_USB_TYPE_PD:
+               mode = V_SET_ACTIVE_MODE_DEDICATED;
+               break;
+       case POWER_SUPPLY_USB_TYPE_SDP:
+               mode = V_SET_ACTIVE_MODE_BC12_SDP;
+               break;
+       case POWER_SUPPLY_USB_TYPE_DCP:
+               mode = V_SET_ACTIVE_MODE_BC12_DCP;
+               break;
+       case POWER_SUPPLY_USB_TYPE_CDP:
+               mode = V_SET_ACTIVE_MODE_BC12_CDP;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return regmap_update_bits(info->regmap, UCS1002_REG_SWITCH_CFG,
+                                 V_SET_ACTIVE_MODE_MASK, mode);
+}
+
+static int ucs1002_get_usb_type(struct ucs1002_info *info,
+                               union power_supply_propval *val)
+{
+       enum power_supply_usb_type type;
+       unsigned int reg;
+       int ret;
+
+       ret = regmap_read(info->regmap, UCS1002_REG_PIN_STATUS, &reg);
+       if (ret)
+               return ret;
+
+       switch (reg & F_ACTIVE_MODE_MASK) {
+       default:
+               type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
+               break;
+       case F_ACTIVE_MODE_DEDICATED:
+               type = POWER_SUPPLY_USB_TYPE_PD;
+               break;
+       case F_ACTIVE_MODE_BC12_SDP:
+               type = POWER_SUPPLY_USB_TYPE_SDP;
+               break;
+       case F_ACTIVE_MODE_BC12_DCP:
+               type = POWER_SUPPLY_USB_TYPE_DCP;
+               break;
+       case F_ACTIVE_MODE_BC12_CDP:
+               type = POWER_SUPPLY_USB_TYPE_CDP;
+               break;
+       };
+
+       val->intval = type;
+
+       return 0;
+}
+
+static int ucs1002_get_health(struct ucs1002_info *info,
+                             union power_supply_propval *val)
+{
+       unsigned int reg;
+       int ret, health;
+
+       ret = regmap_read(info->regmap, UCS1002_REG_INTERRUPT_STATUS, &reg);
+       if (ret)
+               return ret;
+
+       if (reg & F_TSD)
+               health = POWER_SUPPLY_HEALTH_OVERHEAT;
+       else if (reg & (F_OVER_VOLT | F_BACK_VOLT))
+               health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+       else if (reg & F_OVER_ILIM)
+               health = POWER_SUPPLY_HEALTH_OVERCURRENT;
+       else if (reg & (F_DISCHARGE_ERR | F_MIN_KEEP_OUT))
+               health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+       else
+               health = POWER_SUPPLY_HEALTH_GOOD;
+
+       val->intval = health;
+
+       return 0;
+}
+
+static int ucs1002_get_property(struct power_supply *psy,
+                               enum power_supply_property psp,
+                               union power_supply_propval *val)
+{
+       struct ucs1002_info *info = power_supply_get_drvdata(psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ONLINE:
+               return ucs1002_get_online(info, val);
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+               return ucs1002_get_charge(info, val);
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               return ucs1002_get_current(info, val);
+       case POWER_SUPPLY_PROP_CURRENT_MAX:
+               return ucs1002_get_max_current(info, val);
+       case POWER_SUPPLY_PROP_USB_TYPE:
+               return ucs1002_get_usb_type(info, val);
+       case POWER_SUPPLY_PROP_HEALTH:
+               return ucs1002_get_health(info, val);
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = info->present;
+               return 0;
+       case POWER_SUPPLY_PROP_MANUFACTURER:
+               val->strval = UCS1002_MANUFACTURER;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ucs1002_set_property(struct power_supply *psy,
+                               enum power_supply_property psp,
+                               const union power_supply_propval *val)
+{
+       struct ucs1002_info *info = power_supply_get_drvdata(psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CURRENT_MAX:
+               return ucs1002_set_max_current(info, val->intval);
+       case POWER_SUPPLY_PROP_USB_TYPE:
+               return ucs1002_set_usb_type(info, val->intval);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ucs1002_property_is_writeable(struct power_supply *psy,
+                                        enum power_supply_property psp)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CURRENT_MAX:
+       case POWER_SUPPLY_PROP_USB_TYPE:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct power_supply_desc ucs1002_charger_desc = {
+       .name                   = "ucs1002",
+       .type                   = POWER_SUPPLY_TYPE_USB,
+       .usb_types              = ucs1002_usb_types,
+       .num_usb_types          = ARRAY_SIZE(ucs1002_usb_types),
+       .get_property           = ucs1002_get_property,
+       .set_property           = ucs1002_set_property,
+       .property_is_writeable  = ucs1002_property_is_writeable,
+       .properties             = ucs1002_props,
+       .num_properties         = ARRAY_SIZE(ucs1002_props),
+};
+
+static irqreturn_t ucs1002_charger_irq(int irq, void *data)
+{
+       int ret, regval;
+       bool present;
+       struct ucs1002_info *info = data;
+
+       present = info->present;
+
+       ret = regmap_read(info->regmap, UCS1002_REG_OTHER_STATUS, &regval);
+       if (ret)
+               return IRQ_HANDLED;
+
+       /* update attached status */
+       info->present = regval & F_ADET_PIN;
+
+       /* notify the change */
+       if (present != info->present)
+               power_supply_changed(info->charger);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t ucs1002_alert_irq(int irq, void *data)
+{
+       struct ucs1002_info *info = data;
+
+       power_supply_changed(info->charger);
+
+       return IRQ_HANDLED;
+}
+
+static const struct regulator_ops ucs1002_regulator_ops = {
+       .is_enabled     = regulator_is_enabled_regmap,
+       .enable         = regulator_enable_regmap,
+       .disable        = regulator_disable_regmap,
+};
+
+static const struct regulator_desc ucs1002_regulator_descriptor = {
+       .name           = "ucs1002-vbus",
+       .ops            = &ucs1002_regulator_ops,
+       .type           = REGULATOR_VOLTAGE,
+       .owner          = THIS_MODULE,
+       .enable_reg     = UCS1002_REG_SWITCH_CFG,
+       .enable_mask    = F_PWR_EN_SET,
+       .enable_val     = F_PWR_EN_SET,
+       .fixed_uV       = 5000000,
+       .n_voltages     = 1,
+};
+
+static int ucs1002_probe(struct i2c_client *client,
+                        const struct i2c_device_id *dev_id)
+{
+       struct device *dev = &client->dev;
+       struct power_supply_config charger_config = {};
+       const struct regmap_config regmap_config = {
+               .reg_bits = 8,
+               .val_bits = 8,
+       };
+       struct regulator_config regulator_config = {};
+       int irq_a_det, irq_alert, ret;
+       struct regulator_dev *rdev;
+       struct ucs1002_info *info;
+       unsigned int regval;
+
+       info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->regmap = devm_regmap_init_i2c(client, &regmap_config);
+       ret = PTR_ERR_OR_ZERO(info->regmap);
+       if (ret) {
+               dev_err(dev, "Regmap initialization failed: %d\n", ret);
+               return ret;
+       }
+
+       info->client = client;
+
+       irq_a_det = of_irq_get_byname(dev->of_node, "a_det");
+       irq_alert = of_irq_get_byname(dev->of_node, "alert");
+
+       charger_config.of_node = dev->of_node;
+       charger_config.drv_data = info;
+
+       ret = regmap_read(info->regmap, UCS1002_REG_PRODUCT_ID, &regval);
+       if (ret) {
+               dev_err(dev, "Failed to read product ID: %d\n", ret);
+               return ret;
+       }
+
+       if (regval != UCS1002_PRODUCT_ID) {
+               dev_err(dev,
+                       "Product ID does not match (0x%02x != 0x%02x)\n",
+                       regval, UCS1002_PRODUCT_ID);
+               return -ENODEV;
+       }
+
+       /* Enable charge rationing by default */
+       ret = regmap_update_bits(info->regmap, UCS1002_REG_GENERAL_CFG,
+                                F_RATION_EN, F_RATION_EN);
+       if (ret) {
+               dev_err(dev, "Failed to read general config: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * Ignore the M1, M2, PWR_EN, and EM_EN pin states. Set active
+        * mode selection to BC1.2 CDP.
+        */
+       ret = regmap_update_bits(info->regmap, UCS1002_REG_SWITCH_CFG,
+                                V_SET_ACTIVE_MODE_MASK | F_PIN_IGNORE,
+                                V_SET_ACTIVE_MODE_BC12_CDP | F_PIN_IGNORE);
+       if (ret) {
+               dev_err(dev, "Failed to configure default mode: %d\n", ret);
+               return ret;
+       }
+       /*
+        * Be safe and set initial current limit to 500mA
+        */
+       ret = ucs1002_set_max_current(info, 500000);
+       if (ret) {
+               dev_err(dev, "Failed to set max current default: %d\n", ret);
+               return ret;
+       }
+
+       info->charger = devm_power_supply_register(dev, &ucs1002_charger_desc,
+                                                  &charger_config);
+       ret = PTR_ERR_OR_ZERO(info->charger);
+       if (ret) {
+               dev_err(dev, "Failed to register power supply: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_read(info->regmap, UCS1002_REG_PIN_STATUS, &regval);
+       if (ret) {
+               dev_err(dev, "Failed to read pin status: %d\n", ret);
+               return ret;
+       }
+
+       info->regulator_descriptor =
+               devm_kmemdup(dev, &ucs1002_regulator_descriptor,
+                            sizeof(ucs1002_regulator_descriptor),
+                            GFP_KERNEL);
+       if (!info->regulator_descriptor)
+               return -ENOMEM;
+
+       info->regulator_descriptor->enable_is_inverted = !(regval & F_SEL_PIN);
+
+       regulator_config.dev = dev;
+       regulator_config.of_node = dev->of_node;
+       regulator_config.regmap = info->regmap;
+
+       rdev = devm_regulator_register(dev, info->regulator_descriptor,
+                                      &regulator_config);
+       ret = PTR_ERR_OR_ZERO(rdev);
+       if (ret) {
+               dev_err(dev, "Failed to register VBUS regulator: %d\n", ret);
+               return ret;
+       }
+
+       if (irq_a_det > 0) {
+               ret = devm_request_threaded_irq(dev, irq_a_det, NULL,
+                                               ucs1002_charger_irq,
+                                               IRQF_ONESHOT,
+                                               "ucs1002-a_det", info);
+               if (ret) {
+                       dev_err(dev, "Failed to request A_DET threaded irq: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       if (irq_alert > 0) {
+               ret = devm_request_threaded_irq(dev, irq_alert, NULL,
+                                               ucs1002_alert_irq,
+                                               IRQF_ONESHOT,
+                                               "ucs1002-alert", info);
+               if (ret) {
+                       dev_err(dev, "Failed to request ALERT threaded irq: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static const struct of_device_id ucs1002_of_match[] = {
+       { .compatible = "microchip,ucs1002", },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ucs1002_of_match);
+
+static struct i2c_driver ucs1002_driver = {
+       .driver = {
+                  .name = "ucs1002",
+                  .of_match_table = ucs1002_of_match,
+       },
+       .probe = ucs1002_probe,
+};
+module_i2c_driver(ucs1002_driver);
+
+MODULE_DESCRIPTION("Microchip UCS1002 Programmable USB Port Power Controller");
+MODULE_AUTHOR("Enric Balletbo Serra <enric.balletbo@collabora.com>");
+MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
+MODULE_LICENSE("GPL");
index dd5d1103e02b25e47580f10b1190af819edb9c1e..4b6418039387f06ae46d7d84de50231f7c0e26cc 100644 (file)
 #include <linux/slab.h>
 #include <linux/pps_kernel.h>
 #include <linux/pps-gpio.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/list.h>
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
 
 /* Info for each registered platform device */
 struct pps_gpio_device_data {
        int irq;                        /* IRQ used as PPS source */
        struct pps_device *pps;         /* PPS source device */
        struct pps_source_info info;    /* PPS source information */
+       struct gpio_desc *gpio_pin;     /* GPIO port descriptors */
+       struct gpio_desc *echo_pin;
+       struct timer_list echo_timer;   /* timer to reset echo active state */
        bool assert_falling_edge;
        bool capture_clear;
-       unsigned int gpio_pin;
+       unsigned int echo_active_ms;    /* PPS echo active duration */
+       unsigned long echo_timeout;     /* timer timeout value in jiffies */
 };
 
 /*
@@ -61,18 +67,101 @@ static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
 
        info = data;
 
-       rising_edge = gpio_get_value(info->gpio_pin);
+       rising_edge = gpiod_get_value(info->gpio_pin);
        if ((rising_edge && !info->assert_falling_edge) ||
                        (!rising_edge && info->assert_falling_edge))
-               pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL);
+               pps_event(info->pps, &ts, PPS_CAPTUREASSERT, data);
        else if (info->capture_clear &&
                        ((rising_edge && info->assert_falling_edge) ||
-                        (!rising_edge && !info->assert_falling_edge)))
-               pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL);
+                       (!rising_edge && !info->assert_falling_edge)))
+               pps_event(info->pps, &ts, PPS_CAPTURECLEAR, data);
 
        return IRQ_HANDLED;
 }
 
+/* This function will only be called when an ECHO GPIO is defined */
+static void pps_gpio_echo(struct pps_device *pps, int event, void *data)
+{
+       /* add_timer() needs to write into info->echo_timer */
+       struct pps_gpio_device_data *info = data;
+
+       switch (event) {
+       case PPS_CAPTUREASSERT:
+               if (pps->params.mode & PPS_ECHOASSERT)
+                       gpiod_set_value(info->echo_pin, 1);
+               break;
+
+       case PPS_CAPTURECLEAR:
+               if (pps->params.mode & PPS_ECHOCLEAR)
+                       gpiod_set_value(info->echo_pin, 1);
+               break;
+       }
+
+       /* fire the timer */
+       if (info->pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) {
+               info->echo_timer.expires = jiffies + info->echo_timeout;
+               add_timer(&info->echo_timer);
+       }
+}
+
+/* Timer callback to reset the echo pin to the inactive state */
+static void pps_gpio_echo_timer_callback(struct timer_list *t)
+{
+       const struct pps_gpio_device_data *info;
+
+       info = from_timer(info, t, echo_timer);
+
+       gpiod_set_value(info->echo_pin, 0);
+}
+
+static int pps_gpio_setup(struct platform_device *pdev)
+{
+       struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
+       struct device_node *np = pdev->dev.of_node;
+       int ret;
+       u32 value;
+
+       data->gpio_pin = devm_gpiod_get(&pdev->dev,
+               NULL,   /* request "gpios" */
+               GPIOD_IN);
+       if (IS_ERR(data->gpio_pin)) {
+               dev_err(&pdev->dev,
+                       "failed to request PPS GPIO\n");
+               return PTR_ERR(data->gpio_pin);
+       }
+
+       data->echo_pin = devm_gpiod_get_optional(&pdev->dev,
+                       "echo",
+                       GPIOD_OUT_LOW);
+       if (data->echo_pin) {
+               if (IS_ERR(data->echo_pin)) {
+                       dev_err(&pdev->dev, "failed to request ECHO GPIO\n");
+                       return PTR_ERR(data->echo_pin);
+               }
+
+               ret = of_property_read_u32(np,
+                       "echo-active-ms",
+                       &value);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "failed to get echo-active-ms from OF\n");
+                       return ret;
+               }
+               data->echo_active_ms = value;
+               /* sanity check on echo_active_ms */
+               if (!data->echo_active_ms || data->echo_active_ms > 999) {
+                       dev_err(&pdev->dev,
+                               "echo-active-ms: %u - bad value from OF\n",
+                               data->echo_active_ms);
+                       return -EINVAL;
+               }
+       }
+
+       if (of_property_read_bool(np, "assert-falling-edge"))
+               data->assert_falling_edge = true;
+       return 0;
+}
+
 static unsigned long
 get_irqf_trigger_flags(const struct pps_gpio_device_data *data)
 {
@@ -90,53 +179,32 @@ get_irqf_trigger_flags(const struct pps_gpio_device_data *data)
 static int pps_gpio_probe(struct platform_device *pdev)
 {
        struct pps_gpio_device_data *data;
-       const char *gpio_label;
        int ret;
        int pps_default_params;
        const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
-       struct device_node *np = pdev->dev.of_node;
 
        /* allocate space for device info */
-       data = devm_kzalloc(&pdev->dev, sizeof(struct pps_gpio_device_data),
-                       GFP_KERNEL);
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
+       platform_set_drvdata(pdev, data);
 
+       /* GPIO setup */
        if (pdata) {
                data->gpio_pin = pdata->gpio_pin;
-               gpio_label = pdata->gpio_label;
+               data->echo_pin = pdata->echo_pin;
 
                data->assert_falling_edge = pdata->assert_falling_edge;
                data->capture_clear = pdata->capture_clear;
+               data->echo_active_ms = pdata->echo_active_ms;
        } else {
-               ret = of_get_gpio(np, 0);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "failed to get GPIO from device tree\n");
-                       return ret;
-               }
-               data->gpio_pin = ret;
-               gpio_label = PPS_GPIO_NAME;
-
-               if (of_get_property(np, "assert-falling-edge", NULL))
-                       data->assert_falling_edge = true;
-       }
-
-       /* GPIO setup */
-       ret = devm_gpio_request(&pdev->dev, data->gpio_pin, gpio_label);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to request GPIO %u\n",
-                       data->gpio_pin);
-               return ret;
-       }
-
-       ret = gpio_direction_input(data->gpio_pin);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to set pin direction\n");
-               return -EINVAL;
+               ret = pps_gpio_setup(pdev);
+               if (ret)
+                       return -EINVAL;
        }
 
        /* IRQ setup */
-       ret = gpio_to_irq(data->gpio_pin);
+       ret = gpiod_to_irq(data->gpio_pin);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to map GPIO to IRQ: %d\n", ret);
                return -EINVAL;
@@ -152,6 +220,11 @@ static int pps_gpio_probe(struct platform_device *pdev)
        data->info.owner = THIS_MODULE;
        snprintf(data->info.name, PPS_MAX_NAME_LEN - 1, "%s.%d",
                 pdev->name, pdev->id);
+       if (data->echo_pin) {
+               data->info.echo = pps_gpio_echo;
+               data->echo_timeout = msecs_to_jiffies(data->echo_active_ms);
+               timer_setup(&data->echo_timer, pps_gpio_echo_timer_callback, 0);
+       }
 
        /* register PPS source */
        pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
@@ -173,7 +246,6 @@ static int pps_gpio_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       platform_set_drvdata(pdev, data);
        dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n",
                 data->irq);
 
@@ -185,6 +257,11 @@ static int pps_gpio_remove(struct platform_device *pdev)
        struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
 
        pps_unregister_source(data->pps);
+       if (data->echo_pin) {
+               del_timer_sync(&data->echo_timer);
+               /* reset echo pin in any case */
+               gpiod_set_value(data->echo_pin, 0);
+       }
        dev_info(&pdev->dev, "removed IRQ %d as PPS source\n", data->irq);
        return 0;
 }
@@ -209,4 +286,4 @@ MODULE_AUTHOR("Ricardo Martins <rasm@fe.up.pt>");
 MODULE_AUTHOR("James Nuss <jamesnuss@nanometrics.ca>");
 MODULE_DESCRIPTION("Use GPIO pin as PPS source");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("1.0.0");
+MODULE_VERSION("1.2.0");
index 54f8238aac0dece5e2469c0ba02f5e7c7d1d49c0..1311b54089beceb92a75c7e11a073d415b5df8aa 100644 (file)
@@ -210,6 +210,17 @@ config PWM_IMX27
          To compile this driver as a module, choose M here: the module
          will be called pwm-imx27.
 
+config PWM_IMX_TPM
+       tristate "i.MX TPM PWM support"
+       depends on ARCH_MXC || COMPILE_TEST
+       depends on HAVE_CLK && HAS_IOMEM
+       help
+         Generic PWM framework driver for i.MX7ULP TPM module, TPM's full
+         name is Low Power Timer/Pulse Width Modulation Module.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-imx-tpm.
+
 config PWM_JZ4740
        tristate "Ingenic JZ47xx PWM support"
        depends on MACH_INGENIC
@@ -467,10 +478,9 @@ config  PWM_TIECAP
 
 config  PWM_TIEHRPWM
        tristate "EHRPWM PWM support"
-       depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX
+       depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_K3
        help
-         PWM driver support for the EHRPWM controller found on AM33XX
-         TI SOC
+         PWM driver support for the EHRPWM controller found on TI SOCs
 
          To compile this driver as a module, choose M here: the module
          will be called pwm-tiehrpwm.
index 448825e892bc17b1de1549319dcd900be7917901..c368599d36c090148daaf6041d1663da1cb06f8a 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_PWM_HIBVT)               += pwm-hibvt.o
 obj-$(CONFIG_PWM_IMG)          += pwm-img.o
 obj-$(CONFIG_PWM_IMX1)         += pwm-imx1.o
 obj-$(CONFIG_PWM_IMX27)                += pwm-imx27.o
+obj-$(CONFIG_PWM_IMX_TPM)      += pwm-imx-tpm.o
 obj-$(CONFIG_PWM_JZ4740)       += pwm-jz4740.o
 obj-$(CONFIG_PWM_LP3943)       += pwm-lp3943.o
 obj-$(CONFIG_PWM_LPC18XX_SCT)  += pwm-lpc18xx-sct.o
index 3149204567f3cc3b64b4ddf15fb75cbdc8a32d85..3998ebd51db46c9582cb079c7b1fd642be9965d9 100644 (file)
@@ -311,10 +311,12 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
        if (IS_ENABLED(CONFIG_OF))
                of_pwmchip_add(chip);
 
-       pwmchip_sysfs_export(chip);
-
 out:
        mutex_unlock(&pwm_lock);
+
+       if (!ret)
+               pwmchip_sysfs_export(chip);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(pwmchip_add_with_polarity);
@@ -348,7 +350,7 @@ int pwmchip_remove(struct pwm_chip *chip)
        unsigned int i;
        int ret = 0;
 
-       pwmchip_sysfs_unexport_children(chip);
+       pwmchip_sysfs_unexport(chip);
 
        mutex_lock(&pwm_lock);
 
@@ -368,8 +370,6 @@ int pwmchip_remove(struct pwm_chip *chip)
 
        free_pwms(chip);
 
-       pwmchip_sysfs_unexport(chip);
-
 out:
        mutex_unlock(&pwm_lock);
        return ret;
@@ -877,6 +877,7 @@ void pwm_put(struct pwm_device *pwm)
        if (pwm->chip->ops->free)
                pwm->chip->ops->free(pwm->chip, pwm);
 
+       pwm_set_chip_data(pwm, NULL);
        pwm->label = NULL;
 
        module_put(pwm->chip->ops->owner);
index 7c8d6a168ceb254c69420ab293f08e3b43fcdd18..b91c477cc84be90fc29d200a3528fdffd20ae1aa 100644 (file)
@@ -84,7 +84,6 @@ static void berlin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        struct berlin_pwm_channel *channel = pwm_get_chip_data(pwm);
 
-       pwm_set_chip_data(pwm, NULL);
        kfree(channel);
 }
 
index bbf10ae02f0ecf9a147b4c6ee81e161113095519..fa168581e6b8e71a8ad9ce9e394df74661e93396 100644 (file)
@@ -35,7 +35,7 @@
 
 #include <asm/div64.h>
 
-#include <mach/platform.h>     /* for ep93xx_pwm_{acquire,release}_gpio() */
+#include <linux/soc/cirrus/ep93xx.h>   /* for ep93xx_pwm_{acquire,release}_gpio() */
 
 #define EP93XX_PWMx_TERM_COUNT 0x00
 #define EP93XX_PWMx_DUTY_CYCLE 0x04
index 815f5333bb8f98dea06e5d4f1969e8f96933b815..1cc5fbe1e1d3f8cc5afb8119769824d4a7b1a472 100644 (file)
@@ -123,7 +123,7 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        } else if (mul <= max_timebase * 512) {
                div = PWM_CTRL_CFG_SUB_DIV0_DIV1;
                timebase = DIV_ROUND_UP(mul, 512);
-       } else if (mul > max_timebase * 512) {
+       } else {
                dev_err(chip->dev,
                        "failed to configure timebase steps/divider value\n");
                return -EINVAL;
diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c
new file mode 100644 (file)
index 0000000..e8385c1
--- /dev/null
@@ -0,0 +1,449 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018-2019 NXP.
+ *
+ * Limitations:
+ * - The TPM counter and period counter are shared between
+ *   multiple channels, so all channels should use same period
+ *   settings.
+ * - Changes to polarity cannot be latched at the time of the
+ *   next period start.
+ * - Changing period and duty cycle together isn't atomic,
+ *   with the wrong timing it might happen that a period is
+ *   produced with old duty cycle but new period settings.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+#define PWM_IMX_TPM_PARAM      0x4
+#define PWM_IMX_TPM_GLOBAL     0x8
+#define PWM_IMX_TPM_SC         0x10
+#define PWM_IMX_TPM_CNT                0x14
+#define PWM_IMX_TPM_MOD                0x18
+#define PWM_IMX_TPM_CnSC(n)    (0x20 + (n) * 0x8)
+#define PWM_IMX_TPM_CnV(n)     (0x24 + (n) * 0x8)
+
+#define PWM_IMX_TPM_PARAM_CHAN                 GENMASK(7, 0)
+
+#define PWM_IMX_TPM_SC_PS                      GENMASK(2, 0)
+#define PWM_IMX_TPM_SC_CMOD                    GENMASK(4, 3)
+#define PWM_IMX_TPM_SC_CMOD_INC_EVERY_CLK      FIELD_PREP(PWM_IMX_TPM_SC_CMOD, 1)
+#define PWM_IMX_TPM_SC_CPWMS                   BIT(5)
+
+#define PWM_IMX_TPM_CnSC_CHF   BIT(7)
+#define PWM_IMX_TPM_CnSC_MSB   BIT(5)
+#define PWM_IMX_TPM_CnSC_MSA   BIT(4)
+
+/*
+ * The reference manual describes this field as two separate bits. The
+ * semantic of the two bits isn't orthogonal though, so they are treated
+ * together as a 2-bit field here.
+ */
+#define PWM_IMX_TPM_CnSC_ELS   GENMASK(3, 2)
+#define PWM_IMX_TPM_CnSC_ELS_INVERSED  FIELD_PREP(PWM_IMX_TPM_CnSC_ELS, 1)
+#define PWM_IMX_TPM_CnSC_ELS_NORMAL    FIELD_PREP(PWM_IMX_TPM_CnSC_ELS, 2)
+
+
+#define PWM_IMX_TPM_MOD_WIDTH  16
+#define PWM_IMX_TPM_MOD_MOD    GENMASK(PWM_IMX_TPM_MOD_WIDTH - 1, 0)
+
+struct imx_tpm_pwm_chip {
+       struct pwm_chip chip;
+       struct clk *clk;
+       void __iomem *base;
+       struct mutex lock;
+       u32 user_count;
+       u32 enable_count;
+       u32 real_period;
+};
+
+struct imx_tpm_pwm_param {
+       u8 prescale;
+       u32 mod;
+       u32 val;
+};
+
+static inline struct imx_tpm_pwm_chip *
+to_imx_tpm_pwm_chip(struct pwm_chip *chip)
+{
+       return container_of(chip, struct imx_tpm_pwm_chip, chip);
+}
+
+/*
+ * This function determines for a given pwm_state *state that a consumer
+ * might request the pwm_state *real_state that eventually is implemented
+ * by the hardware and the necessary register values (in *p) to achieve
+ * this.
+ */
+static int pwm_imx_tpm_round_state(struct pwm_chip *chip,
+                                  struct imx_tpm_pwm_param *p,
+                                  struct pwm_state *real_state,
+                                  struct pwm_state *state)
+{
+       struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip);
+       u32 rate, prescale, period_count, clock_unit;
+       u64 tmp;
+
+       rate = clk_get_rate(tpm->clk);
+       tmp = (u64)state->period * rate;
+       clock_unit = DIV_ROUND_CLOSEST_ULL(tmp, NSEC_PER_SEC);
+       if (clock_unit <= PWM_IMX_TPM_MOD_MOD)
+               prescale = 0;
+       else
+               prescale = ilog2(clock_unit) + 1 - PWM_IMX_TPM_MOD_WIDTH;
+
+       if ((!FIELD_FIT(PWM_IMX_TPM_SC_PS, prescale)))
+               return -ERANGE;
+       p->prescale = prescale;
+
+       period_count = (clock_unit + ((1 << prescale) >> 1)) >> prescale;
+       p->mod = period_count;
+
+       /* calculate real period HW can support */
+       tmp = (u64)period_count << prescale;
+       tmp *= NSEC_PER_SEC;
+       real_state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate);
+
+       /*
+        * if eventually the PWM output is inactive, either
+        * duty cycle is 0 or status is disabled, need to
+        * make sure the output pin is inactive.
+        */
+       if (!state->enabled)
+               real_state->duty_cycle = 0;
+       else
+               real_state->duty_cycle = state->duty_cycle;
+
+       tmp = (u64)p->mod * real_state->duty_cycle;
+       p->val = DIV_ROUND_CLOSEST_ULL(tmp, real_state->period);
+
+       real_state->polarity = state->polarity;
+       real_state->enabled = state->enabled;
+
+       return 0;
+}
+
+static void pwm_imx_tpm_get_state(struct pwm_chip *chip,
+                                 struct pwm_device *pwm,
+                                 struct pwm_state *state)
+{
+       struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip);
+       u32 rate, val, prescale;
+       u64 tmp;
+
+       /* get period */
+       state->period = tpm->real_period;
+
+       /* get duty cycle */
+       rate = clk_get_rate(tpm->clk);
+       val = readl(tpm->base + PWM_IMX_TPM_SC);
+       prescale = FIELD_GET(PWM_IMX_TPM_SC_PS, val);
+       tmp = readl(tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm));
+       tmp = (tmp << prescale) * NSEC_PER_SEC;
+       state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate);
+
+       /* get polarity */
+       val = readl(tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm));
+       if ((val & PWM_IMX_TPM_CnSC_ELS) == PWM_IMX_TPM_CnSC_ELS_INVERSED)
+               state->polarity = PWM_POLARITY_INVERSED;
+       else
+               /*
+                * Assume reserved values (2b00 and 2b11) to yield
+                * normal polarity.
+                */
+               state->polarity = PWM_POLARITY_NORMAL;
+
+       /* get channel status */
+       state->enabled = FIELD_GET(PWM_IMX_TPM_CnSC_ELS, val) ? true : false;
+}
+
+/* this function is supposed to be called with mutex hold */
+static int pwm_imx_tpm_apply_hw(struct pwm_chip *chip,
+                               struct imx_tpm_pwm_param *p,
+                               struct pwm_state *state,
+                               struct pwm_device *pwm)
+{
+       struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip);
+       bool period_update = false;
+       bool duty_update = false;
+       u32 val, cmod, cur_prescale;
+       unsigned long timeout;
+       struct pwm_state c;
+
+       if (state->period != tpm->real_period) {
+               /*
+                * TPM counter is shared by multiple channels, so
+                * prescale and period can NOT be modified when
+                * there are multiple channels in use with different
+                * period settings.
+                */
+               if (tpm->user_count > 1)
+                       return -EBUSY;
+
+               val = readl(tpm->base + PWM_IMX_TPM_SC);
+               cmod = FIELD_GET(PWM_IMX_TPM_SC_CMOD, val);
+               cur_prescale = FIELD_GET(PWM_IMX_TPM_SC_PS, val);
+               if (cmod && cur_prescale != p->prescale)
+                       return -EBUSY;
+
+               /* set TPM counter prescale */
+               val &= ~PWM_IMX_TPM_SC_PS;
+               val |= FIELD_PREP(PWM_IMX_TPM_SC_PS, p->prescale);
+               writel(val, tpm->base + PWM_IMX_TPM_SC);
+
+               /*
+                * set period count:
+                * if the PWM is disabled (CMOD[1:0] = 2b00), then MOD register
+                * is updated when MOD register is written.
+                *
+                * if the PWM is enabled (CMOD[1:0] ≠ 2b00), the period length
+                * is latched into hardware when the next period starts.
+                */
+               writel(p->mod, tpm->base + PWM_IMX_TPM_MOD);
+               tpm->real_period = state->period;
+               period_update = true;
+       }
+
+       pwm_imx_tpm_get_state(chip, pwm, &c);
+
+       /* polarity is NOT allowed to be changed if PWM is active */
+       if (c.enabled && c.polarity != state->polarity)
+               return -EBUSY;
+
+       if (state->duty_cycle != c.duty_cycle) {
+               /*
+                * set channel value:
+                * if the PWM is disabled (CMOD[1:0] = 2b00), then CnV register
+                * is updated when CnV register is written.
+                *
+                * if the PWM is enabled (CMOD[1:0] ≠ 2b00), the duty length
+                * is latched into hardware when the next period starts.
+                */
+               writel(p->val, tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm));
+               duty_update = true;
+       }
+
+       /* make sure MOD & CnV registers are updated */
+       if (period_update || duty_update) {
+               timeout = jiffies + msecs_to_jiffies(tpm->real_period /
+                                                    NSEC_PER_MSEC + 1);
+               while (readl(tpm->base + PWM_IMX_TPM_MOD) != p->mod
+                      || readl(tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm))
+                      != p->val) {
+                       if (time_after(jiffies, timeout))
+                               return -ETIME;
+                       cpu_relax();
+               }
+       }
+
+       /*
+        * polarity settings will enabled/disable output status
+        * immediately, so if the channel is disabled, need to
+        * make sure MSA/MSB/ELS are set to 0 which means channel
+        * disabled.
+        */
+       val = readl(tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm));
+       val &= ~(PWM_IMX_TPM_CnSC_ELS | PWM_IMX_TPM_CnSC_MSA |
+                PWM_IMX_TPM_CnSC_MSB);
+       if (state->enabled) {
+               /*
+                * set polarity (for edge-aligned PWM modes)
+                *
+                * ELS[1:0] = 2b10 yields normal polarity behaviour,
+                * ELS[1:0] = 2b01 yields inversed polarity.
+                * The other values are reserved.
+                */
+               val |= PWM_IMX_TPM_CnSC_MSB;
+               val |= (state->polarity == PWM_POLARITY_NORMAL) ?
+                       PWM_IMX_TPM_CnSC_ELS_NORMAL :
+                       PWM_IMX_TPM_CnSC_ELS_INVERSED;
+       }
+       writel(val, tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm));
+
+       /* control the counter status */
+       if (state->enabled != c.enabled) {
+               val = readl(tpm->base + PWM_IMX_TPM_SC);
+               if (state->enabled) {
+                       if (++tpm->enable_count == 1)
+                               val |= PWM_IMX_TPM_SC_CMOD_INC_EVERY_CLK;
+               } else {
+                       if (--tpm->enable_count == 0)
+                               val &= ~PWM_IMX_TPM_SC_CMOD;
+               }
+               writel(val, tpm->base + PWM_IMX_TPM_SC);
+       }
+
+       return 0;
+}
+
+static int pwm_imx_tpm_apply(struct pwm_chip *chip,
+                            struct pwm_device *pwm,
+                            struct pwm_state *state)
+{
+       struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip);
+       struct imx_tpm_pwm_param param;
+       struct pwm_state real_state;
+       int ret;
+
+       ret = pwm_imx_tpm_round_state(chip, &param, &real_state, state);
+       if (ret)
+               return ret;
+
+       mutex_lock(&tpm->lock);
+       ret = pwm_imx_tpm_apply_hw(chip, &param, &real_state, pwm);
+       mutex_unlock(&tpm->lock);
+
+       return ret;
+}
+
+static int pwm_imx_tpm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip);
+
+       mutex_lock(&tpm->lock);
+       tpm->user_count++;
+       mutex_unlock(&tpm->lock);
+
+       return 0;
+}
+
+static void pwm_imx_tpm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip);
+
+       mutex_lock(&tpm->lock);
+       tpm->user_count--;
+       mutex_unlock(&tpm->lock);
+}
+
+static const struct pwm_ops imx_tpm_pwm_ops = {
+       .request = pwm_imx_tpm_request,
+       .free = pwm_imx_tpm_free,
+       .get_state = pwm_imx_tpm_get_state,
+       .apply = pwm_imx_tpm_apply,
+       .owner = THIS_MODULE,
+};
+
+static int pwm_imx_tpm_probe(struct platform_device *pdev)
+{
+       struct imx_tpm_pwm_chip *tpm;
+       int ret;
+       u32 val;
+
+       tpm = devm_kzalloc(&pdev->dev, sizeof(*tpm), GFP_KERNEL);
+       if (!tpm)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, tpm);
+
+       tpm->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(tpm->base))
+               return PTR_ERR(tpm->base);
+
+       tpm->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(tpm->clk)) {
+               ret = PTR_ERR(tpm->clk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev,
+                               "failed to get PWM clock: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(tpm->clk);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "failed to prepare or enable clock: %d\n", ret);
+               return ret;
+       }
+
+       tpm->chip.dev = &pdev->dev;
+       tpm->chip.ops = &imx_tpm_pwm_ops;
+       tpm->chip.base = -1;
+       tpm->chip.of_xlate = of_pwm_xlate_with_flags;
+       tpm->chip.of_pwm_n_cells = 3;
+
+       /* get number of channels */
+       val = readl(tpm->base + PWM_IMX_TPM_PARAM);
+       tpm->chip.npwm = FIELD_GET(PWM_IMX_TPM_PARAM_CHAN, val);
+
+       mutex_init(&tpm->lock);
+
+       ret = pwmchip_add(&tpm->chip);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
+               clk_disable_unprepare(tpm->clk);
+       }
+
+       return ret;
+}
+
+static int pwm_imx_tpm_remove(struct platform_device *pdev)
+{
+       struct imx_tpm_pwm_chip *tpm = platform_get_drvdata(pdev);
+       int ret = pwmchip_remove(&tpm->chip);
+
+       clk_disable_unprepare(tpm->clk);
+
+       return ret;
+}
+
+static int __maybe_unused pwm_imx_tpm_suspend(struct device *dev)
+{
+       struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev);
+
+       if (tpm->enable_count > 0)
+               return -EBUSY;
+
+       clk_disable_unprepare(tpm->clk);
+
+       return 0;
+}
+
+static int __maybe_unused pwm_imx_tpm_resume(struct device *dev)
+{
+       struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev);
+       int ret = 0;
+
+       ret = clk_prepare_enable(tpm->clk);
+       if (ret)
+               dev_err(dev,
+                       "failed to prepare or enable clock: %d\n",
+                       ret);
+
+       return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(imx_tpm_pwm_pm,
+                        pwm_imx_tpm_suspend, pwm_imx_tpm_resume);
+
+static const struct of_device_id imx_tpm_pwm_dt_ids[] = {
+       { .compatible = "fsl,imx7ulp-pwm", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_tpm_pwm_dt_ids);
+
+static struct platform_driver imx_tpm_pwm_driver = {
+       .driver = {
+               .name = "imx7ulp-tpm-pwm",
+               .of_match_table = imx_tpm_pwm_dt_ids,
+               .pm = &imx_tpm_pwm_pm,
+       },
+       .probe  = pwm_imx_tpm_probe,
+       .remove = pwm_imx_tpm_remove,
+};
+module_platform_driver(imx_tpm_pwm_driver);
+
+MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
+MODULE_DESCRIPTION("i.MX TPM PWM Driver");
+MODULE_LICENSE("GPL v2");
index 806130654211f1517c5b91915f04ad8f41122801..434a351fb626be9a790f1a8cafa1e77595bd9dfd 100644 (file)
@@ -291,7 +291,6 @@ MODULE_DEVICE_TABLE(of, pwm_imx27_dt_ids);
 static int pwm_imx27_probe(struct platform_device *pdev)
 {
        struct pwm_imx27_chip *imx;
-       struct resource *r;
 
        imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
        if (imx == NULL)
@@ -326,8 +325,7 @@ static int pwm_imx27_probe(struct platform_device *pdev)
        imx->chip.of_xlate = of_pwm_xlate_with_flags;
        imx->chip.of_pwm_n_cells = 3;
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       imx->mmio_base = devm_ioremap_resource(&pdev->dev, r);
+       imx->mmio_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(imx->mmio_base))
                return PTR_ERR(imx->mmio_base);
 
index 4ae5d774443ec09eb6f31f4fd2a290ed268493a2..fb5a369b1a8dd2d03a10bdd5626114fe5562ece3 100644 (file)
@@ -111,6 +111,10 @@ struct meson_pwm {
        const struct meson_pwm_data *data;
        void __iomem *base;
        u8 inverter_mask;
+       /*
+        * Protects register (write) access to the REG_MISC_AB register
+        * that is shared between the two PWMs.
+        */
        spinlock_t lock;
 };
 
@@ -184,7 +188,7 @@ static int meson_pwm_calc(struct meson_pwm *meson,
        do_div(fin_ps, fin_freq);
 
        /* Calc pre_div with the period */
-       for (pre_div = 0; pre_div < MISC_CLK_DIV_MASK; pre_div++) {
+       for (pre_div = 0; pre_div <= MISC_CLK_DIV_MASK; pre_div++) {
                cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000,
                                            fin_ps * (pre_div + 1));
                dev_dbg(meson->chip.dev, "fin_ps=%llu pre_div=%u cnt=%u\n",
@@ -193,7 +197,7 @@ static int meson_pwm_calc(struct meson_pwm *meson,
                        break;
        }
 
-       if (pre_div == MISC_CLK_DIV_MASK) {
+       if (pre_div > MISC_CLK_DIV_MASK) {
                dev_err(meson->chip.dev, "unable to get period pre_div\n");
                return -EINVAL;
        }
@@ -235,6 +239,7 @@ static void meson_pwm_enable(struct meson_pwm *meson,
 {
        u32 value, clk_shift, clk_enable, enable;
        unsigned int offset;
+       unsigned long flags;
 
        switch (id) {
        case 0:
@@ -255,6 +260,8 @@ static void meson_pwm_enable(struct meson_pwm *meson,
                return;
        }
 
+       spin_lock_irqsave(&meson->lock, flags);
+
        value = readl(meson->base + REG_MISC_AB);
        value &= ~(MISC_CLK_DIV_MASK << clk_shift);
        value |= channel->pre_div << clk_shift;
@@ -267,11 +274,14 @@ static void meson_pwm_enable(struct meson_pwm *meson,
        value = readl(meson->base + REG_MISC_AB);
        value |= enable;
        writel(value, meson->base + REG_MISC_AB);
+
+       spin_unlock_irqrestore(&meson->lock, flags);
 }
 
 static void meson_pwm_disable(struct meson_pwm *meson, unsigned int id)
 {
        u32 value, enable;
+       unsigned long flags;
 
        switch (id) {
        case 0:
@@ -286,9 +296,13 @@ static void meson_pwm_disable(struct meson_pwm *meson, unsigned int id)
                return;
        }
 
+       spin_lock_irqsave(&meson->lock, flags);
+
        value = readl(meson->base + REG_MISC_AB);
        value &= ~enable;
        writel(value, meson->base + REG_MISC_AB);
+
+       spin_unlock_irqrestore(&meson->lock, flags);
 }
 
 static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -296,29 +310,21 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 {
        struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
        struct meson_pwm *meson = to_meson_pwm(chip);
-       unsigned long flags;
        int err = 0;
 
        if (!state)
                return -EINVAL;
 
-       spin_lock_irqsave(&meson->lock, flags);
-
        if (!state->enabled) {
                meson_pwm_disable(meson, pwm->hwpwm);
                channel->state.enabled = false;
 
-               goto unlock;
+               return 0;
        }
 
        if (state->period != channel->state.period ||
            state->duty_cycle != channel->state.duty_cycle ||
            state->polarity != channel->state.polarity) {
-               if (channel->state.enabled) {
-                       meson_pwm_disable(meson, pwm->hwpwm);
-                       channel->state.enabled = false;
-               }
-
                if (state->polarity != channel->state.polarity) {
                        if (state->polarity == PWM_POLARITY_NORMAL)
                                meson->inverter_mask |= BIT(pwm->hwpwm);
@@ -329,7 +335,7 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
                err = meson_pwm_calc(meson, channel, pwm->hwpwm,
                                     state->duty_cycle, state->period);
                if (err < 0)
-                       goto unlock;
+                       return err;
 
                channel->state.polarity = state->polarity;
                channel->state.period = state->period;
@@ -341,9 +347,7 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
                channel->state.enabled = true;
        }
 
-unlock:
-       spin_unlock_irqrestore(&meson->lock, flags);
-       return err;
+       return 0;
 }
 
 static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -429,6 +433,24 @@ static const struct meson_pwm_data pwm_axg_ao_data = {
        .num_parents = ARRAY_SIZE(pwm_axg_ao_parent_names),
 };
 
+static const char * const pwm_g12a_ao_cd_parent_names[] = {
+       "aoclk81", "xtal",
+};
+
+static const struct meson_pwm_data pwm_g12a_ao_cd_data = {
+       .parent_names = pwm_g12a_ao_cd_parent_names,
+       .num_parents = ARRAY_SIZE(pwm_g12a_ao_cd_parent_names),
+};
+
+static const char * const pwm_g12a_ee_parent_names[] = {
+       "xtal", "hdmi_pll", "fclk_div4", "fclk_div3"
+};
+
+static const struct meson_pwm_data pwm_g12a_ee_data = {
+       .parent_names = pwm_g12a_ee_parent_names,
+       .num_parents = ARRAY_SIZE(pwm_g12a_ee_parent_names),
+};
+
 static const struct of_device_id meson_pwm_matches[] = {
        {
                .compatible = "amlogic,meson8b-pwm",
@@ -450,6 +472,18 @@ static const struct of_device_id meson_pwm_matches[] = {
                .compatible = "amlogic,meson-axg-ao-pwm",
                .data = &pwm_axg_ao_data
        },
+       {
+               .compatible = "amlogic,meson-g12a-ee-pwm",
+               .data = &pwm_g12a_ee_data
+       },
+       {
+               .compatible = "amlogic,meson-g12a-ao-pwm-ab",
+               .data = &pwm_axg_ao_data
+       },
+       {
+               .compatible = "amlogic,meson-g12a-ao-pwm-cd",
+               .data = &pwm_g12a_ao_cd_data
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, meson_pwm_matches);
index a7eaf962a95b15725e43426edca3bd0f4d28acf6..567f5e2771c47288488063f49363fd3e0b4eaab7 100644 (file)
@@ -176,7 +176,6 @@ static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset)
        pm_runtime_put(pca->chip.dev);
        mutex_lock(&pca->lock);
        pwm = &pca->chip.pwms[offset];
-       pwm_set_chip_data(pwm, NULL);
        mutex_unlock(&pca->lock);
 }
 
index 062f2cfc45ec69545d3150c212d346597d76335e..6674e1e80175f928784d1f3bbbabf89751f51ccb 100644 (file)
@@ -226,7 +226,7 @@ static int pwm_samsung_request(struct pwm_chip *chip, struct pwm_device *pwm)
                return -EINVAL;
        }
 
-       our_chan = devm_kzalloc(chip->dev, sizeof(*our_chan), GFP_KERNEL);
+       our_chan = kzalloc(sizeof(*our_chan), GFP_KERNEL);
        if (!our_chan)
                return -ENOMEM;
 
@@ -237,8 +237,7 @@ static int pwm_samsung_request(struct pwm_chip *chip, struct pwm_device *pwm)
 
 static void pwm_samsung_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-       devm_kfree(chip->dev, pwm_get_chip_data(pwm));
-       pwm_set_chip_data(pwm, NULL);
+       kfree(pwm_get_chip_data(pwm));
 }
 
 static int pwm_samsung_enable(struct pwm_chip *chip, struct pwm_device *pwm)
index f7b8a86fa5c5e9570a616ccbcdb61e7d427b8ae3..ad4a40c0f27cf45271e57aee9e8ee4e168118695 100644 (file)
@@ -382,6 +382,8 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
        }
 
        /* Update shadow register first before modifying active register */
+       ehrpwm_modify(pc->mmio_base, AQSFRC, AQSFRC_RLDCSF_MASK,
+                     AQSFRC_RLDCSF_ZRO);
        ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
        /*
         * Changes to immediate action on Action Qualifier. This puts
index ceb233dd604840bd2370dbe3c0446a751f22fe6d..719f8fada0a73da85f5f15e8aaadb0f7f08110bd 100644 (file)
@@ -398,7 +398,7 @@ void pwmchip_sysfs_export(struct pwm_chip *chip)
 
        /*
         * If device_create() fails the pwm_chip is still usable by
-        * the kernel its just not exported.
+        * the kernel it's just not exported.
         */
        parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip,
                               "pwmchip%d", chip->base);
@@ -409,19 +409,6 @@ void pwmchip_sysfs_export(struct pwm_chip *chip)
 }
 
 void pwmchip_sysfs_unexport(struct pwm_chip *chip)
-{
-       struct device *parent;
-
-       parent = class_find_device(&pwm_class, NULL, chip,
-                                  pwmchip_sysfs_match);
-       if (parent) {
-               /* for class_find_device() */
-               put_device(parent);
-               device_unregister(parent);
-       }
-}
-
-void pwmchip_sysfs_unexport_children(struct pwm_chip *chip)
 {
        struct device *parent;
        unsigned int i;
@@ -439,6 +426,7 @@ void pwmchip_sysfs_unexport_children(struct pwm_chip *chip)
        }
 
        put_device(parent);
+       device_unregister(parent);
 }
 
 static int __init pwm_sysfs_init(void)
index 1e1f42e210a08097da57985fec1b68dfdc60d569..4a4a75fa26d537778a1622649f5d70fe4574994c 100644 (file)
@@ -868,7 +868,9 @@ rio_dma_transfer(struct file *filp, u32 transfer_mode,
 
                pinned = get_user_pages_fast(
                                (unsigned long)xfer->loc_addr & PAGE_MASK,
-                               nr_pages, dir == DMA_FROM_DEVICE, page_list);
+                               nr_pages,
+                               dir == DMA_FROM_DEVICE ? FOLL_WRITE : 0,
+                               page_list);
 
                if (pinned != nr_pages) {
                        if (pinned < 0) {
index cf45829585cb4a0faa6aa89345bf1d89572fa236..b29fc258eeba4becb609d6e2063af1ebf5022e91 100644 (file)
@@ -2147,6 +2147,14 @@ static int riocm_add_mport(struct device *dev,
        mutex_init(&cm->rx_lock);
        riocm_rx_fill(cm, RIOCM_RX_RING_SIZE);
        cm->rx_wq = create_workqueue(DRV_NAME "/rxq");
+       if (!cm->rx_wq) {
+               riocm_error("failed to allocate IBMBOX_%d on %s",
+                           cmbox, mport->name);
+               rio_release_outb_mbox(mport, cmbox);
+               kfree(cm);
+               return -ENOMEM;
+       }
+
        INIT_WORK(&cm->rx_work, rio_ibmsg_handler);
 
        cm->tx_slot = 0;
index 2ef1f13aa47bc3e109b727143dd6c1ae246b8e0b..99e75d92dadab93d9cc57530a8032825c53d04bf 100644 (file)
@@ -79,11 +79,11 @@ static int zynqmp_reset_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
-       platform_set_drvdata(pdev, priv);
-
        priv->eemi_ops = zynqmp_pm_get_eemi_ops();
-       if (!priv->eemi_ops)
-               return -ENXIO;
+       if (IS_ERR(priv->eemi_ops))
+               return PTR_ERR(priv->eemi_ops);
+
+       platform_set_drvdata(pdev, priv);
 
        priv->rcdev.ops = &zynqmp_reset_ops;
        priv->rcdev.owner = THIS_MODULE;
index 32994b0dd1390e3d598e7e0885cf9b4a536d6caa..a2941c875a064abf55251998e227af057adfe4fd 100644 (file)
@@ -403,15 +403,12 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 
 static struct omap_rtc *omap_rtc_power_off_rtc;
 
-/*
- * omap_rtc_poweroff: RTC-controlled power off
- *
- * The RTC can be used to control an external PMIC via the pmic_power_en pin,
- * which can be configured to transition to OFF on ALARM2 events.
- *
- * Called with local interrupts disabled.
+/**
+ * omap_rtc_power_off_program: Set the pmic power off sequence. The RTC
+ * generates pmic_pwr_enable control, which can be used to control an external
+ * PMIC.
  */
-static void omap_rtc_power_off(void)
+int omap_rtc_power_off_program(struct device *dev)
 {
        struct omap_rtc *rtc = omap_rtc_power_off_rtc;
        struct rtc_time tm;
@@ -425,6 +422,9 @@ static void omap_rtc_power_off(void)
        rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN);
 
 again:
+       /* Clear any existing ALARM2 event */
+       rtc_writel(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM2);
+
        /* set alarm one second from now */
        omap_rtc_read_time_raw(rtc, &tm);
        seconds = tm.tm_sec;
@@ -461,6 +461,39 @@ again:
 
        rtc->type->lock(rtc);
 
+       return 0;
+}
+EXPORT_SYMBOL(omap_rtc_power_off_program);
+
+/*
+ * omap_rtc_poweroff: RTC-controlled power off
+ *
+ * The RTC can be used to control an external PMIC via the pmic_power_en pin,
+ * which can be configured to transition to OFF on ALARM2 events.
+ *
+ * Notes:
+ * The one-second alarm offset is the shortest offset possible as the alarm
+ * registers must be set before the next timer update and the offset
+ * calculation is too heavy for everything to be done within a single access
+ * period (~15 us).
+ *
+ * Called with local interrupts disabled.
+ */
+static void omap_rtc_power_off(void)
+{
+       struct rtc_device *rtc = omap_rtc_power_off_rtc->rtc;
+       u32 val;
+
+       omap_rtc_power_off_program(rtc->dev.parent);
+
+       /* Set PMIC power enable and EXT_WAKEUP in case PB power on is used */
+       omap_rtc_power_off_rtc->type->unlock(omap_rtc_power_off_rtc);
+       val = rtc_readl(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG);
+       val |= OMAP_RTC_PMIC_POWER_EN_EN | OMAP_RTC_PMIC_EXT_WKUP_POL(0) |
+                       OMAP_RTC_PMIC_EXT_WKUP_EN(0);
+       rtc_writel(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG, val);
+       omap_rtc_power_off_rtc->type->lock(omap_rtc_power_off_rtc);
+
        /*
         * Wait for alarm to trigger (within one second) and external PMIC to
         * power off the system. Add a 500 ms margin for external latencies
index e62bda0cb53efb71013027c72cce79491c26f03e..8ad4c4e6d5579e79c81e0550040d6327df381071 100644 (file)
 #define EC_CMOS_TOD_WRITE              0x02
 #define EC_CMOS_TOD_READ               0x08
 
+/* Message sent to the EC to request the current time. */
+struct ec_rtc_read_request {
+       u8 command;
+       u8 reserved;
+       u8 param;
+} __packed;
+static struct ec_rtc_read_request read_rq = {
+       .command = EC_COMMAND_CMOS,
+       .param = EC_CMOS_TOD_READ,
+};
+
 /**
- * struct ec_rtc_read - Format of RTC returned by EC.
+ * struct ec_rtc_read_response - Format of RTC returned by EC.
+ * @reserved: Unused byte
  * @second: Second value (0..59)
  * @minute: Minute value (0..59)
  * @hour: Hour value (0..23)
@@ -33,7 +45,8 @@
  *
  * All values are presented in binary (not BCD).
  */
-struct ec_rtc_read {
+struct ec_rtc_read_response {
+       u8 reserved;
        u8 second;
        u8 minute;
        u8 hour;
@@ -44,8 +57,10 @@ struct ec_rtc_read {
 } __packed;
 
 /**
- * struct ec_rtc_write - Format of RTC sent to the EC.
- * @param: EC_CMOS_TOD_WRITE
+ * struct ec_rtc_write_request - Format of RTC sent to the EC.
+ * @command: Always EC_COMMAND_CMOS
+ * @reserved: Unused byte
+ * @param: Always EC_CMOS_TOD_WRITE
  * @century: Century value (full year / 100)
  * @year: Year value (full year % 100)
  * @month: Month value (1..12)
@@ -57,7 +72,9 @@ struct ec_rtc_read {
  *
  * All values are presented in BCD.
  */
-struct ec_rtc_write {
+struct ec_rtc_write_request {
+       u8 command;
+       u8 reserved;
        u8 param;
        u8 century;
        u8 year;
@@ -72,19 +89,17 @@ struct ec_rtc_write {
 static int wilco_ec_rtc_read(struct device *dev, struct rtc_time *tm)
 {
        struct wilco_ec_device *ec = dev_get_drvdata(dev->parent);
-       u8 param = EC_CMOS_TOD_READ;
-       struct ec_rtc_read rtc;
-       struct wilco_ec_message msg = {
-               .type = WILCO_EC_MSG_LEGACY,
-               .flags = WILCO_EC_FLAG_RAW_RESPONSE,
-               .command = EC_COMMAND_CMOS,
-               .request_data = &param,
-               .request_size = sizeof(param),
-               .response_data = &rtc,
-               .response_size = sizeof(rtc),
-       };
+       struct ec_rtc_read_response rtc;
+       struct wilco_ec_message msg;
        int ret;
 
+       memset(&msg, 0, sizeof(msg));
+       msg.type = WILCO_EC_MSG_LEGACY;
+       msg.request_data = &read_rq;
+       msg.request_size = sizeof(read_rq);
+       msg.response_data = &rtc;
+       msg.response_size = sizeof(rtc);
+
        ret = wilco_ec_mailbox(ec, &msg);
        if (ret < 0)
                return ret;
@@ -106,14 +121,8 @@ static int wilco_ec_rtc_read(struct device *dev, struct rtc_time *tm)
 static int wilco_ec_rtc_write(struct device *dev, struct rtc_time *tm)
 {
        struct wilco_ec_device *ec = dev_get_drvdata(dev->parent);
-       struct ec_rtc_write rtc;
-       struct wilco_ec_message msg = {
-               .type = WILCO_EC_MSG_LEGACY,
-               .flags = WILCO_EC_FLAG_RAW_RESPONSE,
-               .command = EC_COMMAND_CMOS,
-               .request_data = &rtc,
-               .request_size = sizeof(rtc),
-       };
+       struct ec_rtc_write_request rtc;
+       struct wilco_ec_message msg;
        int year = tm->tm_year + 1900;
        /*
         * Convert from 0=Sunday to 0=Saturday for the EC
@@ -123,6 +132,7 @@ static int wilco_ec_rtc_write(struct device *dev, struct rtc_time *tm)
        int wday = tm->tm_wday == 6 ? 0 : tm->tm_wday + 1;
        int ret;
 
+       rtc.command     = EC_COMMAND_CMOS;
        rtc.param       = EC_CMOS_TOD_WRITE;
        rtc.century     = bin2bcd(year / 100);
        rtc.year        = bin2bcd(year % 100);
@@ -133,6 +143,11 @@ static int wilco_ec_rtc_write(struct device *dev, struct rtc_time *tm)
        rtc.second      = bin2bcd(tm->tm_sec);
        rtc.weekday     = bin2bcd(wday);
 
+       memset(&msg, 0, sizeof(msg));
+       msg.type = WILCO_EC_MSG_LEGACY;
+       msg.request_data = &rtc;
+       msg.request_size = sizeof(rtc);
+
        ret = wilco_ec_mailbox(ec, &msg);
        if (ret < 0)
                return ret;
index f89f9d02e7884f321f858f18a020e122d83c8a03..c09039eea707eddde5b3d742d4870231125e0265 100644 (file)
@@ -3827,7 +3827,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
        if ((start_padding_sectors || end_padding_sectors) &&
            (rq_data_dir(req) == WRITE)) {
                DBF_DEV_EVENT(DBF_ERR, basedev,
-                             "raw write not track aligned (%lu,%lu) req %p",
+                             "raw write not track aligned (%llu,%llu) req %p",
                              start_padding_sectors, end_padding_sectors, req);
                return ERR_PTR(-EINVAL);
        }
index cfce255521ac4b2a8d1e2ab0ffba19d597810ca7..7b7620de2acdfd83b63d1d885c3037a42b278ab1 100644 (file)
@@ -205,17 +205,22 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr,
                                 int auto_ack, int merge_pending)
 {
        unsigned char __state = 0;
-       int i;
+       int i = 1;
 
        if (is_qebsm(q))
                return qdio_do_eqbs(q, state, bufnr, count, auto_ack);
 
        /* get initial state: */
        __state = q->slsb.val[bufnr];
+
+       /* Bail out early if there is no work on the queue: */
+       if (__state & SLSB_OWNER_CU)
+               goto out;
+
        if (merge_pending && __state == SLSB_P_OUTPUT_PENDING)
                __state = SLSB_P_OUTPUT_EMPTY;
 
-       for (i = 1; i < count; i++) {
+       for (; i < count; i++) {
                bufnr = next_buf(bufnr);
 
                /* merge PENDING into EMPTY: */
@@ -228,6 +233,8 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr,
                if (q->slsb.val[bufnr] != __state)
                        break;
        }
+
+out:
        *state = __state;
        return i;
 }
@@ -382,7 +389,7 @@ int debug_get_buf_state(struct qdio_q *q, unsigned int bufnr,
 {
        if (need_siga_sync(q))
                qdio_siga_sync_q(q);
-       return get_buf_states(q, bufnr, state, 1, 0, 0);
+       return get_buf_state(q, bufnr, state, 0);
 }
 
 static inline void qdio_stop_polling(struct qdio_q *q)
@@ -719,11 +726,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q, unsigned int start)
                    multicast_outbound(q)))
                        qdio_siga_sync_q(q);
 
-       /*
-        * Don't check 128 buffers, as otherwise qdio_inbound_q_moved
-        * would return 0.
-        */
-       count = min(atomic_read(&q->nr_buf_used), QDIO_MAX_BUFFERS_MASK);
+       count = atomic_read(&q->nr_buf_used);
        if (!count)
                return 0;
 
index e331cd97e83bb519ef302178061a42dded67741a..882ee538ca30218c2df61896eb9d78713187a4ce 100644 (file)
@@ -21,5 +21,4 @@ EXPORT_TRACEPOINT_SYMBOL(s390_cio_csch);
 EXPORT_TRACEPOINT_SYMBOL(s390_cio_hsch);
 EXPORT_TRACEPOINT_SYMBOL(s390_cio_xsch);
 EXPORT_TRACEPOINT_SYMBOL(s390_cio_rsch);
-EXPORT_TRACEPOINT_SYMBOL(s390_cio_rchp);
 EXPORT_TRACEPOINT_SYMBOL(s390_cio_chsc);
index 0ebb29b6fd6df2fa65b1cce91fc3e0478eb37345..4803139bce14934e052d7b6bee9ae3f152fb58cc 100644 (file)
@@ -274,29 +274,6 @@ DEFINE_EVENT(s390_class_schid, s390_cio_rsch,
        TP_ARGS(schid, cc)
 );
 
-/**
- * s390_cio_rchp - Reset Channel Path (RCHP) instruction was performed
- * @chpid: Channel-Path Identifier
- * @cc: Condition code
- */
-TRACE_EVENT(s390_cio_rchp,
-       TP_PROTO(struct chp_id chpid, int cc),
-       TP_ARGS(chpid, cc),
-       TP_STRUCT__entry(
-               __field(u8, cssid)
-               __field(u8, id)
-               __field(int, cc)
-       ),
-       TP_fast_assign(
-               __entry->cssid = chpid.cssid;
-               __entry->id = chpid.id;
-               __entry->cc = cc;
-       ),
-       TP_printk("chpid=%x.%02x cc=%d", __entry->cssid, __entry->id,
-                 __entry->cc
-       )
-);
-
 #define CHSC_MAX_REQUEST_LEN           64
 #define CHSC_MAX_RESPONSE_LEN          64
 
index 991420caa4f20c59d691fafa46e6d511bc151c12..6a30768813219fd7a28c597c27dcf8ecb6717dde 100644 (file)
@@ -66,6 +66,7 @@ struct virtio_ccw_device {
        bool device_lost;
        unsigned int config_ready;
        void *airq_info;
+       u64 dma_mask;
 };
 
 struct vq_info_block_legacy {
@@ -108,7 +109,6 @@ struct virtio_rev_info {
 struct virtio_ccw_vq_info {
        struct virtqueue *vq;
        int num;
-       void *queue;
        union {
                struct vq_info_block s;
                struct vq_info_block_legacy l;
@@ -423,7 +423,6 @@ static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
        struct virtio_ccw_device *vcdev = to_vc_device(vq->vdev);
        struct virtio_ccw_vq_info *info = vq->priv;
        unsigned long flags;
-       unsigned long size;
        int ret;
        unsigned int index = vq->index;
 
@@ -461,8 +460,6 @@ static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
                         ret, index);
 
        vring_del_virtqueue(vq);
-       size = PAGE_ALIGN(vring_size(info->num, KVM_VIRTIO_CCW_RING_ALIGN));
-       free_pages_exact(info->queue, size);
        kfree(info->info_block);
        kfree(info);
 }
@@ -494,8 +491,9 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
        int err;
        struct virtqueue *vq = NULL;
        struct virtio_ccw_vq_info *info;
-       unsigned long size = 0; /* silence the compiler */
+       u64 queue;
        unsigned long flags;
+       bool may_reduce;
 
        /* Allocate queue. */
        info = kzalloc(sizeof(struct virtio_ccw_vq_info), GFP_KERNEL);
@@ -516,37 +514,34 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
                err = info->num;
                goto out_err;
        }
-       size = PAGE_ALIGN(vring_size(info->num, KVM_VIRTIO_CCW_RING_ALIGN));
-       info->queue = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
-       if (info->queue == NULL) {
-               dev_warn(&vcdev->cdev->dev, "no queue\n");
-               err = -ENOMEM;
-               goto out_err;
-       }
+       may_reduce = vcdev->revision > 0;
+       vq = vring_create_virtqueue(i, info->num, KVM_VIRTIO_CCW_RING_ALIGN,
+                                   vdev, true, may_reduce, ctx,
+                                   virtio_ccw_kvm_notify, callback, name);
 
-       vq = vring_new_virtqueue(i, info->num, KVM_VIRTIO_CCW_RING_ALIGN, vdev,
-                                true, ctx, info->queue, virtio_ccw_kvm_notify,
-                                callback, name);
        if (!vq) {
                /* For now, we fail if we can't get the requested size. */
                dev_warn(&vcdev->cdev->dev, "no vq\n");
                err = -ENOMEM;
                goto out_err;
        }
+       /* it may have been reduced */
+       info->num = virtqueue_get_vring_size(vq);
 
        /* Register it with the host. */
+       queue = virtqueue_get_desc_addr(vq);
        if (vcdev->revision == 0) {
-               info->info_block->l.queue = (__u64)info->queue;
+               info->info_block->l.queue = queue;
                info->info_block->l.align = KVM_VIRTIO_CCW_RING_ALIGN;
                info->info_block->l.index = i;
                info->info_block->l.num = info->num;
                ccw->count = sizeof(info->info_block->l);
        } else {
-               info->info_block->s.desc = (__u64)info->queue;
+               info->info_block->s.desc = queue;
                info->info_block->s.index = i;
                info->info_block->s.num = info->num;
-               info->info_block->s.avail = (__u64)virtqueue_get_avail(vq);
-               info->info_block->s.used = (__u64)virtqueue_get_used(vq);
+               info->info_block->s.avail = (__u64)virtqueue_get_avail_addr(vq);
+               info->info_block->s.used = (__u64)virtqueue_get_used_addr(vq);
                ccw->count = sizeof(info->info_block->s);
        }
        ccw->cmd_code = CCW_CMD_SET_VQ;
@@ -572,8 +567,6 @@ out_err:
        if (vq)
                vring_del_virtqueue(vq);
        if (info) {
-               if (info->queue)
-                       free_pages_exact(info->queue, size);
                kfree(info->info_block);
        }
        kfree(info);
@@ -780,12 +773,8 @@ out_free:
 static void ccw_transport_features(struct virtio_device *vdev)
 {
        /*
-        * Packed ring isn't enabled on virtio_ccw for now,
-        * because virtio_ccw uses some legacy accessors,
-        * e.g. virtqueue_get_avail() and virtqueue_get_used()
-        * which aren't available in packed ring currently.
+        * Currently nothing to do here.
         */
-       __virtio_clear_bit(vdev, VIRTIO_F_RING_PACKED);
 }
 
 static int virtio_ccw_finalize_features(struct virtio_device *vdev)
@@ -1266,6 +1255,16 @@ static int virtio_ccw_online(struct ccw_device *cdev)
                ret = -ENOMEM;
                goto out_free;
        }
+
+       vcdev->vdev.dev.parent = &cdev->dev;
+       cdev->dev.dma_mask = &vcdev->dma_mask;
+       /* we are fine with common virtio infrastructure using 64 bit DMA */
+       ret = dma_set_mask_and_coherent(&cdev->dev, DMA_BIT_MASK(64));
+       if (ret) {
+               dev_warn(&cdev->dev, "Failed to enable 64-bit DMA.\n");
+               goto out_free;
+       }
+
        vcdev->config_block = kzalloc(sizeof(*vcdev->config_block),
                                   GFP_DMA | GFP_KERNEL);
        if (!vcdev->config_block) {
@@ -1280,7 +1279,6 @@ static int virtio_ccw_online(struct ccw_device *cdev)
 
        vcdev->is_thinint = virtio_ccw_use_airq; /* at least try */
 
-       vcdev->vdev.dev.parent = &cdev->dev;
        vcdev->vdev.dev.release = virtio_ccw_release_dev;
        vcdev->vdev.config = &virtio_ccw_config_ops;
        vcdev->cdev = cdev;
index acd9ba40eabe04abe5a99d3dc5839721f7d7140c..8090dc9a151447c2295742716524ffcb692667a4 100644 (file)
@@ -437,7 +437,7 @@ static int dax_lock_page(void *va, struct page **p)
 
        dax_dbg("uva %p", va);
 
-       ret = get_user_pages_fast((unsigned long)va, 1, 1, p);
+       ret = get_user_pages_fast((unsigned long)va, 1, FOLL_WRITE, p);
        if (ret == 1) {
                dax_dbg("locked page %p, for VA %p", *p, va);
                return 0;
index 19c022e66d6348e444933c38bfb6ef00d91918f5..3c6a18ad9a87132b688d120fceccf7cda00a9d11 100644 (file)
@@ -4922,7 +4922,8 @@ static int sgl_map_user_pages(struct st_buffer *STbp,
 
         /* Try to fault in all of the necessary pages */
         /* rw==READ means read from drive, write into memory area */
-       res = get_user_pages_fast(uaddr, nr_pages, rw == READ, pages);
+       res = get_user_pages_fast(uaddr, nr_pages, rw == READ ? FOLL_WRITE : 0,
+                                 pages);
 
        /* Errors and no page mapped should return here */
        if (res < nr_pages)
index e649ceaaa410caf7d92c4444db3b69d1a2ba9fc7..87d69e7471f97e789c23174c4f3ff1245b037b2f 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/stat.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include "internals.h"
 
 static void __iomem *uimask;
index c07b4a85253f223bf46bf35c7199ed21e31dd643..75bdbb2c51405219d519bdf084eb48cace03d56f 100644 (file)
@@ -2,10 +2,12 @@ menu "SOC (System On Chip) specific Drivers"
 
 source "drivers/soc/actions/Kconfig"
 source "drivers/soc/amlogic/Kconfig"
+source "drivers/soc/aspeed/Kconfig"
 source "drivers/soc/atmel/Kconfig"
 source "drivers/soc/bcm/Kconfig"
 source "drivers/soc/fsl/Kconfig"
 source "drivers/soc/imx/Kconfig"
+source "drivers/soc/ixp4xx/Kconfig"
 source "drivers/soc/mediatek/Kconfig"
 source "drivers/soc/qcom/Kconfig"
 source "drivers/soc/renesas/Kconfig"
index 90b686e586c667e381121fa038903ab54099b6c8..524ecdc2a9bb42eb5e72e8ca415cd71b418b4251 100644 (file)
@@ -4,6 +4,7 @@
 #
 
 obj-$(CONFIG_ARCH_ACTIONS)     += actions/
+obj-$(CONFIG_SOC_ASPEED)       += aspeed/
 obj-$(CONFIG_ARCH_AT91)                += atmel/
 obj-y                          += bcm/
 obj-$(CONFIG_ARCH_DOVE)                += dove/
@@ -11,6 +12,7 @@ obj-$(CONFIG_MACH_DOVE)               += dove/
 obj-y                          += fsl/
 obj-$(CONFIG_ARCH_GEMINI)      += gemini/
 obj-$(CONFIG_ARCH_MXC)         += imx/
+obj-$(CONFIG_ARCH_IXP4XX)      += ixp4xx/
 obj-$(CONFIG_SOC_XWAY)         += lantiq/
 obj-y                          += mediatek/
 obj-y                          += amlogic/
index 6289965c42e98cbe6c13611bf8dd7c29ddb17c80..511b6856225d63637bd850757a55d7b86bb6862b 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/bitfield.h>
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
 #include <linux/reset.h>
 #include <linux/clk.h>
 
@@ -26,6 +27,7 @@
 #define HHI_MEM_PD_REG0                        (0x40 << 2)
 #define HHI_VPU_MEM_PD_REG0            (0x41 << 2)
 #define HHI_VPU_MEM_PD_REG1            (0x42 << 2)
+#define HHI_VPU_MEM_PD_REG2            (0x4d << 2)
 
 struct meson_gx_pwrc_vpu {
        struct generic_pm_domain genpd;
@@ -54,12 +56,55 @@ static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
        /* Power Down Memories */
        for (i = 0; i < 32; i += 2) {
                regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
-                                  0x2 << i, 0x3 << i);
+                                  0x3 << i, 0x3 << i);
                udelay(5);
        }
        for (i = 0; i < 32; i += 2) {
                regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
-                                  0x2 << i, 0x3 << i);
+                                  0x3 << i, 0x3 << i);
+               udelay(5);
+       }
+       for (i = 8; i < 16; i++) {
+               regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
+                                  BIT(i), BIT(i));
+               udelay(5);
+       }
+       udelay(20);
+
+       regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+                          GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
+
+       msleep(20);
+
+       clk_disable_unprepare(pd->vpu_clk);
+       clk_disable_unprepare(pd->vapb_clk);
+
+       return 0;
+}
+
+static int meson_g12a_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
+{
+       struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
+       int i;
+
+       regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+                          GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
+       udelay(20);
+
+       /* Power Down Memories */
+       for (i = 0; i < 32; i += 2) {
+               regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
+                                  0x3 << i, 0x3 << i);
+               udelay(5);
+       }
+       for (i = 0; i < 32; i += 2) {
+               regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
+                                  0x3 << i, 0x3 << i);
+               udelay(5);
+       }
+       for (i = 0; i < 32; i += 2) {
+               regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2,
+                                  0x3 << i, 0x3 << i);
                udelay(5);
        }
        for (i = 8; i < 16; i++) {
@@ -108,13 +153,67 @@ static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
        /* Power Up Memories */
        for (i = 0; i < 32; i += 2) {
                regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
-                                  0x2 << i, 0);
+                                  0x3 << i, 0);
+               udelay(5);
+       }
+
+       for (i = 0; i < 32; i += 2) {
+               regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
+                                  0x3 << i, 0);
+               udelay(5);
+       }
+
+       for (i = 8; i < 16; i++) {
+               regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
+                                  BIT(i), 0);
+               udelay(5);
+       }
+       udelay(20);
+
+       ret = reset_control_assert(pd->rstc);
+       if (ret)
+               return ret;
+
+       regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+                          GEN_PWR_VPU_HDMI_ISO, 0);
+
+       ret = reset_control_deassert(pd->rstc);
+       if (ret)
+               return ret;
+
+       ret = meson_gx_pwrc_vpu_setup_clk(pd);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int meson_g12a_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
+{
+       struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
+       int ret;
+       int i;
+
+       regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+                          GEN_PWR_VPU_HDMI, 0);
+       udelay(20);
+
+       /* Power Up Memories */
+       for (i = 0; i < 32; i += 2) {
+               regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
+                                  0x3 << i, 0);
                udelay(5);
        }
 
        for (i = 0; i < 32; i += 2) {
                regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
-                                  0x2 << i, 0);
+                                  0x3 << i, 0);
+               udelay(5);
+       }
+
+       for (i = 0; i < 32; i += 2) {
+               regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2,
+                                  0x3 << i, 0);
                udelay(5);
        }
 
@@ -160,15 +259,37 @@ static struct meson_gx_pwrc_vpu vpu_hdmi_pd = {
        },
 };
 
+static struct meson_gx_pwrc_vpu vpu_hdmi_pd_g12a = {
+       .genpd = {
+               .name = "vpu_hdmi",
+               .power_off = meson_g12a_pwrc_vpu_power_off,
+               .power_on = meson_g12a_pwrc_vpu_power_on,
+       },
+};
+
 static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
 {
+       const struct meson_gx_pwrc_vpu *vpu_pd_match;
        struct regmap *regmap_ao, *regmap_hhi;
+       struct meson_gx_pwrc_vpu *vpu_pd;
        struct reset_control *rstc;
        struct clk *vpu_clk;
        struct clk *vapb_clk;
        bool powered_off;
        int ret;
 
+       vpu_pd_match = of_device_get_match_data(&pdev->dev);
+       if (!vpu_pd_match) {
+               dev_err(&pdev->dev, "failed to get match data\n");
+               return -ENODEV;
+       }
+
+       vpu_pd = devm_kzalloc(&pdev->dev, sizeof(*vpu_pd), GFP_KERNEL);
+       if (!vpu_pd)
+               return -ENOMEM;
+
+       memcpy(vpu_pd, vpu_pd_match, sizeof(*vpu_pd));
+
        regmap_ao = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node));
        if (IS_ERR(regmap_ao)) {
                dev_err(&pdev->dev, "failed to get regmap\n");
@@ -201,39 +322,46 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
                return PTR_ERR(vapb_clk);
        }
 
-       vpu_hdmi_pd.regmap_ao = regmap_ao;
-       vpu_hdmi_pd.regmap_hhi = regmap_hhi;
-       vpu_hdmi_pd.rstc = rstc;
-       vpu_hdmi_pd.vpu_clk = vpu_clk;
-       vpu_hdmi_pd.vapb_clk = vapb_clk;
+       vpu_pd->regmap_ao = regmap_ao;
+       vpu_pd->regmap_hhi = regmap_hhi;
+       vpu_pd->rstc = rstc;
+       vpu_pd->vpu_clk = vpu_clk;
+       vpu_pd->vapb_clk = vapb_clk;
+
+       platform_set_drvdata(pdev, vpu_pd);
 
-       powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd);
+       powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
 
        /* If already powered, sync the clock states */
        if (!powered_off) {
-               ret = meson_gx_pwrc_vpu_setup_clk(&vpu_hdmi_pd);
+               ret = meson_gx_pwrc_vpu_setup_clk(vpu_pd);
                if (ret)
                        return ret;
        }
 
-       pm_genpd_init(&vpu_hdmi_pd.genpd, &pm_domain_always_on_gov,
+       pm_genpd_init(&vpu_pd->genpd, &pm_domain_always_on_gov,
                      powered_off);
 
        return of_genpd_add_provider_simple(pdev->dev.of_node,
-                                           &vpu_hdmi_pd.genpd);
+                                           &vpu_pd->genpd);
 }
 
 static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev)
 {
+       struct meson_gx_pwrc_vpu *vpu_pd = platform_get_drvdata(pdev);
        bool powered_off;
 
-       powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd);
+       powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
        if (!powered_off)
-               meson_gx_pwrc_vpu_power_off(&vpu_hdmi_pd.genpd);
+               vpu_pd->genpd.power_off(&vpu_pd->genpd);
 }
 
 static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = {
-       { .compatible = "amlogic,meson-gx-pwrc-vpu" },
+       { .compatible = "amlogic,meson-gx-pwrc-vpu", .data = &vpu_hdmi_pd },
+       {
+         .compatible = "amlogic,meson-g12a-pwrc-vpu",
+         .data = &vpu_hdmi_pd_g12a
+       },
        { /* sentinel */ }
 };
 
index 37ea0a1c24c821f7457b23e2a5bf91a1e6da57ce..bca34954518ec00602990e266e1f9b1a4181e341 100644 (file)
@@ -37,26 +37,34 @@ static const struct meson_gx_soc_id {
        { "AXG", 0x25 },
        { "GXLX", 0x26 },
        { "TXHD", 0x27 },
+       { "G12A", 0x28 },
+       { "G12B", 0x29 },
 };
 
 static const struct meson_gx_package_id {
        const char *name;
        unsigned int major_id;
        unsigned int pack_id;
+       unsigned int pack_mask;
 } soc_packages[] = {
-       { "S905", 0x1f, 0 },
-       { "S905H", 0x1f, 0x13 },
-       { "S905M", 0x1f, 0x20 },
-       { "S905D", 0x21, 0 },
-       { "S905X", 0x21, 0x80 },
-       { "S905W", 0x21, 0xa0 },
-       { "S905L", 0x21, 0xc0 },
-       { "S905M2", 0x21, 0xe0 },
-       { "S912", 0x22, 0 },
-       { "962X", 0x24, 0x10 },
-       { "962E", 0x24, 0x20 },
-       { "A113X", 0x25, 0x37 },
-       { "A113D", 0x25, 0x22 },
+       { "S905", 0x1f, 0, 0x20 }, /* pack_id != 0x20 */
+       { "S905H", 0x1f, 0x3, 0xf }, /* pack_id & 0xf == 0x3 */
+       { "S905M", 0x1f, 0x20, 0xf0 }, /* pack_id == 0x20 */
+       { "S905D", 0x21, 0, 0xf0 },
+       { "S905X", 0x21, 0x80, 0xf0 },
+       { "S905W", 0x21, 0xa0, 0xf0 },
+       { "S905L", 0x21, 0xc0, 0xf0 },
+       { "S905M2", 0x21, 0xe0, 0xf0 },
+       { "S805X", 0x21, 0x30, 0xf0 },
+       { "S805Y", 0x21, 0xb0, 0xf0 },
+       { "S912", 0x22, 0, 0x0 }, /* Only S912 is known for GXM */
+       { "962X", 0x24, 0x10, 0xf0 },
+       { "962E", 0x24, 0x20, 0xf0 },
+       { "A113X", 0x25, 0x37, 0xff },
+       { "A113D", 0x25, 0x22, 0xff },
+       { "S905D2", 0x28, 0x10, 0xf0 },
+       { "S905X2", 0x28, 0x40, 0xf0 },
+       { "S922X", 0x29, 0x40, 0xf0 },
 };
 
 static inline unsigned int socinfo_to_major(u32 socinfo)
@@ -81,13 +89,14 @@ static inline unsigned int socinfo_to_misc(u32 socinfo)
 
 static const char *socinfo_to_package_id(u32 socinfo)
 {
-       unsigned int pack = socinfo_to_pack(socinfo) & 0xf0;
+       unsigned int pack = socinfo_to_pack(socinfo);
        unsigned int major = socinfo_to_major(socinfo);
        int i;
 
        for (i = 0 ; i < ARRAY_SIZE(soc_packages) ; ++i) {
                if (soc_packages[i].major_id == major &&
-                   soc_packages[i].pack_id == pack)
+                   soc_packages[i].pack_id ==
+                               (pack & soc_packages[i].pack_mask))
                        return soc_packages[i].name;
        }
 
@@ -123,8 +132,10 @@ static int __init meson_gx_socinfo_init(void)
                return -ENODEV;
 
        /* check if interface is enabled */
-       if (!of_device_is_available(np))
+       if (!of_device_is_available(np)) {
+               of_node_put(np);
                return -ENODEV;
+       }
 
        /* check if chip-id is available */
        if (!of_property_read_bool(np, "amlogic,has-chip-id"))
diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig
new file mode 100644 (file)
index 0000000..765d101
--- /dev/null
@@ -0,0 +1,31 @@
+menu "Aspeed SoC drivers"
+
+config SOC_ASPEED
+       def_bool y
+       depends on ARCH_ASPEED || COMPILE_TEST
+
+config ASPEED_LPC_CTRL
+       depends on SOC_ASPEED && REGMAP && MFD_SYSCON
+       tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control"
+       ---help---
+         Control Aspeed ast2400/2500 HOST LPC to BMC mappings through
+         ioctl()s, the driver also provides a read/write interface to a BMC ram
+         region where the host LPC read/write region can be buffered.
+
+config ASPEED_LPC_SNOOP
+       tristate "Aspeed ast2500 HOST LPC snoop support"
+       depends on SOC_ASPEED && REGMAP && MFD_SYSCON
+       help
+         Provides a driver to control the LPC snoop interface which
+         allows the BMC to listen on and save the data written by
+         the host to an arbitrary LPC I/O port.
+
+config ASPEED_P2A_CTRL
+       depends on SOC_ASPEED && REGMAP && MFD_SYSCON
+       tristate "Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC bridge control"
+       help
+         Control Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC mappings through
+         ioctl()s, the driver also provides an interface for userspace mappings to
+         a pre-defined region.
+
+endmenu
diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
new file mode 100644 (file)
index 0000000..2f7b6da
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_ASPEED_LPC_CTRL)  += aspeed-lpc-ctrl.o
+obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
+obj-$(CONFIG_ASPEED_P2A_CTRL)  += aspeed-p2a-ctrl.o
diff --git a/drivers/soc/aspeed/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c
new file mode 100644 (file)
index 0000000..a024f80
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2017 IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/regmap.h>
+
+#include <linux/aspeed-lpc-ctrl.h>
+
+#define DEVICE_NAME    "aspeed-lpc-ctrl"
+
+#define HICR5 0x0
+#define HICR5_ENL2H    BIT(8)
+#define HICR5_ENFWH    BIT(10)
+
+#define HICR7 0x8
+#define HICR8 0xc
+
+struct aspeed_lpc_ctrl {
+       struct miscdevice       miscdev;
+       struct regmap           *regmap;
+       struct clk              *clk;
+       phys_addr_t             mem_base;
+       resource_size_t         mem_size;
+       u32             pnor_size;
+       u32             pnor_base;
+};
+
+static struct aspeed_lpc_ctrl *file_aspeed_lpc_ctrl(struct file *file)
+{
+       return container_of(file->private_data, struct aspeed_lpc_ctrl,
+                       miscdev);
+}
+
+static int aspeed_lpc_ctrl_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file);
+       unsigned long vsize = vma->vm_end - vma->vm_start;
+       pgprot_t prot = vma->vm_page_prot;
+
+       if (vma->vm_pgoff + vsize > lpc_ctrl->mem_base + lpc_ctrl->mem_size)
+               return -EINVAL;
+
+       /* ast2400/2500 AHB accesses are not cache coherent */
+       prot = pgprot_noncached(prot);
+
+       if (remap_pfn_range(vma, vma->vm_start,
+               (lpc_ctrl->mem_base >> PAGE_SHIFT) + vma->vm_pgoff,
+               vsize, prot))
+               return -EAGAIN;
+
+       return 0;
+}
+
+static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd,
+               unsigned long param)
+{
+       struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file);
+       void __user *p = (void __user *)param;
+       struct aspeed_lpc_ctrl_mapping map;
+       u32 addr;
+       u32 size;
+       long rc;
+
+       if (copy_from_user(&map, p, sizeof(map)))
+               return -EFAULT;
+
+       if (map.flags != 0)
+               return -EINVAL;
+
+       switch (cmd) {
+       case ASPEED_LPC_CTRL_IOCTL_GET_SIZE:
+               /* The flash windows don't report their size */
+               if (map.window_type != ASPEED_LPC_CTRL_WINDOW_MEMORY)
+                       return -EINVAL;
+
+               /* Support more than one window id in the future */
+               if (map.window_id != 0)
+                       return -EINVAL;
+
+               map.size = lpc_ctrl->mem_size;
+
+               return copy_to_user(p, &map, sizeof(map)) ? -EFAULT : 0;
+       case ASPEED_LPC_CTRL_IOCTL_MAP:
+
+               /*
+                * The top half of HICR7 is the MSB of the BMC address of the
+                * mapping.
+                * The bottom half of HICR7 is the MSB of the HOST LPC
+                * firmware space address of the mapping.
+                *
+                * The 1 bits in the top of half of HICR8 represent the bits
+                * (in the requested address) that should be ignored and
+                * replaced with those from the top half of HICR7.
+                * The 1 bits in the bottom half of HICR8 represent the bits
+                * (in the requested address) that should be kept and pass
+                * into the BMC address space.
+                */
+
+               /*
+                * It doesn't make sense to talk about a size or offset with
+                * low 16 bits set. Both HICR7 and HICR8 talk about the top 16
+                * bits of addresses and sizes.
+                */
+
+               if ((map.size & 0x0000ffff) || (map.offset & 0x0000ffff))
+                       return -EINVAL;
+
+               /*
+                * Because of the way the masks work in HICR8 offset has to
+                * be a multiple of size.
+                */
+               if (map.offset & (map.size - 1))
+                       return -EINVAL;
+
+               if (map.window_type == ASPEED_LPC_CTRL_WINDOW_FLASH) {
+                       addr = lpc_ctrl->pnor_base;
+                       size = lpc_ctrl->pnor_size;
+               } else if (map.window_type == ASPEED_LPC_CTRL_WINDOW_MEMORY) {
+                       addr = lpc_ctrl->mem_base;
+                       size = lpc_ctrl->mem_size;
+               } else {
+                       return -EINVAL;
+               }
+
+               /* Check overflow first! */
+               if (map.offset + map.size < map.offset ||
+                       map.offset + map.size > size)
+                       return -EINVAL;
+
+               if (map.size == 0 || map.size > size)
+                       return -EINVAL;
+
+               addr += map.offset;
+
+               /*
+                * addr (host lpc address) is safe regardless of values. This
+                * simply changes the address the host has to request on its
+                * side of the LPC bus. This cannot impact the hosts own
+                * memory space by surprise as LPC specific accessors are
+                * required. The only strange thing that could be done is
+                * setting the lower 16 bits but the shift takes care of that.
+                */
+
+               rc = regmap_write(lpc_ctrl->regmap, HICR7,
+                               (addr | (map.addr >> 16)));
+               if (rc)
+                       return rc;
+
+               rc = regmap_write(lpc_ctrl->regmap, HICR8,
+                               (~(map.size - 1)) | ((map.size >> 16) - 1));
+               if (rc)
+                       return rc;
+
+               /*
+                * Enable LPC FHW cycles. This is required for the host to
+                * access the regions specified.
+                */
+               return regmap_update_bits(lpc_ctrl->regmap, HICR5,
+                               HICR5_ENFWH | HICR5_ENL2H,
+                               HICR5_ENFWH | HICR5_ENL2H);
+       }
+
+       return -EINVAL;
+}
+
+static const struct file_operations aspeed_lpc_ctrl_fops = {
+       .owner          = THIS_MODULE,
+       .mmap           = aspeed_lpc_ctrl_mmap,
+       .unlocked_ioctl = aspeed_lpc_ctrl_ioctl,
+};
+
+static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
+{
+       struct aspeed_lpc_ctrl *lpc_ctrl;
+       struct device_node *node;
+       struct resource resm;
+       struct device *dev;
+       int rc;
+
+       dev = &pdev->dev;
+
+       lpc_ctrl = devm_kzalloc(dev, sizeof(*lpc_ctrl), GFP_KERNEL);
+       if (!lpc_ctrl)
+               return -ENOMEM;
+
+       node = of_parse_phandle(dev->of_node, "flash", 0);
+       if (!node) {
+               dev_err(dev, "Didn't find host pnor flash node\n");
+               return -ENODEV;
+       }
+
+       rc = of_address_to_resource(node, 1, &resm);
+       of_node_put(node);
+       if (rc) {
+               dev_err(dev, "Couldn't address to resource for flash\n");
+               return rc;
+       }
+
+       lpc_ctrl->pnor_size = resource_size(&resm);
+       lpc_ctrl->pnor_base = resm.start;
+
+       dev_set_drvdata(&pdev->dev, lpc_ctrl);
+
+       node = of_parse_phandle(dev->of_node, "memory-region", 0);
+       if (!node) {
+               dev_err(dev, "Didn't find reserved memory\n");
+               return -EINVAL;
+       }
+
+       rc = of_address_to_resource(node, 0, &resm);
+       of_node_put(node);
+       if (rc) {
+               dev_err(dev, "Couldn't address to resource for reserved memory\n");
+               return -ENOMEM;
+       }
+
+       lpc_ctrl->mem_size = resource_size(&resm);
+       lpc_ctrl->mem_base = resm.start;
+
+       lpc_ctrl->regmap = syscon_node_to_regmap(
+                       pdev->dev.parent->of_node);
+       if (IS_ERR(lpc_ctrl->regmap)) {
+               dev_err(dev, "Couldn't get regmap\n");
+               return -ENODEV;
+       }
+
+       lpc_ctrl->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(lpc_ctrl->clk)) {
+               dev_err(dev, "couldn't get clock\n");
+               return PTR_ERR(lpc_ctrl->clk);
+       }
+       rc = clk_prepare_enable(lpc_ctrl->clk);
+       if (rc) {
+               dev_err(dev, "couldn't enable clock\n");
+               return rc;
+       }
+
+       lpc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR;
+       lpc_ctrl->miscdev.name = DEVICE_NAME;
+       lpc_ctrl->miscdev.fops = &aspeed_lpc_ctrl_fops;
+       lpc_ctrl->miscdev.parent = dev;
+       rc = misc_register(&lpc_ctrl->miscdev);
+       if (rc) {
+               dev_err(dev, "Unable to register device\n");
+               goto err;
+       }
+
+       dev_info(dev, "Loaded at %pr\n", &resm);
+
+       return 0;
+
+err:
+       clk_disable_unprepare(lpc_ctrl->clk);
+       return rc;
+}
+
+static int aspeed_lpc_ctrl_remove(struct platform_device *pdev)
+{
+       struct aspeed_lpc_ctrl *lpc_ctrl = dev_get_drvdata(&pdev->dev);
+
+       misc_deregister(&lpc_ctrl->miscdev);
+       clk_disable_unprepare(lpc_ctrl->clk);
+
+       return 0;
+}
+
+static const struct of_device_id aspeed_lpc_ctrl_match[] = {
+       { .compatible = "aspeed,ast2400-lpc-ctrl" },
+       { .compatible = "aspeed,ast2500-lpc-ctrl" },
+       { },
+};
+
+static struct platform_driver aspeed_lpc_ctrl_driver = {
+       .driver = {
+               .name           = DEVICE_NAME,
+               .of_match_table = aspeed_lpc_ctrl_match,
+       },
+       .probe = aspeed_lpc_ctrl_probe,
+       .remove = aspeed_lpc_ctrl_remove,
+};
+
+module_platform_driver(aspeed_lpc_ctrl_driver);
+
+MODULE_DEVICE_TABLE(of, aspeed_lpc_ctrl_match);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cyril Bur <cyrilbur@gmail.com>");
+MODULE_DESCRIPTION("Control for aspeed 2400/2500 LPC HOST to BMC mappings");
diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c
new file mode 100644 (file)
index 0000000..2feb434
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2017 Google Inc
+ *
+ * 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.
+ *
+ * Provides a simple driver to control the ASPEED LPC snoop interface which
+ * allows the BMC to listen on and save the data written by
+ * the host to an arbitrary LPC I/O port.
+ *
+ * Typically used by the BMC to "watch" host boot progress via port
+ * 0x80 writes made by the BIOS during the boot process.
+ */
+
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/kfifo.h>
+#include <linux/mfd/syscon.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/regmap.h>
+
+#define DEVICE_NAME    "aspeed-lpc-snoop"
+
+#define NUM_SNOOP_CHANNELS 2
+#define SNOOP_FIFO_SIZE 2048
+
+#define HICR5  0x0
+#define HICR5_EN_SNP0W         BIT(0)
+#define HICR5_ENINT_SNP0W      BIT(1)
+#define HICR5_EN_SNP1W         BIT(2)
+#define HICR5_ENINT_SNP1W      BIT(3)
+
+#define HICR6  0x4
+#define HICR6_STR_SNP0W                BIT(0)
+#define HICR6_STR_SNP1W                BIT(1)
+#define SNPWADR        0x10
+#define SNPWADR_CH0_MASK       GENMASK(15, 0)
+#define SNPWADR_CH0_SHIFT      0
+#define SNPWADR_CH1_MASK       GENMASK(31, 16)
+#define SNPWADR_CH1_SHIFT      16
+#define SNPWDR 0x14
+#define SNPWDR_CH0_MASK                GENMASK(7, 0)
+#define SNPWDR_CH0_SHIFT       0
+#define SNPWDR_CH1_MASK                GENMASK(15, 8)
+#define SNPWDR_CH1_SHIFT       8
+#define HICRB  0x80
+#define HICRB_ENSNP0D          BIT(14)
+#define HICRB_ENSNP1D          BIT(15)
+
+struct aspeed_lpc_snoop_model_data {
+       /* The ast2400 has bits 14 and 15 as reserved, whereas the ast2500
+        * can use them.
+        */
+       unsigned int has_hicrb_ensnp;
+};
+
+struct aspeed_lpc_snoop_channel {
+       struct kfifo            fifo;
+       wait_queue_head_t       wq;
+       struct miscdevice       miscdev;
+};
+
+struct aspeed_lpc_snoop {
+       struct regmap           *regmap;
+       int                     irq;
+       struct aspeed_lpc_snoop_channel chan[NUM_SNOOP_CHANNELS];
+};
+
+static struct aspeed_lpc_snoop_channel *snoop_file_to_chan(struct file *file)
+{
+       return container_of(file->private_data,
+                           struct aspeed_lpc_snoop_channel,
+                           miscdev);
+}
+
+static ssize_t snoop_file_read(struct file *file, char __user *buffer,
+                               size_t count, loff_t *ppos)
+{
+       struct aspeed_lpc_snoop_channel *chan = snoop_file_to_chan(file);
+       unsigned int copied;
+       int ret = 0;
+
+       if (kfifo_is_empty(&chan->fifo)) {
+               if (file->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               ret = wait_event_interruptible(chan->wq,
+                               !kfifo_is_empty(&chan->fifo));
+               if (ret == -ERESTARTSYS)
+                       return -EINTR;
+       }
+       ret = kfifo_to_user(&chan->fifo, buffer, count, &copied);
+
+       return ret ? ret : copied;
+}
+
+static unsigned int snoop_file_poll(struct file *file,
+                                   struct poll_table_struct *pt)
+{
+       struct aspeed_lpc_snoop_channel *chan = snoop_file_to_chan(file);
+
+       poll_wait(file, &chan->wq, pt);
+       return !kfifo_is_empty(&chan->fifo) ? POLLIN : 0;
+}
+
+static const struct file_operations snoop_fops = {
+       .owner  = THIS_MODULE,
+       .read   = snoop_file_read,
+       .poll   = snoop_file_poll,
+       .llseek = noop_llseek,
+};
+
+/* Save a byte to a FIFO and discard the oldest byte if FIFO is full */
+static void put_fifo_with_discard(struct aspeed_lpc_snoop_channel *chan, u8 val)
+{
+       if (!kfifo_initialized(&chan->fifo))
+               return;
+       if (kfifo_is_full(&chan->fifo))
+               kfifo_skip(&chan->fifo);
+       kfifo_put(&chan->fifo, val);
+       wake_up_interruptible(&chan->wq);
+}
+
+static irqreturn_t aspeed_lpc_snoop_irq(int irq, void *arg)
+{
+       struct aspeed_lpc_snoop *lpc_snoop = arg;
+       u32 reg, data;
+
+       if (regmap_read(lpc_snoop->regmap, HICR6, &reg))
+               return IRQ_NONE;
+
+       /* Check if one of the snoop channels is interrupting */
+       reg &= (HICR6_STR_SNP0W | HICR6_STR_SNP1W);
+       if (!reg)
+               return IRQ_NONE;
+
+       /* Ack pending IRQs */
+       regmap_write(lpc_snoop->regmap, HICR6, reg);
+
+       /* Read and save most recent snoop'ed data byte to FIFO */
+       regmap_read(lpc_snoop->regmap, SNPWDR, &data);
+
+       if (reg & HICR6_STR_SNP0W) {
+               u8 val = (data & SNPWDR_CH0_MASK) >> SNPWDR_CH0_SHIFT;
+
+               put_fifo_with_discard(&lpc_snoop->chan[0], val);
+       }
+       if (reg & HICR6_STR_SNP1W) {
+               u8 val = (data & SNPWDR_CH1_MASK) >> SNPWDR_CH1_SHIFT;
+
+               put_fifo_with_discard(&lpc_snoop->chan[1], val);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int aspeed_lpc_snoop_config_irq(struct aspeed_lpc_snoop *lpc_snoop,
+                                      struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       int rc;
+
+       lpc_snoop->irq = platform_get_irq(pdev, 0);
+       if (!lpc_snoop->irq)
+               return -ENODEV;
+
+       rc = devm_request_irq(dev, lpc_snoop->irq,
+                             aspeed_lpc_snoop_irq, IRQF_SHARED,
+                             DEVICE_NAME, lpc_snoop);
+       if (rc < 0) {
+               dev_warn(dev, "Unable to request IRQ %d\n", lpc_snoop->irq);
+               lpc_snoop->irq = 0;
+               return rc;
+       }
+
+       return 0;
+}
+
+static int aspeed_lpc_enable_snoop(struct aspeed_lpc_snoop *lpc_snoop,
+                                  struct device *dev,
+                                  int channel, u16 lpc_port)
+{
+       int rc = 0;
+       u32 hicr5_en, snpwadr_mask, snpwadr_shift, hicrb_en;
+       const struct aspeed_lpc_snoop_model_data *model_data =
+               of_device_get_match_data(dev);
+
+       init_waitqueue_head(&lpc_snoop->chan[channel].wq);
+       /* Create FIFO datastructure */
+       rc = kfifo_alloc(&lpc_snoop->chan[channel].fifo,
+                        SNOOP_FIFO_SIZE, GFP_KERNEL);
+       if (rc)
+               return rc;
+
+       lpc_snoop->chan[channel].miscdev.minor = MISC_DYNAMIC_MINOR;
+       lpc_snoop->chan[channel].miscdev.name =
+               devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, channel);
+       lpc_snoop->chan[channel].miscdev.fops = &snoop_fops;
+       lpc_snoop->chan[channel].miscdev.parent = dev;
+       rc = misc_register(&lpc_snoop->chan[channel].miscdev);
+       if (rc)
+               return rc;
+
+       /* Enable LPC snoop channel at requested port */
+       switch (channel) {
+       case 0:
+               hicr5_en = HICR5_EN_SNP0W | HICR5_ENINT_SNP0W;
+               snpwadr_mask = SNPWADR_CH0_MASK;
+               snpwadr_shift = SNPWADR_CH0_SHIFT;
+               hicrb_en = HICRB_ENSNP0D;
+               break;
+       case 1:
+               hicr5_en = HICR5_EN_SNP1W | HICR5_ENINT_SNP1W;
+               snpwadr_mask = SNPWADR_CH1_MASK;
+               snpwadr_shift = SNPWADR_CH1_SHIFT;
+               hicrb_en = HICRB_ENSNP1D;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       regmap_update_bits(lpc_snoop->regmap, HICR5, hicr5_en, hicr5_en);
+       regmap_update_bits(lpc_snoop->regmap, SNPWADR, snpwadr_mask,
+                          lpc_port << snpwadr_shift);
+       if (model_data->has_hicrb_ensnp)
+               regmap_update_bits(lpc_snoop->regmap, HICRB,
+                               hicrb_en, hicrb_en);
+
+       return rc;
+}
+
+static void aspeed_lpc_disable_snoop(struct aspeed_lpc_snoop *lpc_snoop,
+                                    int channel)
+{
+       switch (channel) {
+       case 0:
+               regmap_update_bits(lpc_snoop->regmap, HICR5,
+                                  HICR5_EN_SNP0W | HICR5_ENINT_SNP0W,
+                                  0);
+               break;
+       case 1:
+               regmap_update_bits(lpc_snoop->regmap, HICR5,
+                                  HICR5_EN_SNP1W | HICR5_ENINT_SNP1W,
+                                  0);
+               break;
+       default:
+               return;
+       }
+
+       kfifo_free(&lpc_snoop->chan[channel].fifo);
+       misc_deregister(&lpc_snoop->chan[channel].miscdev);
+}
+
+static int aspeed_lpc_snoop_probe(struct platform_device *pdev)
+{
+       struct aspeed_lpc_snoop *lpc_snoop;
+       struct device *dev;
+       u32 port;
+       int rc;
+
+       dev = &pdev->dev;
+
+       lpc_snoop = devm_kzalloc(dev, sizeof(*lpc_snoop), GFP_KERNEL);
+       if (!lpc_snoop)
+               return -ENOMEM;
+
+       lpc_snoop->regmap = syscon_node_to_regmap(
+                       pdev->dev.parent->of_node);
+       if (IS_ERR(lpc_snoop->regmap)) {
+               dev_err(dev, "Couldn't get regmap\n");
+               return -ENODEV;
+       }
+
+       dev_set_drvdata(&pdev->dev, lpc_snoop);
+
+       rc = of_property_read_u32_index(dev->of_node, "snoop-ports", 0, &port);
+       if (rc) {
+               dev_err(dev, "no snoop ports configured\n");
+               return -ENODEV;
+       }
+
+       rc = aspeed_lpc_snoop_config_irq(lpc_snoop, pdev);
+       if (rc)
+               return rc;
+
+       rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 0, port);
+       if (rc)
+               return rc;
+
+       /* Configuration of 2nd snoop channel port is optional */
+       if (of_property_read_u32_index(dev->of_node, "snoop-ports",
+                                      1, &port) == 0) {
+               rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 1, port);
+               if (rc)
+                       aspeed_lpc_disable_snoop(lpc_snoop, 0);
+       }
+
+       return rc;
+}
+
+static int aspeed_lpc_snoop_remove(struct platform_device *pdev)
+{
+       struct aspeed_lpc_snoop *lpc_snoop = dev_get_drvdata(&pdev->dev);
+
+       /* Disable both snoop channels */
+       aspeed_lpc_disable_snoop(lpc_snoop, 0);
+       aspeed_lpc_disable_snoop(lpc_snoop, 1);
+
+       return 0;
+}
+
+static const struct aspeed_lpc_snoop_model_data ast2400_model_data = {
+       .has_hicrb_ensnp = 0,
+};
+
+static const struct aspeed_lpc_snoop_model_data ast2500_model_data = {
+       .has_hicrb_ensnp = 1,
+};
+
+static const struct of_device_id aspeed_lpc_snoop_match[] = {
+       { .compatible = "aspeed,ast2400-lpc-snoop",
+         .data = &ast2400_model_data },
+       { .compatible = "aspeed,ast2500-lpc-snoop",
+         .data = &ast2500_model_data },
+       { },
+};
+
+static struct platform_driver aspeed_lpc_snoop_driver = {
+       .driver = {
+               .name           = DEVICE_NAME,
+               .of_match_table = aspeed_lpc_snoop_match,
+       },
+       .probe = aspeed_lpc_snoop_probe,
+       .remove = aspeed_lpc_snoop_remove,
+};
+
+module_platform_driver(aspeed_lpc_snoop_driver);
+
+MODULE_DEVICE_TABLE(of, aspeed_lpc_snoop_match);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Robert Lippert <rlippert@google.com>");
+MODULE_DESCRIPTION("Linux driver to control Aspeed LPC snoop functionality");
diff --git a/drivers/soc/aspeed/aspeed-p2a-ctrl.c b/drivers/soc/aspeed/aspeed-p2a-ctrl.c
new file mode 100644 (file)
index 0000000..b60fbea
--- /dev/null
@@ -0,0 +1,444 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Google Inc
+ *
+ * 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.
+ *
+ * Provides a simple driver to control the ASPEED P2A interface which allows
+ * the host to read and write to various regions of the BMC's memory.
+ */
+
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include <linux/aspeed-p2a-ctrl.h>
+
+#define DEVICE_NAME    "aspeed-p2a-ctrl"
+
+/* SCU2C is a Misc. Control Register. */
+#define SCU2C 0x2c
+/* SCU180 is the PCIe Configuration Setting Control Register. */
+#define SCU180 0x180
+/* Bit 1 controls the P2A bridge, while bit 0 controls the entire VGA device
+ * on the PCI bus.
+ */
+#define SCU180_ENP2A BIT(1)
+
+/* The ast2400/2500 both have six ranges. */
+#define P2A_REGION_COUNT 6
+
+struct region {
+       u64 min;
+       u64 max;
+       u32 bit;
+};
+
+struct aspeed_p2a_model_data {
+       /* min, max, bit */
+       struct region regions[P2A_REGION_COUNT];
+};
+
+struct aspeed_p2a_ctrl {
+       struct miscdevice miscdev;
+       struct regmap *regmap;
+
+       const struct aspeed_p2a_model_data *config;
+
+       /* Access to these needs to be locked, held via probe, mapping ioctl,
+        * and release, remove.
+        */
+       struct mutex tracking;
+       u32 readers;
+       u32 readerwriters[P2A_REGION_COUNT];
+
+       phys_addr_t mem_base;
+       resource_size_t mem_size;
+};
+
+struct aspeed_p2a_user {
+       struct file *file;
+       struct aspeed_p2a_ctrl *parent;
+
+       /* The entire memory space is opened for reading once the bridge is
+        * enabled, therefore this needs only to be tracked once per user.
+        * If any user has it open for read, the bridge must stay enabled.
+        */
+       u32 read;
+
+       /* Each entry of the array corresponds to a P2A Region.  If the user
+        * opens for read or readwrite, the reference goes up here.  On
+        * release, this array is walked and references adjusted accordingly.
+        */
+       u32 readwrite[P2A_REGION_COUNT];
+};
+
+static void aspeed_p2a_enable_bridge(struct aspeed_p2a_ctrl *p2a_ctrl)
+{
+       regmap_update_bits(p2a_ctrl->regmap,
+               SCU180, SCU180_ENP2A, SCU180_ENP2A);
+}
+
+static void aspeed_p2a_disable_bridge(struct aspeed_p2a_ctrl *p2a_ctrl)
+{
+       regmap_update_bits(p2a_ctrl->regmap, SCU180, SCU180_ENP2A, 0);
+}
+
+static int aspeed_p2a_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       unsigned long vsize;
+       pgprot_t prot;
+       struct aspeed_p2a_user *priv = file->private_data;
+       struct aspeed_p2a_ctrl *ctrl = priv->parent;
+
+       if (ctrl->mem_base == 0 && ctrl->mem_size == 0)
+               return -EINVAL;
+
+       vsize = vma->vm_end - vma->vm_start;
+       prot = vma->vm_page_prot;
+
+       if (vma->vm_pgoff + vsize > ctrl->mem_base + ctrl->mem_size)
+               return -EINVAL;
+
+       /* ast2400/2500 AHB accesses are not cache coherent */
+       prot = pgprot_noncached(prot);
+
+       if (remap_pfn_range(vma, vma->vm_start,
+               (ctrl->mem_base >> PAGE_SHIFT) + vma->vm_pgoff,
+               vsize, prot))
+               return -EAGAIN;
+
+       return 0;
+}
+
+static bool aspeed_p2a_region_acquire(struct aspeed_p2a_user *priv,
+               struct aspeed_p2a_ctrl *ctrl,
+               struct aspeed_p2a_ctrl_mapping *map)
+{
+       int i;
+       u64 base, end;
+       bool matched = false;
+
+       base = map->addr;
+       end = map->addr + (map->length - 1);
+
+       /* If the value is a legal u32, it will find a match. */
+       for (i = 0; i < P2A_REGION_COUNT; i++) {
+               const struct region *curr = &ctrl->config->regions[i];
+
+               /* If the top of this region is lower than your base, skip it.
+                */
+               if (curr->max < base)
+                       continue;
+
+               /* If the bottom of this region is higher than your end, bail.
+                */
+               if (curr->min > end)
+                       break;
+
+               /* Lock this and update it, therefore it someone else is
+                * closing their file out, this'll preserve the increment.
+                */
+               mutex_lock(&ctrl->tracking);
+               ctrl->readerwriters[i] += 1;
+               mutex_unlock(&ctrl->tracking);
+
+               /* Track with the user, so when they close their file, we can
+                * decrement properly.
+                */
+               priv->readwrite[i] += 1;
+
+               /* Enable the region as read-write. */
+               regmap_update_bits(ctrl->regmap, SCU2C, curr->bit, 0);
+               matched = true;
+       }
+
+       return matched;
+}
+
+static long aspeed_p2a_ioctl(struct file *file, unsigned int cmd,
+               unsigned long data)
+{
+       struct aspeed_p2a_user *priv = file->private_data;
+       struct aspeed_p2a_ctrl *ctrl = priv->parent;
+       void __user *arg = (void __user *)data;
+       struct aspeed_p2a_ctrl_mapping map;
+
+       if (copy_from_user(&map, arg, sizeof(map)))
+               return -EFAULT;
+
+       switch (cmd) {
+       case ASPEED_P2A_CTRL_IOCTL_SET_WINDOW:
+               /* If they want a region to be read-only, since the entire
+                * region is read-only once enabled, we just need to track this
+                * user wants to read from the bridge, and if it's not enabled.
+                * Enable it.
+                */
+               if (map.flags == ASPEED_P2A_CTRL_READ_ONLY) {
+                       mutex_lock(&ctrl->tracking);
+                       ctrl->readers += 1;
+                       mutex_unlock(&ctrl->tracking);
+
+                       /* Track with the user, so when they close their file,
+                        * we can decrement properly.
+                        */
+                       priv->read += 1;
+               } else if (map.flags == ASPEED_P2A_CTRL_READWRITE) {
+                       /* If we don't acquire any region return error. */
+                       if (!aspeed_p2a_region_acquire(priv, ctrl, &map)) {
+                               return -EINVAL;
+                       }
+               } else {
+                       /* Invalid map flags. */
+                       return -EINVAL;
+               }
+
+               aspeed_p2a_enable_bridge(ctrl);
+               return 0;
+       case ASPEED_P2A_CTRL_IOCTL_GET_MEMORY_CONFIG:
+               /* This is a request for the memory-region and corresponding
+                * length that is used by the driver for mmap.
+                */
+
+               map.flags = 0;
+               map.addr = ctrl->mem_base;
+               map.length = ctrl->mem_size;
+
+               return copy_to_user(arg, &map, sizeof(map)) ? -EFAULT : 0;
+       }
+
+       return -EINVAL;
+}
+
+
+/*
+ * When a user opens this file, we create a structure to track their mappings.
+ *
+ * A user can map a region as read-only (bridge enabled), or read-write (bit
+ * flipped, and bridge enabled).  Either way, this tracking is used, s.t. when
+ * they release the device references are handled.
+ *
+ * The bridge is not enabled until a user calls an ioctl to map a region,
+ * simply opening the device does not enable it.
+ */
+static int aspeed_p2a_open(struct inode *inode, struct file *file)
+{
+       struct aspeed_p2a_user *priv;
+
+       priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->file = file;
+       priv->read = 0;
+       memset(priv->readwrite, 0, sizeof(priv->readwrite));
+
+       /* The file's private_data is initialized to the p2a_ctrl. */
+       priv->parent = file->private_data;
+
+       /* Set the file's private_data to the user's data. */
+       file->private_data = priv;
+
+       return 0;
+}
+
+/*
+ * This will close the users mappings.  It will go through what they had opened
+ * for readwrite, and decrement those counts.  If at the end, this is the last
+ * user, it'll close the bridge.
+ */
+static int aspeed_p2a_release(struct inode *inode, struct file *file)
+{
+       int i;
+       u32 bits = 0;
+       bool open_regions = false;
+       struct aspeed_p2a_user *priv = file->private_data;
+
+       /* Lock others from changing these values until everything is updated
+        * in one pass.
+        */
+       mutex_lock(&priv->parent->tracking);
+
+       priv->parent->readers -= priv->read;
+
+       for (i = 0; i < P2A_REGION_COUNT; i++) {
+               priv->parent->readerwriters[i] -= priv->readwrite[i];
+
+               if (priv->parent->readerwriters[i] > 0)
+                       open_regions = true;
+               else
+                       bits |= priv->parent->config->regions[i].bit;
+       }
+
+       /* Setting a bit to 1 disables the region, so let's just OR with the
+        * above to disable any.
+        */
+
+       /* Note, if another user is trying to ioctl, they can't grab tracking,
+        * and therefore can't grab either register mutex.
+        * If another user is trying to close, they can't grab tracking either.
+        */
+       regmap_update_bits(priv->parent->regmap, SCU2C, bits, bits);
+
+       /* If parent->readers is zero and open windows is 0, disable the
+        * bridge.
+        */
+       if (!open_regions && priv->parent->readers == 0)
+               aspeed_p2a_disable_bridge(priv->parent);
+
+       mutex_unlock(&priv->parent->tracking);
+
+       kfree(priv);
+
+       return 0;
+}
+
+static const struct file_operations aspeed_p2a_ctrl_fops = {
+       .owner = THIS_MODULE,
+       .mmap = aspeed_p2a_mmap,
+       .unlocked_ioctl = aspeed_p2a_ioctl,
+       .open = aspeed_p2a_open,
+       .release = aspeed_p2a_release,
+};
+
+/* The regions are controlled by SCU2C */
+static void aspeed_p2a_disable_all(struct aspeed_p2a_ctrl *p2a_ctrl)
+{
+       int i;
+       u32 value = 0;
+
+       for (i = 0; i < P2A_REGION_COUNT; i++)
+               value |= p2a_ctrl->config->regions[i].bit;
+
+       regmap_update_bits(p2a_ctrl->regmap, SCU2C, value, value);
+
+       /* Disable the bridge. */
+       aspeed_p2a_disable_bridge(p2a_ctrl);
+}
+
+static int aspeed_p2a_ctrl_probe(struct platform_device *pdev)
+{
+       struct aspeed_p2a_ctrl *misc_ctrl;
+       struct device *dev;
+       struct resource resm;
+       struct device_node *node;
+       int rc = 0;
+
+       dev = &pdev->dev;
+
+       misc_ctrl = devm_kzalloc(dev, sizeof(*misc_ctrl), GFP_KERNEL);
+       if (!misc_ctrl)
+               return -ENOMEM;
+
+       mutex_init(&misc_ctrl->tracking);
+
+       /* optional. */
+       node = of_parse_phandle(dev->of_node, "memory-region", 0);
+       if (node) {
+               rc = of_address_to_resource(node, 0, &resm);
+               of_node_put(node);
+               if (rc) {
+                       dev_err(dev, "Couldn't address to resource for reserved memory\n");
+                       return -ENODEV;
+               }
+
+               misc_ctrl->mem_size = resource_size(&resm);
+               misc_ctrl->mem_base = resm.start;
+       }
+
+       misc_ctrl->regmap = syscon_node_to_regmap(pdev->dev.parent->of_node);
+       if (IS_ERR(misc_ctrl->regmap)) {
+               dev_err(dev, "Couldn't get regmap\n");
+               return -ENODEV;
+       }
+
+       misc_ctrl->config = of_device_get_match_data(dev);
+
+       dev_set_drvdata(&pdev->dev, misc_ctrl);
+
+       aspeed_p2a_disable_all(misc_ctrl);
+
+       misc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR;
+       misc_ctrl->miscdev.name = DEVICE_NAME;
+       misc_ctrl->miscdev.fops = &aspeed_p2a_ctrl_fops;
+       misc_ctrl->miscdev.parent = dev;
+
+       rc = misc_register(&misc_ctrl->miscdev);
+       if (rc)
+               dev_err(dev, "Unable to register device\n");
+
+       return rc;
+}
+
+static int aspeed_p2a_ctrl_remove(struct platform_device *pdev)
+{
+       struct aspeed_p2a_ctrl *p2a_ctrl = dev_get_drvdata(&pdev->dev);
+
+       misc_deregister(&p2a_ctrl->miscdev);
+
+       return 0;
+}
+
+#define SCU2C_DRAM     BIT(25)
+#define SCU2C_SPI      BIT(24)
+#define SCU2C_SOC      BIT(23)
+#define SCU2C_FLASH    BIT(22)
+
+static const struct aspeed_p2a_model_data ast2400_model_data = {
+       .regions = {
+               {0x00000000, 0x17FFFFFF, SCU2C_FLASH},
+               {0x18000000, 0x1FFFFFFF, SCU2C_SOC},
+               {0x20000000, 0x2FFFFFFF, SCU2C_FLASH},
+               {0x30000000, 0x3FFFFFFF, SCU2C_SPI},
+               {0x40000000, 0x5FFFFFFF, SCU2C_DRAM},
+               {0x60000000, 0xFFFFFFFF, SCU2C_SOC},
+       }
+};
+
+static const struct aspeed_p2a_model_data ast2500_model_data = {
+       .regions = {
+               {0x00000000, 0x0FFFFFFF, SCU2C_FLASH},
+               {0x10000000, 0x1FFFFFFF, SCU2C_SOC},
+               {0x20000000, 0x3FFFFFFF, SCU2C_FLASH},
+               {0x40000000, 0x5FFFFFFF, SCU2C_SOC},
+               {0x60000000, 0x7FFFFFFF, SCU2C_SPI},
+               {0x80000000, 0xFFFFFFFF, SCU2C_DRAM},
+       }
+};
+
+static const struct of_device_id aspeed_p2a_ctrl_match[] = {
+       { .compatible = "aspeed,ast2400-p2a-ctrl",
+         .data = &ast2400_model_data },
+       { .compatible = "aspeed,ast2500-p2a-ctrl",
+         .data = &ast2500_model_data },
+       { },
+};
+
+static struct platform_driver aspeed_p2a_ctrl_driver = {
+       .driver = {
+               .name           = DEVICE_NAME,
+               .of_match_table = aspeed_p2a_ctrl_match,
+       },
+       .probe = aspeed_p2a_ctrl_probe,
+       .remove = aspeed_p2a_ctrl_remove,
+};
+
+module_platform_driver(aspeed_p2a_ctrl_driver);
+
+MODULE_DEVICE_TABLE(of, aspeed_p2a_ctrl_match);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick Venture <venture@google.com>");
+MODULE_DESCRIPTION("Control for aspeed 2400/2500 P2A VGA HOST to BMC mappings");
index 506a6f3c2b9bdad27f059baabf3656ffbcea7c1b..d6b529e06d9a5e7667fecf00826ea7d5e3b61e18 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
 obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
+obj-$(CONFIG_ARCH_MXC) += soc-imx8.o
index 7d14a4b4e82a44f6a3d9da31d46cfb44142de8d7..d9231bd3c691aac7388cb76c09eea9f782464112 100644 (file)
@@ -406,7 +406,6 @@ static int imx_gpc_probe(struct platform_device *pdev)
        const struct imx_gpc_dt_data *of_id_data = of_id->data;
        struct device_node *pgc_node;
        struct regmap *regmap;
-       struct resource *res;
        void __iomem *base;
        int ret;
 
@@ -417,8 +416,7 @@ static int imx_gpc_probe(struct platform_device *pdev)
            !pgc_node)
                return 0;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(&pdev->dev, res);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
@@ -431,10 +429,19 @@ static int imx_gpc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       /* Disable PU power down in normal operation if ERR009619 is present */
+       /*
+        * Disable PU power down by runtime PM if ERR009619 is present.
+        *
+        * The PRE clock will be paused for several cycles when turning on the
+        * PU domain LDO from power down state. If PRE is in use at that time,
+        * the IPU/PRG cannot get the correct display data from the PRE.
+        *
+        * This is not a concern when the whole system enters suspend state, so
+        * it's safe to power down PU in this case.
+        */
        if (of_id_data->err009619_present)
                imx_gpc_domains[GPC_PGC_DOMAIN_PU].base.flags |=
-                               GENPD_FLAG_ALWAYS_ON;
+                               GENPD_FLAG_RPM_ALWAYS_ON;
 
        /* Keep DISP always on if ERR006287 is present */
        if (of_id_data->err006287_present)
index 176f473127b6a4a5d70aca1664ab0839b54aa8a0..31b8d002d85583348a1429a734e56334b75418fb 100644 (file)
@@ -136,8 +136,8 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
                GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ;
        const bool enable_power_control = !on;
        const bool has_regulator = !IS_ERR(domain->regulator);
-       unsigned long deadline;
        int i, ret = 0;
+       u32 pxx_req;
 
        regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
                           domain->bits.map, domain->bits.map);
@@ -169,30 +169,19 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
         * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
         * for PUP_REQ/PDN_REQ bit to be cleared
         */
-       deadline = jiffies + msecs_to_jiffies(1);
-       while (true) {
-               u32 pxx_req;
-
-               regmap_read(domain->regmap, offset, &pxx_req);
-
-               if (!(pxx_req & domain->bits.pxx))
-                       break;
-
-               if (time_after(jiffies, deadline)) {
-                       dev_err(domain->dev, "falied to command PGC\n");
-                       ret = -ETIMEDOUT;
-                       /*
-                        * If we were in a process of enabling a
-                        * domain and failed we might as well disable
-                        * the regulator we just enabled. And if it
-                        * was the opposite situation and we failed to
-                        * power down -- keep the regulator on
-                        */
-                       on = !on;
-                       break;
-               }
-
-               cpu_relax();
+       ret = regmap_read_poll_timeout(domain->regmap, offset, pxx_req,
+                                      !(pxx_req & domain->bits.pxx),
+                                      0, USEC_PER_MSEC);
+       if (ret) {
+               dev_err(domain->dev, "failed to command PGC\n");
+               /*
+                * If we were in a process of enabling a
+                * domain and failed we might as well disable
+                * the regulator we just enabled. And if it
+                * was the opposite situation and we failed to
+                * power down -- keep the regulator on
+                */
+               on = !on;
        }
 
        if (enable_power_control)
@@ -574,7 +563,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct device_node *pgc_np, *np;
        struct regmap *regmap;
-       struct resource *res;
        void __iomem *base;
        int ret;
 
@@ -584,8 +572,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       res  = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(dev, res);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
diff --git a/drivers/soc/imx/soc-imx8.c b/drivers/soc/imx/soc-imx8.c
new file mode 100644 (file)
index 0000000..fc6429f
--- /dev/null
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#define REV_B1                         0x21
+
+#define IMX8MQ_SW_INFO_B1              0x40
+#define IMX8MQ_SW_MAGIC_B1             0xff0055aa
+
+struct imx8_soc_data {
+       char *name;
+       u32 (*soc_revision)(void);
+};
+
+static u32 __init imx8mq_soc_revision(void)
+{
+       struct device_node *np;
+       void __iomem *ocotp_base;
+       u32 magic;
+       u32 rev = 0;
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp");
+       if (!np)
+               goto out;
+
+       ocotp_base = of_iomap(np, 0);
+       WARN_ON(!ocotp_base);
+
+       magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1);
+       if (magic == IMX8MQ_SW_MAGIC_B1)
+               rev = REV_B1;
+
+       iounmap(ocotp_base);
+
+out:
+       of_node_put(np);
+       return rev;
+}
+
+static const struct imx8_soc_data imx8mq_soc_data = {
+       .name = "i.MX8MQ",
+       .soc_revision = imx8mq_soc_revision,
+};
+
+static const struct of_device_id imx8_soc_match[] = {
+       { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, },
+       { }
+};
+
+#define imx8_revision(soc_rev) \
+       soc_rev ? \
+       kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf,  soc_rev & 0xf) : \
+       "unknown"
+
+static int __init imx8_soc_init(void)
+{
+       struct soc_device_attribute *soc_dev_attr;
+       struct soc_device *soc_dev;
+       struct device_node *root;
+       const struct of_device_id *id;
+       u32 soc_rev = 0;
+       const struct imx8_soc_data *data;
+       int ret;
+
+       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return -ENODEV;
+
+       soc_dev_attr->family = "Freescale i.MX";
+
+       root = of_find_node_by_path("/");
+       ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
+       if (ret)
+               goto free_soc;
+
+       id = of_match_node(imx8_soc_match, root);
+       if (!id)
+               goto free_soc;
+
+       of_node_put(root);
+
+       data = id->data;
+       if (data) {
+               soc_dev_attr->soc_id = data->name;
+               if (data->soc_revision)
+                       soc_rev = data->soc_revision();
+       }
+
+       soc_dev_attr->revision = imx8_revision(soc_rev);
+       if (!soc_dev_attr->revision)
+               goto free_soc;
+
+       soc_dev = soc_device_register(soc_dev_attr);
+       if (IS_ERR(soc_dev))
+               goto free_rev;
+
+       return 0;
+
+free_rev:
+       kfree(soc_dev_attr->revision);
+free_soc:
+       kfree(soc_dev_attr);
+       of_node_put(root);
+       return -ENODEV;
+}
+device_initcall(imx8_soc_init);
diff --git a/drivers/soc/ixp4xx/Kconfig b/drivers/soc/ixp4xx/Kconfig
new file mode 100644 (file)
index 0000000..de6becd
--- /dev/null
@@ -0,0 +1,16 @@
+menu "IXP4xx SoC drivers"
+
+config IXP4XX_QMGR
+       tristate "IXP4xx Queue Manager support"
+       help
+         This driver supports IXP4xx built-in hardware queue manager
+         and is automatically selected by Ethernet and HSS drivers.
+
+config IXP4XX_NPE
+       tristate "IXP4xx Network Processor Engine support"
+       select FW_LOADER
+       help
+         This driver supports IXP4xx built-in network coprocessors
+         and is automatically selected by Ethernet and HSS drivers.
+
+endmenu
diff --git a/drivers/soc/ixp4xx/Makefile b/drivers/soc/ixp4xx/Makefile
new file mode 100644 (file)
index 0000000..d20d99e
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_IXP4XX_QMGR)      += ixp4xx-qmgr.o
+obj-$(CONFIG_IXP4XX_NPE)       += ixp4xx-npe.o
diff --git a/drivers/soc/ixp4xx/ixp4xx-npe.c b/drivers/soc/ixp4xx/ixp4xx-npe.c
new file mode 100644 (file)
index 0000000..15979d4
--- /dev/null
@@ -0,0 +1,762 @@
+/*
+ * Intel IXP4xx Network Processor Engine driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * The code is based on publicly available information:
+ * - Intel IXP4xx Developer's Manual and other e-papers
+ * - Intel IXP400 Access Library Software (BSD license)
+ * - previous works by Christian Hohnstaedt <chohnstaedt@innominate.com>
+ *   Thanks, Christian.
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/soc/ixp4xx/npe.h>
+
+#define DEBUG_MSG                      0
+#define DEBUG_FW                       0
+
+#define NPE_COUNT                      3
+#define MAX_RETRIES                    1000    /* microseconds */
+#define NPE_42X_DATA_SIZE              0x800   /* in dwords */
+#define NPE_46X_DATA_SIZE              0x1000
+#define NPE_A_42X_INSTR_SIZE           0x1000
+#define NPE_B_AND_C_42X_INSTR_SIZE     0x800
+#define NPE_46X_INSTR_SIZE             0x1000
+#define REGS_SIZE                      0x1000
+
+#define NPE_PHYS_REG                   32
+
+#define FW_MAGIC                       0xFEEDF00D
+#define FW_BLOCK_TYPE_INSTR            0x0
+#define FW_BLOCK_TYPE_DATA             0x1
+#define FW_BLOCK_TYPE_EOF              0xF
+
+/* NPE exec status (read) and command (write) */
+#define CMD_NPE_STEP                   0x01
+#define CMD_NPE_START                  0x02
+#define CMD_NPE_STOP                   0x03
+#define CMD_NPE_CLR_PIPE               0x04
+#define CMD_CLR_PROFILE_CNT            0x0C
+#define CMD_RD_INS_MEM                 0x10 /* instruction memory */
+#define CMD_WR_INS_MEM                 0x11
+#define CMD_RD_DATA_MEM                        0x12 /* data memory */
+#define CMD_WR_DATA_MEM                        0x13
+#define CMD_RD_ECS_REG                 0x14 /* exec access register */
+#define CMD_WR_ECS_REG                 0x15
+
+#define STAT_RUN                       0x80000000
+#define STAT_STOP                      0x40000000
+#define STAT_CLEAR                     0x20000000
+#define STAT_ECS_K                     0x00800000 /* pipeline clean */
+
+#define NPE_STEVT                      0x1B
+#define NPE_STARTPC                    0x1C
+#define NPE_REGMAP                     0x1E
+#define NPE_CINDEX                     0x1F
+
+#define INSTR_WR_REG_SHORT             0x0000C000
+#define INSTR_WR_REG_BYTE              0x00004000
+#define INSTR_RD_FIFO                  0x0F888220
+#define INSTR_RESET_MBOX               0x0FAC8210
+
+#define ECS_BG_CTXT_REG_0              0x00 /* Background Executing Context */
+#define ECS_BG_CTXT_REG_1              0x01 /*         Stack level */
+#define ECS_BG_CTXT_REG_2              0x02
+#define ECS_PRI_1_CTXT_REG_0           0x04 /* Priority 1 Executing Context */
+#define ECS_PRI_1_CTXT_REG_1           0x05 /*         Stack level */
+#define ECS_PRI_1_CTXT_REG_2           0x06
+#define ECS_PRI_2_CTXT_REG_0           0x08 /* Priority 2 Executing Context */
+#define ECS_PRI_2_CTXT_REG_1           0x09 /*         Stack level */
+#define ECS_PRI_2_CTXT_REG_2           0x0A
+#define ECS_DBG_CTXT_REG_0             0x0C /* Debug Executing Context */
+#define ECS_DBG_CTXT_REG_1             0x0D /*         Stack level */
+#define ECS_DBG_CTXT_REG_2             0x0E
+#define ECS_INSTRUCT_REG               0x11 /* NPE Instruction Register */
+
+#define ECS_REG_0_ACTIVE               0x80000000 /* all levels */
+#define ECS_REG_0_NEXTPC_MASK          0x1FFF0000 /* BG/PRI1/PRI2 levels */
+#define ECS_REG_0_LDUR_BITS            8
+#define ECS_REG_0_LDUR_MASK            0x00000700 /* all levels */
+#define ECS_REG_1_CCTXT_BITS           16
+#define ECS_REG_1_CCTXT_MASK           0x000F0000 /* all levels */
+#define ECS_REG_1_SELCTXT_BITS         0
+#define ECS_REG_1_SELCTXT_MASK         0x0000000F /* all levels */
+#define ECS_DBG_REG_2_IF               0x00100000 /* debug level */
+#define ECS_DBG_REG_2_IE               0x00080000 /* debug level */
+
+/* NPE watchpoint_fifo register bit */
+#define WFIFO_VALID                    0x80000000
+
+/* NPE messaging_status register bit definitions */
+#define MSGSTAT_OFNE   0x00010000 /* OutFifoNotEmpty */
+#define MSGSTAT_IFNF   0x00020000 /* InFifoNotFull */
+#define MSGSTAT_OFNF   0x00040000 /* OutFifoNotFull */
+#define MSGSTAT_IFNE   0x00080000 /* InFifoNotEmpty */
+#define MSGSTAT_MBINT  0x00100000 /* Mailbox interrupt */
+#define MSGSTAT_IFINT  0x00200000 /* InFifo interrupt */
+#define MSGSTAT_OFINT  0x00400000 /* OutFifo interrupt */
+#define MSGSTAT_WFINT  0x00800000 /* WatchFifo interrupt */
+
+/* NPE messaging_control register bit definitions */
+#define MSGCTL_OUT_FIFO                        0x00010000 /* enable output FIFO */
+#define MSGCTL_IN_FIFO                 0x00020000 /* enable input FIFO */
+#define MSGCTL_OUT_FIFO_WRITE          0x01000000 /* enable FIFO + WRITE */
+#define MSGCTL_IN_FIFO_WRITE           0x02000000
+
+/* NPE mailbox_status value for reset */
+#define RESET_MBOX_STAT                        0x0000F0F0
+
+#define NPE_A_FIRMWARE "NPE-A"
+#define NPE_B_FIRMWARE "NPE-B"
+#define NPE_C_FIRMWARE "NPE-C"
+
+const char *npe_names[] = { NPE_A_FIRMWARE, NPE_B_FIRMWARE, NPE_C_FIRMWARE };
+
+#define print_npe(pri, npe, fmt, ...)                                  \
+       printk(pri "%s: " fmt, npe_name(npe), ## __VA_ARGS__)
+
+#if DEBUG_MSG
+#define debug_msg(npe, fmt, ...)                                       \
+       print_npe(KERN_DEBUG, npe, fmt, ## __VA_ARGS__)
+#else
+#define debug_msg(npe, fmt, ...)
+#endif
+
+static struct {
+       u32 reg, val;
+} ecs_reset[] = {
+       { ECS_BG_CTXT_REG_0,    0xA0000000 },
+       { ECS_BG_CTXT_REG_1,    0x01000000 },
+       { ECS_BG_CTXT_REG_2,    0x00008000 },
+       { ECS_PRI_1_CTXT_REG_0, 0x20000080 },
+       { ECS_PRI_1_CTXT_REG_1, 0x01000000 },
+       { ECS_PRI_1_CTXT_REG_2, 0x00008000 },
+       { ECS_PRI_2_CTXT_REG_0, 0x20000080 },
+       { ECS_PRI_2_CTXT_REG_1, 0x01000000 },
+       { ECS_PRI_2_CTXT_REG_2, 0x00008000 },
+       { ECS_DBG_CTXT_REG_0,   0x20000000 },
+       { ECS_DBG_CTXT_REG_1,   0x00000000 },
+       { ECS_DBG_CTXT_REG_2,   0x001E0000 },
+       { ECS_INSTRUCT_REG,     0x1003C00F },
+};
+
+static struct npe npe_tab[NPE_COUNT] = {
+       {
+               .id     = 0,
+       }, {
+               .id     = 1,
+       }, {
+               .id     = 2,
+       }
+};
+
+int npe_running(struct npe *npe)
+{
+       return (__raw_readl(&npe->regs->exec_status_cmd) & STAT_RUN) != 0;
+}
+
+static void npe_cmd_write(struct npe *npe, u32 addr, int cmd, u32 data)
+{
+       __raw_writel(data, &npe->regs->exec_data);
+       __raw_writel(addr, &npe->regs->exec_addr);
+       __raw_writel(cmd, &npe->regs->exec_status_cmd);
+}
+
+static u32 npe_cmd_read(struct npe *npe, u32 addr, int cmd)
+{
+       __raw_writel(addr, &npe->regs->exec_addr);
+       __raw_writel(cmd, &npe->regs->exec_status_cmd);
+       /* Iintroduce extra read cycles after issuing read command to NPE
+          so that we read the register after the NPE has updated it.
+          This is to overcome race condition between XScale and NPE */
+       __raw_readl(&npe->regs->exec_data);
+       __raw_readl(&npe->regs->exec_data);
+       return __raw_readl(&npe->regs->exec_data);
+}
+
+static void npe_clear_active(struct npe *npe, u32 reg)
+{
+       u32 val = npe_cmd_read(npe, reg, CMD_RD_ECS_REG);
+       npe_cmd_write(npe, reg, CMD_WR_ECS_REG, val & ~ECS_REG_0_ACTIVE);
+}
+
+static void npe_start(struct npe *npe)
+{
+       /* ensure only Background Context Stack Level is active */
+       npe_clear_active(npe, ECS_PRI_1_CTXT_REG_0);
+       npe_clear_active(npe, ECS_PRI_2_CTXT_REG_0);
+       npe_clear_active(npe, ECS_DBG_CTXT_REG_0);
+
+       __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+       __raw_writel(CMD_NPE_START, &npe->regs->exec_status_cmd);
+}
+
+static void npe_stop(struct npe *npe)
+{
+       __raw_writel(CMD_NPE_STOP, &npe->regs->exec_status_cmd);
+       __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); /*FIXME?*/
+}
+
+static int __must_check npe_debug_instr(struct npe *npe, u32 instr, u32 ctx,
+                                       u32 ldur)
+{
+       u32 wc;
+       int i;
+
+       /* set the Active bit, and the LDUR, in the debug level */
+       npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG,
+                     ECS_REG_0_ACTIVE | (ldur << ECS_REG_0_LDUR_BITS));
+
+       /* set CCTXT at ECS DEBUG L3 to specify in which context to execute
+          the instruction, and set SELCTXT at ECS DEBUG Level to specify
+          which context store to access.
+          Debug ECS Level Reg 1 has form 0x000n000n, where n = context number
+       */
+       npe_cmd_write(npe, ECS_DBG_CTXT_REG_1, CMD_WR_ECS_REG,
+                     (ctx << ECS_REG_1_CCTXT_BITS) |
+                     (ctx << ECS_REG_1_SELCTXT_BITS));
+
+       /* clear the pipeline */
+       __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+
+       /* load NPE instruction into the instruction register */
+       npe_cmd_write(npe, ECS_INSTRUCT_REG, CMD_WR_ECS_REG, instr);
+
+       /* we need this value later to wait for completion of NPE execution
+          step */
+       wc = __raw_readl(&npe->regs->watch_count);
+
+       /* issue a Step One command via the Execution Control register */
+       __raw_writel(CMD_NPE_STEP, &npe->regs->exec_status_cmd);
+
+       /* Watch Count register increments when NPE completes an instruction */
+       for (i = 0; i < MAX_RETRIES; i++) {
+               if (wc != __raw_readl(&npe->regs->watch_count))
+                       return 0;
+               udelay(1);
+       }
+
+       print_npe(KERN_ERR, npe, "reset: npe_debug_instr(): timeout\n");
+       return -ETIMEDOUT;
+}
+
+static int __must_check npe_logical_reg_write8(struct npe *npe, u32 addr,
+                                              u8 val, u32 ctx)
+{
+       /* here we build the NPE assembler instruction: mov8 d0, #0 */
+       u32 instr = INSTR_WR_REG_BYTE | /* OpCode */
+               addr << 9 |             /* base Operand */
+               (val & 0x1F) << 4 |     /* lower 5 bits to immediate data */
+               (val & ~0x1F) << (18 - 5);/* higher 3 bits to CoProc instr. */
+       return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
+}
+
+static int __must_check npe_logical_reg_write16(struct npe *npe, u32 addr,
+                                               u16 val, u32 ctx)
+{
+       /* here we build the NPE assembler instruction: mov16 d0, #0 */
+       u32 instr = INSTR_WR_REG_SHORT | /* OpCode */
+               addr << 9 |             /* base Operand */
+               (val & 0x1F) << 4 |     /* lower 5 bits to immediate data */
+               (val & ~0x1F) << (18 - 5);/* higher 11 bits to CoProc instr. */
+       return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
+}
+
+static int __must_check npe_logical_reg_write32(struct npe *npe, u32 addr,
+                                               u32 val, u32 ctx)
+{
+       /* write in 16 bit steps first the high and then the low value */
+       if (npe_logical_reg_write16(npe, addr, val >> 16, ctx))
+               return -ETIMEDOUT;
+       return npe_logical_reg_write16(npe, addr + 2, val & 0xFFFF, ctx);
+}
+
+static int npe_reset(struct npe *npe)
+{
+       u32 val, ctl, exec_count, ctx_reg2;
+       int i;
+
+       ctl = (__raw_readl(&npe->regs->messaging_control) | 0x3F000000) &
+               0x3F3FFFFF;
+
+       /* disable parity interrupt */
+       __raw_writel(ctl & 0x3F00FFFF, &npe->regs->messaging_control);
+
+       /* pre exec - debug instruction */
+       /* turn off the halt bit by clearing Execution Count register. */
+       exec_count = __raw_readl(&npe->regs->exec_count);
+       __raw_writel(0, &npe->regs->exec_count);
+       /* ensure that IF and IE are on (temporarily), so that we don't end up
+          stepping forever */
+       ctx_reg2 = npe_cmd_read(npe, ECS_DBG_CTXT_REG_2, CMD_RD_ECS_REG);
+       npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2 |
+                     ECS_DBG_REG_2_IF | ECS_DBG_REG_2_IE);
+
+       /* clear the FIFOs */
+       while (__raw_readl(&npe->regs->watchpoint_fifo) & WFIFO_VALID)
+               ;
+       while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE)
+               /* read from the outFIFO until empty */
+               print_npe(KERN_DEBUG, npe, "npe_reset: read FIFO = 0x%X\n",
+                         __raw_readl(&npe->regs->in_out_fifo));
+
+       while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)
+               /* step execution of the NPE intruction to read inFIFO using
+                  the Debug Executing Context stack */
+               if (npe_debug_instr(npe, INSTR_RD_FIFO, 0, 0))
+                       return -ETIMEDOUT;
+
+       /* reset the mailbox reg from the XScale side */
+       __raw_writel(RESET_MBOX_STAT, &npe->regs->mailbox_status);
+       /* from NPE side */
+       if (npe_debug_instr(npe, INSTR_RESET_MBOX, 0, 0))
+               return -ETIMEDOUT;
+
+       /* Reset the physical registers in the NPE register file */
+       for (val = 0; val < NPE_PHYS_REG; val++) {
+               if (npe_logical_reg_write16(npe, NPE_REGMAP, val >> 1, 0))
+                       return -ETIMEDOUT;
+               /* address is either 0 or 4 */
+               if (npe_logical_reg_write32(npe, (val & 1) * 4, 0, 0))
+                       return -ETIMEDOUT;
+       }
+
+       /* Reset the context store = each context's Context Store registers */
+
+       /* Context 0 has no STARTPC. Instead, this value is used to set NextPC
+          for Background ECS, to set where NPE starts executing code */
+       val = npe_cmd_read(npe, ECS_BG_CTXT_REG_0, CMD_RD_ECS_REG);
+       val &= ~ECS_REG_0_NEXTPC_MASK;
+       val |= (0 /* NextPC */ << 16) & ECS_REG_0_NEXTPC_MASK;
+       npe_cmd_write(npe, ECS_BG_CTXT_REG_0, CMD_WR_ECS_REG, val);
+
+       for (i = 0; i < 16; i++) {
+               if (i) {        /* Context 0 has no STEVT nor STARTPC */
+                       /* STEVT = off, 0x80 */
+                       if (npe_logical_reg_write8(npe, NPE_STEVT, 0x80, i))
+                               return -ETIMEDOUT;
+                       if (npe_logical_reg_write16(npe, NPE_STARTPC, 0, i))
+                               return -ETIMEDOUT;
+               }
+               /* REGMAP = d0->p0, d8->p2, d16->p4 */
+               if (npe_logical_reg_write16(npe, NPE_REGMAP, 0x820, i))
+                       return -ETIMEDOUT;
+               if (npe_logical_reg_write8(npe, NPE_CINDEX, 0, i))
+                       return -ETIMEDOUT;
+       }
+
+       /* post exec */
+       /* clear active bit in debug level */
+       npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, 0);
+       /* clear the pipeline */
+       __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+       /* restore previous values */
+       __raw_writel(exec_count, &npe->regs->exec_count);
+       npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2);
+
+       /* write reset values to Execution Context Stack registers */
+       for (val = 0; val < ARRAY_SIZE(ecs_reset); val++)
+               npe_cmd_write(npe, ecs_reset[val].reg, CMD_WR_ECS_REG,
+                             ecs_reset[val].val);
+
+       /* clear the profile counter */
+       __raw_writel(CMD_CLR_PROFILE_CNT, &npe->regs->exec_status_cmd);
+
+       __raw_writel(0, &npe->regs->exec_count);
+       __raw_writel(0, &npe->regs->action_points[0]);
+       __raw_writel(0, &npe->regs->action_points[1]);
+       __raw_writel(0, &npe->regs->action_points[2]);
+       __raw_writel(0, &npe->regs->action_points[3]);
+       __raw_writel(0, &npe->regs->watch_count);
+
+       val = ixp4xx_read_feature_bits();
+       /* reset the NPE */
+       ixp4xx_write_feature_bits(val &
+                                 ~(IXP4XX_FEATURE_RESET_NPEA << npe->id));
+       /* deassert reset */
+       ixp4xx_write_feature_bits(val |
+                                 (IXP4XX_FEATURE_RESET_NPEA << npe->id));
+       for (i = 0; i < MAX_RETRIES; i++) {
+               if (ixp4xx_read_feature_bits() &
+                   (IXP4XX_FEATURE_RESET_NPEA << npe->id))
+                       break;  /* NPE is back alive */
+               udelay(1);
+       }
+       if (i == MAX_RETRIES)
+               return -ETIMEDOUT;
+
+       npe_stop(npe);
+
+       /* restore NPE configuration bus Control Register - parity settings */
+       __raw_writel(ctl, &npe->regs->messaging_control);
+       return 0;
+}
+
+
+int npe_send_message(struct npe *npe, const void *msg, const char *what)
+{
+       const u32 *send = msg;
+       int cycles = 0;
+
+       debug_msg(npe, "Trying to send message %s [%08X:%08X]\n",
+                 what, send[0], send[1]);
+
+       if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) {
+               debug_msg(npe, "NPE input FIFO not empty\n");
+               return -EIO;
+       }
+
+       __raw_writel(send[0], &npe->regs->in_out_fifo);
+
+       if (!(__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNF)) {
+               debug_msg(npe, "NPE input FIFO full\n");
+               return -EIO;
+       }
+
+       __raw_writel(send[1], &npe->regs->in_out_fifo);
+
+       while ((cycles < MAX_RETRIES) &&
+              (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)) {
+               udelay(1);
+               cycles++;
+       }
+
+       if (cycles == MAX_RETRIES) {
+               debug_msg(npe, "Timeout sending message\n");
+               return -ETIMEDOUT;
+       }
+
+#if DEBUG_MSG > 1
+       debug_msg(npe, "Sending a message took %i cycles\n", cycles);
+#endif
+       return 0;
+}
+
+int npe_recv_message(struct npe *npe, void *msg, const char *what)
+{
+       u32 *recv = msg;
+       int cycles = 0, cnt = 0;
+
+       debug_msg(npe, "Trying to receive message %s\n", what);
+
+       while (cycles < MAX_RETRIES) {
+               if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) {
+                       recv[cnt++] = __raw_readl(&npe->regs->in_out_fifo);
+                       if (cnt == 2)
+                               break;
+               } else {
+                       udelay(1);
+                       cycles++;
+               }
+       }
+
+       switch(cnt) {
+       case 1:
+               debug_msg(npe, "Received [%08X]\n", recv[0]);
+               break;
+       case 2:
+               debug_msg(npe, "Received [%08X:%08X]\n", recv[0], recv[1]);
+               break;
+       }
+
+       if (cycles == MAX_RETRIES) {
+               debug_msg(npe, "Timeout waiting for message\n");
+               return -ETIMEDOUT;
+       }
+
+#if DEBUG_MSG > 1
+       debug_msg(npe, "Receiving a message took %i cycles\n", cycles);
+#endif
+       return 0;
+}
+
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what)
+{
+       int result;
+       u32 *send = msg, recv[2];
+
+       if ((result = npe_send_message(npe, msg, what)) != 0)
+               return result;
+       if ((result = npe_recv_message(npe, recv, what)) != 0)
+               return result;
+
+       if ((recv[0] != send[0]) || (recv[1] != send[1])) {
+               debug_msg(npe, "Message %s: unexpected message received\n",
+                         what);
+               return -EIO;
+       }
+       return 0;
+}
+
+
+int npe_load_firmware(struct npe *npe, const char *name, struct device *dev)
+{
+       const struct firmware *fw_entry;
+
+       struct dl_block {
+               u32 type;
+               u32 offset;
+       } *blk;
+
+       struct dl_image {
+               u32 magic;
+               u32 id;
+               u32 size;
+               union {
+                       u32 data[0];
+                       struct dl_block blocks[0];
+               };
+       } *image;
+
+       struct dl_codeblock {
+               u32 npe_addr;
+               u32 size;
+               u32 data[0];
+       } *cb;
+
+       int i, j, err, data_size, instr_size, blocks, table_end;
+       u32 cmd;
+
+       if ((err = request_firmware(&fw_entry, name, dev)) != 0)
+               return err;
+
+       err = -EINVAL;
+       if (fw_entry->size < sizeof(struct dl_image)) {
+               print_npe(KERN_ERR, npe, "incomplete firmware file\n");
+               goto err;
+       }
+       image = (struct dl_image*)fw_entry->data;
+
+#if DEBUG_FW
+       print_npe(KERN_DEBUG, npe, "firmware: %08X %08X %08X (0x%X bytes)\n",
+                 image->magic, image->id, image->size, image->size * 4);
+#endif
+
+       if (image->magic == swab32(FW_MAGIC)) { /* swapped file */
+               image->id = swab32(image->id);
+               image->size = swab32(image->size);
+       } else if (image->magic != FW_MAGIC) {
+               print_npe(KERN_ERR, npe, "bad firmware file magic: 0x%X\n",
+                         image->magic);
+               goto err;
+       }
+       if ((image->size * 4 + sizeof(struct dl_image)) != fw_entry->size) {
+               print_npe(KERN_ERR, npe,
+                         "inconsistent size of firmware file\n");
+               goto err;
+       }
+       if (((image->id >> 24) & 0xF /* NPE ID */) != npe->id) {
+               print_npe(KERN_ERR, npe, "firmware file NPE ID mismatch\n");
+               goto err;
+       }
+       if (image->magic == swab32(FW_MAGIC))
+               for (i = 0; i < image->size; i++)
+                       image->data[i] = swab32(image->data[i]);
+
+       if (cpu_is_ixp42x() && ((image->id >> 28) & 0xF /* device ID */)) {
+               print_npe(KERN_INFO, npe, "IXP43x/IXP46x firmware ignored on "
+                         "IXP42x\n");
+               goto err;
+       }
+
+       if (npe_running(npe)) {
+               print_npe(KERN_INFO, npe, "unable to load firmware, NPE is "
+                         "already running\n");
+               err = -EBUSY;
+               goto err;
+       }
+#if 0
+       npe_stop(npe);
+       npe_reset(npe);
+#endif
+
+       print_npe(KERN_INFO, npe, "firmware functionality 0x%X, "
+                 "revision 0x%X:%X\n", (image->id >> 16) & 0xFF,
+                 (image->id >> 8) & 0xFF, image->id & 0xFF);
+
+       if (cpu_is_ixp42x()) {
+               if (!npe->id)
+                       instr_size = NPE_A_42X_INSTR_SIZE;
+               else
+                       instr_size = NPE_B_AND_C_42X_INSTR_SIZE;
+               data_size = NPE_42X_DATA_SIZE;
+       } else {
+               instr_size = NPE_46X_INSTR_SIZE;
+               data_size = NPE_46X_DATA_SIZE;
+       }
+
+       for (blocks = 0; blocks * sizeof(struct dl_block) / 4 < image->size;
+            blocks++)
+               if (image->blocks[blocks].type == FW_BLOCK_TYPE_EOF)
+                       break;
+       if (blocks * sizeof(struct dl_block) / 4 >= image->size) {
+               print_npe(KERN_INFO, npe, "firmware EOF block marker not "
+                         "found\n");
+               goto err;
+       }
+
+#if DEBUG_FW
+       print_npe(KERN_DEBUG, npe, "%i firmware blocks found\n", blocks);
+#endif
+
+       table_end = blocks * sizeof(struct dl_block) / 4 + 1 /* EOF marker */;
+       for (i = 0, blk = image->blocks; i < blocks; i++, blk++) {
+               if (blk->offset > image->size - sizeof(struct dl_codeblock) / 4
+                   || blk->offset < table_end) {
+                       print_npe(KERN_INFO, npe, "invalid offset 0x%X of "
+                                 "firmware block #%i\n", blk->offset, i);
+                       goto err;
+               }
+
+               cb = (struct dl_codeblock*)&image->data[blk->offset];
+               if (blk->type == FW_BLOCK_TYPE_INSTR) {
+                       if (cb->npe_addr + cb->size > instr_size)
+                               goto too_big;
+                       cmd = CMD_WR_INS_MEM;
+               } else if (blk->type == FW_BLOCK_TYPE_DATA) {
+                       if (cb->npe_addr + cb->size > data_size)
+                               goto too_big;
+                       cmd = CMD_WR_DATA_MEM;
+               } else {
+                       print_npe(KERN_INFO, npe, "invalid firmware block #%i "
+                                 "type 0x%X\n", i, blk->type);
+                       goto err;
+               }
+               if (blk->offset + sizeof(*cb) / 4 + cb->size > image->size) {
+                       print_npe(KERN_INFO, npe, "firmware block #%i doesn't "
+                                 "fit in firmware image: type %c, start 0x%X,"
+                                 " length 0x%X\n", i,
+                                 blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+                                 cb->npe_addr, cb->size);
+                       goto err;
+               }
+
+               for (j = 0; j < cb->size; j++)
+                       npe_cmd_write(npe, cb->npe_addr + j, cmd, cb->data[j]);
+       }
+
+       npe_start(npe);
+       if (!npe_running(npe))
+               print_npe(KERN_ERR, npe, "unable to start\n");
+       release_firmware(fw_entry);
+       return 0;
+
+too_big:
+       print_npe(KERN_INFO, npe, "firmware block #%i doesn't fit in NPE "
+                 "memory: type %c, start 0x%X, length 0x%X\n", i,
+                 blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+                 cb->npe_addr, cb->size);
+err:
+       release_firmware(fw_entry);
+       return err;
+}
+
+
+struct npe *npe_request(unsigned id)
+{
+       if (id < NPE_COUNT)
+               if (npe_tab[id].valid)
+                       if (try_module_get(THIS_MODULE))
+                               return &npe_tab[id];
+       return NULL;
+}
+
+void npe_release(struct npe *npe)
+{
+       module_put(THIS_MODULE);
+}
+
+static int ixp4xx_npe_probe(struct platform_device *pdev)
+{
+       int i, found = 0;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+
+       for (i = 0; i < NPE_COUNT; i++) {
+               struct npe *npe = &npe_tab[i];
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+               if (!res)
+                       return -ENODEV;
+
+               if (!(ixp4xx_read_feature_bits() &
+                     (IXP4XX_FEATURE_RESET_NPEA << i))) {
+                       dev_info(dev, "NPE%d at 0x%08x-0x%08x not available\n",
+                                i, res->start, res->end);
+                       continue; /* NPE already disabled or not present */
+               }
+               npe->regs = devm_ioremap_resource(dev, res);
+               if (!npe->regs)
+                       return -ENOMEM;
+
+               if (npe_reset(npe)) {
+                       dev_info(dev, "NPE%d at 0x%08x-0x%08x does not reset\n",
+                                i, res->start, res->end);
+                       continue;
+               }
+               npe->valid = 1;
+               dev_info(dev, "NPE%d at 0x%08x-0x%08x registered\n",
+                        i, res->start, res->end);
+               found++;
+       }
+
+       if (!found)
+               return -ENODEV;
+       return 0;
+}
+
+static int ixp4xx_npe_remove(struct platform_device *pdev)
+{
+       int i;
+
+       for (i = 0; i < NPE_COUNT; i++)
+               if (npe_tab[i].regs) {
+                       npe_reset(&npe_tab[i]);
+               }
+
+       return 0;
+}
+
+static const struct of_device_id ixp4xx_npe_of_match[] = {
+       {
+               .compatible = "intel,ixp4xx-network-processing-engine",
+        },
+       {},
+};
+
+static struct platform_driver ixp4xx_npe_driver = {
+       .driver = {
+               .name           = "ixp4xx-npe",
+               .of_match_table = of_match_ptr(ixp4xx_npe_of_match),
+       },
+       .probe = ixp4xx_npe_probe,
+       .remove = ixp4xx_npe_remove,
+};
+module_platform_driver(ixp4xx_npe_driver);
+
+MODULE_AUTHOR("Krzysztof Halasa");
+MODULE_LICENSE("GPL v2");
+MODULE_FIRMWARE(NPE_A_FIRMWARE);
+MODULE_FIRMWARE(NPE_B_FIRMWARE);
+MODULE_FIRMWARE(NPE_C_FIRMWARE);
+
+EXPORT_SYMBOL(npe_names);
+EXPORT_SYMBOL(npe_running);
+EXPORT_SYMBOL(npe_request);
+EXPORT_SYMBOL(npe_release);
+EXPORT_SYMBOL(npe_load_firmware);
+EXPORT_SYMBOL(npe_send_message);
+EXPORT_SYMBOL(npe_recv_message);
+EXPORT_SYMBOL(npe_send_recv_message);
diff --git a/drivers/soc/ixp4xx/ixp4xx-qmgr.c b/drivers/soc/ixp4xx/ixp4xx-qmgr.c
new file mode 100644 (file)
index 0000000..13a8a13
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * Intel IXP4xx Queue Manager driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/soc/ixp4xx/qmgr.h>
+
+static struct qmgr_regs __iomem *qmgr_regs;
+static int qmgr_irq_1;
+static int qmgr_irq_2;
+static spinlock_t qmgr_lock;
+static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
+static void (*irq_handlers[QUEUES])(void *pdev);
+static void *irq_pdevs[QUEUES];
+
+#if DEBUG_QMGR
+char qmgr_queue_descs[QUEUES][32];
+#endif
+
+void qmgr_put_entry(unsigned int queue, u32 val)
+{
+#if DEBUG_QMGR
+       BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
+
+       printk(KERN_DEBUG "Queue %s(%i) put %X\n",
+              qmgr_queue_descs[queue], queue, val);
+#endif
+       __raw_writel(val, &qmgr_regs->acc[queue][0]);
+}
+
+u32 qmgr_get_entry(unsigned int queue)
+{
+       u32 val;
+       val = __raw_readl(&qmgr_regs->acc[queue][0]);
+#if DEBUG_QMGR
+       BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
+
+       printk(KERN_DEBUG "Queue %s(%i) get %X\n",
+              qmgr_queue_descs[queue], queue, val);
+#endif
+       return val;
+}
+
+static int __qmgr_get_stat1(unsigned int queue)
+{
+       return (__raw_readl(&qmgr_regs->stat1[queue >> 3])
+               >> ((queue & 7) << 2)) & 0xF;
+}
+
+static int __qmgr_get_stat2(unsigned int queue)
+{
+       BUG_ON(queue >= HALF_QUEUES);
+       return (__raw_readl(&qmgr_regs->stat2[queue >> 4])
+               >> ((queue & 0xF) << 1)) & 0x3;
+}
+
+/**
+ * qmgr_stat_empty() - checks if a hardware queue is empty
+ * @queue:     queue number
+ *
+ * Returns non-zero value if the queue is empty.
+ */
+int qmgr_stat_empty(unsigned int queue)
+{
+       BUG_ON(queue >= HALF_QUEUES);
+       return __qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY;
+}
+
+/**
+ * qmgr_stat_below_low_watermark() - checks if a queue is below low watermark
+ * @queue:     queue number
+ *
+ * Returns non-zero value if the queue is below low watermark.
+ */
+int qmgr_stat_below_low_watermark(unsigned int queue)
+{
+       if (queue >= HALF_QUEUES)
+               return (__raw_readl(&qmgr_regs->statne_h) >>
+                       (queue - HALF_QUEUES)) & 0x01;
+       return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY;
+}
+
+/**
+ * qmgr_stat_full() - checks if a hardware queue is full
+ * @queue:     queue number
+ *
+ * Returns non-zero value if the queue is full.
+ */
+int qmgr_stat_full(unsigned int queue)
+{
+       if (queue >= HALF_QUEUES)
+               return (__raw_readl(&qmgr_regs->statf_h) >>
+                       (queue - HALF_QUEUES)) & 0x01;
+       return __qmgr_get_stat1(queue) & QUEUE_STAT1_FULL;
+}
+
+/**
+ * qmgr_stat_overflow() - checks if a hardware queue experienced overflow
+ * @queue:     queue number
+ *
+ * Returns non-zero value if the queue experienced overflow.
+ */
+int qmgr_stat_overflow(unsigned int queue)
+{
+       return __qmgr_get_stat2(queue) & QUEUE_STAT2_OVERFLOW;
+}
+
+void qmgr_set_irq(unsigned int queue, int src,
+                 void (*handler)(void *pdev), void *pdev)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&qmgr_lock, flags);
+       if (queue < HALF_QUEUES) {
+               u32 __iomem *reg;
+               int bit;
+               BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL);
+               reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */
+               bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
+               __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit),
+                            reg);
+       } else
+               /* IRQ source for queues 32-63 is fixed */
+               BUG_ON(src != QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY);
+
+       irq_handlers[queue] = handler;
+       irq_pdevs[queue] = pdev;
+       spin_unlock_irqrestore(&qmgr_lock, flags);
+}
+
+
+static irqreturn_t qmgr_irq1_a0(int irq, void *pdev)
+{
+       int i, ret = 0;
+       u32 en_bitmap, src, stat;
+
+       /* ACK - it may clear any bits so don't rely on it */
+       __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]);
+
+       en_bitmap = qmgr_regs->irqen[0];
+       while (en_bitmap) {
+               i = __fls(en_bitmap); /* number of the last "low" queue */
+               en_bitmap &= ~BIT(i);
+               src = qmgr_regs->irqsrc[i >> 3];
+               stat = qmgr_regs->stat1[i >> 3];
+               if (src & 4) /* the IRQ condition is inverted */
+                       stat = ~stat;
+               if (stat & BIT(src & 3)) {
+                       irq_handlers[i](irq_pdevs[i]);
+                       ret = IRQ_HANDLED;
+               }
+       }
+       return ret;
+}
+
+
+static irqreturn_t qmgr_irq2_a0(int irq, void *pdev)
+{
+       int i, ret = 0;
+       u32 req_bitmap;
+
+       /* ACK - it may clear any bits so don't rely on it */
+       __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[1]);
+
+       req_bitmap = qmgr_regs->irqen[1] & qmgr_regs->statne_h;
+       while (req_bitmap) {
+               i = __fls(req_bitmap); /* number of the last "high" queue */
+               req_bitmap &= ~BIT(i);
+               irq_handlers[HALF_QUEUES + i](irq_pdevs[HALF_QUEUES + i]);
+               ret = IRQ_HANDLED;
+       }
+       return ret;
+}
+
+
+static irqreturn_t qmgr_irq(int irq, void *pdev)
+{
+       int i, half = (irq == qmgr_irq_1 ? 0 : 1);
+       u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[half]);
+
+       if (!req_bitmap)
+               return 0;
+       __raw_writel(req_bitmap, &qmgr_regs->irqstat[half]); /* ACK */
+
+       while (req_bitmap) {
+               i = __fls(req_bitmap); /* number of the last queue */
+               req_bitmap &= ~BIT(i);
+               i += half * HALF_QUEUES;
+               irq_handlers[i](irq_pdevs[i]);
+       }
+       return IRQ_HANDLED;
+}
+
+
+void qmgr_enable_irq(unsigned int queue)
+{
+       unsigned long flags;
+       int half = queue / 32;
+       u32 mask = 1 << (queue & (HALF_QUEUES - 1));
+
+       spin_lock_irqsave(&qmgr_lock, flags);
+       __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) | mask,
+                    &qmgr_regs->irqen[half]);
+       spin_unlock_irqrestore(&qmgr_lock, flags);
+}
+
+void qmgr_disable_irq(unsigned int queue)
+{
+       unsigned long flags;
+       int half = queue / 32;
+       u32 mask = 1 << (queue & (HALF_QUEUES - 1));
+
+       spin_lock_irqsave(&qmgr_lock, flags);
+       __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) & ~mask,
+                    &qmgr_regs->irqen[half]);
+       __raw_writel(mask, &qmgr_regs->irqstat[half]); /* clear */
+       spin_unlock_irqrestore(&qmgr_lock, flags);
+}
+
+static inline void shift_mask(u32 *mask)
+{
+       mask[3] = mask[3] << 1 | mask[2] >> 31;
+       mask[2] = mask[2] << 1 | mask[1] >> 31;
+       mask[1] = mask[1] << 1 | mask[0] >> 31;
+       mask[0] <<= 1;
+}
+
+#if DEBUG_QMGR
+int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+                      unsigned int nearly_empty_watermark,
+                      unsigned int nearly_full_watermark,
+                      const char *desc_format, const char* name)
+#else
+int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+                        unsigned int nearly_empty_watermark,
+                        unsigned int nearly_full_watermark)
+#endif
+{
+       u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
+       int err;
+
+       BUG_ON(queue >= QUEUES);
+
+       if ((nearly_empty_watermark | nearly_full_watermark) & ~7)
+               return -EINVAL;
+
+       switch (len) {
+       case  16:
+               cfg = 0 << 24;
+               mask[0] = 0x1;
+               break;
+       case  32:
+               cfg = 1 << 24;
+               mask[0] = 0x3;
+               break;
+       case  64:
+               cfg = 2 << 24;
+               mask[0] = 0xF;
+               break;
+       case 128:
+               cfg = 3 << 24;
+               mask[0] = 0xFF;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       cfg |= nearly_empty_watermark << 26;
+       cfg |= nearly_full_watermark << 29;
+       len /= 16;              /* in 16-dwords: 1, 2, 4 or 8 */
+       mask[1] = mask[2] = mask[3] = 0;
+
+       if (!try_module_get(THIS_MODULE))
+               return -ENODEV;
+
+       spin_lock_irq(&qmgr_lock);
+       if (__raw_readl(&qmgr_regs->sram[queue])) {
+               err = -EBUSY;
+               goto err;
+       }
+
+       while (1) {
+               if (!(used_sram_bitmap[0] & mask[0]) &&
+                   !(used_sram_bitmap[1] & mask[1]) &&
+                   !(used_sram_bitmap[2] & mask[2]) &&
+                   !(used_sram_bitmap[3] & mask[3]))
+                       break; /* found free space */
+
+               addr++;
+               shift_mask(mask);
+               if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) {
+                       printk(KERN_ERR "qmgr: no free SRAM space for"
+                              " queue %i\n", queue);
+                       err = -ENOMEM;
+                       goto err;
+               }
+       }
+
+       used_sram_bitmap[0] |= mask[0];
+       used_sram_bitmap[1] |= mask[1];
+       used_sram_bitmap[2] |= mask[2];
+       used_sram_bitmap[3] |= mask[3];
+       __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
+#if DEBUG_QMGR
+       snprintf(qmgr_queue_descs[queue], sizeof(qmgr_queue_descs[0]),
+                desc_format, name);
+       printk(KERN_DEBUG "qmgr: requested queue %s(%i) addr = 0x%02X\n",
+              qmgr_queue_descs[queue], queue, addr);
+#endif
+       spin_unlock_irq(&qmgr_lock);
+       return 0;
+
+err:
+       spin_unlock_irq(&qmgr_lock);
+       module_put(THIS_MODULE);
+       return err;
+}
+
+void qmgr_release_queue(unsigned int queue)
+{
+       u32 cfg, addr, mask[4];
+
+       BUG_ON(queue >= QUEUES); /* not in valid range */
+
+       spin_lock_irq(&qmgr_lock);
+       cfg = __raw_readl(&qmgr_regs->sram[queue]);
+       addr = (cfg >> 14) & 0xFF;
+
+       BUG_ON(!addr);          /* not requested */
+
+       switch ((cfg >> 24) & 3) {
+       case 0: mask[0] = 0x1; break;
+       case 1: mask[0] = 0x3; break;
+       case 2: mask[0] = 0xF; break;
+       case 3: mask[0] = 0xFF; break;
+       }
+
+       mask[1] = mask[2] = mask[3] = 0;
+
+       while (addr--)
+               shift_mask(mask);
+
+#if DEBUG_QMGR
+       printk(KERN_DEBUG "qmgr: releasing queue %s(%i)\n",
+              qmgr_queue_descs[queue], queue);
+       qmgr_queue_descs[queue][0] = '\x0';
+#endif
+
+       while ((addr = qmgr_get_entry(queue)))
+               printk(KERN_ERR "qmgr: released queue %i not empty: 0x%08X\n",
+                      queue, addr);
+
+       __raw_writel(0, &qmgr_regs->sram[queue]);
+
+       used_sram_bitmap[0] &= ~mask[0];
+       used_sram_bitmap[1] &= ~mask[1];
+       used_sram_bitmap[2] &= ~mask[2];
+       used_sram_bitmap[3] &= ~mask[3];
+       irq_handlers[queue] = NULL; /* catch IRQ bugs */
+       spin_unlock_irq(&qmgr_lock);
+
+       module_put(THIS_MODULE);
+}
+
+static int ixp4xx_qmgr_probe(struct platform_device *pdev)
+{
+       int i, err;
+       irq_handler_t handler1, handler2;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       int irq1, irq2;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+       qmgr_regs = devm_ioremap_resource(dev, res);
+       if (!qmgr_regs)
+               return -ENOMEM;
+
+       irq1 = platform_get_irq(pdev, 0);
+       if (irq1 <= 0)
+               return irq1 ? irq1 : -EINVAL;
+       qmgr_irq_1 = irq1;
+       irq2 = platform_get_irq(pdev, 1);
+       if (irq2 <= 0)
+               return irq2 ? irq2 : -EINVAL;
+       qmgr_irq_2 = irq2;
+
+       /* reset qmgr registers */
+       for (i = 0; i < 4; i++) {
+               __raw_writel(0x33333333, &qmgr_regs->stat1[i]);
+               __raw_writel(0, &qmgr_regs->irqsrc[i]);
+       }
+       for (i = 0; i < 2; i++) {
+               __raw_writel(0, &qmgr_regs->stat2[i]);
+               __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */
+               __raw_writel(0, &qmgr_regs->irqen[i]);
+       }
+
+       __raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h);
+       __raw_writel(0, &qmgr_regs->statf_h);
+
+       for (i = 0; i < QUEUES; i++)
+               __raw_writel(0, &qmgr_regs->sram[i]);
+
+       if (cpu_is_ixp42x_rev_a0()) {
+               handler1 = qmgr_irq1_a0;
+               handler2 = qmgr_irq2_a0;
+       } else
+               handler1 = handler2 = qmgr_irq;
+
+       err = devm_request_irq(dev, irq1, handler1, 0, "IXP4xx Queue Manager",
+                              NULL);
+       if (err) {
+               dev_err(dev, "failed to request IRQ%i (%i)\n",
+                       irq1, err);
+               return err;
+       }
+
+       err = devm_request_irq(dev, irq2, handler2, 0, "IXP4xx Queue Manager",
+                              NULL);
+       if (err) {
+               dev_err(dev, "failed to request IRQ%i (%i)\n",
+                       irq2, err);
+               return err;
+       }
+
+       used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
+       spin_lock_init(&qmgr_lock);
+
+       dev_info(dev, "IXP4xx Queue Manager initialized.\n");
+       return 0;
+}
+
+static int ixp4xx_qmgr_remove(struct platform_device *pdev)
+{
+       synchronize_irq(qmgr_irq_1);
+       synchronize_irq(qmgr_irq_2);
+       return 0;
+}
+
+static const struct of_device_id ixp4xx_qmgr_of_match[] = {
+       {
+               .compatible = "intel,ixp4xx-ahb-queue-manager",
+        },
+       {},
+};
+
+static struct platform_driver ixp4xx_qmgr_driver = {
+       .driver = {
+               .name           = "ixp4xx-qmgr",
+               .of_match_table = of_match_ptr(ixp4xx_qmgr_of_match),
+       },
+       .probe = ixp4xx_qmgr_probe,
+       .remove = ixp4xx_qmgr_remove,
+};
+module_platform_driver(ixp4xx_qmgr_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Krzysztof Halasa");
+
+EXPORT_SYMBOL(qmgr_put_entry);
+EXPORT_SYMBOL(qmgr_get_entry);
+EXPORT_SYMBOL(qmgr_stat_empty);
+EXPORT_SYMBOL(qmgr_stat_below_low_watermark);
+EXPORT_SYMBOL(qmgr_stat_full);
+EXPORT_SYMBOL(qmgr_stat_overflow);
+EXPORT_SYMBOL(qmgr_set_irq);
+EXPORT_SYMBOL(qmgr_enable_irq);
+EXPORT_SYMBOL(qmgr_disable_irq);
+#if DEBUG_QMGR
+EXPORT_SYMBOL(qmgr_queue_descs);
+EXPORT_SYMBOL(qmgr_request_queue);
+#else
+EXPORT_SYMBOL(__qmgr_request_queue);
+#endif
+EXPORT_SYMBOL(qmgr_release_queue);
index 8236a6c87e19f0bcd3f066b409307a844c2f1e61..c4449a163991bff58c2a40cf0442a96383ca788c 100644 (file)
@@ -381,6 +381,10 @@ enum pwrap_regs {
        PWRAP_EXT_GPS_AUXADC_RDATA_ADDR,
        PWRAP_GPSINF_0_STA,
        PWRAP_GPSINF_1_STA,
+
+       /* MT8516 only regs */
+       PWRAP_OP_TYPE,
+       PWRAP_MSB_FIRST,
 };
 
 static int mt2701_regs[] = {
@@ -852,6 +856,91 @@ static int mt8183_regs[] = {
        [PWRAP_WACS2_VLDCLR] =                  0xC28,
 };
 
+static int mt8516_regs[] = {
+       [PWRAP_MUX_SEL] =               0x0,
+       [PWRAP_WRAP_EN] =               0x4,
+       [PWRAP_DIO_EN] =                0x8,
+       [PWRAP_SIDLY] =                 0xc,
+       [PWRAP_RDDMY] =                 0x10,
+       [PWRAP_SI_CK_CON] =             0x14,
+       [PWRAP_CSHEXT_WRITE] =          0x18,
+       [PWRAP_CSHEXT_READ] =           0x1c,
+       [PWRAP_CSLEXT_START] =          0x20,
+       [PWRAP_CSLEXT_END] =            0x24,
+       [PWRAP_STAUPD_PRD] =            0x28,
+       [PWRAP_STAUPD_GRPEN] =          0x2c,
+       [PWRAP_STAUPD_MAN_TRIG] =       0x40,
+       [PWRAP_STAUPD_STA] =            0x44,
+       [PWRAP_WRAP_STA] =              0x48,
+       [PWRAP_HARB_INIT] =             0x4c,
+       [PWRAP_HARB_HPRIO] =            0x50,
+       [PWRAP_HIPRIO_ARB_EN] =         0x54,
+       [PWRAP_HARB_STA0] =             0x58,
+       [PWRAP_HARB_STA1] =             0x5c,
+       [PWRAP_MAN_EN] =                0x60,
+       [PWRAP_MAN_CMD] =               0x64,
+       [PWRAP_MAN_RDATA] =             0x68,
+       [PWRAP_MAN_VLDCLR] =            0x6c,
+       [PWRAP_WACS0_EN] =              0x70,
+       [PWRAP_INIT_DONE0] =            0x74,
+       [PWRAP_WACS0_CMD] =             0x78,
+       [PWRAP_WACS0_RDATA] =           0x7c,
+       [PWRAP_WACS0_VLDCLR] =          0x80,
+       [PWRAP_WACS1_EN] =              0x84,
+       [PWRAP_INIT_DONE1] =            0x88,
+       [PWRAP_WACS1_CMD] =             0x8c,
+       [PWRAP_WACS1_RDATA] =           0x90,
+       [PWRAP_WACS1_VLDCLR] =          0x94,
+       [PWRAP_WACS2_EN] =              0x98,
+       [PWRAP_INIT_DONE2] =            0x9c,
+       [PWRAP_WACS2_CMD] =             0xa0,
+       [PWRAP_WACS2_RDATA] =           0xa4,
+       [PWRAP_WACS2_VLDCLR] =          0xa8,
+       [PWRAP_INT_EN] =                0xac,
+       [PWRAP_INT_FLG_RAW] =           0xb0,
+       [PWRAP_INT_FLG] =               0xb4,
+       [PWRAP_INT_CLR] =               0xb8,
+       [PWRAP_SIG_ADR] =               0xbc,
+       [PWRAP_SIG_MODE] =              0xc0,
+       [PWRAP_SIG_VALUE] =             0xc4,
+       [PWRAP_SIG_ERRVAL] =            0xc8,
+       [PWRAP_CRC_EN] =                0xcc,
+       [PWRAP_TIMER_EN] =              0xd0,
+       [PWRAP_TIMER_STA] =             0xd4,
+       [PWRAP_WDT_UNIT] =              0xd8,
+       [PWRAP_WDT_SRC_EN] =            0xdc,
+       [PWRAP_WDT_FLG] =               0xe0,
+       [PWRAP_DEBUG_INT_SEL] =         0xe4,
+       [PWRAP_DVFS_ADR0] =             0xe8,
+       [PWRAP_DVFS_WDATA0] =           0xec,
+       [PWRAP_DVFS_ADR1] =             0xf0,
+       [PWRAP_DVFS_WDATA1] =           0xf4,
+       [PWRAP_DVFS_ADR2] =             0xf8,
+       [PWRAP_DVFS_WDATA2] =           0xfc,
+       [PWRAP_DVFS_ADR3] =             0x100,
+       [PWRAP_DVFS_WDATA3] =           0x104,
+       [PWRAP_DVFS_ADR4] =             0x108,
+       [PWRAP_DVFS_WDATA4] =           0x10c,
+       [PWRAP_DVFS_ADR5] =             0x110,
+       [PWRAP_DVFS_WDATA5] =           0x114,
+       [PWRAP_DVFS_ADR6] =             0x118,
+       [PWRAP_DVFS_WDATA6] =           0x11c,
+       [PWRAP_DVFS_ADR7] =             0x120,
+       [PWRAP_DVFS_WDATA7] =           0x124,
+       [PWRAP_SPMINF_STA] =            0x128,
+       [PWRAP_CIPHER_KEY_SEL] =        0x12c,
+       [PWRAP_CIPHER_IV_SEL] =         0x130,
+       [PWRAP_CIPHER_EN] =             0x134,
+       [PWRAP_CIPHER_RDY] =            0x138,
+       [PWRAP_CIPHER_MODE] =           0x13c,
+       [PWRAP_CIPHER_SWRST] =          0x140,
+       [PWRAP_DCM_EN] =                0x144,
+       [PWRAP_DCM_DBC_PRD] =           0x148,
+       [PWRAP_SW_RST] =                0x168,
+       [PWRAP_OP_TYPE] =               0x16c,
+       [PWRAP_MSB_FIRST] =             0x170,
+};
+
 enum pmic_type {
        PMIC_MT6323,
        PMIC_MT6351,
@@ -869,6 +958,7 @@ enum pwrap_type {
        PWRAP_MT8135,
        PWRAP_MT8173,
        PWRAP_MT8183,
+       PWRAP_MT8516,
 };
 
 struct pmic_wrapper;
@@ -1281,7 +1371,7 @@ static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp)
 static int pwrap_init_cipher(struct pmic_wrapper *wrp)
 {
        int ret;
-       u32 rdata;
+       u32 rdata = 0;
 
        pwrap_writel(wrp, 0x1, PWRAP_CIPHER_SWRST);
        pwrap_writel(wrp, 0x0, PWRAP_CIPHER_SWRST);
@@ -1297,6 +1387,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
        case PWRAP_MT6765:
        case PWRAP_MT6797:
        case PWRAP_MT8173:
+       case PWRAP_MT8516:
                pwrap_writel(wrp, 1, PWRAP_CIPHER_EN);
                break;
        case PWRAP_MT7622:
@@ -1478,7 +1569,8 @@ static int pwrap_init(struct pmic_wrapper *wrp)
 {
        int ret;
 
-       reset_control_reset(wrp->rstc);
+       if (wrp->rstc)
+               reset_control_reset(wrp->rstc);
        if (wrp->rstc_bridge)
                reset_control_reset(wrp->rstc_bridge);
 
@@ -1764,6 +1856,18 @@ static const struct pmic_wrapper_type pwrap_mt8183 = {
        .init_soc_specific = pwrap_mt8183_init_soc_specific,
 };
 
+static struct pmic_wrapper_type pwrap_mt8516 = {
+       .regs = mt8516_regs,
+       .type = PWRAP_MT8516,
+       .arb_en_all = 0xff,
+       .int_en_all = ~(u32)(BIT(31) | BIT(2)),
+       .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+       .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+       .caps = PWRAP_CAP_DCM,
+       .init_reg_clock = pwrap_mt2701_init_reg_clock,
+       .init_soc_specific = NULL,
+};
+
 static const struct of_device_id of_pwrap_match_tbl[] = {
        {
                .compatible = "mediatek,mt2701-pwrap",
@@ -1786,6 +1890,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = {
        }, {
                .compatible = "mediatek,mt8183-pwrap",
                .data = &pwrap_mt8183,
+       }, {
+               .compatible = "mediatek,mt8516-pwrap",
+               .data = &pwrap_mt8516,
        }, {
                /* sentinel */
        }
index c701b3b010f13b90615f3b62790bb81ef70c2f93..f6c3d17b05c74c9ed2dac69312e2a2aafbe41eb1 100644 (file)
@@ -248,8 +248,8 @@ static int cmd_db_dev_probe(struct platform_device *pdev)
        }
 
        cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WB);
-       if (IS_ERR_OR_NULL(cmd_db_header)) {
-               ret = PTR_ERR(cmd_db_header);
+       if (!cmd_db_header) {
+               ret = -ENOMEM;
                cmd_db_header = NULL;
                return ret;
        }
index c239a28e503f93fd56935c6e9a865f4e64117df2..f9e309f0acd32debbb44cb116386ed8bc9fc3093 100644 (file)
@@ -345,8 +345,7 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout)
        struct qmi_handle *qmi = txn->qmi;
        int ret;
 
-       ret = wait_for_completion_interruptible_timeout(&txn->completion,
-                                                       timeout);
+       ret = wait_for_completion_timeout(&txn->completion, timeout);
 
        mutex_lock(&qmi->txn_lock);
        mutex_lock(&txn->lock);
@@ -354,9 +353,7 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout)
        mutex_unlock(&txn->lock);
        mutex_unlock(&qmi->txn_lock);
 
-       if (ret < 0)
-               return ret;
-       else if (ret == 0)
+       if (ret == 0)
                return -ETIMEDOUT;
        else
                return txn->result;
index 7200d762a951085d9169a6d1003e5a6002a3add8..6f5e8be9689cf451dab5a95f2d3d79d60820f39a 100644 (file)
@@ -137,6 +137,26 @@ static struct class rmtfs_class = {
        .name           = "rmtfs",
 };
 
+static int qcom_rmtfs_mem_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+       struct qcom_rmtfs_mem *rmtfs_mem = filep->private_data;
+
+       if (vma->vm_end - vma->vm_start > rmtfs_mem->size) {
+               dev_dbg(&rmtfs_mem->dev,
+                       "vm_end[%lu] - vm_start[%lu] [%lu] > mem->size[%pa]\n",
+                       vma->vm_end, vma->vm_start,
+                       (vma->vm_end - vma->vm_start), &rmtfs_mem->size);
+               return -EINVAL;
+       }
+
+       vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+       return remap_pfn_range(vma,
+                              vma->vm_start,
+                              rmtfs_mem->addr >> PAGE_SHIFT,
+                              vma->vm_end - vma->vm_start,
+                              vma->vm_page_prot);
+}
+
 static const struct file_operations qcom_rmtfs_mem_fops = {
        .owner = THIS_MODULE,
        .open = qcom_rmtfs_mem_open,
@@ -144,6 +164,7 @@ static const struct file_operations qcom_rmtfs_mem_fops = {
        .write = qcom_rmtfs_mem_write,
        .release = qcom_rmtfs_mem_release,
        .llseek = default_llseek,
+       .mmap = qcom_rmtfs_mem_mmap,
 };
 
 static void qcom_rmtfs_mem_release_device(struct device *dev)
index 75bd9a83aef00670d474a69c86fde81aa4794e93..e278fc11fe5cfa7606784901cec178c5cd5a79bd 100644 (file)
@@ -459,7 +459,7 @@ static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg,
        do {
                slot = bitmap_find_next_zero_area(tcs->slots, MAX_TCS_SLOTS,
                                                  i, msg->num_cmds, 0);
-               if (slot == tcs->num_tcs * tcs->ncpt)
+               if (slot >= tcs->num_tcs * tcs->ncpt)
                        return -ENOMEM;
                i += tcs->ncpt;
        } while (slot + msg->num_cmds - 1 >= i);
index 4af96e668a2f1d69f49c0045f56b3b4ea2be6dbf..3299cf5365f3c7d54237cc2a9cf11d859d647a76 100644 (file)
@@ -335,6 +335,9 @@ static int __init renesas_soc_init(void)
                /* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */
                if ((product & 0x7fff) == 0x5210)
                        product ^= 0x11;
+               /* R-Car M3-W ES1.3 incorrectly identifies as ES2.1 */
+               if ((product & 0x7fff) == 0x5211)
+                       product ^= 0x12;
                if (soc->id && ((product >> 8) & 0xff) != soc->id) {
                        pr_warn("SoC mismatch (product = 0x%x)\n", product);
                        return -ENODEV;
index 96882ffde67ea6b7a6303fa5f69f51864e82fb94..3b81e1d75a97e75fd579fcc38117f06e94d2450d 100644 (file)
@@ -66,9 +66,11 @@ static const struct rockchip_grf_info rk3228_grf __initconst = {
 };
 
 #define RK3288_GRF_SOC_CON0            0x244
+#define RK3288_GRF_SOC_CON2            0x24c
 
 static const struct rockchip_grf_value rk3288_defaults[] __initconst = {
        { "jtag switching", RK3288_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 12) },
+       { "pwm select", RK3288_GRF_SOC_CON2, HIWORD_UPDATE(1, 1, 0) },
 };
 
 static const struct rockchip_grf_info rk3288_grf __initconst = {
index 0df25851869365e4dccd0e10f8042f54d65e99c4..5648e5c09ef5476a92d5ed2613c20b9b9777a348 100644 (file)
@@ -268,6 +268,14 @@ static const char * const tegra186_reset_levels[] = {
 };
 
 static const char * const tegra30_reset_sources[] = {
+       "POWER_ON_RESET",
+       "WATCHDOG",
+       "SENSOR",
+       "SW_MAIN",
+       "LP0"
+};
+
+static const char * const tegra210_reset_sources[] = {
        "POWER_ON_RESET",
        "WATCHDOG",
        "SENSOR",
@@ -656,10 +664,15 @@ static int tegra_genpd_power_on(struct generic_pm_domain *domain)
        int err;
 
        err = tegra_powergate_power_up(pg, true);
-       if (err)
+       if (err) {
                dev_err(dev, "failed to turn on PM domain %s: %d\n",
                        pg->genpd.name, err);
+               goto out;
+       }
+
+       reset_control_release(pg->reset);
 
+out:
        return err;
 }
 
@@ -669,10 +682,18 @@ static int tegra_genpd_power_off(struct generic_pm_domain *domain)
        struct device *dev = pg->pmc->dev;
        int err;
 
+       err = reset_control_acquire(pg->reset);
+       if (err < 0) {
+               pr_err("failed to acquire resets: %d\n", err);
+               return err;
+       }
+
        err = tegra_powergate_power_down(pg);
-       if (err)
+       if (err) {
                dev_err(dev, "failed to turn off PM domain %s: %d\n",
                        pg->genpd.name, err);
+               reset_control_release(pg->reset);
+       }
 
        return err;
 }
@@ -937,38 +958,53 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
        struct device *dev = pg->pmc->dev;
        int err;
 
-       pg->reset = of_reset_control_array_get_exclusive(np);
+       pg->reset = of_reset_control_array_get_exclusive_released(np);
        if (IS_ERR(pg->reset)) {
                err = PTR_ERR(pg->reset);
                dev_err(dev, "failed to get device resets: %d\n", err);
                return err;
        }
 
-       if (off)
+       err = reset_control_acquire(pg->reset);
+       if (err < 0) {
+               pr_err("failed to acquire resets: %d\n", err);
+               goto out;
+       }
+
+       if (off) {
                err = reset_control_assert(pg->reset);
-       else
+       } else {
                err = reset_control_deassert(pg->reset);
+               if (err < 0)
+                       goto out;
 
-       if (err)
+               reset_control_release(pg->reset);
+       }
+
+out:
+       if (err) {
+               reset_control_release(pg->reset);
                reset_control_put(pg->reset);
+       }
 
        return err;
 }
 
-static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
+static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
 {
        struct device *dev = pmc->dev;
        struct tegra_powergate *pg;
-       int id, err;
+       int id, err = 0;
        bool off;
 
        pg = kzalloc(sizeof(*pg), GFP_KERNEL);
        if (!pg)
-               return;
+               return -ENOMEM;
 
        id = tegra_powergate_lookup(pmc, np->name);
        if (id < 0) {
                dev_err(dev, "powergate lookup failed for %pOFn: %d\n", np, id);
+               err = -ENODEV;
                goto free_mem;
        }
 
@@ -1021,7 +1057,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
 
        dev_dbg(dev, "added PM domain %s\n", pg->genpd.name);
 
-       return;
+       return 0;
 
 remove_genpd:
        pm_genpd_remove(&pg->genpd);
@@ -1040,25 +1076,67 @@ set_available:
 
 free_mem:
        kfree(pg);
+
+       return err;
 }
 
-static void tegra_powergate_init(struct tegra_pmc *pmc,
-                                struct device_node *parent)
+static int tegra_powergate_init(struct tegra_pmc *pmc,
+                               struct device_node *parent)
 {
        struct device_node *np, *child;
-       unsigned int i;
+       int err = 0;
+
+       np = of_get_child_by_name(parent, "powergates");
+       if (!np)
+               return 0;
+
+       for_each_child_of_node(np, child) {
+               err = tegra_powergate_add(pmc, child);
+               if (err < 0) {
+                       of_node_put(child);
+                       break;
+               }
+       }
+
+       of_node_put(np);
+
+       return err;
+}
+
+static void tegra_powergate_remove(struct generic_pm_domain *genpd)
+{
+       struct tegra_powergate *pg = to_powergate(genpd);
+
+       reset_control_put(pg->reset);
+
+       while (pg->num_clks--)
+               clk_put(pg->clks[pg->num_clks]);
+
+       kfree(pg->clks);
 
-       /* Create a bitmap of the available and valid partitions */
-       for (i = 0; i < pmc->soc->num_powergates; i++)
-               if (pmc->soc->powergates[i])
-                       set_bit(i, pmc->powergates_available);
+       set_bit(pg->id, pmc->powergates_available);
+
+       kfree(pg);
+}
+
+static void tegra_powergate_remove_all(struct device_node *parent)
+{
+       struct generic_pm_domain *genpd;
+       struct device_node *np, *child;
 
        np = of_get_child_by_name(parent, "powergates");
        if (!np)
                return;
 
-       for_each_child_of_node(np, child)
-               tegra_powergate_add(pmc, child);
+       for_each_child_of_node(np, child) {
+               of_genpd_del_provider(child);
+
+               genpd = of_genpd_remove_last(child);
+               if (IS_ERR(genpd))
+                       continue;
+
+               tegra_powergate_remove(genpd);
+       }
 
        of_node_put(np);
 }
@@ -1709,13 +1787,16 @@ static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc)
 static ssize_t reset_reason_show(struct device *dev,
                                 struct device_attribute *attr, char *buf)
 {
-       u32 value, rst_src;
+       u32 value;
 
        value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status);
-       rst_src = (value & pmc->soc->regs->rst_source_mask) >>
-                       pmc->soc->regs->rst_source_shift;
+       value &= pmc->soc->regs->rst_source_mask;
+       value >>= pmc->soc->regs->rst_source_shift;
+
+       if (WARN_ON(value >= pmc->soc->num_reset_sources))
+               return sprintf(buf, "%s\n", "UNKNOWN");
 
-       return sprintf(buf, "%s\n", pmc->soc->reset_sources[rst_src]);
+       return sprintf(buf, "%s\n", pmc->soc->reset_sources[value]);
 }
 
 static DEVICE_ATTR_RO(reset_reason);
@@ -1723,13 +1804,16 @@ static DEVICE_ATTR_RO(reset_reason);
 static ssize_t reset_level_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       u32 value, rst_lvl;
+       u32 value;
 
        value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status);
-       rst_lvl = (value & pmc->soc->regs->rst_level_mask) >>
-                       pmc->soc->regs->rst_level_shift;
+       value &= pmc->soc->regs->rst_level_mask;
+       value >>= pmc->soc->regs->rst_level_shift;
 
-       return sprintf(buf, "%s\n", pmc->soc->reset_levels[rst_lvl]);
+       if (WARN_ON(value >= pmc->soc->num_reset_levels))
+               return sprintf(buf, "%s\n", "UNKNOWN");
+
+       return sprintf(buf, "%s\n", pmc->soc->reset_levels[value]);
 }
 
 static DEVICE_ATTR_RO(reset_level);
@@ -1999,7 +2083,7 @@ static int tegra_pmc_probe(struct platform_device *pdev)
        if (IS_ENABLED(CONFIG_DEBUG_FS)) {
                err = tegra_powergate_debugfs_init();
                if (err < 0)
-                       return err;
+                       goto cleanup_sysfs;
        }
 
        err = register_restart_handler(&tegra_pmc_restart_handler);
@@ -2013,9 +2097,13 @@ static int tegra_pmc_probe(struct platform_device *pdev)
        if (err)
                goto cleanup_restart_handler;
 
+       err = tegra_powergate_init(pmc, pdev->dev.of_node);
+       if (err < 0)
+               goto cleanup_powergates;
+
        err = tegra_pmc_irq_init(pmc);
        if (err < 0)
-               goto cleanup_restart_handler;
+               goto cleanup_powergates;
 
        mutex_lock(&pmc->powergates_lock);
        iounmap(pmc->base);
@@ -2026,10 +2114,15 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 
        return 0;
 
+cleanup_powergates:
+       tegra_powergate_remove_all(pdev->dev.of_node);
 cleanup_restart_handler:
        unregister_restart_handler(&tegra_pmc_restart_handler);
 cleanup_debugfs:
        debugfs_remove(pmc->debugfs);
+cleanup_sysfs:
+       device_remove_file(&pdev->dev, &dev_attr_reset_reason);
+       device_remove_file(&pdev->dev, &dev_attr_reset_level);
        return err;
 }
 
@@ -2185,7 +2278,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
        .init = tegra20_pmc_init,
        .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
        .reset_sources = tegra30_reset_sources,
-       .num_reset_sources = 5,
+       .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
        .reset_levels = NULL,
        .num_reset_levels = 0,
 };
@@ -2236,7 +2329,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
        .init = tegra20_pmc_init,
        .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
        .reset_sources = tegra30_reset_sources,
-       .num_reset_sources = 5,
+       .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
        .reset_levels = NULL,
        .num_reset_levels = 0,
 };
@@ -2347,7 +2440,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
        .init = tegra20_pmc_init,
        .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
        .reset_sources = tegra30_reset_sources,
-       .num_reset_sources = 5,
+       .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
        .reset_levels = NULL,
        .num_reset_levels = 0,
 };
@@ -2452,8 +2545,8 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
        .regs = &tegra20_pmc_regs,
        .init = tegra20_pmc_init,
        .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
-       .reset_sources = tegra30_reset_sources,
-       .num_reset_sources = 5,
+       .reset_sources = tegra210_reset_sources,
+       .num_reset_sources = ARRAY_SIZE(tegra210_reset_sources),
        .reset_levels = NULL,
        .num_reset_levels = 0,
 };
@@ -2578,9 +2671,9 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
        .init = NULL,
        .setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
        .reset_sources = tegra186_reset_sources,
-       .num_reset_sources = 14,
+       .num_reset_sources = ARRAY_SIZE(tegra186_reset_sources),
        .reset_levels = tegra186_reset_levels,
-       .num_reset_levels = 3,
+       .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
        .num_wake_events = ARRAY_SIZE(tegra186_wake_events),
        .wake_events = tegra186_wake_events,
 };
@@ -2719,6 +2812,7 @@ static int __init tegra_pmc_early_init(void)
        const struct of_device_id *match;
        struct device_node *np;
        struct resource regs;
+       unsigned int i;
        bool invert;
 
        mutex_init(&pmc->powergates_lock);
@@ -2775,7 +2869,10 @@ static int __init tegra_pmc_early_init(void)
                if (pmc->soc->maybe_tz_only)
                        pmc->tz_only = tegra_pmc_detect_tz_only(pmc);
 
-               tegra_powergate_init(pmc, np);
+               /* Create a bitmap of the available and valid partitions */
+               for (i = 0; i < pmc->soc->num_powergates; i++)
+                       if (pmc->soc->powergates[i])
+                               set_bit(i, pmc->powergates_available);
 
                /*
                 * Invert the interrupt polarity if a PMC device tree node
index be4570baad96c0c1a1bd5c1d9eb1d0d70e4da97d..57960e92ebe03bafa01ad04ba7ca95176640e677 100644 (file)
@@ -45,11 +45,12 @@ config KEYSTONE_NAVIGATOR_DMA
 config AMX3_PM
        tristate "AMx3 Power Management"
        depends on SOC_AM33XX || SOC_AM43XX
-       depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM
+       depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM && RTC_DRV_OMAP
        help
          Enable power management on AM335x and AM437x. Required for suspend to mem
          and standby states on both AM335x and AM437x platforms and for deeper cpuidle
-         c-states on AM335x.
+         c-states on AM335x. Also required for rtc and ddr in self-refresh low
+         power mode on AM437x platforms.
 
 config WKUP_M3_IPC
        tristate "TI AMx3 Wkup-M3 IPC Driver"
index d0dab323651fc3b6c4741898669318b54a32e588..fc5802ccb1c00da9e0d209e7d3dd949bd8f6583c 100644 (file)
@@ -6,6 +6,7 @@
  *     Vaibhav Bedia, Dave Gerlach
  */
 
+#include <linux/clk.h>
 #include <linux/cpu.h>
 #include <linux/err.h>
 #include <linux/genalloc.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/nvmem-consumer.h>
 #include <linux/of.h>
 #include <linux/platform_data/pm33xx.h>
 #include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/rtc/rtc-omap.h>
 #include <linux/sizes.h>
 #include <linux/sram.h>
 #include <linux/suspend.h>
 #define AMX3_PM_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \
                                         (unsigned long)pm_sram->do_wfi)
 
+#define RTC_SCRATCH_RESUME_REG 0
+#define RTC_SCRATCH_MAGIC_REG  1
+#define RTC_REG_BOOT_MAGIC     0x8cd0 /* RTC */
+#define GIC_INT_SET_PENDING_BASE 0x200
+#define AM43XX_GIC_DIST_BASE   0x48241000
+
+static u32 rtc_magic_val;
+
 static int (*am33xx_do_wfi_sram)(unsigned long unused);
 static phys_addr_t am33xx_do_wfi_sram_phys;
 
 static struct gen_pool *sram_pool, *sram_pool_data;
 static unsigned long ocmcram_location, ocmcram_location_data;
 
+static struct rtc_device *omap_rtc;
+static void __iomem *gic_dist_base;
+
 static struct am33xx_pm_platform_data *pm_ops;
 static struct am33xx_pm_sram_addr *pm_sram;
 
 static struct device *pm33xx_dev;
 static struct wkup_m3_ipc *m3_ipc;
 
+#ifdef CONFIG_SUSPEND
+static int rtc_only_idle;
+static int retrigger_irq;
 static unsigned long suspend_wfi_flags;
 
+static struct wkup_m3_wakeup_src wakeup_src = {.irq_nr = 0,
+       .src = "Unknown",
+};
+
+static struct wkup_m3_wakeup_src rtc_alarm_wakeup = {
+       .irq_nr = 108, .src = "RTC Alarm",
+};
+
+static struct wkup_m3_wakeup_src rtc_ext_wakeup = {
+       .irq_nr = 0, .src = "Ext wakeup",
+};
+#endif
+
 static u32 sram_suspend_address(unsigned long addr)
 {
        return ((unsigned long)am33xx_do_wfi_sram +
                AMX3_PM_SRAM_SYMBOL_OFFSET(addr));
 }
 
+static int am33xx_push_sram_idle(void)
+{
+       struct am33xx_pm_ro_sram_data ro_sram_data;
+       int ret;
+       u32 table_addr, ro_data_addr;
+       void *copy_addr;
+
+       ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data;
+       ro_sram_data.amx3_pm_sram_data_phys =
+               gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data);
+       ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr();
+
+       /* Save physical address to calculate resume offset during pm init */
+       am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool,
+                                                       ocmcram_location);
+
+       am33xx_do_wfi_sram = sram_exec_copy(sram_pool, (void *)ocmcram_location,
+                                           pm_sram->do_wfi,
+                                           *pm_sram->do_wfi_sz);
+       if (!am33xx_do_wfi_sram) {
+               dev_err(pm33xx_dev,
+                       "PM: %s: am33xx_do_wfi copy to sram failed\n",
+                       __func__);
+               return -ENODEV;
+       }
+
+       table_addr =
+               sram_suspend_address((unsigned long)pm_sram->emif_sram_table);
+       ret = ti_emif_copy_pm_function_table(sram_pool, (void *)table_addr);
+       if (ret) {
+               dev_dbg(pm33xx_dev,
+                       "PM: %s: EMIF function copy failed\n", __func__);
+               return -EPROBE_DEFER;
+       }
+
+       ro_data_addr =
+               sram_suspend_address((unsigned long)pm_sram->ro_sram_data);
+       copy_addr = sram_exec_copy(sram_pool, (void *)ro_data_addr,
+                                  &ro_sram_data,
+                                  sizeof(ro_sram_data));
+       if (!copy_addr) {
+               dev_err(pm33xx_dev,
+                       "PM: %s: ro_sram_data copy to sram failed\n",
+                       __func__);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int __init am43xx_map_gic(void)
+{
+       gic_dist_base = ioremap(AM43XX_GIC_DIST_BASE, SZ_4K);
+
+       if (!gic_dist_base)
+               return -ENOMEM;
+
+       return 0;
+}
+
 #ifdef CONFIG_SUSPEND
+struct wkup_m3_wakeup_src rtc_wake_src(void)
+{
+       u32 i;
+
+       i = __raw_readl(pm_ops->get_rtc_base_addr() + 0x44) & 0x40;
+
+       if (i) {
+               retrigger_irq = rtc_alarm_wakeup.irq_nr;
+               return rtc_alarm_wakeup;
+       }
+
+       retrigger_irq = rtc_ext_wakeup.irq_nr;
+
+       return rtc_ext_wakeup;
+}
+
+int am33xx_rtc_only_idle(unsigned long wfi_flags)
+{
+       omap_rtc_power_off_program(&omap_rtc->dev);
+       am33xx_do_wfi_sram(wfi_flags);
+       return 0;
+}
+
 static int am33xx_pm_suspend(suspend_state_t suspend_state)
 {
        int i, ret = 0;
 
-       ret = pm_ops->soc_suspend((unsigned long)suspend_state,
-                                 am33xx_do_wfi_sram, suspend_wfi_flags);
+       if (suspend_state == PM_SUSPEND_MEM &&
+           pm_ops->check_off_mode_enable()) {
+               pm_ops->prepare_rtc_suspend();
+               pm_ops->save_context();
+               suspend_wfi_flags |= WFI_FLAG_RTC_ONLY;
+               clk_save_context();
+               ret = pm_ops->soc_suspend(suspend_state, am33xx_rtc_only_idle,
+                                         suspend_wfi_flags);
+
+               suspend_wfi_flags &= ~WFI_FLAG_RTC_ONLY;
+
+               if (!ret) {
+                       clk_restore_context();
+                       pm_ops->restore_context();
+                       m3_ipc->ops->set_rtc_only(m3_ipc);
+                       am33xx_push_sram_idle();
+               }
+       } else {
+               ret = pm_ops->soc_suspend(suspend_state, am33xx_do_wfi_sram,
+                                         suspend_wfi_flags);
+       }
 
        if (ret) {
                dev_err(pm33xx_dev, "PM: Kernel suspend failure\n");
@@ -77,8 +210,20 @@ static int am33xx_pm_suspend(suspend_state_t suspend_state)
                                "PM: CM3 returned unknown result = %d\n", i);
                        ret = -1;
                }
+
+               /* print the wakeup reason */
+               if (rtc_only_idle) {
+                       wakeup_src = rtc_wake_src();
+                       pr_info("PM: Wakeup source %s\n", wakeup_src.src);
+               } else {
+                       pr_info("PM: Wakeup source %s\n",
+                               m3_ipc->ops->request_wake_src(m3_ipc));
+               }
        }
 
+       if (suspend_state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable())
+               pm_ops->prepare_rtc_resume();
+
        return ret;
 }
 
@@ -101,6 +246,18 @@ static int am33xx_pm_enter(suspend_state_t suspend_state)
 static int am33xx_pm_begin(suspend_state_t state)
 {
        int ret = -EINVAL;
+       struct nvmem_device *nvmem;
+
+       if (state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) {
+               nvmem = devm_nvmem_device_get(&omap_rtc->dev,
+                                             "omap_rtc_scratch0");
+               if (nvmem)
+                       nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4,
+                                          (void *)&rtc_magic_val);
+               rtc_only_idle = 1;
+       } else {
+               rtc_only_idle = 0;
+       }
 
        switch (state) {
        case PM_SUSPEND_MEM:
@@ -116,7 +273,28 @@ static int am33xx_pm_begin(suspend_state_t state)
 
 static void am33xx_pm_end(void)
 {
+       u32 val = 0;
+       struct nvmem_device *nvmem;
+
+       nvmem = devm_nvmem_device_get(&omap_rtc->dev, "omap_rtc_scratch0");
        m3_ipc->ops->finish_low_power(m3_ipc);
+       if (rtc_only_idle) {
+               if (retrigger_irq)
+                       /*
+                        * 32 bits of Interrupt Set-Pending correspond to 32
+                        * 32 interrupts. Compute the bit offset of the
+                        * Interrupt and set that particular bit
+                        * Compute the register offset by dividing interrupt
+                        * number by 32 and mutiplying by 4
+                        */
+                       writel_relaxed(1 << (retrigger_irq & 31),
+                                      gic_dist_base + GIC_INT_SET_PENDING_BASE
+                                      + retrigger_irq / 32 * 4);
+                       nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4,
+                                          (void *)&val);
+       }
+
+       rtc_only_idle = 0;
 }
 
 static int am33xx_pm_valid(suspend_state_t state)
@@ -219,51 +397,37 @@ mpu_put_node:
        return ret;
 }
 
-static int am33xx_push_sram_idle(void)
+static int am33xx_pm_rtc_setup(void)
 {
-       struct am33xx_pm_ro_sram_data ro_sram_data;
-       int ret;
-       u32 table_addr, ro_data_addr;
-       void *copy_addr;
-
-       ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data;
-       ro_sram_data.amx3_pm_sram_data_phys =
-               gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data);
-       ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr();
+       struct device_node *np;
+       unsigned long val = 0;
+       struct nvmem_device *nvmem;
 
-       /* Save physical address to calculate resume offset during pm init */
-       am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool,
-                                                       ocmcram_location);
+       np = of_find_node_by_name(NULL, "rtc");
 
-       am33xx_do_wfi_sram = sram_exec_copy(sram_pool, (void *)ocmcram_location,
-                                           pm_sram->do_wfi,
-                                           *pm_sram->do_wfi_sz);
-       if (!am33xx_do_wfi_sram) {
-               dev_err(pm33xx_dev,
-                       "PM: %s: am33xx_do_wfi copy to sram failed\n",
-                       __func__);
-               return -ENODEV;
-       }
-
-       table_addr =
-               sram_suspend_address((unsigned long)pm_sram->emif_sram_table);
-       ret = ti_emif_copy_pm_function_table(sram_pool, (void *)table_addr);
-       if (ret) {
-               dev_dbg(pm33xx_dev,
-                       "PM: %s: EMIF function copy failed\n", __func__);
-               return -EPROBE_DEFER;
-       }
+       if (of_device_is_available(np)) {
+               omap_rtc = rtc_class_open("rtc0");
+               if (!omap_rtc) {
+                       pr_warn("PM: rtc0 not available");
+                       return -EPROBE_DEFER;
+               }
 
-       ro_data_addr =
-               sram_suspend_address((unsigned long)pm_sram->ro_sram_data);
-       copy_addr = sram_exec_copy(sram_pool, (void *)ro_data_addr,
-                                  &ro_sram_data,
-                                  sizeof(ro_sram_data));
-       if (!copy_addr) {
-               dev_err(pm33xx_dev,
-                       "PM: %s: ro_sram_data copy to sram failed\n",
-                       __func__);
-               return -ENODEV;
+               nvmem = devm_nvmem_device_get(&omap_rtc->dev,
+                                             "omap_rtc_scratch0");
+               if (nvmem) {
+                       nvmem_device_read(nvmem, RTC_SCRATCH_MAGIC_REG * 4,
+                                         4, (void *)&rtc_magic_val);
+                       if ((rtc_magic_val & 0xffff) != RTC_REG_BOOT_MAGIC)
+                               pr_warn("PM: bootloader does not support rtc-only!\n");
+
+                       nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4,
+                                          4, (void *)&val);
+                       val = pm_sram->resume_address;
+                       nvmem_device_write(nvmem, RTC_SCRATCH_RESUME_REG * 4,
+                                          4, (void *)&val);
+               }
+       } else {
+               pr_warn("PM: no-rtc available, rtc-only mode disabled.\n");
        }
 
        return 0;
@@ -284,34 +448,42 @@ static int am33xx_pm_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
+       ret = am43xx_map_gic();
+       if (ret) {
+               pr_err("PM: Could not ioremap GIC base\n");
+               return ret;
+       }
+
        pm_sram = pm_ops->get_sram_addrs();
        if (!pm_sram) {
                dev_err(dev, "PM: Cannot get PM asm function addresses!!\n");
                return -ENODEV;
        }
 
+       m3_ipc = wkup_m3_ipc_get();
+       if (!m3_ipc) {
+               pr_err("PM: Cannot get wkup_m3_ipc handle\n");
+               return -EPROBE_DEFER;
+       }
+
        pm33xx_dev = dev;
 
        ret = am33xx_pm_alloc_sram();
        if (ret)
                return ret;
 
-       ret = am33xx_push_sram_idle();
+       ret = am33xx_pm_rtc_setup();
        if (ret)
                goto err_free_sram;
 
-       m3_ipc = wkup_m3_ipc_get();
-       if (!m3_ipc) {
-               dev_dbg(dev, "PM: Cannot get wkup_m3_ipc handle\n");
-               ret = -EPROBE_DEFER;
+       ret = am33xx_push_sram_idle();
+       if (ret)
                goto err_free_sram;
-       }
 
        am33xx_pm_set_ipc_ops();
 
 #ifdef CONFIG_SUSPEND
        suspend_set_ops(&am33xx_pm_ops);
-#endif /* CONFIG_SUSPEND */
 
        /*
         * For a system suspend we must flush the caches, we want
@@ -323,6 +495,7 @@ static int am33xx_pm_probe(struct platform_device *pdev)
        suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH;
        suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF;
        suspend_wfi_flags |= WFI_FLAG_WAKE_M3;
+#endif /* CONFIG_SUSPEND */
 
        ret = pm_ops->init();
        if (ret) {
index 354d256e6e006dac32935e7187f0a7245f68568f..600f57cf0c2e5014e14a09001609cb8cfc4eeb85 100644 (file)
@@ -23,6 +23,8 @@
 /* Flag stating if PM nodes mapped to the PM domain has been requested */
 #define ZYNQMP_PM_DOMAIN_REQUESTED     BIT(0)
 
+static const struct zynqmp_eemi_ops *eemi_ops;
+
 /**
  * struct zynqmp_pm_domain - Wrapper around struct generic_pm_domain
  * @gpd:               Generic power domain
@@ -71,9 +73,8 @@ static int zynqmp_gpd_power_on(struct generic_pm_domain *domain)
 {
        int ret;
        struct zynqmp_pm_domain *pd;
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
 
-       if (!eemi_ops || !eemi_ops->set_requirement)
+       if (!eemi_ops->set_requirement)
                return -ENXIO;
 
        pd = container_of(domain, struct zynqmp_pm_domain, gpd);
@@ -107,9 +108,8 @@ static int zynqmp_gpd_power_off(struct generic_pm_domain *domain)
        struct zynqmp_pm_domain *pd;
        u32 capabilities = 0;
        bool may_wakeup;
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
 
-       if (!eemi_ops || !eemi_ops->set_requirement)
+       if (!eemi_ops->set_requirement)
                return -ENXIO;
 
        pd = container_of(domain, struct zynqmp_pm_domain, gpd);
@@ -160,9 +160,8 @@ static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain,
 {
        int ret;
        struct zynqmp_pm_domain *pd;
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
 
-       if (!eemi_ops || !eemi_ops->request_node)
+       if (!eemi_ops->request_node)
                return -ENXIO;
 
        pd = container_of(domain, struct zynqmp_pm_domain, gpd);
@@ -197,9 +196,8 @@ static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain,
 {
        int ret;
        struct zynqmp_pm_domain *pd;
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
 
-       if (!eemi_ops || !eemi_ops->release_node)
+       if (!eemi_ops->release_node)
                return;
 
        pd = container_of(domain, struct zynqmp_pm_domain, gpd);
@@ -266,6 +264,10 @@ static int zynqmp_gpd_probe(struct platform_device *pdev)
        struct zynqmp_pm_domain *pd;
        struct device *dev = &pdev->dev;
 
+       eemi_ops = zynqmp_pm_get_eemi_ops();
+       if (IS_ERR(eemi_ops))
+               return PTR_ERR(eemi_ops);
+
        pd = devm_kcalloc(dev, ZYNQMP_NUM_DOMAINS, sizeof(*pd), GFP_KERNEL);
        if (!pd)
                return -ENOMEM;
index 771cb59b9d22eeb76ac7191c119241037544526d..1b9d14411a1526082e2d640089750126d32af4f3 100644 (file)
@@ -31,6 +31,7 @@ static const char *const suspend_modes[] = {
 };
 
 static enum pm_suspend_mode suspend_mode = PM_SUSPEND_MODE_STD;
+static const struct zynqmp_eemi_ops *eemi_ops;
 
 enum pm_api_cb_id {
        PM_INIT_SUSPEND_CB = 30,
@@ -92,9 +93,8 @@ static ssize_t suspend_mode_store(struct device *dev,
                                  const char *buf, size_t count)
 {
        int md, ret = -EINVAL;
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
 
-       if (!eemi_ops || !eemi_ops->set_suspend_mode)
+       if (!eemi_ops->set_suspend_mode)
                return ret;
 
        for (md = PM_SUSPEND_MODE_FIRST; md < ARRAY_SIZE(suspend_modes); md++)
@@ -120,9 +120,11 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
        int ret, irq;
        u32 pm_api_version;
 
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+       eemi_ops = zynqmp_pm_get_eemi_ops();
+       if (IS_ERR(eemi_ops))
+               return PTR_ERR(eemi_ops);
 
-       if (!eemi_ops || !eemi_ops->get_api_version || !eemi_ops->init_finalize)
+       if (!eemi_ops->get_api_version || !eemi_ops->init_finalize)
                return -ENXIO;
 
        eemi_ops->init_finalize();
index 3912526ead6641067e189a825c9df8ebf8faabfc..cdb613d38062c5608af5f45663d98b30c43dd269 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/clk.h>
 #include <linux/dmaengine.h>
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/pinctrl/consumer.h>
index 9f83e1b17aa16b6aa934d24955e5da7773af10a7..9850a0efe85a34bd0a4565671d0ea66b135ee4da 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
+#include <linux/firmware/xlnx-zynqmp.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
 
 #define SPI_AUTOSUSPEND_TIMEOUT                3000
 enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA};
+static const struct zynqmp_eemi_ops *eemi_ops;
 
 /**
  * struct zynqmp_qspi - Defines qspi driver instance
@@ -1021,6 +1023,10 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
        struct resource *res;
        struct device *dev = &pdev->dev;
 
+       eemi_ops = zynqmp_pm_get_eemi_ops();
+       if (IS_ERR(eemi_ops))
+               return PTR_ERR(eemi_ops);
+
        master = spi_alloc_master(&pdev->dev, sizeof(*xqspi));
        if (!master)
                return -ENOMEM;
index 600928f635777e518737e16688e5ddf25ba274f9..d35c4fb19e280ed78b847ea3c150b1d026eed313 100644 (file)
@@ -486,8 +486,8 @@ static int gasket_perform_mapping(struct gasket_page_table *pg_tbl,
                        ptes[i].dma_addr = pg_tbl->coherent_pages[0].paddr +
                                           off + i * PAGE_SIZE;
                } else {
-                       ret = get_user_pages_fast(page_addr - offset, 1, 1,
-                                                 &page);
+                       ret = get_user_pages_fast(page_addr - offset, 1,
+                                                 FOLL_WRITE, &page);
 
                        if (ret <= 0) {
                                dev_err(pg_tbl->device,
index 1ba4a5154fb5518e145f41ae579f42696067ae2e..64037b0a83877e15d2e6846e5abc662199335396 100644 (file)
@@ -1266,7 +1266,7 @@ static int prp_registered(struct v4l2_subdev *sd)
        if (ret)
                return ret;
 
-       ret = imx_media_capture_device_register(priv->vdev);
+       ret = imx_media_capture_device_register(priv->md, priv->vdev);
        if (ret)
                return ret;
 
index b7ce9d4392791ab3bea39a020644b6122bd11f41..9430c835c4349ddfe68ec5937ea250d6e2d6f121 100644 (file)
@@ -701,7 +701,8 @@ void imx_media_capture_device_error(struct imx_media_video_dev *vdev)
 }
 EXPORT_SYMBOL_GPL(imx_media_capture_device_error);
 
-int imx_media_capture_device_register(struct imx_media_video_dev *vdev)
+int imx_media_capture_device_register(struct imx_media_dev *md,
+                                     struct imx_media_video_dev *vdev)
 {
        struct capture_priv *priv = to_capture_priv(vdev);
        struct v4l2_subdev *sd = priv->src_sd;
@@ -710,8 +711,7 @@ int imx_media_capture_device_register(struct imx_media_video_dev *vdev)
        struct v4l2_subdev_format fmt_src;
        int ret;
 
-       /* get media device */
-       priv->md = dev_get_drvdata(sd->v4l2_dev->dev);
+       priv->md = md;
 
        vfd->v4l2_dev = sd->v4l2_dev;
 
index 28fe66052cc7486622d79ac91e5f859aa3fb0932..1d248aca40a9ec3795fcf27c70fb1fa81ce9a164 100644 (file)
@@ -1812,7 +1812,7 @@ static int csi_registered(struct v4l2_subdev *sd)
        if (ret)
                goto free_fim;
 
-       ret = imx_media_capture_device_register(priv->vdev);
+       ret = imx_media_capture_device_register(priv->md, priv->vdev);
        if (ret)
                goto free_fim;
 
index eb59ba0c3b62bfbc270142513ceb27cccd275adf..6587aa49e0051859b79076c515f9701a1876870d 100644 (file)
@@ -268,7 +268,8 @@ int imx_media_of_add_csi(struct imx_media_dev *imxmd,
 struct imx_media_video_dev *
 imx_media_capture_device_init(struct v4l2_subdev *src_sd, int pad);
 void imx_media_capture_device_remove(struct imx_media_video_dev *vdev);
-int imx_media_capture_device_register(struct imx_media_video_dev *vdev);
+int imx_media_capture_device_register(struct imx_media_dev *md,
+                                     struct imx_media_video_dev *vdev);
 void imx_media_capture_device_unregister(struct imx_media_video_dev *vdev);
 struct imx_media_buffer *
 imx_media_capture_device_next_buf(struct imx_media_video_dev *vdev);
index 18eb5d3ecf102ad5bca3f84379f1c290d2929a92..a708a0340eb18a0a0d5931870b946e13ba78181a 100644 (file)
@@ -1126,7 +1126,7 @@ static int imx7_csi_registered(struct v4l2_subdev *sd)
        if (ret < 0)
                return ret;
 
-       ret = imx_media_capture_device_register(csi->vdev);
+       ret = imx_media_capture_device_register(csi->imxmd, csi->vdev);
        if (ret < 0)
                return ret;
 
index 58721c46fba4184ea03ce95da4c574704b984f68..8bbc905b26c83d7b41c8159ad898f46bfeaa6b76 100644 (file)
@@ -352,7 +352,7 @@ static int rockchip_vpu_video_device_register(struct rockchip_vpu_dev *vpu)
        vpu->vfd_enc = vfd;
        video_set_drvdata(vfd, vpu);
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
        if (ret) {
                v4l2_err(&vpu->v4l2_dev, "Failed to register video device\n");
                goto err_free_dev;
@@ -463,6 +463,8 @@ static int rockchip_vpu_probe(struct platform_device *pdev)
 
        vpu->mdev.dev = vpu->dev;
        strscpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model));
+       strscpy(vpu->mdev.bus_info, "platform: " DRIVER_NAME,
+               sizeof(vpu->mdev.model));
        media_device_init(&vpu->mdev);
        vpu->v4l2_dev.mdev = &vpu->mdev;
 
@@ -480,15 +482,18 @@ static int rockchip_vpu_probe(struct platform_device *pdev)
        return 0;
 err_video_dev_unreg:
        if (vpu->vfd_enc) {
+               v4l2_m2m_unregister_media_controller(vpu->m2m_dev);
                video_unregister_device(vpu->vfd_enc);
                video_device_release(vpu->vfd_enc);
        }
 err_m2m_rel:
+       media_device_cleanup(&vpu->mdev);
        v4l2_m2m_release(vpu->m2m_dev);
 err_v4l2_unreg:
        v4l2_device_unregister(&vpu->v4l2_dev);
 err_clk_unprepare:
        clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks);
+       pm_runtime_dont_use_autosuspend(vpu->dev);
        pm_runtime_disable(vpu->dev);
        return ret;
 }
@@ -500,15 +505,16 @@ static int rockchip_vpu_remove(struct platform_device *pdev)
        v4l2_info(&vpu->v4l2_dev, "Removing %s\n", pdev->name);
 
        media_device_unregister(&vpu->mdev);
-       v4l2_m2m_unregister_media_controller(vpu->m2m_dev);
-       v4l2_m2m_release(vpu->m2m_dev);
-       media_device_cleanup(&vpu->mdev);
        if (vpu->vfd_enc) {
+               v4l2_m2m_unregister_media_controller(vpu->m2m_dev);
                video_unregister_device(vpu->vfd_enc);
                video_device_release(vpu->vfd_enc);
        }
+       media_device_cleanup(&vpu->mdev);
+       v4l2_m2m_release(vpu->m2m_dev);
        v4l2_device_unregister(&vpu->v4l2_dev);
        clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks);
+       pm_runtime_dont_use_autosuspend(vpu->dev);
        pm_runtime_disable(vpu->dev);
        return 0;
 }
index fb5e36aedd8c5e58feda0b675eba83e038e309b3..dcbfc3cbc9f31539b26f0f10ad577fca3224c0be 100644 (file)
@@ -152,9 +152,10 @@ static int vidioc_querycap(struct file *file, void *priv,
                           struct v4l2_capability *cap)
 {
        struct rockchip_vpu_dev *vpu = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
 
        strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver));
-       strscpy(cap->card, vpu->vfd_enc->name, sizeof(cap->card));
+       strscpy(cap->card, vdev->name, sizeof(cap->card));
        snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s",
                 vpu->dev->driver->name);
        return 0;
index 255e266c40e1d8cef1d75aa85301a9ac76bf17af..f5c716bb3413160713c34e30a9c32404132b05b5 100644 (file)
@@ -3,7 +3,6 @@ config FB_OLPC_DCON
        tristate "One Laptop Per Child Display CONtroller support"
        depends on OLPC && FB
        depends on I2C
-       depends on BACKLIGHT_LCD_SUPPORT
        depends on (GPIO_CS5535 || GPIO_CS5535=n)
        select BACKLIGHT_CLASS_DEVICE
        help
index 0842b6e6af822c5a3230c95084169e1346517ff9..48963eab32f5e02c171a09abd4e0966b4299859c 100644 (file)
@@ -419,9 +419,35 @@ static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn,
        return true;
 }
 
+static struct tee_shm_pool *optee_config_dyn_shm(void)
+{
+       struct tee_shm_pool_mgr *priv_mgr;
+       struct tee_shm_pool_mgr *dmabuf_mgr;
+       void *rc;
+
+       rc = optee_shm_pool_alloc_pages();
+       if (IS_ERR(rc))
+               return rc;
+       priv_mgr = rc;
+
+       rc = optee_shm_pool_alloc_pages();
+       if (IS_ERR(rc)) {
+               tee_shm_pool_mgr_destroy(priv_mgr);
+               return rc;
+       }
+       dmabuf_mgr = rc;
+
+       rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
+       if (IS_ERR(rc)) {
+               tee_shm_pool_mgr_destroy(priv_mgr);
+               tee_shm_pool_mgr_destroy(dmabuf_mgr);
+       }
+
+       return rc;
+}
+
 static struct tee_shm_pool *
-optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm,
-                         u32 sec_caps)
+optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm)
 {
        union {
                struct arm_smccc_res smccc;
@@ -436,10 +462,11 @@ optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm,
        struct tee_shm_pool_mgr *priv_mgr;
        struct tee_shm_pool_mgr *dmabuf_mgr;
        void *rc;
+       const int sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
 
        invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
        if (res.result.status != OPTEE_SMC_RETURN_OK) {
-               pr_info("shm service not available\n");
+               pr_err("static shm service not available\n");
                return ERR_PTR(-ENOENT);
        }
 
@@ -465,28 +492,15 @@ optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm,
        }
        vaddr = (unsigned long)va;
 
-       /*
-        * If OP-TEE can work with unregistered SHM, we will use own pool
-        * for private shm
-        */
-       if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) {
-               rc = optee_shm_pool_alloc_pages();
-               if (IS_ERR(rc))
-                       goto err_memunmap;
-               priv_mgr = rc;
-       } else {
-               const size_t sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
-
-               rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz,
-                                                   3 /* 8 bytes aligned */);
-               if (IS_ERR(rc))
-                       goto err_memunmap;
-               priv_mgr = rc;
-
-               vaddr += sz;
-               paddr += sz;
-               size -= sz;
-       }
+       rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz,
+                                           3 /* 8 bytes aligned */);
+       if (IS_ERR(rc))
+               goto err_memunmap;
+       priv_mgr = rc;
+
+       vaddr += sz;
+       paddr += sz;
+       size -= sz;
 
        rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, size, PAGE_SHIFT);
        if (IS_ERR(rc))
@@ -552,7 +566,7 @@ static optee_invoke_fn *get_invoke_func(struct device_node *np)
 static struct optee *optee_probe(struct device_node *np)
 {
        optee_invoke_fn *invoke_fn;
-       struct tee_shm_pool *pool;
+       struct tee_shm_pool *pool = ERR_PTR(-EINVAL);
        struct optee *optee = NULL;
        void *memremaped_shm = NULL;
        struct tee_device *teedev;
@@ -581,13 +595,17 @@ static struct optee *optee_probe(struct device_node *np)
        }
 
        /*
-        * We have no other option for shared memory, if secure world
-        * doesn't have any reserved memory we can use we can't continue.
+        * Try to use dynamic shared memory if possible
         */
-       if (!(sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM))
-               return ERR_PTR(-EINVAL);
+       if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
+               pool = optee_config_dyn_shm();
+
+       /*
+        * If dynamic shared memory is not available or failed - try static one
+        */
+       if (IS_ERR(pool) && (sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM))
+               pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm);
 
-       pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm, sec_caps);
        if (IS_ERR(pool))
                return (void *)pool;
 
index 0b9ab1d0dd45dd69046f921e6bf846e7af23fe88..49fd7312e2aab0892408deb07e1c44ee6a8ad45f 100644 (file)
@@ -273,7 +273,7 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
                goto err;
        }
 
-       rc = get_user_pages_fast(start, num_pages, 1, shm->pages);
+       rc = get_user_pages_fast(start, num_pages, FOLL_WRITE, shm->pages);
        if (rc > 0)
                shm->num_pages = rc;
        if (rc != num_pages) {
index 653aa27a25a49d8b0e7f1265209579e6c25da653..15bdd25780beecc67eac993a31308c0257571c79 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 menuconfig THERMAL
-       tristate "Generic Thermal sysfs driver"
+       bool "Generic Thermal sysfs driver"
        help
          Generic Thermal Sysfs driver offers a generic mechanism for
          thermal management. Usually it's made up of one or more thermal
@@ -11,7 +11,7 @@ menuconfig THERMAL
          Each thermal zone contains its own temperature, trip points,
          cooling devices.
          All platforms with ACPI thermal support can use this driver.
-         If you want this support, you should say Y or M here.
+         If you want this support, you should say Y here.
 
 if THERMAL
 
@@ -24,7 +24,6 @@ config THERMAL_STATISTICS
 
 config THERMAL_EMERGENCY_POWEROFF_DELAY_MS
        int "Emergency poweroff delay in milli-seconds"
-       depends on THERMAL
        default 0
        help
          Thermal subsystem will issue a graceful shutdown when
@@ -149,10 +148,9 @@ config THERMAL_GOV_POWER_ALLOCATOR
          allocating and limiting power to devices.
 
 config CPU_THERMAL
-       bool "generic cpu cooling support"
+       bool "Generic cpu cooling support"
        depends on CPU_FREQ
        depends on THERMAL_OF
-       depends on THERMAL=y
        help
          This implements the generic cpu cooling mechanism through frequency
          reduction. An ACPI version of this already exists
@@ -200,6 +198,17 @@ config THERMAL_EMULATION
          because userland can easily disable the thermal policy by simply
          flooding this sysfs node with low temperature values.
 
+config THERMAL_MMIO
+       tristate "Generic Thermal MMIO driver"
+       depends on OF || COMPILE_TEST
+       depends on HAS_IOMEM
+       help
+         This option enables the generic thermal MMIO driver that will use
+         memory-mapped reads to get the temperature.  Any HW/System that
+         allows temperature reading by a single memory-mapped reading, be it
+         register or shared memory, is a potential candidate to work with this
+         driver.
+
 config HISI_THERMAL
        tristate "Hisilicon thermal driver"
        depends on ARCH_HISI || COMPILE_TEST
index 486d682be0477e3052600c958de837302f243421..74a37c7f847a6f50e84de4605944c0fa16e2aebf 100644 (file)
@@ -29,6 +29,7 @@ thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
 
 # platform thermal drivers
 obj-y                          += broadcom/
+obj-$(CONFIG_THERMAL_MMIO)             += thermal_mmio.o
 obj-$(CONFIG_SPEAR_THERMAL)    += spear_thermal.o
 obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o
 obj-$(CONFIG_RCAR_THERMAL)     += rcar_thermal.o
index 2284cbecedf38595791bc5669a4d5d2faf4c2f13..475ce2900771337f5398b21f406a3c9877324222 100644 (file)
@@ -3,7 +3,6 @@
  * Copyright (C) 2018 Broadcom
  */
 
-#include <linux/acpi.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
@@ -100,18 +99,11 @@ static const struct of_device_id sr_thermal_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, sr_thermal_of_match);
 
-static const struct acpi_device_id sr_thermal_acpi_ids[] = {
-       { .id = "BRCM0500" },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(acpi, sr_thermal_acpi_ids);
-
 static struct platform_driver sr_thermal_driver = {
        .probe          = sr_thermal_probe,
        .driver = {
                .name = "sr-thermal",
                .of_match_table = sr_thermal_of_match,
-               .acpi_match_table = ACPI_PTR(sr_thermal_acpi_ids),
        },
 };
 module_platform_driver(sr_thermal_driver);
index f7c1f49ec87f2a397d882ca595421e26d71df2b3..4c5db59a619b07c23aafeb50e0f5fad6aff98517 100644 (file)
@@ -1,26 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  *  linux/drivers/thermal/cpu_cooling.c
  *
  *  Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com)
- *  Copyright (C) 2012  Amit Daniel <amit.kachhap@linaro.org>
  *
- *  Copyright (C) 2014  Viresh Kumar <viresh.kumar@linaro.org>
+ *  Copyright (C) 2012-2018 Linaro Limited.
  *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *  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 of the License.
+ *  Authors:   Amit Daniel <amit.kachhap@linaro.org>
+ *             Viresh Kumar <viresh.kumar@linaro.org>
  *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 #include <linux/module.h>
 #include <linux/thermal.h>
@@ -99,7 +87,6 @@ struct cpufreq_cooling_device {
        unsigned int clipped_freq;
        unsigned int max_level;
        struct freq_table *freq_table;  /* In descending order */
-       struct thermal_cooling_device *cdev;
        struct cpufreq_policy *policy;
        struct list_head node;
        struct time_in_idle *idle_time;
@@ -207,8 +194,7 @@ static int update_freq_table(struct cpufreq_cooling_device *cpufreq_cdev,
 
        dev = get_cpu_device(cpu);
        if (unlikely(!dev)) {
-               dev_warn(&cpufreq_cdev->cdev->device,
-                        "No cpu device for cpu %d\n", cpu);
+               pr_warn("No cpu device for cpu %d\n", cpu);
                return -ENODEV;
        }
 
@@ -458,7 +444,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
                        load = 0;
 
                total_load += load;
-               if (trace_thermal_power_cpu_limit_enabled() && load_cpu)
+               if (load_cpu)
                        load_cpu[i] = load;
 
                i++;
@@ -541,7 +527,6 @@ static int cpufreq_power2state(struct thermal_cooling_device *cdev,
        struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
        struct cpufreq_policy *policy = cpufreq_cdev->policy;
 
-       power = power > 0 ? power : 0;
        last_load = cpufreq_cdev->last_load ?: 1;
        normalised_power = (power * 100) / last_load;
        target_freq = cpu_power_to_freq(cpufreq_cdev, normalised_power);
@@ -692,7 +677,6 @@ __cpufreq_cooling_register(struct device_node *np,
                goto remove_ida;
 
        cpufreq_cdev->clipped_freq = cpufreq_cdev->freq_table[0].frequency;
-       cpufreq_cdev->cdev = cdev;
 
        mutex_lock(&cooling_list_lock);
        /* Register the notifier for first cpufreq cooling device */
@@ -810,7 +794,7 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
                cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
                                            CPUFREQ_POLICY_NOTIFIER);
 
-       thermal_cooling_device_unregister(cpufreq_cdev->cdev);
+       thermal_cooling_device_unregister(cdev);
        ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
        kfree(cpufreq_cdev->idle_time);
        kfree(cpufreq_cdev->freq_table);
index 2e013eeb4a1d9f79d65512bca49e4042e959f0fe..2c727a820759cc8ac78e84a4f41e8d559aefb6ce 100644 (file)
@@ -1,6 +1,5 @@
 config INTEL_POWERCLAMP
        tristate "Intel PowerClamp idle injection driver"
-       depends on THERMAL
        depends on X86
        depends on CPU_SUP_INTEL
        help
index 0c19fcd56a0da02713e93778afc78c84017aeeef..79a7df2baa92450ee17b843789fdf648149f5c8a 100644 (file)
@@ -220,6 +220,7 @@ static int int3403_add(struct platform_device *pdev)
 {
        struct int3403_priv *priv;
        int result = 0;
+       unsigned long long tmp;
        acpi_status status;
 
        priv = devm_kzalloc(&pdev->dev, sizeof(struct int3403_priv),
@@ -234,19 +235,18 @@ static int int3403_add(struct platform_device *pdev)
                goto err;
        }
 
-       status = acpi_evaluate_integer(priv->adev->handle, "PTYP",
-                                      NULL, &priv->type);
-       if (ACPI_FAILURE(status)) {
-               unsigned long long tmp;
 
-               status = acpi_evaluate_integer(priv->adev->handle, "_TMP",
-                                              NULL, &tmp);
+       status = acpi_evaluate_integer(priv->adev->handle, "_TMP",
+                                      NULL, &tmp);
+       if (ACPI_FAILURE(status)) {
+               status = acpi_evaluate_integer(priv->adev->handle, "PTYP",
+                                      NULL, &priv->type);
                if (ACPI_FAILURE(status)) {
                        result = -EINVAL;
                        goto err;
-               } else {
-                       priv->type = INT3403_TYPE_SENSOR;
                }
+       } else {
+               priv->type = INT3403_TYPE_SENSOR;
        }
 
        platform_set_drvdata(pdev, priv);
index 8e1cf4d789be10df2413e1311bba63dde3545f43..2e6071a82da2748071971dd37e65a42ce48e54dd 100644 (file)
@@ -81,22 +81,13 @@ static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \
                                        struct device_attribute *attr, \
                                        char *buf) \
 { \
-       struct pci_dev *pci_dev; \
-       struct platform_device *pdev; \
-       struct proc_thermal_device *proc_dev; \
+       struct proc_thermal_device *proc_dev = dev_get_drvdata(dev); \
        \
        if (proc_thermal_emum_mode == PROC_THERMAL_NONE) { \
                dev_warn(dev, "Attempted to get power limit before device was initialized!\n"); \
                return 0; \
        } \
        \
-       if (proc_thermal_emum_mode == PROC_THERMAL_PLATFORM_DEV) { \
-               pdev = to_platform_device(dev); \
-               proc_dev = platform_get_drvdata(pdev); \
-       } else { \
-               pci_dev = to_pci_dev(dev); \
-               proc_dev = pci_get_drvdata(pci_dev); \
-       } \
        return sprintf(buf, "%lu\n",\
        (unsigned long)proc_dev->power_limits[index].suffix * 1000); \
 }
@@ -274,7 +265,7 @@ static void proc_thermal_notify(acpi_handle handle, u32 event, void *data)
                                THERMAL_DEVICE_POWER_CAPABILITY_CHANGED);
                break;
        default:
-               dev_err(proc_priv->dev, "Unsupported event [0x%x]\n", event);
+               dev_dbg(proc_priv->dev, "Unsupported event [0x%x]\n", event);
                break;
        }
 }
index 2df059cc07e2fb76fbe2b23aa436f3878e84125a..dc5093be553ec19019162e2571adfbe8c691ddc7 100644 (file)
@@ -5,6 +5,9 @@
  *  Copyright (C) 2013 Texas Instruments
  *  Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com>
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/thermal.h>
 #include <linux/slab.h>
 #include <linux/types.h>
index cdb455ffd5752ef1e7c9094ebf5205ee97bf4403..3ce20fec86a2bd583922fc68a07fc716d8d4755e 100644 (file)
@@ -1,6 +1,5 @@
 config QCOM_TSENS
        tristate "Qualcomm TSENS Temperature Alarm"
-       depends on THERMAL
        depends on QCOM_QFPROM
        depends on ARCH_QCOM || COMPILE_TEST
        help
index 717a08600bb5662c983bb9cc5761c3ad148b82c0..fc6fe50cdde4c1a17259558402b73c80504f54e9 100644 (file)
@@ -1,3 +1,5 @@
 obj-$(CONFIG_QCOM_TSENS)       += qcom_tsens.o
-qcom_tsens-y                   += tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o tsens-v2.o
+
+qcom_tsens-y                   += tsens.o tsens-common.o tsens-v0_1.o \
+                                  tsens-8960.o tsens-v2.o tsens-v1.o
 obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM)     += qcom-spmi-temp-alarm.o
diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c
deleted file mode 100644 (file)
index c6dd620..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
- */
-
-#include <linux/platform_device.h>
-#include "tsens.h"
-
-/* eeprom layout data for 8916 */
-#define BASE0_MASK     0x0000007f
-#define BASE1_MASK     0xfe000000
-#define BASE0_SHIFT    0
-#define BASE1_SHIFT    25
-
-#define S0_P1_MASK     0x00000f80
-#define S1_P1_MASK     0x003e0000
-#define S2_P1_MASK     0xf8000000
-#define S3_P1_MASK     0x000003e0
-#define S4_P1_MASK     0x000f8000
-
-#define S0_P2_MASK     0x0001f000
-#define S1_P2_MASK     0x07c00000
-#define S2_P2_MASK     0x0000001f
-#define S3_P2_MASK     0x00007c00
-#define S4_P2_MASK     0x01f00000
-
-#define S0_P1_SHIFT    7
-#define S1_P1_SHIFT    17
-#define S2_P1_SHIFT    27
-#define S3_P1_SHIFT    5
-#define S4_P1_SHIFT    15
-
-#define S0_P2_SHIFT    12
-#define S1_P2_SHIFT    22
-#define S2_P2_SHIFT    0
-#define S3_P2_SHIFT    10
-#define S4_P2_SHIFT    20
-
-#define CAL_SEL_MASK   0xe0000000
-#define CAL_SEL_SHIFT  29
-
-static int calibrate_8916(struct tsens_device *tmdev)
-{
-       int base0 = 0, base1 = 0, i;
-       u32 p1[5], p2[5];
-       int mode = 0;
-       u32 *qfprom_cdata, *qfprom_csel;
-
-       qfprom_cdata = (u32 *)qfprom_read(tmdev->dev, "calib");
-       if (IS_ERR(qfprom_cdata))
-               return PTR_ERR(qfprom_cdata);
-
-       qfprom_csel = (u32 *)qfprom_read(tmdev->dev, "calib_sel");
-       if (IS_ERR(qfprom_csel))
-               return PTR_ERR(qfprom_csel);
-
-       mode = (qfprom_csel[0] & CAL_SEL_MASK) >> CAL_SEL_SHIFT;
-       dev_dbg(tmdev->dev, "calibration mode is %d\n", mode);
-
-       switch (mode) {
-       case TWO_PT_CALIB:
-               base1 = (qfprom_cdata[1] & BASE1_MASK) >> BASE1_SHIFT;
-               p2[0] = (qfprom_cdata[0] & S0_P2_MASK) >> S0_P2_SHIFT;
-               p2[1] = (qfprom_cdata[0] & S1_P2_MASK) >> S1_P2_SHIFT;
-               p2[2] = (qfprom_cdata[1] & S2_P2_MASK) >> S2_P2_SHIFT;
-               p2[3] = (qfprom_cdata[1] & S3_P2_MASK) >> S3_P2_SHIFT;
-               p2[4] = (qfprom_cdata[1] & S4_P2_MASK) >> S4_P2_SHIFT;
-               for (i = 0; i < tmdev->num_sensors; i++)
-                       p2[i] = ((base1 + p2[i]) << 3);
-               /* Fall through */
-       case ONE_PT_CALIB2:
-               base0 = (qfprom_cdata[0] & BASE0_MASK);
-               p1[0] = (qfprom_cdata[0] & S0_P1_MASK) >> S0_P1_SHIFT;
-               p1[1] = (qfprom_cdata[0] & S1_P1_MASK) >> S1_P1_SHIFT;
-               p1[2] = (qfprom_cdata[0] & S2_P1_MASK) >> S2_P1_SHIFT;
-               p1[3] = (qfprom_cdata[1] & S3_P1_MASK) >> S3_P1_SHIFT;
-               p1[4] = (qfprom_cdata[1] & S4_P1_MASK) >> S4_P1_SHIFT;
-               for (i = 0; i < tmdev->num_sensors; i++)
-                       p1[i] = (((base0) + p1[i]) << 3);
-               break;
-       default:
-               for (i = 0; i < tmdev->num_sensors; i++) {
-                       p1[i] = 500;
-                       p2[i] = 780;
-               }
-               break;
-       }
-
-       compute_intercept_slope(tmdev, p1, p2, mode);
-
-       return 0;
-}
-
-static const struct tsens_ops ops_8916 = {
-       .init           = init_common,
-       .calibrate      = calibrate_8916,
-       .get_temp       = get_temp_common,
-};
-
-const struct tsens_data data_8916 = {
-       .num_sensors    = 5,
-       .ops            = &ops_8916,
-       .reg_offsets    = { [SROT_CTRL_OFFSET] = 0x0 },
-       .hw_ids         = (unsigned int []){0, 1, 2, 4, 5 },
-};
index 0f0adb302a7bce8149dd973f1830c13c264a39f2..8d9b721dadb6522122891f7fbff59ea8922fe488 100644 (file)
 #define TRDY_MASK              BIT(7)
 #define TIMEOUT_US             100
 
-static int suspend_8960(struct tsens_device *tmdev)
+static int suspend_8960(struct tsens_priv *priv)
 {
        int ret;
        unsigned int mask;
-       struct regmap *map = tmdev->tm_map;
+       struct regmap *map = priv->tm_map;
 
-       ret = regmap_read(map, THRESHOLD_ADDR, &tmdev->ctx.threshold);
+       ret = regmap_read(map, THRESHOLD_ADDR, &priv->ctx.threshold);
        if (ret)
                return ret;
 
-       ret = regmap_read(map, CNTL_ADDR, &tmdev->ctx.control);
+       ret = regmap_read(map, CNTL_ADDR, &priv->ctx.control);
        if (ret)
                return ret;
 
-       if (tmdev->num_sensors > 1)
+       if (priv->num_sensors > 1)
                mask = SLP_CLK_ENA | EN;
        else
                mask = SLP_CLK_ENA_8660 | EN;
@@ -82,10 +82,10 @@ static int suspend_8960(struct tsens_device *tmdev)
        return 0;
 }
 
-static int resume_8960(struct tsens_device *tmdev)
+static int resume_8960(struct tsens_priv *priv)
 {
        int ret;
-       struct regmap *map = tmdev->tm_map;
+       struct regmap *map = priv->tm_map;
 
        ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST);
        if (ret)
@@ -95,80 +95,80 @@ static int resume_8960(struct tsens_device *tmdev)
         * Separate CONFIG restore is not needed only for 8660 as
         * config is part of CTRL Addr and its restored as such
         */
-       if (tmdev->num_sensors > 1) {
+       if (priv->num_sensors > 1) {
                ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG);
                if (ret)
                        return ret;
        }
 
-       ret = regmap_write(map, THRESHOLD_ADDR, tmdev->ctx.threshold);
+       ret = regmap_write(map, THRESHOLD_ADDR, priv->ctx.threshold);
        if (ret)
                return ret;
 
-       ret = regmap_write(map, CNTL_ADDR, tmdev->ctx.control);
+       ret = regmap_write(map, CNTL_ADDR, priv->ctx.control);
        if (ret)
                return ret;
 
        return 0;
 }
 
-static int enable_8960(struct tsens_device *tmdev, int id)
+static int enable_8960(struct tsens_priv *priv, int id)
 {
        int ret;
        u32 reg, mask;
 
-       ret = regmap_read(tmdev->tm_map, CNTL_ADDR, &reg);
+       ret = regmap_read(priv->tm_map, CNTL_ADDR, &reg);
        if (ret)
                return ret;
 
        mask = BIT(id + SENSOR0_SHIFT);
-       ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg | SW_RST);
+       ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
        if (ret)
                return ret;
 
-       if (tmdev->num_sensors > 1)
+       if (priv->num_sensors > 1)
                reg |= mask | SLP_CLK_ENA | EN;
        else
                reg |= mask | SLP_CLK_ENA_8660 | EN;
 
-       ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg);
+       ret = regmap_write(priv->tm_map, CNTL_ADDR, reg);
        if (ret)
                return ret;
 
        return 0;
 }
 
-static void disable_8960(struct tsens_device *tmdev)
+static void disable_8960(struct tsens_priv *priv)
 {
        int ret;
        u32 reg_cntl;
        u32 mask;
 
-       mask = GENMASK(tmdev->num_sensors - 1, 0);
+       mask = GENMASK(priv->num_sensors - 1, 0);
        mask <<= SENSOR0_SHIFT;
        mask |= EN;
 
-       ret = regmap_read(tmdev->tm_map, CNTL_ADDR, &reg_cntl);
+       ret = regmap_read(priv->tm_map, CNTL_ADDR, &reg_cntl);
        if (ret)
                return;
 
        reg_cntl &= ~mask;
 
-       if (tmdev->num_sensors > 1)
+       if (priv->num_sensors > 1)
                reg_cntl &= ~SLP_CLK_ENA;
        else
                reg_cntl &= ~SLP_CLK_ENA_8660;
 
-       regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl);
+       regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
 }
 
-static int init_8960(struct tsens_device *tmdev)
+static int init_8960(struct tsens_priv *priv)
 {
        int ret, i;
        u32 reg_cntl;
 
-       tmdev->tm_map = dev_get_regmap(tmdev->dev, NULL);
-       if (!tmdev->tm_map)
+       priv->tm_map = dev_get_regmap(priv->dev, NULL);
+       if (!priv->tm_map)
                return -ENODEV;
 
        /*
@@ -177,21 +177,21 @@ static int init_8960(struct tsens_device *tmdev)
         * but the control registers stay in the same place, i.e
         * directly after the first 5 status registers.
         */
-       for (i = 0; i < tmdev->num_sensors; i++) {
+       for (i = 0; i < priv->num_sensors; i++) {
                if (i >= 5)
-                       tmdev->sensor[i].status = S0_STATUS_ADDR + 40;
-               tmdev->sensor[i].status += i * 4;
+                       priv->sensor[i].status = S0_STATUS_ADDR + 40;
+               priv->sensor[i].status += i * 4;
        }
 
        reg_cntl = SW_RST;
-       ret = regmap_update_bits(tmdev->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
+       ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
        if (ret)
                return ret;
 
-       if (tmdev->num_sensors > 1) {
+       if (priv->num_sensors > 1) {
                reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
                reg_cntl &= ~SW_RST;
-               ret = regmap_update_bits(tmdev->tm_map, CONFIG_ADDR,
+               ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
                                         CONFIG_MASK, CONFIG);
        } else {
                reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
@@ -199,30 +199,30 @@ static int init_8960(struct tsens_device *tmdev)
                reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
        }
 
-       reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << SENSOR0_SHIFT;
-       ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl);
+       reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
+       ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
        if (ret)
                return ret;
 
        reg_cntl |= EN;
-       ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl);
+       ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
        if (ret)
                return ret;
 
        return 0;
 }
 
-static int calibrate_8960(struct tsens_device *tmdev)
+static int calibrate_8960(struct tsens_priv *priv)
 {
        int i;
        char *data;
 
-       ssize_t num_read = tmdev->num_sensors;
-       struct tsens_sensor *s = tmdev->sensor;
+       ssize_t num_read = priv->num_sensors;
+       struct tsens_sensor *s = priv->sensor;
 
-       data = qfprom_read(tmdev->dev, "calib");
+       data = qfprom_read(priv->dev, "calib");
        if (IS_ERR(data))
-               data = qfprom_read(tmdev->dev, "calib_backup");
+               data = qfprom_read(priv->dev, "calib_backup");
        if (IS_ERR(data))
                return PTR_ERR(data);
 
@@ -243,21 +243,21 @@ static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
        return adc_code * slope + offset;
 }
 
-static int get_temp_8960(struct tsens_device *tmdev, int id, int *temp)
+static int get_temp_8960(struct tsens_priv *priv, int id, int *temp)
 {
        int ret;
        u32 code, trdy;
-       const struct tsens_sensor *s = &tmdev->sensor[id];
+       const struct tsens_sensor *s = &priv->sensor[id];
        unsigned long timeout;
 
        timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
        do {
-               ret = regmap_read(tmdev->tm_map, INT_STATUS_ADDR, &trdy);
+               ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy);
                if (ret)
                        return ret;
                if (!(trdy & TRDY_MASK))
                        continue;
-               ret = regmap_read(tmdev->tm_map, s->status, &code);
+               ret = regmap_read(priv->tm_map, s->status, &code);
                if (ret)
                        return ret;
                *temp = code_to_mdegC(code, s);
@@ -277,7 +277,7 @@ static const struct tsens_ops ops_8960 = {
        .resume         = resume_8960,
 };
 
-const struct tsens_data data_8960 = {
+const struct tsens_plat_data data_8960 = {
        .num_sensors    = 11,
        .ops            = &ops_8960,
 };
diff --git a/drivers/thermal/qcom/tsens-8974.c b/drivers/thermal/qcom/tsens-8974.c
deleted file mode 100644 (file)
index 3d3fda3..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
- */
-
-#include <linux/platform_device.h>
-#include "tsens.h"
-
-/* eeprom layout data for 8974 */
-#define BASE1_MASK             0xff
-#define S0_P1_MASK             0x3f00
-#define S1_P1_MASK             0xfc000
-#define S2_P1_MASK             0x3f00000
-#define S3_P1_MASK             0xfc000000
-#define S4_P1_MASK             0x3f
-#define S5_P1_MASK             0xfc0
-#define S6_P1_MASK             0x3f000
-#define S7_P1_MASK             0xfc0000
-#define S8_P1_MASK             0x3f000000
-#define S8_P1_MASK_BKP         0x3f
-#define S9_P1_MASK             0x3f
-#define S9_P1_MASK_BKP         0xfc0
-#define S10_P1_MASK            0xfc0
-#define S10_P1_MASK_BKP                0x3f000
-#define CAL_SEL_0_1            0xc0000000
-#define CAL_SEL_2              0x40000000
-#define CAL_SEL_SHIFT          30
-#define CAL_SEL_SHIFT_2                28
-
-#define S0_P1_SHIFT            8
-#define S1_P1_SHIFT            14
-#define S2_P1_SHIFT            20
-#define S3_P1_SHIFT            26
-#define S5_P1_SHIFT            6
-#define S6_P1_SHIFT            12
-#define S7_P1_SHIFT            18
-#define S8_P1_SHIFT            24
-#define S9_P1_BKP_SHIFT                6
-#define S10_P1_SHIFT           6
-#define S10_P1_BKP_SHIFT       12
-
-#define BASE2_SHIFT            12
-#define BASE2_BKP_SHIFT                18
-#define S0_P2_SHIFT            20
-#define S0_P2_BKP_SHIFT                26
-#define S1_P2_SHIFT            26
-#define S2_P2_BKP_SHIFT                6
-#define S3_P2_SHIFT            6
-#define S3_P2_BKP_SHIFT                12
-#define S4_P2_SHIFT            12
-#define S4_P2_BKP_SHIFT                18
-#define S5_P2_SHIFT            18
-#define S5_P2_BKP_SHIFT                24
-#define S6_P2_SHIFT            24
-#define S7_P2_BKP_SHIFT                6
-#define S8_P2_SHIFT            6
-#define S8_P2_BKP_SHIFT                12
-#define S9_P2_SHIFT            12
-#define S9_P2_BKP_SHIFT                18
-#define S10_P2_SHIFT           18
-#define S10_P2_BKP_SHIFT       24
-
-#define BASE2_MASK             0xff000
-#define BASE2_BKP_MASK         0xfc0000
-#define S0_P2_MASK             0x3f00000
-#define S0_P2_BKP_MASK         0xfc000000
-#define S1_P2_MASK             0xfc000000
-#define S1_P2_BKP_MASK         0x3f
-#define S2_P2_MASK             0x3f
-#define S2_P2_BKP_MASK         0xfc0
-#define S3_P2_MASK             0xfc0
-#define S3_P2_BKP_MASK         0x3f000
-#define S4_P2_MASK             0x3f000
-#define S4_P2_BKP_MASK         0xfc0000
-#define S5_P2_MASK             0xfc0000
-#define S5_P2_BKP_MASK         0x3f000000
-#define S6_P2_MASK             0x3f000000
-#define S6_P2_BKP_MASK         0x3f
-#define S7_P2_MASK             0x3f
-#define S7_P2_BKP_MASK         0xfc0
-#define S8_P2_MASK             0xfc0
-#define S8_P2_BKP_MASK         0x3f000
-#define S9_P2_MASK             0x3f000
-#define S9_P2_BKP_MASK         0xfc0000
-#define S10_P2_MASK            0xfc0000
-#define S10_P2_BKP_MASK                0x3f000000
-
-#define BKP_SEL                        0x3
-#define BKP_REDUN_SEL          0xe0000000
-#define BKP_REDUN_SHIFT                29
-
-#define BIT_APPEND             0x3
-
-static int calibrate_8974(struct tsens_device *tmdev)
-{
-       int base1 = 0, base2 = 0, i;
-       u32 p1[11], p2[11];
-       int mode = 0;
-       u32 *calib, *bkp;
-       u32 calib_redun_sel;
-
-       calib = (u32 *)qfprom_read(tmdev->dev, "calib");
-       if (IS_ERR(calib))
-               return PTR_ERR(calib);
-
-       bkp = (u32 *)qfprom_read(tmdev->dev, "calib_backup");
-       if (IS_ERR(bkp))
-               return PTR_ERR(bkp);
-
-       calib_redun_sel =  bkp[1] & BKP_REDUN_SEL;
-       calib_redun_sel >>= BKP_REDUN_SHIFT;
-
-       if (calib_redun_sel == BKP_SEL) {
-               mode = (calib[4] & CAL_SEL_0_1) >> CAL_SEL_SHIFT;
-               mode |= (calib[5] & CAL_SEL_2) >> CAL_SEL_SHIFT_2;
-
-               switch (mode) {
-               case TWO_PT_CALIB:
-                       base2 = (bkp[2] & BASE2_BKP_MASK) >> BASE2_BKP_SHIFT;
-                       p2[0] = (bkp[2] & S0_P2_BKP_MASK) >> S0_P2_BKP_SHIFT;
-                       p2[1] = (bkp[3] & S1_P2_BKP_MASK);
-                       p2[2] = (bkp[3] & S2_P2_BKP_MASK) >> S2_P2_BKP_SHIFT;
-                       p2[3] = (bkp[3] & S3_P2_BKP_MASK) >> S3_P2_BKP_SHIFT;
-                       p2[4] = (bkp[3] & S4_P2_BKP_MASK) >> S4_P2_BKP_SHIFT;
-                       p2[5] = (calib[4] & S5_P2_BKP_MASK) >> S5_P2_BKP_SHIFT;
-                       p2[6] = (calib[5] & S6_P2_BKP_MASK);
-                       p2[7] = (calib[5] & S7_P2_BKP_MASK) >> S7_P2_BKP_SHIFT;
-                       p2[8] = (calib[5] & S8_P2_BKP_MASK) >> S8_P2_BKP_SHIFT;
-                       p2[9] = (calib[5] & S9_P2_BKP_MASK) >> S9_P2_BKP_SHIFT;
-                       p2[10] = (calib[5] & S10_P2_BKP_MASK) >> S10_P2_BKP_SHIFT;
-                       /* Fall through */
-               case ONE_PT_CALIB:
-               case ONE_PT_CALIB2:
-                       base1 = bkp[0] & BASE1_MASK;
-                       p1[0] = (bkp[0] & S0_P1_MASK) >> S0_P1_SHIFT;
-                       p1[1] = (bkp[0] & S1_P1_MASK) >> S1_P1_SHIFT;
-                       p1[2] = (bkp[0] & S2_P1_MASK) >> S2_P1_SHIFT;
-                       p1[3] = (bkp[0] & S3_P1_MASK) >> S3_P1_SHIFT;
-                       p1[4] = (bkp[1] & S4_P1_MASK);
-                       p1[5] = (bkp[1] & S5_P1_MASK) >> S5_P1_SHIFT;
-                       p1[6] = (bkp[1] & S6_P1_MASK) >> S6_P1_SHIFT;
-                       p1[7] = (bkp[1] & S7_P1_MASK) >> S7_P1_SHIFT;
-                       p1[8] = (bkp[2] & S8_P1_MASK_BKP) >> S8_P1_SHIFT;
-                       p1[9] = (bkp[2] & S9_P1_MASK_BKP) >> S9_P1_BKP_SHIFT;
-                       p1[10] = (bkp[2] & S10_P1_MASK_BKP) >> S10_P1_BKP_SHIFT;
-                       break;
-               }
-       } else {
-               mode = (calib[1] & CAL_SEL_0_1) >> CAL_SEL_SHIFT;
-               mode |= (calib[3] & CAL_SEL_2) >> CAL_SEL_SHIFT_2;
-
-               switch (mode) {
-               case TWO_PT_CALIB:
-                       base2 = (calib[2] & BASE2_MASK) >> BASE2_SHIFT;
-                       p2[0] = (calib[2] & S0_P2_MASK) >> S0_P2_SHIFT;
-                       p2[1] = (calib[2] & S1_P2_MASK) >> S1_P2_SHIFT;
-                       p2[2] = (calib[3] & S2_P2_MASK);
-                       p2[3] = (calib[3] & S3_P2_MASK) >> S3_P2_SHIFT;
-                       p2[4] = (calib[3] & S4_P2_MASK) >> S4_P2_SHIFT;
-                       p2[5] = (calib[3] & S5_P2_MASK) >> S5_P2_SHIFT;
-                       p2[6] = (calib[3] & S6_P2_MASK) >> S6_P2_SHIFT;
-                       p2[7] = (calib[4] & S7_P2_MASK);
-                       p2[8] = (calib[4] & S8_P2_MASK) >> S8_P2_SHIFT;
-                       p2[9] = (calib[4] & S9_P2_MASK) >> S9_P2_SHIFT;
-                       p2[10] = (calib[4] & S10_P2_MASK) >> S10_P2_SHIFT;
-                       /* Fall through */
-               case ONE_PT_CALIB:
-               case ONE_PT_CALIB2:
-                       base1 = calib[0] & BASE1_MASK;
-                       p1[0] = (calib[0] & S0_P1_MASK) >> S0_P1_SHIFT;
-                       p1[1] = (calib[0] & S1_P1_MASK) >> S1_P1_SHIFT;
-                       p1[2] = (calib[0] & S2_P1_MASK) >> S2_P1_SHIFT;
-                       p1[3] = (calib[0] & S3_P1_MASK) >> S3_P1_SHIFT;
-                       p1[4] = (calib[1] & S4_P1_MASK);
-                       p1[5] = (calib[1] & S5_P1_MASK) >> S5_P1_SHIFT;
-                       p1[6] = (calib[1] & S6_P1_MASK) >> S6_P1_SHIFT;
-                       p1[7] = (calib[1] & S7_P1_MASK) >> S7_P1_SHIFT;
-                       p1[8] = (calib[1] & S8_P1_MASK) >> S8_P1_SHIFT;
-                       p1[9] = (calib[2] & S9_P1_MASK);
-                       p1[10] = (calib[2] & S10_P1_MASK) >> S10_P1_SHIFT;
-                       break;
-               }
-       }
-
-       switch (mode) {
-       case ONE_PT_CALIB:
-               for (i = 0; i < tmdev->num_sensors; i++)
-                       p1[i] += (base1 << 2) | BIT_APPEND;
-               break;
-       case TWO_PT_CALIB:
-               for (i = 0; i < tmdev->num_sensors; i++) {
-                       p2[i] += base2;
-                       p2[i] <<= 2;
-                       p2[i] |= BIT_APPEND;
-               }
-               /* Fall through */
-       case ONE_PT_CALIB2:
-               for (i = 0; i < tmdev->num_sensors; i++) {
-                       p1[i] += base1;
-                       p1[i] <<= 2;
-                       p1[i] |= BIT_APPEND;
-               }
-               break;
-       default:
-               for (i = 0; i < tmdev->num_sensors; i++)
-                       p2[i] = 780;
-               p1[0] = 502;
-               p1[1] = 509;
-               p1[2] = 503;
-               p1[3] = 509;
-               p1[4] = 505;
-               p1[5] = 509;
-               p1[6] = 507;
-               p1[7] = 510;
-               p1[8] = 508;
-               p1[9] = 509;
-               p1[10] = 508;
-               break;
-       }
-
-       compute_intercept_slope(tmdev, p1, p2, mode);
-
-       return 0;
-}
-
-static const struct tsens_ops ops_8974 = {
-       .init           = init_common,
-       .calibrate      = calibrate_8974,
-       .get_temp       = get_temp_common,
-};
-
-const struct tsens_data data_8974 = {
-       .num_sensors    = 11,
-       .ops            = &ops_8974,
-       .reg_offsets    = { [SROT_CTRL_OFFSET] = 0x0 },
-};
index f80c73f117406b587e9b2a5c38bd7e337eca2b9b..928e8e81ba6970cd20e710df70f7080a0a4ead3c 100644 (file)
 #include <linux/regmap.h>
 #include "tsens.h"
 
-/* SROT */
-#define TSENS_EN               BIT(0)
-
-/* TM */
-#define STATUS_OFFSET          0x30
-#define SN_ADDR_OFFSET         0x4
-#define SN_ST_TEMP_MASK                0x3ff
-#define CAL_DEGC_PT1           30
-#define CAL_DEGC_PT2           120
-#define SLOPE_FACTOR           1000
-#define SLOPE_DEFAULT          3200
-
 char *qfprom_read(struct device *dev, const char *cname)
 {
        struct nvmem_cell *cell;
@@ -46,18 +34,18 @@ char *qfprom_read(struct device *dev, const char *cname)
  * and offset values are derived from tz->tzp->slope and tz->tzp->offset
  * resp.
  */
-void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1,
+void compute_intercept_slope(struct tsens_priv *priv, u32 *p1,
                             u32 *p2, u32 mode)
 {
        int i;
        int num, den;
 
-       for (i = 0; i < tmdev->num_sensors; i++) {
-               dev_dbg(tmdev->dev,
+       for (i = 0; i < priv->num_sensors; i++) {
+               dev_dbg(priv->dev,
                        "sensor%d - data_point1:%#x data_point2:%#x\n",
                        i, p1[i], p2[i]);
 
-               tmdev->sensor[i].slope = SLOPE_DEFAULT;
+               priv->sensor[i].slope = SLOPE_DEFAULT;
                if (mode == TWO_PT_CALIB) {
                        /*
                         * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
@@ -66,16 +54,30 @@ void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1,
                        num = p2[i] - p1[i];
                        num *= SLOPE_FACTOR;
                        den = CAL_DEGC_PT2 - CAL_DEGC_PT1;
-                       tmdev->sensor[i].slope = num / den;
+                       priv->sensor[i].slope = num / den;
                }
 
-               tmdev->sensor[i].offset = (p1[i] * SLOPE_FACTOR) -
+               priv->sensor[i].offset = (p1[i] * SLOPE_FACTOR) -
                                (CAL_DEGC_PT1 *
-                               tmdev->sensor[i].slope);
-               dev_dbg(tmdev->dev, "offset:%d\n", tmdev->sensor[i].offset);
+                               priv->sensor[i].slope);
+               dev_dbg(priv->dev, "offset:%d\n", priv->sensor[i].offset);
        }
 }
 
+bool is_sensor_enabled(struct tsens_priv *priv, u32 hw_id)
+{
+       u32 val;
+       int ret;
+
+       if ((hw_id > (priv->num_sensors - 1)) || (hw_id < 0))
+               return -EINVAL;
+       ret = regmap_field_read(priv->rf[SENSOR_EN], &val);
+       if (ret)
+               return ret;
+
+       return val & (1 << hw_id);
+}
+
 static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
 {
        int degc, num, den;
@@ -95,18 +97,54 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
        return degc;
 }
 
-int get_temp_common(struct tsens_device *tmdev, int id, int *temp)
+int get_temp_tsens_valid(struct tsens_priv *priv, int i, int *temp)
 {
-       struct tsens_sensor *s = &tmdev->sensor[id];
-       u32 code;
-       unsigned int status_reg;
+       struct tsens_sensor *s = &priv->sensor[i];
+       u32 temp_idx = LAST_TEMP_0 + s->hw_id;
+       u32 valid_idx = VALID_0 + s->hw_id;
+       u32 last_temp = 0, valid, mask;
+       int ret;
+
+       ret = regmap_field_read(priv->rf[valid_idx], &valid);
+       if (ret)
+               return ret;
+       while (!valid) {
+               /* Valid bit is 0 for 6 AHB clock cycles.
+                * At 19.2MHz, 1 AHB clock is ~60ns.
+                * We should enter this loop very, very rarely.
+                */
+               ndelay(400);
+               ret = regmap_field_read(priv->rf[valid_idx], &valid);
+               if (ret)
+                       return ret;
+       }
+
+       /* Valid bit is set, OK to read the temperature */
+       ret = regmap_field_read(priv->rf[temp_idx], &last_temp);
+       if (ret)
+               return ret;
+
+       if (priv->feat->adc) {
+               /* Convert temperature from ADC code to milliCelsius */
+               *temp = code_to_degc(last_temp, s) * 1000;
+       } else {
+               mask = GENMASK(priv->fields[LAST_TEMP_0].msb,
+                              priv->fields[LAST_TEMP_0].lsb);
+               /* Convert temperature from deciCelsius to milliCelsius */
+               *temp = sign_extend32(last_temp, fls(mask) - 1) * 100;
+       }
+
+       return 0;
+}
+
+int get_temp_common(struct tsens_priv *priv, int i, int *temp)
+{
+       struct tsens_sensor *s = &priv->sensor[i];
        int last_temp = 0, ret;
 
-       status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * SN_ADDR_OFFSET;
-       ret = regmap_read(tmdev->tm_map, status_reg, &code);
+       ret = regmap_field_read(priv->rf[LAST_TEMP_0 + s->hw_id], &last_temp);
        if (ret)
                return ret;
-       last_temp = code & SN_ST_TEMP_MASK;
 
        *temp = code_to_degc(last_temp, s) * 1000;
 
@@ -127,21 +165,21 @@ static const struct regmap_config tsens_srot_config = {
        .reg_stride     = 4,
 };
 
-int __init init_common(struct tsens_device *tmdev)
+int __init init_common(struct tsens_priv *priv)
 {
        void __iomem *tm_base, *srot_base;
+       struct device *dev = priv->dev;
        struct resource *res;
-       u32 code;
-       int ret;
-       struct platform_device *op = of_find_device_by_node(tmdev->dev->of_node);
-       u16 ctrl_offset = tmdev->reg_offsets[SROT_CTRL_OFFSET];
+       u32 enabled;
+       int ret, i, j;
+       struct platform_device *op = of_find_device_by_node(priv->dev->of_node);
 
        if (!op)
                return -EINVAL;
 
        if (op->num_resources > 1) {
                /* DT with separate SROT and TM address space */
-               tmdev->tm_offset = 0;
+               priv->tm_offset = 0;
                res = platform_get_resource(op, IORESOURCE_MEM, 1);
                srot_base = devm_ioremap_resource(&op->dev, res);
                if (IS_ERR(srot_base)) {
@@ -149,16 +187,15 @@ int __init init_common(struct tsens_device *tmdev)
                        goto err_put_device;
                }
 
-               tmdev->srot_map = devm_regmap_init_mmio(tmdev->dev, srot_base,
+               priv->srot_map = devm_regmap_init_mmio(dev, srot_base,
                                                        &tsens_srot_config);
-               if (IS_ERR(tmdev->srot_map)) {
-                       ret = PTR_ERR(tmdev->srot_map);
+               if (IS_ERR(priv->srot_map)) {
+                       ret = PTR_ERR(priv->srot_map);
                        goto err_put_device;
                }
-
        } else {
                /* old DTs where SROT and TM were in a contiguous 2K block */
-               tmdev->tm_offset = 0x1000;
+               priv->tm_offset = 0x1000;
        }
 
        res = platform_get_resource(op, IORESOURCE_MEM, 0);
@@ -168,19 +205,47 @@ int __init init_common(struct tsens_device *tmdev)
                goto err_put_device;
        }
 
-       tmdev->tm_map = devm_regmap_init_mmio(tmdev->dev, tm_base, &tsens_config);
-       if (IS_ERR(tmdev->tm_map)) {
-               ret = PTR_ERR(tmdev->tm_map);
+       priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config);
+       if (IS_ERR(priv->tm_map)) {
+               ret = PTR_ERR(priv->tm_map);
                goto err_put_device;
        }
 
-       if (tmdev->srot_map) {
-               ret = regmap_read(tmdev->srot_map, ctrl_offset, &code);
-               if (ret)
+       priv->rf[TSENS_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
+                                                    priv->fields[TSENS_EN]);
+       if (IS_ERR(priv->rf[TSENS_EN])) {
+               ret = PTR_ERR(priv->rf[TSENS_EN]);
+               goto err_put_device;
+       }
+       ret = regmap_field_read(priv->rf[TSENS_EN], &enabled);
+       if (ret)
+               goto err_put_device;
+       if (!enabled) {
+               dev_err(dev, "tsens device is not enabled\n");
+               ret = -ENODEV;
+               goto err_put_device;
+       }
+
+       priv->rf[SENSOR_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
+                                                     priv->fields[SENSOR_EN]);
+       if (IS_ERR(priv->rf[SENSOR_EN])) {
+               ret = PTR_ERR(priv->rf[SENSOR_EN]);
+               goto err_put_device;
+       }
+       /* now alloc regmap_fields in tm_map */
+       for (i = 0, j = LAST_TEMP_0; i < priv->feat->max_sensors; i++, j++) {
+               priv->rf[j] = devm_regmap_field_alloc(dev, priv->tm_map,
+                                                     priv->fields[j]);
+               if (IS_ERR(priv->rf[j])) {
+                       ret = PTR_ERR(priv->rf[j]);
                        goto err_put_device;
-               if (!(code & TSENS_EN)) {
-                       dev_err(tmdev->dev, "tsens device is not enabled\n");
-                       ret = -ENODEV;
+               }
+       }
+       for (i = 0, j = VALID_0; i < priv->feat->max_sensors; i++, j++) {
+               priv->rf[j] = devm_regmap_field_alloc(dev, priv->tm_map,
+                                                     priv->fields[j]);
+               if (IS_ERR(priv->rf[j])) {
+                       ret = PTR_ERR(priv->rf[j]);
                        goto err_put_device;
                }
        }
diff --git a/drivers/thermal/qcom/tsens-v0_1.c b/drivers/thermal/qcom/tsens-v0_1.c
new file mode 100644 (file)
index 0000000..a319283
--- /dev/null
@@ -0,0 +1,382 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/platform_device.h>
+#include "tsens.h"
+
+/* ----- SROT ------ */
+#define SROT_CTRL_OFF 0x0000
+
+/* ----- TM ------ */
+#define TM_INT_EN_OFF                          0x0000
+#define TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF      0x0004
+#define TM_Sn_STATUS_OFF                       0x0030
+#define TM_TRDY_OFF                            0x005c
+
+/* eeprom layout data for 8916 */
+#define MSM8916_BASE0_MASK     0x0000007f
+#define MSM8916_BASE1_MASK     0xfe000000
+#define MSM8916_BASE0_SHIFT    0
+#define MSM8916_BASE1_SHIFT    25
+
+#define MSM8916_S0_P1_MASK     0x00000f80
+#define MSM8916_S1_P1_MASK     0x003e0000
+#define MSM8916_S2_P1_MASK     0xf8000000
+#define MSM8916_S3_P1_MASK     0x000003e0
+#define MSM8916_S4_P1_MASK     0x000f8000
+
+#define MSM8916_S0_P2_MASK     0x0001f000
+#define MSM8916_S1_P2_MASK     0x07c00000
+#define MSM8916_S2_P2_MASK     0x0000001f
+#define MSM8916_S3_P2_MASK     0x00007c00
+#define MSM8916_S4_P2_MASK     0x01f00000
+
+#define MSM8916_S0_P1_SHIFT    7
+#define MSM8916_S1_P1_SHIFT    17
+#define MSM8916_S2_P1_SHIFT    27
+#define MSM8916_S3_P1_SHIFT    5
+#define MSM8916_S4_P1_SHIFT    15
+
+#define MSM8916_S0_P2_SHIFT    12
+#define MSM8916_S1_P2_SHIFT    22
+#define MSM8916_S2_P2_SHIFT    0
+#define MSM8916_S3_P2_SHIFT    10
+#define MSM8916_S4_P2_SHIFT    20
+
+#define MSM8916_CAL_SEL_MASK   0xe0000000
+#define MSM8916_CAL_SEL_SHIFT  29
+
+/* eeprom layout data for 8974 */
+#define BASE1_MASK             0xff
+#define S0_P1_MASK             0x3f00
+#define S1_P1_MASK             0xfc000
+#define S2_P1_MASK             0x3f00000
+#define S3_P1_MASK             0xfc000000
+#define S4_P1_MASK             0x3f
+#define S5_P1_MASK             0xfc0
+#define S6_P1_MASK             0x3f000
+#define S7_P1_MASK             0xfc0000
+#define S8_P1_MASK             0x3f000000
+#define S8_P1_MASK_BKP         0x3f
+#define S9_P1_MASK             0x3f
+#define S9_P1_MASK_BKP         0xfc0
+#define S10_P1_MASK            0xfc0
+#define S10_P1_MASK_BKP                0x3f000
+#define CAL_SEL_0_1            0xc0000000
+#define CAL_SEL_2              0x40000000
+#define CAL_SEL_SHIFT          30
+#define CAL_SEL_SHIFT_2                28
+
+#define S0_P1_SHIFT            8
+#define S1_P1_SHIFT            14
+#define S2_P1_SHIFT            20
+#define S3_P1_SHIFT            26
+#define S5_P1_SHIFT            6
+#define S6_P1_SHIFT            12
+#define S7_P1_SHIFT            18
+#define S8_P1_SHIFT            24
+#define S9_P1_BKP_SHIFT                6
+#define S10_P1_SHIFT           6
+#define S10_P1_BKP_SHIFT       12
+
+#define BASE2_SHIFT            12
+#define BASE2_BKP_SHIFT                18
+#define S0_P2_SHIFT            20
+#define S0_P2_BKP_SHIFT                26
+#define S1_P2_SHIFT            26
+#define S2_P2_BKP_SHIFT                6
+#define S3_P2_SHIFT            6
+#define S3_P2_BKP_SHIFT                12
+#define S4_P2_SHIFT            12
+#define S4_P2_BKP_SHIFT                18
+#define S5_P2_SHIFT            18
+#define S5_P2_BKP_SHIFT                24
+#define S6_P2_SHIFT            24
+#define S7_P2_BKP_SHIFT                6
+#define S8_P2_SHIFT            6
+#define S8_P2_BKP_SHIFT                12
+#define S9_P2_SHIFT            12
+#define S9_P2_BKP_SHIFT                18
+#define S10_P2_SHIFT           18
+#define S10_P2_BKP_SHIFT       24
+
+#define BASE2_MASK             0xff000
+#define BASE2_BKP_MASK         0xfc0000
+#define S0_P2_MASK             0x3f00000
+#define S0_P2_BKP_MASK         0xfc000000
+#define S1_P2_MASK             0xfc000000
+#define S1_P2_BKP_MASK         0x3f
+#define S2_P2_MASK             0x3f
+#define S2_P2_BKP_MASK         0xfc0
+#define S3_P2_MASK             0xfc0
+#define S3_P2_BKP_MASK         0x3f000
+#define S4_P2_MASK             0x3f000
+#define S4_P2_BKP_MASK         0xfc0000
+#define S5_P2_MASK             0xfc0000
+#define S5_P2_BKP_MASK         0x3f000000
+#define S6_P2_MASK             0x3f000000
+#define S6_P2_BKP_MASK         0x3f
+#define S7_P2_MASK             0x3f
+#define S7_P2_BKP_MASK         0xfc0
+#define S8_P2_MASK             0xfc0
+#define S8_P2_BKP_MASK         0x3f000
+#define S9_P2_MASK             0x3f000
+#define S9_P2_BKP_MASK         0xfc0000
+#define S10_P2_MASK            0xfc0000
+#define S10_P2_BKP_MASK                0x3f000000
+
+#define BKP_SEL                        0x3
+#define BKP_REDUN_SEL          0xe0000000
+#define BKP_REDUN_SHIFT                29
+
+#define BIT_APPEND             0x3
+
+static int calibrate_8916(struct tsens_priv *priv)
+{
+       int base0 = 0, base1 = 0, i;
+       u32 p1[5], p2[5];
+       int mode = 0;
+       u32 *qfprom_cdata, *qfprom_csel;
+
+       qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib");
+       if (IS_ERR(qfprom_cdata))
+               return PTR_ERR(qfprom_cdata);
+
+       qfprom_csel = (u32 *)qfprom_read(priv->dev, "calib_sel");
+       if (IS_ERR(qfprom_csel))
+               return PTR_ERR(qfprom_csel);
+
+       mode = (qfprom_csel[0] & MSM8916_CAL_SEL_MASK) >> MSM8916_CAL_SEL_SHIFT;
+       dev_dbg(priv->dev, "calibration mode is %d\n", mode);
+
+       switch (mode) {
+       case TWO_PT_CALIB:
+               base1 = (qfprom_cdata[1] & MSM8916_BASE1_MASK) >> MSM8916_BASE1_SHIFT;
+               p2[0] = (qfprom_cdata[0] & MSM8916_S0_P2_MASK) >> MSM8916_S0_P2_SHIFT;
+               p2[1] = (qfprom_cdata[0] & MSM8916_S1_P2_MASK) >> MSM8916_S1_P2_SHIFT;
+               p2[2] = (qfprom_cdata[1] & MSM8916_S2_P2_MASK) >> MSM8916_S2_P2_SHIFT;
+               p2[3] = (qfprom_cdata[1] & MSM8916_S3_P2_MASK) >> MSM8916_S3_P2_SHIFT;
+               p2[4] = (qfprom_cdata[1] & MSM8916_S4_P2_MASK) >> MSM8916_S4_P2_SHIFT;
+               for (i = 0; i < priv->num_sensors; i++)
+                       p2[i] = ((base1 + p2[i]) << 3);
+               /* Fall through */
+       case ONE_PT_CALIB2:
+               base0 = (qfprom_cdata[0] & MSM8916_BASE0_MASK);
+               p1[0] = (qfprom_cdata[0] & MSM8916_S0_P1_MASK) >> MSM8916_S0_P1_SHIFT;
+               p1[1] = (qfprom_cdata[0] & MSM8916_S1_P1_MASK) >> MSM8916_S1_P1_SHIFT;
+               p1[2] = (qfprom_cdata[0] & MSM8916_S2_P1_MASK) >> MSM8916_S2_P1_SHIFT;
+               p1[3] = (qfprom_cdata[1] & MSM8916_S3_P1_MASK) >> MSM8916_S3_P1_SHIFT;
+               p1[4] = (qfprom_cdata[1] & MSM8916_S4_P1_MASK) >> MSM8916_S4_P1_SHIFT;
+               for (i = 0; i < priv->num_sensors; i++)
+                       p1[i] = (((base0) + p1[i]) << 3);
+               break;
+       default:
+               for (i = 0; i < priv->num_sensors; i++) {
+                       p1[i] = 500;
+                       p2[i] = 780;
+               }
+               break;
+       }
+
+       compute_intercept_slope(priv, p1, p2, mode);
+
+       return 0;
+}
+
+static int calibrate_8974(struct tsens_priv *priv)
+{
+       int base1 = 0, base2 = 0, i;
+       u32 p1[11], p2[11];
+       int mode = 0;
+       u32 *calib, *bkp;
+       u32 calib_redun_sel;
+
+       calib = (u32 *)qfprom_read(priv->dev, "calib");
+       if (IS_ERR(calib))
+               return PTR_ERR(calib);
+
+       bkp = (u32 *)qfprom_read(priv->dev, "calib_backup");
+       if (IS_ERR(bkp))
+               return PTR_ERR(bkp);
+
+       calib_redun_sel =  bkp[1] & BKP_REDUN_SEL;
+       calib_redun_sel >>= BKP_REDUN_SHIFT;
+
+       if (calib_redun_sel == BKP_SEL) {
+               mode = (calib[4] & CAL_SEL_0_1) >> CAL_SEL_SHIFT;
+               mode |= (calib[5] & CAL_SEL_2) >> CAL_SEL_SHIFT_2;
+
+               switch (mode) {
+               case TWO_PT_CALIB:
+                       base2 = (bkp[2] & BASE2_BKP_MASK) >> BASE2_BKP_SHIFT;
+                       p2[0] = (bkp[2] & S0_P2_BKP_MASK) >> S0_P2_BKP_SHIFT;
+                       p2[1] = (bkp[3] & S1_P2_BKP_MASK);
+                       p2[2] = (bkp[3] & S2_P2_BKP_MASK) >> S2_P2_BKP_SHIFT;
+                       p2[3] = (bkp[3] & S3_P2_BKP_MASK) >> S3_P2_BKP_SHIFT;
+                       p2[4] = (bkp[3] & S4_P2_BKP_MASK) >> S4_P2_BKP_SHIFT;
+                       p2[5] = (calib[4] & S5_P2_BKP_MASK) >> S5_P2_BKP_SHIFT;
+                       p2[6] = (calib[5] & S6_P2_BKP_MASK);
+                       p2[7] = (calib[5] & S7_P2_BKP_MASK) >> S7_P2_BKP_SHIFT;
+                       p2[8] = (calib[5] & S8_P2_BKP_MASK) >> S8_P2_BKP_SHIFT;
+                       p2[9] = (calib[5] & S9_P2_BKP_MASK) >> S9_P2_BKP_SHIFT;
+                       p2[10] = (calib[5] & S10_P2_BKP_MASK) >> S10_P2_BKP_SHIFT;
+                       /* Fall through */
+               case ONE_PT_CALIB:
+               case ONE_PT_CALIB2:
+                       base1 = bkp[0] & BASE1_MASK;
+                       p1[0] = (bkp[0] & S0_P1_MASK) >> S0_P1_SHIFT;
+                       p1[1] = (bkp[0] & S1_P1_MASK) >> S1_P1_SHIFT;
+                       p1[2] = (bkp[0] & S2_P1_MASK) >> S2_P1_SHIFT;
+                       p1[3] = (bkp[0] & S3_P1_MASK) >> S3_P1_SHIFT;
+                       p1[4] = (bkp[1] & S4_P1_MASK);
+                       p1[5] = (bkp[1] & S5_P1_MASK) >> S5_P1_SHIFT;
+                       p1[6] = (bkp[1] & S6_P1_MASK) >> S6_P1_SHIFT;
+                       p1[7] = (bkp[1] & S7_P1_MASK) >> S7_P1_SHIFT;
+                       p1[8] = (bkp[2] & S8_P1_MASK_BKP) >> S8_P1_SHIFT;
+                       p1[9] = (bkp[2] & S9_P1_MASK_BKP) >> S9_P1_BKP_SHIFT;
+                       p1[10] = (bkp[2] & S10_P1_MASK_BKP) >> S10_P1_BKP_SHIFT;
+                       break;
+               }
+       } else {
+               mode = (calib[1] & CAL_SEL_0_1) >> CAL_SEL_SHIFT;
+               mode |= (calib[3] & CAL_SEL_2) >> CAL_SEL_SHIFT_2;
+
+               switch (mode) {
+               case TWO_PT_CALIB:
+                       base2 = (calib[2] & BASE2_MASK) >> BASE2_SHIFT;
+                       p2[0] = (calib[2] & S0_P2_MASK) >> S0_P2_SHIFT;
+                       p2[1] = (calib[2] & S1_P2_MASK) >> S1_P2_SHIFT;
+                       p2[2] = (calib[3] & S2_P2_MASK);
+                       p2[3] = (calib[3] & S3_P2_MASK) >> S3_P2_SHIFT;
+                       p2[4] = (calib[3] & S4_P2_MASK) >> S4_P2_SHIFT;
+                       p2[5] = (calib[3] & S5_P2_MASK) >> S5_P2_SHIFT;
+                       p2[6] = (calib[3] & S6_P2_MASK) >> S6_P2_SHIFT;
+                       p2[7] = (calib[4] & S7_P2_MASK);
+                       p2[8] = (calib[4] & S8_P2_MASK) >> S8_P2_SHIFT;
+                       p2[9] = (calib[4] & S9_P2_MASK) >> S9_P2_SHIFT;
+                       p2[10] = (calib[4] & S10_P2_MASK) >> S10_P2_SHIFT;
+                       /* Fall through */
+               case ONE_PT_CALIB:
+               case ONE_PT_CALIB2:
+                       base1 = calib[0] & BASE1_MASK;
+                       p1[0] = (calib[0] & S0_P1_MASK) >> S0_P1_SHIFT;
+                       p1[1] = (calib[0] & S1_P1_MASK) >> S1_P1_SHIFT;
+                       p1[2] = (calib[0] & S2_P1_MASK) >> S2_P1_SHIFT;
+                       p1[3] = (calib[0] & S3_P1_MASK) >> S3_P1_SHIFT;
+                       p1[4] = (calib[1] & S4_P1_MASK);
+                       p1[5] = (calib[1] & S5_P1_MASK) >> S5_P1_SHIFT;
+                       p1[6] = (calib[1] & S6_P1_MASK) >> S6_P1_SHIFT;
+                       p1[7] = (calib[1] & S7_P1_MASK) >> S7_P1_SHIFT;
+                       p1[8] = (calib[1] & S8_P1_MASK) >> S8_P1_SHIFT;
+                       p1[9] = (calib[2] & S9_P1_MASK);
+                       p1[10] = (calib[2] & S10_P1_MASK) >> S10_P1_SHIFT;
+                       break;
+               }
+       }
+
+       switch (mode) {
+       case ONE_PT_CALIB:
+               for (i = 0; i < priv->num_sensors; i++)
+                       p1[i] += (base1 << 2) | BIT_APPEND;
+               break;
+       case TWO_PT_CALIB:
+               for (i = 0; i < priv->num_sensors; i++) {
+                       p2[i] += base2;
+                       p2[i] <<= 2;
+                       p2[i] |= BIT_APPEND;
+               }
+               /* Fall through */
+       case ONE_PT_CALIB2:
+               for (i = 0; i < priv->num_sensors; i++) {
+                       p1[i] += base1;
+                       p1[i] <<= 2;
+                       p1[i] |= BIT_APPEND;
+               }
+               break;
+       default:
+               for (i = 0; i < priv->num_sensors; i++)
+                       p2[i] = 780;
+               p1[0] = 502;
+               p1[1] = 509;
+               p1[2] = 503;
+               p1[3] = 509;
+               p1[4] = 505;
+               p1[5] = 509;
+               p1[6] = 507;
+               p1[7] = 510;
+               p1[8] = 508;
+               p1[9] = 509;
+               p1[10] = 508;
+               break;
+       }
+
+       compute_intercept_slope(priv, p1, p2, mode);
+
+       return 0;
+}
+
+/* v0.1: 8916, 8974 */
+
+static const struct tsens_features tsens_v0_1_feat = {
+       .ver_major      = VER_0_1,
+       .crit_int       = 0,
+       .adc            = 1,
+       .srot_split     = 1,
+       .max_sensors    = 11,
+};
+
+static const struct reg_field tsens_v0_1_regfields[MAX_REGFIELDS] = {
+       /* ----- SROT ------ */
+       /* No VERSION information */
+
+       /* CTRL_OFFSET */
+       [TSENS_EN]     = REG_FIELD(SROT_CTRL_OFF, 0,  0),
+       [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1,  1),
+       [SENSOR_EN]    = REG_FIELD(SROT_CTRL_OFF, 3, 13),
+
+       /* ----- TM ------ */
+       /* INTERRUPT ENABLE */
+       [INT_EN] = REG_FIELD(TM_INT_EN_OFF, 0, 0),
+
+       /* Sn_STATUS */
+       REG_FIELD_FOR_EACH_SENSOR11(LAST_TEMP,    TM_Sn_STATUS_OFF,  0,  9),
+       /* No VALID field on v0.1 */
+       REG_FIELD_FOR_EACH_SENSOR11(MIN_STATUS,   TM_Sn_STATUS_OFF, 10, 10),
+       REG_FIELD_FOR_EACH_SENSOR11(LOWER_STATUS, TM_Sn_STATUS_OFF, 11, 11),
+       REG_FIELD_FOR_EACH_SENSOR11(UPPER_STATUS, TM_Sn_STATUS_OFF, 12, 12),
+       /* No CRITICAL field on v0.1 */
+       REG_FIELD_FOR_EACH_SENSOR11(MAX_STATUS,   TM_Sn_STATUS_OFF, 13, 13),
+
+       /* TRDY: 1=ready, 0=in progress */
+       [TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),
+};
+
+static const struct tsens_ops ops_8916 = {
+       .init           = init_common,
+       .calibrate      = calibrate_8916,
+       .get_temp       = get_temp_common,
+};
+
+const struct tsens_plat_data data_8916 = {
+       .num_sensors    = 5,
+       .ops            = &ops_8916,
+       .hw_ids         = (unsigned int []){0, 1, 2, 4, 5 },
+
+       .feat           = &tsens_v0_1_feat,
+       .fields = tsens_v0_1_regfields,
+};
+
+static const struct tsens_ops ops_8974 = {
+       .init           = init_common,
+       .calibrate      = calibrate_8974,
+       .get_temp       = get_temp_common,
+};
+
+const struct tsens_plat_data data_8974 = {
+       .num_sensors    = 11,
+       .ops            = &ops_8974,
+       .feat           = &tsens_v0_1_feat,
+       .fields = tsens_v0_1_regfields,
+};
diff --git a/drivers/thermal/qcom/tsens-v1.c b/drivers/thermal/qcom/tsens-v1.c
new file mode 100644 (file)
index 0000000..10b595d
--- /dev/null
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019, Linaro Limited
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include "tsens.h"
+
+/* ----- SROT ------ */
+#define SROT_HW_VER_OFF        0x0000
+#define SROT_CTRL_OFF          0x0004
+
+/* ----- TM ------ */
+#define TM_INT_EN_OFF                          0x0000
+#define TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF      0x0004
+#define TM_Sn_STATUS_OFF                       0x0044
+#define TM_TRDY_OFF                            0x0084
+
+/* eeprom layout data for qcs404/405 (v1) */
+#define BASE0_MASK     0x000007f8
+#define BASE1_MASK     0x0007f800
+#define BASE0_SHIFT    3
+#define BASE1_SHIFT    11
+
+#define S0_P1_MASK     0x0000003f
+#define S1_P1_MASK     0x0003f000
+#define S2_P1_MASK     0x3f000000
+#define S3_P1_MASK     0x000003f0
+#define S4_P1_MASK     0x003f0000
+#define S5_P1_MASK     0x0000003f
+#define S6_P1_MASK     0x0003f000
+#define S7_P1_MASK     0x3f000000
+#define S8_P1_MASK     0x000003f0
+#define S9_P1_MASK     0x003f0000
+
+#define S0_P2_MASK     0x00000fc0
+#define S1_P2_MASK     0x00fc0000
+#define S2_P2_MASK_1_0 0xc0000000
+#define S2_P2_MASK_5_2 0x0000000f
+#define S3_P2_MASK     0x0000fc00
+#define S4_P2_MASK     0x0fc00000
+#define S5_P2_MASK     0x00000fc0
+#define S6_P2_MASK     0x00fc0000
+#define S7_P2_MASK_1_0 0xc0000000
+#define S7_P2_MASK_5_2 0x0000000f
+#define S8_P2_MASK     0x0000fc00
+#define S9_P2_MASK     0x0fc00000
+
+#define S0_P1_SHIFT    0
+#define S0_P2_SHIFT    6
+#define S1_P1_SHIFT    12
+#define S1_P2_SHIFT    18
+#define S2_P1_SHIFT    24
+#define S2_P2_SHIFT_1_0        30
+
+#define S2_P2_SHIFT_5_2        0
+#define S3_P1_SHIFT    4
+#define S3_P2_SHIFT    10
+#define S4_P1_SHIFT    16
+#define S4_P2_SHIFT    22
+
+#define S5_P1_SHIFT    0
+#define S5_P2_SHIFT    6
+#define S6_P1_SHIFT    12
+#define S6_P2_SHIFT    18
+#define S7_P1_SHIFT    24
+#define S7_P2_SHIFT_1_0        30
+
+#define S7_P2_SHIFT_5_2        0
+#define S8_P1_SHIFT    4
+#define S8_P2_SHIFT    10
+#define S9_P1_SHIFT    16
+#define S9_P2_SHIFT    22
+
+#define CAL_SEL_MASK   7
+#define CAL_SEL_SHIFT  0
+
+static int calibrate_v1(struct tsens_priv *priv)
+{
+       u32 base0 = 0, base1 = 0;
+       u32 p1[10], p2[10];
+       u32 mode = 0, lsb = 0, msb = 0;
+       u32 *qfprom_cdata;
+       int i;
+
+       qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib");
+       if (IS_ERR(qfprom_cdata))
+               return PTR_ERR(qfprom_cdata);
+
+       mode = (qfprom_cdata[4] & CAL_SEL_MASK) >> CAL_SEL_SHIFT;
+       dev_dbg(priv->dev, "calibration mode is %d\n", mode);
+
+       switch (mode) {
+       case TWO_PT_CALIB:
+               base1 = (qfprom_cdata[4] & BASE1_MASK) >> BASE1_SHIFT;
+               p2[0] = (qfprom_cdata[0] & S0_P2_MASK) >> S0_P2_SHIFT;
+               p2[1] = (qfprom_cdata[0] & S1_P2_MASK) >> S1_P2_SHIFT;
+               /* This value is split over two registers, 2 bits and 4 bits */
+               lsb   = (qfprom_cdata[0] & S2_P2_MASK_1_0) >> S2_P2_SHIFT_1_0;
+               msb   = (qfprom_cdata[1] & S2_P2_MASK_5_2) >> S2_P2_SHIFT_5_2;
+               p2[2] = msb << 2 | lsb;
+               p2[3] = (qfprom_cdata[1] & S3_P2_MASK) >> S3_P2_SHIFT;
+               p2[4] = (qfprom_cdata[1] & S4_P2_MASK) >> S4_P2_SHIFT;
+               p2[5] = (qfprom_cdata[2] & S5_P2_MASK) >> S5_P2_SHIFT;
+               p2[6] = (qfprom_cdata[2] & S6_P2_MASK) >> S6_P2_SHIFT;
+               /* This value is split over two registers, 2 bits and 4 bits */
+               lsb   = (qfprom_cdata[2] & S7_P2_MASK_1_0) >> S7_P2_SHIFT_1_0;
+               msb   = (qfprom_cdata[3] & S7_P2_MASK_5_2) >> S7_P2_SHIFT_5_2;
+               p2[7] = msb << 2 | lsb;
+               p2[8] = (qfprom_cdata[3] & S8_P2_MASK) >> S8_P2_SHIFT;
+               p2[9] = (qfprom_cdata[3] & S9_P2_MASK) >> S9_P2_SHIFT;
+               for (i = 0; i < priv->num_sensors; i++)
+                       p2[i] = ((base1 + p2[i]) << 2);
+               /* Fall through */
+       case ONE_PT_CALIB2:
+               base0 = (qfprom_cdata[4] & BASE0_MASK) >> BASE0_SHIFT;
+               p1[0] = (qfprom_cdata[0] & S0_P1_MASK) >> S0_P1_SHIFT;
+               p1[1] = (qfprom_cdata[0] & S1_P1_MASK) >> S1_P1_SHIFT;
+               p1[2] = (qfprom_cdata[0] & S2_P1_MASK) >> S2_P1_SHIFT;
+               p1[3] = (qfprom_cdata[1] & S3_P1_MASK) >> S3_P1_SHIFT;
+               p1[4] = (qfprom_cdata[1] & S4_P1_MASK) >> S4_P1_SHIFT;
+               p1[5] = (qfprom_cdata[2] & S5_P1_MASK) >> S5_P1_SHIFT;
+               p1[6] = (qfprom_cdata[2] & S6_P1_MASK) >> S6_P1_SHIFT;
+               p1[7] = (qfprom_cdata[2] & S7_P1_MASK) >> S7_P1_SHIFT;
+               p1[8] = (qfprom_cdata[3] & S8_P1_MASK) >> S8_P1_SHIFT;
+               p1[9] = (qfprom_cdata[3] & S9_P1_MASK) >> S9_P1_SHIFT;
+               for (i = 0; i < priv->num_sensors; i++)
+                       p1[i] = (((base0) + p1[i]) << 2);
+               break;
+       default:
+               for (i = 0; i < priv->num_sensors; i++) {
+                       p1[i] = 500;
+                       p2[i] = 780;
+               }
+               break;
+       }
+
+       compute_intercept_slope(priv, p1, p2, mode);
+
+       return 0;
+}
+
+/* v1.x: qcs404,405 */
+
+static const struct tsens_features tsens_v1_feat = {
+       .ver_major      = VER_1_X,
+       .crit_int       = 0,
+       .adc            = 1,
+       .srot_split     = 1,
+       .max_sensors    = 11,
+};
+
+static const struct reg_field tsens_v1_regfields[MAX_REGFIELDS] = {
+       /* ----- SROT ------ */
+       /* VERSION */
+       [VER_MAJOR] = REG_FIELD(SROT_HW_VER_OFF, 28, 31),
+       [VER_MINOR] = REG_FIELD(SROT_HW_VER_OFF, 16, 27),
+       [VER_STEP]  = REG_FIELD(SROT_HW_VER_OFF,  0, 15),
+       /* CTRL_OFFSET */
+       [TSENS_EN]     = REG_FIELD(SROT_CTRL_OFF, 0,  0),
+       [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1,  1),
+       [SENSOR_EN]    = REG_FIELD(SROT_CTRL_OFF, 3, 13),
+
+       /* ----- TM ------ */
+       /* INTERRUPT ENABLE */
+       [INT_EN]     = REG_FIELD(TM_INT_EN_OFF, 0, 0),
+
+       /* Sn_STATUS */
+       REG_FIELD_FOR_EACH_SENSOR11(LAST_TEMP,    TM_Sn_STATUS_OFF,  0,  9),
+       REG_FIELD_FOR_EACH_SENSOR11(VALID,        TM_Sn_STATUS_OFF, 14, 14),
+       REG_FIELD_FOR_EACH_SENSOR11(MIN_STATUS,   TM_Sn_STATUS_OFF, 10, 10),
+       REG_FIELD_FOR_EACH_SENSOR11(LOWER_STATUS, TM_Sn_STATUS_OFF, 11, 11),
+       REG_FIELD_FOR_EACH_SENSOR11(UPPER_STATUS, TM_Sn_STATUS_OFF, 12, 12),
+       /* No CRITICAL field on v1.x */
+       REG_FIELD_FOR_EACH_SENSOR11(MAX_STATUS,   TM_Sn_STATUS_OFF, 13, 13),
+
+       /* TRDY: 1=ready, 0=in progress */
+       [TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),
+};
+
+static const struct tsens_ops ops_generic_v1 = {
+       .init           = init_common,
+       .calibrate      = calibrate_v1,
+       .get_temp       = get_temp_tsens_valid,
+};
+
+const struct tsens_plat_data data_tsens_v1 = {
+       .ops            = &ops_generic_v1,
+       .feat           = &tsens_v1_feat,
+       .fields = tsens_v1_regfields,
+};
index 381a212872bfb4151b3606bea23d821403997741..1099069f2aa3efe87e0ab5cea51a8aa9a66b1079 100644 (file)
@@ -4,76 +4,81 @@
  * Copyright (c) 2018, Linaro Limited
  */
 
-#include <linux/regmap.h>
 #include <linux/bitops.h>
+#include <linux/regmap.h>
 #include "tsens.h"
 
-#define STATUS_OFFSET          0xa0
-#define LAST_TEMP_MASK         0xfff
-#define STATUS_VALID_BIT       BIT(21)
+/* ----- SROT ------ */
+#define SROT_HW_VER_OFF        0x0000
+#define SROT_CTRL_OFF          0x0004
+
+/* ----- TM ------ */
+#define TM_INT_EN_OFF                  0x0004
+#define TM_UPPER_LOWER_INT_STATUS_OFF  0x0008
+#define TM_UPPER_LOWER_INT_CLEAR_OFF   0x000c
+#define TM_UPPER_LOWER_INT_MASK_OFF    0x0010
+#define TM_CRITICAL_INT_STATUS_OFF     0x0014
+#define TM_CRITICAL_INT_CLEAR_OFF      0x0018
+#define TM_CRITICAL_INT_MASK_OFF       0x001c
+#define TM_Sn_UPPER_LOWER_THRESHOLD_OFF 0x0020
+#define TM_Sn_CRITICAL_THRESHOLD_OFF   0x0060
+#define TM_Sn_STATUS_OFF               0x00a0
+#define TM_TRDY_OFF                    0x00e4
 
-static int get_temp_tsens_v2(struct tsens_device *tmdev, int id, int *temp)
-{
-       struct tsens_sensor *s = &tmdev->sensor[id];
-       u32 code;
-       unsigned int status_reg;
-       u32 last_temp = 0, last_temp2 = 0, last_temp3 = 0;
-       int ret;
+/* v2.x: 8996, 8998, sdm845 */
 
-       status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * 4;
-       ret = regmap_read(tmdev->tm_map, status_reg, &code);
-       if (ret)
-               return ret;
-       last_temp = code & LAST_TEMP_MASK;
-       if (code & STATUS_VALID_BIT)
-               goto done;
+static const struct tsens_features tsens_v2_feat = {
+       .ver_major      = VER_2_X,
+       .crit_int       = 1,
+       .adc            = 0,
+       .srot_split     = 1,
+       .max_sensors    = 16,
+};
 
-       /* Try a second time */
-       ret = regmap_read(tmdev->tm_map, status_reg, &code);
-       if (ret)
-               return ret;
-       if (code & STATUS_VALID_BIT) {
-               last_temp = code & LAST_TEMP_MASK;
-               goto done;
-       } else {
-               last_temp2 = code & LAST_TEMP_MASK;
-       }
+static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
+       /* ----- SROT ------ */
+       /* VERSION */
+       [VER_MAJOR] = REG_FIELD(SROT_HW_VER_OFF, 28, 31),
+       [VER_MINOR] = REG_FIELD(SROT_HW_VER_OFF, 16, 27),
+       [VER_STEP]  = REG_FIELD(SROT_HW_VER_OFF,  0, 15),
+       /* CTRL_OFF */
+       [TSENS_EN]     = REG_FIELD(SROT_CTRL_OFF,    0,  0),
+       [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF,    1,  1),
+       [SENSOR_EN]    = REG_FIELD(SROT_CTRL_OFF,    3, 18),
 
-       /* Try a third/last time */
-       ret = regmap_read(tmdev->tm_map, status_reg, &code);
-       if (ret)
-               return ret;
-       if (code & STATUS_VALID_BIT) {
-               last_temp = code & LAST_TEMP_MASK;
-               goto done;
-       } else {
-               last_temp3 = code & LAST_TEMP_MASK;
-       }
+       /* ----- TM ------ */
+       /* INTERRUPT ENABLE */
+       /* v2 has separate enables for UPPER/LOWER/CRITICAL interrupts */
+       [INT_EN]  = REG_FIELD(TM_INT_EN_OFF, 0, 2),
 
-       if (last_temp == last_temp2)
-               last_temp = last_temp2;
-       else if (last_temp2 == last_temp3)
-               last_temp = last_temp3;
-done:
-       /* Convert temperature from deciCelsius to milliCelsius */
-       *temp = sign_extend32(last_temp, fls(LAST_TEMP_MASK) - 1) * 100;
+       /* Sn_STATUS */
+       REG_FIELD_FOR_EACH_SENSOR16(LAST_TEMP,       TM_Sn_STATUS_OFF,  0,  11),
+       REG_FIELD_FOR_EACH_SENSOR16(VALID,           TM_Sn_STATUS_OFF, 21,  21),
+       REG_FIELD_FOR_EACH_SENSOR16(MIN_STATUS,      TM_Sn_STATUS_OFF, 16,  16),
+       REG_FIELD_FOR_EACH_SENSOR16(LOWER_STATUS,    TM_Sn_STATUS_OFF, 17,  17),
+       REG_FIELD_FOR_EACH_SENSOR16(UPPER_STATUS,    TM_Sn_STATUS_OFF, 18,  18),
+       REG_FIELD_FOR_EACH_SENSOR16(CRITICAL_STATUS, TM_Sn_STATUS_OFF, 19,  19),
+       REG_FIELD_FOR_EACH_SENSOR16(MAX_STATUS,      TM_Sn_STATUS_OFF, 20,  20),
 
-       return 0;
-}
+       /* TRDY: 1=ready, 0=in progress */
+       [TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),
+};
 
 static const struct tsens_ops ops_generic_v2 = {
        .init           = init_common,
-       .get_temp       = get_temp_tsens_v2,
+       .get_temp       = get_temp_tsens_valid,
 };
 
-const struct tsens_data data_tsens_v2 = {
-       .ops            = &ops_generic_v2,
-       .reg_offsets    = { [SROT_CTRL_OFFSET] = 0x4 },
+const struct tsens_plat_data data_tsens_v2 = {
+       .ops            = &ops_generic_v2,
+       .feat           = &tsens_v2_feat,
+       .fields = tsens_v2_regfields,
 };
 
 /* Kept around for backward compatibility with old msm8996.dtsi */
-const struct tsens_data data_8996 = {
+const struct tsens_plat_data data_8996 = {
        .num_sensors    = 13,
        .ops            = &ops_generic_v2,
-       .reg_offsets    = { [SROT_CTRL_OFFSET] = 0x4 },
+       .feat           = &tsens_v2_feat,
+       .fields = tsens_v2_regfields,
 };
index f1ec9bbe4717e6f0f5c3aea4fb19b5963a189d19..36b0b52db524cb78114b912b7e6d0b8514844592 100644 (file)
 static int tsens_get_temp(void *data, int *temp)
 {
        const struct tsens_sensor *s = data;
-       struct tsens_device *tmdev = s->tmdev;
+       struct tsens_priv *priv = s->priv;
 
-       return tmdev->ops->get_temp(tmdev, s->id, temp);
+       return priv->ops->get_temp(priv, s->id, temp);
 }
 
-static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend)
+static int tsens_get_trend(void *data, int trip, enum thermal_trend *trend)
 {
-       const struct tsens_sensor *s = p;
-       struct tsens_device *tmdev = s->tmdev;
+       const struct tsens_sensor *s = data;
+       struct tsens_priv *priv = s->priv;
 
-       if (tmdev->ops->get_trend)
-               return  tmdev->ops->get_trend(tmdev, s->id, trend);
+       if (priv->ops->get_trend)
+               return priv->ops->get_trend(priv, s->id, trend);
 
        return -ENOTSUPP;
 }
 
 static int  __maybe_unused tsens_suspend(struct device *dev)
 {
-       struct tsens_device *tmdev = dev_get_drvdata(dev);
+       struct tsens_priv *priv = dev_get_drvdata(dev);
 
-       if (tmdev->ops && tmdev->ops->suspend)
-               return tmdev->ops->suspend(tmdev);
+       if (priv->ops && priv->ops->suspend)
+               return priv->ops->suspend(priv);
 
        return 0;
 }
 
 static int __maybe_unused tsens_resume(struct device *dev)
 {
-       struct tsens_device *tmdev = dev_get_drvdata(dev);
+       struct tsens_priv *priv = dev_get_drvdata(dev);
 
-       if (tmdev->ops && tmdev->ops->resume)
-               return tmdev->ops->resume(tmdev);
+       if (priv->ops && priv->ops->resume)
+               return priv->ops->resume(priv);
 
        return 0;
 }
@@ -63,6 +63,9 @@ static const struct of_device_id tsens_table[] = {
        }, {
                .compatible = "qcom,msm8996-tsens",
                .data = &data_8996,
+       }, {
+               .compatible = "qcom,tsens-v1",
+               .data = &data_tsens_v1,
        }, {
                .compatible = "qcom,tsens-v2",
                .data = &data_tsens_v2,
@@ -76,22 +79,27 @@ static const struct thermal_zone_of_device_ops tsens_of_ops = {
        .get_trend = tsens_get_trend,
 };
 
-static int tsens_register(struct tsens_device *tmdev)
+static int tsens_register(struct tsens_priv *priv)
 {
        int i;
        struct thermal_zone_device *tzd;
 
-       for (i = 0;  i < tmdev->num_sensors; i++) {
-               tmdev->sensor[i].tmdev = tmdev;
-               tmdev->sensor[i].id = i;
-               tzd = devm_thermal_zone_of_sensor_register(tmdev->dev, i,
-                                                          &tmdev->sensor[i],
+       for (i = 0;  i < priv->num_sensors; i++) {
+               if (!is_sensor_enabled(priv, priv->sensor[i].hw_id)) {
+                       dev_err(priv->dev, "sensor %d: disabled\n",
+                               priv->sensor[i].hw_id);
+                       continue;
+               }
+               priv->sensor[i].priv = priv;
+               priv->sensor[i].id = i;
+               tzd = devm_thermal_zone_of_sensor_register(priv->dev, i,
+                                                          &priv->sensor[i],
                                                           &tsens_of_ops);
                if (IS_ERR(tzd))
                        continue;
-               tmdev->sensor[i].tzd = tzd;
-               if (tmdev->ops->enable)
-                       tmdev->ops->enable(tmdev, i);
+               priv->sensor[i].tzd = tzd;
+               if (priv->ops->enable)
+                       priv->ops->enable(priv, i);
        }
        return 0;
 }
@@ -101,8 +109,8 @@ static int tsens_probe(struct platform_device *pdev)
        int ret, i;
        struct device *dev;
        struct device_node *np;
-       struct tsens_device *tmdev;
-       const struct tsens_data *data;
+       struct tsens_priv *priv;
+       const struct tsens_plat_data *data;
        const struct of_device_id *id;
        u32 num_sensors;
 
@@ -129,55 +137,55 @@ static int tsens_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       tmdev = devm_kzalloc(dev,
-                            struct_size(tmdev, sensor, num_sensors),
+       priv = devm_kzalloc(dev,
+                            struct_size(priv, sensor, num_sensors),
                             GFP_KERNEL);
-       if (!tmdev)
+       if (!priv)
                return -ENOMEM;
 
-       tmdev->dev = dev;
-       tmdev->num_sensors = num_sensors;
-       tmdev->ops = data->ops;
-       for (i = 0;  i < tmdev->num_sensors; i++) {
+       priv->dev = dev;
+       priv->num_sensors = num_sensors;
+       priv->ops = data->ops;
+       for (i = 0;  i < priv->num_sensors; i++) {
                if (data->hw_ids)
-                       tmdev->sensor[i].hw_id = data->hw_ids[i];
+                       priv->sensor[i].hw_id = data->hw_ids[i];
                else
-                       tmdev->sensor[i].hw_id = i;
-       }
-       for (i = 0; i < REG_ARRAY_SIZE; i++) {
-               tmdev->reg_offsets[i] = data->reg_offsets[i];
+                       priv->sensor[i].hw_id = i;
        }
+       priv->feat = data->feat;
+       priv->fields = data->fields;
 
-       if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->get_temp)
+       if (!priv->ops || !priv->ops->init || !priv->ops->get_temp)
                return -EINVAL;
 
-       ret = tmdev->ops->init(tmdev);
+       ret = priv->ops->init(priv);
        if (ret < 0) {
                dev_err(dev, "tsens init failed\n");
                return ret;
        }
 
-       if (tmdev->ops->calibrate) {
-               ret = tmdev->ops->calibrate(tmdev);
+       if (priv->ops->calibrate) {
+               ret = priv->ops->calibrate(priv);
                if (ret < 0) {
-                       dev_err(dev, "tsens calibration failed\n");
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "tsens calibration failed\n");
                        return ret;
                }
        }
 
-       ret = tsens_register(tmdev);
+       ret = tsens_register(priv);
 
-       platform_set_drvdata(pdev, tmdev);
+       platform_set_drvdata(pdev, priv);
 
        return ret;
 }
 
 static int tsens_remove(struct platform_device *pdev)
 {
-       struct tsens_device *tmdev = platform_get_drvdata(pdev);
+       struct tsens_priv *priv = platform_get_drvdata(pdev);
 
-       if (tmdev->ops->disable)
-               tmdev->ops->disable(tmdev);
+       if (priv->ops->disable)
+               priv->ops->disable(priv);
 
        return 0;
 }
index 7b7feee5dc4633b72893ddf36ec69c8405f7c318..eefe3844fb4ef4e0c2391a22e39afd9c5a499ef9 100644 (file)
@@ -9,17 +9,39 @@
 #define ONE_PT_CALIB           0x1
 #define ONE_PT_CALIB2          0x2
 #define TWO_PT_CALIB           0x3
+#define CAL_DEGC_PT1           30
+#define CAL_DEGC_PT2           120
+#define SLOPE_FACTOR           1000
+#define SLOPE_DEFAULT          3200
+
 
 #include <linux/thermal.h>
+#include <linux/regmap.h>
+
+struct tsens_priv;
 
-struct tsens_device;
+enum tsens_ver {
+       VER_0_1 = 0,
+       VER_1_X,
+       VER_2_X,
+};
 
+/**
+ * struct tsens_sensor - data for each sensor connected to the tsens device
+ * @priv: tsens device instance that this sensor is connected to
+ * @tzd: pointer to the thermal zone that this sensor is in
+ * @offset: offset of temperature adjustment curve
+ * @id: Sensor ID
+ * @hw_id: HW ID can be used in case of platform-specific IDs
+ * @slope: slope of temperature adjustment curve
+ * @status: 8960-specific variable to track 8960 and 8660 status register offset
+ */
 struct tsens_sensor {
-       struct tsens_device             *tmdev;
+       struct tsens_priv               *priv;
        struct thermal_zone_device      *tzd;
        int                             offset;
-       int                             id;
-       int                             hw_id;
+       unsigned int                    id;
+       unsigned int                    hw_id;
        int                             slope;
        u32                             status;
 };
@@ -37,63 +59,274 @@ struct tsens_sensor {
  */
 struct tsens_ops {
        /* mandatory callbacks */
-       int (*init)(struct tsens_device *);
-       int (*calibrate)(struct tsens_device *);
-       int (*get_temp)(struct tsens_device *, int, int *);
+       int (*init)(struct tsens_priv *priv);
+       int (*calibrate)(struct tsens_priv *priv);
+       int (*get_temp)(struct tsens_priv *priv, int i, int *temp);
        /* optional callbacks */
-       int (*enable)(struct tsens_device *, int);
-       void (*disable)(struct tsens_device *);
-       int (*suspend)(struct tsens_device *);
-       int (*resume)(struct tsens_device *);
-       int (*get_trend)(struct tsens_device *, int, enum thermal_trend *);
+       int (*enable)(struct tsens_priv *priv, int i);
+       void (*disable)(struct tsens_priv *priv);
+       int (*suspend)(struct tsens_priv *priv);
+       int (*resume)(struct tsens_priv *priv);
+       int (*get_trend)(struct tsens_priv *priv, int i, enum thermal_trend *trend);
 };
 
-enum reg_list {
-       SROT_CTRL_OFFSET,
+#define REG_FIELD_FOR_EACH_SENSOR11(_name, _offset, _startbit, _stopbit) \
+       [_name##_##0]  = REG_FIELD(_offset,      _startbit, _stopbit),  \
+       [_name##_##1]  = REG_FIELD(_offset +  4, _startbit, _stopbit), \
+       [_name##_##2]  = REG_FIELD(_offset +  8, _startbit, _stopbit), \
+       [_name##_##3]  = REG_FIELD(_offset + 12, _startbit, _stopbit), \
+       [_name##_##4]  = REG_FIELD(_offset + 16, _startbit, _stopbit), \
+       [_name##_##5]  = REG_FIELD(_offset + 20, _startbit, _stopbit), \
+       [_name##_##6]  = REG_FIELD(_offset + 24, _startbit, _stopbit), \
+       [_name##_##7]  = REG_FIELD(_offset + 28, _startbit, _stopbit), \
+       [_name##_##8]  = REG_FIELD(_offset + 32, _startbit, _stopbit), \
+       [_name##_##9]  = REG_FIELD(_offset + 36, _startbit, _stopbit), \
+       [_name##_##10] = REG_FIELD(_offset + 40, _startbit, _stopbit)
 
-       REG_ARRAY_SIZE,
+#define REG_FIELD_FOR_EACH_SENSOR16(_name, _offset, _startbit, _stopbit) \
+       [_name##_##0]  = REG_FIELD(_offset,      _startbit, _stopbit),  \
+       [_name##_##1]  = REG_FIELD(_offset +  4, _startbit, _stopbit), \
+       [_name##_##2]  = REG_FIELD(_offset +  8, _startbit, _stopbit), \
+       [_name##_##3]  = REG_FIELD(_offset + 12, _startbit, _stopbit), \
+       [_name##_##4]  = REG_FIELD(_offset + 16, _startbit, _stopbit), \
+       [_name##_##5]  = REG_FIELD(_offset + 20, _startbit, _stopbit), \
+       [_name##_##6]  = REG_FIELD(_offset + 24, _startbit, _stopbit), \
+       [_name##_##7]  = REG_FIELD(_offset + 28, _startbit, _stopbit), \
+       [_name##_##8]  = REG_FIELD(_offset + 32, _startbit, _stopbit), \
+       [_name##_##9]  = REG_FIELD(_offset + 36, _startbit, _stopbit), \
+       [_name##_##10] = REG_FIELD(_offset + 40, _startbit, _stopbit), \
+       [_name##_##11] = REG_FIELD(_offset + 44, _startbit, _stopbit), \
+       [_name##_##12] = REG_FIELD(_offset + 48, _startbit, _stopbit), \
+       [_name##_##13] = REG_FIELD(_offset + 52, _startbit, _stopbit), \
+       [_name##_##14] = REG_FIELD(_offset + 56, _startbit, _stopbit), \
+       [_name##_##15] = REG_FIELD(_offset + 60, _startbit, _stopbit)
+
+/* reg_field IDs to use as an index into an array */
+enum regfield_ids {
+       /* ----- SROT ------ */
+       /* HW_VER */
+       VER_MAJOR = 0,
+       VER_MINOR,
+       VER_STEP,
+       /* CTRL_OFFSET */
+       TSENS_EN =  3,
+       TSENS_SW_RST,
+       SENSOR_EN,
+       CODE_OR_TEMP,
+
+       /* ----- TM ------ */
+       /* STATUS */
+       LAST_TEMP_0 = 7,        /* Last temperature reading */
+       LAST_TEMP_1,
+       LAST_TEMP_2,
+       LAST_TEMP_3,
+       LAST_TEMP_4,
+       LAST_TEMP_5,
+       LAST_TEMP_6,
+       LAST_TEMP_7,
+       LAST_TEMP_8,
+       LAST_TEMP_9,
+       LAST_TEMP_10,
+       LAST_TEMP_11,
+       LAST_TEMP_12,
+       LAST_TEMP_13,
+       LAST_TEMP_14,
+       LAST_TEMP_15,
+       VALID_0 = 23,           /* VALID reading or not */
+       VALID_1,
+       VALID_2,
+       VALID_3,
+       VALID_4,
+       VALID_5,
+       VALID_6,
+       VALID_7,
+       VALID_8,
+       VALID_9,
+       VALID_10,
+       VALID_11,
+       VALID_12,
+       VALID_13,
+       VALID_14,
+       VALID_15,
+       MIN_STATUS_0,           /* MIN threshold violated */
+       MIN_STATUS_1,
+       MIN_STATUS_2,
+       MIN_STATUS_3,
+       MIN_STATUS_4,
+       MIN_STATUS_5,
+       MIN_STATUS_6,
+       MIN_STATUS_7,
+       MIN_STATUS_8,
+       MIN_STATUS_9,
+       MIN_STATUS_10,
+       MIN_STATUS_11,
+       MIN_STATUS_12,
+       MIN_STATUS_13,
+       MIN_STATUS_14,
+       MIN_STATUS_15,
+       MAX_STATUS_0,           /* MAX threshold violated */
+       MAX_STATUS_1,
+       MAX_STATUS_2,
+       MAX_STATUS_3,
+       MAX_STATUS_4,
+       MAX_STATUS_5,
+       MAX_STATUS_6,
+       MAX_STATUS_7,
+       MAX_STATUS_8,
+       MAX_STATUS_9,
+       MAX_STATUS_10,
+       MAX_STATUS_11,
+       MAX_STATUS_12,
+       MAX_STATUS_13,
+       MAX_STATUS_14,
+       MAX_STATUS_15,
+       LOWER_STATUS_0, /* LOWER threshold violated */
+       LOWER_STATUS_1,
+       LOWER_STATUS_2,
+       LOWER_STATUS_3,
+       LOWER_STATUS_4,
+       LOWER_STATUS_5,
+       LOWER_STATUS_6,
+       LOWER_STATUS_7,
+       LOWER_STATUS_8,
+       LOWER_STATUS_9,
+       LOWER_STATUS_10,
+       LOWER_STATUS_11,
+       LOWER_STATUS_12,
+       LOWER_STATUS_13,
+       LOWER_STATUS_14,
+       LOWER_STATUS_15,
+       UPPER_STATUS_0, /* UPPER threshold violated */
+       UPPER_STATUS_1,
+       UPPER_STATUS_2,
+       UPPER_STATUS_3,
+       UPPER_STATUS_4,
+       UPPER_STATUS_5,
+       UPPER_STATUS_6,
+       UPPER_STATUS_7,
+       UPPER_STATUS_8,
+       UPPER_STATUS_9,
+       UPPER_STATUS_10,
+       UPPER_STATUS_11,
+       UPPER_STATUS_12,
+       UPPER_STATUS_13,
+       UPPER_STATUS_14,
+       UPPER_STATUS_15,
+       CRITICAL_STATUS_0,      /* CRITICAL threshold violated */
+       CRITICAL_STATUS_1,
+       CRITICAL_STATUS_2,
+       CRITICAL_STATUS_3,
+       CRITICAL_STATUS_4,
+       CRITICAL_STATUS_5,
+       CRITICAL_STATUS_6,
+       CRITICAL_STATUS_7,
+       CRITICAL_STATUS_8,
+       CRITICAL_STATUS_9,
+       CRITICAL_STATUS_10,
+       CRITICAL_STATUS_11,
+       CRITICAL_STATUS_12,
+       CRITICAL_STATUS_13,
+       CRITICAL_STATUS_14,
+       CRITICAL_STATUS_15,
+       /* TRDY */
+       TRDY,
+       /* INTERRUPT ENABLE */
+       INT_EN, /* Pre-V1, V1.x */
+       LOW_INT_EN,     /* V2.x */
+       UP_INT_EN,      /* V2.x */
+       CRIT_INT_EN,    /* V2.x */
+
+       /* Keep last */
+       MAX_REGFIELDS
 };
 
 /**
- * struct tsens_data - tsens instance specific data
- * @num_sensors: Max number of sensors supported by platform
+ * struct tsens_features - Features supported by the IP
+ * @ver_major: Major number of IP version
+ * @crit_int: does the IP support critical interrupts?
+ * @adc:      do the sensors only output adc code (instead of temperature)?
+ * @srot_split: does the IP neatly splits the register space into SROT and TM,
+ *              with SROT only being available to secure boot firmware?
+ * @max_sensors: maximum sensors supported by this version of the IP
+ */
+struct tsens_features {
+       unsigned int ver_major;
+       unsigned int crit_int:1;
+       unsigned int adc:1;
+       unsigned int srot_split:1;
+       unsigned int max_sensors;
+};
+
+/**
+ * struct tsens_plat_data - tsens compile-time platform data
+ * @num_sensors: Number of sensors supported by platform
  * @ops: operations the tsens instance supports
  * @hw_ids: Subset of sensors ids supported by platform, if not the first n
- * @reg_offsets: Register offsets for commonly used registers
+ * @feat: features of the IP
+ * @fields: bitfield locations
  */
-struct tsens_data {
+struct tsens_plat_data {
        const u32               num_sensors;
        const struct tsens_ops  *ops;
-       const u16               reg_offsets[REG_ARRAY_SIZE];
        unsigned int            *hw_ids;
+       const struct tsens_features     *feat;
+       const struct reg_field          *fields;
 };
 
-/* Registers to be saved/restored across a context loss */
+/**
+ * struct tsens_context - Registers to be saved/restored across a context loss
+ */
 struct tsens_context {
        int     threshold;
        int     control;
 };
 
-struct tsens_device {
+/**
+ * struct tsens_priv - private data for each instance of the tsens IP
+ * @dev: pointer to struct device
+ * @num_sensors: number of sensors enabled on this device
+ * @tm_map: pointer to TM register address space
+ * @srot_map: pointer to SROT register address space
+ * @tm_offset: deal with old device trees that don't address TM and SROT
+ *             address space separately
+ * @rf: array of regmap_fields used to store value of the field
+ * @ctx: registers to be saved and restored during suspend/resume
+ * @feat: features of the IP
+ * @fields: bitfield locations
+ * @ops: pointer to list of callbacks supported by this device
+ * @sensor: list of sensors attached to this device
+ */
+struct tsens_priv {
        struct device                   *dev;
        u32                             num_sensors;
        struct regmap                   *tm_map;
        struct regmap                   *srot_map;
        u32                             tm_offset;
-       u16                             reg_offsets[REG_ARRAY_SIZE];
+       struct regmap_field             *rf[MAX_REGFIELDS];
        struct tsens_context            ctx;
+       const struct tsens_features     *feat;
+       const struct reg_field          *fields;
        const struct tsens_ops          *ops;
        struct tsens_sensor             sensor[0];
 };
 
-char *qfprom_read(struct device *, const char *);
-void compute_intercept_slope(struct tsens_device *, u32 *, u32 *, u32);
-int init_common(struct tsens_device *);
-int get_temp_common(struct tsens_device *, int, int *);
+char *qfprom_read(struct device *dev, const char *cname);
+void compute_intercept_slope(struct tsens_priv *priv, u32 *pt1, u32 *pt2, u32 mode);
+int init_common(struct tsens_priv *priv);
+int get_temp_tsens_valid(struct tsens_priv *priv, int i, int *temp);
+int get_temp_common(struct tsens_priv *priv, int i, int *temp);
+bool is_sensor_enabled(struct tsens_priv *priv, u32 hw_id);
+
+/* TSENS target */
+extern const struct tsens_plat_data data_8960;
+
+/* TSENS v0.1 targets */
+extern const struct tsens_plat_data data_8916, data_8974;
 
 /* TSENS v1 targets */
-extern const struct tsens_data data_8916, data_8974, data_8960;
+extern const struct tsens_plat_data data_tsens_v1;
+
 /* TSENS v2 targets */
-extern const struct tsens_data data_8996, data_tsens_v2;
+extern const struct tsens_plat_data data_8996, data_tsens_v2;
 
 #endif /* __QCOM_TSENS_H__ */
index 3b5f5b3fb1bc9b94e5aa73032cb60bede1d12190..7b364933bfb18b2d863f7f869fbe78199ee2ca81 100644 (file)
@@ -193,11 +193,6 @@ static int qoriq_tmu_probe(struct platform_device *pdev)
        struct qoriq_tmu_data *data;
        struct device_node *np = pdev->dev.of_node;
 
-       if (!np) {
-               dev_err(&pdev->dev, "Device OF-Node is NULL");
-               return -ENODEV;
-       }
-
        data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data),
                            GFP_KERNEL);
        if (!data)
index 88fa41cf16e83e67f670295988897542e90bb7d9..83f306265ee192c17b79ec94c1431f09fa42c734 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
-#include <linux/spinlock.h>
 #include <linux/sys_soc.h>
 #include <linux/thermal.h>
 
@@ -82,7 +81,6 @@ struct rcar_gen3_thermal_tsc {
 struct rcar_gen3_thermal_priv {
        struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
        unsigned int num_tscs;
-       spinlock_t lock; /* Protect interrupts on and off */
        void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc);
 };
 
@@ -232,38 +230,16 @@ static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
 {
        struct rcar_gen3_thermal_priv *priv = data;
        u32 status;
-       int i, ret = IRQ_HANDLED;
+       int i;
 
-       spin_lock(&priv->lock);
        for (i = 0; i < priv->num_tscs; i++) {
                status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR);
                rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0);
                if (status)
-                       ret = IRQ_WAKE_THREAD;
+                       thermal_zone_device_update(priv->tscs[i]->zone,
+                                                  THERMAL_EVENT_UNSPECIFIED);
        }
 
-       if (ret == IRQ_WAKE_THREAD)
-               rcar_thermal_irq_set(priv, false);
-
-       spin_unlock(&priv->lock);
-
-       return ret;
-}
-
-static irqreturn_t rcar_gen3_thermal_irq_thread(int irq, void *data)
-{
-       struct rcar_gen3_thermal_priv *priv = data;
-       unsigned long flags;
-       int i;
-
-       for (i = 0; i < priv->num_tscs; i++)
-               thermal_zone_device_update(priv->tscs[i]->zone,
-                                          THERMAL_EVENT_UNSPECIFIED);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       rcar_thermal_irq_set(priv, true);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
        return IRQ_HANDLED;
 }
 
@@ -307,7 +283,7 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
 
        usleep_range(1000, 2000);
 
-       rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
+       rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0);
        rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
        rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2);
 
@@ -331,6 +307,9 @@ MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
 static int rcar_gen3_thermal_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
+
+       rcar_thermal_irq_set(priv, false);
 
        pm_runtime_put(dev);
        pm_runtime_disable(dev);
@@ -371,8 +350,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
        if (soc_device_match(r8a7795es1))
                priv->thermal_init = rcar_gen3_thermal_init_r8a7795es1;
 
-       spin_lock_init(&priv->lock);
-
        platform_set_drvdata(pdev, priv);
 
        /*
@@ -390,9 +367,9 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
                if (!irqname)
                        return -ENOMEM;
 
-               ret = devm_request_threaded_irq(dev, irq, rcar_gen3_thermal_irq,
-                                               rcar_gen3_thermal_irq_thread,
-                                               IRQF_SHARED, irqname, priv);
+               ret = devm_request_threaded_irq(dev, irq, NULL,
+                                               rcar_gen3_thermal_irq,
+                                               IRQF_ONESHOT, irqname, priv);
                if (ret)
                        return ret;
        }
@@ -433,10 +410,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
                }
                tsc->zone = zone;
 
-               ret = of_thermal_get_ntrips(tsc->zone);
-               if (ret < 0)
-                       goto error_unregister;
-
                tsc->zone->tzp->no_hwmon = false;
                ret = thermal_add_hwmon_sysfs(tsc->zone);
                if (ret)
@@ -448,6 +421,10 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
                        goto error_unregister;
                }
 
+               ret = of_thermal_get_ntrips(tsc->zone);
+               if (ret < 0)
+                       goto error_unregister;
+
                dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret);
        }
 
index 97462e9b40d8b8da91694aca523f4dde5796d963..d0873de718da92189d57b1510a72dac504ef77cf 100644 (file)
@@ -52,6 +52,7 @@ struct rcar_thermal_chip {
        unsigned int irq_per_ch : 1;
        unsigned int needs_suspend_resume : 1;
        unsigned int nirqs;
+       unsigned int ctemp_bands;
 };
 
 static const struct rcar_thermal_chip rcar_thermal = {
@@ -60,6 +61,7 @@ static const struct rcar_thermal_chip rcar_thermal = {
        .irq_per_ch = 0,
        .needs_suspend_resume = 0,
        .nirqs = 1,
+       .ctemp_bands = 1,
 };
 
 static const struct rcar_thermal_chip rcar_gen2_thermal = {
@@ -68,6 +70,7 @@ static const struct rcar_thermal_chip rcar_gen2_thermal = {
        .irq_per_ch = 0,
        .needs_suspend_resume = 0,
        .nirqs = 1,
+       .ctemp_bands = 1,
 };
 
 static const struct rcar_thermal_chip rcar_gen3_thermal = {
@@ -80,6 +83,7 @@ static const struct rcar_thermal_chip rcar_gen3_thermal = {
         * interrupts to detect a temperature change, rise or fall.
         */
        .nirqs = 2,
+       .ctemp_bands = 2,
 };
 
 struct rcar_thermal_priv {
@@ -263,7 +267,12 @@ static int rcar_thermal_get_current_temp(struct rcar_thermal_priv *priv,
                return ret;
 
        mutex_lock(&priv->lock);
-       tmp =  MCELSIUS((priv->ctemp * 5) - 65);
+       if (priv->chip->ctemp_bands == 1)
+               tmp = MCELSIUS((priv->ctemp * 5) - 65);
+       else if (priv->ctemp < 24)
+               tmp = MCELSIUS(((priv->ctemp * 55) - 720) / 10);
+       else
+               tmp = MCELSIUS((priv->ctemp * 5) - 60);
        mutex_unlock(&priv->lock);
 
        if ((tmp < MCELSIUS(-45)) || (tmp > MCELSIUS(125))) {
index 9c7643d62ed70782e35a7807f90692e9c47670b2..bda1ca199abd3f9cbbe3a8195d9ae93a61036139 100644 (file)
@@ -172,6 +172,9 @@ struct rockchip_thermal_data {
        int tshut_temp;
        enum tshut_mode tshut_mode;
        enum tshut_polarity tshut_polarity;
+       struct pinctrl *pinctrl;
+       struct pinctrl_state *gpio_state;
+       struct pinctrl_state *otp_state;
 };
 
 /**
@@ -222,11 +225,15 @@ struct rockchip_thermal_data {
 #define GRF_TSADC_TESTBIT_L                    0x0e648
 #define GRF_TSADC_TESTBIT_H                    0x0e64c
 
+#define PX30_GRF_SOC_CON2                      0x0408
+
 #define GRF_SARADC_TESTBIT_ON                  (0x10001 << 2)
 #define GRF_TSADC_TESTBIT_H_ON                 (0x10001 << 2)
 #define GRF_TSADC_VCM_EN_L                     (0x10001 << 7)
 #define GRF_TSADC_VCM_EN_H                     (0x10001 << 7)
 
+#define GRF_CON_TSADC_CH_INV                   (0x10001 << 1)
+
 /**
  * struct tsadc_table - code to temperature conversion table
  * @code: the value of adc channel
@@ -689,6 +696,13 @@ static void rk_tsadcv3_initialize(struct regmap *grf, void __iomem *regs,
                               regs + TSADCV2_AUTO_CON);
 }
 
+static void rk_tsadcv4_initialize(struct regmap *grf, void __iomem *regs,
+                                 enum tshut_polarity tshut_polarity)
+{
+       rk_tsadcv2_initialize(grf, regs, tshut_polarity);
+       regmap_write(grf, PX30_GRF_SOC_CON2, GRF_CON_TSADC_CH_INV);
+}
+
 static void rk_tsadcv2_irq_ack(void __iomem *regs)
 {
        u32 val;
@@ -818,6 +832,30 @@ static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs,
        writel_relaxed(val, regs + TSADCV2_INT_EN);
 }
 
+static const struct rockchip_tsadc_chip px30_tsadc_data = {
+       .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */
+       .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */
+       .chn_num = 2, /* 2 channels for tsadc */
+
+       .tshut_mode = TSHUT_MODE_CRU, /* default TSHUT via CRU */
+       .tshut_temp = 95000,
+
+       .initialize = rk_tsadcv4_initialize,
+       .irq_ack = rk_tsadcv3_irq_ack,
+       .control = rk_tsadcv3_control,
+       .get_temp = rk_tsadcv2_get_temp,
+       .set_alarm_temp = rk_tsadcv2_alarm_temp,
+       .set_tshut_temp = rk_tsadcv2_tshut_temp,
+       .set_tshut_mode = rk_tsadcv2_tshut_mode,
+
+       .table = {
+               .id = rk3328_code_table,
+               .length = ARRAY_SIZE(rk3328_code_table),
+               .data_mask = TSADCV2_DATA_MASK,
+               .mode = ADC_INCREMENT,
+       },
+};
+
 static const struct rockchip_tsadc_chip rv1108_tsadc_data = {
        .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */
        .chn_num = 1, /* one channel for tsadc */
@@ -990,6 +1028,9 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = {
 };
 
 static const struct of_device_id of_rockchip_thermal_match[] = {
+       {       .compatible = "rockchip,px30-tsadc",
+               .data = (void *)&px30_tsadc_data,
+       },
        {
                .compatible = "rockchip,rv1108-tsadc",
                .data = (void *)&rv1108_tsadc_data,
@@ -1242,6 +1283,8 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
                return error;
        }
 
+       thermal->chip->control(thermal->regs, false);
+
        error = clk_prepare_enable(thermal->clk);
        if (error) {
                dev_err(&pdev->dev, "failed to enable converter clock: %d\n",
@@ -1267,6 +1310,30 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
        thermal->chip->initialize(thermal->grf, thermal->regs,
                                  thermal->tshut_polarity);
 
+       if (thermal->tshut_mode == TSHUT_MODE_GPIO) {
+               thermal->pinctrl = devm_pinctrl_get(&pdev->dev);
+               if (IS_ERR(thermal->pinctrl)) {
+                       dev_err(&pdev->dev, "failed to find thermal pinctrl\n");
+                       return PTR_ERR(thermal->pinctrl);
+               }
+
+               thermal->gpio_state = pinctrl_lookup_state(thermal->pinctrl,
+                                                          "gpio");
+               if (IS_ERR_OR_NULL(thermal->gpio_state)) {
+                       dev_err(&pdev->dev, "failed to find thermal gpio state\n");
+                       return -EINVAL;
+               }
+
+               thermal->otp_state = pinctrl_lookup_state(thermal->pinctrl,
+                                                         "otpout");
+               if (IS_ERR_OR_NULL(thermal->otp_state)) {
+                       dev_err(&pdev->dev, "failed to find thermal otpout state\n");
+                       return -EINVAL;
+               }
+
+               pinctrl_select_state(thermal->pinctrl, thermal->otp_state);
+       }
+
        for (i = 0; i < thermal->chip->chn_num; i++) {
                error = rockchip_thermal_register_sensor(pdev, thermal,
                                                &thermal->sensors[i],
@@ -1337,8 +1404,8 @@ static int __maybe_unused rockchip_thermal_suspend(struct device *dev)
 
        clk_disable(thermal->pclk);
        clk_disable(thermal->clk);
-
-       pinctrl_pm_select_sleep_state(dev);
+       if (thermal->tshut_mode == TSHUT_MODE_GPIO)
+               pinctrl_select_state(thermal->pinctrl, thermal->gpio_state);
 
        return 0;
 }
@@ -1383,7 +1450,8 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev)
        for (i = 0; i < thermal->chip->chn_num; i++)
                rockchip_thermal_toggle_sensor(&thermal->sensors[i], true);
 
-       pinctrl_pm_select_default_state(dev);
+       if (thermal->tshut_mode == TSHUT_MODE_GPIO)
+               pinctrl_select_state(thermal->pinctrl, thermal->otp_state);
 
        return 0;
 }
index b80f9a9e4f8f603dd822d90a9154dea96fafcb6d..d8b1a4586d0bf28812d536e8a0c2dbcfe3f7ba23 100644 (file)
@@ -3,9 +3,9 @@
 #
 
 config ST_THERMAL
-       tristate "Thermal sensors on STMicroelectronics STi series of SoCs"
-       help
-         Support for thermal sensors on STMicroelectronics STi series of SoCs.
+       tristate "Thermal sensors on STMicroelectronics STi series of SoCs"
+       help
+         Support for thermal sensors on STMicroelectronics STi series of SoCs.
 
 config ST_THERMAL_SYSCFG
        select ST_THERMAL
@@ -16,11 +16,11 @@ config ST_THERMAL_MEMMAP
        tristate "STi series memory mapped access based thermal sensors"
 
 config STM32_THERMAL
-       tristate "Thermal framework support on STMicroelectronics STM32 series of SoCs"
-       depends on MACH_STM32MP157
-       default y
-       help
-       Support for thermal framework on STMicroelectronics STM32 series of
-       SoCs. This thermal driver allows to access to general thermal framework
-       functionalities and to acces to SoC sensor functionalities. This
-       configuration is fully dependent of MACH_STM32MP157.
+       tristate "Thermal framework support on STMicroelectronics STM32 series of SoCs"
+       depends on MACH_STM32MP157
+       default y
+       help
+         Support for thermal framework on STMicroelectronics STM32 series of
+         SoCs. This thermal driver allows to access to general thermal framework
+         functionalities and to acces to SoC sensor functionalities. This
+         configuration is fully dependent of MACH_STM32MP157.
index bbd73c5a4a4e92f4c3d361f129e7ec7d409a6d94..cf9ddc52f30e1735ea6d583de562624df68df757 100644 (file)
@@ -570,8 +570,7 @@ thermal_unprepare:
 static int stm_thermal_suspend(struct device *dev)
 {
        int ret;
-       struct platform_device *pdev = to_platform_device(dev);
-       struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
+       struct stm_thermal_sensor *sensor = dev_get_drvdata(dev);
 
        ret = stm_thermal_sensor_off(sensor);
        if (ret)
@@ -585,8 +584,7 @@ static int stm_thermal_suspend(struct device *dev)
 static int stm_thermal_resume(struct device *dev)
 {
        int ret;
-       struct platform_device *pdev = to_platform_device(dev);
-       struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
+       struct stm_thermal_sensor *sensor = dev_get_drvdata(dev);
 
        ret = stm_thermal_prepare(sensor);
        if (ret)
index f8740f7852e3b8bd52cf6c5088a9a27a31d290c9..fc0b33b3f26bd5cc346e08c07f295a4d5295f837 100644 (file)
@@ -14,7 +14,7 @@ config TEGRA_BPMP_THERMAL
        tristate "Tegra BPMP thermal sensing"
        depends on TEGRA_BPMP || COMPILE_TEST
        help
-        Enable this option for support for sensing system temperature of NVIDIA
-        Tegra systems-on-chip with the BPMP coprocessor (Tegra186).
+         Enable this option for support for sensing system temperature of NVIDIA
+         Tegra systems-on-chip with the BPMP coprocessor (Tegra186).
 
 endmenu
index 70043a28eb7a1d91956eb808eb1b0a9fede3960c..fcf70a3728b60451ce5153baa039f16c2b8d3943 100644 (file)
@@ -1,5 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2014 - 2018, NVIDIA CORPORATION.  All rights reserved.
  *
  * Author:
  *     Mikko Perttunen <mperttunen@nvidia.com>
@@ -22,6 +23,8 @@
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #define THERMCTL_LVL0_UP_STATS                 0x10
 #define THERMCTL_LVL0_DN_STATS                 0x14
 
+#define THERMCTL_INTR_STATUS                   0x84
+
+#define TH_INTR_MD0_MASK                       BIT(25)
+#define TH_INTR_MU0_MASK                       BIT(24)
+#define TH_INTR_GD0_MASK                       BIT(17)
+#define TH_INTR_GU0_MASK                       BIT(16)
+#define TH_INTR_CD0_MASK                       BIT(9)
+#define TH_INTR_CU0_MASK                       BIT(8)
+#define TH_INTR_PD0_MASK                       BIT(1)
+#define TH_INTR_PU0_MASK                       BIT(0)
+#define TH_INTR_IGNORE_MASK                    0xFCFCFCFC
+
 #define THERMCTL_STATS_CTL                     0x94
 #define STATS_CTL_CLR_DN                       0x8
 #define STATS_CTL_EN_DN                                0x4
 #define STATS_CTL_CLR_UP                       0x2
 #define STATS_CTL_EN_UP                                0x1
 
+#define OC1_CFG                                        0x310
+#define OC1_CFG_LONG_LATENCY_MASK              BIT(6)
+#define OC1_CFG_HW_RESTORE_MASK                        BIT(5)
+#define OC1_CFG_PWR_GOOD_MASK_MASK             BIT(4)
+#define OC1_CFG_THROTTLE_MODE_MASK             (0x3 << 2)
+#define OC1_CFG_ALARM_POLARITY_MASK            BIT(1)
+#define OC1_CFG_EN_THROTTLE_MASK               BIT(0)
+
+#define OC1_CNT_THRESHOLD                      0x314
+#define OC1_THROTTLE_PERIOD                    0x318
+#define OC1_ALARM_COUNT                                0x31c
+#define OC1_FILTER                             0x320
+#define OC1_STATS                              0x3a8
+
+#define OC_INTR_STATUS                         0x39c
+#define OC_INTR_ENABLE                         0x3a0
+#define OC_INTR_DISABLE                                0x3a4
+#define OC_STATS_CTL                           0x3c4
+#define OC_STATS_CTL_CLR_ALL                   0x2
+#define OC_STATS_CTL_EN_ALL                    0x1
+
+#define OC_INTR_OC1_MASK                       BIT(0)
+#define OC_INTR_OC2_MASK                       BIT(1)
+#define OC_INTR_OC3_MASK                       BIT(2)
+#define OC_INTR_OC4_MASK                       BIT(3)
+#define OC_INTR_OC5_MASK                       BIT(4)
+
 #define THROT_GLOBAL_CFG                       0x400
 #define THROT_GLOBAL_ENB_MASK                  BIT(0)
 
 /* get dividend from the depth */
 #define THROT_DEPTH_DIVIDEND(depth)    ((256 * (100 - (depth)) / 100) - 1)
 
+/* gk20a nv_therm interface N:3 Mapping. Levels defined in tegra124-sochterm.h
+ * level       vector
+ * NONE                3'b000
+ * LOW         3'b001
+ * MED         3'b011
+ * HIGH                3'b111
+ */
+#define THROT_LEVEL_TO_DEPTH(level)    ((0x1 << (level)) - 1)
+
 /* get THROT_PSKIP_xxx offset per LIGHT/HEAVY throt and CPU/GPU dev */
 #define THROT_OFFSET                   0x30
 #define THROT_PSKIP_CTRL(throt, dev)   (THROT_PSKIP_CTRL_LITE_CPU + \
 #define THROT_DELAY_CTRL(throt)                (THROT_DELAY_LITE + \
                                        (THROT_OFFSET * throt))
 
+#define ALARM_OFFSET                   0x14
+#define ALARM_CFG(throt)               (OC1_CFG + \
+                                       (ALARM_OFFSET * (throt - THROTTLE_OC1)))
+
+#define ALARM_CNT_THRESHOLD(throt)     (OC1_CNT_THRESHOLD + \
+                                       (ALARM_OFFSET * (throt - THROTTLE_OC1)))
+
+#define ALARM_THROTTLE_PERIOD(throt)   (OC1_THROTTLE_PERIOD + \
+                                       (ALARM_OFFSET * (throt - THROTTLE_OC1)))
+
+#define ALARM_ALARM_COUNT(throt)       (OC1_ALARM_COUNT + \
+                                       (ALARM_OFFSET * (throt - THROTTLE_OC1)))
+
+#define ALARM_FILTER(throt)            (OC1_FILTER + \
+                                       (ALARM_OFFSET * (throt - THROTTLE_OC1)))
+
+#define ALARM_STATS(throt)             (OC1_STATS + \
+                                       (4 * (throt - THROTTLE_OC1)))
+
 /* get CCROC_THROT_PSKIP_xxx offset per HIGH/MED/LOW vect*/
 #define CCROC_THROT_OFFSET                     0x0c
 #define CCROC_THROT_PSKIP_CTRL_CPU_REG(vect)    (CCROC_THROT_PSKIP_CTRL_CPU + \
 #define THERMCTL_LVL_REGS_SIZE         0x20
 #define THERMCTL_LVL_REG(rg, lv)       ((rg) + ((lv) * THERMCTL_LVL_REGS_SIZE))
 
+#define OC_THROTTLE_MODE_DISABLED      0
+#define OC_THROTTLE_MODE_BRIEF         2
+
 static const int min_low_temp = -127000;
 static const int max_high_temp = 127000;
 
 enum soctherm_throttle_id {
        THROTTLE_LIGHT = 0,
        THROTTLE_HEAVY,
+       THROTTLE_OC1,
+       THROTTLE_OC2,
+       THROTTLE_OC3,
+       THROTTLE_OC4,
+       THROTTLE_OC5, /* OC5 is reserved */
        THROTTLE_SIZE,
 };
 
+enum soctherm_oc_irq_id {
+       TEGRA_SOC_OC_IRQ_1,
+       TEGRA_SOC_OC_IRQ_2,
+       TEGRA_SOC_OC_IRQ_3,
+       TEGRA_SOC_OC_IRQ_4,
+       TEGRA_SOC_OC_IRQ_5,
+       TEGRA_SOC_OC_IRQ_MAX,
+};
+
 enum soctherm_throttle_dev_id {
        THROTTLE_DEV_CPU = 0,
        THROTTLE_DEV_GPU,
@@ -202,6 +289,11 @@ enum soctherm_throttle_dev_id {
 static const char *const throt_names[] = {
        [THROTTLE_LIGHT] = "light",
        [THROTTLE_HEAVY] = "heavy",
+       [THROTTLE_OC1]   = "oc1",
+       [THROTTLE_OC2]   = "oc2",
+       [THROTTLE_OC3]   = "oc3",
+       [THROTTLE_OC4]   = "oc4",
+       [THROTTLE_OC5]   = "oc5",
 };
 
 struct tegra_soctherm;
@@ -213,12 +305,23 @@ struct tegra_thermctl_zone {
        const struct tegra_tsensor_group *sg;
 };
 
+struct soctherm_oc_cfg {
+       u32 active_low;
+       u32 throt_period;
+       u32 alarm_cnt_thresh;
+       u32 alarm_filter;
+       u32 mode;
+       bool intr_en;
+};
+
 struct soctherm_throt_cfg {
        const char *name;
        unsigned int id;
        u8 priority;
        u8 cpu_throt_level;
        u32 cpu_throt_depth;
+       u32 gpu_throt_level;
+       struct soctherm_oc_cfg oc_cfg;
        struct thermal_cooling_device *cdev;
        bool init;
 };
@@ -231,6 +334,9 @@ struct tegra_soctherm {
        void __iomem *clk_regs;
        void __iomem *ccroc_regs;
 
+       int thermal_irq;
+       int edp_irq;
+
        u32 *calib;
        struct thermal_zone_device **thermctl_tzs;
        struct tegra_soctherm_soc *soc;
@@ -238,8 +344,19 @@ struct tegra_soctherm {
        struct soctherm_throt_cfg throt_cfgs[THROTTLE_SIZE];
 
        struct dentry *debugfs_dir;
+
+       struct mutex thermctl_lock;
 };
 
+struct soctherm_oc_irq_chip_data {
+       struct mutex            irq_lock; /* serialize OC IRQs */
+       struct irq_chip         irq_chip;
+       struct irq_domain       *domain;
+       int                     irq_enable;
+};
+
+static struct soctherm_oc_irq_chip_data soc_irq_cdata;
+
 /**
  * ccroc_writel() - writes a value to a CCROC register
  * @ts: pointer to a struct tegra_soctherm
@@ -446,6 +563,24 @@ find_throttle_cfg_by_name(struct tegra_soctherm *ts, const char *name)
        return NULL;
 }
 
+static int tsensor_group_thermtrip_get(struct tegra_soctherm *ts, int id)
+{
+       int i, temp = min_low_temp;
+       struct tsensor_group_thermtrips *tt = ts->soc->thermtrips;
+
+       if (id >= TEGRA124_SOCTHERM_SENSOR_NUM)
+               return temp;
+
+       if (tt) {
+               for (i = 0; i < ts->soc->num_ttgs; i++) {
+                       if (tt[i].id == id)
+                               return tt[i].temp;
+               }
+       }
+
+       return temp;
+}
+
 static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp)
 {
        struct tegra_thermctl_zone *zone = data;
@@ -464,7 +599,16 @@ static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp)
                return ret;
 
        if (type == THERMAL_TRIP_CRITICAL) {
-               return thermtrip_program(dev, sg, temp);
+               /*
+                * If thermtrips property is set in DT,
+                * doesn't need to program critical type trip to HW,
+                * if not, program critical trip to HW.
+                */
+               if (min_low_temp == tsensor_group_thermtrip_get(ts, sg->id))
+                       return thermtrip_program(dev, sg, temp);
+               else
+                       return 0;
+
        } else if (type == THERMAL_TRIP_HOT) {
                int i;
 
@@ -519,10 +663,60 @@ static int tegra_thermctl_get_trend(void *data, int trip,
        return 0;
 }
 
+static void thermal_irq_enable(struct tegra_thermctl_zone *zn)
+{
+       u32 r;
+
+       /* multiple zones could be handling and setting trips at once */
+       mutex_lock(&zn->ts->thermctl_lock);
+       r = readl(zn->ts->regs + THERMCTL_INTR_ENABLE);
+       r = REG_SET_MASK(r, zn->sg->thermctl_isr_mask, TH_INTR_UP_DN_EN);
+       writel(r, zn->ts->regs + THERMCTL_INTR_ENABLE);
+       mutex_unlock(&zn->ts->thermctl_lock);
+}
+
+static void thermal_irq_disable(struct tegra_thermctl_zone *zn)
+{
+       u32 r;
+
+       /* multiple zones could be handling and setting trips at once */
+       mutex_lock(&zn->ts->thermctl_lock);
+       r = readl(zn->ts->regs + THERMCTL_INTR_DISABLE);
+       r = REG_SET_MASK(r, zn->sg->thermctl_isr_mask, 0);
+       writel(r, zn->ts->regs + THERMCTL_INTR_DISABLE);
+       mutex_unlock(&zn->ts->thermctl_lock);
+}
+
+static int tegra_thermctl_set_trips(void *data, int lo, int hi)
+{
+       struct tegra_thermctl_zone *zone = data;
+       u32 r;
+
+       thermal_irq_disable(zone);
+
+       r = readl(zone->ts->regs + zone->sg->thermctl_lvl0_offset);
+       r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_EN_MASK, 0);
+       writel(r, zone->ts->regs + zone->sg->thermctl_lvl0_offset);
+
+       lo = enforce_temp_range(zone->dev, lo) / zone->ts->soc->thresh_grain;
+       hi = enforce_temp_range(zone->dev, hi) / zone->ts->soc->thresh_grain;
+       dev_dbg(zone->dev, "%s hi:%d, lo:%d\n", __func__, hi, lo);
+
+       r = REG_SET_MASK(r, zone->sg->thermctl_lvl0_up_thresh_mask, hi);
+       r = REG_SET_MASK(r, zone->sg->thermctl_lvl0_dn_thresh_mask, lo);
+       r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_EN_MASK, 1);
+       writel(r, zone->ts->regs + zone->sg->thermctl_lvl0_offset);
+
+       thermal_irq_enable(zone);
+
+       return 0;
+}
+
 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,
 };
 
 static int get_hot_temp(struct thermal_zone_device *tz, int *trip, int *temp)
@@ -555,7 +749,8 @@ static int get_hot_temp(struct thermal_zone_device *tz, int *trip, int *temp)
  * @dev: struct device * of the SOC_THERM instance
  *
  * Configure the SOC_THERM HW trip points, setting "THERMTRIP"
- * "THROTTLE" trip points , using "critical" or "hot" type trip_temp
+ * "THROTTLE" trip points , using "thermtrips", "critical" or "hot"
+ * type trip_temp
  * from thermal zone.
  * After they have been configured, THERMTRIP or THROTTLE will take
  * action when the configured SoC thermal sensor group reaches a
@@ -577,28 +772,23 @@ static int tegra_soctherm_set_hwtrips(struct device *dev,
 {
        struct tegra_soctherm *ts = dev_get_drvdata(dev);
        struct soctherm_throt_cfg *stc;
-       int i, trip, temperature;
-       int ret;
+       int i, trip, temperature, ret;
 
-       ret = tz->ops->get_crit_temp(tz, &temperature);
-       if (ret) {
-               dev_warn(dev, "thermtrip: %s: missing critical temperature\n",
-                        sg->name);
-               goto set_throttle;
-       }
+       /* Get thermtrips. If missing, try to get critical trips. */
+       temperature = tsensor_group_thermtrip_get(ts, sg->id);
+       if (min_low_temp == temperature)
+               if (tz->ops->get_crit_temp(tz, &temperature))
+                       temperature = max_high_temp;
 
        ret = thermtrip_program(dev, sg, temperature);
        if (ret) {
-               dev_err(dev, "thermtrip: %s: error during enable\n",
-                       sg->name);
+               dev_err(dev, "thermtrip: %s: error during enable\n", sg->name);
                return ret;
        }
 
-       dev_info(dev,
-                "thermtrip: will shut down when %s reaches %d mC\n",
+       dev_info(dev, "thermtrip: will shut down when %s reaches %d mC\n",
                 sg->name, temperature);
 
-set_throttle:
        ret = get_hot_temp(tz, &trip, &temperature);
        if (ret) {
                dev_info(dev, "throttrip: %s: missing hot temperature\n",
@@ -606,7 +796,7 @@ set_throttle:
                return 0;
        }
 
-       for (i = 0; i < THROTTLE_SIZE; i++) {
+       for (i = 0; i < THROTTLE_OC1; i++) {
                struct thermal_cooling_device *cdev;
 
                if (!ts->throt_cfgs[i].init)
@@ -638,6 +828,461 @@ set_throttle:
        return 0;
 }
 
+static irqreturn_t soctherm_thermal_isr(int irq, void *dev_id)
+{
+       struct tegra_soctherm *ts = dev_id;
+       u32 r;
+
+       /* Case for no lock:
+        * Although interrupts are enabled in set_trips, there is still no need
+        * to lock here because the interrupts are disabled before programming
+        * new trip points. Hence there cant be a interrupt on the same sensor.
+        * An interrupt can however occur on a sensor while trips are being
+        * programmed on a different one. This beign a LEVEL interrupt won't
+        * cause a new interrupt but this is taken care of by the re-reading of
+        * the STATUS register in the thread function.
+        */
+       r = readl(ts->regs + THERMCTL_INTR_STATUS);
+       writel(r, ts->regs + THERMCTL_INTR_DISABLE);
+
+       return IRQ_WAKE_THREAD;
+}
+
+/**
+ * soctherm_thermal_isr_thread() - Handles a thermal interrupt request
+ * @irq:       The interrupt number being requested; not used
+ * @dev_id:    Opaque pointer to tegra_soctherm;
+ *
+ * Clears the interrupt status register if there are expected
+ * interrupt bits set.
+ * The interrupt(s) are then handled by updating the corresponding
+ * thermal zones.
+ *
+ * An error is logged if any unexpected interrupt bits are set.
+ *
+ * Disabled interrupts are re-enabled.
+ *
+ * Return: %IRQ_HANDLED. Interrupt was handled and no further processing
+ * is needed.
+ */
+static irqreturn_t soctherm_thermal_isr_thread(int irq, void *dev_id)
+{
+       struct tegra_soctherm *ts = dev_id;
+       struct thermal_zone_device *tz;
+       u32 st, ex = 0, cp = 0, gp = 0, pl = 0, me = 0;
+
+       st = readl(ts->regs + THERMCTL_INTR_STATUS);
+
+       /* deliberately clear expected interrupts handled in SW */
+       cp |= st & TH_INTR_CD0_MASK;
+       cp |= st & TH_INTR_CU0_MASK;
+
+       gp |= st & TH_INTR_GD0_MASK;
+       gp |= st & TH_INTR_GU0_MASK;
+
+       pl |= st & TH_INTR_PD0_MASK;
+       pl |= st & TH_INTR_PU0_MASK;
+
+       me |= st & TH_INTR_MD0_MASK;
+       me |= st & TH_INTR_MU0_MASK;
+
+       ex |= cp | gp | pl | me;
+       if (ex) {
+               writel(ex, ts->regs + THERMCTL_INTR_STATUS);
+               st &= ~ex;
+
+               if (cp) {
+                       tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_CPU];
+                       thermal_zone_device_update(tz,
+                                                  THERMAL_EVENT_UNSPECIFIED);
+               }
+
+               if (gp) {
+                       tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_GPU];
+                       thermal_zone_device_update(tz,
+                                                  THERMAL_EVENT_UNSPECIFIED);
+               }
+
+               if (pl) {
+                       tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_PLLX];
+                       thermal_zone_device_update(tz,
+                                                  THERMAL_EVENT_UNSPECIFIED);
+               }
+
+               if (me) {
+                       tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_MEM];
+                       thermal_zone_device_update(tz,
+                                                  THERMAL_EVENT_UNSPECIFIED);
+               }
+       }
+
+       /* deliberately ignore expected interrupts NOT handled in SW */
+       ex |= TH_INTR_IGNORE_MASK;
+       st &= ~ex;
+
+       if (st) {
+               /* Whine about any other unexpected INTR bits still set */
+               pr_err("soctherm: Ignored unexpected INTRs 0x%08x\n", st);
+               writel(st, ts->regs + THERMCTL_INTR_STATUS);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * soctherm_oc_intr_enable() - Enables the soctherm over-current interrupt
+ * @alarm:             The soctherm throttle id
+ * @enable:            Flag indicating enable the soctherm over-current
+ *                     interrupt or disable it
+ *
+ * Enables a specific over-current pins @alarm to raise an interrupt if the flag
+ * is set and the alarm corresponds to OC1, OC2, OC3, or OC4.
+ */
+static void soctherm_oc_intr_enable(struct tegra_soctherm *ts,
+                                   enum soctherm_throttle_id alarm,
+                                   bool enable)
+{
+       u32 r;
+
+       if (!enable)
+               return;
+
+       r = readl(ts->regs + OC_INTR_ENABLE);
+       switch (alarm) {
+       case THROTTLE_OC1:
+               r = REG_SET_MASK(r, OC_INTR_OC1_MASK, 1);
+               break;
+       case THROTTLE_OC2:
+               r = REG_SET_MASK(r, OC_INTR_OC2_MASK, 1);
+               break;
+       case THROTTLE_OC3:
+               r = REG_SET_MASK(r, OC_INTR_OC3_MASK, 1);
+               break;
+       case THROTTLE_OC4:
+               r = REG_SET_MASK(r, OC_INTR_OC4_MASK, 1);
+               break;
+       default:
+               r = 0;
+               break;
+       }
+       writel(r, ts->regs + OC_INTR_ENABLE);
+}
+
+/**
+ * soctherm_handle_alarm() - Handles soctherm alarms
+ * @alarm:             The soctherm throttle id
+ *
+ * "Handles" over-current alarms (OC1, OC2, OC3, and OC4) by printing
+ * a warning or informative message.
+ *
+ * Return: -EINVAL for @alarm = THROTTLE_OC3, otherwise 0 (success).
+ */
+static int soctherm_handle_alarm(enum soctherm_throttle_id alarm)
+{
+       int rv = -EINVAL;
+
+       switch (alarm) {
+       case THROTTLE_OC1:
+               pr_debug("soctherm: Successfully handled OC1 alarm\n");
+               rv = 0;
+               break;
+
+       case THROTTLE_OC2:
+               pr_debug("soctherm: Successfully handled OC2 alarm\n");
+               rv = 0;
+               break;
+
+       case THROTTLE_OC3:
+               pr_debug("soctherm: Successfully handled OC3 alarm\n");
+               rv = 0;
+               break;
+
+       case THROTTLE_OC4:
+               pr_debug("soctherm: Successfully handled OC4 alarm\n");
+               rv = 0;
+               break;
+
+       default:
+               break;
+       }
+
+       if (rv)
+               pr_err("soctherm: ERROR in handling %s alarm\n",
+                      throt_names[alarm]);
+
+       return rv;
+}
+
+/**
+ * soctherm_edp_isr_thread() - log an over-current interrupt request
+ * @irq:       OC irq number. Currently not being used. See description
+ * @arg:       a void pointer for callback, currently not being used
+ *
+ * Over-current events are handled in hardware. This function is called to log
+ * and handle any OC events that happened. Additionally, it checks every
+ * over-current interrupt registers for registers are set but
+ * was not expected (i.e. any discrepancy in interrupt status) by the function,
+ * the discrepancy will logged.
+ *
+ * Return: %IRQ_HANDLED
+ */
+static irqreturn_t soctherm_edp_isr_thread(int irq, void *arg)
+{
+       struct tegra_soctherm *ts = arg;
+       u32 st, ex, oc1, oc2, oc3, oc4;
+
+       st = readl(ts->regs + OC_INTR_STATUS);
+
+       /* deliberately clear expected interrupts handled in SW */
+       oc1 = st & OC_INTR_OC1_MASK;
+       oc2 = st & OC_INTR_OC2_MASK;
+       oc3 = st & OC_INTR_OC3_MASK;
+       oc4 = st & OC_INTR_OC4_MASK;
+       ex = oc1 | oc2 | oc3 | oc4;
+
+       pr_err("soctherm: OC ALARM 0x%08x\n", ex);
+       if (ex) {
+               writel(st, ts->regs + OC_INTR_STATUS);
+               st &= ~ex;
+
+               if (oc1 && !soctherm_handle_alarm(THROTTLE_OC1))
+                       soctherm_oc_intr_enable(ts, THROTTLE_OC1, true);
+
+               if (oc2 && !soctherm_handle_alarm(THROTTLE_OC2))
+                       soctherm_oc_intr_enable(ts, THROTTLE_OC2, true);
+
+               if (oc3 && !soctherm_handle_alarm(THROTTLE_OC3))
+                       soctherm_oc_intr_enable(ts, THROTTLE_OC3, true);
+
+               if (oc4 && !soctherm_handle_alarm(THROTTLE_OC4))
+                       soctherm_oc_intr_enable(ts, THROTTLE_OC4, true);
+
+               if (oc1 && soc_irq_cdata.irq_enable & BIT(0))
+                       handle_nested_irq(
+                               irq_find_mapping(soc_irq_cdata.domain, 0));
+
+               if (oc2 && soc_irq_cdata.irq_enable & BIT(1))
+                       handle_nested_irq(
+                               irq_find_mapping(soc_irq_cdata.domain, 1));
+
+               if (oc3 && soc_irq_cdata.irq_enable & BIT(2))
+                       handle_nested_irq(
+                               irq_find_mapping(soc_irq_cdata.domain, 2));
+
+               if (oc4 && soc_irq_cdata.irq_enable & BIT(3))
+                       handle_nested_irq(
+                               irq_find_mapping(soc_irq_cdata.domain, 3));
+       }
+
+       if (st) {
+               pr_err("soctherm: Ignored unexpected OC ALARM 0x%08x\n", st);
+               writel(st, ts->regs + OC_INTR_STATUS);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * soctherm_edp_isr() - Disables any active interrupts
+ * @irq:       The interrupt request number
+ * @arg:       Opaque pointer to an argument
+ *
+ * Writes to the OC_INTR_DISABLE register the over current interrupt status,
+ * masking any asserted interrupts. Doing this prevents the same interrupts
+ * from triggering this isr repeatedly. The thread woken by this isr will
+ * handle asserted interrupts and subsequently unmask/re-enable them.
+ *
+ * The OC_INTR_DISABLE register indicates which OC interrupts
+ * have been disabled.
+ *
+ * Return: %IRQ_WAKE_THREAD, handler requests to wake the handler thread
+ */
+static irqreturn_t soctherm_edp_isr(int irq, void *arg)
+{
+       struct tegra_soctherm *ts = arg;
+       u32 r;
+
+       if (!ts)
+               return IRQ_NONE;
+
+       r = readl(ts->regs + OC_INTR_STATUS);
+       writel(r, ts->regs + OC_INTR_DISABLE);
+
+       return IRQ_WAKE_THREAD;
+}
+
+/**
+ * soctherm_oc_irq_lock() - locks the over-current interrupt request
+ * @data:      Interrupt request data
+ *
+ * Looks up the chip data from @data and locks the mutex associated with
+ * a particular over-current interrupt request.
+ */
+static void soctherm_oc_irq_lock(struct irq_data *data)
+{
+       struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&d->irq_lock);
+}
+
+/**
+ * soctherm_oc_irq_sync_unlock() - Unlocks the OC interrupt request
+ * @data:              Interrupt request data
+ *
+ * Looks up the interrupt request data @data and unlocks the mutex associated
+ * with a particular over-current interrupt request.
+ */
+static void soctherm_oc_irq_sync_unlock(struct irq_data *data)
+{
+       struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+
+       mutex_unlock(&d->irq_lock);
+}
+
+/**
+ * soctherm_oc_irq_enable() - Enables the SOC_THERM over-current interrupt queue
+ * @data:       irq_data structure of the chip
+ *
+ * Sets the irq_enable bit of SOC_THERM allowing SOC_THERM
+ * to respond to over-current interrupts.
+ *
+ */
+static void soctherm_oc_irq_enable(struct irq_data *data)
+{
+       struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+
+       d->irq_enable |= BIT(data->hwirq);
+}
+
+/**
+ * soctherm_oc_irq_disable() - Disables overcurrent interrupt requests
+ * @irq_data:  The interrupt request information
+ *
+ * Clears the interrupt request enable bit of the overcurrent
+ * interrupt request chip data.
+ *
+ * Return: Nothing is returned (void)
+ */
+static void soctherm_oc_irq_disable(struct irq_data *data)
+{
+       struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+
+       d->irq_enable &= ~BIT(data->hwirq);
+}
+
+static int soctherm_oc_irq_set_type(struct irq_data *data, unsigned int type)
+{
+       return 0;
+}
+
+/**
+ * soctherm_oc_irq_map() - SOC_THERM interrupt request domain mapper
+ * @h:         Interrupt request domain
+ * @virq:      Virtual interrupt request number
+ * @hw:                Hardware interrupt request number
+ *
+ * Mapping callback function for SOC_THERM's irq_domain. When a SOC_THERM
+ * interrupt request is called, the irq_domain takes the request's virtual
+ * request number (much like a virtual memory address) and maps it to a
+ * physical hardware request number.
+ *
+ * When a mapping doesn't already exist for a virtual request number, the
+ * irq_domain calls this function to associate the virtual request number with
+ * a hardware request number.
+ *
+ * Return: 0
+ */
+static int soctherm_oc_irq_map(struct irq_domain *h, unsigned int virq,
+               irq_hw_number_t hw)
+{
+       struct soctherm_oc_irq_chip_data *data = h->host_data;
+
+       irq_set_chip_data(virq, data);
+       irq_set_chip(virq, &data->irq_chip);
+       irq_set_nested_thread(virq, 1);
+       return 0;
+}
+
+/**
+ * soctherm_irq_domain_xlate_twocell() - xlate for soctherm interrupts
+ * @d:      Interrupt request domain
+ * @intspec:    Array of u32s from DTs "interrupt" property
+ * @intsize:    Number of values inside the intspec array
+ * @out_hwirq:  HW IRQ value associated with this interrupt
+ * @out_type:   The IRQ SENSE type for this interrupt.
+ *
+ * This Device Tree IRQ specifier translation function will translate a
+ * specific "interrupt" as defined by 2 DT values where the cell values map
+ * the hwirq number + 1 and linux irq flags. Since the output is the hwirq
+ * number, this function will subtract 1 from the value listed in DT.
+ *
+ * Return: 0
+ */
+static int soctherm_irq_domain_xlate_twocell(struct irq_domain *d,
+       struct device_node *ctrlr, const u32 *intspec, unsigned int intsize,
+       irq_hw_number_t *out_hwirq, unsigned int *out_type)
+{
+       if (WARN_ON(intsize < 2))
+               return -EINVAL;
+
+       /*
+        * The HW value is 1 index less than the DT IRQ values.
+        * i.e. OC4 goes to HW index 3.
+        */
+       *out_hwirq = intspec[0] - 1;
+       *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+       return 0;
+}
+
+static const struct irq_domain_ops soctherm_oc_domain_ops = {
+       .map    = soctherm_oc_irq_map,
+       .xlate  = soctherm_irq_domain_xlate_twocell,
+};
+
+/**
+ * soctherm_oc_int_init() - Initial enabling of the over
+ * current interrupts
+ * @np:        The devicetree node for soctherm
+ * @num_irqs:  The number of new interrupt requests
+ *
+ * Sets the over current interrupt request chip data
+ *
+ * Return: 0 on success or if overcurrent interrupts are not enabled,
+ * -ENOMEM (out of memory), or irq_base if the function failed to
+ * allocate the irqs
+ */
+static int soctherm_oc_int_init(struct device_node *np, int num_irqs)
+{
+       if (!num_irqs) {
+               pr_info("%s(): OC interrupts are not enabled\n", __func__);
+               return 0;
+       }
+
+       mutex_init(&soc_irq_cdata.irq_lock);
+       soc_irq_cdata.irq_enable = 0;
+
+       soc_irq_cdata.irq_chip.name = "soc_therm_oc";
+       soc_irq_cdata.irq_chip.irq_bus_lock = soctherm_oc_irq_lock;
+       soc_irq_cdata.irq_chip.irq_bus_sync_unlock =
+               soctherm_oc_irq_sync_unlock;
+       soc_irq_cdata.irq_chip.irq_disable = soctherm_oc_irq_disable;
+       soc_irq_cdata.irq_chip.irq_enable = soctherm_oc_irq_enable;
+       soc_irq_cdata.irq_chip.irq_set_type = soctherm_oc_irq_set_type;
+       soc_irq_cdata.irq_chip.irq_set_wake = NULL;
+
+       soc_irq_cdata.domain = irq_domain_add_linear(np, num_irqs,
+                                                    &soctherm_oc_domain_ops,
+                                                    &soc_irq_cdata);
+
+       if (!soc_irq_cdata.domain) {
+               pr_err("%s: Failed to create IRQ domain\n", __func__);
+               return -ENOMEM;
+       }
+
+       pr_debug("%s(): OC interrupts enabled successful\n", __func__);
+       return 0;
+}
+
 #ifdef CONFIG_DEBUG_FS
 static int regs_show(struct seq_file *s, void *data)
 {
@@ -929,6 +1574,120 @@ static const struct thermal_cooling_device_ops throt_cooling_ops = {
        .set_cur_state = throt_set_cdev_state,
 };
 
+static int soctherm_thermtrips_parse(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct tegra_soctherm *ts = dev_get_drvdata(dev);
+       struct tsensor_group_thermtrips *tt = ts->soc->thermtrips;
+       const int max_num_prop = ts->soc->num_ttgs * 2;
+       u32 *tlb;
+       int i, j, n, ret;
+
+       if (!tt)
+               return -ENOMEM;
+
+       n = of_property_count_u32_elems(dev->of_node, "nvidia,thermtrips");
+       if (n <= 0) {
+               dev_info(dev,
+                        "missing thermtrips, will use critical trips as shut down temp\n");
+               return n;
+       }
+
+       n = min(max_num_prop, n);
+
+       tlb = devm_kcalloc(&pdev->dev, max_num_prop, sizeof(u32), GFP_KERNEL);
+       if (!tlb)
+               return -ENOMEM;
+       ret = of_property_read_u32_array(dev->of_node, "nvidia,thermtrips",
+                                        tlb, n);
+       if (ret) {
+               dev_err(dev, "invalid num ele: thermtrips:%d\n", ret);
+               return ret;
+       }
+
+       i = 0;
+       for (j = 0; j < n; j = j + 2) {
+               if (tlb[j] >= TEGRA124_SOCTHERM_SENSOR_NUM)
+                       continue;
+
+               tt[i].id = tlb[j];
+               tt[i].temp = tlb[j + 1];
+               i++;
+       }
+
+       return 0;
+}
+
+static void soctherm_oc_cfg_parse(struct device *dev,
+                               struct device_node *np_oc,
+                               struct soctherm_throt_cfg *stc)
+{
+       u32 val;
+
+       if (of_property_read_bool(np_oc, "nvidia,polarity-active-low"))
+               stc->oc_cfg.active_low = 1;
+       else
+               stc->oc_cfg.active_low = 0;
+
+       if (!of_property_read_u32(np_oc, "nvidia,count-threshold", &val)) {
+               stc->oc_cfg.intr_en = 1;
+               stc->oc_cfg.alarm_cnt_thresh = val;
+       }
+
+       if (!of_property_read_u32(np_oc, "nvidia,throttle-period-us", &val))
+               stc->oc_cfg.throt_period = val;
+
+       if (!of_property_read_u32(np_oc, "nvidia,alarm-filter", &val))
+               stc->oc_cfg.alarm_filter = val;
+
+       /* BRIEF throttling by default, do not support STICKY */
+       stc->oc_cfg.mode = OC_THROTTLE_MODE_BRIEF;
+}
+
+static int soctherm_throt_cfg_parse(struct device *dev,
+                                   struct device_node *np,
+                                   struct soctherm_throt_cfg *stc)
+{
+       struct tegra_soctherm *ts = dev_get_drvdata(dev);
+       int ret;
+       u32 val;
+
+       ret = of_property_read_u32(np, "nvidia,priority", &val);
+       if (ret) {
+               dev_err(dev, "throttle-cfg: %s: invalid priority\n", stc->name);
+               return -EINVAL;
+       }
+       stc->priority = val;
+
+       ret = of_property_read_u32(np, ts->soc->use_ccroc ?
+                                  "nvidia,cpu-throt-level" :
+                                  "nvidia,cpu-throt-percent", &val);
+       if (!ret) {
+               if (ts->soc->use_ccroc &&
+                   val <= TEGRA_SOCTHERM_THROT_LEVEL_HIGH)
+                       stc->cpu_throt_level = val;
+               else if (!ts->soc->use_ccroc && val <= 100)
+                       stc->cpu_throt_depth = val;
+               else
+                       goto err;
+       } else {
+               goto err;
+       }
+
+       ret = of_property_read_u32(np, "nvidia,gpu-throt-level", &val);
+       if (!ret && val <= TEGRA_SOCTHERM_THROT_LEVEL_HIGH)
+               stc->gpu_throt_level = val;
+       else
+               goto err;
+
+       return 0;
+
+err:
+       dev_err(dev, "throttle-cfg: %s: no throt prop or invalid prop\n",
+               stc->name);
+       return -EINVAL;
+}
+
 /**
  * soctherm_init_hw_throt_cdev() - Parse the HW throttle configurations
  * and register them as cooling devices.
@@ -939,8 +1698,7 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
        struct tegra_soctherm *ts = dev_get_drvdata(dev);
        struct device_node *np_stc, *np_stcc;
        const char *name;
-       u32 val;
-       int i, r;
+       int i;
 
        for (i = 0; i < THROTTLE_SIZE; i++) {
                ts->throt_cfgs[i].name = throt_names[i];
@@ -958,6 +1716,7 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
        for_each_child_of_node(np_stc, np_stcc) {
                struct soctherm_throt_cfg *stc;
                struct thermal_cooling_device *tcd;
+               int err;
 
                name = np_stcc->name;
                stc = find_throttle_cfg_by_name(ts, name);
@@ -967,51 +1726,34 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
                        continue;
                }
 
-               r = of_property_read_u32(np_stcc, "nvidia,priority", &val);
-               if (r) {
-                       dev_info(dev,
-                                "throttle-cfg: %s: missing priority\n", name);
-                       continue;
+               if (stc->init) {
+                       dev_err(dev, "throttle-cfg: %s: redefined!\n", name);
+                       of_node_put(np_stcc);
+                       break;
                }
-               stc->priority = val;
-
-               if (ts->soc->use_ccroc) {
-                       r = of_property_read_u32(np_stcc,
-                                                "nvidia,cpu-throt-level",
-                                                &val);
-                       if (r) {
-                               dev_info(dev,
-                                        "throttle-cfg: %s: missing cpu-throt-level\n",
-                                        name);
-                               continue;
-                       }
-                       stc->cpu_throt_level = val;
+
+               err = soctherm_throt_cfg_parse(dev, np_stcc, stc);
+               if (err)
+                       continue;
+
+               if (stc->id >= THROTTLE_OC1) {
+                       soctherm_oc_cfg_parse(dev, np_stcc, stc);
+                       stc->init = true;
                } else {
-                       r = of_property_read_u32(np_stcc,
-                                                "nvidia,cpu-throt-percent",
-                                                &val);
-                       if (r) {
-                               dev_info(dev,
-                                        "throttle-cfg: %s: missing cpu-throt-percent\n",
-                                        name);
-                               continue;
-                       }
-                       stc->cpu_throt_depth = val;
-               }
 
-               tcd = thermal_of_cooling_device_register(np_stcc,
+                       tcd = thermal_of_cooling_device_register(np_stcc,
                                                         (char *)name, ts,
                                                         &throt_cooling_ops);
-               of_node_put(np_stcc);
-               if (IS_ERR_OR_NULL(tcd)) {
-                       dev_err(dev,
-                               "throttle-cfg: %s: failed to register cooling device\n",
-                               name);
-                       continue;
+                       if (IS_ERR_OR_NULL(tcd)) {
+                               dev_err(dev,
+                                       "throttle-cfg: %s: failed to register cooling device\n",
+                                       name);
+                               continue;
+                       }
+                       stc->cdev = tcd;
+                       stc->init = true;
                }
 
-               stc->cdev = tcd;
-               stc->init = true;
        }
 
        of_node_put(np_stc);
@@ -1140,6 +1882,50 @@ static void throttlectl_cpu_mn(struct tegra_soctherm *ts,
        writel(r, ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));
 }
 
+/**
+ * throttlectl_gpu_level_select() - selects throttling level for GPU
+ * @throt: the LIGHT/HEAVY of throttle event id
+ *
+ * This function programs soctherm's interface to GK20a NV_THERM to select
+ * pre-configured "Low", "Medium" or "Heavy" throttle levels.
+ *
+ * Return: boolean true if HW was programmed
+ */
+static void throttlectl_gpu_level_select(struct tegra_soctherm *ts,
+                                        enum soctherm_throttle_id throt)
+{
+       u32 r, level, throt_vect;
+
+       level = ts->throt_cfgs[throt].gpu_throt_level;
+       throt_vect = THROT_LEVEL_TO_DEPTH(level);
+       r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_GPU));
+       r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1);
+       r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT_GPU_MASK, throt_vect);
+       writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_GPU));
+}
+
+static int soctherm_oc_cfg_program(struct tegra_soctherm *ts,
+                                     enum soctherm_throttle_id throt)
+{
+       u32 r;
+       struct soctherm_oc_cfg *oc = &ts->throt_cfgs[throt].oc_cfg;
+
+       if (oc->mode == OC_THROTTLE_MODE_DISABLED)
+               return -EINVAL;
+
+       r = REG_SET_MASK(0, OC1_CFG_HW_RESTORE_MASK, 1);
+       r = REG_SET_MASK(r, OC1_CFG_THROTTLE_MODE_MASK, oc->mode);
+       r = REG_SET_MASK(r, OC1_CFG_ALARM_POLARITY_MASK, oc->active_low);
+       r = REG_SET_MASK(r, OC1_CFG_EN_THROTTLE_MASK, 1);
+       writel(r, ts->regs + ALARM_CFG(throt));
+       writel(oc->throt_period, ts->regs + ALARM_THROTTLE_PERIOD(throt));
+       writel(oc->alarm_cnt_thresh, ts->regs + ALARM_CNT_THRESHOLD(throt));
+       writel(oc->alarm_filter, ts->regs + ALARM_FILTER(throt));
+       soctherm_oc_intr_enable(ts, throt, oc->intr_en);
+
+       return 0;
+}
+
 /**
  * soctherm_throttle_program() - programs pulse skippers' configuration
  * @throt: the LIGHT/HEAVY of the throttle event id.
@@ -1156,12 +1942,17 @@ static void soctherm_throttle_program(struct tegra_soctherm *ts,
        if (!stc.init)
                return;
 
+       if ((throt >= THROTTLE_OC1) && (soctherm_oc_cfg_program(ts, throt)))
+               return;
+
        /* Setup PSKIP parameters */
        if (ts->soc->use_ccroc)
                throttlectl_cpu_level_select(ts, throt);
        else
                throttlectl_cpu_mn(ts, throt);
 
+       throttlectl_gpu_level_select(ts, throt);
+
        r = REG_SET_MASK(0, THROT_PRIORITY_LITE_PRIO_MASK, stc.priority);
        writel(r, ts->regs + THROT_PRIORITY_CTRL(throt));
 
@@ -1215,6 +2006,57 @@ static void tegra_soctherm_throttle(struct device *dev)
        writel(v, ts->regs + THERMCTL_STATS_CTL);
 }
 
+static int soctherm_interrupts_init(struct platform_device *pdev,
+                                   struct tegra_soctherm *tegra)
+{
+       struct device_node *np = pdev->dev.of_node;
+       int ret;
+
+       ret = soctherm_oc_int_init(np, TEGRA_SOC_OC_IRQ_MAX);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "soctherm_oc_int_init failed\n");
+               return ret;
+       }
+
+       tegra->thermal_irq = platform_get_irq(pdev, 0);
+       if (tegra->thermal_irq < 0) {
+               dev_dbg(&pdev->dev, "get 'thermal_irq' failed.\n");
+               return 0;
+       }
+
+       tegra->edp_irq = platform_get_irq(pdev, 1);
+       if (tegra->edp_irq < 0) {
+               dev_dbg(&pdev->dev, "get 'edp_irq' failed.\n");
+               return 0;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev,
+                                       tegra->thermal_irq,
+                                       soctherm_thermal_isr,
+                                       soctherm_thermal_isr_thread,
+                                       IRQF_ONESHOT,
+                                       dev_name(&pdev->dev),
+                                       tegra);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "request_irq 'thermal_irq' failed.\n");
+               return ret;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev,
+                                       tegra->edp_irq,
+                                       soctherm_edp_isr,
+                                       soctherm_edp_isr_thread,
+                                       IRQF_ONESHOT,
+                                       "soctherm_edp",
+                                       tegra);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "request_irq 'edp_irq' failed.\n");
+               return ret;
+       }
+
+       return 0;
+}
+
 static void soctherm_init(struct platform_device *pdev)
 {
        struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
@@ -1292,6 +2134,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
        if (!tegra)
                return -ENOMEM;
 
+       mutex_init(&tegra->thermctl_lock);
        dev_set_drvdata(&pdev->dev, tegra);
 
        tegra->soc = soc;
@@ -1370,6 +2213,8 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
        if (err)
                return err;
 
+       soctherm_thermtrips_parse(pdev);
+
        soctherm_init_hw_throt_cdev(pdev);
 
        soctherm_init(pdev);
@@ -1406,6 +2251,8 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
                        goto disable_clocks;
        }
 
+       err = soctherm_interrupts_init(pdev, tegra);
+
        soctherm_debug_init(pdev);
 
        return 0;
index e96ca73fd780bd0a47918df573312ba8ee97def6..70501e73d586230d3caca8dea0966afd7f23142a 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (c) 2014-2016, NVIDIA CORPORATION.  All rights reserved.
  *
 #define THERMCTL_THERMTRIP_CTL                 0x80
 /* BITs are defined in device file */
 
+#define THERMCTL_INTR_ENABLE                   0x88
+#define THERMCTL_INTR_DISABLE                  0x8c
+#define TH_INTR_UP_DN_EN                       0x3
+#define THERM_IRQ_MEM_MASK                     (TH_INTR_UP_DN_EN << 24)
+#define THERM_IRQ_GPU_MASK                     (TH_INTR_UP_DN_EN << 16)
+#define THERM_IRQ_CPU_MASK                     (TH_INTR_UP_DN_EN << 8)
+#define THERM_IRQ_TSENSE_MASK                  (TH_INTR_UP_DN_EN << 0)
+
 #define SENSOR_PDIV                            0x1c0
 #define SENSOR_PDIV_CPU_MASK                   (0xf << 12)
 #define SENSOR_PDIV_GPU_MASK                   (0xf << 8)
@@ -70,6 +79,7 @@ struct tegra_tsensor_group {
        u32 thermtrip_enable_mask;
        u32 thermtrip_any_en_mask;
        u32 thermtrip_threshold_mask;
+       u32 thermctl_isr_mask;
        u16 thermctl_lvl0_offset;
        u32 thermctl_lvl0_up_thresh_mask;
        u32 thermctl_lvl0_dn_thresh_mask;
@@ -92,6 +102,11 @@ struct tegra_tsensor {
        const struct tegra_tsensor_group *group;
 };
 
+struct tsensor_group_thermtrips {
+       u8 id;
+       u32 temp;
+};
+
 struct tegra_soctherm_fuse {
        u32 fuse_base_cp_mask, fuse_base_cp_shift;
        u32 fuse_base_ft_mask, fuse_base_ft_shift;
@@ -113,6 +128,7 @@ struct tegra_soctherm_soc {
        const int thresh_grain;
        const unsigned int bptt;
        const bool use_ccroc;
+       struct tsensor_group_thermtrips *thermtrips;
 };
 
 int tegra_calc_shared_calib(const struct tegra_soctherm_fuse *tfuse,
index 36768630f78c9f435a8961d74a3125dd6dec2a1f..20ad27f4d1a161d419a19f3406a494d08b31542d 100644 (file)
@@ -1,5 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2014-2016, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2014-2018, NVIDIA CORPORATION.  All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -55,6 +56,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_cpu = {
        .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
        .thermtrip_enable_mask = TEGRA124_THERMTRIP_CPU_EN_MASK,
        .thermtrip_threshold_mask = TEGRA124_THERMTRIP_CPU_THRESH_MASK,
+       .thermctl_isr_mask = THERM_IRQ_CPU_MASK,
        .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU,
        .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
        .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
@@ -73,6 +75,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = {
        .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
        .thermtrip_enable_mask = TEGRA124_THERMTRIP_GPU_EN_MASK,
        .thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK,
+       .thermctl_isr_mask = THERM_IRQ_GPU_MASK,
        .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU,
        .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
        .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
@@ -89,6 +92,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_pll = {
        .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
        .thermtrip_enable_mask = TEGRA124_THERMTRIP_TSENSE_EN_MASK,
        .thermtrip_threshold_mask = TEGRA124_THERMTRIP_TSENSE_THRESH_MASK,
+       .thermctl_isr_mask = THERM_IRQ_TSENSE_MASK,
        .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE,
        .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
        .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
@@ -107,6 +111,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_mem = {
        .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
        .thermtrip_enable_mask = TEGRA124_THERMTRIP_MEM_EN_MASK,
        .thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK,
+       .thermctl_isr_mask = THERM_IRQ_MEM_MASK,
        .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM,
        .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
        .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
index 97fa30501eb19eeec32c05c7365e4f7ab9a8af3f..b76308fdad9e26820261e0f62c56a357d1f576fb 100644 (file)
@@ -1,5 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2014-2016, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2014-2018, NVIDIA CORPORATION.  All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -55,6 +56,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_cpu = {
        .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
        .thermtrip_enable_mask = TEGRA132_THERMTRIP_CPU_EN_MASK,
        .thermtrip_threshold_mask = TEGRA132_THERMTRIP_CPU_THRESH_MASK,
+       .thermctl_isr_mask = THERM_IRQ_CPU_MASK,
        .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU,
        .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
        .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
@@ -73,6 +75,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = {
        .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
        .thermtrip_enable_mask = TEGRA132_THERMTRIP_GPU_EN_MASK,
        .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK,
+       .thermctl_isr_mask = THERM_IRQ_GPU_MASK,
        .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU,
        .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
        .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
@@ -89,6 +92,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_pll = {
        .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
        .thermtrip_enable_mask = TEGRA132_THERMTRIP_TSENSE_EN_MASK,
        .thermtrip_threshold_mask = TEGRA132_THERMTRIP_TSENSE_THRESH_MASK,
+       .thermctl_isr_mask = THERM_IRQ_TSENSE_MASK,
        .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE,
        .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
        .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
@@ -107,6 +111,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_mem = {
        .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
        .thermtrip_enable_mask = TEGRA132_THERMTRIP_MEM_EN_MASK,
        .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK,
+       .thermctl_isr_mask = THERM_IRQ_MEM_MASK,
        .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM,
        .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
        .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
index ad53169a8e955718783d56a27f32cc2bf4015f28..d31b50050faa0d107d20d9e282f0accc72a3db45 100644 (file)
@@ -1,5 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2014-2016, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2014-2018, NVIDIA CORPORATION.  All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -56,6 +57,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_cpu = {
        .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
        .thermtrip_enable_mask = TEGRA210_THERMTRIP_CPU_EN_MASK,
        .thermtrip_threshold_mask = TEGRA210_THERMTRIP_CPU_THRESH_MASK,
+       .thermctl_isr_mask = THERM_IRQ_CPU_MASK,
        .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU,
        .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
        .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
@@ -74,6 +76,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_gpu = {
        .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
        .thermtrip_enable_mask = TEGRA210_THERMTRIP_GPU_EN_MASK,
        .thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK,
+       .thermctl_isr_mask = THERM_IRQ_GPU_MASK,
        .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU,
        .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
        .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
@@ -90,6 +93,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_pll = {
        .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
        .thermtrip_enable_mask = TEGRA210_THERMTRIP_TSENSE_EN_MASK,
        .thermtrip_threshold_mask = TEGRA210_THERMTRIP_TSENSE_THRESH_MASK,
+       .thermctl_isr_mask = THERM_IRQ_TSENSE_MASK,
        .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE,
        .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
        .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
@@ -108,6 +112,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_mem = {
        .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
        .thermtrip_enable_mask = TEGRA210_THERMTRIP_MEM_EN_MASK,
        .thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK,
+       .thermctl_isr_mask = THERM_IRQ_MEM_MASK,
        .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM,
        .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
        .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
@@ -203,6 +208,13 @@ static const struct tegra_soctherm_fuse tegra210_soctherm_fuse = {
        .fuse_spare_realignment = 0,
 };
 
+struct tsensor_group_thermtrips tegra210_tsensor_thermtrips[] = {
+       {.id = TEGRA124_SOCTHERM_SENSOR_NUM},
+       {.id = TEGRA124_SOCTHERM_SENSOR_NUM},
+       {.id = TEGRA124_SOCTHERM_SENSOR_NUM},
+       {.id = TEGRA124_SOCTHERM_SENSOR_NUM},
+};
+
 const struct tegra_soctherm_soc tegra210_soctherm = {
        .tsensors = tegra210_tsensors,
        .num_tsensors = ARRAY_SIZE(tegra210_tsensors),
@@ -212,4 +224,5 @@ const struct tegra_soctherm_soc tegra210_soctherm = {
        .thresh_grain = TEGRA210_THRESH_GRAIN,
        .bptt = TEGRA210_BPTT,
        .use_ccroc = false,
+       .thermtrips = tegra210_tsensor_thermtrips,
 };
index e22fc60ad36dcf7e3b36321cab50c85b7e73079a..deb244f12de41324fe17d28b970414d84910dbbf 100644 (file)
@@ -29,6 +29,9 @@ static int gadc_thermal_adc_to_temp(struct gadc_thermal_info *gti, int val)
        int temp, temp_hi, temp_lo, adc_hi, adc_lo;
        int i;
 
+       if (!gti->lookup_table)
+               return val;
+
        for (i = 0; i < gti->nlookup_table; i++) {
                if (val >= gti->lookup_table[2 * i + 1])
                        break;
@@ -81,9 +84,9 @@ static int gadc_thermal_read_linear_lookup_table(struct device *dev,
 
        ntable = of_property_count_elems_of_size(np, "temperature-lookup-table",
                                                 sizeof(u32));
-       if (ntable < 0) {
-               dev_err(dev, "Lookup table is not provided\n");
-               return ntable;
+       if (ntable <= 0) {
+               dev_notice(dev, "no lookup table, assuming DAC channel returns milliCelcius\n");
+               return 0;
        }
 
        if (ntable % 2) {
index 6590bb5cb6885e4d2d0af88e3aa741cc24bd7745..46cfb7de4eb289d7b81db525178a5dd5ef6656d4 100644 (file)
@@ -266,7 +266,7 @@ static int __init thermal_register_governors(void)
        return thermal_gov_power_allocator_register();
 }
 
-static void thermal_unregister_governors(void)
+static void __init thermal_unregister_governors(void)
 {
        thermal_gov_step_wise_unregister();
        thermal_gov_fair_share_unregister();
@@ -941,7 +941,7 @@ static void bind_cdev(struct thermal_cooling_device *cdev)
  */
 static struct thermal_cooling_device *
 __thermal_cooling_device_register(struct device_node *np,
-                                 char *type, void *devdata,
+                                 const char *type, void *devdata,
                                  const struct thermal_cooling_device_ops *ops)
 {
        struct thermal_cooling_device *cdev;
@@ -1015,7 +1015,7 @@ __thermal_cooling_device_register(struct device_node *np,
  * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
  */
 struct thermal_cooling_device *
-thermal_cooling_device_register(char *type, void *devdata,
+thermal_cooling_device_register(const char *type, void *devdata,
                                const struct thermal_cooling_device_ops *ops)
 {
        return __thermal_cooling_device_register(NULL, type, devdata, ops);
@@ -1039,13 +1039,62 @@ EXPORT_SYMBOL_GPL(thermal_cooling_device_register);
  */
 struct thermal_cooling_device *
 thermal_of_cooling_device_register(struct device_node *np,
-                                  char *type, void *devdata,
+                                  const char *type, void *devdata,
                                   const struct thermal_cooling_device_ops *ops)
 {
        return __thermal_cooling_device_register(np, type, devdata, ops);
 }
 EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register);
 
+static void thermal_cooling_device_release(struct device *dev, void *res)
+{
+       thermal_cooling_device_unregister(
+                               *(struct thermal_cooling_device **)res);
+}
+
+/**
+ * devm_thermal_of_cooling_device_register() - register an OF thermal cooling
+ *                                            device
+ * @dev:       a valid struct device pointer of a sensor device.
+ * @np:                a pointer to a device tree node.
+ * @type:      the thermal cooling device type.
+ * @devdata:   device private data.
+ * @ops:       standard thermal cooling devices callbacks.
+ *
+ * This function will register a cooling device with device tree node reference.
+ * This interface function adds a new thermal cooling device (fan/processor/...)
+ * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
+ * to all the thermal zone devices registered at the same time.
+ *
+ * Return: a pointer to the created struct thermal_cooling_device or an
+ * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
+ */
+struct thermal_cooling_device *
+devm_thermal_of_cooling_device_register(struct device *dev,
+                               struct device_node *np,
+                               char *type, void *devdata,
+                               const struct thermal_cooling_device_ops *ops)
+{
+       struct thermal_cooling_device **ptr, *tcd;
+
+       ptr = devres_alloc(thermal_cooling_device_release, sizeof(*ptr),
+                          GFP_KERNEL);
+       if (!ptr)
+               return ERR_PTR(-ENOMEM);
+
+       tcd = __thermal_cooling_device_register(np, type, devdata, ops);
+       if (IS_ERR(tcd)) {
+               devres_free(ptr);
+               return tcd;
+       }
+
+       *ptr = tcd;
+       devres_add(dev, ptr);
+
+       return tcd;
+}
+EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register);
+
 static void __unbind(struct thermal_zone_device *tz, int mask,
                     struct thermal_cooling_device *cdev)
 {
@@ -1494,6 +1543,7 @@ static int thermal_pm_notify(struct notifier_block *nb,
                             unsigned long mode, void *_unused)
 {
        struct thermal_zone_device *tz;
+       enum thermal_device_mode tz_mode;
 
        switch (mode) {
        case PM_HIBERNATION_PREPARE:
@@ -1506,6 +1556,13 @@ static int thermal_pm_notify(struct notifier_block *nb,
        case PM_POST_SUSPEND:
                atomic_set(&in_suspend, 0);
                list_for_each_entry(tz, &thermal_tz_list, node) {
+                       tz_mode = THERMAL_DEVICE_ENABLED;
+                       if (tz->ops->get_mode)
+                               tz->ops->get_mode(tz, &tz_mode);
+
+                       if (tz_mode == THERMAL_DEVICE_DISABLED)
+                               continue;
+
                        thermal_zone_device_init(tz);
                        thermal_zone_device_update(tz,
                                                   THERMAL_EVENT_UNSPECIFIED);
@@ -1563,19 +1620,4 @@ error:
        mutex_destroy(&poweroff_lock);
        return result;
 }
-
-static void __exit thermal_exit(void)
-{
-       unregister_pm_notifier(&thermal_pm_nb);
-       of_thermal_destroy_zones();
-       genetlink_exit();
-       class_unregister(&thermal_class);
-       thermal_unregister_governors();
-       ida_destroy(&thermal_tz_ida);
-       ida_destroy(&thermal_cdev_ida);
-       mutex_destroy(&thermal_list_lock);
-       mutex_destroy(&thermal_governor_lock);
-}
-
 fs_initcall(thermal_init);
-module_exit(thermal_exit);
diff --git a/drivers/thermal/thermal_mmio.c b/drivers/thermal/thermal_mmio.c
new file mode 100644 (file)
index 0000000..de3ccee
--- /dev/null
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+
+struct thermal_mmio {
+       void __iomem *mmio_base;
+       u32 (*read_mmio)(void __iomem *mmio_base);
+       u32 mask;
+       int factor;
+};
+
+static u32 thermal_mmio_readb(void __iomem *mmio_base)
+{
+       return readb(mmio_base);
+}
+
+static int thermal_mmio_get_temperature(void *private, int *temp)
+{
+       int t;
+       struct thermal_mmio *sensor =
+               (struct thermal_mmio *)private;
+
+       t = sensor->read_mmio(sensor->mmio_base) & sensor->mask;
+       t *= sensor->factor;
+
+       *temp = t;
+
+       return 0;
+}
+
+static struct thermal_zone_of_device_ops thermal_mmio_ops = {
+       .get_temp = thermal_mmio_get_temperature,
+};
+
+static int thermal_mmio_probe(struct platform_device *pdev)
+{
+       struct resource *resource;
+       struct thermal_mmio *sensor;
+       int (*sensor_init_func)(struct platform_device *pdev,
+                               struct thermal_mmio *sensor);
+       struct thermal_zone_device *thermal_zone;
+       int ret;
+       int temperature;
+
+       sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL);
+       if (!sensor)
+               return -ENOMEM;
+
+       resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (IS_ERR(resource)) {
+               dev_err(&pdev->dev,
+                       "fail to get platform memory resource (%ld)\n",
+                       PTR_ERR(resource));
+               return PTR_ERR(resource);
+       }
+
+       sensor->mmio_base = devm_ioremap_resource(&pdev->dev, resource);
+       if (IS_ERR(sensor->mmio_base)) {
+               dev_err(&pdev->dev, "failed to ioremap memory (%ld)\n",
+                       PTR_ERR(sensor->mmio_base));
+               return PTR_ERR(sensor->mmio_base);
+       }
+
+       sensor_init_func = device_get_match_data(&pdev->dev);
+       if (sensor_init_func) {
+               ret = sensor_init_func(pdev, sensor);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "failed to initialize sensor (%d)\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       thermal_zone = devm_thermal_zone_of_sensor_register(&pdev->dev,
+                                                           0,
+                                                           sensor,
+                                                           &thermal_mmio_ops);
+       if (IS_ERR(thermal_zone)) {
+               dev_err(&pdev->dev,
+                       "failed to register sensor (%ld)\n",
+                       PTR_ERR(thermal_zone));
+               return PTR_ERR(thermal_zone);
+       }
+
+       thermal_mmio_get_temperature(sensor, &temperature);
+       dev_info(&pdev->dev,
+                "thermal mmio sensor %s registered, current temperature: %d\n",
+                pdev->name, temperature);
+
+       return 0;
+}
+
+static int al_thermal_init(struct platform_device *pdev,
+                          struct thermal_mmio *sensor)
+{
+       sensor->read_mmio = thermal_mmio_readb;
+       sensor->mask = 0xff;
+       sensor->factor = 1000;
+
+       return 0;
+}
+
+static const struct of_device_id thermal_mmio_id_table[] = {
+       { .compatible = "amazon,al-thermal", .data = al_thermal_init},
+       {}
+};
+MODULE_DEVICE_TABLE(of, thermal_mmio_id_table);
+
+static struct platform_driver thermal_mmio_driver = {
+       .probe = thermal_mmio_probe,
+       .driver = {
+               .name = "thermal-mmio",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(thermal_mmio_id_table),
+       },
+};
+
+module_platform_driver(thermal_mmio_driver);
+
+MODULE_AUTHOR("Talel Shenhar <talel@amazon.com>");
+MODULE_DESCRIPTION("Thermal MMIO Driver");
+MODULE_LICENSE("GPL v2");
index 75155bde2b8810306dc19f97e47f334c26a3979d..31f53fa77e4af5f1c4cd1ecd4677210d1d515cf0 100644 (file)
@@ -53,7 +53,6 @@ device_initcall(hvc_sbi_init);
 static int __init hvc_sbi_console_init(void)
 {
        hvc_instantiate(0, 0, &hvc_sbi_ops);
-       add_preferred_console("hvc", 0, NULL);
 
        return 0;
 }
index 59e82e6d776ddaf4a4d30a21eac3b14e86539433..573b2055173c177c9def565967027da99a341237 100644 (file)
@@ -527,8 +527,12 @@ void __handle_sysrq(int key, bool check_mask)
 {
        struct sysrq_key_op *op_p;
        int orig_log_level;
+       int orig_suppress_printk;
        int i;
 
+       orig_suppress_printk = suppress_printk;
+       suppress_printk = 0;
+
        rcu_sysrq_start();
        rcu_read_lock();
        /*
@@ -574,6 +578,8 @@ void __handle_sysrq(int key, bool check_mask)
        }
        rcu_read_unlock();
        rcu_sysrq_end();
+
+       suppress_printk = orig_suppress_printk;
 }
 
 void handle_sysrq(int key)
index ca8a94f15ac05b9eff29c3c04139cd6d8bc4d222..38183ac438c673871b08ecb485bcf6b20893bb18 100644 (file)
@@ -40,8 +40,6 @@ struct da8xx_ohci_hcd {
        struct phy *usb11_phy;
        struct regulator *vbus_reg;
        struct notifier_block nb;
-       unsigned int reg_enabled;
-       struct gpio_desc *vbus_gpio;
        struct gpio_desc *oc_gpio;
 };
 
@@ -92,29 +90,21 @@ static int ohci_da8xx_set_power(struct usb_hcd *hcd, int on)
        struct device *dev = hcd->self.controller;
        int ret;
 
-       if (da8xx_ohci->vbus_gpio) {
-               gpiod_set_value_cansleep(da8xx_ohci->vbus_gpio, on);
-               return 0;
-       }
-
        if (!da8xx_ohci->vbus_reg)
                return 0;
 
-       if (on && !da8xx_ohci->reg_enabled) {
+       if (on) {
                ret = regulator_enable(da8xx_ohci->vbus_reg);
                if (ret) {
                        dev_err(dev, "Failed to enable regulator: %d\n", ret);
                        return ret;
                }
-               da8xx_ohci->reg_enabled = 1;
-
-       } else if (!on && da8xx_ohci->reg_enabled) {
+       } else {
                ret = regulator_disable(da8xx_ohci->vbus_reg);
                if (ret) {
                        dev_err(dev, "Failed  to disable regulator: %d\n", ret);
                        return ret;
                }
-               da8xx_ohci->reg_enabled = 0;
        }
 
        return 0;
@@ -124,9 +114,6 @@ static int ohci_da8xx_get_power(struct usb_hcd *hcd)
 {
        struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
 
-       if (da8xx_ohci->vbus_gpio)
-               return gpiod_get_value_cansleep(da8xx_ohci->vbus_gpio);
-
        if (da8xx_ohci->vbus_reg)
                return regulator_is_enabled(da8xx_ohci->vbus_reg);
 
@@ -159,9 +146,6 @@ static int ohci_da8xx_has_set_power(struct usb_hcd *hcd)
 {
        struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
 
-       if (da8xx_ohci->vbus_gpio)
-               return 1;
-
        if (da8xx_ohci->vbus_reg)
                return 1;
 
@@ -206,12 +190,18 @@ static int ohci_da8xx_regulator_event(struct notifier_block *nb,
        return 0;
 }
 
-static irqreturn_t ohci_da8xx_oc_handler(int irq, void *data)
+static irqreturn_t ohci_da8xx_oc_thread(int irq, void *data)
 {
        struct da8xx_ohci_hcd *da8xx_ohci = data;
+       struct device *dev = da8xx_ohci->hcd->self.controller;
+       int ret;
 
-       if (gpiod_get_value(da8xx_ohci->oc_gpio))
-               gpiod_set_value(da8xx_ohci->vbus_gpio, 0);
+       if (gpiod_get_value_cansleep(da8xx_ohci->oc_gpio) &&
+           da8xx_ohci->vbus_reg) {
+               ret = regulator_disable(da8xx_ohci->vbus_reg);
+               if (ret)
+                       dev_err(dev, "Failed to disable regulator: %d\n", ret);
+       }
 
        return IRQ_HANDLED;
 }
@@ -424,11 +414,6 @@ static int ohci_da8xx_probe(struct platform_device *pdev)
                }
        }
 
-       da8xx_ohci->vbus_gpio = devm_gpiod_get_optional(dev, "vbus",
-                                                       GPIOD_OUT_HIGH);
-       if (IS_ERR(da8xx_ohci->vbus_gpio))
-               goto err;
-
        da8xx_ohci->oc_gpio = devm_gpiod_get_optional(dev, "oc", GPIOD_IN);
        if (IS_ERR(da8xx_ohci->oc_gpio))
                goto err;
@@ -438,8 +423,9 @@ static int ohci_da8xx_probe(struct platform_device *pdev)
                if (oc_irq < 0)
                        goto err;
 
-               error = devm_request_irq(dev, oc_irq, ohci_da8xx_oc_handler,
-                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+               error = devm_request_threaded_irq(dev, oc_irq, NULL,
+                               ohci_da8xx_oc_thread, IRQF_TRIGGER_RISING |
+                               IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                                "OHCI over-current indicator", da8xx_ohci);
                if (error)
                        goto err;
index be04c117fe809430769428ef5bca3f83783050e9..c97f270338bfdfb54a3c6f76b0d4f835d360779a 100644 (file)
@@ -142,7 +142,6 @@ config USB_FTDI_ELAN
 
 config USB_APPLEDISPLAY
        tristate "Apple Cinema Display support"
-       select BACKLIGHT_LCD_SUPPORT
        select BACKLIGHT_CLASS_DEVICE
        help
          Say Y here if you want to control the backlight of Apple Cinema
index b96fedc77ee51219a9c4f71800e43dc529114156..3cc1a05fde1c9de281900d8768dfd16bf0e3dbad 100644 (file)
@@ -88,7 +88,7 @@ static void mdev_release_parent(struct kref *kref)
        put_device(dev);
 }
 
-static inline struct mdev_parent *mdev_get_parent(struct mdev_parent *parent)
+static struct mdev_parent *mdev_get_parent(struct mdev_parent *parent)
 {
        if (parent)
                kref_get(&parent->ref);
@@ -96,7 +96,7 @@ static inline struct mdev_parent *mdev_get_parent(struct mdev_parent *parent)
        return parent;
 }
 
-static inline void mdev_put_parent(struct mdev_parent *parent)
+static void mdev_put_parent(struct mdev_parent *parent)
 {
        if (parent)
                kref_put(&parent->ref, mdev_release_parent);
@@ -141,7 +141,7 @@ static int mdev_device_remove_ops(struct mdev_device *mdev, bool force_remove)
         */
        ret = parent->ops->remove(mdev);
        if (ret && !force_remove)
-               return -EBUSY;
+               return ret;
 
        sysfs_remove_groups(&mdev->dev.kobj, parent->ops->mdev_attr_groups);
        return 0;
@@ -149,10 +149,10 @@ static int mdev_device_remove_ops(struct mdev_device *mdev, bool force_remove)
 
 static int mdev_device_remove_cb(struct device *dev, void *data)
 {
-       if (!dev_is_mdev(dev))
-               return 0;
+       if (dev_is_mdev(dev))
+               mdev_device_remove(dev, true);
 
-       return mdev_device_remove(dev, data ? *(bool *)data : true);
+       return 0;
 }
 
 /*
@@ -181,6 +181,7 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
        /* Check for duplicate */
        parent = __find_parent_device(dev);
        if (parent) {
+               parent = NULL;
                ret = -EEXIST;
                goto add_dev_err;
        }
@@ -239,7 +240,6 @@ EXPORT_SYMBOL(mdev_register_device);
 void mdev_unregister_device(struct device *dev)
 {
        struct mdev_parent *parent;
-       bool force_remove = true;
 
        mutex_lock(&parent_list_lock);
        parent = __find_parent_device(dev);
@@ -253,8 +253,7 @@ void mdev_unregister_device(struct device *dev)
        list_del(&parent->next);
        class_compat_remove_link(mdev_bus_compat_class, dev, NULL);
 
-       device_for_each_child(dev, (void *)&force_remove,
-                             mdev_device_remove_cb);
+       device_for_each_child(dev, NULL, mdev_device_remove_cb);
 
        parent_remove_sysfs_files(parent);
 
@@ -310,7 +309,6 @@ int mdev_device_create(struct kobject *kobj,
        mutex_unlock(&mdev_list_lock);
 
        mdev->parent = parent;
-       kref_init(&mdev->ref);
 
        mdev->dev.parent  = dev;
        mdev->dev.bus     = &mdev_bus_type;
@@ -390,6 +388,24 @@ int mdev_device_remove(struct device *dev, bool force_remove)
        return 0;
 }
 
+int mdev_set_iommu_device(struct device *dev, struct device *iommu_device)
+{
+       struct mdev_device *mdev = to_mdev_device(dev);
+
+       mdev->iommu_device = iommu_device;
+
+       return 0;
+}
+EXPORT_SYMBOL(mdev_set_iommu_device);
+
+struct device *mdev_get_iommu_device(struct device *dev)
+{
+       struct mdev_device *mdev = to_mdev_device(dev);
+
+       return mdev->iommu_device;
+}
+EXPORT_SYMBOL(mdev_get_iommu_device);
+
 static int __init mdev_init(void)
 {
        return mdev_bus_register();
index 379758c52b1b4cc40a566ef9e530a33a77f59a08..36cbbdb754deade31338b715a0750b0172553617 100644 (file)
@@ -30,9 +30,9 @@ struct mdev_device {
        struct mdev_parent *parent;
        guid_t uuid;
        void *driver_data;
-       struct kref ref;
        struct list_head next;
        struct kobject *type_kobj;
+       struct device *iommu_device;
        bool active;
 };
 
index 5193a0e0ce5aa4d2fb97ea57957eeb99b53b45be..cbf94b8165ea8a78c77cbd45515b3945a250fcb8 100644 (file)
@@ -280,7 +280,7 @@ type_link_failed:
 
 void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type)
 {
+       sysfs_remove_files(&dev->kobj, mdev_device_attrs);
        sysfs_remove_link(&dev->kobj, "mdev_type");
        sysfs_remove_link(type->devices_kobj, dev_name(dev));
-       sysfs_remove_files(&dev->kobj, mdev_device_attrs);
 }
index 3fa20e95a6bb6446fb2c4aa3d71abf75b611ce33..cab71da46f4ae4fd1263a4df0312afcb05c2a8f7 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#define dev_fmt pr_fmt
 
 #include <linux/device.h>
 #include <linux/eventfd.h>
@@ -287,12 +288,11 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
        pci_save_state(pdev);
        vdev->pci_saved_state = pci_store_saved_state(pdev);
        if (!vdev->pci_saved_state)
-               pr_debug("%s: Couldn't store %s saved state\n",
-                        __func__, dev_name(&pdev->dev));
+               pci_dbg(pdev, "%s: Couldn't store saved state\n", __func__);
 
        if (likely(!nointxmask)) {
                if (vfio_pci_nointx(pdev)) {
-                       dev_info(&pdev->dev, "Masking broken INTx support\n");
+                       pci_info(pdev, "Masking broken INTx support\n");
                        vdev->nointx = true;
                        pci_intx(pdev, 0);
                } else
@@ -336,8 +336,7 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
            IS_ENABLED(CONFIG_VFIO_PCI_IGD)) {
                ret = vfio_pci_igd_init(vdev);
                if (ret) {
-                       dev_warn(&vdev->pdev->dev,
-                                "Failed to setup Intel IGD regions\n");
+                       pci_warn(pdev, "Failed to setup Intel IGD regions\n");
                        goto disable_exit;
                }
        }
@@ -346,8 +345,7 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
            IS_ENABLED(CONFIG_VFIO_PCI_NVLINK2)) {
                ret = vfio_pci_nvdia_v100_nvlink2_init(vdev);
                if (ret && ret != -ENODEV) {
-                       dev_warn(&vdev->pdev->dev,
-                                "Failed to setup NVIDIA NV2 RAM region\n");
+                       pci_warn(pdev, "Failed to setup NVIDIA NV2 RAM region\n");
                        goto disable_exit;
                }
        }
@@ -356,8 +354,7 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
            IS_ENABLED(CONFIG_VFIO_PCI_NVLINK2)) {
                ret = vfio_pci_ibm_npu2_init(vdev);
                if (ret && ret != -ENODEV) {
-                       dev_warn(&vdev->pdev->dev,
-                                       "Failed to setup NVIDIA NV2 ATSD region\n");
+                       pci_warn(pdev, "Failed to setup NVIDIA NV2 ATSD region\n");
                        goto disable_exit;
                }
        }
@@ -429,8 +426,7 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
         * is just busy work.
         */
        if (pci_load_and_free_saved_state(pdev, &vdev->pci_saved_state)) {
-               pr_info("%s: Couldn't reload %s saved state\n",
-                       __func__, dev_name(&pdev->dev));
+               pci_info(pdev, "%s: Couldn't reload saved state\n", __func__);
 
                if (!vdev->reset_works)
                        goto out;
@@ -1255,17 +1251,18 @@ static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma)
 static void vfio_pci_request(void *device_data, unsigned int count)
 {
        struct vfio_pci_device *vdev = device_data;
+       struct pci_dev *pdev = vdev->pdev;
 
        mutex_lock(&vdev->igate);
 
        if (vdev->req_trigger) {
                if (!(count % 10))
-                       dev_notice_ratelimited(&vdev->pdev->dev,
+                       pci_notice_ratelimited(pdev,
                                "Relaying device request to user (#%u)\n",
                                count);
                eventfd_signal(vdev->req_trigger, 1);
        } else if (count == 0) {
-               dev_warn(&vdev->pdev->dev,
+               pci_warn(pdev,
                        "No device request channel registered, blocked until released by user\n");
        }
 
index e82b511146871567f5e06f1f08ddfc05dd94823b..52963a9047902b90c4154085d321536ff7a061d1 100644 (file)
@@ -412,8 +412,7 @@ static void vfio_bar_restore(struct vfio_pci_device *vdev)
        if (pdev->is_virtfn)
                return;
 
-       pr_info("%s: %s reset recovery - restoring bars\n",
-               __func__, dev_name(&pdev->dev));
+       pci_info(pdev, "%s: reset recovery - restoring BARs\n", __func__);
 
        for (i = PCI_BASE_ADDRESS_0; i <= PCI_BASE_ADDRESS_5; i += 4, rbar++)
                pci_user_write_config_dword(pdev, i, *rbar);
@@ -1298,8 +1297,8 @@ static int vfio_cap_len(struct vfio_pci_device *vdev, u8 cap, u8 pos)
                else
                        return PCI_SATA_SIZEOF_SHORT;
        default:
-               pr_warn("%s: %s unknown length for pci cap 0x%x@0x%x\n",
-                       dev_name(&pdev->dev), __func__, cap, pos);
+               pci_warn(pdev, "%s: unknown length for PCI cap %#x@%#x\n",
+                        __func__, cap, pos);
        }
 
        return 0;
@@ -1372,8 +1371,8 @@ static int vfio_ext_cap_len(struct vfio_pci_device *vdev, u16 ecap, u16 epos)
                }
                return PCI_TPH_BASE_SIZEOF;
        default:
-               pr_warn("%s: %s unknown length for pci ecap 0x%x@0x%x\n",
-                       dev_name(&pdev->dev), __func__, ecap, epos);
+               pci_warn(pdev, "%s: unknown length for PCI ecap %#x@%#x\n",
+                        __func__, ecap, epos);
        }
 
        return 0;
@@ -1474,8 +1473,8 @@ static int vfio_cap_init(struct vfio_pci_device *vdev)
                }
 
                if (!len) {
-                       pr_info("%s: %s hiding cap 0x%x\n",
-                               __func__, dev_name(&pdev->dev), cap);
+                       pci_info(pdev, "%s: hiding cap %#x@%#x\n", __func__,
+                                cap, pos);
                        *prev = next;
                        pos = next;
                        continue;
@@ -1486,9 +1485,8 @@ static int vfio_cap_init(struct vfio_pci_device *vdev)
                        if (likely(map[pos + i] == PCI_CAP_ID_INVALID))
                                continue;
 
-                       pr_warn("%s: %s pci config conflict @0x%x, was cap 0x%x now cap 0x%x\n",
-                               __func__, dev_name(&pdev->dev),
-                               pos + i, map[pos + i], cap);
+                       pci_warn(pdev, "%s: PCI config conflict @%#x, was cap %#x now cap %#x\n",
+                                __func__, pos + i, map[pos + i], cap);
                }
 
                BUILD_BUG_ON(PCI_CAP_ID_MAX >= PCI_CAP_ID_INVALID_VIRT);
@@ -1549,8 +1547,8 @@ static int vfio_ecap_init(struct vfio_pci_device *vdev)
                }
 
                if (!len) {
-                       pr_info("%s: %s hiding ecap 0x%x@0x%x\n",
-                               __func__, dev_name(&pdev->dev), ecap, epos);
+                       pci_info(pdev, "%s: hiding ecap %#x@%#x\n",
+                                __func__, ecap, epos);
 
                        /* If not the first in the chain, we can skip over it */
                        if (prev) {
@@ -1572,9 +1570,8 @@ static int vfio_ecap_init(struct vfio_pci_device *vdev)
                        if (likely(map[epos + i] == PCI_CAP_ID_INVALID))
                                continue;
 
-                       pr_warn("%s: %s pci config conflict @0x%x, was ecap 0x%x now ecap 0x%x\n",
-                               __func__, dev_name(&pdev->dev),
-                               epos + i, map[epos + i], ecap);
+                       pci_warn(pdev, "%s: PCI config conflict @%#x, was ecap %#x now ecap %#x\n",
+                                __func__, epos + i, map[epos + i], ecap);
                }
 
                /*
index 32f695ffe128085b0df8b8c0025e9b420868f6f8..50fe3c4f7feb64494fd028146d11c950ee11d8ec 100644 (file)
@@ -472,6 +472,8 @@ int vfio_pci_ibm_npu2_init(struct vfio_pci_device *vdev)
        return 0;
 
 free_exit:
+       if (data->base)
+               memunmap(data->base);
        kfree(data);
 
        return ret;
index 3ddb2704221d9182969b9153392161074fa99ea4..fe95964bc3be8a779b2b2adda96ee5834ed90110 100644 (file)
@@ -89,7 +89,8 @@ static int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev)
        } while ((pcs_value & MDIO_CTRL1_RESET) && --count);
 
        if (pcs_value & MDIO_CTRL1_RESET)
-               pr_warn("%s XGBE PHY reset timeout\n", __func__);
+               dev_warn(vdev->device, "%s: XGBE PHY reset timeout\n",
+                        __func__);
 
        /* disable auto-negotiation */
        value = xmdio_read(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_CTRL1);
@@ -114,7 +115,7 @@ static int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev)
                usleep_range(500, 600);
 
        if (!count)
-               pr_warn("%s MAC SW reset failed\n", __func__);
+               dev_warn(vdev->device, "%s: MAC SW reset failed\n", __func__);
 
        return 0;
 }
index c0cd824be2b767bea76dbea2d8137125762836c2..2a45b36bcf58e43b4d7b25781c1434a219423901 100644 (file)
@@ -12,6 +12,8 @@
  * GNU General Public License for more details.
  */
 
+#define dev_fmt(fmt)   "VFIO: " fmt
+
 #include <linux/device.h>
 #include <linux/acpi.h>
 #include <linux/iommu.h>
@@ -63,7 +65,7 @@ static int vfio_platform_acpi_probe(struct vfio_platform_device *vdev,
 
        adev = ACPI_COMPANION(dev);
        if (!adev) {
-               pr_err("VFIO: ACPI companion device not found for %s\n",
+               dev_err(dev, "ACPI companion device not found for %s\n",
                        vdev->name);
                return -ENODEV;
        }
@@ -638,7 +640,7 @@ static int vfio_platform_of_probe(struct vfio_platform_device *vdev,
        ret = device_property_read_string(dev, "compatible",
                                          &vdev->compat);
        if (ret)
-               pr_err("VFIO: Cannot retrieve compat for %s\n", vdev->name);
+               dev_err(dev, "Cannot retrieve compat for %s\n", vdev->name);
 
        return ret;
 }
@@ -680,14 +682,14 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev,
 
        ret = vfio_platform_get_reset(vdev);
        if (ret && vdev->reset_required) {
-               pr_err("VFIO: No reset function found for device %s\n",
-                      vdev->name);
+               dev_err(dev, "No reset function found for device %s\n",
+                       vdev->name);
                return ret;
        }
 
        group = vfio_iommu_group_get(dev);
        if (!group) {
-               pr_err("VFIO: No IOMMU group for device %s\n", vdev->name);
+               dev_err(dev, "No IOMMU group for device %s\n", vdev->name);
                ret = -EINVAL;
                goto put_reset;
        }
index a3030cdf3c182c6f276db2b8f78624377e245c4e..82fcf07fa9ea7a08d9a7980c8bd3d25f1cb8c12e 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/uaccess.h>
 #include <linux/vfio.h>
 #include <linux/wait.h>
+#include <linux/sched/signal.h>
 
 #define DRIVER_VERSION "0.3"
 #define DRIVER_AUTHOR  "Alex Williamson <alex.williamson@redhat.com>"
@@ -704,8 +705,8 @@ static int vfio_group_nb_add_dev(struct vfio_group *group, struct device *dev)
                return 0;
 
        /* TODO Prevent device auto probing */
-       WARN(1, "Device %s added to live group %d!\n", dev_name(dev),
-            iommu_group_id(group->iommu_group));
+       dev_WARN(dev, "Device added to live group %d!\n",
+                iommu_group_id(group->iommu_group));
 
        return 0;
 }
@@ -748,25 +749,22 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb,
                 */
                break;
        case IOMMU_GROUP_NOTIFY_BIND_DRIVER:
-               pr_debug("%s: Device %s, group %d binding to driver\n",
-                        __func__, dev_name(dev),
-                        iommu_group_id(group->iommu_group));
+               dev_dbg(dev, "%s: group %d binding to driver\n", __func__,
+                       iommu_group_id(group->iommu_group));
                break;
        case IOMMU_GROUP_NOTIFY_BOUND_DRIVER:
-               pr_debug("%s: Device %s, group %d bound to driver %s\n",
-                        __func__, dev_name(dev),
-                        iommu_group_id(group->iommu_group), dev->driver->name);
+               dev_dbg(dev, "%s: group %d bound to driver %s\n", __func__,
+                       iommu_group_id(group->iommu_group), dev->driver->name);
                BUG_ON(vfio_group_nb_verify(group, dev));
                break;
        case IOMMU_GROUP_NOTIFY_UNBIND_DRIVER:
-               pr_debug("%s: Device %s, group %d unbinding from driver %s\n",
-                        __func__, dev_name(dev),
-                        iommu_group_id(group->iommu_group), dev->driver->name);
+               dev_dbg(dev, "%s: group %d unbinding from driver %s\n",
+                       __func__, iommu_group_id(group->iommu_group),
+                       dev->driver->name);
                break;
        case IOMMU_GROUP_NOTIFY_UNBOUND_DRIVER:
-               pr_debug("%s: Device %s, group %d unbound from driver\n",
-                        __func__, dev_name(dev),
-                        iommu_group_id(group->iommu_group));
+               dev_dbg(dev, "%s: group %d unbound from driver\n", __func__,
+                       iommu_group_id(group->iommu_group));
                /*
                 * XXX An unbound device in a live group is ok, but we'd
                 * really like to avoid the above BUG_ON by preventing other
@@ -830,8 +828,8 @@ int vfio_add_group_dev(struct device *dev,
 
        device = vfio_group_get_device(group, dev);
        if (device) {
-               WARN(1, "Device %s already exists on group %d\n",
-                    dev_name(dev), iommu_group_id(iommu_group));
+               dev_WARN(dev, "Device already exists on group %d\n",
+                        iommu_group_id(iommu_group));
                vfio_device_put(device);
                vfio_group_put(group);
                return -EBUSY;
@@ -904,30 +902,17 @@ void *vfio_device_data(struct vfio_device *device)
 }
 EXPORT_SYMBOL_GPL(vfio_device_data);
 
-/* Given a referenced group, check if it contains the device */
-static bool vfio_dev_present(struct vfio_group *group, struct device *dev)
-{
-       struct vfio_device *device;
-
-       device = vfio_group_get_device(group, dev);
-       if (!device)
-               return false;
-
-       vfio_device_put(device);
-       return true;
-}
-
 /*
  * Decrement the device reference count and wait for the device to be
  * removed.  Open file descriptors for the device... */
 void *vfio_del_group_dev(struct device *dev)
 {
+       DEFINE_WAIT_FUNC(wait, woken_wake_function);
        struct vfio_device *device = dev_get_drvdata(dev);
        struct vfio_group *group = device->group;
        void *device_data = device->device_data;
        struct vfio_unbound_dev *unbound;
        unsigned int i = 0;
-       long ret;
        bool interrupted = false;
 
        /*
@@ -964,6 +949,8 @@ void *vfio_del_group_dev(struct device *dev)
         * interval with counter to allow the driver to take escalating
         * measures to release the device if it has the ability to do so.
         */
+       add_wait_queue(&vfio.release_q, &wait);
+
        do {
                device = vfio_group_get_device(group, dev);
                if (!device)
@@ -975,12 +962,10 @@ void *vfio_del_group_dev(struct device *dev)
                vfio_device_put(device);
 
                if (interrupted) {
-                       ret = wait_event_timeout(vfio.release_q,
-                                       !vfio_dev_present(group, dev), HZ * 10);
+                       wait_woken(&wait, TASK_UNINTERRUPTIBLE, HZ * 10);
                } else {
-                       ret = wait_event_interruptible_timeout(vfio.release_q,
-                                       !vfio_dev_present(group, dev), HZ * 10);
-                       if (ret == -ERESTARTSYS) {
+                       wait_woken(&wait, TASK_INTERRUPTIBLE, HZ * 10);
+                       if (signal_pending(current)) {
                                interrupted = true;
                                dev_warn(dev,
                                         "Device is currently in use, task"
@@ -989,8 +974,10 @@ void *vfio_del_group_dev(struct device *dev)
                                         current->comm, task_pid_nr(current));
                        }
                }
-       } while (ret <= 0);
 
+       } while (1);
+
+       remove_wait_queue(&vfio.release_q, &wait);
        /*
         * In order to support multiple devices per group, devices can be
         * plucked from the group while other devices in the group are still
index 6b64e45a52691ffd9dd4809d0e127fc8c450cf80..40ddc0c5f677c6a2db46ab3c2f7855fabcf09da7 100644 (file)
@@ -532,7 +532,8 @@ static int tce_iommu_use_page(unsigned long tce, unsigned long *hpa)
        enum dma_data_direction direction = iommu_tce_direction(tce);
 
        if (get_user_pages_fast(tce & PAGE_MASK, 1,
-                       direction != DMA_TO_DEVICE, &page) != 1)
+                       direction != DMA_TO_DEVICE ? FOLL_WRITE : 0,
+                       &page) != 1)
                return -EFAULT;
 
        *hpa = __pa((unsigned long) page_address(page));
index d0f731c9920a65a44d614181ecf3a4e4c2d90755..3ddc375e70635bd5eec73966eb3a9e822df40b51 100644 (file)
@@ -97,6 +97,7 @@ struct vfio_dma {
 struct vfio_group {
        struct iommu_group      *iommu_group;
        struct list_head        next;
+       bool                    mdev_group;     /* An mdev group */
 };
 
 /*
@@ -357,7 +358,8 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr,
 
        down_read(&mm->mmap_sem);
        if (mm == current->mm) {
-               ret = get_user_pages_longterm(vaddr, 1, flags, page, vmas);
+               ret = get_user_pages(vaddr, 1, flags | FOLL_LONGTERM, page,
+                                    vmas);
        } else {
                ret = get_user_pages_remote(NULL, mm, vaddr, 1, flags, page,
                                            vmas, NULL);
@@ -564,7 +566,7 @@ static int vfio_iommu_type1_pin_pages(void *iommu_data,
        mutex_lock(&iommu->lock);
 
        /* Fail if notifier list is empty */
-       if ((!iommu->external_domain) || (!iommu->notifier.head)) {
+       if (!iommu->notifier.head) {
                ret = -EINVAL;
                goto pin_done;
        }
@@ -646,11 +648,6 @@ static int vfio_iommu_type1_unpin_pages(void *iommu_data,
 
        mutex_lock(&iommu->lock);
 
-       if (!iommu->external_domain) {
-               mutex_unlock(&iommu->lock);
-               return -EINVAL;
-       }
-
        do_accounting = !IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu);
        for (i = 0; i < npage; i++) {
                struct vfio_dma *dma;
@@ -1311,13 +1308,109 @@ static bool vfio_iommu_has_sw_msi(struct iommu_group *group, phys_addr_t *base)
        return ret;
 }
 
+static struct device *vfio_mdev_get_iommu_device(struct device *dev)
+{
+       struct device *(*fn)(struct device *dev);
+       struct device *iommu_device;
+
+       fn = symbol_get(mdev_get_iommu_device);
+       if (fn) {
+               iommu_device = fn(dev);
+               symbol_put(mdev_get_iommu_device);
+
+               return iommu_device;
+       }
+
+       return NULL;
+}
+
+static int vfio_mdev_attach_domain(struct device *dev, void *data)
+{
+       struct iommu_domain *domain = data;
+       struct device *iommu_device;
+
+       iommu_device = vfio_mdev_get_iommu_device(dev);
+       if (iommu_device) {
+               if (iommu_dev_feature_enabled(iommu_device, IOMMU_DEV_FEAT_AUX))
+                       return iommu_aux_attach_device(domain, iommu_device);
+               else
+                       return iommu_attach_device(domain, iommu_device);
+       }
+
+       return -EINVAL;
+}
+
+static int vfio_mdev_detach_domain(struct device *dev, void *data)
+{
+       struct iommu_domain *domain = data;
+       struct device *iommu_device;
+
+       iommu_device = vfio_mdev_get_iommu_device(dev);
+       if (iommu_device) {
+               if (iommu_dev_feature_enabled(iommu_device, IOMMU_DEV_FEAT_AUX))
+                       iommu_aux_detach_device(domain, iommu_device);
+               else
+                       iommu_detach_device(domain, iommu_device);
+       }
+
+       return 0;
+}
+
+static int vfio_iommu_attach_group(struct vfio_domain *domain,
+                                  struct vfio_group *group)
+{
+       if (group->mdev_group)
+               return iommu_group_for_each_dev(group->iommu_group,
+                                               domain->domain,
+                                               vfio_mdev_attach_domain);
+       else
+               return iommu_attach_group(domain->domain, group->iommu_group);
+}
+
+static void vfio_iommu_detach_group(struct vfio_domain *domain,
+                                   struct vfio_group *group)
+{
+       if (group->mdev_group)
+               iommu_group_for_each_dev(group->iommu_group, domain->domain,
+                                        vfio_mdev_detach_domain);
+       else
+               iommu_detach_group(domain->domain, group->iommu_group);
+}
+
+static bool vfio_bus_is_mdev(struct bus_type *bus)
+{
+       struct bus_type *mdev_bus;
+       bool ret = false;
+
+       mdev_bus = symbol_get(mdev_bus_type);
+       if (mdev_bus) {
+               ret = (bus == mdev_bus);
+               symbol_put(mdev_bus_type);
+       }
+
+       return ret;
+}
+
+static int vfio_mdev_iommu_device(struct device *dev, void *data)
+{
+       struct device **old = data, *new;
+
+       new = vfio_mdev_get_iommu_device(dev);
+       if (!new || (*old && *old != new))
+               return -EINVAL;
+
+       *old = new;
+
+       return 0;
+}
+
 static int vfio_iommu_type1_attach_group(void *iommu_data,
                                         struct iommu_group *iommu_group)
 {
        struct vfio_iommu *iommu = iommu_data;
        struct vfio_group *group;
        struct vfio_domain *domain, *d;
-       struct bus_type *bus = NULL, *mdev_bus;
+       struct bus_type *bus = NULL;
        int ret;
        bool resv_msi, msi_remap;
        phys_addr_t resv_msi_base;
@@ -1352,23 +1445,30 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
        if (ret)
                goto out_free;
 
-       mdev_bus = symbol_get(mdev_bus_type);
+       if (vfio_bus_is_mdev(bus)) {
+               struct device *iommu_device = NULL;
 
-       if (mdev_bus) {
-               if ((bus == mdev_bus) && !iommu_present(bus)) {
-                       symbol_put(mdev_bus_type);
+               group->mdev_group = true;
+
+               /* Determine the isolation type */
+               ret = iommu_group_for_each_dev(iommu_group, &iommu_device,
+                                              vfio_mdev_iommu_device);
+               if (ret || !iommu_device) {
                        if (!iommu->external_domain) {
                                INIT_LIST_HEAD(&domain->group_list);
                                iommu->external_domain = domain;
-                       } else
+                       } else {
                                kfree(domain);
+                       }
 
                        list_add(&group->next,
                                 &iommu->external_domain->group_list);
                        mutex_unlock(&iommu->lock);
+
                        return 0;
                }
-               symbol_put(mdev_bus_type);
+
+               bus = iommu_device->bus;
        }
 
        domain->domain = iommu_domain_alloc(bus);
@@ -1386,7 +1486,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
                        goto out_domain;
        }
 
-       ret = iommu_attach_group(domain->domain, iommu_group);
+       ret = vfio_iommu_attach_group(domain, group);
        if (ret)
                goto out_domain;
 
@@ -1418,8 +1518,8 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
        list_for_each_entry(d, &iommu->domain_list, next) {
                if (d->domain->ops == domain->domain->ops &&
                    d->prot == domain->prot) {
-                       iommu_detach_group(domain->domain, iommu_group);
-                       if (!iommu_attach_group(d->domain, iommu_group)) {
+                       vfio_iommu_detach_group(domain, group);
+                       if (!vfio_iommu_attach_group(d, group)) {
                                list_add(&group->next, &d->group_list);
                                iommu_domain_free(domain->domain);
                                kfree(domain);
@@ -1427,7 +1527,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
                                return 0;
                        }
 
-                       ret = iommu_attach_group(domain->domain, iommu_group);
+                       ret = vfio_iommu_attach_group(domain, group);
                        if (ret)
                                goto out_domain;
                }
@@ -1453,7 +1553,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
        return 0;
 
 out_detach:
-       iommu_detach_group(domain->domain, iommu_group);
+       vfio_iommu_detach_group(domain, group);
 out_domain:
        iommu_domain_free(domain->domain);
 out_free:
@@ -1544,7 +1644,7 @@ static void vfio_iommu_type1_detach_group(void *iommu_data,
                if (!group)
                        continue;
 
-               iommu_detach_group(domain->domain, iommu_group);
+               vfio_iommu_detach_group(domain, group);
                list_del(&group->next);
                kfree(group);
                /*
@@ -1610,7 +1710,7 @@ static void vfio_release_domain(struct vfio_domain *domain, bool external)
        list_for_each_entry_safe(group, group_tmp,
                                 &domain->group_list, next) {
                if (!external)
-                       iommu_detach_group(domain->domain, group->iommu_group);
+                       vfio_iommu_detach_group(domain, group);
                list_del(&group->next);
                kfree(group);
        }
index 618fb646101768ebfb5ddd71166d6420d42e3caa..c090d177bd75cf2c006b39d848038806748040a4 100644 (file)
@@ -1443,7 +1443,6 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs,
                        tpg->tv_tpg_vhost_count++;
                        tpg->vhost_scsi = vs;
                        vs_tpg[tpg->tport_tpgt] = tpg;
-                       smp_mb__after_atomic();
                        match = true;
                }
                mutex_unlock(&tpg->tv_tpg_mutex);
index 351af88231ada1145bfb72326f905bfaac3819ca..1e3ed41ae1f3f35bea447b6667ebd36427b3a7be 100644 (file)
@@ -1704,7 +1704,7 @@ static int set_bit_to_user(int nr, void __user *addr)
        int bit = nr + (log % PAGE_SIZE) * 8;
        int r;
 
-       r = get_user_pages_fast(log, 1, 1, &page);
+       r = get_user_pages_fast(log, 1, FOLL_WRITE, &page);
        if (r < 0)
                return r;
        BUG_ON(r != 1);
index 71ee978c848f3abaf74178ad4c397aad45e1a62c..3ed1d9084f942688cf67b005c8af16a33b58e11d 100644 (file)
@@ -2,13 +2,7 @@
 # Backlight & LCD drivers configuration
 #
 
-menuconfig BACKLIGHT_LCD_SUPPORT
-       bool "Backlight & LCD device support"
-       help
-         Enable this to be able to choose the drivers for controlling the
-         backlight and the LCD panel on some platforms, for example on PDAs.
-
-if BACKLIGHT_LCD_SUPPORT
+menu "Backlight & LCD device support"
 
 #
 # LCD
@@ -199,7 +193,6 @@ config BACKLIGHT_IPAQ_MICRO
 
 config BACKLIGHT_LM3533
        tristate "Backlight Driver for LM3533"
-       depends on BACKLIGHT_CLASS_DEVICE
        depends on MFD_LM3533
        help
          Say Y to enable the backlight driver for National Semiconductor / TI
@@ -323,7 +316,7 @@ config BACKLIGHT_ADP5520
 
 config BACKLIGHT_ADP8860
        tristate "Backlight Driver for ADP8860/ADP8861/ADP8863 using WLED"
-       depends on BACKLIGHT_CLASS_DEVICE && I2C
+       depends on I2C
        select NEW_LEDS
        select LEDS_CLASS
        help
@@ -335,7 +328,7 @@ config BACKLIGHT_ADP8860
 
 config BACKLIGHT_ADP8870
        tristate "Backlight Driver for ADP8870 using WLED"
-       depends on BACKLIGHT_CLASS_DEVICE && I2C
+       depends on I2C
        select NEW_LEDS
        select LEDS_CLASS
        help
@@ -353,28 +346,28 @@ config BACKLIGHT_88PM860X
 
 config BACKLIGHT_PCF50633
        tristate "Backlight driver for NXP PCF50633 MFD"
-       depends on BACKLIGHT_CLASS_DEVICE && MFD_PCF50633
+       depends on MFD_PCF50633
        help
          If you have a backlight driven by a NXP PCF50633 MFD, say Y here to
          enable its driver.
 
 config BACKLIGHT_AAT2870
        tristate "AnalogicTech AAT2870 Backlight"
-       depends on BACKLIGHT_CLASS_DEVICE && MFD_AAT2870_CORE
+       depends on MFD_AAT2870_CORE
        help
          If you have a AnalogicTech AAT2870 say Y to enable the
          backlight driver.
 
 config BACKLIGHT_LM3630A
        tristate "Backlight Driver for LM3630A"
-       depends on BACKLIGHT_CLASS_DEVICE && I2C && PWM
+       depends on I2C && PWM
        select REGMAP_I2C
        help
          This supports TI LM3630A Backlight Driver
 
 config BACKLIGHT_LM3639
        tristate "Backlight Driver for LM3639"
-       depends on BACKLIGHT_CLASS_DEVICE && I2C
+       depends on I2C
        select REGMAP_I2C
        select NEW_LEDS
        select LEDS_CLASS
@@ -383,20 +376,20 @@ config BACKLIGHT_LM3639
 
 config BACKLIGHT_LP855X
        tristate "Backlight driver for TI LP855X"
-       depends on BACKLIGHT_CLASS_DEVICE && I2C && PWM
+       depends on I2C && PWM
        help
          This supports TI LP8550, LP8551, LP8552, LP8553, LP8555, LP8556 and
          LP8557 backlight driver.
 
 config BACKLIGHT_LP8788
        tristate "Backlight driver for TI LP8788 MFD"
-       depends on BACKLIGHT_CLASS_DEVICE && MFD_LP8788 && PWM
+       depends on MFD_LP8788 && PWM
        help
          This supports TI LP8788 backlight driver.
 
 config BACKLIGHT_OT200
        tristate "Backlight driver for ot200 visualisation device"
-       depends on BACKLIGHT_CLASS_DEVICE && CS5535_MFGPT && GPIO_CS5535
+       depends on CS5535_MFGPT && GPIO_CS5535
        help
          To compile this driver as a module, choose M here: the module will be
          called ot200_bl.
@@ -410,7 +403,7 @@ config BACKLIGHT_PANDORA
 
 config BACKLIGHT_SKY81452
        tristate "Backlight driver for SKY81452"
-       depends on BACKLIGHT_CLASS_DEVICE && MFD_SKY81452
+       depends on MFD_SKY81452
        help
          If you have a Skyworks SKY81452, say Y to enable the
          backlight driver.
@@ -420,14 +413,14 @@ config BACKLIGHT_SKY81452
 
 config BACKLIGHT_TPS65217
        tristate "TPS65217 Backlight"
-       depends on BACKLIGHT_CLASS_DEVICE && MFD_TPS65217
+       depends on MFD_TPS65217
        help
          If you have a Texas Instruments TPS65217 say Y to enable the
          backlight driver.
 
 config BACKLIGHT_AS3711
        tristate "AS3711 Backlight"
-       depends on BACKLIGHT_CLASS_DEVICE && MFD_AS3711
+       depends on MFD_AS3711
        help
          If you have an Austrian Microsystems AS3711 say Y to enable the
          backlight driver.
@@ -466,4 +459,4 @@ config BACKLIGHT_RAVE_SP
 
 endif # BACKLIGHT_CLASS_DEVICE
 
-endif # BACKLIGHT_LCD_SUPPORT
+endmenu
index 2030a6b77a09725e97bb1618b2695aea5c55f2a0..75d996490cf0a31a0e3a661a4075d103b7de73c1 100644 (file)
 #define REG_MAX                0x50
 
 #define INT_DEBOUNCE_MSEC      10
+
+#define LM3630A_BANK_0         0
+#define LM3630A_BANK_1         1
+
+#define LM3630A_NUM_SINKS      2
+#define LM3630A_SINK_0         0
+#define LM3630A_SINK_1         1
+
 struct lm3630a_chip {
        struct device *dev;
        struct delayed_work work;
@@ -201,7 +209,7 @@ static int lm3630a_bank_a_update_status(struct backlight_device *bl)
                                      LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE);
        if (ret < 0)
                goto out_i2c_err;
-       return bl->props.brightness;
+       return 0;
 
 out_i2c_err:
        dev_err(pchip->dev, "i2c failed to access\n");
@@ -278,7 +286,7 @@ static int lm3630a_bank_b_update_status(struct backlight_device *bl)
                                      LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE);
        if (ret < 0)
                goto out_i2c_err;
-       return bl->props.brightness;
+       return 0;
 
 out_i2c_err:
        dev_err(pchip->dev, "i2c failed to access REG_CTRL\n");
@@ -329,15 +337,17 @@ static const struct backlight_ops lm3630a_bank_b_ops = {
 
 static int lm3630a_backlight_register(struct lm3630a_chip *pchip)
 {
-       struct backlight_properties props;
        struct lm3630a_platform_data *pdata = pchip->pdata;
+       struct backlight_properties props;
+       const char *label;
 
        props.type = BACKLIGHT_RAW;
        if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) {
                props.brightness = pdata->leda_init_brt;
                props.max_brightness = pdata->leda_max_brt;
+               label = pdata->leda_label ? pdata->leda_label : "lm3630a_leda";
                pchip->bleda =
-                   devm_backlight_device_register(pchip->dev, "lm3630a_leda",
+                   devm_backlight_device_register(pchip->dev, label,
                                                   pchip->dev, pchip,
                                                   &lm3630a_bank_a_ops, &props);
                if (IS_ERR(pchip->bleda))
@@ -348,8 +358,9 @@ static int lm3630a_backlight_register(struct lm3630a_chip *pchip)
            (pdata->ledb_ctrl != LM3630A_LEDB_ON_A)) {
                props.brightness = pdata->ledb_init_brt;
                props.max_brightness = pdata->ledb_max_brt;
+               label = pdata->ledb_label ? pdata->ledb_label : "lm3630a_ledb";
                pchip->bledb =
-                   devm_backlight_device_register(pchip->dev, "lm3630a_ledb",
+                   devm_backlight_device_register(pchip->dev, label,
                                                   pchip->dev, pchip,
                                                   &lm3630a_bank_b_ops, &props);
                if (IS_ERR(pchip->bledb))
@@ -364,6 +375,123 @@ static const struct regmap_config lm3630a_regmap = {
        .max_register = REG_MAX,
 };
 
+static int lm3630a_parse_led_sources(struct fwnode_handle *node,
+                                    int default_led_sources)
+{
+       u32 sources[LM3630A_NUM_SINKS];
+       int ret, num_sources, i;
+
+       num_sources = fwnode_property_read_u32_array(node, "led-sources", NULL,
+                                                    0);
+       if (num_sources < 0)
+               return default_led_sources;
+       else if (num_sources > ARRAY_SIZE(sources))
+               return -EINVAL;
+
+       ret = fwnode_property_read_u32_array(node, "led-sources", sources,
+                                            num_sources);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < num_sources; i++) {
+               if (sources[i] < LM3630A_SINK_0 || sources[i] > LM3630A_SINK_1)
+                       return -EINVAL;
+
+               ret |= BIT(sources[i]);
+       }
+
+       return ret;
+}
+
+static int lm3630a_parse_bank(struct lm3630a_platform_data *pdata,
+                             struct fwnode_handle *node, int *seen_led_sources)
+{
+       int led_sources, ret;
+       const char *label;
+       u32 bank, val;
+       bool linear;
+
+       ret = fwnode_property_read_u32(node, "reg", &bank);
+       if (ret)
+               return ret;
+
+       if (bank < LM3630A_BANK_0 || bank > LM3630A_BANK_1)
+               return -EINVAL;
+
+       led_sources = lm3630a_parse_led_sources(node, BIT(bank));
+       if (led_sources < 0)
+               return led_sources;
+
+       if (*seen_led_sources & led_sources)
+               return -EINVAL;
+
+       *seen_led_sources |= led_sources;
+
+       linear = fwnode_property_read_bool(node,
+                                          "ti,linear-mapping-mode");
+       if (bank) {
+               if (led_sources & BIT(LM3630A_SINK_0) ||
+                   !(led_sources & BIT(LM3630A_SINK_1)))
+                       return -EINVAL;
+
+               pdata->ledb_ctrl = linear ?
+                       LM3630A_LEDB_ENABLE_LINEAR :
+                       LM3630A_LEDB_ENABLE;
+       } else {
+               if (!(led_sources & BIT(LM3630A_SINK_0)))
+                       return -EINVAL;
+
+               pdata->leda_ctrl = linear ?
+                       LM3630A_LEDA_ENABLE_LINEAR :
+                       LM3630A_LEDA_ENABLE;
+
+               if (led_sources & BIT(LM3630A_SINK_1))
+                       pdata->ledb_ctrl = LM3630A_LEDB_ON_A;
+       }
+
+       ret = fwnode_property_read_string(node, "label", &label);
+       if (!ret) {
+               if (bank)
+                       pdata->ledb_label = label;
+               else
+                       pdata->leda_label = label;
+       }
+
+       ret = fwnode_property_read_u32(node, "default-brightness",
+                                      &val);
+       if (!ret) {
+               if (bank)
+                       pdata->ledb_init_brt = val;
+               else
+                       pdata->leda_init_brt = val;
+       }
+
+       ret = fwnode_property_read_u32(node, "max-brightness", &val);
+       if (!ret) {
+               if (bank)
+                       pdata->ledb_max_brt = val;
+               else
+                       pdata->leda_max_brt = val;
+       }
+
+       return 0;
+}
+
+static int lm3630a_parse_node(struct lm3630a_chip *pchip,
+                             struct lm3630a_platform_data *pdata)
+{
+       int ret = -ENODEV, seen_led_sources = 0;
+       struct fwnode_handle *node;
+
+       device_for_each_child_node(pchip->dev, node) {
+               ret = lm3630a_parse_bank(pdata, node, &seen_led_sources);
+               if (ret)
+                       return ret;
+       }
+
+       return ret;
+}
+
 static int lm3630a_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
@@ -396,13 +524,18 @@ static int lm3630a_probe(struct i2c_client *client,
                                     GFP_KERNEL);
                if (pdata == NULL)
                        return -ENOMEM;
+
                /* default values */
-               pdata->leda_ctrl = LM3630A_LEDA_ENABLE;
-               pdata->ledb_ctrl = LM3630A_LEDB_ENABLE;
                pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS;
                pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS;
                pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS;
                pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS;
+
+               rval = lm3630a_parse_node(pchip, pdata);
+               if (rval) {
+                       dev_err(&client->dev, "fail : parse node\n");
+                       return rval;
+               }
        }
        pchip->pdata = pdata;
 
@@ -470,11 +603,17 @@ static const struct i2c_device_id lm3630a_id[] = {
        {}
 };
 
+static const struct of_device_id lm3630a_match_table[] = {
+       { .compatible = "ti,lm3630a", },
+       { },
+};
+
 MODULE_DEVICE_TABLE(i2c, lm3630a_id);
 
 static struct i2c_driver lm3630a_i2c_driver = {
        .driver = {
                   .name = LM3630A_NAME,
+                  .of_match_table = lm3630a_match_table,
                   },
        .probe = lm3630a_probe,
        .remove = lm3630a_remove,
index 53b8ceea9bde15d8fb48b0679f34a496a00e77a8..fb45f866b92349cd61e92d42a994252923750496 100644 (file)
@@ -155,21 +155,6 @@ static const struct backlight_ops pwm_backlight_ops = {
 #ifdef CONFIG_OF
 #define PWM_LUMINANCE_SCALE    10000 /* luminance scale */
 
-/* An integer based power function */
-static u64 int_pow(u64 base, int exp)
-{
-       u64 result = 1;
-
-       while (exp) {
-               if (exp & 1)
-                       result *= base;
-               exp >>= 1;
-               base *= base;
-       }
-
-       return result;
-}
-
 /*
  * CIE lightness to PWM conversion.
  *
index 58a9590c9db6d377023ebb69ee01fd12d9c33962..bf6b77b964f19681d487d27ed05d5e1e1bf45cb0 100644 (file)
@@ -45,25 +45,25 @@ menuconfig FB
          device-aware may cause unexpected results. If unsure, say N.
 
 config FIRMWARE_EDID
-       bool "Enable firmware EDID"
-       depends on FB
-       ---help---
-         This enables access to the EDID transferred from the firmware.
-        On the i386, this is from the Video BIOS. Enable this if DDC/I2C
-        transfers do not work for your driver and if you are using
-        nvidiafb, i810fb or savagefb.
-
-        In general, choosing Y for this option is safe.  If you
-        experience extremely long delays while booting before you get
-        something on your display, try setting this to N.  Matrox cards in
-        combination with certain motherboards and monitors are known to
-        suffer from this problem.
+       bool "Enable firmware EDID"
+       depends on FB
+       ---help---
+         This enables access to the EDID transferred from the firmware.
+         On the i386, this is from the Video BIOS. Enable this if DDC/I2C
+         transfers do not work for your driver and if you are using
+         nvidiafb, i810fb or savagefb.
+
+         In general, choosing Y for this option is safe.  If you
+         experience extremely long delays while booting before you get
+         something on your display, try setting this to N.  Matrox cards in
+         combination with certain motherboards and monitors are known to
+         suffer from this problem.
 
 config FB_DDC
-       tristate
-       depends on FB
-       select I2C_ALGOBIT
-       select I2C
+       tristate
+       depends on FB
+       select I2C_ALGOBIT
+       select I2C
 
 config FB_BOOT_VESA_SUPPORT
        bool
@@ -160,8 +160,8 @@ config FB_LITTLE_ENDIAN
 endchoice
 
 config FB_SYS_FOPS
-       tristate
-       depends on FB
+       tristate
+       depends on FB
 
 config FB_DEFERRED_IO
        bool
@@ -180,41 +180,40 @@ config FB_SVGALIB
          cards.
 
 config FB_MACMODES
-       tristate
-       depends on FB
+       tristate
+       depends on FB
 
 config FB_BACKLIGHT
        tristate
        depends on FB
-       select BACKLIGHT_LCD_SUPPORT
        select BACKLIGHT_CLASS_DEVICE
 
 config FB_MODE_HELPERS
-        bool "Enable Video Mode Handling Helpers"
-        depends on FB
+       bool "Enable Video Mode Handling Helpers"
+       depends on FB
        ---help---
          This enables functions for handling video modes using the
          Generalized Timing Formula and the EDID parser. A few drivers rely
-          on this feature such as the radeonfb, rivafb, and the i810fb. If
+         on this feature such as the radeonfb, rivafb, and the i810fb. If
          your driver does not take advantage of this feature, choosing Y will
          just increase the kernel size by about 5K.
 
 config FB_TILEBLITTING
-       bool "Enable Tile Blitting Support"
-       depends on FB
-       ---help---
-         This enables tile blitting.  Tile blitting is a drawing technique
-        where the screen is divided into rectangular sections (tiles), whereas
-        the standard blitting divides the screen into pixels. Because the
-        default drawing element is a tile, drawing functions will be passed
-        parameters in terms of number of tiles instead of number of pixels.
-        For example, to draw a single character, instead of using bitmaps,
-        an index to an array of bitmaps will be used.  To clear or move a
-        rectangular section of a screen, the rectangle will be described in
-        terms of number of tiles in the x- and y-axis.
-
-        This is particularly important to one driver, matroxfb.  If
-        unsure, say N.
+       bool "Enable Tile Blitting Support"
+       depends on FB
+       ---help---
+         This enables tile blitting.  Tile blitting is a drawing technique
+         where the screen is divided into rectangular sections (tiles), whereas
+         the standard blitting divides the screen into pixels. Because the
+         default drawing element is a tile, drawing functions will be passed
+         parameters in terms of number of tiles instead of number of pixels.
+         For example, to draw a single character, instead of using bitmaps,
+         an index to an array of bitmaps will be used.  To clear or move a
+         rectangular section of a screen, the rectangle will be described in
+         terms of number of tiles in the x- and y-axis.
+
+         This is particularly important to one driver, matroxfb.  If
+         unsure, say N.
 
 comment "Frame buffer hardware drivers"
        depends on FB
@@ -226,7 +225,7 @@ config FB_GRVGA
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        ---help---
-       This enables support for the SVGACTRL framebuffer in the GRLIB IP library from Aeroflex Gaisler.
+         This enables support for the SVGACTRL framebuffer in the GRLIB IP library from Aeroflex Gaisler.
 
 config FB_CIRRUS
        tristate "Cirrus Logic support"
@@ -281,7 +280,6 @@ config FB_ARMCLCD
        select FB_CFB_IMAGEBLIT
        select FB_MODE_HELPERS if OF
        select VIDEOMODE_HELPERS if OF
-       select BACKLIGHT_LCD_SUPPORT if OF
        select BACKLIGHT_CLASS_DEVICE if OF
        help
          This framebuffer device driver is for the ARM PrimeCell PL110
@@ -293,14 +291,6 @@ config FB_ARMCLCD
          here and read <file:Documentation/kbuild/modules.txt>.  The module
          will be called amba-clcd.
 
-# Helper logic selected only by the ARM Versatile platform family.
-config PLAT_VERSATILE_CLCD
-       def_bool ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || ARCH_INTEGRATOR
-       depends on ARM
-       depends on FB_ARMCLCD && FB=y
-       select REGMAP
-       select MFD_SYSCON
-
 config FB_ACORN
        bool "Acorn VIDC support"
        depends on (FB = y) && ARM && ARCH_ACORN
@@ -315,7 +305,6 @@ config FB_ACORN
 config FB_CLPS711X
        tristate "CLPS711X LCD support"
        depends on FB && (ARCH_CLPS711X || COMPILE_TEST)
-       select BACKLIGHT_LCD_SUPPORT
        select FB_MODE_HELPERS
        select FB_SYS_FILLRECT
        select FB_SYS_COPYAREA
@@ -343,7 +332,6 @@ config FB_SA1100
 config FB_IMX
        tristate "Freescale i.MX1/21/25/27 LCD support"
        depends on FB && ARCH_MXC
-       select BACKLIGHT_LCD_SUPPORT
        select LCD_CLASS_DEVICE
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
@@ -655,17 +643,17 @@ config FB_EFI
          using the EFI framebuffer as your console.
 
 config FB_N411
-       tristate "N411 Apollo/Hecuba devkit support"
-       depends on FB && X86 && MMU
-       select FB_SYS_FILLRECT
-       select FB_SYS_COPYAREA
-       select FB_SYS_IMAGEBLIT
-       select FB_SYS_FOPS
-       select FB_DEFERRED_IO
-       select FB_HECUBA
-       help
-         This enables support for the Apollo display controller in its
-         Hecuba form using the n411 devkit.
+       tristate "N411 Apollo/Hecuba devkit support"
+       depends on FB && X86 && MMU
+       select FB_SYS_FILLRECT
+       select FB_SYS_COPYAREA
+       select FB_SYS_IMAGEBLIT
+       select FB_SYS_FOPS
+       select FB_DEFERRED_IO
+       select FB_HECUBA
+       help
+         This enables support for the Apollo display controller in its
+         Hecuba form using the n411 devkit.
 
 config FB_HGA
        tristate "Hercules mono graphics support"
@@ -685,7 +673,7 @@ config FB_GBE
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
-       help
+       help
          This is the frame buffer device driver for SGI Graphics Backend.
          This chip is used in SGI O2 and Visual Workstation 320/540.
 
@@ -866,8 +854,8 @@ config FB_S1D13XXX
          <http://vdc.epson.com/>
 
 config FB_ATMEL
-       tristate "AT91/AT32 LCD Controller support"
-       depends on FB && HAVE_FB_ATMEL
+       tristate "AT91 LCD Controller support"
+       depends on FB && OF && HAVE_FB_ATMEL
        select FB_BACKLIGHT
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
@@ -875,7 +863,7 @@ config FB_ATMEL
        select FB_MODE_HELPERS
        select VIDEOMODE_HELPERS
        help
-         This enables support for the AT91/AT32 LCD Controller.
+         This enables support for the AT91 LCD Controller.
 
 config FB_NVIDIA
        tristate "nVidia Framebuffer Support"
@@ -897,10 +885,10 @@ config FB_NVIDIA
          module will be called nvidiafb.
 
 config FB_NVIDIA_I2C
-       bool "Enable DDC Support"
-       depends on FB_NVIDIA
-       select FB_DDC
-       help
+       bool "Enable DDC Support"
+       depends on FB_NVIDIA
+       select FB_DDC
+       help
          This enables I2C support for nVidia Chipsets.  This is used
          only for getting EDID information from the attached display
          allowing for robust video mode handling and switching.
@@ -943,10 +931,10 @@ config FB_RIVA
          module will be called rivafb.
 
 config FB_RIVA_I2C
-       bool "Enable DDC Support"
-       depends on FB_RIVA
-       select FB_DDC
-       help
+       bool "Enable DDC Support"
+       depends on FB_RIVA
+       select FB_DDC
+       help
          This enables I2C support for nVidia Chipsets.  This is used
          only for getting EDID information from the attached display
          allowing for robust video mode handling and switching.
@@ -991,37 +979,37 @@ config FB_I810
        select FB_CFB_IMAGEBLIT
        select VGASTATE
        help
-         This driver supports the on-board graphics built in to the Intel 810 
-          and 815 chipsets.  Say Y if you have and plan to use such a board.
+         This driver supports the on-board graphics built in to the Intel 810
+         and 815 chipsets.  Say Y if you have and plan to use such a board.
 
-          To compile this driver as a module, choose M here: the
+         To compile this driver as a module, choose M here: the
          module will be called i810fb.
 
-          For more information, please read 
+         For more information, please read
          <file:Documentation/fb/intel810.txt>
 
 config FB_I810_GTF
        bool "use VESA Generalized Timing Formula"
        depends on FB_I810
        help
-         If you say Y, then the VESA standard, Generalized Timing Formula 
-          or GTF, will be used to calculate the required video timing values
-         per video mode.  Since the GTF allows nondiscrete timings 
-          (nondiscrete being a range of values as opposed to discrete being a
-          set of values), you'll be able to use any combination of horizontal 
+         If you say Y, then the VESA standard, Generalized Timing Formula
+         or GTF, will be used to calculate the required video timing values
+         per video mode.  Since the GTF allows nondiscrete timings
+         (nondiscrete being a range of values as opposed to discrete being a
+         set of values), you'll be able to use any combination of horizontal
          and vertical resolutions, and vertical refresh rates without having
          to specify your own timing parameters.  This is especially useful
-         to maximize the performance of an aging display, or if you just 
-          have a display with nonstandard dimensions. A VESA compliant 
+         to maximize the performance of an aging display, or if you just
+         have a display with nonstandard dimensions. A VESA compliant
          monitor is recommended, but can still work with non-compliant ones.
-         If you need or want this, then select this option. The timings may 
-         not be compliant with Intel's recommended values. Use at your own 
+         If you need or want this, then select this option. The timings may
+         not be compliant with Intel's recommended values. Use at your own
          risk.
 
-          If you say N, the driver will revert to discrete video timings 
+         If you say N, the driver will revert to discrete video timings
          using a set recommended by Intel in their documentation.
-  
-          If unsure, say N.
+
+         If unsure, say N.
 
 config FB_I810_I2C
        bool "Enable DDC Support"
@@ -1060,8 +1048,8 @@ config FB_INTEL
        depends on !DRM_I915
        help
          This driver supports the on-board graphics built in to the Intel
-          830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets.
-          Say Y if you have and plan to use such a board.
+         830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets.
+         Say Y if you have and plan to use such a board.
 
          To make FB_INTEL=Y work you need to say AGP_INTEL=y too.
 
@@ -1142,10 +1130,10 @@ config FB_MATROX_G
          G450/G550 secondary head and digital output are supported without
          additional modules.
 
-         The driver starts in monitor mode. You must use the matroxset tool 
-         (available at <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to 
-         swap primary and secondary head outputs, or to change output mode.  
-         Secondary head driver always start in 640x480 resolution and you 
+         The driver starts in monitor mode. You must use the matroxset tool
+         (available at <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to
+         swap primary and secondary head outputs, or to change output mode.
+         Secondary head driver always start in 640x480 resolution and you
          must use fbset to change it.
 
          Do not forget that second head supports only 16 and 32 bpp
@@ -1228,7 +1216,7 @@ config FB_RADEON_I2C
        select FB_DDC
        default y
        help
-         Say Y here if you want DDC/I2C support for your Radeon board. 
+         Say Y here if you want DDC/I2C support for your Radeon board.
 
 config FB_RADEON_BACKLIGHT
        bool "Support for backlight control"
@@ -1357,10 +1345,10 @@ config FB_SAVAGE
          will be called savagefb.
 
 config FB_SAVAGE_I2C
-       bool "Enable DDC2 Support"
-       depends on FB_SAVAGE
-       select FB_DDC
-       help
+       bool "Enable DDC2 Support"
+       depends on FB_SAVAGE
+       select FB_DDC
+       help
          This enables I2C support for S3 Savage Chipsets.  This is used
          only for getting EDID information from the attached display
          allowing for robust video mode handling and switching.
@@ -1370,12 +1358,12 @@ config FB_SAVAGE_I2C
          here.
 
 config FB_SAVAGE_ACCEL
-       bool "Enable Console Acceleration"
-       depends on FB_SAVAGE
-       help
-          This option will compile in console acceleration support. If
-          the resulting framebuffer console has bothersome glitches, then
-          choose N here.
+       bool "Enable Console Acceleration"
+       depends on FB_SAVAGE
+       help
+         This option will compile in console acceleration support. If
+         the resulting framebuffer console has bothersome glitches, then
+         choose N here.
 
 config FB_SIS
        tristate "SiS/XGI display support"
@@ -1408,17 +1396,17 @@ config FB_SIS_315
          as XGI V3XT, V5, V8 and Z7.
 
 config FB_VIA
-       tristate "VIA UniChrome (Pro) and Chrome9 display support"
-       depends on FB && PCI && GPIOLIB && I2C && (X86 || COMPILE_TEST)
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
-       select I2C_ALGOBIT
-       help
+       tristate "VIA UniChrome (Pro) and Chrome9 display support"
+       depends on FB && PCI && GPIOLIB && I2C && (X86 || COMPILE_TEST)
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       select I2C_ALGOBIT
+       help
          This is the frame buffer device driver for Graphics chips of VIA
          UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/
          CN700/VN800,CX700/VX700,P4M890) and Chrome9 Family (K8M890,CN896
-         /P4M900,VX800)
+         /P4M900,VX800)
          Say Y if you have a VIA UniChrome graphics board.
 
          To compile this driver as a module, choose M here: the
@@ -1455,7 +1443,7 @@ config FB_NEOMAGIC
        select VGASTATE
        help
          This driver supports notebooks with NeoMagic PCI chips.
-         Say Y if you have such a graphics card. 
+         Say Y if you have such a graphics card.
 
          To compile this driver as a module, choose M here: the
          module will be called neofb.
@@ -1510,7 +1498,7 @@ config FB_VOODOO1
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        ---help---
-         Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or 
+         Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or
          Voodoo2 (cvg) based graphics card.
 
          To compile this driver as a module, choose M here: the
@@ -1679,9 +1667,9 @@ config FB_HIT
 config FB_PMAG_AA
        tristate "PMAG-AA TURBOchannel framebuffer support"
        depends on FB && TC
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
        help
          Support for the PMAG-AA TURBOchannel framebuffer card (1280x1024x1)
          used mainly in the MIPS-based DECstation series.
@@ -1689,9 +1677,9 @@ config FB_PMAG_AA
 config FB_PMAG_BA
        tristate "PMAG-BA TURBOchannel framebuffer support"
        depends on FB && TC
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
        help
          Support for the PMAG-BA TURBOchannel framebuffer card (1024x864x8)
          used mainly in the MIPS-based DECstation series.
@@ -1699,9 +1687,9 @@ config FB_PMAG_BA
 config FB_PMAGB_B
        tristate "PMAGB-B TURBOchannel framebuffer support"
        depends on FB && TC
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
        help
          Support for the PMAGB-B TURBOchannel framebuffer card used mainly
          in the MIPS-based DECstation series. The card is currently only
@@ -1710,9 +1698,9 @@ config FB_PMAGB_B
 config FB_MAXINE
        bool "Maxine (Personal DECstation) onboard framebuffer support"
        depends on (FB = y) && MACH_DECSTATION
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
        help
          Support for the onboard framebuffer (1024x768x8) in the Personal
          DECstation series (Personal DECstation 5000/20, /25, /33, /50,
@@ -1721,9 +1709,9 @@ config FB_MAXINE
 config FB_G364
        bool "G364 frame buffer support"
        depends on (FB = y) && (MIPS_MAGNUM_4000 || OLIVETTI_M700)
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
        help
          The G364 driver is the framebuffer used in MIPS Magnum 4000 and
          Olivetti M700-10 systems.
@@ -1731,9 +1719,9 @@ config FB_G364
 config FB_68328
        bool "Motorola 68328 native frame buffer support"
        depends on (FB = y) && (M68328 || M68EZ328 || M68VZ328)
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
        help
          Say Y here if you want to support the built-in frame buffer of
          the Motorola 68328 CPU family.
@@ -1812,13 +1800,13 @@ config FB_MBX
          Accelerator
 
 config FB_MBX_DEBUG
-       bool "Enable debugging info via debugfs"
-       depends on FB_MBX && DEBUG_FS
-       ---help---
-         Enable this if you want debugging information using the debug
-         filesystem (debugfs)
+       bool "Enable debugging info via debugfs"
+       depends on FB_MBX && DEBUG_FS
+       ---help---
+         Enable this if you want debugging information using the debug
+         filesystem (debugfs)
 
-         If unsure, say N.
+         If unsure, say N.
 
 config FB_FSL_DIU
        tristate "Freescale DIU framebuffer support"
@@ -1834,9 +1822,9 @@ config FB_FSL_DIU
 config FB_W100
        tristate "W100 frame buffer support"
        depends on FB && ARCH_PXA
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
        ---help---
          Frame buffer driver for the w100 as found on the Sharp SL-Cxx series.
          It can also drive the w3220 chip found on iPAQ hx4700.
@@ -1901,10 +1889,10 @@ config FB_S3C
          Currently the support is only for the S3C6400 and S3C6410 SoCs.
 
 config FB_S3C_DEBUG_REGWRITE
-       bool "Debug register writes"
-       depends on FB_S3C
-       ---help---
-         Show all register writes via pr_debug()
+       bool "Debug register writes"
+       depends on FB_S3C
+       ---help---
+         Show all register writes via pr_debug()
 
 config FB_S3C2410
        tristate "S3C2410 LCD framebuffer support"
@@ -1930,18 +1918,18 @@ config FB_S3C2410_DEBUG
          through sysfs
 
 config FB_NUC900
-        tristate "NUC900 LCD framebuffer support"
-        depends on FB && ARCH_W90X900
-        select FB_CFB_FILLRECT
-        select FB_CFB_COPYAREA
-        select FB_CFB_IMAGEBLIT
-        ---help---
-          Frame buffer driver for the built-in LCD controller in the Nuvoton
-          NUC900 processor
+       tristate "NUC900 LCD framebuffer support"
+       depends on FB && ARCH_W90X900
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       ---help---
+         Frame buffer driver for the built-in LCD controller in the Nuvoton
+         NUC900 processor
 
 config GPM1040A0_320X240
-        bool "Giantplus Technology GPM1040A0 320x240 Color TFT LCD"
-        depends on FB_NUC900
+       bool "Giantplus Technology GPM1040A0 320x240 Color TFT LCD"
+       depends on FB_NUC900
 
 config FB_SM501
        tristate "Silicon Motion SM501 framebuffer support"
@@ -2183,7 +2171,7 @@ config FB_EP93XX
 
 config FB_PRE_INIT_FB
        bool "Don't reinitialize, use bootloader's GDC/Display configuration"
-       depends on FB && FB_MB862XX_LIME
+       depends on FB && (FB_MB862XX_LIME || FB_MXS)
        ---help---
          Select this option if display contents should be inherited as set by
          the bootloader.
@@ -2192,7 +2180,6 @@ config FB_MX3
        tristate "MX3 Framebuffer support"
        depends on FB && MX3_IPU
        select BACKLIGHT_CLASS_DEVICE
-       select BACKLIGHT_LCD_SUPPORT
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
index 846b0c9ea9db7541c1bc2c347846af0e2437d877..655f2537cac13b8c4ec70837f9006b76a7df2d50 100644 (file)
@@ -76,8 +76,6 @@ obj-$(CONFIG_FB_ATMEL)                  += atmel_lcdfb.o
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
 obj-$(CONFIG_FB_ARMCLCD)         += amba-clcd.o
-obj-$(CONFIG_ARCH_NOMADIK)       += amba-clcd-nomadik.o
-obj-$(CONFIG_PLAT_VERSATILE_CLCD) += amba-clcd-versatile.o
 obj-$(CONFIG_FB_GOLDFISH)         += goldfishfb.o
 obj-$(CONFIG_FB_68328)            += 68328fb.o
 obj-$(CONFIG_FB_GBE)              += gbefb.o
diff --git a/drivers/video/fbdev/amba-clcd-nomadik.c b/drivers/video/fbdev/amba-clcd-nomadik.c
deleted file mode 100644 (file)
index cd2db11..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-#include <linux/amba/bus.h>
-#include <linux/amba/clcd.h>
-#include <linux/gpio/consumer.h>
-#include <linux/of.h>
-#include <linux/of_graph.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/mfd/syscon.h>
-#include <linux/regmap.h>
-
-#include "amba-clcd-nomadik.h"
-
-static struct gpio_desc *grestb;
-static struct gpio_desc *scen;
-static struct gpio_desc *scl;
-static struct gpio_desc *sda;
-
-static u8 tpg110_readwrite_reg(bool write, u8 address, u8 outval)
-{
-       int i;
-       u8 inval = 0;
-
-       /* Assert SCEN */
-       gpiod_set_value_cansleep(scen, 1);
-       ndelay(150);
-       /* Hammer out the address */
-       for (i = 5; i >= 0; i--) {
-               if (address & BIT(i))
-                       gpiod_set_value_cansleep(sda, 1);
-               else
-                       gpiod_set_value_cansleep(sda, 0);
-               ndelay(150);
-               /* Send an SCL pulse */
-               gpiod_set_value_cansleep(scl, 1);
-               ndelay(160);
-               gpiod_set_value_cansleep(scl, 0);
-               ndelay(160);
-       }
-
-       if (write) {
-               /* WRITE */
-               gpiod_set_value_cansleep(sda, 0);
-       } else {
-               /* READ */
-               gpiod_set_value_cansleep(sda, 1);
-       }
-       ndelay(150);
-       /* Send an SCL pulse */
-       gpiod_set_value_cansleep(scl, 1);
-       ndelay(160);
-       gpiod_set_value_cansleep(scl, 0);
-       ndelay(160);
-
-       if (!write)
-               /* HiZ turn-around cycle */
-               gpiod_direction_input(sda);
-       ndelay(150);
-       /* Send an SCL pulse */
-       gpiod_set_value_cansleep(scl, 1);
-       ndelay(160);
-       gpiod_set_value_cansleep(scl, 0);
-       ndelay(160);
-
-       /* Hammer in/out the data */
-       for (i = 7; i >= 0; i--) {
-               int value;
-
-               if (write) {
-                       value = !!(outval & BIT(i));
-                       gpiod_set_value_cansleep(sda, value);
-               } else {
-                       value = gpiod_get_value(sda);
-                       if (value)
-                               inval |= BIT(i);
-               }
-               ndelay(150);
-               /* Send an SCL pulse */
-               gpiod_set_value_cansleep(scl, 1);
-               ndelay(160);
-               gpiod_set_value_cansleep(scl, 0);
-               ndelay(160);
-       }
-
-       gpiod_direction_output(sda, 0);
-       /* Deassert SCEN */
-       gpiod_set_value_cansleep(scen, 0);
-       /* Satisfies SCEN pulse width */
-       udelay(1);
-
-       return inval;
-}
-
-static u8 tpg110_read_reg(u8 address)
-{
-       return tpg110_readwrite_reg(false, address, 0);
-}
-
-static void tpg110_write_reg(u8 address, u8 outval)
-{
-       tpg110_readwrite_reg(true, address, outval);
-}
-
-static void tpg110_startup(struct device *dev)
-{
-       u8 val;
-
-       dev_info(dev, "TPG110 display enable\n");
-       /* De-assert the reset signal */
-       gpiod_set_value_cansleep(grestb, 0);
-       mdelay(1);
-       dev_info(dev, "de-asserted GRESTB\n");
-
-       /* Test display communication */
-       tpg110_write_reg(0x00, 0x55);
-       val = tpg110_read_reg(0x00);
-       if (val == 0x55)
-               dev_info(dev, "passed communication test\n");
-       val = tpg110_read_reg(0x01);
-       dev_info(dev, "TPG110 chip ID: %d version: %d\n",
-               val>>4, val&0x0f);
-
-       /* Show display resolution */
-       val = tpg110_read_reg(0x02);
-       val &= 7;
-       switch (val) {
-       case 0x0:
-               dev_info(dev, "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)");
-               break;
-       case 0x1:
-               dev_info(dev, "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)");
-               break;
-       case 0x4:
-               dev_info(dev, "480x640 RGB");
-               break;
-       case 0x5:
-               dev_info(dev, "480x272 RGB");
-               break;
-       case 0x6:
-               dev_info(dev, "640x480 RGB");
-               break;
-       case 0x7:
-               dev_info(dev, "800x480 RGB");
-               break;
-       default:
-               dev_info(dev, "ILLEGAL RESOLUTION");
-               break;
-       }
-
-       val = tpg110_read_reg(0x03);
-       dev_info(dev, "resolution is controlled by %s\n",
-               (val & BIT(7)) ? "software" : "hardware");
-}
-
-static void tpg110_enable(struct clcd_fb *fb)
-{
-       struct device *dev = &fb->dev->dev;
-       static bool startup;
-       u8 val;
-
-       if (!startup) {
-               tpg110_startup(dev);
-               startup = true;
-       }
-
-       /* Take chip out of standby */
-       val = tpg110_read_reg(0x03);
-       val |= BIT(0);
-       tpg110_write_reg(0x03, val);
-}
-
-static void tpg110_disable(struct clcd_fb *fb)
-{
-       u8 val;
-
-       dev_info(&fb->dev->dev, "TPG110 display disable\n");
-       val = tpg110_read_reg(0x03);
-       /* Put into standby */
-       val &= ~BIT(0);
-       tpg110_write_reg(0x03, val);
-}
-
-static void tpg110_init(struct device *dev, struct device_node *np,
-                       struct clcd_board *board)
-{
-       dev_info(dev, "TPG110 display init\n");
-
-       /* This asserts the GRESTB signal, putting the display into reset */
-       grestb = devm_fwnode_get_gpiod_from_child(dev, "grestb", &np->fwnode,
-                                                 GPIOD_OUT_HIGH, "grestb");
-       if (IS_ERR(grestb)) {
-               dev_err(dev, "no GRESTB GPIO\n");
-               return;
-       }
-       scen = devm_fwnode_get_gpiod_from_child(dev, "scen", &np->fwnode,
-                                               GPIOD_OUT_LOW, "scen");
-       if (IS_ERR(scen)) {
-               dev_err(dev, "no SCEN GPIO\n");
-               return;
-       }
-       scl = devm_fwnode_get_gpiod_from_child(dev, "scl", &np->fwnode,
-                                              GPIOD_OUT_LOW, "scl");
-       if (IS_ERR(scl)) {
-               dev_err(dev, "no SCL GPIO\n");
-               return;
-       }
-       sda = devm_fwnode_get_gpiod_from_child(dev, "sda", &np->fwnode,
-                                              GPIOD_OUT_LOW, "sda");
-       if (IS_ERR(sda)) {
-               dev_err(dev, "no SDA GPIO\n");
-               return;
-       }
-       board->enable = tpg110_enable;
-       board->disable = tpg110_disable;
-}
-
-int nomadik_clcd_init_panel(struct clcd_fb *fb, struct device_node *panel)
-{
-       if (of_device_is_compatible(panel, "tpo,tpg110"))
-               tpg110_init(&fb->dev->dev, panel, fb->board);
-       else
-               dev_info(&fb->dev->dev, "unknown panel\n");
-
-       /* Unknown panel, fall through */
-       return 0;
-}
-EXPORT_SYMBOL_GPL(nomadik_clcd_init_panel);
-
-#define PMU_CTRL_OFFSET 0x0000
-#define PMU_CTRL_LCDNDIF BIT(26)
-
-int nomadik_clcd_init_board(struct amba_device *adev,
-                           struct clcd_board *board)
-{
-       struct regmap *pmu_regmap;
-
-       dev_info(&adev->dev, "Nomadik CLCD board init\n");
-       pmu_regmap =
-               syscon_regmap_lookup_by_compatible("stericsson,nomadik-pmu");
-       if (IS_ERR(pmu_regmap)) {
-               dev_err(&adev->dev, "could not find PMU syscon regmap\n");
-               return PTR_ERR(pmu_regmap);
-       }
-       regmap_update_bits(pmu_regmap,
-                          PMU_CTRL_OFFSET,
-                          PMU_CTRL_LCDNDIF,
-                          0);
-       dev_info(&adev->dev, "set PMU mux to CLCD mode\n");
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(nomadik_clcd_init_board);
diff --git a/drivers/video/fbdev/amba-clcd-nomadik.h b/drivers/video/fbdev/amba-clcd-nomadik.h
deleted file mode 100644 (file)
index 462c313..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _AMBA_CLCD_NOMADIK_H
-#define _AMBA_CLCD_NOMADIK_H
-
-#include <linux/amba/bus.h>
-
-#ifdef CONFIG_ARCH_NOMADIK
-int nomadik_clcd_init_board(struct amba_device *adev,
-                            struct clcd_board *board);
-int nomadik_clcd_init_panel(struct clcd_fb *fb, struct device_node *panel);
-#else
-static inline int nomadik_clcd_init_board(struct amba_device *adev,
-                                         struct clcd_board *board)
-{
-       return 0;
-}
-static inline int nomadik_clcd_init_panel(struct clcd_fb *fb,
-                                         struct device_node *panel)
-{
-       return 0;
-}
-#endif
-
-#endif /* inclusion guard */
diff --git a/drivers/video/fbdev/amba-clcd-versatile.c b/drivers/video/fbdev/amba-clcd-versatile.c
deleted file mode 100644 (file)
index d42047d..0000000
+++ /dev/null
@@ -1,567 +0,0 @@
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/clcd.h>
-#include <linux/platform_data/video-clcd-versatile.h>
-#include <linux/of.h>
-#include <linux/of_graph.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/bitops.h>
-#include "amba-clcd-versatile.h"
-
-static struct clcd_panel vga = {
-       .mode           = {
-               .name           = "VGA",
-               .refresh        = 60,
-               .xres           = 640,
-               .yres           = 480,
-               .pixclock       = 39721,
-               .left_margin    = 40,
-               .right_margin   = 24,
-               .upper_margin   = 32,
-               .lower_margin   = 11,
-               .hsync_len      = 96,
-               .vsync_len      = 2,
-               .sync           = 0,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_BCD | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
-       .caps           = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
-       .bpp            = 16,
-};
-
-static struct clcd_panel xvga = {
-       .mode           = {
-               .name           = "XVGA",
-               .refresh        = 60,
-               .xres           = 1024,
-               .yres           = 768,
-               .pixclock       = 15748,
-               .left_margin    = 152,
-               .right_margin   = 48,
-               .upper_margin   = 23,
-               .lower_margin   = 3,
-               .hsync_len      = 104,
-               .vsync_len      = 4,
-               .sync           = 0,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_BCD | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
-       .caps           = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
-       .bpp            = 16,
-};
-
-/* Sanyo TM38QV67A02A - 3.8 inch QVGA (320x240) Color TFT */
-static struct clcd_panel sanyo_tm38qv67a02a = {
-       .mode           = {
-               .name           = "Sanyo TM38QV67A02A",
-               .refresh        = 116,
-               .xres           = 320,
-               .yres           = 240,
-               .pixclock       = 100000,
-               .left_margin    = 6,
-               .right_margin   = 6,
-               .upper_margin   = 5,
-               .lower_margin   = 5,
-               .hsync_len      = 6,
-               .vsync_len      = 6,
-               .sync           = 0,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_BCD,
-       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
-       .caps           = CLCD_CAP_5551,
-       .bpp            = 16,
-};
-
-static struct clcd_panel sanyo_2_5_in = {
-       .mode           = {
-               .name           = "Sanyo QVGA Portrait",
-               .refresh        = 116,
-               .xres           = 240,
-               .yres           = 320,
-               .pixclock       = 100000,
-               .left_margin    = 20,
-               .right_margin   = 10,
-               .upper_margin   = 2,
-               .lower_margin   = 2,
-               .hsync_len      = 10,
-               .vsync_len      = 2,
-               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_IVS | TIM2_IHS | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
-       .caps           = CLCD_CAP_5551,
-       .bpp            = 16,
-};
-
-/* Epson L2F50113T00 - 2.2 inch 176x220 Color TFT */
-static struct clcd_panel epson_l2f50113t00 = {
-       .mode           = {
-               .name           = "Epson L2F50113T00",
-               .refresh        = 390,
-               .xres           = 176,
-               .yres           = 220,
-               .pixclock       = 62500,
-               .left_margin    = 3,
-               .right_margin   = 2,
-               .upper_margin   = 1,
-               .lower_margin   = 0,
-               .hsync_len      = 3,
-               .vsync_len      = 2,
-               .sync           = 0,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_BCD | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
-       .caps           = CLCD_CAP_5551,
-       .bpp            = 16,
-};
-
-static struct clcd_panel *panels[] = {
-       &vga,
-       &xvga,
-       &sanyo_tm38qv67a02a,
-       &sanyo_2_5_in,
-       &epson_l2f50113t00,
-};
-
-struct clcd_panel *versatile_clcd_get_panel(const char *name)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(panels); i++)
-               if (strcmp(panels[i]->mode.name, name) == 0)
-                       break;
-
-       if (i < ARRAY_SIZE(panels))
-               return panels[i];
-
-       pr_err("CLCD: couldn't get parameters for panel %s\n", name);
-
-       return NULL;
-}
-
-int versatile_clcd_setup_dma(struct clcd_fb *fb, unsigned long framesize)
-{
-       dma_addr_t dma;
-
-       fb->fb.screen_base = dma_alloc_wc(&fb->dev->dev, framesize, &dma,
-                                         GFP_KERNEL);
-       if (!fb->fb.screen_base) {
-               pr_err("CLCD: unable to map framebuffer\n");
-               return -ENOMEM;
-       }
-
-       fb->fb.fix.smem_start   = dma;
-       fb->fb.fix.smem_len     = framesize;
-
-       return 0;
-}
-
-int versatile_clcd_mmap_dma(struct clcd_fb *fb, struct vm_area_struct *vma)
-{
-       return dma_mmap_wc(&fb->dev->dev, vma, fb->fb.screen_base,
-                          fb->fb.fix.smem_start, fb->fb.fix.smem_len);
-}
-
-void versatile_clcd_remove_dma(struct clcd_fb *fb)
-{
-       dma_free_wc(&fb->dev->dev, fb->fb.fix.smem_len, fb->fb.screen_base,
-                   fb->fb.fix.smem_start);
-}
-
-#ifdef CONFIG_OF
-
-static struct regmap *versatile_syscon_map;
-static struct regmap *versatile_ib2_map;
-
-/*
- * We detect the different syscon types from the compatible strings.
- */
-enum versatile_clcd {
-       INTEGRATOR_CLCD_CM,
-       VERSATILE_CLCD,
-       REALVIEW_CLCD_EB,
-       REALVIEW_CLCD_PB1176,
-       REALVIEW_CLCD_PB11MP,
-       REALVIEW_CLCD_PBA8,
-       REALVIEW_CLCD_PBX,
-};
-
-static const struct of_device_id versatile_clcd_of_match[] = {
-       {
-               .compatible = "arm,core-module-integrator",
-               .data = (void *)INTEGRATOR_CLCD_CM,
-       },
-       {
-               .compatible = "arm,versatile-sysreg",
-               .data = (void *)VERSATILE_CLCD,
-       },
-       {
-               .compatible = "arm,realview-eb-syscon",
-               .data = (void *)REALVIEW_CLCD_EB,
-       },
-       {
-               .compatible = "arm,realview-pb1176-syscon",
-               .data = (void *)REALVIEW_CLCD_PB1176,
-       },
-       {
-               .compatible = "arm,realview-pb11mp-syscon",
-               .data = (void *)REALVIEW_CLCD_PB11MP,
-       },
-       {
-               .compatible = "arm,realview-pba8-syscon",
-               .data = (void *)REALVIEW_CLCD_PBA8,
-       },
-       {
-               .compatible = "arm,realview-pbx-syscon",
-               .data = (void *)REALVIEW_CLCD_PBX,
-       },
-       {},
-};
-
-/*
- * Core module CLCD control on the Integrator/CP, bits
- * 8 thru 19 of the CM_CONTROL register controls a bunch
- * of CLCD settings.
- */
-#define INTEGRATOR_HDR_CTRL_OFFSET     0x0C
-#define INTEGRATOR_CLCD_LCDBIASEN      BIT(8)
-#define INTEGRATOR_CLCD_LCDBIASUP      BIT(9)
-#define INTEGRATOR_CLCD_LCDBIASDN      BIT(10)
-/* Bits 11,12,13 controls the LCD type */
-#define INTEGRATOR_CLCD_LCDMUX_MASK    (BIT(11)|BIT(12)|BIT(13))
-#define INTEGRATOR_CLCD_LCDMUX_LCD24   BIT(11)
-#define INTEGRATOR_CLCD_LCDMUX_VGA565  BIT(12)
-#define INTEGRATOR_CLCD_LCDMUX_SHARP   (BIT(11)|BIT(12))
-#define INTEGRATOR_CLCD_LCDMUX_VGA555  BIT(13)
-#define INTEGRATOR_CLCD_LCDMUX_VGA24   (BIT(11)|BIT(12)|BIT(13))
-#define INTEGRATOR_CLCD_LCD0_EN                BIT(14)
-#define INTEGRATOR_CLCD_LCD1_EN                BIT(15)
-/* R/L flip on Sharp */
-#define INTEGRATOR_CLCD_LCD_STATIC1    BIT(16)
-/* U/D flip on Sharp */
-#define INTEGRATOR_CLCD_LCD_STATIC2    BIT(17)
-/* No connection on Sharp */
-#define INTEGRATOR_CLCD_LCD_STATIC     BIT(18)
-/* 0 = 24bit VGA, 1 = 18bit VGA */
-#define INTEGRATOR_CLCD_LCD_N24BITEN   BIT(19)
-
-#define INTEGRATOR_CLCD_MASK           (INTEGRATOR_CLCD_LCDBIASEN | \
-                                        INTEGRATOR_CLCD_LCDBIASUP | \
-                                        INTEGRATOR_CLCD_LCDBIASDN | \
-                                        INTEGRATOR_CLCD_LCDMUX_MASK | \
-                                        INTEGRATOR_CLCD_LCD0_EN | \
-                                        INTEGRATOR_CLCD_LCD1_EN | \
-                                        INTEGRATOR_CLCD_LCD_STATIC1 | \
-                                        INTEGRATOR_CLCD_LCD_STATIC2 | \
-                                        INTEGRATOR_CLCD_LCD_STATIC | \
-                                        INTEGRATOR_CLCD_LCD_N24BITEN)
-
-static void integrator_clcd_enable(struct clcd_fb *fb)
-{
-       struct fb_var_screeninfo *var = &fb->fb.var;
-       u32 val;
-
-       dev_info(&fb->dev->dev, "enable Integrator CLCD connectors\n");
-
-       /* FIXME: really needed? */
-       val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 |
-               INTEGRATOR_CLCD_LCD0_EN | INTEGRATOR_CLCD_LCD1_EN;
-       if (var->bits_per_pixel <= 8 ||
-           (var->bits_per_pixel == 16 && var->green.length == 5))
-               /* Pseudocolor, RGB555, BGR555 */
-               val |= INTEGRATOR_CLCD_LCDMUX_VGA555;
-       else if (fb->fb.var.bits_per_pixel <= 16)
-               /* truecolor RGB565 */
-               val |= INTEGRATOR_CLCD_LCDMUX_VGA565;
-       else
-               val = 0; /* no idea for this, don't trust the docs */
-
-       regmap_update_bits(versatile_syscon_map,
-                          INTEGRATOR_HDR_CTRL_OFFSET,
-                          INTEGRATOR_CLCD_MASK,
-                          val);
-}
-
-/*
- * This configuration register in the Versatile and RealView
- * family is uniformly present but appears more and more
- * unutilized starting with the RealView series.
- */
-#define SYS_CLCD                       0x50
-#define SYS_CLCD_MODE_MASK             (BIT(0)|BIT(1))
-#define SYS_CLCD_MODE_888              0
-#define SYS_CLCD_MODE_5551             BIT(0)
-#define SYS_CLCD_MODE_565_R_LSB                BIT(1)
-#define SYS_CLCD_MODE_565_B_LSB                (BIT(0)|BIT(1))
-#define SYS_CLCD_CONNECTOR_MASK                (BIT(2)|BIT(3)|BIT(4)|BIT(5))
-#define SYS_CLCD_NLCDIOON              BIT(2)
-#define SYS_CLCD_VDDPOSSWITCH          BIT(3)
-#define SYS_CLCD_PWR3V5SWITCH          BIT(4)
-#define SYS_CLCD_VDDNEGSWITCH          BIT(5)
-#define SYS_CLCD_TSNSS                 BIT(6) /* touchscreen enable */
-#define SYS_CLCD_SSPEXP                        BIT(7) /* SSP expansion enable */
-
-/* The Versatile can detect the connected panel type */
-#define SYS_CLCD_CLCDID_MASK           (BIT(8)|BIT(9)|BIT(10)|BIT(11)|BIT(12))
-#define SYS_CLCD_ID_SANYO_3_8          (0x00 << 8)
-#define SYS_CLCD_ID_SHARP_8_4          (0x01 << 8)
-#define SYS_CLCD_ID_EPSON_2_2          (0x02 << 8)
-#define SYS_CLCD_ID_SANYO_2_5          (0x07 << 8)
-#define SYS_CLCD_ID_VGA                        (0x1f << 8)
-
-#define SYS_CLCD_TSNDAV                        BIT(13) /* data ready from TS */
-
-/* IB2 control register for the Versatile daughterboard */
-#define IB2_CTRL                       0x00
-#define IB2_CTRL_LCD_SD                        BIT(1) /* 1 = shut down LCD */
-#define IB2_CTRL_LCD_BL_ON             BIT(0)
-#define IB2_CTRL_LCD_MASK              (BIT(0)|BIT(1))
-
-static void versatile_clcd_disable(struct clcd_fb *fb)
-{
-       dev_info(&fb->dev->dev, "disable Versatile CLCD connectors\n");
-       regmap_update_bits(versatile_syscon_map,
-                          SYS_CLCD,
-                          SYS_CLCD_CONNECTOR_MASK,
-                          0);
-
-       /* If we're on an IB2 daughterboard, turn off display */
-       if (versatile_ib2_map) {
-               dev_info(&fb->dev->dev, "disable IB2 display\n");
-               regmap_update_bits(versatile_ib2_map,
-                                  IB2_CTRL,
-                                  IB2_CTRL_LCD_MASK,
-                                  IB2_CTRL_LCD_SD);
-       }
-}
-
-static void versatile_clcd_enable(struct clcd_fb *fb)
-{
-       struct fb_var_screeninfo *var = &fb->fb.var;
-       u32 val = 0;
-
-       dev_info(&fb->dev->dev, "enable Versatile CLCD connectors\n");
-       switch (var->green.length) {
-       case 5:
-               val |= SYS_CLCD_MODE_5551;
-               break;
-       case 6:
-               if (var->red.offset == 0)
-                       val |= SYS_CLCD_MODE_565_R_LSB;
-               else
-                       val |= SYS_CLCD_MODE_565_B_LSB;
-               break;
-       case 8:
-               val |= SYS_CLCD_MODE_888;
-               break;
-       }
-
-       /* Set up the MUX */
-       regmap_update_bits(versatile_syscon_map,
-                          SYS_CLCD,
-                          SYS_CLCD_MODE_MASK,
-                          val);
-
-       /* Then enable the display */
-       regmap_update_bits(versatile_syscon_map,
-                          SYS_CLCD,
-                          SYS_CLCD_CONNECTOR_MASK,
-                          SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
-
-       /* If we're on an IB2 daughterboard, turn on display */
-       if (versatile_ib2_map) {
-               dev_info(&fb->dev->dev, "enable IB2 display\n");
-               regmap_update_bits(versatile_ib2_map,
-                                  IB2_CTRL,
-                                  IB2_CTRL_LCD_MASK,
-                                  IB2_CTRL_LCD_BL_ON);
-       }
-}
-
-static void versatile_clcd_decode(struct clcd_fb *fb, struct clcd_regs *regs)
-{
-       clcdfb_decode(fb, regs);
-
-       /* Always clear BGR for RGB565: we do the routing externally */
-       if (fb->fb.var.green.length == 6)
-               regs->cntl &= ~CNTL_BGR;
-}
-
-static void realview_clcd_disable(struct clcd_fb *fb)
-{
-       dev_info(&fb->dev->dev, "disable RealView CLCD connectors\n");
-       regmap_update_bits(versatile_syscon_map,
-                          SYS_CLCD,
-                          SYS_CLCD_CONNECTOR_MASK,
-                          0);
-}
-
-static void realview_clcd_enable(struct clcd_fb *fb)
-{
-       dev_info(&fb->dev->dev, "enable RealView CLCD connectors\n");
-       regmap_update_bits(versatile_syscon_map,
-                          SYS_CLCD,
-                          SYS_CLCD_CONNECTOR_MASK,
-                          SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
-}
-
-struct versatile_panel {
-       u32 id;
-       char *compatible;
-       bool ib2;
-};
-
-static const struct versatile_panel versatile_panels[] = {
-       {
-               .id = SYS_CLCD_ID_VGA,
-               .compatible = "VGA",
-       },
-       {
-               .id = SYS_CLCD_ID_SANYO_3_8,
-               .compatible = "sanyo,tm38qv67a02a",
-       },
-       {
-               .id = SYS_CLCD_ID_SHARP_8_4,
-               .compatible = "sharp,lq084v1dg21",
-       },
-       {
-               .id = SYS_CLCD_ID_EPSON_2_2,
-               .compatible = "epson,l2f50113t00",
-       },
-       {
-               .id = SYS_CLCD_ID_SANYO_2_5,
-               .compatible = "sanyo,alr252rgt",
-               .ib2 = true,
-       },
-};
-
-static void versatile_panel_probe(struct device *dev, struct device_node *panel)
-{
-       struct versatile_panel const *vpanel = NULL;
-       u32 val;
-       int ret;
-       int i;
-
-       /*
-        * The Versatile CLCD has a panel auto-detection mechanism.
-        * We use this and look for the compatible panel in the
-        * device tree.
-        */
-       ret = regmap_read(versatile_syscon_map, SYS_CLCD, &val);
-       if (ret) {
-               dev_err(dev, "cannot read CLCD syscon register\n");
-               return;
-       }
-       val &= SYS_CLCD_CLCDID_MASK;
-
-       /* First find corresponding panel information */
-       for (i = 0; i < ARRAY_SIZE(versatile_panels); i++) {
-               vpanel = &versatile_panels[i];
-
-               if (val == vpanel->id) {
-                       dev_err(dev, "autodetected panel \"%s\"\n",
-                               vpanel->compatible);
-                       break;
-               }
-       }
-       if (i == ARRAY_SIZE(versatile_panels)) {
-               dev_err(dev, "could not auto-detect panel\n");
-               return;
-       }
-
-       if (!of_device_is_compatible(panel, vpanel->compatible))
-               dev_err(dev, "panel in DT is not compatible with the "
-                       "auto-detected panel, continuing anyway\n");
-
-       /*
-        * If we have a Sanyo 2.5" port
-        * that we're running on an IB2 and proceed to look for the
-        * IB2 syscon regmap.
-        */
-       if (!vpanel->ib2)
-               return;
-
-       versatile_ib2_map = syscon_regmap_lookup_by_compatible(
-               "arm,versatile-ib2-syscon");
-       if (IS_ERR(versatile_ib2_map)) {
-               dev_err(dev, "could not locate IB2 control register\n");
-               versatile_ib2_map = NULL;
-               return;
-       }
-}
-
-int versatile_clcd_init_panel(struct clcd_fb *fb, struct device_node *panel)
-{
-       const struct of_device_id *clcd_id;
-       enum versatile_clcd versatile_clcd_type;
-       struct device_node *np;
-       struct regmap *map;
-       struct device *dev = &fb->dev->dev;
-
-       np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match,
-                                            &clcd_id);
-       if (!np) {
-               /* Vexpress does not have this */
-               return 0;
-       }
-       versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
-
-       map = syscon_node_to_regmap(np);
-       if (IS_ERR(map)) {
-               dev_err(dev, "no Versatile syscon regmap\n");
-               return PTR_ERR(map);
-       }
-
-       switch (versatile_clcd_type) {
-       case INTEGRATOR_CLCD_CM:
-               versatile_syscon_map = map;
-               fb->board->enable = integrator_clcd_enable;
-               /* Override the caps, we have only these */
-               fb->board->caps = CLCD_CAP_5551 | CLCD_CAP_RGB565 |
-                       CLCD_CAP_888;
-               dev_info(dev, "set up callbacks for Integrator PL110\n");
-               break;
-       case VERSATILE_CLCD:
-               versatile_syscon_map = map;
-               fb->board->enable = versatile_clcd_enable;
-               fb->board->disable = versatile_clcd_disable;
-               fb->board->decode = versatile_clcd_decode;
-               versatile_panel_probe(dev, panel);
-               dev_info(dev, "set up callbacks for Versatile\n");
-               break;
-       case REALVIEW_CLCD_EB:
-       case REALVIEW_CLCD_PB1176:
-       case REALVIEW_CLCD_PB11MP:
-       case REALVIEW_CLCD_PBA8:
-       case REALVIEW_CLCD_PBX:
-               versatile_syscon_map = map;
-               fb->board->enable = realview_clcd_enable;
-               fb->board->disable = realview_clcd_disable;
-               dev_info(dev, "set up callbacks for RealView PL111\n");
-               break;
-       default:
-               dev_info(dev, "unknown Versatile system controller\n");
-               break;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(versatile_clcd_init_panel);
-#endif
diff --git a/drivers/video/fbdev/amba-clcd-versatile.h b/drivers/video/fbdev/amba-clcd-versatile.h
deleted file mode 100644 (file)
index b20baa4..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Special local versatile callbacks
- */
-#include <linux/of.h>
-#include <linux/amba/bus.h>
-#include <linux/platform_data/video-clcd-versatile.h>
-
-#if defined(CONFIG_PLAT_VERSATILE_CLCD) && defined(CONFIG_OF)
-int versatile_clcd_init_panel(struct clcd_fb *fb, struct device_node *panel);
-#else
-static inline int versatile_clcd_init_panel(struct clcd_fb *fb,
-                                           struct device_node *panel)
-{
-       return 0;
-}
-#endif
index 38c1f324ce15d98d513e7dfd613c9a7e835f5979..89324e42a03392f2c381d98a70461f519d9b23a1 100644 (file)
@@ -30,9 +30,6 @@
 #include <video/of_display_timing.h>
 #include <video/videomode.h>
 
-#include "amba-clcd-nomadik.h"
-#include "amba-clcd-versatile.h"
-
 #define to_clcd(info)  container_of(info, struct clcd_fb, fb)
 
 /* This is limited to 16 characters when displayed by X startup */
@@ -223,15 +220,6 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
                        var->blue.length = 4;
                }
                break;
-       case 24:
-               if (fb->vendor->packed_24_bit_pixels) {
-                       var->red.length = 8;
-                       var->green.length = 8;
-                       var->blue.length = 8;
-               } else {
-                       ret = -EINVAL;
-               }
-               break;
        case 32:
                /* If we can't do 888, reject */
                caps &= CLCD_CAP_888;
@@ -318,12 +306,6 @@ static int clcdfb_set_par(struct fb_info *info)
 
        clcdfb_disable(fb);
 
-       /* Some variants must be clocked here */
-       if (fb->vendor->clock_timregs && !fb->clk_enabled) {
-               fb->clk_enabled = true;
-               clk_enable(fb->clk);
-       }
-
        writel(regs.tim0, fb->regs + CLCD_TIM0);
        writel(regs.tim1, fb->regs + CLCD_TIM1);
        writel(regs.tim2, fb->regs + CLCD_TIM2);
@@ -465,14 +447,8 @@ static int clcdfb_register(struct clcd_fb *fb)
                fb->off_ienb = CLCD_PL111_IENB;
                fb->off_cntl = CLCD_PL111_CNTL;
        } else {
-               if (of_machine_is_compatible("arm,versatile-ab") ||
-                   of_machine_is_compatible("arm,versatile-pb")) {
-                       fb->off_ienb = CLCD_PL111_IENB;
-                       fb->off_cntl = CLCD_PL111_CNTL;
-               } else {
-                       fb->off_ienb = CLCD_PL110_IENB;
-                       fb->off_cntl = CLCD_PL110_CNTL;
-               }
+               fb->off_ienb = CLCD_PL110_IENB;
+               fb->off_cntl = CLCD_PL110_CNTL;
        }
 
        fb->clk = clk_get(&fb->dev->dev, NULL);
@@ -713,42 +689,6 @@ static int clcdfb_of_init_tft_panel(struct clcd_fb *fb, u32 r0, u32 g0, u32 b0)
        if (r0 != 0 && b0 == 0)
                fb->panel->bgr_connection = true;
 
-       if (fb->panel->caps && fb->vendor->st_bitmux_control) {
-               /*
-                * Set up the special bits for the Nomadik control register
-                * (other platforms tend to do this through an external
-                * register).
-                */
-
-               /* Offset of the highest used color */
-               int maxoff = max3(r0, g0, b0);
-               /* Most significant bit out, highest used bit */
-               int msb = 0;
-
-               if (fb->panel->caps & CLCD_CAP_888) {
-                       msb = maxoff + 8 - 1;
-               } else if (fb->panel->caps & CLCD_CAP_565) {
-                       msb = maxoff + 5 - 1;
-                       fb->panel->cntl |= CNTL_ST_1XBPP_565;
-               } else if (fb->panel->caps & CLCD_CAP_5551) {
-                       msb = maxoff + 5 - 1;
-                       fb->panel->cntl |= CNTL_ST_1XBPP_5551;
-               } else if (fb->panel->caps & CLCD_CAP_444) {
-                       msb = maxoff + 4 - 1;
-                       fb->panel->cntl |= CNTL_ST_1XBPP_444;
-               }
-
-               /* Send out as many bits as we need */
-               if (msb > 17)
-                       fb->panel->cntl |= CNTL_ST_CDWID_24;
-               else if (msb > 15)
-                       fb->panel->cntl |= CNTL_ST_CDWID_18;
-               else if (msb > 11)
-                       fb->panel->cntl |= CNTL_ST_CDWID_16;
-               else
-                       fb->panel->cntl |= CNTL_ST_CDWID_12;
-       }
-
        return fb->panel->caps ? 0 : -EINVAL;
 }
 
@@ -775,12 +715,6 @@ static int clcdfb_of_init_display(struct clcd_fb *fb)
        if (!panel)
                return -ENODEV;
 
-       if (fb->vendor->init_panel) {
-               err = fb->vendor->init_panel(fb, panel);
-               if (err)
-                       return err;
-       }
-
        err = clcdfb_of_get_backlight(panel, fb->panel);
        if (err)
                return err;
@@ -941,7 +875,6 @@ static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
 static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
 {
        struct clcd_board *board = dev_get_platdata(&dev->dev);
-       struct clcd_vendor_data *vendor = id->data;
        struct clcd_fb *fb;
        int ret;
 
@@ -951,12 +884,6 @@ static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
        if (!board)
                return -EINVAL;
 
-       if (vendor->init_board) {
-               ret = vendor->init_board(dev, board);
-               if (ret)
-                       return ret;
-       }
-
        ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
        if (ret)
                goto out;
@@ -974,7 +901,6 @@ static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
        }
 
        fb->dev = dev;
-       fb->vendor = vendor;
        fb->board = board;
 
        dev_info(&fb->dev->dev, "PL%03x designer %02x rev%u at 0x%08llx\n",
@@ -1021,30 +947,10 @@ static int clcdfb_remove(struct amba_device *dev)
        return 0;
 }
 
-static struct clcd_vendor_data vendor_arm = {
-       /* Sets up the versatile board displays */
-       .init_panel = versatile_clcd_init_panel,
-};
-
-static struct clcd_vendor_data vendor_nomadik = {
-       .clock_timregs = true,
-       .packed_24_bit_pixels = true,
-       .st_bitmux_control = true,
-       .init_board = nomadik_clcd_init_board,
-       .init_panel = nomadik_clcd_init_panel,
-};
-
 static const struct amba_id clcdfb_id_table[] = {
        {
                .id     = 0x00041110,
                .mask   = 0x000ffffe,
-               .data   = &vendor_arm,
-       },
-       /* ST Electronics Nomadik variant */
-       {
-               .id     = 0x00180110,
-               .mask   = 0x00fffffe,
-               .data   = &vendor_nomadik,
        },
        { 0, 0 },
 };
index fcd2dd670a658fe33d3d14ac61aa8c2e4e46ada1..b986af2a8042800343744d7adc98a9ec96850fb2 100644 (file)
@@ -47,7 +47,6 @@
 #define ATAFB_EXT
 #define ATAFB_FALCON
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -55,6 +54,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
 
 #include <asm/setup.h>
 #include <linux/uaccess.h>
@@ -3073,28 +3073,22 @@ int __init atafb_setup(char *options)
        return 0;
 }
 
-int __init atafb_init(void)
+static int __init atafb_probe(struct platform_device *pdev)
 {
        int pad, detected_mode, error;
        unsigned int defmode = 0;
        unsigned long mem_req;
-
-#ifndef MODULE
        char *option = NULL;
 
        if (fb_get_options("atafb", &option))
                return -ENODEV;
        atafb_setup(option);
-#endif
-       printk("atafb_init: start\n");
-
-       if (!MACH_IS_ATARI)
-               return -ENODEV;
+       dev_dbg(&pdev->dev, "%s: start\n", __func__);
 
        do {
 #ifdef ATAFB_EXT
                if (external_addr) {
-                       printk("atafb_init: initializing external hw\n");
+                       dev_dbg(&pdev->dev, "initializing external hw\n");
                        fbhw = &ext_switch;
                        atafb_ops.fb_setcolreg = &ext_setcolreg;
                        defmode = DEFMODE_EXT;
@@ -3103,7 +3097,7 @@ int __init atafb_init(void)
 #endif
 #ifdef ATAFB_TT
                if (ATARIHW_PRESENT(TT_SHIFTER)) {
-                       printk("atafb_init: initializing TT hw\n");
+                       dev_dbg(&pdev->dev, "initializing TT hw\n");
                        fbhw = &tt_switch;
                        atafb_ops.fb_setcolreg = &tt_setcolreg;
                        defmode = DEFMODE_TT;
@@ -3112,7 +3106,7 @@ int __init atafb_init(void)
 #endif
 #ifdef ATAFB_FALCON
                if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
-                       printk("atafb_init: initializing Falcon hw\n");
+                       dev_dbg(&pdev->dev, "initializing Falcon hw\n");
                        fbhw = &falcon_switch;
                        atafb_ops.fb_setcolreg = &falcon_setcolreg;
                        error = request_irq(IRQ_AUTO_4, falcon_vbl_switcher, 0,
@@ -3127,7 +3121,7 @@ int __init atafb_init(void)
 #ifdef ATAFB_STE
                if (ATARIHW_PRESENT(STND_SHIFTER) ||
                    ATARIHW_PRESENT(EXTD_SHIFTER)) {
-                       printk("atafb_init: initializing ST/E hw\n");
+                       dev_dbg(&pdev->dev, "initializing ST/E hw\n");
                        fbhw = &st_switch;
                        atafb_ops.fb_setcolreg = &stste_setcolreg;
                        defmode = DEFMODE_STE;
@@ -3135,7 +3129,8 @@ int __init atafb_init(void)
                }
                fbhw = &st_switch;
                atafb_ops.fb_setcolreg = &stste_setcolreg;
-               printk("Cannot determine video hardware; defaulting to ST(e)\n");
+               dev_warn(&pdev->dev,
+                        "Cannot determine video hardware; defaulting to ST(e)\n");
 #else /* ATAFB_STE */
                /* no default driver included */
                /* Nobody will ever see this message :-) */
@@ -3175,8 +3170,8 @@ int __init atafb_init(void)
                        kernel_set_cachemode(screen_base, screen_len,
                                             IOMAP_WRITETHROUGH);
                }
-               printk("atafb: screen_base %p phys_screen_base %lx screen_len %d\n",
-                       screen_base, phys_screen_base, screen_len);
+               dev_info(&pdev->dev, "phys_screen_base %lx screen_len %d\n",
+                        phys_screen_base, screen_len);
 #ifdef ATAFB_EXT
        } else {
                /* Map the video memory (physical address given) to somewhere
@@ -3223,12 +3218,12 @@ int __init atafb_init(void)
        fb_alloc_cmap(&(fb_info.cmap), 1 << fb_info.var.bits_per_pixel, 0);
 
 
-       printk("Determined %dx%d, depth %d\n",
-              fb_info.var.xres, fb_info.var.yres, fb_info.var.bits_per_pixel);
+       dev_info(&pdev->dev, "Determined %dx%d, depth %d\n", fb_info.var.xres,
+                fb_info.var.yres, fb_info.var.bits_per_pixel);
        if ((fb_info.var.xres != fb_info.var.xres_virtual) ||
            (fb_info.var.yres != fb_info.var.yres_virtual))
-               printk("   virtual %dx%d\n", fb_info.var.xres_virtual,
-                      fb_info.var.yres_virtual);
+               dev_info(&pdev->dev, "   virtual %dx%d\n",
+                        fb_info.var.xres_virtual, fb_info.var.yres_virtual);
 
        if (register_framebuffer(&fb_info) < 0) {
 #ifdef ATAFB_EXT
@@ -3251,14 +3246,32 @@ int __init atafb_init(void)
        return 0;
 }
 
-module_init(atafb_init);
+static void atafb_shutdown(struct platform_device *pdev)
+{
+       /* Unblank before kexec */
+       if (fbhw->blank)
+               fbhw->blank(0);
+}
 
-#ifdef MODULE
-MODULE_LICENSE("GPL");
+static struct platform_driver atafb_driver = {
+       .shutdown       = atafb_shutdown,
+       .driver = {
+               .name   = "atafb",
+       },
+};
 
-int cleanup_module(void)
+static int __init atafb_init(void)
 {
-       unregister_framebuffer(&fb_info);
-       return atafb_deinit();
+       struct platform_device *pdev;
+
+       if (!MACH_IS_ATARI)
+               return -ENODEV;
+
+       pdev = platform_device_register_simple("atafb", -1, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       return platform_driver_probe(&atafb_driver, atafb_probe);
 }
-#endif /* MODULE */
+
+device_initcall(atafb_init);
index 8cc9c50379d0f0363683d55e3aa33c4b61e9078e..a1660c24bf3629a5c8b42cf80a34f0a0d17bfe2c 100644 (file)
@@ -10,7 +10,6 @@
  *  more details.
  */
 
-#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/fb.h>
 
@@ -269,25 +268,3 @@ void atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line,
        if (width)
                fill8_2col((u8 *)dest, fgcolor, bgcolor, *data);
 }
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-int init_module(void)
-{
-       return 0;
-}
-
-void cleanup_module(void)
-{
-}
-#endif /* MODULE */
-
-
-    /*
-     *  Visible symbols for modules
-     */
-
-EXPORT_SYMBOL(atafb_iplan2p2_copyarea);
-EXPORT_SYMBOL(atafb_iplan2p2_fillrect);
-EXPORT_SYMBOL(atafb_iplan2p2_linefill);
index bee0d89463f755a4fc7a22a4d37966e618d148cb..663d66582d791c03ecc530abbfeaa67f359a2ed5 100644 (file)
@@ -10,7 +10,6 @@
  *  more details.
  */
 
-#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/fb.h>
 
@@ -284,25 +283,3 @@ void atafb_iplan2p4_linefill(struct fb_info *info, u_long next_line,
        if (width)
                fill8_2col((u8 *)dest, fgcolor, bgcolor, *data);
 }
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-int init_module(void)
-{
-       return 0;
-}
-
-void cleanup_module(void)
-{
-}
-#endif /* MODULE */
-
-
-    /*
-     *  Visible symbols for modules
-     */
-
-EXPORT_SYMBOL(atafb_iplan2p4_copyarea);
-EXPORT_SYMBOL(atafb_iplan2p4_fillrect);
-EXPORT_SYMBOL(atafb_iplan2p4_linefill);
index 356fb52ce44307410be7dc20dfab0c50a79c5d3e..39a6cbbb6ca39db034c7340adae2237d771372c1 100644 (file)
@@ -10,7 +10,6 @@
  *  more details.
  */
 
-#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/fb.h>
 
@@ -321,25 +320,3 @@ void atafb_iplan2p8_linefill(struct fb_info *info, u_long next_line,
        if (width)
                fill8_2col((u8 *)dest, fgcolor, bgcolor, *data);
 }
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-int init_module(void)
-{
-       return 0;
-}
-
-void cleanup_module(void)
-{
-}
-#endif /* MODULE */
-
-
-    /*
-     *  Visible symbols for modules
-     */
-
-EXPORT_SYMBOL(atafb_iplan2p8_copyarea);
-EXPORT_SYMBOL(atafb_iplan2p8_fillrect);
-EXPORT_SYMBOL(atafb_iplan2p8_linefill);
index 6a352d62eecf2b737336cce422198c1fe357bc55..384fd3e4d3e139353c723b77c5c659827ac70dae 100644 (file)
@@ -9,7 +9,6 @@
  *  more details.
  */
 
-#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/fb.h>
 
@@ -88,25 +87,3 @@ void atafb_mfb_linefill(struct fb_info *info, u_long next_line,
                *dest++ = *data++;
        }
 }
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-int init_module(void)
-{
-       return 0;
-}
-
-void cleanup_module(void)
-{
-}
-#endif /* MODULE */
-
-
-    /*
-     *  Visible symbols for modules
-     */
-
-EXPORT_SYMBOL(atafb_mfb_copyarea);
-EXPORT_SYMBOL(atafb_mfb_fillrect);
-EXPORT_SYMBOL(atafb_mfb_linefill);
index 4ed55e6bbb84047927c0da3a314b419e9312dd02..e67dfd94bf1d51d7d093f6f01e136aa84ad6eda9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Driver for AT91/AT32 LCD Controller
+ *  Driver for AT91 LCD Controller
  *
  *  Copyright (C) 2007 Atmel Corporation
  *
@@ -99,86 +99,6 @@ static struct atmel_lcdfb_config at91sam9rl_config = {
        .have_intensity_bit     = true,
 };
 
-static struct atmel_lcdfb_config at32ap_config = {
-       .have_hozval            = true,
-};
-
-static const struct platform_device_id atmel_lcdfb_devtypes[] = {
-       {
-               .name = "at91sam9261-lcdfb",
-               .driver_data = (unsigned long)&at91sam9261_config,
-       }, {
-               .name = "at91sam9263-lcdfb",
-               .driver_data = (unsigned long)&at91sam9263_config,
-       }, {
-               .name = "at91sam9g10-lcdfb",
-               .driver_data = (unsigned long)&at91sam9g10_config,
-       }, {
-               .name = "at91sam9g45-lcdfb",
-               .driver_data = (unsigned long)&at91sam9g45_config,
-       }, {
-               .name = "at91sam9g45es-lcdfb",
-               .driver_data = (unsigned long)&at91sam9g45es_config,
-       }, {
-               .name = "at91sam9rl-lcdfb",
-               .driver_data = (unsigned long)&at91sam9rl_config,
-       }, {
-               .name = "at32ap-lcdfb",
-               .driver_data = (unsigned long)&at32ap_config,
-       }, {
-               /* terminator */
-       }
-};
-MODULE_DEVICE_TABLE(platform, atmel_lcdfb_devtypes);
-
-static struct atmel_lcdfb_config *
-atmel_lcdfb_get_config(struct platform_device *pdev)
-{
-       unsigned long data;
-
-       data = platform_get_device_id(pdev)->driver_data;
-
-       return (struct atmel_lcdfb_config *)data;
-}
-
-#if defined(CONFIG_ARCH_AT91)
-#define        ATMEL_LCDFB_FBINFO_DEFAULT      (FBINFO_DEFAULT \
-                                        | FBINFO_PARTIAL_PAN_OK \
-                                        | FBINFO_HWACCEL_YPAN)
-
-static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
-                                       struct fb_var_screeninfo *var,
-                                       struct fb_info *info)
-{
-
-}
-#elif defined(CONFIG_AVR32)
-#define        ATMEL_LCDFB_FBINFO_DEFAULT      (FBINFO_DEFAULT \
-                                       | FBINFO_PARTIAL_PAN_OK \
-                                       | FBINFO_HWACCEL_XPAN \
-                                       | FBINFO_HWACCEL_YPAN)
-
-static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
-                                    struct fb_var_screeninfo *var,
-                                    struct fb_info *info)
-{
-       u32 dma2dcfg;
-       u32 pixeloff;
-
-       pixeloff = (var->xoffset * info->var.bits_per_pixel) & 0x1f;
-
-       dma2dcfg = (info->var.xres_virtual - info->var.xres)
-                * info->var.bits_per_pixel / 8;
-       dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
-       lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
-
-       /* Update configuration */
-       lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
-                   lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
-                   | ATMEL_LCDC_DMAUPDT);
-}
-#endif
-
 static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
                | ATMEL_LCDC_POL_POSITIVE
                | ATMEL_LCDC_ENA_PWMENABLE;
@@ -404,8 +324,6 @@ static void atmel_lcdfb_update_dma(struct fb_info *info,
 
        /* Set framebuffer DMA base address and pixel offset */
        lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
-
-       atmel_lcdfb_update_dma2d(sinfo, var, info);
 }
 
 static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
@@ -978,7 +896,6 @@ static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
        clk_disable_unprepare(sinfo->lcdc_clk);
 }
 
-#ifdef CONFIG_OF
 static const struct of_device_id atmel_lcdfb_dt_ids[] = {
        { .compatible = "atmel,at91sam9261-lcdc" , .data = &at91sam9261_config, },
        { .compatible = "atmel,at91sam9263-lcdc" , .data = &at91sam9263_config, },
@@ -986,7 +903,6 @@ static const struct of_device_id atmel_lcdfb_dt_ids[] = {
        { .compatible = "atmel,at91sam9g45-lcdc" , .data = &at91sam9g45_config, },
        { .compatible = "atmel,at91sam9g45es-lcdc" , .data = &at91sam9g45es_config, },
        { .compatible = "atmel,at91sam9rl-lcdc" , .data = &at91sam9rl_config, },
-       { .compatible = "atmel,at32ap-lcdc" , .data = &at32ap_config, },
        { /* sentinel */ }
 };
 
@@ -1122,19 +1038,12 @@ put_display_node:
        of_node_put(display_np);
        return ret;
 }
-#else
-static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
-{
-       return 0;
-}
-#endif
 
 static int __init atmel_lcdfb_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct fb_info *info;
        struct atmel_lcdfb_info *sinfo;
-       struct atmel_lcdfb_pdata *pdata = NULL;
        struct resource *regs = NULL;
        struct resource *map = NULL;
        struct fb_modelist *modelist;
@@ -1159,21 +1068,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
                ret = atmel_lcdfb_of_init(sinfo);
                if (ret)
                        goto free_info;
-       } else if (dev_get_platdata(dev)) {
-               struct fb_monspecs *monspecs;
-               int i;
-
-               pdata = dev_get_platdata(dev);
-               monspecs = pdata->default_monspecs;
-               sinfo->pdata = *pdata;
-
-               for (i = 0; i < monspecs->modedb_len; i++)
-                       fb_add_videomode(&monspecs->modedb[i], &info->modelist);
-
-               sinfo->config = atmel_lcdfb_get_config(pdev);
-
-               info->var.bits_per_pixel = pdata->default_bpp ? pdata->default_bpp : 16;
-               memcpy(&info->monspecs, pdata->default_monspecs, sizeof(info->monspecs));
        } else {
                dev_err(dev, "cannot get default configuration\n");
                goto free_info;
@@ -1186,7 +1080,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
        if (IS_ERR(sinfo->reg_lcd))
                sinfo->reg_lcd = NULL;
 
-       info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
+       info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK |
+                     FBINFO_HWACCEL_YPAN;
        info->pseudo_palette = sinfo->pseudo_palette;
        info->fbops = &atmel_lcdfb_ops;
 
@@ -1357,12 +1252,10 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct fb_info *info = dev_get_drvdata(dev);
        struct atmel_lcdfb_info *sinfo;
-       struct atmel_lcdfb_pdata *pdata;
 
        if (!info || !info->par)
                return 0;
        sinfo = info->par;
-       pdata = &sinfo->pdata;
 
        cancel_work_sync(&sinfo->task);
        exit_backlight(sinfo);
@@ -1435,7 +1328,6 @@ static struct platform_driver atmel_lcdfb_driver = {
        .remove         = __exit_p(atmel_lcdfb_remove),
        .suspend        = atmel_lcdfb_suspend,
        .resume         = atmel_lcdfb_resume,
-       .id_table       = atmel_lcdfb_devtypes,
        .driver         = {
                .name   = "atmel_lcdfb",
                .of_match_table = of_match_ptr(atmel_lcdfb_dt_ids),
@@ -1444,6 +1336,6 @@ static struct platform_driver atmel_lcdfb_driver = {
 
 module_platform_driver_probe(atmel_lcdfb_driver, atmel_lcdfb_probe);
 
-MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
+MODULE_DESCRIPTION("AT91 LCD Controller framebuffer driver");
 MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>");
 MODULE_LICENSE("GPL");
index 68a113594808f220aa818424cd6e342897806a74..2811c4afde01c0e507c6d163410f8084b67bfa7f 100644 (file)
@@ -94,6 +94,8 @@ int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags)
        int size = len * sizeof(u16);
        int ret = -ENOMEM;
 
+       flags |= __GFP_NOWARN;
+
        if (cmap->len != len) {
                fb_dealloc_cmap(cmap);
                if (!len)
index cd059a801662e9f78d0bc43669d21c64d9e9b47f..786f9aab55df6bdd4bb5504010b453c9991bd076 100644 (file)
@@ -1069,7 +1069,7 @@ static void fbcon_init(struct vc_data *vc, int init)
 
        cap = info->flags;
 
-       if (console_loglevel <= CONSOLE_LOGLEVEL_QUIET)
+       if (logo_shown < 0 && console_loglevel <= CONSOLE_LOGLEVEL_QUIET)
                logo_shown = FBCON_LOGO_DONTSHOW;
 
        if (vc != svc || logo_shown == FBCON_LOGO_DONTSHOW ||
index 4721491e6c8cf67ab100a957809f453ef405ab6b..d1949c92be986f21e8ad87f87c3e289a3bd76fdf 100644 (file)
@@ -1882,14 +1882,35 @@ int remove_conflicting_pci_framebuffers(struct pci_dev *pdev, int res_id, const
 {
        struct apertures_struct *ap;
        bool primary = false;
-       int err;
+       int err, idx, bar;
+       bool res_id_found = false;
+
+       for (idx = 0, bar = 0; bar < PCI_ROM_RESOURCE; bar++) {
+               if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
+                       continue;
+               idx++;
+       }
 
-       ap = alloc_apertures(1);
+       ap = alloc_apertures(idx);
        if (!ap)
                return -ENOMEM;
 
-       ap->ranges[0].base = pci_resource_start(pdev, res_id);
-       ap->ranges[0].size = pci_resource_len(pdev, res_id);
+       for (idx = 0, bar = 0; bar < PCI_ROM_RESOURCE; bar++) {
+               if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
+                       continue;
+               ap->ranges[idx].base = pci_resource_start(pdev, bar);
+               ap->ranges[idx].size = pci_resource_len(pdev, bar);
+               pci_info(pdev, "%s: bar %d: 0x%lx -> 0x%lx\n", __func__, bar,
+                        (unsigned long)pci_resource_start(pdev, bar),
+                        (unsigned long)pci_resource_end(pdev, bar));
+               idx++;
+               if (res_id == bar)
+                       res_id_found = true;
+       }
+       if (!res_id_found)
+               pci_warn(pdev, "%s: passed res_id (%d) is not a memory bar\n",
+                        __func__, res_id);
+
 #ifdef CONFIG_X86
        primary = pdev->resource[PCI_ROM_RESOURCE].flags &
                                        IORESOURCE_ROM_SHADOW;
index 283d9307df21c2d9b46d609080f078e591943b65..ac049871704ddd6148c6c0623b3e603807a885c1 100644 (file)
@@ -935,6 +935,9 @@ void fb_var_to_videomode(struct fb_videomode *mode,
        if (var->vmode & FB_VMODE_DOUBLE)
                vtotal *= 2;
 
+       if (!htotal || !vtotal)
+               return;
+
        hfreq = pixclock/htotal;
        mode->refresh = hfreq/vtotal;
 }
index d9e816d53531324b2ec03a33ebea709936489c53..1bddcc20b2c09a7b190f3675502f2d658969ad7d 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/console.h>
 #include <linux/mm.h>
 
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 #include <asm/pgtable.h>
 #include <mach/hardware.h>
 
index 46302854317367e7649a7929cde2f10a2e882dc9..59e1cae5794814e387618c66f77ba7cfe715968e 100644 (file)
@@ -285,6 +285,8 @@ static int hga_card_detect(void)
        hga_vram_len  = 0x08000;
 
        hga_vram = ioremap(0xb0000, hga_vram_len);
+       if (!hga_vram)
+               goto error;
 
        if (request_region(0x3b0, 12, "hgafb"))
                release_io_ports = 1;
index 4b9615e4ce746242015010cdf7b0d956c0fde6f5..35bba3c2036d4d20c037cc6b786436646dcdcb7f 100644 (file)
@@ -1515,6 +1515,11 @@ static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        info->fix.smem_start = addr;
        info->screen_base = (__u8 *)ioremap(addr, par->ramdac == IBM ?
                                            0x400000 : 0x800000);
+       if (!info->screen_base) {
+               release_mem_region(addr, size);
+               framebuffer_release(info);
+               return -ENOMEM;
+       }
        info->fix.mmio_start = addr + 0x800000;
        par->dc_regs = ioremap(addr + 0x800000, 0x1000);
        par->cmap_regs_phys = addr + 0x840000;
index e707e617bf1c77006e5142221bbb614a5176882f..8820a556014c48e131723efc92d3668fd35643fc 100644 (file)
@@ -120,10 +120,7 @@ struct jet_cmap_regs {
 #define PIXEL_TO_MM(a) (((a)*10)/28)   /* width in mm at 72 dpi */
 
 static struct fb_var_screeninfo macfb_defined = {
-       .bits_per_pixel = 8,
        .activate       = FB_ACTIVATE_NOW,
-       .width          = -1,
-       .height         = -1,
        .right_margin   = 32,
        .upper_margin   = 16,
        .lower_margin   = 4,
@@ -139,7 +136,6 @@ static struct fb_fix_screeninfo macfb_fix = {
 static void *slot_addr;
 static struct fb_info fb_info;
 static u32 pseudo_palette[16];
-static int inverse;
 static int vidtest;
 
 /*
@@ -152,7 +148,7 @@ static int dafb_setpalette(unsigned int regno, unsigned int red,
                           unsigned int green, unsigned int blue,
                           struct fb_info *info)
 {
-       static int lastreg = -1;
+       static int lastreg = -2;
        unsigned long flags;
 
        local_irq_save(flags);
@@ -201,9 +197,6 @@ static int v8_brazil_setpalette(unsigned int regno, unsigned int red,
        unsigned int bpp = info->var.bits_per_pixel;
        unsigned long flags;
 
-       if (bpp > 8)
-               return 1; /* failsafe */
-
        local_irq_save(flags);
 
        /* On these chips, the CLUT register numbers are spread out
@@ -234,9 +227,6 @@ static int rbv_setpalette(unsigned int regno, unsigned int red,
 {
        unsigned long flags;
 
-       if (info->var.bits_per_pixel > 8)
-               return 1; /* failsafe */
-
        local_irq_save(flags);
 
        /* From the VideoToolbox driver.  Seems to be saying that
@@ -353,9 +343,6 @@ static int civic_setpalette(unsigned int regno, unsigned int red,
        unsigned long flags;
        int clut_status;
        
-       if (info->var.bits_per_pixel > 8)
-               return 1; /* failsafe */
-
        local_irq_save(flags);
 
        /* Set the register address */
@@ -532,7 +519,7 @@ static void __init macfb_setup(char *options)
                        continue;
 
                if (!strcmp(this_opt, "inverse"))
-                       inverse = 1;
+                       fb_invert_cmaps();
                else
                        if (!strcmp(this_opt, "vidtest"))
                                vidtest = 1; /* enable experimental CLUT code */
@@ -688,17 +675,14 @@ static int __init macfb_init(void)
                case NUBUS_DRHW_APPLE_MDC:
                        strcpy(macfb_fix.id, "Mac Disp. Card");
                        macfb_setpalette = mdc_setpalette;
-                       macfb_defined.activate = FB_ACTIVATE_NOW;
                        break;
                case NUBUS_DRHW_APPLE_TFB:
                        strcpy(macfb_fix.id, "Toby");
                        macfb_setpalette = toby_setpalette;
-                       macfb_defined.activate = FB_ACTIVATE_NOW;
                        break;
                case NUBUS_DRHW_APPLE_JET:
                        strcpy(macfb_fix.id, "Jet");
                        macfb_setpalette = jet_setpalette;
-                       macfb_defined.activate = FB_ACTIVATE_NOW;
                        break;
                default:
                        strcpy(macfb_fix.id, "Generic NuBus");
@@ -731,7 +715,6 @@ static int __init macfb_init(void)
                        strcpy(macfb_fix.id, "DAFB");
                        macfb_setpalette = dafb_setpalette;
                        dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000);
-                       macfb_defined.activate = FB_ACTIVATE_NOW;
                        break;
 
                /*
@@ -741,7 +724,6 @@ static int __init macfb_init(void)
                        strcpy(macfb_fix.id, "V8");
                        macfb_setpalette = v8_brazil_setpalette;
                        v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
-                       macfb_defined.activate = FB_ACTIVATE_NOW;
                        break;
 
                /*
@@ -755,7 +737,6 @@ static int __init macfb_init(void)
                        strcpy(macfb_fix.id, "Brazil");
                        macfb_setpalette = v8_brazil_setpalette;
                        v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
-                       macfb_defined.activate = FB_ACTIVATE_NOW;
                        break;
 
                /*
@@ -772,7 +753,6 @@ static int __init macfb_init(void)
                        strcpy(macfb_fix.id, "Sonora");
                        macfb_setpalette = v8_brazil_setpalette;
                        v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
-                       macfb_defined.activate = FB_ACTIVATE_NOW;
                        break;
 
                /*
@@ -785,7 +765,6 @@ static int __init macfb_init(void)
                        strcpy(macfb_fix.id, "RBV");
                        macfb_setpalette = rbv_setpalette;
                        rbv_cmap_regs = ioremap(DAC_BASE, 0x1000);
-                       macfb_defined.activate = FB_ACTIVATE_NOW;
                        break;
 
                /*
@@ -796,7 +775,6 @@ static int __init macfb_init(void)
                        strcpy(macfb_fix.id, "Civic");
                        macfb_setpalette = civic_setpalette;
                        civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000);
-                       macfb_defined.activate = FB_ACTIVATE_NOW;
                        break;
 
                
@@ -810,7 +788,6 @@ static int __init macfb_init(void)
                                macfb_setpalette = v8_brazil_setpalette;
                                v8_brazil_cmap_regs =
                                        ioremap(DAC_BASE, 0x1000);
-                               macfb_defined.activate = FB_ACTIVATE_NOW;
                        }
                        break;
 
@@ -823,7 +800,6 @@ static int __init macfb_init(void)
                                macfb_setpalette = v8_brazil_setpalette;
                                v8_brazil_cmap_regs =
                                        ioremap(DAC_BASE, 0x1000);
-                               macfb_defined.activate = FB_ACTIVATE_NOW;
                        }
                        break;
 
@@ -892,7 +868,6 @@ static int __init macfb_init(void)
                        strcpy(macfb_fix.id, "CSC");
                        macfb_setpalette = csc_setpalette;
                        csc_cmap_regs = ioremap(CSC_BASE, 0x1000);
-                       macfb_defined.activate = FB_ACTIVATE_NOW;
                        break;
 
                default:
index f56a7e2e8136adef77664805d1b711615a216b6b..1b5e80c8a984d4e2498013ed86311d753c8dcc12 100644 (file)
@@ -1,7 +1,7 @@
 menuconfig MMP_DISP
-        tristate "Marvell MMP Display Subsystem support"
-        depends on CPU_PXA910 || CPU_MMP2
-        help
+       tristate "Marvell MMP Display Subsystem support"
+       depends on CPU_PXA910 || CPU_MMP2
+       help
          Marvell Display Subsystem support.
 
 if MMP_DISP
index 12c8bd1d24d5321af7106c3738eeffbee056b25d..1fdd1eb38fe0aa67bd317281c521358d50db60ac 100644 (file)
@@ -181,6 +181,7 @@ struct mxsfb_info {
        const struct mxsfb_devdata *devdata;
        u32 sync;
        struct regulator *reg_lcd;
+       int pre_init;
 };
 
 #define mxsfb_is_v3(host) (host->devdata->ipversion == 3)
@@ -419,6 +420,12 @@ static int mxsfb_set_par(struct fb_info *fb_info)
 
        fb_info->fix.line_length = line_size;
 
+       if (host->pre_init) {
+               mxsfb_enable_controller(fb_info);
+               host->pre_init = 0;
+               return 0;
+       }
+
        /*
         * It seems, you can't re-program the controller if it is still running.
         * This may lead into shifted pictures (FIFO issue?).
@@ -623,7 +630,6 @@ static int mxsfb_restore_mode(struct fb_info *fb_info,
                        struct fb_videomode *vmode)
 {
        struct mxsfb_info *host = fb_info->par;
-       unsigned line_count;
        unsigned period;
        unsigned long pa, fbsize;
        int bits_per_pixel, ofs, ret = 0;
@@ -710,7 +716,6 @@ static int mxsfb_restore_mode(struct fb_info *fb_info,
                writel(fb_info->fix.smem_start, host->base + host->devdata->next_buf);
        }
 
-       line_count = fb_info->fix.smem_len / fb_info->fix.line_length;
        fb_info->fix.ypanstep = 1;
 
        clk_prepare_enable(host->clk);
@@ -931,6 +936,10 @@ static int mxsfb_probe(struct platform_device *pdev)
        if (IS_ERR(host->reg_lcd))
                host->reg_lcd = NULL;
 
+#if defined(CONFIG_FB_PRE_INIT_FB)
+       host->pre_init = 1;
+#endif
+
        fb_info->pseudo_palette = devm_kcalloc(&pdev->dev, 16, sizeof(u32),
                                               GFP_KERNEL);
        if (!fb_info->pseudo_palette) {
@@ -963,6 +972,7 @@ static int mxsfb_probe(struct platform_device *pdev)
                mxsfb_enable_controller(fb_info);
        }
 
+       host->pre_init = 0;
        dev_info(&pdev->dev, "initialized\n");
 
        return 0;
index 6680edae4696d1b0dc4dff547dda27ca8c159ab5..44ea5380a546e514aa64026d406094ae44283300 100644 (file)
@@ -455,7 +455,7 @@ static int nuc900fb_cpufreq_transition(struct notifier_block *nb,
        struct fb_info *fbinfo;
        long delta_f;
        info = container_of(nb, struct nuc900fb_info, freq_transition);
-       fbinfo = platform_get_drvdata(to_platform_device(info->dev));
+       fbinfo = dev_get_drvdata(info->dev);
 
        delta_f = info->clk_rate - clk_get_rate(info->clk);
 
index 29d250da8a3e5f976a7fd39341e4540d43a7f35d..ca147936bb5c4db6f7a871ebfabe8ca3edf6722d 100644 (file)
@@ -6,7 +6,7 @@ config FB_OMAP
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        help
-          Frame buffer driver for OMAP based boards.
+         Frame buffer driver for OMAP based boards.
 
 config FB_OMAP_LCDC_EXTERNAL
        bool "External LCD controller support"
@@ -49,13 +49,11 @@ config FB_OMAP_LCD_H3
          H3 board.
 
 config FB_OMAP_DMA_TUNE
-        bool "Set DMA SDRAM access priority high"
-        depends on FB_OMAP
-        help
-          On systems in which video memory is in system memory
-          (SDRAM) this will speed up graphics DMA operations.
-          If you have such a system and want to use rotation
-          answer yes. Answer no if you have a dedicated video
-          memory, or don't use any of the accelerated features.
-
-
+       bool "Set DMA SDRAM access priority high"
+       depends on FB_OMAP
+       help
+         On systems in which video memory is in system memory
+         (SDRAM) this will speed up graphics DMA operations.
+         If you have such a system and want to use rotation
+         answer yes. Answer no if you have a dedicated video
+         memory, or don't use any of the accelerated features.
index 3bf154e676d1cc7cea1f812482fcf135a6d0b088..0410e07bb29ee3b7150fd113be007cb065e890fd 100644 (file)
@@ -2,23 +2,23 @@ config OMAP2_VRFB
        bool
 
 menuconfig FB_OMAP2
-        tristate "OMAP2+ frame buffer support"
-        depends on FB
-        depends on DRM_OMAP = n
+       tristate "OMAP2+ frame buffer support"
+       depends on FB
+       depends on DRM_OMAP = n
        depends on GPIOLIB
 
-        select FB_OMAP2_DSS
+       select FB_OMAP2_DSS
        select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
-        select FB_CFB_FILLRECT
-        select FB_CFB_COPYAREA
-        select FB_CFB_IMAGEBLIT
-        help
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       help
          Frame buffer driver for OMAP2+ based boards.
 
 if FB_OMAP2
 
 config FB_OMAP2_DEBUG_SUPPORT
-        bool "Debug support for OMAP2+ FB"
+       bool "Debug support for OMAP2+ FB"
        default y
        depends on FB_OMAP2
        help
index 08f12039dd024fbc53aa9cecac04985225eb8e82..3df8736cf8d834e57e527ea2bbf8bc93146cf73c 100644 (file)
@@ -1,5 +1,5 @@
 menu "OMAPFB Panel and Encoder Drivers"
-        depends on FB_OMAP2_DSS
+       depends on FB_OMAP2_DSS
 
 config FB_OMAP2_ENCODER_OPA362
        tristate "OPA362 external analog amplifier"
@@ -8,29 +8,29 @@ config FB_OMAP2_ENCODER_OPA362
          through a GPIO.
 
 config FB_OMAP2_ENCODER_TFP410
-        tristate "TFP410 DPI to DVI Encoder"
+       tristate "TFP410 DPI to DVI Encoder"
        help
          Driver for TFP410 DPI to DVI encoder.
 
 config FB_OMAP2_ENCODER_TPD12S015
-        tristate "TPD12S015 HDMI ESD protection and level shifter"
+       tristate "TPD12S015 HDMI ESD protection and level shifter"
        help
          Driver for TPD12S015, which offers HDMI ESD protection and level
          shifting.
 
 config FB_OMAP2_CONNECTOR_DVI
-        tristate "DVI Connector"
+       tristate "DVI Connector"
        depends on I2C
        help
          Driver for a generic DVI connector.
 
 config FB_OMAP2_CONNECTOR_HDMI
-        tristate "HDMI Connector"
+       tristate "HDMI Connector"
        help
          Driver for a generic HDMI connector.
 
 config FB_OMAP2_CONNECTOR_ANALOG_TV
-        tristate "Analog TV Connector"
+       tristate "Analog TV Connector"
        help
          Driver for a generic analog TV connector.
 
@@ -58,29 +58,29 @@ config FB_OMAP2_PANEL_LGPHILIPS_LB035Q02
          LCD Panel used on the Gumstix Overo Palo35
 
 config FB_OMAP2_PANEL_SHARP_LS037V7DW01
-        tristate "Sharp LS037V7DW01 LCD Panel"
-        depends on BACKLIGHT_CLASS_DEVICE
-        help
-          LCD Panel used in TI's SDP3430 and EVM boards
+       tristate "Sharp LS037V7DW01 LCD Panel"
+       depends on BACKLIGHT_CLASS_DEVICE
+       help
+         LCD Panel used in TI's SDP3430 and EVM boards
 
 config FB_OMAP2_PANEL_TPO_TD028TTEC1
-        tristate "TPO TD028TTEC1 LCD Panel"
-        depends on SPI
-        help
-          LCD panel used in Openmoko.
+       tristate "TPO TD028TTEC1 LCD Panel"
+       depends on SPI
+       help
+         LCD panel used in Openmoko.
 
 config FB_OMAP2_PANEL_TPO_TD043MTEA1
-        tristate "TPO TD043MTEA1 LCD Panel"
-        depends on SPI
-        help
-          LCD Panel used in OMAP3 Pandora
+       tristate "TPO TD043MTEA1 LCD Panel"
+       depends on SPI
+       help
+         LCD Panel used in OMAP3 Pandora
 
 config FB_OMAP2_PANEL_NEC_NL8048HL11
        tristate "NEC NL8048HL11 Panel"
        depends on SPI
        depends on BACKLIGHT_CLASS_DEVICE
        help
-               This NEC NL8048HL11 panel is TFT LCD used in the
-               Zoom2/3/3630 sdp boards.
+         This NEC NL8048HL11 panel is TFT LCD used in the
+         Zoom2/3/3630 sdp boards.
 
 endmenu
index 356b89b378d4de2981d285f6711b9f880e73499b..a34820e8ab974c62851c06484782fcadc261f598 100644 (file)
@@ -3,7 +3,7 @@ config FB_OMAP2_DSS_INIT
        bool
 
 config FB_OMAP2_DSS
-        tristate
+       tristate
        select VIDEOMODE_HELPERS
        select FB_OMAP2_DSS_INIT
        select HDMI
@@ -53,7 +53,7 @@ config FB_OMAP2_DSS_RFBI
 
 config FB_OMAP2_DSS_VENC
        bool "VENC support"
-        default y
+       default y
        help
          OMAP Video Encoder support for S-Video and composite TV-out.
 
@@ -62,7 +62,7 @@ config FB_OMAP2_DSS_HDMI_COMMON
 
 config FB_OMAP4_DSS_HDMI
        bool "HDMI support for OMAP4"
-        default y
+       default y
        select FB_OMAP2_DSS_HDMI_COMMON
        help
          HDMI support for OMAP4 based SoCs.
index 136d30484d02345430a1875d49acffa836c8a059..5da7ed6d653ea2118107dd1625ff1d7213b44942 100644 (file)
@@ -111,6 +111,8 @@ static void __init omapdss_omapify_node(struct device_node *node)
 
        new_len = prop->length + strlen(prefix) * num_strs;
        new_compat = kmalloc(new_len, GFP_KERNEL);
+       if (!new_compat)
+               return;
 
        omapdss_prefix_strcpy(new_compat, new_len, prop->value, prop->length);
 
@@ -193,8 +195,10 @@ static int __init omapdss_boot_init(void)
 
        dss = of_find_matching_node(NULL, omapdss_of_match);
 
-       if (dss == NULL || !of_device_is_available(dss))
+       if (dss == NULL || !of_device_is_available(dss)) {
+               of_node_put(dss);
                return 0;
+       }
 
        omapdss_walk_device(dss, true);
 
index 8a53d1de611d5cdd99f58ddbef03ca8ba73dcc09..4e4d6a0df978cc3688b2a045d4f35da4f4494eeb 100644 (file)
@@ -686,7 +686,7 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
        if (!pages)
                return -ENOMEM;
 
-       ret = get_user_pages_fast((unsigned long)buf, nr_pages, true, pages);
+       ret = get_user_pages_fast((unsigned long)buf, nr_pages, FOLL_WRITE, pages);
        if (ret < nr_pages) {
                nr_pages = ret;
                ret = -EINVAL;
@@ -1071,7 +1071,6 @@ static struct pvr2_board {
 static int __init pvr2fb_init(void)
 {
        int i, ret = -ENODEV;
-       int size;
 
 #ifndef MODULE
        char *option = NULL;
@@ -1080,7 +1079,6 @@ static int __init pvr2fb_init(void)
                return -ENODEV;
        pvr2fb_setup(option);
 #endif
-       size = sizeof(struct fb_info) + sizeof(struct pvr2fb_par) + 16 * sizeof(u32);
 
        fb_info = framebuffer_alloc(sizeof(struct pvr2fb_par), NULL);
 
index a67e4567e65619632fc8479b8feb9133bf801239..a702da89910bdafae20d3086be36704909302897 100644 (file)
@@ -777,7 +777,7 @@ static int s3c2410fb_cpufreq_transition(struct notifier_block *nb,
        long delta_f;
 
        info = container_of(nb, struct s3c2410fb_info, freq_transition);
-       fbinfo = platform_get_drvdata(to_platform_device(info->dev));
+       fbinfo = dev_get_drvdata(info->dev);
 
        /* work out change, <0 for speed-up */
        delta_f = info->clk_rate - clk_get_rate(info->clk);
index c09d7426cd92505f9418d17ba852ea0aaef2fa0a..47b78f0138c382c1dfce9fb1afbcd46ad78c63a2 100644 (file)
@@ -2155,9 +2155,9 @@ static int savage_init_fb_info(struct fb_info *info, struct pci_dev *dev,
 
                err = fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
                if (!err)
-               info->flags |= FBINFO_HWACCEL_COPYAREA |
-                              FBINFO_HWACCEL_FILLRECT |
-                              FBINFO_HWACCEL_IMAGEBLIT;
+                       info->flags |= FBINFO_HWACCEL_COPYAREA |
+                                      FBINFO_HWACCEL_FILLRECT |
+                                      FBINFO_HWACCEL_IMAGEBLIT;
        }
 #endif
        return err;
index aad1cc4be34a9069ca5312bc075d8440aa46b797..c7ebf03b8d5378b2536123a7c957cbabc17c41ee 100644 (file)
 
 #define FB_ACCEL_SMI_LYNX 88
 
-#define SCREEN_X_RES      1024
-#define SCREEN_Y_RES      600
-#define SCREEN_BPP        16
-
-/*Assume SM712 graphics chip has 4MB VRAM */
-#define SM712_VIDEOMEMORYSIZE    0x00400000
-/*Assume SM722 graphics chip has 8MB VRAM */
-#define SM722_VIDEOMEMORYSIZE    0x00800000
+#define SCREEN_X_RES          1024
+#define SCREEN_Y_RES_PC       768
+#define SCREEN_Y_RES_NETBOOK  600
+#define SCREEN_BPP            16
 
 #define dac_reg        (0x3c8)
 #define dac_val        (0x3c9)
index 502d0de2feec524f6b8eec46072300a86733179c..f1dcc6766d1ef457d18c5e09e35521c896154162 100644 (file)
@@ -530,6 +530,65 @@ static const struct modeinit vgamode[] = {
                        0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
                },
        },
+       {       /*  1024 x 768  16Bpp  60Hz */
+               1024, 768, 16, 60,
+               /*  Init_MISC */
+               0xEB,
+               {       /*  Init_SR0_SR4 */
+                       0x03, 0x01, 0x0F, 0x03, 0x0E,
+               },
+               {       /*  Init_SR10_SR24 */
+                       0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+                       0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xC4, 0x30, 0x02, 0x01, 0x01,
+               },
+               {       /*  Init_SR30_SR75 */
+                       0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+                       0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+                       0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+                       0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+                       0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+                       0x0F, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+                       0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+                       0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
+                       0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+               },
+               {       /*  Init_SR80_SR93 */
+                       0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+                       0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+                       0x00, 0x00, 0x00, 0x00,
+               },
+               {       /*  Init_SRA0_SRAF */
+                       0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+                       0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+               },
+               {       /*  Init_GR00_GR08 */
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+                       0xFF,
+               },
+               {       /*  Init_AR00_AR14 */
+                       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                       0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+                       0x41, 0x00, 0x0F, 0x00, 0x00,
+               },
+               {       /*  Init_CR00_CR18 */
+                       0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+                       0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+                       0xFF,
+               },
+               {       /*  Init_CR30_CR4D */
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+                       0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+                       0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
+                       0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
+               },
+               {       /*  Init_CR90_CRA7 */
+                       0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+                       0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+                       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+               },
+       },
        {       /*  mode#5: 1024 x 768  24Bpp  60Hz */
                1024, 768, 24, 60,
                /*  Init_MISC */
@@ -827,67 +886,80 @@ static inline unsigned int chan_to_field(unsigned int chan,
 
 static int smtc_blank(int blank_mode, struct fb_info *info)
 {
+       struct smtcfb_info *sfb = info->par;
+
        /* clear DPMS setting */
        switch (blank_mode) {
        case FB_BLANK_UNBLANK:
                /* Screen On: HSync: On, VSync : On */
+
+               switch (sfb->chip_id) {
+               case 0x710:
+               case 0x712:
+                       smtc_seqw(0x6a, 0x16);
+                       smtc_seqw(0x6b, 0x02);
+                       break;
+               case 0x720:
+                       smtc_seqw(0x6a, 0x0d);
+                       smtc_seqw(0x6b, 0x02);
+                       break;
+               }
+
+               smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
                smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
-               smtc_seqw(0x6a, 0x16);
-               smtc_seqw(0x6b, 0x02);
                smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
                smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
-               smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
-               smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
                smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
+               smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
                break;
        case FB_BLANK_NORMAL:
                /* Screen Off: HSync: On, VSync : On   Soft blank */
+               smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
+               smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+               smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
                smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
+               smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
                smtc_seqw(0x6a, 0x16);
                smtc_seqw(0x6b, 0x02);
-               smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
-               smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
-               smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
-               smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
                break;
        case FB_BLANK_VSYNC_SUSPEND:
                /* Screen On: HSync: On, VSync : Off */
+               smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+               smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+               smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
                smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
-               smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
-               smtc_seqw(0x6a, 0x0c);
-               smtc_seqw(0x6b, 0x02);
                smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+               smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
                smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
-               smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
-               smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
-               smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
                smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+               smtc_seqw(0x6a, 0x0c);
+               smtc_seqw(0x6b, 0x02);
                break;
        case FB_BLANK_HSYNC_SUSPEND:
                /* Screen On: HSync: Off, VSync : On */
+               smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+               smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+               smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
                smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
-               smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
-               smtc_seqw(0x6a, 0x0c);
-               smtc_seqw(0x6b, 0x02);
                smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+               smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
                smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
-               smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
-               smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
-               smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
                smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+               smtc_seqw(0x6a, 0x0c);
+               smtc_seqw(0x6b, 0x02);
                break;
        case FB_BLANK_POWERDOWN:
                /* Screen On: HSync: Off, VSync : Off */
+               smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+               smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+               smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
                smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
-               smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
-               smtc_seqw(0x6a, 0x0c);
-               smtc_seqw(0x6b, 0x02);
                smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+               smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
                smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
-               smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
-               smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
-               smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
                smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+               smtc_seqw(0x6a, 0x0c);
+               smtc_seqw(0x6b, 0x02);
                break;
        default:
                return -EINVAL;
@@ -1145,8 +1217,10 @@ static void sm7xx_set_timing(struct smtcfb_info *sfb)
 
                /* init SEQ register SR30 - SR75 */
                for (i = 0; i < SIZE_SR30_SR75; i++)
-                       if ((i + 0x30) != 0x62 && (i + 0x30) != 0x6a &&
-                           (i + 0x30) != 0x6b)
+                       if ((i + 0x30) != 0x30 && (i + 0x30) != 0x62 &&
+                           (i + 0x30) != 0x6a && (i + 0x30) != 0x6b &&
+                           (i + 0x30) != 0x70 && (i + 0x30) != 0x71 &&
+                           (i + 0x30) != 0x74 && (i + 0x30) != 0x75)
                                smtc_seqw(i + 0x30,
                                          vgamode[j].init_sr30_sr75[i]);
 
@@ -1171,8 +1245,12 @@ static void sm7xx_set_timing(struct smtcfb_info *sfb)
                        smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
 
                /* init CRTC register CR30 - CR4D */
-               for (i = 0; i < SIZE_CR30_CR4D; i++)
+               for (i = 0; i < SIZE_CR30_CR4D; i++) {
+                       if ((i + 0x30) >= 0x3B && (i + 0x30) <= 0x3F)
+                               /* side-effect, don't write to CR3B-CR3F */
+                               continue;
                        smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]);
+               }
 
                /* init CRTC register CR90 - CRA7 */
                for (i = 0; i < SIZE_CR90_CRA7; i++)
@@ -1323,6 +1401,11 @@ static int smtc_map_smem(struct smtcfb_info *sfb,
 {
        sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
 
+       if (sfb->chip_id == 0x720)
+               /* on SM720, the framebuffer starts at the 1 MB offset */
+               sfb->fb->fix.smem_start += 0x00200000;
+
+       /* XXX: is it safe for SM720 on Big-Endian? */
        if (sfb->fb->var.bits_per_pixel == 32)
                sfb->fb->fix.smem_start += big_addr;
 
@@ -1360,12 +1443,82 @@ static inline void sm7xx_init_hw(void)
        outb_p(0x11, 0x3c5);
 }
 
+static u_long sm7xx_vram_probe(struct smtcfb_info *sfb)
+{
+       u8 vram;
+
+       switch (sfb->chip_id) {
+       case 0x710:
+       case 0x712:
+               /*
+                * Assume SM712 graphics chip has 4MB VRAM.
+                *
+                * FIXME: SM712 can have 2MB VRAM, which is used on earlier
+                * laptops, such as IBM Thinkpad 240X. This driver would
+                * probably crash on those machines. If anyone gets one of
+                * those and is willing to help, run "git blame" and send me
+                * an E-mail.
+                */
+               return 0x00400000;
+       case 0x720:
+               outb_p(0x76, 0x3c4);
+               vram = inb_p(0x3c5) >> 6;
+
+               if (vram == 0x00)
+                       return 0x00800000;  /* 8 MB */
+               else if (vram == 0x01)
+                       return 0x01000000;  /* 16 MB */
+               else if (vram == 0x02)
+                       return 0x00400000;  /* illegal, fallback to 4 MB */
+               else if (vram == 0x03)
+                       return 0x00400000;  /* 4 MB */
+       }
+       return 0;  /* unknown hardware */
+}
+
+static void sm7xx_resolution_probe(struct smtcfb_info *sfb)
+{
+       /* get mode parameter from smtc_scr_info */
+       if (smtc_scr_info.lfb_width != 0) {
+               sfb->fb->var.xres = smtc_scr_info.lfb_width;
+               sfb->fb->var.yres = smtc_scr_info.lfb_height;
+               sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
+               goto final;
+       }
+
+       /*
+        * No parameter, default resolution is 1024x768-16.
+        *
+        * FIXME: earlier laptops, such as IBM Thinkpad 240X, has a 800x600
+        * panel, also see the comments about Thinkpad 240X above.
+        */
+       sfb->fb->var.xres = SCREEN_X_RES;
+       sfb->fb->var.yres = SCREEN_Y_RES_PC;
+       sfb->fb->var.bits_per_pixel = SCREEN_BPP;
+
+#ifdef CONFIG_MIPS
+       /*
+        * Loongson MIPS netbooks use 1024x600 LCD panels, which is the original
+        * target platform of this driver, but nearly all old x86 laptops have
+        * 1024x768. Lighting 768 panels using 600's timings would partially
+        * garble the display, so we don't want that. But it's not possible to
+        * distinguish them reliably.
+        *
+        * So we change the default to 768, but keep 600 as-is on MIPS.
+        */
+       sfb->fb->var.yres = SCREEN_Y_RES_NETBOOK;
+#endif
+
+final:
+       big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
+}
+
 static int smtcfb_pci_probe(struct pci_dev *pdev,
                            const struct pci_device_id *ent)
 {
        struct smtcfb_info *sfb;
        struct fb_info *info;
-       u_long smem_size = 0x00800000;  /* default 8MB */
+       u_long smem_size;
        int err;
        unsigned long mmio_base;
 
@@ -1405,29 +1558,19 @@ static int smtcfb_pci_probe(struct pci_dev *pdev,
 
        sm7xx_init_hw();
 
-       /* get mode parameter from smtc_scr_info */
-       if (smtc_scr_info.lfb_width != 0) {
-               sfb->fb->var.xres = smtc_scr_info.lfb_width;
-               sfb->fb->var.yres = smtc_scr_info.lfb_height;
-               sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
-       } else {
-               /* default resolution 1024x600 16bit mode */
-               sfb->fb->var.xres = SCREEN_X_RES;
-               sfb->fb->var.yres = SCREEN_Y_RES;
-               sfb->fb->var.bits_per_pixel = SCREEN_BPP;
-       }
-
-       big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
        /* Map address and memory detection */
        mmio_base = pci_resource_start(pdev, 0);
        pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
 
+       smem_size = sm7xx_vram_probe(sfb);
+       dev_info(&pdev->dev, "%lu MiB of VRAM detected.\n",
+                                       smem_size / 1048576);
+
        switch (sfb->chip_id) {
        case 0x710:
        case 0x712:
                sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
                sfb->fb->fix.mmio_len = 0x00400000;
-               smem_size = SM712_VIDEOMEMORYSIZE;
                sfb->lfb = ioremap(mmio_base, mmio_addr);
                if (!sfb->lfb) {
                        dev_err(&pdev->dev,
@@ -1459,8 +1602,7 @@ static int smtcfb_pci_probe(struct pci_dev *pdev,
        case 0x720:
                sfb->fb->fix.mmio_start = mmio_base;
                sfb->fb->fix.mmio_len = 0x00200000;
-               smem_size = SM722_VIDEOMEMORYSIZE;
-               sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
+               sfb->dp_regs = ioremap(mmio_base, 0x00200000 + smem_size);
                sfb->lfb = sfb->dp_regs + 0x00200000;
                sfb->mmio = (smtc_regbaseaddress =
                    sfb->dp_regs + 0x000c0000);
@@ -1477,6 +1619,9 @@ static int smtcfb_pci_probe(struct pci_dev *pdev,
                goto failed_fb;
        }
 
+       /* probe and decide resolution */
+       sm7xx_resolution_probe(sfb);
+
        /* can support 32 bpp */
        if (sfb->fb->var.bits_per_pixel == 15)
                sfb->fb->var.bits_per_pixel = 16;
@@ -1487,7 +1632,11 @@ static int smtcfb_pci_probe(struct pci_dev *pdev,
        if (err)
                goto failed;
 
-       smtcfb_setmode(sfb);
+       /*
+        * The screen would be temporarily garbled when sm712fb takes over
+        * vesafb or VGA text mode. Zero the framebuffer.
+        */
+       memset_io(sfb->lfb, 0, sfb->fb->fix.smem_len);
 
        err = register_framebuffer(info);
        if (err < 0)
index 1d034dddc556949426369d81b0c49b5f3a61176b..5a0d6fb02bbc5811425afaf18812c6b4b8560dbe 100644 (file)
@@ -594,8 +594,7 @@ static int dlfb_render_hline(struct dlfb_data *dlfb, struct urb **urb_ptr,
        return 0;
 }
 
-static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y,
-              int width, int height, char *data)
+static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y, int width, int height)
 {
        int i, ret;
        char *cmd;
@@ -607,21 +606,29 @@ static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y,
 
        start_cycles = get_cycles();
 
+       mutex_lock(&dlfb->render_mutex);
+
        aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
        width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long));
        x = aligned_x;
 
        if ((width <= 0) ||
            (x + width > dlfb->info->var.xres) ||
-           (y + height > dlfb->info->var.yres))
-               return -EINVAL;
+           (y + height > dlfb->info->var.yres)) {
+               ret = -EINVAL;
+               goto unlock_ret;
+       }
 
-       if (!atomic_read(&dlfb->usb_active))
-               return 0;
+       if (!atomic_read(&dlfb->usb_active)) {
+               ret = 0;
+               goto unlock_ret;
+       }
 
        urb = dlfb_get_urb(dlfb);
-       if (!urb)
-               return 0;
+       if (!urb) {
+               ret = 0;
+               goto unlock_ret;
+       }
        cmd = urb->transfer_buffer;
 
        for (i = y; i < y + height ; i++) {
@@ -641,7 +648,7 @@ static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y,
                        *cmd++ = 0xAF;
                /* Send partial buffer remaining before exiting */
                len = cmd - (char *) urb->transfer_buffer;
-               ret = dlfb_submit_urb(dlfb, urb, len);
+               dlfb_submit_urb(dlfb, urb, len);
                bytes_sent += len;
        } else
                dlfb_urb_completion(urb);
@@ -655,7 +662,55 @@ error:
                    >> 10)), /* Kcycles */
                   &dlfb->cpu_kcycles_used);
 
-       return 0;
+       ret = 0;
+
+unlock_ret:
+       mutex_unlock(&dlfb->render_mutex);
+       return ret;
+}
+
+static void dlfb_init_damage(struct dlfb_data *dlfb)
+{
+       dlfb->damage_x = INT_MAX;
+       dlfb->damage_x2 = 0;
+       dlfb->damage_y = INT_MAX;
+       dlfb->damage_y2 = 0;
+}
+
+static void dlfb_damage_work(struct work_struct *w)
+{
+       struct dlfb_data *dlfb = container_of(w, struct dlfb_data, damage_work);
+       int x, x2, y, y2;
+
+       spin_lock_irq(&dlfb->damage_lock);
+       x = dlfb->damage_x;
+       x2 = dlfb->damage_x2;
+       y = dlfb->damage_y;
+       y2 = dlfb->damage_y2;
+       dlfb_init_damage(dlfb);
+       spin_unlock_irq(&dlfb->damage_lock);
+
+       if (x < x2 && y < y2)
+               dlfb_handle_damage(dlfb, x, y, x2 - x, y2 - y);
+}
+
+static void dlfb_offload_damage(struct dlfb_data *dlfb, int x, int y, int width, int height)
+{
+       unsigned long flags;
+       int x2 = x + width;
+       int y2 = y + height;
+
+       if (x >= x2 || y >= y2)
+               return;
+
+       spin_lock_irqsave(&dlfb->damage_lock, flags);
+       dlfb->damage_x = min(x, dlfb->damage_x);
+       dlfb->damage_x2 = max(x2, dlfb->damage_x2);
+       dlfb->damage_y = min(y, dlfb->damage_y);
+       dlfb->damage_y2 = max(y2, dlfb->damage_y2);
+       spin_unlock_irqrestore(&dlfb->damage_lock, flags);
+
+       schedule_work(&dlfb->damage_work);
 }
 
 /*
@@ -679,7 +734,7 @@ static ssize_t dlfb_ops_write(struct fb_info *info, const char __user *buf,
                                (u32)info->var.yres);
 
                dlfb_handle_damage(dlfb, 0, start, info->var.xres,
-                       lines, info->screen_base);
+                       lines);
        }
 
        return result;
@@ -694,8 +749,8 @@ static void dlfb_ops_copyarea(struct fb_info *info,
 
        sys_copyarea(info, area);
 
-       dlfb_handle_damage(dlfb, area->dx, area->dy,
-                       area->width, area->height, info->screen_base);
+       dlfb_offload_damage(dlfb, area->dx, area->dy,
+                       area->width, area->height);
 }
 
 static void dlfb_ops_imageblit(struct fb_info *info,
@@ -705,8 +760,8 @@ static void dlfb_ops_imageblit(struct fb_info *info,
 
        sys_imageblit(info, image);
 
-       dlfb_handle_damage(dlfb, image->dx, image->dy,
-                       image->width, image->height, info->screen_base);
+       dlfb_offload_damage(dlfb, image->dx, image->dy,
+                       image->width, image->height);
 }
 
 static void dlfb_ops_fillrect(struct fb_info *info,
@@ -716,8 +771,8 @@ static void dlfb_ops_fillrect(struct fb_info *info,
 
        sys_fillrect(info, rect);
 
-       dlfb_handle_damage(dlfb, rect->dx, rect->dy, rect->width,
-                             rect->height, info->screen_base);
+       dlfb_offload_damage(dlfb, rect->dx, rect->dy, rect->width,
+                             rect->height);
 }
 
 /*
@@ -739,17 +794,19 @@ static void dlfb_dpy_deferred_io(struct fb_info *info,
        int bytes_identical = 0;
        int bytes_rendered = 0;
 
+       mutex_lock(&dlfb->render_mutex);
+
        if (!fb_defio)
-               return;
+               goto unlock_ret;
 
        if (!atomic_read(&dlfb->usb_active))
-               return;
+               goto unlock_ret;
 
        start_cycles = get_cycles();
 
        urb = dlfb_get_urb(dlfb);
        if (!urb)
-               return;
+               goto unlock_ret;
 
        cmd = urb->transfer_buffer;
 
@@ -782,6 +839,8 @@ error:
        atomic_add(((unsigned int) ((end_cycles - start_cycles)
                    >> 10)), /* Kcycles */
                   &dlfb->cpu_kcycles_used);
+unlock_ret:
+       mutex_unlock(&dlfb->render_mutex);
 }
 
 static int dlfb_get_edid(struct dlfb_data *dlfb, char *edid, int len)
@@ -859,8 +918,7 @@ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
                if (area.y > info->var.yres)
                        area.y = info->var.yres;
 
-               dlfb_handle_damage(dlfb, area.x, area.y, area.w, area.h,
-                          info->screen_base);
+               dlfb_handle_damage(dlfb, area.x, area.y, area.w, area.h);
        }
 
        return 0;
@@ -942,6 +1000,10 @@ static void dlfb_ops_destroy(struct fb_info *info)
 {
        struct dlfb_data *dlfb = info->par;
 
+       cancel_work_sync(&dlfb->damage_work);
+
+       mutex_destroy(&dlfb->render_mutex);
+
        if (info->cmap.len != 0)
                fb_dealloc_cmap(&info->cmap);
        if (info->monspecs.modedb)
@@ -1065,8 +1127,7 @@ static int dlfb_ops_set_par(struct fb_info *info)
                        pix_framebuffer[i] = 0x37e6;
        }
 
-       dlfb_handle_damage(dlfb, 0, 0, info->var.xres, info->var.yres,
-                          info->screen_base);
+       dlfb_handle_damage(dlfb, 0, 0, info->var.xres, info->var.yres);
 
        return 0;
 }
@@ -1639,6 +1700,11 @@ static int dlfb_usb_probe(struct usb_interface *intf,
        dlfb->ops = dlfb_ops;
        info->fbops = &dlfb->ops;
 
+       mutex_init(&dlfb->render_mutex);
+       dlfb_init_damage(dlfb);
+       spin_lock_init(&dlfb->damage_lock);
+       INIT_WORK(&dlfb->damage_work, dlfb_damage_work);
+
        INIT_LIST_HEAD(&info->modelist);
 
        if (!dlfb_alloc_urb_list(dlfb, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
index 34dc8e53a1e9db4266e0f1aacb22a0b48fd027bc..d707fdb97354e44547e9bc95ee501ee2b059e263 100644 (file)
@@ -1543,7 +1543,7 @@ static void uvesafb_ioremap(struct fb_info *info)
 static ssize_t uvesafb_show_vbe_ver(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+       struct fb_info *info = dev_get_drvdata(dev);
        struct uvesafb_par *par = info->par;
 
        return snprintf(buf, PAGE_SIZE, "%.4x\n", par->vbe_ib.vbe_version);
@@ -1554,7 +1554,7 @@ static DEVICE_ATTR(vbe_version, S_IRUGO, uvesafb_show_vbe_ver, NULL);
 static ssize_t uvesafb_show_vbe_modes(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+       struct fb_info *info = dev_get_drvdata(dev);
        struct uvesafb_par *par = info->par;
        int ret = 0, i;
 
@@ -1573,7 +1573,7 @@ static DEVICE_ATTR(vbe_modes, S_IRUGO, uvesafb_show_vbe_modes, NULL);
 static ssize_t uvesafb_show_vendor(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+       struct fb_info *info = dev_get_drvdata(dev);
        struct uvesafb_par *par = info->par;
 
        if (par->vbe_ib.oem_vendor_name_ptr)
@@ -1588,7 +1588,7 @@ static DEVICE_ATTR(oem_vendor, S_IRUGO, uvesafb_show_vendor, NULL);
 static ssize_t uvesafb_show_product_name(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+       struct fb_info *info = dev_get_drvdata(dev);
        struct uvesafb_par *par = info->par;
 
        if (par->vbe_ib.oem_product_name_ptr)
@@ -1603,7 +1603,7 @@ static DEVICE_ATTR(oem_product_name, S_IRUGO, uvesafb_show_product_name, NULL);
 static ssize_t uvesafb_show_product_rev(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+       struct fb_info *info = dev_get_drvdata(dev);
        struct uvesafb_par *par = info->par;
 
        if (par->vbe_ib.oem_product_rev_ptr)
@@ -1618,7 +1618,7 @@ static DEVICE_ATTR(oem_product_rev, S_IRUGO, uvesafb_show_product_rev, NULL);
 static ssize_t uvesafb_show_oem_string(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+       struct fb_info *info = dev_get_drvdata(dev);
        struct uvesafb_par *par = info->par;
 
        if (par->vbe_ib.oem_string_ptr)
@@ -1633,7 +1633,7 @@ static DEVICE_ATTR(oem_string, S_IRUGO, uvesafb_show_oem_string, NULL);
 static ssize_t uvesafb_show_nocrtc(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+       struct fb_info *info = dev_get_drvdata(dev);
        struct uvesafb_par *par = info->par;
 
        return snprintf(buf, PAGE_SIZE, "%d\n", par->nocrtc);
@@ -1642,7 +1642,7 @@ static ssize_t uvesafb_show_nocrtc(struct device *dev,
 static ssize_t uvesafb_store_nocrtc(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+       struct fb_info *info = dev_get_drvdata(dev);
        struct uvesafb_par *par = info->par;
 
        if (count > 0) {
index 528fe917dd49473ecd64d81a97b2b1987ac3d913..dc1f9cfb6e7ee5a1a984db510e645c26523dc708 100644 (file)
@@ -336,8 +336,8 @@ static int vesafb_probe(struct platform_device *dev)
                printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal);
                if (pmi_base[3]) {
                        printk(KERN_INFO "vesafb: pmi: ports = ");
-                               for (i = pmi_base[3]/2; pmi_base[i] != 0xffff; i++)
-                                       printk("%x ",pmi_base[i]);
+                       for (i = pmi_base[3]/2; pmi_base[i] != 0xffff; i++)
+                               printk("%x ", pmi_base[i]);
                        printk("\n");
                        if (pmi_base[i] != 0xffff) {
                                /*
index 6a4bbc9e1fb095e3444085cddcaf67340809454a..a3d6b6db221b0ba11dcfbc363e2b75e25991ef28 100644 (file)
@@ -677,7 +677,7 @@ static void xenfb_backend_changed(struct xenbus_device *dev,
        case XenbusStateClosed:
                if (dev->state == XenbusStateClosed)
                        break;
-               /* Missed the backend's CLOSING state -- fallthrough */
+               /* fall through - Missed the backend's CLOSING state. */
        case XenbusStateClosing:
                xenbus_frontend_closed(dev);
                break;
index 8ba726e600e9a9c1a17278783f8b95ed0699ff9b..93d5bebf9572a4892c3375f592812eb81b9caf58 100644 (file)
@@ -215,6 +215,9 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
         * hypervisor.
         */
        lb_offset = param.local_vaddr & (PAGE_SIZE - 1);
+       if (param.count == 0 ||
+           param.count > U64_MAX - lb_offset - PAGE_SIZE + 1)
+               return -EINVAL;
        num_pages = (param.count + lb_offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
        /* Allocate the buffers we need */
@@ -244,7 +247,7 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
 
        /* Get the physical addresses of the source buffer */
        num_pinned = get_user_pages_fast(param.local_vaddr - lb_offset,
-               num_pages, param.source != -1, pages);
+               num_pages, param.source != -1 ? FOLL_WRITE : 0, pages);
 
        if (num_pinned != num_pages) {
                /* get_user_pages() failed */
@@ -331,8 +334,8 @@ static long ioctl_dtprop(struct fsl_hv_ioctl_prop __user *p, int set)
        struct fsl_hv_ioctl_prop param;
        char __user *upath, *upropname;
        void __user *upropval;
-       char *path = NULL, *propname = NULL;
-       void *propval = NULL;
+       char *path, *propname;
+       void *propval;
        int ret = 0;
 
        /* Get the parameters from the user. */
@@ -344,32 +347,30 @@ static long ioctl_dtprop(struct fsl_hv_ioctl_prop __user *p, int set)
        upropval = (void __user *)(uintptr_t)param.propval;
 
        path = strndup_user(upath, FH_DTPROP_MAX_PATHLEN);
-       if (IS_ERR(path)) {
-               ret = PTR_ERR(path);
-               goto out;
-       }
+       if (IS_ERR(path))
+               return PTR_ERR(path);
 
        propname = strndup_user(upropname, FH_DTPROP_MAX_PATHLEN);
        if (IS_ERR(propname)) {
                ret = PTR_ERR(propname);
-               goto out;
+               goto err_free_path;
        }
 
        if (param.proplen > FH_DTPROP_MAX_PROPLEN) {
                ret = -EINVAL;
-               goto out;
+               goto err_free_propname;
        }
 
        propval = kmalloc(param.proplen, GFP_KERNEL);
        if (!propval) {
                ret = -ENOMEM;
-               goto out;
+               goto err_free_propname;
        }
 
        if (set) {
                if (copy_from_user(propval, upropval, param.proplen)) {
                        ret = -EFAULT;
-                       goto out;
+                       goto err_free_propval;
                }
 
                param.ret = fh_partition_set_dtprop(param.handle,
@@ -388,7 +389,7 @@ static long ioctl_dtprop(struct fsl_hv_ioctl_prop __user *p, int set)
                        if (copy_to_user(upropval, propval, param.proplen) ||
                            put_user(param.proplen, &p->proplen)) {
                                ret = -EFAULT;
-                               goto out;
+                               goto err_free_propval;
                        }
                }
        }
@@ -396,10 +397,12 @@ static long ioctl_dtprop(struct fsl_hv_ioctl_prop __user *p, int set)
        if (put_user(param.ret, &p->ret))
                ret = -EFAULT;
 
-out:
-       kfree(path);
+err_free_propval:
        kfree(propval);
+err_free_propname:
        kfree(propname);
+err_free_path:
+       kfree(path);
 
        return ret;
 }
index 5df92c308286dc0f5afe203cf279adb3d8af8185..0a7b3ce3fb7542a4b2ff1e277a7ecb74b95ba4a2 100644 (file)
@@ -1004,6 +1004,7 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
 
        if (unlikely(vq->vq.num_free < 1)) {
                pr_debug("Can't add buf len 1 - avail = 0\n");
+               kfree(desc);
                END_USE(vq);
                return -ENOSPC;
        }
@@ -1718,10 +1719,10 @@ static inline int virtqueue_add(struct virtqueue *_vq,
 
 /**
  * virtqueue_add_sgs - expose buffers to other end
- * @vq: the struct virtqueue we're talking about.
+ * @_vq: the struct virtqueue we're talking about.
  * @sgs: array of terminated scatterlists.
- * @out_num: the number of scatterlists readable by other side
- * @in_num: the number of scatterlists which are writable (after readable ones)
+ * @out_sgs: the number of scatterlists readable by other side
+ * @in_sgs: the number of scatterlists which are writable (after readable ones)
  * @data: the token identifying the buffer.
  * @gfp: how to do memory allocations (if necessary).
  *
@@ -1821,7 +1822,7 @@ EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_ctx);
 
 /**
  * virtqueue_kick_prepare - first half of split virtqueue_kick call.
- * @vq: the struct virtqueue
+ * @_vq: the struct virtqueue
  *
  * Instead of virtqueue_kick(), you can do:
  *     if (virtqueue_kick_prepare(vq))
@@ -1841,7 +1842,7 @@ EXPORT_SYMBOL_GPL(virtqueue_kick_prepare);
 
 /**
  * virtqueue_notify - second half of split virtqueue_kick call.
- * @vq: the struct virtqueue
+ * @_vq: the struct virtqueue
  *
  * This does not need to be serialized.
  *
@@ -1885,8 +1886,9 @@ EXPORT_SYMBOL_GPL(virtqueue_kick);
 
 /**
  * virtqueue_get_buf - get the next used buffer
- * @vq: the struct virtqueue we're talking about.
+ * @_vq: the struct virtqueue we're talking about.
  * @len: the length written into the buffer
+ * @ctx: extra context for the token
  *
  * If the device wrote data into the buffer, @len will be set to the
  * amount written.  This means you don't need to clear the buffer
@@ -1916,7 +1918,7 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
 EXPORT_SYMBOL_GPL(virtqueue_get_buf);
 /**
  * virtqueue_disable_cb - disable callbacks
- * @vq: the struct virtqueue we're talking about.
+ * @_vq: the struct virtqueue we're talking about.
  *
  * Note that this is not necessarily synchronous, hence unreliable and only
  * useful as an optimization.
@@ -1936,7 +1938,7 @@ EXPORT_SYMBOL_GPL(virtqueue_disable_cb);
 
 /**
  * virtqueue_enable_cb_prepare - restart callbacks after disable_cb
- * @vq: the struct virtqueue we're talking about.
+ * @_vq: the struct virtqueue we're talking about.
  *
  * This re-enables callbacks; it returns current queue state
  * in an opaque unsigned value. This value should be later tested by
@@ -1957,7 +1959,7 @@ EXPORT_SYMBOL_GPL(virtqueue_enable_cb_prepare);
 
 /**
  * virtqueue_poll - query pending used buffers
- * @vq: the struct virtqueue we're talking about.
+ * @_vq: the struct virtqueue we're talking about.
  * @last_used_idx: virtqueue state (from call to virtqueue_enable_cb_prepare).
  *
  * Returns "true" if there are pending used buffers in the queue.
@@ -1976,7 +1978,7 @@ EXPORT_SYMBOL_GPL(virtqueue_poll);
 
 /**
  * virtqueue_enable_cb - restart callbacks after disable_cb.
- * @vq: the struct virtqueue we're talking about.
+ * @_vq: the struct virtqueue we're talking about.
  *
  * This re-enables callbacks; it returns "false" if there are pending
  * buffers in the queue, to detect a possible race between the driver
@@ -1995,7 +1997,7 @@ EXPORT_SYMBOL_GPL(virtqueue_enable_cb);
 
 /**
  * virtqueue_enable_cb_delayed - restart callbacks after disable_cb.
- * @vq: the struct virtqueue we're talking about.
+ * @_vq: the struct virtqueue we're talking about.
  *
  * This re-enables callbacks but hints to the other side to delay
  * interrupts until most of the available buffers have been processed;
@@ -2017,7 +2019,7 @@ EXPORT_SYMBOL_GPL(virtqueue_enable_cb_delayed);
 
 /**
  * virtqueue_detach_unused_buf - detach first unused buffer
- * @vq: the struct virtqueue we're talking about.
+ * @_vq: the struct virtqueue we're talking about.
  *
  * Returns NULL or the "data" token handed to virtqueue_add_*().
  * This is not valid on an active queue; it is useful only for device
@@ -2249,7 +2251,7 @@ EXPORT_SYMBOL_GPL(vring_transport_features);
 
 /**
  * virtqueue_get_vring_size - return the size of the virtqueue's vring
- * @vq: the struct virtqueue containing the vring of interest.
+ * @_vq: the struct virtqueue containing the vring of interest.
  *
  * Returns the size of the vring.  This is mainly used for boasting to
  * userspace.  Unlike other operations, this need not be serialized.
index 242eea8596373e21fc677a9004f55641034ab6fd..7ea60371bda0d3921b97f5035b64d40222530334 100644 (file)
@@ -30,7 +30,7 @@ menuconfig WATCHDOG
 if WATCHDOG
 
 config WATCHDOG_CORE
-       bool "WatchDog Timer Driver Core"
+       tristate "WatchDog Timer Driver Core"
        ---help---
          Say Y here if you want to use the new watchdog timer driver core.
          This driver provides a framework for all watchdog timer drivers
@@ -63,6 +63,66 @@ config WATCHDOG_SYSFS
          Say Y here if you want to enable watchdog device status read through
          sysfs attributes.
 
+comment "Watchdog Pretimeout Governors"
+
+config WATCHDOG_PRETIMEOUT_GOV
+       bool "Enable watchdog pretimeout governors"
+       depends on WATCHDOG_CORE
+       help
+         The option allows to select watchdog pretimeout governors.
+
+config WATCHDOG_PRETIMEOUT_GOV_SEL
+       tristate
+       depends on WATCHDOG_PRETIMEOUT_GOV
+       default m
+       select WATCHDOG_PRETIMEOUT_GOV_PANIC if WATCHDOG_PRETIMEOUT_GOV_NOOP=n
+
+if WATCHDOG_PRETIMEOUT_GOV
+
+config WATCHDOG_PRETIMEOUT_GOV_NOOP
+       tristate "Noop watchdog pretimeout governor"
+       depends on WATCHDOG_CORE
+       default WATCHDOG_CORE
+       help
+         Noop watchdog pretimeout governor, only an informational
+         message is added to kernel log buffer.
+
+config WATCHDOG_PRETIMEOUT_GOV_PANIC
+       tristate "Panic watchdog pretimeout governor"
+       depends on WATCHDOG_CORE
+       default WATCHDOG_CORE
+       help
+         Panic watchdog pretimeout governor, on watchdog pretimeout
+         event put the kernel into panic.
+
+choice
+       prompt "Default Watchdog Pretimeout Governor"
+       default WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC
+       help
+         This option selects a default watchdog pretimeout governor.
+         The governor takes its action, if a watchdog is capable
+         to report a pretimeout event.
+
+config WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP
+       bool "noop"
+       depends on WATCHDOG_PRETIMEOUT_GOV_NOOP
+       help
+         Use noop watchdog pretimeout governor by default. If noop
+         governor is selected by a user, write a short message to
+         the kernel log buffer and don't do any system changes.
+
+config WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC
+       bool "panic"
+       depends on WATCHDOG_PRETIMEOUT_GOV_PANIC
+       help
+         Use panic watchdog pretimeout governor by default, if
+         a watchdog pretimeout event happens, consider that
+         a watchdog feeder is dead and reboot is unavoidable.
+
+endchoice
+
+endif # WATCHDOG_PRETIMEOUT_GOV
+
 #
 # General Watchdog drivers
 #
@@ -90,6 +150,18 @@ config SOFT_WATCHDOG_PRETIMEOUT
          watchdog. Be aware that governors might affect the watchdog because it
          is purely software, e.g. the panic governor will stall it!
 
+config BD70528_WATCHDOG
+       tristate "ROHM BD70528 PMIC Watchdog"
+       depends on MFD_ROHM_BD70528
+       select WATCHDOG_CORE
+       help
+         Support for the watchdog in the ROHM BD70528 PMIC. Watchdog trigger
+         cause system reset.
+
+         Say Y here to include support for the ROHM BD70528 watchdog.
+         Alternatively say M to compile the driver as a module,
+         which will be called bd70528_wdt.
+
 config DA9052_WATCHDOG
        tristate "Dialog DA9052 Watchdog"
        depends on PMIC_DA9052 || COMPILE_TEST
@@ -552,7 +624,7 @@ config COH901327_WATCHDOG
          compiled as a module.
 
 config NPCM7XX_WATCHDOG
-       bool "Nuvoton NPCM750 watchdog"
+       tristate "Nuvoton NPCM750 watchdog"
        depends on ARCH_NPCM || COMPILE_TEST
        default y if ARCH_NPCM7XX
        select WATCHDOG_CORE
@@ -641,6 +713,22 @@ config IMX2_WDT
          To compile this driver as a module, choose M here: the
          module will be called imx2_wdt.
 
+config IMX_SC_WDT
+       tristate "IMX SC Watchdog"
+       depends on HAVE_ARM_SMCCC
+       select WATCHDOG_CORE
+       help
+         This is the driver for the system controller watchdog
+         on the NXP i.MX SoCs with system controller inside, the
+         watchdog driver will call ARM SMC API and trap into
+         ARM-Trusted-Firmware for operations, ARM-Trusted-Firmware
+         will request system controller to execute the operations.
+         If you have one of these processors and wish to have
+         watchdog support enabled, say Y, otherwise say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called imx_sc_wdt.
+
 config UX500_WATCHDOG
        tristate "ST-Ericsson Ux500 watchdog"
        depends on MFD_DB8500_PRCMU
@@ -1179,6 +1267,15 @@ config HP_WATCHDOG
          To compile this driver as a module, choose M here: the module will be
          called hpwdt.
 
+config HPWDT_NMI_DECODING
+       bool "NMI support for the HP ProLiant iLO2+ Hardware Watchdog Timer"
+       depends on HP_WATCHDOG
+       default y
+       help
+         Enables the NMI handler for the watchdog pretimeout NMI and the iLO
+         "Generate NMI to System" virtual button.  When an NMI is claimed
+         by the driver, panic is called.
+
 config KEMPLD_WDT
        tristate "Kontron COM Watchdog Timer"
        depends on MFD_KEMPLD
@@ -1190,15 +1287,6 @@ config KEMPLD_WDT
          This driver can also be built as a module. If so, the module will be
          called kempld_wdt.
 
-config HPWDT_NMI_DECODING
-       bool "NMI support for the HP ProLiant iLO2+ Hardware Watchdog Timer"
-       depends on HP_WATCHDOG
-       default y
-       help
-         Enables the NMI handler for the watchdog pretimeout NMI and the iLO
-         "Generate NMI to System" virtual button.  When an NMI is claimed
-         by the driver, panic is called.
-
 config SC1200_WDT
        tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
        depends on X86
@@ -1647,7 +1735,7 @@ config BCM_KONA_WDT
 
 config BCM_KONA_WDT_DEBUG
        bool "DEBUGFS support for BCM Kona Watchdog"
-       depends on BCM_KONA_WDT || COMPILE_TEST
+       depends on BCM_KONA_WDT
        help
          If enabled, adds /sys/kernel/debug/bcm_kona_wdt/info which provides
          access to the driver's internal data structures as well as watchdog
@@ -2024,53 +2112,4 @@ config USBPCWATCHDOG
 
          Most people will say N.
 
-comment "Watchdog Pretimeout Governors"
-
-config WATCHDOG_PRETIMEOUT_GOV
-       bool "Enable watchdog pretimeout governors"
-       help
-         The option allows to select watchdog pretimeout governors.
-
-if WATCHDOG_PRETIMEOUT_GOV
-
-choice
-       prompt "Default Watchdog Pretimeout Governor"
-       default WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC
-       help
-         This option selects a default watchdog pretimeout governor.
-         The governor takes its action, if a watchdog is capable
-         to report a pretimeout event.
-
-config WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP
-       bool "noop"
-       select WATCHDOG_PRETIMEOUT_GOV_NOOP
-       help
-         Use noop watchdog pretimeout governor by default. If noop
-         governor is selected by a user, write a short message to
-         the kernel log buffer and don't do any system changes.
-
-config WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC
-       bool "panic"
-       select WATCHDOG_PRETIMEOUT_GOV_PANIC
-       help
-         Use panic watchdog pretimeout governor by default, if
-         a watchdog pretimeout event happens, consider that
-         a watchdog feeder is dead and reboot is unavoidable.
-
-endchoice
-
-config WATCHDOG_PRETIMEOUT_GOV_NOOP
-       tristate "Noop watchdog pretimeout governor"
-       help
-         Noop watchdog pretimeout governor, only an informational
-         message is added to kernel log buffer.
-
-config WATCHDOG_PRETIMEOUT_GOV_PANIC
-       tristate "Panic watchdog pretimeout governor"
-       help
-         Panic watchdog pretimeout governor, on watchdog pretimeout
-         event put the kernel into panic.
-
-endif # WATCHDOG_PRETIMEOUT_GOV
-
 endif # WATCHDOG
index ba930e464657590131ba2f35ef28afad27ef091e..7caa920e7e607fb6e2cf3b15bc536275d880d549 100644 (file)
@@ -68,6 +68,7 @@ obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
 obj-$(CONFIG_TS4800_WATCHDOG) += ts4800_wdt.o
 obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
 obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
+obj-$(CONFIG_IMX_SC_WDT) += imx_sc_wdt.o
 obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
 obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
 obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
@@ -205,6 +206,7 @@ obj-$(CONFIG_WATCHDOG_SUN4V)                += sun4v_wdt.o
 obj-$(CONFIG_XEN_WDT) += xen_wdt.o
 
 # Architecture Independent
+obj-$(CONFIG_BD70528_WATCHDOG) += bd70528_wdt.o
 obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o
 obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o
 obj-$(CONFIG_DA9062_WATCHDOG) += da9062_wdt.o
index 7e9884960eb9401949fd77fe9f8f3f02bd6d6e86..689b8a0593c1ad2ac8caaba1403ebb53c8a922d0 100644 (file)
@@ -277,8 +277,8 @@ static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        return -EINVAL;
                timeout = new_timeout;
                wdt_keepalive();
-               /* Fall through */
        }
+               /* Fall through */
        case WDIOC_GETTIMEOUT:
                return put_user(timeout, p);
        default:
index 4b4054f54df97c5a6225b91822eb2c8004421e63..e5dcb26d85f0a95c9046f0c976e52f9d92d1de0e 100644 (file)
@@ -244,6 +244,11 @@ static const struct watchdog_ops armada_37xx_wdt_ops = {
        .get_timeleft = armada_37xx_wdt_get_timeleft,
 };
 
+static void armada_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int armada_37xx_wdt_probe(struct platform_device *pdev)
 {
        struct armada_37xx_watchdog *dev;
@@ -278,12 +283,14 @@ static int armada_37xx_wdt_probe(struct platform_device *pdev)
        ret = clk_prepare_enable(dev->clk);
        if (ret)
                return ret;
+       ret = devm_add_action_or_reset(&pdev->dev,
+                                      armada_clk_disable_unprepare, dev->clk);
+       if (ret)
+               return ret;
 
        dev->clk_rate = clk_get_rate(dev->clk);
-       if (!dev->clk_rate) {
-               ret = -EINVAL;
-               goto disable_clk;
-       }
+       if (!dev->clk_rate)
+               return -EINVAL;
 
        /*
         * Since the timeout in seconds is given as 32 bit unsigned int, and
@@ -307,35 +314,15 @@ static int armada_37xx_wdt_probe(struct platform_device *pdev)
                set_bit(WDOG_HW_RUNNING, &dev->wdt.status);
 
        watchdog_set_nowayout(&dev->wdt, nowayout);
-       ret = watchdog_register_device(&dev->wdt);
+       watchdog_stop_on_reboot(&dev->wdt);
+       ret = devm_watchdog_register_device(&pdev->dev, &dev->wdt);
        if (ret)
-               goto disable_clk;
+               return ret;
 
        dev_info(&pdev->dev, "Initial timeout %d sec%s\n",
                 dev->wdt.timeout, nowayout ? ", nowayout" : "");
 
        return 0;
-
-disable_clk:
-       clk_disable_unprepare(dev->clk);
-       return ret;
-}
-
-static int armada_37xx_wdt_remove(struct platform_device *pdev)
-{
-       struct watchdog_device *wdt = platform_get_drvdata(pdev);
-       struct armada_37xx_watchdog *dev = watchdog_get_drvdata(wdt);
-
-       watchdog_unregister_device(wdt);
-       clk_disable_unprepare(dev->clk);
-       return 0;
-}
-
-static void armada_37xx_wdt_shutdown(struct platform_device *pdev)
-{
-       struct watchdog_device *wdt = platform_get_drvdata(pdev);
-
-       armada_37xx_wdt_stop(wdt);
 }
 
 static int __maybe_unused armada_37xx_wdt_suspend(struct device *dev)
@@ -370,8 +357,6 @@ MODULE_DEVICE_TABLE(of, armada_37xx_wdt_match);
 
 static struct platform_driver armada_37xx_wdt_driver = {
        .probe          = armada_37xx_wdt_probe,
-       .remove         = armada_37xx_wdt_remove,
-       .shutdown       = armada_37xx_wdt_shutdown,
        .driver         = {
                .name   = "armada_37xx_wdt",
                .of_match_table = of_match_ptr(armada_37xx_wdt_match),
index 9768e44ffeb8a46d136e457bfc9e9e652540ee8d..c5b9aae544dd4ef73cb2f089ffc35409e6d944f7 100644 (file)
@@ -196,6 +196,11 @@ static const struct watchdog_ops asm9260_wdt_ops = {
        .restart        = asm9260_restart,
 };
 
+static void asm9260_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int asm9260_wdt_get_dt_clks(struct asm9260_wdt_priv *priv)
 {
        int err;
@@ -219,26 +224,32 @@ static int asm9260_wdt_get_dt_clks(struct asm9260_wdt_priv *priv)
                dev_err(priv->dev, "Failed to enable ahb_clk!\n");
                return err;
        }
+       err = devm_add_action_or_reset(priv->dev,
+                                      asm9260_clk_disable_unprepare,
+                                      priv->clk_ahb);
+       if (err)
+               return err;
 
        err = clk_set_rate(priv->clk, CLOCK_FREQ);
        if (err) {
-               clk_disable_unprepare(priv->clk_ahb);
                dev_err(priv->dev, "Failed to set rate!\n");
                return err;
        }
 
        err = clk_prepare_enable(priv->clk);
        if (err) {
-               clk_disable_unprepare(priv->clk_ahb);
                dev_err(priv->dev, "Failed to enable clk!\n");
                return err;
        }
+       err = devm_add_action_or_reset(priv->dev,
+                                      asm9260_clk_disable_unprepare,
+                                      priv->clk);
+       if (err)
+               return err;
 
        /* wdt has internal divider */
        clk = clk_get_rate(priv->clk);
        if (!clk) {
-               clk_disable_unprepare(priv->clk);
-               clk_disable_unprepare(priv->clk_ahb);
                dev_err(priv->dev, "Failed, clk is 0!\n");
                return -EINVAL;
        }
@@ -274,25 +285,23 @@ static void asm9260_wdt_get_dt_mode(struct asm9260_wdt_priv *priv)
 
 static int asm9260_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct asm9260_wdt_priv *priv;
        struct watchdog_device *wdd;
-       struct resource *res;
        int ret;
        static const char * const mode_name[] = { "hw", "sw", "debug", };
 
-       priv = devm_kzalloc(&pdev->dev, sizeof(struct asm9260_wdt_priv),
-                           GFP_KERNEL);
+       priv = devm_kzalloc(dev, sizeof(struct asm9260_wdt_priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       priv->dev = &pdev->dev;
+       priv->dev = dev;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->iobase = devm_ioremap_resource(&pdev->dev, res);
+       priv->iobase = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->iobase))
                return PTR_ERR(priv->iobase);
 
-       priv->rst = devm_reset_control_get_exclusive(&pdev->dev, "wdt_rst");
+       priv->rst = devm_reset_control_get_exclusive(dev, "wdt_rst");
        if (IS_ERR(priv->rst))
                return PTR_ERR(priv->rst);
 
@@ -305,7 +314,7 @@ static int asm9260_wdt_probe(struct platform_device *pdev)
        wdd->ops = &asm9260_wdt_ops;
        wdd->min_timeout = 1;
        wdd->max_timeout = BM_WDTC_MAX(priv->wdt_freq);
-       wdd->parent = &pdev->dev;
+       wdd->parent = dev;
 
        watchdog_set_drvdata(wdd, priv);
 
@@ -315,7 +324,7 @@ static int asm9260_wdt_probe(struct platform_device *pdev)
         * the max instead.
         */
        wdd->timeout = ASM9260_WDT_DEFAULT_TIMEOUT;
-       watchdog_init_timeout(wdd, 0, &pdev->dev);
+       watchdog_init_timeout(wdd, 0, dev);
 
        asm9260_wdt_get_dt_mode(priv);
 
@@ -327,49 +336,25 @@ static int asm9260_wdt_probe(struct platform_device *pdev)
                 * Not all supported platforms specify an interrupt for the
                 * watchdog, so let's make it optional.
                 */
-               ret = devm_request_irq(&pdev->dev, priv->irq,
-                                      asm9260_wdt_irq, 0, pdev->name, priv);
+               ret = devm_request_irq(dev, priv->irq, asm9260_wdt_irq, 0,
+                                      pdev->name, priv);
                if (ret < 0)
-                       dev_warn(&pdev->dev, "failed to request IRQ\n");
+                       dev_warn(dev, "failed to request IRQ\n");
        }
 
        watchdog_set_restart_priority(wdd, 128);
 
-       ret = watchdog_register_device(wdd);
+       watchdog_stop_on_reboot(wdd);
+       watchdog_stop_on_unregister(wdd);
+       ret = devm_watchdog_register_device(dev, wdd);
        if (ret)
-               goto clk_off;
+               return ret;
 
        platform_set_drvdata(pdev, priv);
 
-       dev_info(&pdev->dev, "Watchdog enabled (timeout: %d sec, mode: %s)\n",
+       dev_info(dev, "Watchdog enabled (timeout: %d sec, mode: %s)\n",
                 wdd->timeout, mode_name[priv->mode]);
        return 0;
-
-clk_off:
-       clk_disable_unprepare(priv->clk);
-       clk_disable_unprepare(priv->clk_ahb);
-       return ret;
-}
-
-static void asm9260_wdt_shutdown(struct platform_device *pdev)
-{
-       struct asm9260_wdt_priv *priv = platform_get_drvdata(pdev);
-
-       asm9260_wdt_disable(&priv->wdd);
-}
-
-static int asm9260_wdt_remove(struct platform_device *pdev)
-{
-       struct asm9260_wdt_priv *priv = platform_get_drvdata(pdev);
-
-       asm9260_wdt_disable(&priv->wdd);
-
-       watchdog_unregister_device(&priv->wdd);
-
-       clk_disable_unprepare(priv->clk);
-       clk_disable_unprepare(priv->clk_ahb);
-
-       return 0;
 }
 
 static const struct of_device_id asm9260_wdt_of_match[] = {
@@ -384,8 +369,6 @@ static struct platform_driver asm9260_wdt_driver = {
                .of_match_table = asm9260_wdt_of_match,
        },
        .probe = asm9260_wdt_probe,
-       .remove = asm9260_wdt_remove,
-       .shutdown = asm9260_wdt_shutdown,
 };
 module_platform_driver(asm9260_wdt_driver);
 
index 1abe4d021fd27171bae9fb7a289c72916f041486..34117745c65f1786d0879be10395b36ea7137801 100644 (file)
@@ -187,22 +187,21 @@ static const struct watchdog_info aspeed_wdt_info = {
 
 static int aspeed_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        const struct aspeed_wdt_config *config;
        const struct of_device_id *ofdid;
        struct aspeed_wdt *wdt;
-       struct resource *res;
        struct device_node *np;
        const char *reset_type;
        u32 duration;
        u32 status;
        int ret;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->base = devm_ioremap_resource(&pdev->dev, res);
+       wdt->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->base))
                return PTR_ERR(wdt->base);
 
@@ -214,12 +213,12 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
        wdt->wdd.info = &aspeed_wdt_info;
        wdt->wdd.ops = &aspeed_wdt_ops;
        wdt->wdd.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT_MS;
-       wdt->wdd.parent = &pdev->dev;
+       wdt->wdd.parent = dev;
 
        wdt->wdd.timeout = WDT_DEFAULT_TIMEOUT;
-       watchdog_init_timeout(&wdt->wdd, 0, &pdev->dev);
+       watchdog_init_timeout(&wdt->wdd, 0, dev);
 
-       np = pdev->dev.of_node;
+       np = dev->of_node;
 
        ofdid = of_match_node(aspeed_wdt_of_table, np);
        if (!ofdid)
@@ -288,11 +287,11 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
                u32 max_duration = config->ext_pulse_width_mask + 1;
 
                if (duration == 0 || duration > max_duration) {
-                       dev_err(&pdev->dev, "Invalid pulse duration: %uus\n",
-                                       duration);
+                       dev_err(dev, "Invalid pulse duration: %uus\n",
+                               duration);
                        duration = max(1U, min(max_duration, duration));
-                       dev_info(&pdev->dev, "Pulse duration set to %uus\n",
-                                       duration);
+                       dev_info(dev, "Pulse duration set to %uus\n",
+                                duration);
                }
 
                /*
@@ -314,9 +313,9 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
        if (status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY)
                wdt->wdd.bootstatus = WDIOF_CARDRESET;
 
-       ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdd);
+       ret = devm_watchdog_register_device(dev, &wdt->wdd);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register\n");
+               dev_err(dev, "failed to register\n");
                return ret;
        }
 
index f4050a229eb5865574f3085be11d747d2ff020ee..292b5a1ca8318a50040957f68effe0685095530b 100644 (file)
@@ -327,7 +327,6 @@ static inline int of_at91wdt_init(struct device_node *np, struct at91wdt *wdt)
 
 static int __init at91wdt_probe(struct platform_device *pdev)
 {
-       struct resource *r;
        int err;
        struct at91wdt *wdt;
 
@@ -346,8 +345,7 @@ static int __init at91wdt_probe(struct platform_device *pdev)
        wdt->wdd.min_timeout = 1;
        wdt->wdd.max_timeout = 0xFFFF;
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->base = devm_ioremap_resource(&pdev->dev, r);
+       wdt->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->base))
                return PTR_ERR(wdt->base);
 
index 4f56b63f96910c3fa3b8b53b513b096f46bb8322..02234c254b10644850b9e838176463f9d85ac0c5 100644 (file)
@@ -250,15 +250,13 @@ static struct miscdevice ath79_wdt_miscdev = {
 
 static int ath79_wdt_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        u32 ctrl;
        int err;
 
        if (wdt_base)
                return -EBUSY;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt_base = devm_ioremap_resource(&pdev->dev, res);
+       wdt_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt_base))
                return PTR_ERR(wdt_base);
 
index 4abdcabd8219e61ddc8adbbba23ac804f2f54f2c..79337d2a8a8e226a8ff08d347e8b858490b47aa2 100644 (file)
@@ -125,80 +125,57 @@ static const struct of_device_id atlas7_wdt_ids[] = {
        {}
 };
 
+static void atlas7_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int atlas7_wdt_probe(struct platform_device *pdev)
 {
-       struct device_node *np = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
        struct atlas7_wdog *wdt;
-       struct resource *res;
        struct clk *clk;
        int ret;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->base = devm_ioremap_resource(&pdev->dev, res);
+       wdt->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->base))
                return PTR_ERR(wdt->base);
 
-       clk = of_clk_get(np, 0);
+       clk = devm_clk_get(dev, NULL);
        if (IS_ERR(clk))
                return PTR_ERR(clk);
        ret = clk_prepare_enable(clk);
        if (ret) {
-               dev_err(&pdev->dev, "clk enable failed\n");
-               goto err;
+               dev_err(dev, "clk enable failed\n");
+               return ret;
        }
+       ret = devm_add_action_or_reset(dev, atlas7_clk_disable_unprepare, clk);
+       if (ret)
+               return ret;
 
        /* disable watchdog hardware */
        writel(0, wdt->base + ATLAS7_WDT_CNT_CTRL);
 
        wdt->tick_rate = clk_get_rate(clk);
-       if (!wdt->tick_rate) {
-               ret = -EINVAL;
-               goto err1;
-       }
+       if (!wdt->tick_rate)
+               return -EINVAL;
 
        wdt->clk = clk;
        atlas7_wdd.min_timeout = 1;
        atlas7_wdd.max_timeout = UINT_MAX / wdt->tick_rate;
 
-       watchdog_init_timeout(&atlas7_wdd, 0, &pdev->dev);
+       watchdog_init_timeout(&atlas7_wdd, 0, dev);
        watchdog_set_nowayout(&atlas7_wdd, nowayout);
 
        watchdog_set_drvdata(&atlas7_wdd, wdt);
        platform_set_drvdata(pdev, &atlas7_wdd);
 
-       ret = watchdog_register_device(&atlas7_wdd);
-       if (ret)
-               goto err1;
-
-       return 0;
-
-err1:
-       clk_disable_unprepare(clk);
-err:
-       clk_put(clk);
-       return ret;
-}
-
-static void atlas7_wdt_shutdown(struct platform_device *pdev)
-{
-       struct watchdog_device *wdd = platform_get_drvdata(pdev);
-       struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
-
-       atlas7_wdt_disable(wdd);
-       clk_disable_unprepare(wdt->clk);
-}
-
-static int atlas7_wdt_remove(struct platform_device *pdev)
-{
-       struct watchdog_device *wdd = platform_get_drvdata(pdev);
-       struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
-
-       atlas7_wdt_shutdown(pdev);
-       clk_put(wdt->clk);
-       return 0;
+       watchdog_stop_on_reboot(&atlas7_wdd);
+       watchdog_stop_on_unregister(&atlas7_wdd);
+       return devm_watchdog_register_device(dev, &atlas7_wdd);
 }
 
 static int __maybe_unused atlas7_wdt_suspend(struct device *dev)
@@ -236,8 +213,6 @@ static struct platform_driver atlas7_wdt_driver = {
                .of_match_table = atlas7_wdt_ids,
        },
        .probe = atlas7_wdt_probe,
-       .remove = atlas7_wdt_remove,
-       .shutdown = atlas7_wdt_shutdown,
 };
 module_platform_driver(atlas7_wdt_driver);
 
index 1834524ae3734c4d87e64ad3c83e321a407ffd50..560c1c54c17790781766bf065e86d0cdd6e8ef20 100644 (file)
@@ -177,7 +177,6 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
        wdt = devm_kzalloc(dev, sizeof(struct bcm2835_wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
-       platform_set_drvdata(pdev, wdt);
 
        spin_lock_init(&wdt->lock);
 
index ce3f646e80775d324b29e4c5d2c3db00327645d1..d3d88f6703d79ea8daaa685d8f10d5668c143aa1 100644 (file)
@@ -107,11 +107,15 @@ static const struct watchdog_ops bcm7038_wdt_ops = {
        .get_timeleft   = bcm7038_wdt_get_timeleft,
 };
 
+static void bcm7038_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int bcm7038_wdt_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct bcm7038_watchdog *wdt;
-       struct resource *res;
        int err;
 
        wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
@@ -120,8 +124,7 @@ static int bcm7038_wdt_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, wdt);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->base = devm_ioremap_resource(dev, res);
+       wdt->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->base))
                return PTR_ERR(wdt->base);
 
@@ -129,6 +132,11 @@ static int bcm7038_wdt_probe(struct platform_device *pdev)
        /* If unable to get clock, use default frequency */
        if (!IS_ERR(wdt->clk)) {
                err = clk_prepare_enable(wdt->clk);
+               if (err)
+                       return err;
+               err = devm_add_action_or_reset(dev,
+                                              bcm7038_clk_disable_unprepare,
+                                              wdt->clk);
                if (err)
                        return err;
                wdt->rate = clk_get_rate(wdt->clk);
@@ -148,10 +156,11 @@ static int bcm7038_wdt_probe(struct platform_device *pdev)
        wdt->wdd.parent         = dev;
        watchdog_set_drvdata(&wdt->wdd, wdt);
 
-       err = watchdog_register_device(&wdt->wdd);
+       watchdog_stop_on_reboot(&wdt->wdd);
+       watchdog_stop_on_unregister(&wdt->wdd);
+       err = devm_watchdog_register_device(dev, &wdt->wdd);
        if (err) {
                dev_err(dev, "Failed to register watchdog device\n");
-               clk_disable_unprepare(wdt->clk);
                return err;
        }
 
@@ -160,19 +169,6 @@ static int bcm7038_wdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int bcm7038_wdt_remove(struct platform_device *pdev)
-{
-       struct bcm7038_watchdog *wdt = platform_get_drvdata(pdev);
-
-       if (!nowayout)
-               bcm7038_wdt_stop(&wdt->wdd);
-
-       watchdog_unregister_device(&wdt->wdd);
-       clk_disable_unprepare(wdt->clk);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int bcm7038_wdt_suspend(struct device *dev)
 {
@@ -198,14 +194,6 @@ static int bcm7038_wdt_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(bcm7038_wdt_pm_ops, bcm7038_wdt_suspend,
                         bcm7038_wdt_resume);
 
-static void bcm7038_wdt_shutdown(struct platform_device *pdev)
-{
-       struct bcm7038_watchdog *wdt = platform_get_drvdata(pdev);
-
-       if (watchdog_active(&wdt->wdd))
-               bcm7038_wdt_stop(&wdt->wdd);
-}
-
 static const struct of_device_id bcm7038_wdt_match[] = {
        { .compatible = "brcm,bcm7038-wdt" },
        {},
@@ -214,8 +202,6 @@ MODULE_DEVICE_TABLE(of, bcm7038_wdt_match);
 
 static struct platform_driver bcm7038_wdt_driver = {
        .probe          = bcm7038_wdt_probe,
-       .remove         = bcm7038_wdt_remove,
-       .shutdown       = bcm7038_wdt_shutdown,
        .driver         = {
                .name           = "bcm7038-wdt",
                .of_match_table = bcm7038_wdt_match,
index 4249b47902bd5321bf7955b3f86bb773b8c2a305..e2ad4481635996fb98511eccaa398177c6e618c3 100644 (file)
@@ -271,16 +271,10 @@ static struct watchdog_device bcm_kona_wdt_wdd = {
        .timeout =      SECWDOG_MAX_COUNT >> SECWDOG_DEFAULT_RESOLUTION,
 };
 
-static void bcm_kona_wdt_shutdown(struct platform_device *pdev)
-{
-       bcm_kona_wdt_stop(&bcm_kona_wdt_wdd);
-}
-
 static int bcm_kona_wdt_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct bcm_kona_wdt *wdt;
-       struct resource *res;
        int ret;
 
        wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
@@ -289,8 +283,7 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev)
 
        spin_lock_init(&wdt->lock);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->base = devm_ioremap_resource(dev, res);
+       wdt->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->base))
                return -ENODEV;
 
@@ -303,7 +296,7 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, wdt);
        watchdog_set_drvdata(&bcm_kona_wdt_wdd, wdt);
-       bcm_kona_wdt_wdd.parent = &pdev->dev;
+       bcm_kona_wdt_wdd.parent = dev;
 
        ret = bcm_kona_wdt_set_timeout_reg(&bcm_kona_wdt_wdd, 0);
        if (ret) {
@@ -311,7 +304,9 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = watchdog_register_device(&bcm_kona_wdt_wdd);
+       watchdog_stop_on_reboot(&bcm_kona_wdt_wdd);
+       watchdog_stop_on_unregister(&bcm_kona_wdt_wdd);
+       ret = devm_watchdog_register_device(dev, &bcm_kona_wdt_wdd);
        if (ret) {
                dev_err(dev, "Failed to register watchdog device");
                return ret;
@@ -326,8 +321,6 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev)
 static int bcm_kona_wdt_remove(struct platform_device *pdev)
 {
        bcm_kona_wdt_debug_exit(pdev);
-       bcm_kona_wdt_shutdown(pdev);
-       watchdog_unregister_device(&bcm_kona_wdt_wdd);
        dev_dbg(&pdev->dev, "Watchdog driver disabled");
 
        return 0;
@@ -346,7 +339,6 @@ static struct platform_driver bcm_kona_wdt_driver = {
                  },
        .probe = bcm_kona_wdt_probe,
        .remove = bcm_kona_wdt_remove,
-       .shutdown = bcm_kona_wdt_shutdown,
 };
 
 module_platform_driver(bcm_kona_wdt_driver);
diff --git a/drivers/watchdog/bd70528_wdt.c b/drivers/watchdog/bd70528_wdt.c
new file mode 100644 (file)
index 0000000..b0152fe
--- /dev/null
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 ROHM Semiconductors
+// ROHM BD70528MWV watchdog driver
+
+#include <linux/bcd.h>
+#include <linux/kernel.h>
+#include <linux/mfd/rohm-bd70528.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/watchdog.h>
+
+/*
+ * Max time we can set is 1 hour, 59 minutes and 59 seconds
+ * and Minimum time is 1 second
+ */
+#define WDT_MAX_MS     ((2 * 60 * 60 - 1) * 1000)
+#define WDT_MIN_MS     1000
+#define DEFAULT_TIMEOUT        60
+
+#define WD_CTRL_MAGIC1 0x55
+#define WD_CTRL_MAGIC2 0xAA
+
+struct wdtbd70528 {
+       struct device *dev;
+       struct regmap *regmap;
+       struct rohm_regmap_dev *mfd;
+       struct watchdog_device wdt;
+};
+
+/**
+ * bd70528_wdt_set - arm or disarm watchdog timer
+ *
+ * @data:      device data for the PMIC instance we want to operate on
+ * @enable:    new state of WDT. zero to disable, non zero to enable
+ * @old_state: previous state of WDT will be filled here
+ *
+ * Arm or disarm WDT on BD70528 PMIC. Expected to be called only by
+ * BD70528 RTC and BD70528 WDT drivers. The rtc_timer_lock must be taken
+ * by calling bd70528_wdt_lock before calling bd70528_wdt_set.
+ */
+int bd70528_wdt_set(struct rohm_regmap_dev *data, int enable, int *old_state)
+{
+       int ret, i;
+       unsigned int tmp;
+       struct bd70528_data *bd70528 = container_of(data, struct bd70528_data,
+                                                chip);
+       u8 wd_ctrl_arr[3] = { WD_CTRL_MAGIC1, WD_CTRL_MAGIC2, 0 };
+       u8 *wd_ctrl = &wd_ctrl_arr[2];
+
+       ret = regmap_read(bd70528->chip.regmap, BD70528_REG_WDT_CTRL, &tmp);
+       if (ret)
+               return ret;
+
+       *wd_ctrl = (u8)tmp;
+
+       if (old_state) {
+               if (*wd_ctrl & BD70528_MASK_WDT_EN)
+                       *old_state |= BD70528_WDT_STATE_BIT;
+               else
+                       *old_state &= ~BD70528_WDT_STATE_BIT;
+               if ((!enable) == (!(*old_state & BD70528_WDT_STATE_BIT)))
+                       return 0;
+       }
+
+       if (enable) {
+               if (*wd_ctrl & BD70528_MASK_WDT_EN)
+                       return 0;
+               *wd_ctrl |= BD70528_MASK_WDT_EN;
+       } else {
+               if (*wd_ctrl & BD70528_MASK_WDT_EN)
+                       *wd_ctrl &= ~BD70528_MASK_WDT_EN;
+               else
+                       return 0;
+       }
+
+       for (i = 0; i < 3; i++) {
+               ret = regmap_write(bd70528->chip.regmap, BD70528_REG_WDT_CTRL,
+                                  wd_ctrl_arr[i]);
+               if (ret)
+                       return ret;
+       }
+
+       ret = regmap_read(bd70528->chip.regmap, BD70528_REG_WDT_CTRL, &tmp);
+       if ((tmp & BD70528_MASK_WDT_EN) != (*wd_ctrl & BD70528_MASK_WDT_EN)) {
+               dev_err(bd70528->chip.dev,
+                       "Watchdog ctrl mismatch (hw) 0x%x (set) 0x%x\n",
+                       tmp, *wd_ctrl);
+               ret = -EIO;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(bd70528_wdt_set);
+
+/**
+ * bd70528_wdt_lock - take WDT lock
+ *
+ * @bd70528:   device data for the PMIC instance we want to operate on
+ *
+ * Lock WDT for arming/disarming in order to avoid race condition caused
+ * by WDT state changes initiated by WDT and RTC drivers.
+ */
+void bd70528_wdt_lock(struct rohm_regmap_dev *data)
+{
+       struct bd70528_data *bd70528 = container_of(data, struct bd70528_data,
+                                                chip);
+
+       mutex_lock(&bd70528->rtc_timer_lock);
+}
+EXPORT_SYMBOL(bd70528_wdt_lock);
+
+/**
+ * bd70528_wdt_unlock - unlock WDT lock
+ *
+ * @bd70528:   device data for the PMIC instance we want to operate on
+ *
+ * Unlock WDT lock which has previously been taken by call to
+ * bd70528_wdt_lock.
+ */
+void bd70528_wdt_unlock(struct rohm_regmap_dev *data)
+{
+       struct bd70528_data *bd70528 = container_of(data, struct bd70528_data,
+                                                chip);
+
+       mutex_unlock(&bd70528->rtc_timer_lock);
+}
+EXPORT_SYMBOL(bd70528_wdt_unlock);
+
+static int bd70528_wdt_set_locked(struct wdtbd70528 *w, int enable)
+{
+       return bd70528_wdt_set(w->mfd, enable, NULL);
+}
+
+static int bd70528_wdt_change(struct wdtbd70528 *w, int enable)
+{
+       int ret;
+
+       bd70528_wdt_lock(w->mfd);
+       ret = bd70528_wdt_set_locked(w, enable);
+       bd70528_wdt_unlock(w->mfd);
+
+       return ret;
+}
+
+static int bd70528_wdt_start(struct watchdog_device *wdt)
+{
+       struct wdtbd70528 *w = watchdog_get_drvdata(wdt);
+
+       dev_dbg(w->dev, "WDT ping...\n");
+       return bd70528_wdt_change(w, 1);
+}
+
+static int bd70528_wdt_stop(struct watchdog_device *wdt)
+{
+       struct wdtbd70528 *w = watchdog_get_drvdata(wdt);
+
+       dev_dbg(w->dev, "WDT stopping...\n");
+       return bd70528_wdt_change(w, 0);
+}
+
+static int bd70528_wdt_set_timeout(struct watchdog_device *wdt,
+                                  unsigned int timeout)
+{
+       unsigned int hours;
+       unsigned int minutes;
+       unsigned int seconds;
+       int ret;
+       struct wdtbd70528 *w = watchdog_get_drvdata(wdt);
+
+       seconds = timeout;
+       hours = timeout / (60 * 60);
+       /* Maximum timeout is 1h 59m 59s => hours is 1 or 0 */
+       if (hours)
+               seconds -= (60 * 60);
+       minutes = seconds / 60;
+       seconds = seconds % 60;
+
+       bd70528_wdt_lock(w->mfd);
+
+       ret = bd70528_wdt_set_locked(w, 0);
+       if (ret)
+               goto out_unlock;
+
+       ret = regmap_update_bits(w->regmap, BD70528_REG_WDT_HOUR,
+                                BD70528_MASK_WDT_HOUR, hours);
+       if (ret) {
+               dev_err(w->dev, "Failed to set WDT hours\n");
+               goto out_en_unlock;
+       }
+       ret = regmap_update_bits(w->regmap, BD70528_REG_WDT_MINUTE,
+                                BD70528_MASK_WDT_MINUTE, bin2bcd(minutes));
+       if (ret) {
+               dev_err(w->dev, "Failed to set WDT minutes\n");
+               goto out_en_unlock;
+       }
+       ret = regmap_update_bits(w->regmap, BD70528_REG_WDT_SEC,
+                                BD70528_MASK_WDT_SEC, bin2bcd(seconds));
+       if (ret)
+               dev_err(w->dev, "Failed to set WDT seconds\n");
+       else
+               dev_dbg(w->dev, "WDT tmo set to %u\n", timeout);
+
+out_en_unlock:
+       ret = bd70528_wdt_set_locked(w, 1);
+out_unlock:
+       bd70528_wdt_unlock(w->mfd);
+
+       return ret;
+}
+
+static const struct watchdog_info bd70528_wdt_info = {
+       .identity = "bd70528-wdt",
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+};
+
+static const struct watchdog_ops bd70528_wdt_ops = {
+       .start          = bd70528_wdt_start,
+       .stop           = bd70528_wdt_stop,
+       .set_timeout    = bd70528_wdt_set_timeout,
+};
+
+static int bd70528_wdt_probe(struct platform_device *pdev)
+{
+       struct rohm_regmap_dev *bd70528;
+       struct wdtbd70528 *w;
+       int ret;
+       unsigned int reg;
+
+       bd70528 = dev_get_drvdata(pdev->dev.parent);
+       if (!bd70528) {
+               dev_err(&pdev->dev, "No MFD driver data\n");
+               return -EINVAL;
+       }
+       w = devm_kzalloc(&pdev->dev, sizeof(*w), GFP_KERNEL);
+       if (!w)
+               return -ENOMEM;
+
+       w->regmap = bd70528->regmap;
+       w->mfd = bd70528;
+       w->dev = &pdev->dev;
+
+       w->wdt.info = &bd70528_wdt_info;
+       w->wdt.ops =  &bd70528_wdt_ops;
+       w->wdt.min_hw_heartbeat_ms = WDT_MIN_MS;
+       w->wdt.max_hw_heartbeat_ms = WDT_MAX_MS;
+       w->wdt.parent = pdev->dev.parent;
+       w->wdt.timeout = DEFAULT_TIMEOUT;
+       watchdog_set_drvdata(&w->wdt, w);
+       watchdog_init_timeout(&w->wdt, 0, pdev->dev.parent);
+
+       ret = bd70528_wdt_set_timeout(&w->wdt, w->wdt.timeout);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to set the watchdog timeout\n");
+               return ret;
+       }
+
+       bd70528_wdt_lock(w->mfd);
+       ret = regmap_read(w->regmap, BD70528_REG_WDT_CTRL, &reg);
+       bd70528_wdt_unlock(w->mfd);
+
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to get the watchdog state\n");
+               return ret;
+       }
+       if (reg & BD70528_MASK_WDT_EN) {
+               dev_dbg(&pdev->dev, "watchdog was running during probe\n");
+               set_bit(WDOG_HW_RUNNING, &w->wdt.status);
+       }
+
+       ret = devm_watchdog_register_device(&pdev->dev, &w->wdt);
+       if (ret < 0)
+               dev_err(&pdev->dev, "watchdog registration failed: %d\n", ret);
+
+       return ret;
+}
+
+static struct platform_driver bd70528_wdt = {
+       .driver = {
+               .name = "bd70528-wdt"
+       },
+       .probe = bd70528_wdt_probe,
+};
+
+module_platform_driver(bd70528_wdt);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("BD70528 watchdog driver");
+MODULE_LICENSE("GPL");
index c3924356d1731153847b82147b58f70f76a5a382..a22f2d431a3556906e4b2719a65bbde72e955668 100644 (file)
@@ -274,6 +274,11 @@ static const struct watchdog_ops cdns_wdt_ops = {
        .set_timeout = cdns_wdt_settimeout,
 };
 
+static void cdns_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 /************************Platform Operations*****************************/
 /**
  * cdns_wdt_probe - Probe call for the device.
@@ -285,13 +290,13 @@ static const struct watchdog_ops cdns_wdt_ops = {
  */
 static int cdns_wdt_probe(struct platform_device *pdev)
 {
-       struct resource *res;
+       struct device *dev = &pdev->dev;
        int ret, irq;
        unsigned long clock_f;
        struct cdns_wdt *wdt;
        struct watchdog_device *cdns_wdt_device;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
@@ -302,19 +307,18 @@ static int cdns_wdt_probe(struct platform_device *pdev)
        cdns_wdt_device->min_timeout = CDNS_WDT_MIN_TIMEOUT;
        cdns_wdt_device->max_timeout = CDNS_WDT_MAX_TIMEOUT;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->regs = devm_ioremap_resource(&pdev->dev, res);
+       wdt->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->regs))
                return PTR_ERR(wdt->regs);
 
        /* Register the interrupt */
-       wdt->rst = of_property_read_bool(pdev->dev.of_node, "reset-on-timeout");
+       wdt->rst = of_property_read_bool(dev->of_node, "reset-on-timeout");
        irq = platform_get_irq(pdev, 0);
        if (!wdt->rst && irq >= 0) {
-               ret = devm_request_irq(&pdev->dev, irq, cdns_wdt_irq_handler, 0,
+               ret = devm_request_irq(dev, irq, cdns_wdt_irq_handler, 0,
                                       pdev->name, pdev);
                if (ret) {
-                       dev_err(&pdev->dev,
+                       dev_err(dev,
                                "cannot register interrupt handler err=%d\n",
                                ret);
                        return ret;
@@ -322,30 +326,28 @@ static int cdns_wdt_probe(struct platform_device *pdev)
        }
 
        /* Initialize the members of cdns_wdt structure */
-       cdns_wdt_device->parent = &pdev->dev;
-
-       ret = watchdog_init_timeout(cdns_wdt_device, wdt_timeout, &pdev->dev);
-       if (ret) {
-               dev_err(&pdev->dev, "unable to set timeout value\n");
-               return ret;
-       }
+       cdns_wdt_device->parent = dev;
 
+       watchdog_init_timeout(cdns_wdt_device, wdt_timeout, dev);
        watchdog_set_nowayout(cdns_wdt_device, nowayout);
        watchdog_stop_on_reboot(cdns_wdt_device);
        watchdog_set_drvdata(cdns_wdt_device, wdt);
 
-       wdt->clk = devm_clk_get(&pdev->dev, NULL);
+       wdt->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(wdt->clk)) {
-               dev_err(&pdev->dev, "input clock not found\n");
-               ret = PTR_ERR(wdt->clk);
-               return ret;
+               dev_err(dev, "input clock not found\n");
+               return PTR_ERR(wdt->clk);
        }
 
        ret = clk_prepare_enable(wdt->clk);
        if (ret) {
-               dev_err(&pdev->dev, "unable to enable clock\n");
+               dev_err(dev, "unable to enable clock\n");
                return ret;
        }
+       ret = devm_add_action_or_reset(dev, cdns_clk_disable_unprepare,
+                                      wdt->clk);
+       if (ret)
+               return ret;
 
        clock_f = clk_get_rate(wdt->clk);
        if (clock_f <= CDNS_WDT_CLK_75MHZ) {
@@ -358,56 +360,20 @@ static int cdns_wdt_probe(struct platform_device *pdev)
 
        spin_lock_init(&wdt->io_lock);
 
-       ret = watchdog_register_device(cdns_wdt_device);
+       watchdog_stop_on_reboot(cdns_wdt_device);
+       watchdog_stop_on_unregister(cdns_wdt_device);
+       ret = devm_watchdog_register_device(dev, cdns_wdt_device);
        if (ret) {
-               dev_err(&pdev->dev, "Failed to register wdt device\n");
-               goto err_clk_disable;
+               dev_err(dev, "Failed to register wdt device\n");
+               return ret;
        }
        platform_set_drvdata(pdev, wdt);
 
-       dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds%s\n",
+       dev_info(dev, "Xilinx Watchdog Timer at %p with timeout %ds%s\n",
                 wdt->regs, cdns_wdt_device->timeout,
                 nowayout ? ", nowayout" : "");
 
        return 0;
-
-err_clk_disable:
-       clk_disable_unprepare(wdt->clk);
-
-       return ret;
-}
-
-/**
- * cdns_wdt_remove - Probe call for the device.
- *
- * @pdev: handle to the platform device structure.
- * Return: 0 on success, otherwise negative error.
- *
- * Unregister the device after releasing the resources.
- */
-static int cdns_wdt_remove(struct platform_device *pdev)
-{
-       struct cdns_wdt *wdt = platform_get_drvdata(pdev);
-
-       cdns_wdt_stop(&wdt->cdns_wdt_device);
-       watchdog_unregister_device(&wdt->cdns_wdt_device);
-       clk_disable_unprepare(wdt->clk);
-
-       return 0;
-}
-
-/**
- * cdns_wdt_shutdown - Stop the device.
- *
- * @pdev: handle to the platform structure.
- *
- */
-static void cdns_wdt_shutdown(struct platform_device *pdev)
-{
-       struct cdns_wdt *wdt = platform_get_drvdata(pdev);
-
-       cdns_wdt_stop(&wdt->cdns_wdt_device);
-       clk_disable_unprepare(wdt->clk);
 }
 
 /**
@@ -462,8 +428,6 @@ MODULE_DEVICE_TABLE(of, cdns_wdt_of_match);
 /* Driver Structure */
 static struct platform_driver cdns_wdt_driver = {
        .probe          = cdns_wdt_probe,
-       .remove         = cdns_wdt_remove,
-       .shutdown       = cdns_wdt_shutdown,
        .driver         = {
                .name   = "cdns-wdt",
                .of_match_table = cdns_wdt_of_match,
index f29d1edc5badef49f74950330b587d55eba40473..260c50b08483f86e6f987574d5e8e3b79c314bb5 100644 (file)
@@ -6,7 +6,7 @@
  * Watchdog driver for the ST-Ericsson AB COH 901 327 IP core
  * Author: Linus Walleij <linus.walleij@stericsson.com>
  */
-#include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/mod_devicetable.h>
 #include <linux/types.h>
 #include <linux/watchdog.h>
@@ -243,27 +243,15 @@ static struct watchdog_device coh901327_wdt = {
        .timeout = U300_WDOG_DEFAULT_TIMEOUT,
 };
 
-static int __exit coh901327_remove(struct platform_device *pdev)
-{
-       watchdog_unregister_device(&coh901327_wdt);
-       coh901327_disable();
-       free_irq(irq, pdev);
-       clk_disable_unprepare(clk);
-       clk_put(clk);
-       return 0;
-}
-
 static int __init coh901327_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        int ret;
        u16 val;
-       struct resource *res;
 
        parent = dev;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       virtbase = devm_ioremap_resource(dev, res);
+       virtbase = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(virtbase))
                return PTR_ERR(virtbase);
 
@@ -408,19 +396,13 @@ static struct platform_driver coh901327_driver = {
        .driver = {
                .name   = "coh901327_wdog",
                .of_match_table = coh901327_dt_match,
+               .suppress_bind_attrs = true,
        },
-       .remove         = __exit_p(coh901327_remove),
        .suspend        = coh901327_suspend,
        .resume         = coh901327_resume,
 };
+builtin_platform_driver_probe(coh901327_driver, coh901327_probe);
 
-module_platform_driver_probe(coh901327_driver, coh901327_probe);
-
-MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
-MODULE_DESCRIPTION("COH 901 327 Watchdog");
-
+/* not really modular, but ... */
 module_param(margin, uint, 0);
 MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
-
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:coh901327-watchdog");
index e263bad99574a2c627736a0a14634c5f8aaa1628..a2feef1ff30763d8b6992e5d6b778d2ad9ce098b 100644 (file)
@@ -150,13 +150,13 @@ static const struct watchdog_ops da9052_wdt_ops = {
 
 static int da9052_wdt_probe(struct platform_device *pdev)
 {
-       struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent);
+       struct device *dev = &pdev->dev;
+       struct da9052 *da9052 = dev_get_drvdata(dev->parent);
        struct da9052_wdt_data *driver_data;
        struct watchdog_device *da9052_wdt;
        int ret;
 
-       driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
-                                  GFP_KERNEL);
+       driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);
        if (!driver_data)
                return -ENOMEM;
        driver_data->da9052 = da9052;
@@ -166,18 +166,17 @@ static int da9052_wdt_probe(struct platform_device *pdev)
        da9052_wdt->timeout = DA9052_DEF_TIMEOUT;
        da9052_wdt->info = &da9052_wdt_info;
        da9052_wdt->ops = &da9052_wdt_ops;
-       da9052_wdt->parent = &pdev->dev;
+       da9052_wdt->parent = dev;
        watchdog_set_drvdata(da9052_wdt, driver_data);
 
        ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG,
                                DA9052_CONTROLD_TWDSCALE, 0);
        if (ret < 0) {
-               dev_err(&pdev->dev, "Failed to disable watchdog bits, %d\n",
-                       ret);
+               dev_err(dev, "Failed to disable watchdog bits, %d\n", ret);
                return ret;
        }
 
-       ret = devm_watchdog_register_device(&pdev->dev, &driver_data->wdt);
+       ret = devm_watchdog_register_device(dev, &driver_data->wdt);
        if (ret != 0) {
                dev_err(da9052->dev, "watchdog_register_device() failed: %d\n",
                        ret);
index 26a5b2984094da437cb768140b7d1330e7a134d6..389a4bdd208ce69b9f6053a4d7ecd592a1b3ee7a 100644 (file)
@@ -119,13 +119,13 @@ static const struct watchdog_ops da9055_wdt_ops = {
 
 static int da9055_wdt_probe(struct platform_device *pdev)
 {
-       struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent);
+       struct device *dev = &pdev->dev;
+       struct da9055 *da9055 = dev_get_drvdata(dev->parent);
        struct da9055_wdt_data *driver_data;
        struct watchdog_device *da9055_wdt;
        int ret;
 
-       driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
-                                  GFP_KERNEL);
+       driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);
        if (!driver_data)
                return -ENOMEM;
 
@@ -136,17 +136,17 @@ static int da9055_wdt_probe(struct platform_device *pdev)
        da9055_wdt->timeout = DA9055_DEF_TIMEOUT;
        da9055_wdt->info = &da9055_wdt_info;
        da9055_wdt->ops = &da9055_wdt_ops;
-       da9055_wdt->parent = &pdev->dev;
+       da9055_wdt->parent = dev;
        watchdog_set_nowayout(da9055_wdt, nowayout);
        watchdog_set_drvdata(da9055_wdt, driver_data);
 
        ret = da9055_wdt_stop(da9055_wdt);
        if (ret < 0) {
-               dev_err(&pdev->dev, "Failed to stop watchdog, %d\n", ret);
+               dev_err(dev, "Failed to stop watchdog, %d\n", ret);
                return ret;
        }
 
-       ret = devm_watchdog_register_device(&pdev->dev, &driver_data->wdt);
+       ret = devm_watchdog_register_device(dev, &driver_data->wdt);
        if (ret != 0)
                dev_err(da9055->dev, "watchdog_register_device() failed: %d\n",
                        ret);
index fe169d8e1fb2f2c75b4dca8d8af6e83dd462123b..aac749cfaccbbf3bf4dba71445e03e8a2067da92 100644 (file)
@@ -46,14 +46,9 @@ static unsigned int da9062_wdt_timeout_to_sel(unsigned int secs)
 
 static int da9062_reset_watchdog_timer(struct da9062_watchdog *wdt)
 {
-       int ret;
-
-       ret = regmap_update_bits(wdt->hw->regmap,
-                          DA9062AA_CONTROL_F,
-                          DA9062AA_WATCHDOG_MASK,
-                          DA9062AA_WATCHDOG_MASK);
-
-       return ret;
+       return regmap_update_bits(wdt->hw->regmap, DA9062AA_CONTROL_F,
+                                 DA9062AA_WATCHDOG_MASK,
+                                 DA9062AA_WATCHDOG_MASK);
 }
 
 static int da9062_wdt_update_timeout_register(struct da9062_watchdog *wdt,
@@ -190,15 +185,16 @@ MODULE_DEVICE_TABLE(of, da9062_compatible_id_table);
 
 static int da9062_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        int ret;
        struct da9062 *chip;
        struct da9062_watchdog *wdt;
 
-       chip = dev_get_drvdata(pdev->dev.parent);
+       chip = dev_get_drvdata(dev->parent);
        if (!chip)
                return -EINVAL;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
@@ -211,13 +207,13 @@ static int da9062_wdt_probe(struct platform_device *pdev)
        wdt->wdtdev.min_hw_heartbeat_ms = DA9062_RESET_PROTECTION_MS;
        wdt->wdtdev.timeout = DA9062_WDG_DEFAULT_TIMEOUT;
        wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS;
-       wdt->wdtdev.parent = &pdev->dev;
+       wdt->wdtdev.parent = dev;
 
        watchdog_set_restart_priority(&wdt->wdtdev, 128);
 
        watchdog_set_drvdata(&wdt->wdtdev, wdt);
 
-       ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev);
+       ret = devm_watchdog_register_device(dev, &wdt->wdtdev);
        if (ret < 0) {
                dev_err(wdt->hw->dev,
                        "watchdog registration failed (%d)\n", ret);
index 384dca16af8b36bf2e51f8ed6bfeb5ca82e30e06..3d65e92a4e3fea7dc612904cbf927957f5b5c116 100644 (file)
@@ -188,17 +188,18 @@ static const struct watchdog_ops da9063_watchdog_ops = {
 
 static int da9063_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct da9063 *da9063;
        struct watchdog_device *wdd;
 
-       if (!pdev->dev.parent)
+       if (!dev->parent)
                return -EINVAL;
 
-       da9063 = dev_get_drvdata(pdev->dev.parent);
+       da9063 = dev_get_drvdata(dev->parent);
        if (!da9063)
                return -EINVAL;
 
-       wdd = devm_kzalloc(&pdev->dev, sizeof(*wdd), GFP_KERNEL);
+       wdd = devm_kzalloc(dev, sizeof(*wdd), GFP_KERNEL);
        if (!wdd)
                return -ENOMEM;
 
@@ -207,22 +208,24 @@ static int da9063_wdt_probe(struct platform_device *pdev)
        wdd->min_timeout = DA9063_WDT_MIN_TIMEOUT;
        wdd->max_timeout = DA9063_WDT_MAX_TIMEOUT;
        wdd->min_hw_heartbeat_ms = DA9063_RESET_PROTECTION_MS;
-       wdd->timeout = DA9063_WDG_TIMEOUT;
-       wdd->parent = &pdev->dev;
-
+       wdd->parent = dev;
        wdd->status = WATCHDOG_NOWAYOUT_INIT_STATUS;
 
        watchdog_set_restart_priority(wdd, 128);
-
        watchdog_set_drvdata(wdd, da9063);
 
+       /* Set default timeout, maybe override it with DT value, scale it */
+       wdd->timeout = DA9063_WDG_TIMEOUT;
+       watchdog_init_timeout(wdd, 0, dev);
+       da9063_wdt_set_timeout(wdd, wdd->timeout);
+
        /* Change the timeout to the default value if the watchdog is running */
        if (da9063_wdt_is_running(da9063)) {
-               da9063_wdt_update_timeout(da9063, DA9063_WDG_TIMEOUT);
+               da9063_wdt_update_timeout(da9063, wdd->timeout);
                set_bit(WDOG_HW_RUNNING, &wdd->status);
        }
 
-       return devm_watchdog_register_device(&pdev->dev, wdd);
+       return devm_watchdog_register_device(dev, wdd);
 }
 
 static struct platform_driver da9063_wdt_driver = {
index ebb85d60b6d5b8b77f62081eb0b7352167960b48..7b2ee35b5ffd32d73be6d0f4a8b633d711be9fda 100644 (file)
@@ -191,11 +191,15 @@ static const struct watchdog_ops davinci_wdt_ops = {
        .restart        = davinci_wdt_restart,
 };
 
+static void davinci_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int davinci_wdt_probe(struct platform_device *pdev)
 {
        int ret = 0;
        struct device *dev = &pdev->dev;
-       struct resource  *wdt_mem;
        struct watchdog_device *wdd;
        struct davinci_wdt_device *davinci_wdt;
 
@@ -207,15 +211,19 @@ static int davinci_wdt_probe(struct platform_device *pdev)
 
        if (IS_ERR(davinci_wdt->clk)) {
                if (PTR_ERR(davinci_wdt->clk) != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "failed to get clock node\n");
+                       dev_err(dev, "failed to get clock node\n");
                return PTR_ERR(davinci_wdt->clk);
        }
 
        ret = clk_prepare_enable(davinci_wdt->clk);
        if (ret) {
-               dev_err(&pdev->dev, "failed to prepare clock\n");
+               dev_err(dev, "failed to prepare clock\n");
                return ret;
        }
+       ret = devm_add_action_or_reset(dev, davinci_clk_disable_unprepare,
+                                      davinci_wdt->clk);
+       if (ret)
+               return ret;
 
        platform_set_drvdata(pdev, davinci_wdt);
 
@@ -225,7 +233,7 @@ static int davinci_wdt_probe(struct platform_device *pdev)
        wdd->min_timeout        = 1;
        wdd->max_timeout        = MAX_HEARTBEAT;
        wdd->timeout            = DEFAULT_HEARTBEAT;
-       wdd->parent             = &pdev->dev;
+       wdd->parent             = dev;
 
        watchdog_init_timeout(wdd, heartbeat, dev);
 
@@ -235,34 +243,16 @@ static int davinci_wdt_probe(struct platform_device *pdev)
        watchdog_set_nowayout(wdd, 1);
        watchdog_set_restart_priority(wdd, 128);
 
-       wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       davinci_wdt->base = devm_ioremap_resource(dev, wdt_mem);
-       if (IS_ERR(davinci_wdt->base)) {
-               ret = PTR_ERR(davinci_wdt->base);
-               goto err_clk_disable;
-       }
+       davinci_wdt->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(davinci_wdt->base))
+               return PTR_ERR(davinci_wdt->base);
 
-       ret = watchdog_register_device(wdd);
+       ret = devm_watchdog_register_device(dev, wdd);
        if (ret) {
                dev_err(dev, "cannot register watchdog device\n");
-               goto err_clk_disable;
+               return ret;
        }
 
-       return 0;
-
-err_clk_disable:
-       clk_disable_unprepare(davinci_wdt->clk);
-
-       return ret;
-}
-
-static int davinci_wdt_remove(struct platform_device *pdev)
-{
-       struct davinci_wdt_device *davinci_wdt = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&davinci_wdt->wdd);
-       clk_disable_unprepare(davinci_wdt->clk);
-
        return 0;
 }
 
@@ -278,7 +268,6 @@ static struct platform_driver platform_wdt_driver = {
                .of_match_table = davinci_wdt_of_match,
        },
        .probe = davinci_wdt_probe,
-       .remove = davinci_wdt_remove,
 };
 
 module_platform_driver(platform_wdt_driver);
index a9e11df155b8e44e5aac99fd02db4fb5e7d21038..8af6e9a67d0defefe8fc49fe6d2ed68b3c92115e 100644 (file)
@@ -116,7 +116,6 @@ static struct watchdog_device dc_wdt_wdd = {
 
 static int dc_wdt_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        struct device *dev = &pdev->dev;
        struct dc_wdt *wdt;
        int ret;
@@ -125,8 +124,7 @@ static int dc_wdt_probe(struct platform_device *pdev)
        if (!wdt)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->base = devm_ioremap_resource(dev, res);
+       wdt->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->base))
                return PTR_ERR(wdt->base);
 
index aa95f57cc1c316c64b3325259bcf12efcf3f1743..39e43750ab08da9a3c100930fc39f62f863066c3 100644 (file)
@@ -238,15 +238,13 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct watchdog_device *wdd;
        struct dw_wdt *dw_wdt;
-       struct resource *mem;
        int ret;
 
        dw_wdt = devm_kzalloc(dev, sizeof(*dw_wdt), GFP_KERNEL);
        if (!dw_wdt)
                return -ENOMEM;
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dw_wdt->regs = devm_ioremap_resource(dev, mem);
+       dw_wdt->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(dw_wdt->regs))
                return PTR_ERR(dw_wdt->regs);
 
index 4c4c8ce780212ad189c593c3804d2ef95bf95ca8..c176f59fea28fdecc4a899f4fe284b2da73a3b2d 100644 (file)
@@ -117,10 +117,7 @@ static int ebc_c384_wdt_probe(struct device *dev, unsigned int id)
        wdd->max_timeout = WATCHDOG_MAX_TIMEOUT;
 
        watchdog_set_nowayout(wdd, nowayout);
-
-       if (watchdog_init_timeout(wdd, timeout, dev))
-               dev_warn(dev, "Invalid timeout (%u seconds), using default (%u seconds)\n",
-                       timeout, WATCHDOG_TIMEOUT);
+       watchdog_init_timeout(wdd, timeout, dev);
 
        return devm_watchdog_register_device(dev, wdd);
 }
index f9b14e6efd9ac226f56ca232812e61276266e090..38e26f160b9a57fb7a86d787f87452b5b3bbe64d 100644 (file)
@@ -89,18 +89,17 @@ static const struct watchdog_ops ep93xx_wdt_ops = {
 
 static int ep93xx_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct ep93xx_wdt_priv *priv;
        struct watchdog_device *wdd;
-       struct resource *res;
        unsigned long val;
        int ret;
 
-       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->mmio = devm_ioremap_resource(&pdev->dev, res);
+       priv->mmio = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->mmio))
                return PTR_ERR(priv->mmio);
 
@@ -112,21 +111,21 @@ static int ep93xx_wdt_probe(struct platform_device *pdev)
        wdd->ops = &ep93xx_wdt_ops;
        wdd->min_timeout = 1;
        wdd->max_hw_heartbeat_ms = 200;
-       wdd->parent = &pdev->dev;
+       wdd->parent = dev;
 
        watchdog_set_nowayout(wdd, nowayout);
 
        wdd->timeout = WDT_TIMEOUT;
-       watchdog_init_timeout(wdd, timeout, &pdev->dev);
+       watchdog_init_timeout(wdd, timeout, dev);
 
        watchdog_set_drvdata(wdd, priv);
 
-       ret = devm_watchdog_register_device(&pdev->dev, wdd);
+       ret = devm_watchdog_register_device(dev, wdd);
        if (ret)
                return ret;
 
-       dev_info(&pdev->dev, "EP93XX watchdog driver %s\n",
-               (val & 0x08) ? " (nCS1 disable detected)" : "");
+       dev_info(dev, "EP93XX watchdog driver %s\n",
+                (val & 0x08) ? " (nCS1 disable detected)" : "");
 
        return 0;
 }
index 021c6ace9462744aba25ddd8f77dea6b3d16fb7d..041172e6c4697de83df9bb636d966a1452a9f6f5 100644 (file)
@@ -338,8 +338,11 @@ static int f71862fg_pin_configure(unsigned short ioaddr)
 
 static int watchdog_start(void)
 {
+       int err;
+       u8 tmp;
+
        /* Make sure we don't die as soon as the watchdog is enabled below */
-       int err = watchdog_keepalive();
+       err = watchdog_keepalive();
        if (err)
                return err;
 
@@ -386,19 +389,18 @@ static int watchdog_start(void)
                break;
 
        case f81866:
-               /* Set pin 70 to WDTRST# */
-               superio_clear_bit(watchdog.sioaddr, SIO_F81866_REG_PORT_SEL,
-                                 BIT(3) | BIT(0));
-               superio_set_bit(watchdog.sioaddr, SIO_F81866_REG_PORT_SEL,
-                               BIT(2));
                /*
                 * GPIO1 Control Register when 27h BIT3:2 = 01 & BIT0 = 0.
                 * The PIN 70(GPIO15/WDTRST) is controlled by 2Ch:
                 *     BIT5: 0 -> WDTRST#
                 *           1 -> GPIO15
                 */
-               superio_clear_bit(watchdog.sioaddr, SIO_F81866_REG_GPIO1,
-                                 BIT(5));
+               tmp = superio_inb(watchdog.sioaddr, SIO_F81866_REG_PORT_SEL);
+               tmp &= ~(BIT(3) | BIT(0));
+               tmp |= BIT(2);
+               superio_outb(watchdog.sioaddr, SIO_F81866_REG_PORT_SEL, tmp);
+
+               superio_clear_bit(watchdog.sioaddr, SIO_F81866_REG_GPIO1, 5);
                break;
 
        default:
index a9c2912ee28029192d1be1e8f525dc6adb250b1a..9ea0e56fa7eefb86fa7f1d3d54a6d0682a100281 100644 (file)
@@ -124,7 +124,6 @@ static const struct watchdog_info ftwdt010_wdt_info = {
 static int ftwdt010_wdt_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct resource *res;
        struct ftwdt010_wdt *gwdt;
        unsigned int reg;
        int irq;
@@ -134,8 +133,7 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)
        if (!gwdt)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       gwdt->base = devm_ioremap_resource(dev, res);
+       gwdt->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(gwdt->base))
                return PTR_ERR(gwdt->base);
 
@@ -171,7 +169,7 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)
 
        ret = devm_watchdog_register_device(dev, &gwdt->wdd);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register watchdog\n");
+               dev_err(dev, "failed to register watchdog\n");
                return ret;
        }
 
index ea77cae03c9d858047ec7175bb95cc2d12d40182..bc24674b4d9e1a5dd079640431d977472f7a8226 100644 (file)
@@ -154,25 +154,14 @@ static int gpio_wdt_probe(struct platform_device *pdev)
        priv->wdd.parent        = dev;
        priv->wdd.timeout       = SOFT_TIMEOUT_DEF;
 
-       watchdog_init_timeout(&priv->wdd, 0, &pdev->dev);
+       watchdog_init_timeout(&priv->wdd, 0, dev);
 
        watchdog_stop_on_reboot(&priv->wdd);
 
        if (priv->always_running)
                gpio_wdt_start(&priv->wdd);
 
-       ret = watchdog_register_device(&priv->wdd);
-
-       return ret;
-}
-
-static int gpio_wdt_remove(struct platform_device *pdev)
-{
-       struct gpio_wdt_priv *priv = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&priv->wdd);
-
-       return 0;
+       return devm_watchdog_register_device(dev, &priv->wdd);
 }
 
 static const struct of_device_id gpio_wdt_dt_ids[] = {
@@ -187,7 +176,6 @@ static struct platform_driver gpio_wdt_driver = {
                .of_match_table = gpio_wdt_dt_ids,
        },
        .probe  = gpio_wdt_probe,
-       .remove = gpio_wdt_remove,
 };
 
 #ifdef CONFIG_GPIO_WATCHDOG_ARCH_INITCALL
index ef30c7e9728de5e4aee04477debc6bf00559a752..db1bf6f546aec70988d6614644c51b750b862efc 100644 (file)
@@ -311,8 +311,7 @@ static int hpwdt_init_one(struct pci_dev *dev,
                goto error_init_nmi_decoding;
 
        watchdog_set_nowayout(&hpwdt_dev, nowayout);
-       if (watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL))
-               dev_warn(&dev->dev, "Invalid soft_margin: %d.\n", soft_margin);
+       watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL);
 
        if (pretimeout && hpwdt_dev.timeout <= PRETIMEOUT_SEC) {
                dev_warn(&dev->dev, "timeout <= pretimeout. Setting pretimeout to zero\n");
index 950c71a8bb22fdfe5d6902df618ab5de6f8e8c1e..17941c03996b65bc0eb518f418f12a4c6933d5a8 100644 (file)
@@ -311,10 +311,7 @@ static int esb_probe(struct pci_dev *pdev,
        edev->wdd.min_timeout = ESB_HEARTBEAT_MIN;
        edev->wdd.max_timeout = ESB_HEARTBEAT_MAX;
        edev->wdd.timeout = ESB_HEARTBEAT_DEFAULT;
-       if (watchdog_init_timeout(&edev->wdd, heartbeat, NULL))
-               dev_info(&pdev->dev,
-                       "heartbeat value must be " ESB_HEARTBEAT_RANGE
-                       ", using %u\n", edev->wdd.timeout);
+       watchdog_init_timeout(&edev->wdd, heartbeat, NULL);
        watchdog_set_nowayout(&edev->wdd, nowayout);
        watchdog_stop_on_reboot(&edev->wdd);
        watchdog_stop_on_unregister(&edev->wdd);
@@ -328,8 +325,8 @@ static int esb_probe(struct pci_dev *pdev,
                goto err_unmap;
        }
        dev_info(&pdev->dev,
-               "initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
-               edev->base, edev->wdd.timeout, nowayout);
+               "initialized. heartbeat=%d sec (nowayout=%d)\n",
+               edev->wdd.timeout, nowayout);
        return 0;
 
 err_unmap:
index 0a5318b7865e35660f47f78ce73864846f0de55d..89cea6ce9a08f2eabc9c4a31ec26e57fc075eae0 100644 (file)
@@ -545,6 +545,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
        }
 
        watchdog_stop_on_reboot(&p->wddev);
+       watchdog_stop_on_unregister(&p->wddev);
        ret = devm_watchdog_register_device(dev, &p->wddev);
        if (ret != 0) {
                pr_err("cannot register watchdog device (err=%d)\n", ret);
@@ -557,17 +558,6 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int iTCO_wdt_remove(struct platform_device *pdev)
-{
-       struct iTCO_wdt_private *p = platform_get_drvdata(pdev);
-
-       /* Stop the timer before we leave */
-       if (!nowayout)
-               iTCO_wdt_stop(&p->wddev);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 /*
  * Suspend-to-idle requires this, because it stops the ticks and timekeeping, so
@@ -620,7 +610,6 @@ static const struct dev_pm_ops iTCO_wdt_pm = {
 
 static struct platform_driver iTCO_wdt_driver = {
        .probe          = iTCO_wdt_probe,
-       .remove         = iTCO_wdt_remove,
        .driver         = {
                .name   = DRV_NAME,
                .pm     = ITCO_WDT_PM_OPS,
index a3134ffa59f8db0c89f13b6aa477b4df52d7ec1e..0fc31aadeee3bc611c6cade425fa0dc497e6092c 100644 (file)
@@ -178,59 +178,69 @@ static const struct watchdog_ops pdc_wdt_ops = {
        .restart        = pdc_wdt_restart,
 };
 
+static void pdc_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int pdc_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        u64 div;
        int ret, val;
        unsigned long clk_rate;
-       struct resource *res;
        struct pdc_wdt_dev *pdc_wdt;
 
-       pdc_wdt = devm_kzalloc(&pdev->dev, sizeof(*pdc_wdt), GFP_KERNEL);
+       pdc_wdt = devm_kzalloc(dev, sizeof(*pdc_wdt), GFP_KERNEL);
        if (!pdc_wdt)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       pdc_wdt->base = devm_ioremap_resource(&pdev->dev, res);
+       pdc_wdt->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(pdc_wdt->base))
                return PTR_ERR(pdc_wdt->base);
 
-       pdc_wdt->sys_clk = devm_clk_get(&pdev->dev, "sys");
+       pdc_wdt->sys_clk = devm_clk_get(dev, "sys");
        if (IS_ERR(pdc_wdt->sys_clk)) {
-               dev_err(&pdev->dev, "failed to get the sys clock\n");
+               dev_err(dev, "failed to get the sys clock\n");
                return PTR_ERR(pdc_wdt->sys_clk);
        }
 
-       pdc_wdt->wdt_clk = devm_clk_get(&pdev->dev, "wdt");
+       pdc_wdt->wdt_clk = devm_clk_get(dev, "wdt");
        if (IS_ERR(pdc_wdt->wdt_clk)) {
-               dev_err(&pdev->dev, "failed to get the wdt clock\n");
+               dev_err(dev, "failed to get the wdt clock\n");
                return PTR_ERR(pdc_wdt->wdt_clk);
        }
 
        ret = clk_prepare_enable(pdc_wdt->sys_clk);
        if (ret) {
-               dev_err(&pdev->dev, "could not prepare or enable sys clock\n");
+               dev_err(dev, "could not prepare or enable sys clock\n");
                return ret;
        }
+       ret = devm_add_action_or_reset(dev, pdc_clk_disable_unprepare,
+                                      pdc_wdt->sys_clk);
+       if (ret)
+               return ret;
 
        ret = clk_prepare_enable(pdc_wdt->wdt_clk);
        if (ret) {
-               dev_err(&pdev->dev, "could not prepare or enable wdt clock\n");
-               goto disable_sys_clk;
+               dev_err(dev, "could not prepare or enable wdt clock\n");
+               return ret;
        }
+       ret = devm_add_action_or_reset(dev, pdc_clk_disable_unprepare,
+                                      pdc_wdt->wdt_clk);
+       if (ret)
+               return ret;
 
        /* We use the clock rate to calculate the max timeout */
        clk_rate = clk_get_rate(pdc_wdt->wdt_clk);
        if (clk_rate == 0) {
-               dev_err(&pdev->dev, "failed to get clock rate\n");
-               ret = -EINVAL;
-               goto disable_wdt_clk;
+               dev_err(dev, "failed to get clock rate\n");
+               return -EINVAL;
        }
 
        if (order_base_2(clk_rate) > PDC_WDT_CONFIG_DELAY_MASK + 1) {
-               dev_err(&pdev->dev, "invalid clock rate\n");
-               ret = -EINVAL;
-               goto disable_wdt_clk;
+               dev_err(dev, "invalid clock rate\n");
+               return -EINVAL;
        }
 
        if (order_base_2(clk_rate) == 0)
@@ -245,10 +255,10 @@ static int pdc_wdt_probe(struct platform_device *pdev)
        do_div(div, clk_rate);
        pdc_wdt->wdt_dev.max_timeout = div;
        pdc_wdt->wdt_dev.timeout = PDC_WDT_DEF_TIMEOUT;
-       pdc_wdt->wdt_dev.parent = &pdev->dev;
+       pdc_wdt->wdt_dev.parent = dev;
        watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt);
 
-       watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, &pdev->dev);
+       watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, dev);
 
        pdc_wdt_stop(&pdc_wdt->wdt_dev);
 
@@ -259,24 +269,22 @@ static int pdc_wdt_probe(struct platform_device *pdev)
        case PDC_WDT_TICKLE_STATUS_TICKLE:
        case PDC_WDT_TICKLE_STATUS_TIMEOUT:
                pdc_wdt->wdt_dev.bootstatus |= WDIOF_CARDRESET;
-               dev_info(&pdev->dev,
-                        "watchdog module last reset due to timeout\n");
+               dev_info(dev, "watchdog module last reset due to timeout\n");
                break;
        case PDC_WDT_TICKLE_STATUS_HRESET:
-               dev_info(&pdev->dev,
+               dev_info(dev,
                         "watchdog module last reset due to hard reset\n");
                break;
        case PDC_WDT_TICKLE_STATUS_SRESET:
-               dev_info(&pdev->dev,
+               dev_info(dev,
                         "watchdog module last reset due to soft reset\n");
                break;
        case PDC_WDT_TICKLE_STATUS_USER:
-               dev_info(&pdev->dev,
+               dev_info(dev,
                         "watchdog module last reset due to user reset\n");
                break;
        default:
-               dev_info(&pdev->dev,
-                        "contains an illegal status code (%08x)\n", val);
+               dev_info(dev, "contains an illegal status code (%08x)\n", val);
                break;
        }
 
@@ -285,36 +293,9 @@ static int pdc_wdt_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, pdc_wdt);
 
-       ret = watchdog_register_device(&pdc_wdt->wdt_dev);
-       if (ret)
-               goto disable_wdt_clk;
-
-       return 0;
-
-disable_wdt_clk:
-       clk_disable_unprepare(pdc_wdt->wdt_clk);
-disable_sys_clk:
-       clk_disable_unprepare(pdc_wdt->sys_clk);
-       return ret;
-}
-
-static void pdc_wdt_shutdown(struct platform_device *pdev)
-{
-       struct pdc_wdt_dev *pdc_wdt = platform_get_drvdata(pdev);
-
-       pdc_wdt_stop(&pdc_wdt->wdt_dev);
-}
-
-static int pdc_wdt_remove(struct platform_device *pdev)
-{
-       struct pdc_wdt_dev *pdc_wdt = platform_get_drvdata(pdev);
-
-       pdc_wdt_stop(&pdc_wdt->wdt_dev);
-       watchdog_unregister_device(&pdc_wdt->wdt_dev);
-       clk_disable_unprepare(pdc_wdt->wdt_clk);
-       clk_disable_unprepare(pdc_wdt->sys_clk);
-
-       return 0;
+       watchdog_stop_on_reboot(&pdc_wdt->wdt_dev);
+       watchdog_stop_on_unregister(&pdc_wdt->wdt_dev);
+       return devm_watchdog_register_device(dev, &pdc_wdt->wdt_dev);
 }
 
 static const struct of_device_id pdc_wdt_match[] = {
@@ -329,8 +310,6 @@ static struct platform_driver pdc_wdt_driver = {
                .of_match_table = pdc_wdt_match,
        },
        .probe = pdc_wdt_probe,
-       .remove = pdc_wdt_remove,
-       .shutdown = pdc_wdt_shutdown,
 };
 module_platform_driver(pdc_wdt_driver);
 
index 2b52514eaa86a84ed837634edc8027ed31663bf7..a606005dd65f17290185704141b9795972d78429 100644 (file)
@@ -178,8 +178,10 @@ static void __imx2_wdt_set_timeout(struct watchdog_device *wdog,
 static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
                                unsigned int new_timeout)
 {
-       __imx2_wdt_set_timeout(wdog, new_timeout);
+       unsigned int actual;
 
+       actual = min(new_timeout, wdog->max_hw_heartbeat_ms * 1000);
+       __imx2_wdt_set_timeout(wdog, actual);
        wdog->timeout = new_timeout;
        return 0;
 }
@@ -247,7 +249,6 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
 {
        struct imx2_wdt_device *wdev;
        struct watchdog_device *wdog;
-       struct resource *res;
        void __iomem *base;
        int ret;
        u32 val;
@@ -256,8 +257,7 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
        if (!wdev)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(&pdev->dev, res);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
diff --git a/drivers/watchdog/imx_sc_wdt.c b/drivers/watchdog/imx_sc_wdt.c
new file mode 100644 (file)
index 0000000..49848b6
--- /dev/null
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018-2019 NXP.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/watchdog.h>
+
+#define DEFAULT_TIMEOUT 60
+/*
+ * Software timer tick implemented in scfw side, support 10ms to 0xffffffff ms
+ * in theory, but for normal case, 1s~128s is enough, you can change this max
+ * value in case it's not enough.
+ */
+#define MAX_TIMEOUT 128
+
+#define IMX_SIP_TIMER                  0xC2000002
+#define IMX_SIP_TIMER_START_WDOG               0x01
+#define IMX_SIP_TIMER_STOP_WDOG                0x02
+#define IMX_SIP_TIMER_SET_WDOG_ACT     0x03
+#define IMX_SIP_TIMER_PING_WDOG                0x04
+#define IMX_SIP_TIMER_SET_TIMEOUT_WDOG 0x05
+#define IMX_SIP_TIMER_GET_WDOG_STAT    0x06
+#define IMX_SIP_TIMER_SET_PRETIME_WDOG 0x07
+
+#define SC_TIMER_WDOG_ACTION_PARTITION 0
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0000);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int imx_sc_wdt_ping(struct watchdog_device *wdog)
+{
+       struct arm_smccc_res res;
+
+       arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_PING_WDOG,
+                     0, 0, 0, 0, 0, 0, &res);
+
+       return 0;
+}
+
+static int imx_sc_wdt_start(struct watchdog_device *wdog)
+{
+       struct arm_smccc_res res;
+
+       arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_START_WDOG,
+                     0, 0, 0, 0, 0, 0, &res);
+       if (res.a0)
+               return -EACCES;
+
+       arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_SET_WDOG_ACT,
+                     SC_TIMER_WDOG_ACTION_PARTITION,
+                     0, 0, 0, 0, 0, &res);
+       return res.a0 ? -EACCES : 0;
+}
+
+static int imx_sc_wdt_stop(struct watchdog_device *wdog)
+{
+       struct arm_smccc_res res;
+
+       arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_STOP_WDOG,
+                     0, 0, 0, 0, 0, 0, &res);
+
+       return res.a0 ? -EACCES : 0;
+}
+
+static int imx_sc_wdt_set_timeout(struct watchdog_device *wdog,
+                               unsigned int timeout)
+{
+       struct arm_smccc_res res;
+
+       wdog->timeout = timeout;
+       arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_SET_TIMEOUT_WDOG,
+                     timeout * 1000, 0, 0, 0, 0, 0, &res);
+
+       return res.a0 ? -EACCES : 0;
+}
+
+static const struct watchdog_ops imx_sc_wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = imx_sc_wdt_start,
+       .stop  = imx_sc_wdt_stop,
+       .ping  = imx_sc_wdt_ping,
+       .set_timeout = imx_sc_wdt_set_timeout,
+};
+
+static const struct watchdog_info imx_sc_wdt_info = {
+       .identity       = "i.MX SC watchdog timer",
+       .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
+                         WDIOF_MAGICCLOSE | WDIOF_PRETIMEOUT,
+};
+
+static int imx_sc_wdt_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct watchdog_device *imx_sc_wdd;
+       int ret;
+
+       imx_sc_wdd = devm_kzalloc(dev, sizeof(*imx_sc_wdd), GFP_KERNEL);
+       if (!imx_sc_wdd)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, imx_sc_wdd);
+
+       imx_sc_wdd->info = &imx_sc_wdt_info;
+       imx_sc_wdd->ops = &imx_sc_wdt_ops;
+       imx_sc_wdd->min_timeout = 1;
+       imx_sc_wdd->max_timeout = MAX_TIMEOUT;
+       imx_sc_wdd->parent = dev;
+       imx_sc_wdd->timeout = DEFAULT_TIMEOUT;
+
+       watchdog_init_timeout(imx_sc_wdd, 0, dev);
+       watchdog_stop_on_reboot(imx_sc_wdd);
+       watchdog_stop_on_unregister(imx_sc_wdd);
+
+       ret = devm_watchdog_register_device(dev, imx_sc_wdd);
+       if (ret) {
+               dev_err(dev, "Failed to register watchdog device\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __maybe_unused imx_sc_wdt_suspend(struct device *dev)
+{
+       struct watchdog_device *imx_sc_wdd = dev_get_drvdata(dev);
+
+       if (watchdog_active(imx_sc_wdd))
+               imx_sc_wdt_stop(imx_sc_wdd);
+
+       return 0;
+}
+
+static int __maybe_unused imx_sc_wdt_resume(struct device *dev)
+{
+       struct watchdog_device *imx_sc_wdd = dev_get_drvdata(dev);
+
+       if (watchdog_active(imx_sc_wdd))
+               imx_sc_wdt_start(imx_sc_wdd);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(imx_sc_wdt_pm_ops,
+                        imx_sc_wdt_suspend, imx_sc_wdt_resume);
+
+static const struct of_device_id imx_sc_wdt_dt_ids[] = {
+       { .compatible = "fsl,imx-sc-wdt", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_sc_wdt_dt_ids);
+
+static struct platform_driver imx_sc_wdt_driver = {
+       .probe          = imx_sc_wdt_probe,
+       .driver         = {
+               .name   = "imx-sc-wdt",
+               .of_match_table = imx_sc_wdt_dt_ids,
+               .pm     = &imx_sc_wdt_pm_ops,
+       },
+};
+module_platform_driver(imx_sc_wdt_driver);
+
+MODULE_AUTHOR("Robin Gong <yibin.gong@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX system controller watchdog driver");
+MODULE_LICENSE("GPL v2");
index 72c108a12c19d72d9958c71a62a315b8e3a4668a..6cf7cc1ff615aa22e99068e324b4f04879c41e9c 100644 (file)
@@ -110,12 +110,13 @@ static const struct watchdog_ops mid_wdt_ops = {
 
 static int mid_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct watchdog_device *wdt_dev;
-       struct intel_mid_wdt_pdata *pdata = pdev->dev.platform_data;
+       struct intel_mid_wdt_pdata *pdata = dev->platform_data;
        int ret;
 
        if (!pdata) {
-               dev_err(&pdev->dev, "missing platform data\n");
+               dev_err(dev, "missing platform data\n");
                return -EINVAL;
        }
 
@@ -125,7 +126,7 @@ static int mid_wdt_probe(struct platform_device *pdev)
                        return ret;
        }
 
-       wdt_dev = devm_kzalloc(&pdev->dev, sizeof(*wdt_dev), GFP_KERNEL);
+       wdt_dev = devm_kzalloc(dev, sizeof(*wdt_dev), GFP_KERNEL);
        if (!wdt_dev)
                return -ENOMEM;
 
@@ -134,16 +135,15 @@ static int mid_wdt_probe(struct platform_device *pdev)
        wdt_dev->min_timeout = MID_WDT_TIMEOUT_MIN;
        wdt_dev->max_timeout = MID_WDT_TIMEOUT_MAX;
        wdt_dev->timeout = MID_WDT_DEFAULT_TIMEOUT;
-       wdt_dev->parent = &pdev->dev;
+       wdt_dev->parent = dev;
 
-       watchdog_set_drvdata(wdt_dev, &pdev->dev);
+       watchdog_set_drvdata(wdt_dev, dev);
 
-       ret = devm_request_irq(&pdev->dev, pdata->irq, mid_wdt_irq,
+       ret = devm_request_irq(dev, pdata->irq, mid_wdt_irq,
                               IRQF_SHARED | IRQF_NO_SUSPEND, "watchdog",
                               wdt_dev);
        if (ret) {
-               dev_err(&pdev->dev, "error requesting warning irq %d\n",
-                       pdata->irq);
+               dev_err(dev, "error requesting warning irq %d\n", pdata->irq);
                return ret;
        }
 
@@ -163,13 +163,13 @@ static int mid_wdt_probe(struct platform_device *pdev)
        /* Make sure the watchdog is serviced */
        set_bit(WDOG_HW_RUNNING, &wdt_dev->status);
 
-       ret = devm_watchdog_register_device(&pdev->dev, wdt_dev);
+       ret = devm_watchdog_register_device(dev, wdt_dev);
        if (ret) {
-               dev_err(&pdev->dev, "error registering watchdog device\n");
+               dev_err(dev, "error registering watchdog device\n");
                return ret;
        }
 
-       dev_info(&pdev->dev, "Intel MID watchdog device probed\n");
+       dev_info(dev, "Intel MID watchdog device probed\n");
 
        return 0;
 }
index 3181a72c7ddf3f736a05ae0fb0507f7a7bb1b7f9..f7baf75d38c0ebfd3fb7546612aa838f1848b037 100644 (file)
@@ -25,7 +25,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/compiler.h>
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -224,7 +223,7 @@ static int intel_scu_set_heartbeat(u32 t)
                 watchdog_device.timer_tbl_ptr->freq_hz);
        pr_debug("set_heartbeat: timer_set is %x (hex)\n",
                 watchdog_device.timer_set);
-       pr_debug("set_hearbeat: timer_margin is %x (hex)\n", timer_margin);
+       pr_debug("set_heartbeat: timer_margin is %x (hex)\n", timer_margin);
        pr_debug("set_heartbeat: threshold is %x (hex)\n",
                 watchdog_device.threshold);
        pr_debug("set_heartbeat: soft_threshold is %x (hex)\n",
@@ -545,21 +544,4 @@ register_reboot_error:
        iounmap(watchdog_device.timer_load_count_addr);
        return ret;
 }
-
-static void __exit intel_scu_watchdog_exit(void)
-{
-
-       misc_deregister(&watchdog_device.miscdev);
-       unregister_reboot_notifier(&watchdog_device.intel_scu_notifier);
-       /* disable the timer */
-       iowrite32(0x00000002, watchdog_device.timer_control_addr);
-       iounmap(watchdog_device.timer_load_count_addr);
-}
-
 late_initcall(intel_scu_watchdog_init);
-module_exit(intel_scu_watchdog_exit);
-
-MODULE_AUTHOR("Intel Corporation");
-MODULE_DESCRIPTION("Intel SCU Watchdog Device Driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(WDT_VER);
index dd139cda936c58e10328634c55edecc6c9d83fab..9067998759e36214dbd8beb8f8eefe231b69deb5 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
+#include <linux/of.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
@@ -176,6 +177,14 @@ static int __init ixp4xx_wdt_init(void)
 {
        int ret;
 
+       /*
+        * FIXME: we bail out on device tree boot but this really needs
+        * to be fixed in a nicer way: this registers the MDIO bus before
+        * even matching the driver infrastructure, we should only probe
+        * detected hardware.
+        */
+       if (of_have_populated_dt())
+               return -ENODEV;
        if (!(read_cpuid_id() & 0xf) && !cpu_is_ixp46x()) {
                pr_err("Rev. A0 IXP42x CPU detected - watchdog disabled\n");
 
index ec4d99a830ba61b53c3963afba9fddf749de70af..d1bc7cbd4f2b1a53d73cb2dc4b5b0f36ea7ee64f 100644 (file)
@@ -163,12 +163,12 @@ MODULE_DEVICE_TABLE(of, jz4740_wdt_of_matches);
 
 static int jz4740_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct jz4740_wdt_drvdata *drvdata;
        struct watchdog_device *jz4740_wdt;
-       struct resource *res;
        int ret;
 
-       drvdata = devm_kzalloc(&pdev->dev, sizeof(struct jz4740_wdt_drvdata),
+       drvdata = devm_kzalloc(dev, sizeof(struct jz4740_wdt_drvdata),
                               GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
@@ -182,27 +182,24 @@ static int jz4740_wdt_probe(struct platform_device *pdev)
        jz4740_wdt->timeout = heartbeat;
        jz4740_wdt->min_timeout = 1;
        jz4740_wdt->max_timeout = MAX_HEARTBEAT;
-       jz4740_wdt->parent = &pdev->dev;
+       jz4740_wdt->parent = dev;
        watchdog_set_nowayout(jz4740_wdt, nowayout);
        watchdog_set_drvdata(jz4740_wdt, drvdata);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       drvdata->base = devm_ioremap_resource(&pdev->dev, res);
+       drvdata->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(drvdata->base))
                return PTR_ERR(drvdata->base);
 
-       drvdata->rtc_clk = devm_clk_get(&pdev->dev, "rtc");
+       drvdata->rtc_clk = devm_clk_get(dev, "rtc");
        if (IS_ERR(drvdata->rtc_clk)) {
-               dev_err(&pdev->dev, "cannot find RTC clock\n");
+               dev_err(dev, "cannot find RTC clock\n");
                return PTR_ERR(drvdata->rtc_clk);
        }
 
-       ret = devm_watchdog_register_device(&pdev->dev, &drvdata->wdt);
+       ret = devm_watchdog_register_device(dev, &drvdata->wdt);
        if (ret < 0)
                return ret;
 
-       platform_set_drvdata(pdev, drvdata);
-
        return 0;
 }
 
index e268add430104bb1d02a4024d0d5b51c0299f0ab..543eb0f27a4238f0f4daef15e2d5c16113e6b727 100644 (file)
@@ -467,7 +467,7 @@ static int kempld_wdt_probe(struct platform_device *pdev)
                        KEMPLD_WDT_CFG_GLOBAL_LOCK)) {
                if (!nowayout)
                        dev_warn(dev,
-                               "Forcing nowayout - watchdog lock enabled!\n");
+                                "Forcing nowayout - watchdog lock enabled!\n");
                nowayout = true;
        }
 
@@ -492,7 +492,9 @@ static int kempld_wdt_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, wdt_data);
-       ret = watchdog_register_device(wdd);
+       watchdog_stop_on_reboot(wdd);
+       watchdog_stop_on_unregister(wdd);
+       ret = devm_watchdog_register_device(dev, wdd);
        if (ret)
                return ret;
 
@@ -501,26 +503,6 @@ static int kempld_wdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-static void kempld_wdt_shutdown(struct platform_device *pdev)
-{
-       struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
-
-       kempld_wdt_stop(&wdt_data->wdd);
-}
-
-static int kempld_wdt_remove(struct platform_device *pdev)
-{
-       struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
-       struct watchdog_device *wdd = &wdt_data->wdd;
-       int ret = 0;
-
-       if (!nowayout)
-               ret = kempld_wdt_stop(wdd);
-       watchdog_unregister_device(wdd);
-
-       return ret;
-}
-
 #ifdef CONFIG_PM
 /* Disable watchdog if it is active during suspend */
 static int kempld_wdt_suspend(struct platform_device *pdev,
@@ -567,8 +549,6 @@ static struct platform_driver kempld_wdt_driver = {
                .name   = "kempld-wdt",
        },
        .probe          = kempld_wdt_probe,
-       .remove         = kempld_wdt_remove,
-       .shutdown       = kempld_wdt_shutdown,
        .suspend        = kempld_wdt_suspend,
        .resume         = kempld_wdt_resume,
 };
index 83da84d6074b80ee5ff9d56c6a1106b17c106302..4caf02ba5d49b8b72482e29425395aa705886763 100644 (file)
@@ -203,7 +203,6 @@ static int ltq_wdt_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct ltq_wdt_priv *priv;
        struct watchdog_device *wdt;
-       struct resource *res;
        struct clk *clk;
        const struct ltq_wdt_hw *ltq_wdt_hw;
        int ret;
@@ -213,8 +212,7 @@ static int ltq_wdt_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->membase = devm_ioremap_resource(dev, res);
+       priv->membase = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->membase))
                return PTR_ERR(priv->membase);
 
index 3aee50c64a3660c7070a2fd047ff219c7cef3719..d8075e2affa77d78a61d142833bab6d61d3666ec 100644 (file)
@@ -83,38 +83,44 @@ static const struct watchdog_ops ls1x_wdt_ops = {
        .set_timeout = ls1x_wdt_set_timeout,
 };
 
+static void ls1x_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int ls1x_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct ls1x_wdt_drvdata *drvdata;
        struct watchdog_device *ls1x_wdt;
        unsigned long clk_rate;
-       struct resource *res;
        int err;
 
-       drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+       drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       drvdata->base = devm_ioremap_resource(&pdev->dev, res);
+       drvdata->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(drvdata->base))
                return PTR_ERR(drvdata->base);
 
-       drvdata->clk = devm_clk_get(&pdev->dev, pdev->name);
+       drvdata->clk = devm_clk_get(dev, pdev->name);
        if (IS_ERR(drvdata->clk))
                return PTR_ERR(drvdata->clk);
 
        err = clk_prepare_enable(drvdata->clk);
        if (err) {
-               dev_err(&pdev->dev, "clk enable failed\n");
+               dev_err(dev, "clk enable failed\n");
                return err;
        }
+       err = devm_add_action_or_reset(dev, ls1x_clk_disable_unprepare,
+                                      drvdata->clk);
+       if (err)
+               return err;
 
        clk_rate = clk_get_rate(drvdata->clk);
-       if (!clk_rate) {
-               err = -EINVAL;
-               goto err0;
-       }
+       if (!clk_rate)
+               return -EINVAL;
        drvdata->clk_rate = clk_rate;
 
        ls1x_wdt = &drvdata->wdt;
@@ -123,41 +129,27 @@ static int ls1x_wdt_probe(struct platform_device *pdev)
        ls1x_wdt->timeout = DEFAULT_HEARTBEAT;
        ls1x_wdt->min_timeout = 1;
        ls1x_wdt->max_hw_heartbeat_ms = U32_MAX / clk_rate * 1000;
-       ls1x_wdt->parent = &pdev->dev;
+       ls1x_wdt->parent = dev;
 
-       watchdog_init_timeout(ls1x_wdt, heartbeat, &pdev->dev);
+       watchdog_init_timeout(ls1x_wdt, heartbeat, dev);
        watchdog_set_nowayout(ls1x_wdt, nowayout);
        watchdog_set_drvdata(ls1x_wdt, drvdata);
 
-       err = watchdog_register_device(&drvdata->wdt);
+       err = devm_watchdog_register_device(dev, &drvdata->wdt);
        if (err) {
-               dev_err(&pdev->dev, "failed to register watchdog device\n");
-               goto err0;
+               dev_err(dev, "failed to register watchdog device\n");
+               return err;
        }
 
        platform_set_drvdata(pdev, drvdata);
 
-       dev_info(&pdev->dev, "Loongson1 Watchdog driver registered\n");
-
-       return 0;
-err0:
-       clk_disable_unprepare(drvdata->clk);
-       return err;
-}
-
-static int ls1x_wdt_remove(struct platform_device *pdev)
-{
-       struct ls1x_wdt_drvdata *drvdata = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&drvdata->wdt);
-       clk_disable_unprepare(drvdata->clk);
+       dev_info(dev, "Loongson1 Watchdog driver registered\n");
 
        return 0;
 }
 
 static struct platform_driver ls1x_wdt_driver = {
        .probe = ls1x_wdt_probe,
-       .remove = ls1x_wdt_remove,
        .driver = {
                .name = "ls1x-wdt",
        },
index 331cadb459ac5da03c6f4c5fb74d7266c337e446..0e82abd71d35ceee3a49312e0d81cc28c43ceb22 100644 (file)
@@ -200,19 +200,22 @@ static const struct watchdog_ops lpc18xx_wdt_ops = {
        .restart        = lpc18xx_wdt_restart,
 };
 
+static void lpc18xx_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int lpc18xx_wdt_probe(struct platform_device *pdev)
 {
        struct lpc18xx_wdt_dev *lpc18xx_wdt;
        struct device *dev = &pdev->dev;
-       struct resource *res;
        int ret;
 
        lpc18xx_wdt = devm_kzalloc(dev, sizeof(*lpc18xx_wdt), GFP_KERNEL);
        if (!lpc18xx_wdt)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       lpc18xx_wdt->base = devm_ioremap_resource(dev, res);
+       lpc18xx_wdt->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(lpc18xx_wdt->base))
                return PTR_ERR(lpc18xx_wdt->base);
 
@@ -233,19 +236,26 @@ static int lpc18xx_wdt_probe(struct platform_device *pdev)
                dev_err(dev, "could not prepare or enable sys clock\n");
                return ret;
        }
+       ret = devm_add_action_or_reset(dev, lpc18xx_clk_disable_unprepare,
+                                      lpc18xx_wdt->reg_clk);
+       if (ret)
+               return ret;
 
        ret = clk_prepare_enable(lpc18xx_wdt->wdt_clk);
        if (ret) {
                dev_err(dev, "could not prepare or enable wdt clock\n");
-               goto disable_reg_clk;
+               return ret;
        }
+       ret = devm_add_action_or_reset(dev, lpc18xx_clk_disable_unprepare,
+                                      lpc18xx_wdt->wdt_clk);
+       if (ret)
+               return ret;
 
        /* We use the clock rate to calculate timeouts */
        lpc18xx_wdt->clk_rate = clk_get_rate(lpc18xx_wdt->wdt_clk);
        if (lpc18xx_wdt->clk_rate == 0) {
                dev_err(dev, "failed to get clock rate\n");
-               ret = -EINVAL;
-               goto disable_wdt_clk;
+               return -EINVAL;
        }
 
        lpc18xx_wdt->wdt_dev.info = &lpc18xx_wdt_info;
@@ -276,24 +286,8 @@ static int lpc18xx_wdt_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, lpc18xx_wdt);
 
-       ret = watchdog_register_device(&lpc18xx_wdt->wdt_dev);
-       if (ret)
-               goto disable_wdt_clk;
-
-       return 0;
-
-disable_wdt_clk:
-       clk_disable_unprepare(lpc18xx_wdt->wdt_clk);
-disable_reg_clk:
-       clk_disable_unprepare(lpc18xx_wdt->reg_clk);
-       return ret;
-}
-
-static void lpc18xx_wdt_shutdown(struct platform_device *pdev)
-{
-       struct lpc18xx_wdt_dev *lpc18xx_wdt = platform_get_drvdata(pdev);
-
-       lpc18xx_wdt_stop(&lpc18xx_wdt->wdt_dev);
+       watchdog_stop_on_reboot(&lpc18xx_wdt->wdt_dev);
+       return devm_watchdog_register_device(dev, &lpc18xx_wdt->wdt_dev);
 }
 
 static int lpc18xx_wdt_remove(struct platform_device *pdev)
@@ -303,10 +297,6 @@ static int lpc18xx_wdt_remove(struct platform_device *pdev)
        dev_warn(&pdev->dev, "I quit now, hardware will probably reboot!\n");
        del_timer(&lpc18xx_wdt->timer);
 
-       watchdog_unregister_device(&lpc18xx_wdt->wdt_dev);
-       clk_disable_unprepare(lpc18xx_wdt->wdt_clk);
-       clk_disable_unprepare(lpc18xx_wdt->reg_clk);
-
        return 0;
 }
 
@@ -323,7 +313,6 @@ static struct platform_driver lpc18xx_wdt_driver = {
        },
        .probe = lpc18xx_wdt_probe,
        .remove = lpc18xx_wdt_remove,
-       .shutdown = lpc18xx_wdt_shutdown,
 };
 module_platform_driver(lpc18xx_wdt_driver);
 
index 53759415cf06e9890315e0a0a63245a94e9ff93f..c0c9e948adbcd48bd91d7e77110203113796d871 100644 (file)
@@ -177,6 +177,7 @@ static inline void zf_set_timer(unsigned short new, unsigned char n)
        switch (n) {
        case WD1:
                zf_writew(COUNTER_1, new);
+               /* fall through */
        case WD2:
                zf_writeb(COUNTER_2, new > 0xff ? 0xff : new);
        default:
@@ -318,7 +319,7 @@ static long zf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case WDIOC_GETBOOTSTATUS:
                return put_user(0, p);
        case WDIOC_KEEPALIVE:
-               zf_ping(0);
+               zf_ping(NULL);
                break;
        default:
                return -ENOTTY;
index bf6a068245ba0513eae2a93c49ebc888faf2480d..3a899628a83474d503a4c320021dee5af6485161 100644 (file)
@@ -187,9 +187,7 @@ static void max63xx_mmap_set(struct max63xx_wdt *wdt, u8 set)
 
 static int max63xx_mmap_init(struct platform_device *p, struct max63xx_wdt *wdt)
 {
-       struct resource *mem = platform_get_resource(p, IORESOURCE_MEM, 0);
-
-       wdt->base = devm_ioremap_resource(&p->dev, mem);
+       wdt->base = devm_platform_ioremap_resource(p, 0);
        if (IS_ERR(wdt->base))
                return PTR_ERR(wdt->base);
 
@@ -202,11 +200,12 @@ static int max63xx_mmap_init(struct platform_device *p, struct max63xx_wdt *wdt)
 
 static int max63xx_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct max63xx_wdt *wdt;
        struct max63xx_timeout *table;
        int err;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
@@ -217,7 +216,7 @@ static int max63xx_wdt_probe(struct platform_device *pdev)
 
        wdt->timeout = max63xx_select_timeout(table, heartbeat);
        if (!wdt->timeout) {
-               dev_err(&pdev->dev, "unable to satisfy %ds heartbeat request\n",
+               dev_err(dev, "unable to satisfy %ds heartbeat request\n",
                        heartbeat);
                return -EINVAL;
        }
@@ -229,30 +228,22 @@ static int max63xx_wdt_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, &wdt->wdd);
        watchdog_set_drvdata(&wdt->wdd, wdt);
 
-       wdt->wdd.parent = &pdev->dev;
+       wdt->wdd.parent = dev;
        wdt->wdd.timeout = wdt->timeout->twd;
        wdt->wdd.info = &max63xx_wdt_info;
        wdt->wdd.ops = &max63xx_wdt_ops;
 
        watchdog_set_nowayout(&wdt->wdd, nowayout);
 
-       err = watchdog_register_device(&wdt->wdd);
+       err = devm_watchdog_register_device(dev, &wdt->wdd);
        if (err)
                return err;
 
-       dev_info(&pdev->dev, "using %ds heartbeat with %ds initial delay\n",
+       dev_info(dev, "using %ds heartbeat with %ds initial delay\n",
                 wdt->timeout->twd, wdt->timeout->tdelay);
        return 0;
 }
 
-static int max63xx_wdt_remove(struct platform_device *pdev)
-{
-       struct watchdog_device *wdd = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(wdd);
-       return 0;
-}
-
 static const struct platform_device_id max63xx_id_table[] = {
        { "max6369_wdt", (kernel_ulong_t)max6369_table, },
        { "max6370_wdt", (kernel_ulong_t)max6369_table, },
@@ -266,7 +257,6 @@ MODULE_DEVICE_TABLE(platform, max63xx_id_table);
 
 static struct platform_driver max63xx_wdt_driver = {
        .probe          = max63xx_wdt_probe,
-       .remove         = max63xx_wdt_remove,
        .id_table       = max63xx_id_table,
        .driver         = {
                .name   = "max63xx_wdt",
index 70c9cd3ba9389de044fcb094ca9729355ce9cc56..3ca6b9337932e2a85b984a18571ad073b415c964 100644 (file)
@@ -112,17 +112,18 @@ static const struct watchdog_ops max77620_wdt_ops = {
 
 static int max77620_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct max77620_wdt *wdt;
        struct watchdog_device *wdt_dev;
        unsigned int regval;
        int ret;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
-       wdt->dev = &pdev->dev;
-       wdt->rmap = dev_get_regmap(pdev->dev.parent, NULL);
+       wdt->dev = dev;
+       wdt->rmap = dev_get_regmap(dev->parent, NULL);
        if (!wdt->rmap) {
                dev_err(wdt->dev, "Failed to get parent regmap\n");
                return -ENODEV;
@@ -183,25 +184,16 @@ static int max77620_wdt_probe(struct platform_device *pdev)
        watchdog_set_nowayout(wdt_dev, nowayout);
        watchdog_set_drvdata(wdt_dev, wdt);
 
-       ret = watchdog_register_device(wdt_dev);
+       watchdog_stop_on_unregister(wdt_dev);
+       ret = devm_watchdog_register_device(dev, wdt_dev);
        if (ret < 0) {
-               dev_err(&pdev->dev, "watchdog registration failed: %d\n", ret);
+               dev_err(dev, "watchdog registration failed: %d\n", ret);
                return ret;
        }
 
        return 0;
 }
 
-static int max77620_wdt_remove(struct platform_device *pdev)
-{
-       struct max77620_wdt *wdt = platform_get_drvdata(pdev);
-
-       max77620_wdt_stop(&wdt->wdt_dev);
-       watchdog_unregister_device(&wdt->wdt_dev);
-
-       return 0;
-}
-
 static const struct platform_device_id max77620_wdt_devtype[] = {
        { .name = "max77620-watchdog", },
        { },
@@ -213,7 +205,6 @@ static struct platform_driver max77620_wdt_driver = {
                .name   = "max77620-watchdog",
        },
        .probe  = max77620_wdt_probe,
-       .remove = max77620_wdt_remove,
        .id_table = max77620_wdt_devtype,
 };
 
index 6db69883ece69540839ec6da3ec5a88939019df8..e9ca4e0e25dc02babc50bb2818346cb9bc9d096a 100644 (file)
@@ -127,19 +127,20 @@ static struct watchdog_device a21_wdt = {
 
 static int a21_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct a21_wdt_drv *drv;
        unsigned int reset = 0;
        int num_gpios;
        int ret;
        int i;
 
-       drv = devm_kzalloc(&pdev->dev, sizeof(struct a21_wdt_drv), GFP_KERNEL);
+       drv = devm_kzalloc(dev, sizeof(struct a21_wdt_drv), GFP_KERNEL);
        if (!drv)
                return -ENOMEM;
 
-       num_gpios = gpiod_count(&pdev->dev, NULL);
+       num_gpios = gpiod_count(dev, NULL);
        if (num_gpios != NUM_GPIOS) {
-               dev_err(&pdev->dev, "gpios DT property wrong, got %d want %d",
+               dev_err(dev, "gpios DT property wrong, got %d want %d",
                        num_gpios, NUM_GPIOS);
                return -ENODEV;
        }
@@ -152,12 +153,9 @@ static int a21_wdt_probe(struct platform_device *pdev)
                        gflags = GPIOD_ASIS;
                else
                        gflags = GPIOD_IN;
-               drv->gpios[i] = devm_gpiod_get_index(&pdev->dev, NULL, i,
-                                                    gflags);
-               if (IS_ERR(drv->gpios[i])) {
-                       ret = PTR_ERR(drv->gpios[i]);
-                       return ret;
-               }
+               drv->gpios[i] = devm_gpiod_get_index(dev, NULL, i, gflags);
+               if (IS_ERR(drv->gpios[i]))
+                       return PTR_ERR(drv->gpios[i]);
 
                gpiod_set_consumer_name(drv->gpios[i], "MEN A21 Watchdog");
 
@@ -173,10 +171,10 @@ static int a21_wdt_probe(struct platform_device *pdev)
                }
        }
 
-       watchdog_init_timeout(&a21_wdt, 30, &pdev->dev);
+       watchdog_init_timeout(&a21_wdt, 30, dev);
        watchdog_set_nowayout(&a21_wdt, nowayout);
        watchdog_set_drvdata(&a21_wdt, drv);
-       a21_wdt.parent = &pdev->dev;
+       a21_wdt.parent = dev;
 
        reset = a21_wdt_get_bootstatus(drv);
        if (reset == 2)
@@ -189,15 +187,15 @@ static int a21_wdt_probe(struct platform_device *pdev)
                a21_wdt.bootstatus |= WDIOF_EXTERN2;
 
        drv->wdt = a21_wdt;
-       dev_set_drvdata(&pdev->dev, drv);
+       dev_set_drvdata(dev, drv);
 
-       ret = devm_watchdog_register_device(&pdev->dev, &a21_wdt);
+       ret = devm_watchdog_register_device(dev, &a21_wdt);
        if (ret) {
-               dev_err(&pdev->dev, "Cannot register watchdog device\n");
+               dev_err(dev, "Cannot register watchdog device\n");
                return ret;
        }
 
-       dev_info(&pdev->dev, "MEN A21 watchdog timer driver enabled\n");
+       dev_info(dev, "MEN A21 watchdog timer driver enabled\n");
 
        return 0;
 }
index 3aefddebb386184456ef009182e35a267d0cca34..b1dbff553cdc7a3838b18e6bde1514800c7e205a 100644 (file)
@@ -117,12 +117,12 @@ static const struct watchdog_ops menf21bmc_wdt_ops = {
 
 static int menf21bmc_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        int ret, bmc_timeout;
        struct menf21bmc_wdt *drv_data;
-       struct i2c_client *i2c_client = to_i2c_client(pdev->dev.parent);
+       struct i2c_client *i2c_client = to_i2c_client(dev->parent);
 
-       drv_data = devm_kzalloc(&pdev->dev,
-                               sizeof(struct menf21bmc_wdt), GFP_KERNEL);
+       drv_data = devm_kzalloc(dev, sizeof(struct menf21bmc_wdt), GFP_KERNEL);
        if (!drv_data)
                return -ENOMEM;
 
@@ -130,7 +130,7 @@ static int menf21bmc_wdt_probe(struct platform_device *pdev)
        drv_data->wdt.info = &menf21bmc_wdt_info;
        drv_data->wdt.min_timeout = BMC_WD_TIMEOUT_MIN;
        drv_data->wdt.max_timeout = BMC_WD_TIMEOUT_MAX;
-       drv_data->wdt.parent = &pdev->dev;
+       drv_data->wdt.parent = dev;
        drv_data->i2c_client = i2c_client;
 
        /*
@@ -140,40 +140,28 @@ static int menf21bmc_wdt_probe(struct platform_device *pdev)
        bmc_timeout = i2c_smbus_read_word_data(drv_data->i2c_client,
                                               BMC_CMD_WD_TIME);
        if (bmc_timeout < 0) {
-               dev_err(&pdev->dev, "failed to get current WDT timeout\n");
+               dev_err(dev, "failed to get current WDT timeout\n");
                return bmc_timeout;
        }
 
-       watchdog_init_timeout(&drv_data->wdt, bmc_timeout / 10, &pdev->dev);
+       watchdog_init_timeout(&drv_data->wdt, bmc_timeout / 10, dev);
        watchdog_set_nowayout(&drv_data->wdt, nowayout);
        watchdog_set_drvdata(&drv_data->wdt, drv_data);
        platform_set_drvdata(pdev, drv_data);
 
        ret = menf21bmc_wdt_set_bootstatus(drv_data);
        if (ret < 0) {
-               dev_err(&pdev->dev, "failed to set Watchdog bootstatus\n");
+               dev_err(dev, "failed to set Watchdog bootstatus\n");
                return ret;
        }
 
-       ret = watchdog_register_device(&drv_data->wdt);
+       ret = devm_watchdog_register_device(dev, &drv_data->wdt);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register Watchdog device\n");
+               dev_err(dev, "failed to register Watchdog device\n");
                return ret;
        }
 
-       dev_info(&pdev->dev, "MEN 14F021P00 BMC Watchdog device enabled\n");
-
-       return 0;
-}
-
-static int menf21bmc_wdt_remove(struct platform_device *pdev)
-{
-       struct menf21bmc_wdt *drv_data = platform_get_drvdata(pdev);
-
-       dev_warn(&pdev->dev,
-                "Unregister MEN 14F021P00 BMC Watchdog device, board may reset\n");
-
-       watchdog_unregister_device(&drv_data->wdt);
+       dev_info(dev, "MEN 14F021P00 BMC Watchdog device enabled\n");
 
        return 0;
 }
@@ -191,7 +179,6 @@ static struct  platform_driver menf21bmc_wdt = {
                .name   = DEVNAME,
        },
        .probe          = menf21bmc_wdt_probe,
-       .remove         = menf21bmc_wdt_remove,
        .shutdown       = menf21bmc_wdt_shutdown,
 };
 
index 69adeab3fde70fb9c692eca84d06f44da350491a..d17c1a6ed7234c5f0a4581da6ab3f38fc957fe41 100644 (file)
@@ -136,32 +136,40 @@ static const struct of_device_id meson_gxbb_wdt_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, meson_gxbb_wdt_dt_ids);
 
+static void meson_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int meson_gxbb_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct meson_gxbb_wdt *data;
-       struct resource *res;
        int ret;
 
-       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       data->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       data->reg_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(data->reg_base))
                return PTR_ERR(data->reg_base);
 
-       data->clk = devm_clk_get(&pdev->dev, NULL);
+       data->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(data->clk))
                return PTR_ERR(data->clk);
 
        ret = clk_prepare_enable(data->clk);
        if (ret)
                return ret;
+       ret = devm_add_action_or_reset(dev, meson_clk_disable_unprepare,
+                                      data->clk);
+       if (ret)
+               return ret;
 
        platform_set_drvdata(pdev, data);
 
-       data->wdt_dev.parent = &pdev->dev;
+       data->wdt_dev.parent = dev;
        data->wdt_dev.info = &meson_gxbb_wdt_info;
        data->wdt_dev.ops = &meson_gxbb_wdt_ops;
        data->wdt_dev.max_hw_heartbeat_ms = GXBB_WDT_TCNT_SETUP_MASK;
@@ -178,37 +186,12 @@ static int meson_gxbb_wdt_probe(struct platform_device *pdev)
 
        meson_gxbb_wdt_set_timeout(&data->wdt_dev, data->wdt_dev.timeout);
 
-       ret = watchdog_register_device(&data->wdt_dev);
-       if (ret) {
-               clk_disable_unprepare(data->clk);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int meson_gxbb_wdt_remove(struct platform_device *pdev)
-{
-       struct meson_gxbb_wdt *data = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&data->wdt_dev);
-
-       clk_disable_unprepare(data->clk);
-
-       return 0;
-}
-
-static void meson_gxbb_wdt_shutdown(struct platform_device *pdev)
-{
-       struct meson_gxbb_wdt *data = platform_get_drvdata(pdev);
-
-       meson_gxbb_wdt_stop(&data->wdt_dev);
+       watchdog_stop_on_reboot(&data->wdt_dev);
+       return devm_watchdog_register_device(dev, &data->wdt_dev);
 }
 
 static struct platform_driver meson_gxbb_wdt_driver = {
        .probe  = meson_gxbb_wdt_probe,
-       .remove = meson_gxbb_wdt_remove,
-       .shutdown = meson_gxbb_wdt_shutdown,
        .driver = {
                .name = "meson-gxbb-wdt",
                .pm = &meson_gxbb_wdt_pm_ops,
index cd0275a6cdac101e417e8912748e722417433bd8..01889cef81e19477e777a87117ad55ffb46d221d 100644 (file)
@@ -164,28 +164,27 @@ MODULE_DEVICE_TABLE(of, meson_wdt_dt_ids);
 
 static int meson_wdt_probe(struct platform_device *pdev)
 {
-       struct resource *res;
+       struct device *dev = &pdev->dev;
        struct meson_wdt_dev *meson_wdt;
        const struct of_device_id *of_id;
        int err;
 
-       meson_wdt = devm_kzalloc(&pdev->dev, sizeof(*meson_wdt), GFP_KERNEL);
+       meson_wdt = devm_kzalloc(dev, sizeof(*meson_wdt), GFP_KERNEL);
        if (!meson_wdt)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       meson_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res);
+       meson_wdt->wdt_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(meson_wdt->wdt_base))
                return PTR_ERR(meson_wdt->wdt_base);
 
-       of_id = of_match_device(meson_wdt_dt_ids, &pdev->dev);
+       of_id = of_match_device(meson_wdt_dt_ids, dev);
        if (!of_id) {
-               dev_err(&pdev->dev, "Unable to initialize WDT data\n");
+               dev_err(dev, "Unable to initialize WDT data\n");
                return -ENODEV;
        }
        meson_wdt->data = of_id->data;
 
-       meson_wdt->wdt_dev.parent = &pdev->dev;
+       meson_wdt->wdt_dev.parent = dev;
        meson_wdt->wdt_dev.info = &meson_wdt_info;
        meson_wdt->wdt_dev.ops = &meson_wdt_ops;
        meson_wdt->wdt_dev.max_timeout =
@@ -197,18 +196,18 @@ static int meson_wdt_probe(struct platform_device *pdev)
 
        watchdog_set_drvdata(&meson_wdt->wdt_dev, meson_wdt);
 
-       watchdog_init_timeout(&meson_wdt->wdt_dev, timeout, &pdev->dev);
+       watchdog_init_timeout(&meson_wdt->wdt_dev, timeout, dev);
        watchdog_set_nowayout(&meson_wdt->wdt_dev, nowayout);
        watchdog_set_restart_priority(&meson_wdt->wdt_dev, 128);
 
        meson_wdt_stop(&meson_wdt->wdt_dev);
 
        watchdog_stop_on_reboot(&meson_wdt->wdt_dev);
-       err = devm_watchdog_register_device(&pdev->dev, &meson_wdt->wdt_dev);
+       err = devm_watchdog_register_device(dev, &meson_wdt->wdt_dev);
        if (err)
                return err;
 
-       dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)",
+       dev_info(dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)",
                 meson_wdt->wdt_dev.timeout, nowayout);
 
        return 0;
index 70c2cbf9c9933af4137217c490bdde297f2f1238..03b9ac4b99af79d33765e847bc6b810b89b0e6fa 100644 (file)
@@ -233,20 +233,21 @@ static int mlxreg_wdt_init_timeout(struct mlxreg_wdt *wdt,
 
 static int mlxreg_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct mlxreg_core_platform_data *pdata;
        struct mlxreg_wdt *wdt;
        int rc;
 
-       pdata = dev_get_platdata(&pdev->dev);
+       pdata = dev_get_platdata(dev);
        if (!pdata) {
-               dev_err(&pdev->dev, "Failed to get platform data.\n");
+               dev_err(dev, "Failed to get platform data.\n");
                return -EINVAL;
        }
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
-       wdt->wdd.parent = &pdev->dev;
+       wdt->wdd.parent = dev;
        wdt->regmap = pdata->regmap;
        mlxreg_wdt_config(wdt, pdata);
 
@@ -266,12 +267,11 @@ static int mlxreg_wdt_probe(struct platform_device *pdev)
                set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
        }
        mlxreg_wdt_check_card_reset(wdt);
-       rc = devm_watchdog_register_device(&pdev->dev, &wdt->wdd);
+       rc = devm_watchdog_register_device(dev, &wdt->wdd);
 
 register_error:
        if (rc)
-               dev_err(&pdev->dev,
-                       "Cannot register watchdog device (err=%d)\n", rc);
+               dev_err(dev, "Cannot register watchdog device (err=%d)\n", rc);
        return rc;
 }
 
index 430c3ab84c07c49b509c937dc5d9c2c2486ab8a4..6340a1f5f471b21e272bd85a497bbf0674d0eac4 100644 (file)
@@ -91,8 +91,6 @@ static int moxart_wdt_probe(struct platform_device *pdev)
 {
        struct moxart_wdt_dev *moxart_wdt;
        struct device *dev = &pdev->dev;
-       struct device_node *node = dev->of_node;
-       struct resource *res;
        struct clk *clk;
        int err;
        unsigned int max_timeout;
@@ -104,12 +102,11 @@ static int moxart_wdt_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, moxart_wdt);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       moxart_wdt->base = devm_ioremap_resource(dev, res);
+       moxart_wdt->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(moxart_wdt->base))
                return PTR_ERR(moxart_wdt->base);
 
-       clk = of_clk_get(node, 0);
+       clk = devm_clk_get(dev, NULL);
        if (IS_ERR(clk)) {
                pr_err("%s: of_clk_get failed\n", __func__);
                return PTR_ERR(clk);
@@ -136,7 +133,8 @@ static int moxart_wdt_probe(struct platform_device *pdev)
 
        watchdog_set_drvdata(&moxart_wdt->dev, moxart_wdt);
 
-       err = watchdog_register_device(&moxart_wdt->dev);
+       watchdog_stop_on_unregister(&moxart_wdt->dev);
+       err = devm_watchdog_register_device(dev, &moxart_wdt->dev);
        if (err)
                return err;
 
@@ -146,15 +144,6 @@ static int moxart_wdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int moxart_wdt_remove(struct platform_device *pdev)
-{
-       struct moxart_wdt_dev *moxart_wdt = platform_get_drvdata(pdev);
-
-       moxart_wdt_stop(&moxart_wdt->dev);
-
-       return 0;
-}
-
 static const struct of_device_id moxart_watchdog_match[] = {
        { .compatible = "moxa,moxart-watchdog" },
        { },
@@ -163,7 +152,6 @@ MODULE_DEVICE_TABLE(of, moxart_watchdog_match);
 
 static struct platform_driver moxart_wdt_driver = {
        .probe      = moxart_wdt_probe,
-       .remove     = moxart_wdt_remove,
        .driver     = {
                .name           = "moxart-watchdog",
                .of_match_table = moxart_watchdog_match,
index 069072e6747df321876e54c94410f2801bff0c7c..9b6d6a5a27adcd6615e023fcec66c11d35d62f33 100644 (file)
@@ -149,8 +149,7 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
        if (!ddata)
                return -ENOMEM;
 
-       res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
-       ddata->base = devm_ioremap_resource(dev, res);
+       ddata->base = devm_platform_ioremap_resource(ofdev, 0);
        if (IS_ERR(ddata->base))
                return PTR_ERR(ddata->base);
 
@@ -205,9 +204,10 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
        if (ddata->wdd.timeout < ddata->wdd.min_timeout)
                ddata->wdd.timeout = ddata->wdd.min_timeout;
 
-       ret = watchdog_register_device(&ddata->wdd);
+       ret = devm_watchdog_register_device(dev, &ddata->wdd);
        if (ret) {
-               dev_err(dev, "cannot register watchdog device (err=%d)\n", ret);
+               dev_err(dev, "cannot register watchdog device (err=%d)\n",
+                       ret);
                return ret;
        }
 
@@ -219,17 +219,6 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
        return 0;
 }
 
-static int mpc8xxx_wdt_remove(struct platform_device *ofdev)
-{
-       struct mpc8xxx_wdt_ddata *ddata = platform_get_drvdata(ofdev);
-
-       dev_crit(&ofdev->dev, "Watchdog removed, expect the %s soon!\n",
-                reset ? "reset" : "machine check exception");
-       watchdog_unregister_device(&ddata->wdd);
-
-       return 0;
-}
-
 static const struct of_device_id mpc8xxx_wdt_match[] = {
        {
                .compatible = "mpc83xx_wdt",
@@ -260,7 +249,6 @@ MODULE_DEVICE_TABLE(of, mpc8xxx_wdt_match);
 
 static struct platform_driver mpc8xxx_wdt_driver = {
        .probe          = mpc8xxx_wdt_probe,
-       .remove         = mpc8xxx_wdt_remove,
        .driver = {
                .name = "mpc8xxx_wdt",
                .of_match_table = mpc8xxx_wdt_match,
index 81208cd3f4ecba3edc2dc6334b360cdd98a7f935..cbb3c0dde13696a6b9cf445c684bf4d08b9a5796 100644 (file)
@@ -133,21 +133,19 @@ static struct watchdog_device mt7621_wdt_dev = {
 
 static int mt7621_wdt_probe(struct platform_device *pdev)
 {
-       struct resource *res;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mt7621_wdt_base = devm_ioremap_resource(&pdev->dev, res);
+       struct device *dev = &pdev->dev;
+       mt7621_wdt_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(mt7621_wdt_base))
                return PTR_ERR(mt7621_wdt_base);
 
-       mt7621_wdt_reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+       mt7621_wdt_reset = devm_reset_control_get_exclusive(dev, NULL);
        if (!IS_ERR(mt7621_wdt_reset))
                reset_control_deassert(mt7621_wdt_reset);
 
        mt7621_wdt_dev.bootstatus = mt7621_wdt_bootcause();
 
        watchdog_init_timeout(&mt7621_wdt_dev, mt7621_wdt_dev.max_timeout,
-                             &pdev->dev);
+                             dev);
        watchdog_set_nowayout(&mt7621_wdt_dev, nowayout);
        if (mt7621_wdt_is_running(&mt7621_wdt_dev)) {
                /*
@@ -164,7 +162,7 @@ static int mt7621_wdt_probe(struct platform_device *pdev)
                set_bit(WDOG_HW_RUNNING, &mt7621_wdt_dev.status);
        }
 
-       return devm_watchdog_register_device(&pdev->dev, &mt7621_wdt_dev);
+       return devm_watchdog_register_device(dev, &mt7621_wdt_dev);
 }
 
 static void mt7621_wdt_shutdown(struct platform_device *pdev)
index 4baf64f21aa11f23e1b61d01703be9a56463934b..9c3d0033260d9665d5f72fd5f8b25b3cf1475681 100644 (file)
@@ -153,18 +153,17 @@ static const struct watchdog_ops mtk_wdt_ops = {
 
 static int mtk_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct mtk_wdt_dev *mtk_wdt;
-       struct resource *res;
        int err;
 
-       mtk_wdt = devm_kzalloc(&pdev->dev, sizeof(*mtk_wdt), GFP_KERNEL);
+       mtk_wdt = devm_kzalloc(dev, sizeof(*mtk_wdt), GFP_KERNEL);
        if (!mtk_wdt)
                return -ENOMEM;
 
        platform_set_drvdata(pdev, mtk_wdt);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mtk_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res);
+       mtk_wdt->wdt_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(mtk_wdt->wdt_base))
                return PTR_ERR(mtk_wdt->wdt_base);
 
@@ -173,9 +172,9 @@ static int mtk_wdt_probe(struct platform_device *pdev)
        mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT;
        mtk_wdt->wdt_dev.max_timeout = WDT_MAX_TIMEOUT;
        mtk_wdt->wdt_dev.min_timeout = WDT_MIN_TIMEOUT;
-       mtk_wdt->wdt_dev.parent = &pdev->dev;
+       mtk_wdt->wdt_dev.parent = dev;
 
-       watchdog_init_timeout(&mtk_wdt->wdt_dev, timeout, &pdev->dev);
+       watchdog_init_timeout(&mtk_wdt->wdt_dev, timeout, dev);
        watchdog_set_nowayout(&mtk_wdt->wdt_dev, nowayout);
        watchdog_set_restart_priority(&mtk_wdt->wdt_dev, 128);
 
@@ -183,29 +182,13 @@ static int mtk_wdt_probe(struct platform_device *pdev)
 
        mtk_wdt_stop(&mtk_wdt->wdt_dev);
 
-       err = watchdog_register_device(&mtk_wdt->wdt_dev);
+       watchdog_stop_on_reboot(&mtk_wdt->wdt_dev);
+       err = devm_watchdog_register_device(dev, &mtk_wdt->wdt_dev);
        if (unlikely(err))
                return err;
 
-       dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n",
-                       mtk_wdt->wdt_dev.timeout, nowayout);
-
-       return 0;
-}
-
-static void mtk_wdt_shutdown(struct platform_device *pdev)
-{
-       struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev);
-
-       if (watchdog_active(&mtk_wdt->wdt_dev))
-               mtk_wdt_stop(&mtk_wdt->wdt_dev);
-}
-
-static int mtk_wdt_remove(struct platform_device *pdev)
-{
-       struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&mtk_wdt->wdt_dev);
+       dev_info(dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n",
+                mtk_wdt->wdt_dev.timeout, nowayout);
 
        return 0;
 }
@@ -247,8 +230,6 @@ static const struct dev_pm_ops mtk_wdt_pm_ops = {
 
 static struct platform_driver mtk_wdt_driver = {
        .probe          = mtk_wdt_probe,
-       .remove         = mtk_wdt_remove,
-       .shutdown       = mtk_wdt_shutdown,
        .driver         = {
                .name           = DRV_NAME,
                .pm             = &mtk_wdt_pm_ops,
index dc67742e9018306a2ea351e83eb310858b0fbf9a..fbc1df86c6cc6249768e0336b5acb1a862bb831f 100644 (file)
@@ -217,9 +217,7 @@ static int ni903x_acpi_add(struct acpi_device *device)
        wdd->parent = dev;
        watchdog_set_drvdata(wdd, wdt);
        watchdog_set_nowayout(wdd, nowayout);
-       ret = watchdog_init_timeout(wdd, timeout, dev);
-       if (ret)
-               dev_err(dev, "unable to set timeout value, using default\n");
+       watchdog_init_timeout(wdd, timeout, dev);
 
        ret = watchdog_register_device(wdd);
        if (ret) {
index dcd26568583762839390c0c558b7b21deb5ee63f..82843abe38f8b8c598bf07b17d686fa6a74fe9c8 100644 (file)
@@ -211,10 +211,7 @@ static int nic7018_probe(struct platform_device *pdev)
 
        watchdog_set_drvdata(wdd, wdt);
        watchdog_set_nowayout(wdd, nowayout);
-
-       ret = watchdog_init_timeout(wdd, timeout, dev);
-       if (ret)
-               dev_warn(dev, "unable to set timeout value, using default\n");
+       watchdog_init_timeout(wdd, timeout, dev);
 
        /* Unlock WDT register */
        outb(UNLOCK, wdt->io_base + WDT_REG_LOCK);
index 0d4213652ecc917029d65c1c2f8d519374ef0470..9d6c1689b12cc558a0ae085773e98d8e7c2a2f3f 100644 (file)
@@ -181,16 +181,14 @@ static int npcm_wdt_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct npcm_wdt *wdt;
-       struct resource *res;
        int irq;
        int ret;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->reg = devm_ioremap_resource(dev, res);
+       wdt->reg = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->reg))
                return PTR_ERR(wdt->reg);
 
@@ -216,8 +214,8 @@ static int npcm_wdt_probe(struct platform_device *pdev)
                set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
        }
 
-       ret = devm_request_irq(dev, irq, npcm_wdt_interrupt, 0,
-                              "watchdog", wdt);
+       ret = devm_request_irq(dev, irq, npcm_wdt_interrupt, 0, "watchdog",
+                              wdt);
        if (ret)
                return ret;
 
index 8a36350bab7bbdd1ef616162cecf5add2c1986e3..f36eae34e848049401ec29929d0010038e3ff81d 100644 (file)
@@ -242,7 +242,6 @@ static struct miscdevice nuc900wdt_miscdev = {
 
 static int nuc900wdt_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        int ret = 0;
 
        nuc900_wdt = devm_kzalloc(&pdev->dev, sizeof(*nuc900_wdt),
@@ -254,8 +253,7 @@ static int nuc900wdt_probe(struct platform_device *pdev)
 
        spin_lock_init(&nuc900_wdt->wdt_lock);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       nuc900_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res);
+       nuc900_wdt->wdt_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(nuc900_wdt->wdt_base))
                return PTR_ERR(nuc900_wdt->wdt_base);
 
index d3f7eb0466782f4b386895cf509c54213a31819d..03786992b7018e748813bdd806258b4b16973db7 100644 (file)
@@ -151,43 +151,46 @@ static u32 xwdt_selftest(struct xwdt_device *xdev)
                return XWT_TIMER_FAILED;
 }
 
+static void xwdt_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int xwdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        int rc;
        u32 pfreq = 0, enable_once = 0;
-       struct resource *res;
        struct xwdt_device *xdev;
        struct watchdog_device *xilinx_wdt_wdd;
 
-       xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
+       xdev = devm_kzalloc(dev, sizeof(*xdev), GFP_KERNEL);
        if (!xdev)
                return -ENOMEM;
 
        xilinx_wdt_wdd = &xdev->xilinx_wdt_wdd;
        xilinx_wdt_wdd->info = &xilinx_wdt_ident;
        xilinx_wdt_wdd->ops = &xilinx_wdt_ops;
-       xilinx_wdt_wdd->parent = &pdev->dev;
+       xilinx_wdt_wdd->parent = dev;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       xdev->base = devm_ioremap_resource(&pdev->dev, res);
+       xdev->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(xdev->base))
                return PTR_ERR(xdev->base);
 
-       rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-interval",
+       rc = of_property_read_u32(dev->of_node, "xlnx,wdt-interval",
                                  &xdev->wdt_interval);
        if (rc)
-               dev_warn(&pdev->dev,
-                        "Parameter \"xlnx,wdt-interval\" not found\n");
+               dev_warn(dev, "Parameter \"xlnx,wdt-interval\" not found\n");
 
-       rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-enable-once",
+       rc = of_property_read_u32(dev->of_node, "xlnx,wdt-enable-once",
                                  &enable_once);
        if (rc)
-               dev_warn(&pdev->dev,
+               dev_warn(dev,
                         "Parameter \"xlnx,wdt-enable-once\" not found\n");
 
        watchdog_set_nowayout(xilinx_wdt_wdd, enable_once);
 
-       xdev->clk = devm_clk_get(&pdev->dev, NULL);
+       xdev->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(xdev->clk)) {
                if (PTR_ERR(xdev->clk) != -ENOENT)
                        return PTR_ERR(xdev->clk);
@@ -198,10 +201,10 @@ static int xwdt_probe(struct platform_device *pdev)
                 */
                xdev->clk = NULL;
 
-               rc = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+               rc = of_property_read_u32(dev->of_node, "clock-frequency",
                                          &pfreq);
                if (rc)
-                       dev_warn(&pdev->dev,
+                       dev_warn(dev,
                                 "The watchdog clock freq cannot be obtained\n");
        } else {
                pfreq = clk_get_rate(xdev->clk);
@@ -220,43 +223,33 @@ static int xwdt_probe(struct platform_device *pdev)
 
        rc = clk_prepare_enable(xdev->clk);
        if (rc) {
-               dev_err(&pdev->dev, "unable to enable clock\n");
+               dev_err(dev, "unable to enable clock\n");
                return rc;
        }
+       rc = devm_add_action_or_reset(dev, xwdt_clk_disable_unprepare,
+                                     xdev->clk);
+       if (rc)
+               return rc;
 
        rc = xwdt_selftest(xdev);
        if (rc == XWT_TIMER_FAILED) {
-               dev_err(&pdev->dev, "SelfTest routine error\n");
-               goto err_clk_disable;
+               dev_err(dev, "SelfTest routine error\n");
+               return rc;
        }
 
-       rc = watchdog_register_device(xilinx_wdt_wdd);
+       rc = devm_watchdog_register_device(dev, xilinx_wdt_wdd);
        if (rc) {
-               dev_err(&pdev->dev, "Cannot register watchdog (err=%d)\n", rc);
-               goto err_clk_disable;
+               dev_err(dev, "Cannot register watchdog (err=%d)\n", rc);
+               return rc;
        }
 
        clk_disable(xdev->clk);
 
-       dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n",
+       dev_info(dev, "Xilinx Watchdog Timer at %p with timeout %ds\n",
                 xdev->base, xilinx_wdt_wdd->timeout);
 
        platform_set_drvdata(pdev, xdev);
 
-       return 0;
-err_clk_disable:
-       clk_disable_unprepare(xdev->clk);
-
-       return rc;
-}
-
-static int xwdt_remove(struct platform_device *pdev)
-{
-       struct xwdt_device *xdev = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&xdev->xilinx_wdt_wdd);
-       clk_disable_unprepare(xdev->clk);
-
        return 0;
 }
 
@@ -305,7 +298,6 @@ MODULE_DEVICE_TABLE(of, xwdt_of_match);
 
 static struct platform_driver xwdt_driver = {
        .probe       = xwdt_probe,
-       .remove      = xwdt_remove,
        .driver = {
                .name  = WATCHDOG_NAME,
                .of_match_table = xwdt_of_match,
index cbd752f9ac56375e9daf4b76b07704e79ee66a21..d49688d93f6ae156ab3db095f85bdd0261603813 100644 (file)
@@ -231,7 +231,6 @@ static const struct watchdog_ops omap_wdt_ops = {
 static int omap_wdt_probe(struct platform_device *pdev)
 {
        struct omap_wd_timer_platform_data *pdata = dev_get_platdata(&pdev->dev);
-       struct resource *res;
        struct omap_wdt_dev *wdev;
        int ret;
 
@@ -245,8 +244,7 @@ static int omap_wdt_probe(struct platform_device *pdev)
        mutex_init(&wdev->lock);
 
        /* reserve static register mappings */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdev->base = devm_ioremap_resource(&pdev->dev, res);
+       wdev->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdev->base))
                return PTR_ERR(wdev->base);
 
index 9db3b09f7568ef30077471463e53aff03fe062bf..cdb0d174c5e2de3572369f41cef2c1c92d590a40 100644 (file)
@@ -349,13 +349,6 @@ static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
        return readl(dev->reg + dev->data->wdt_counter_offset) / dev->clk_rate;
 }
 
-static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev,
-                                unsigned int timeout)
-{
-       wdt_dev->timeout = timeout;
-       return 0;
-}
-
 static const struct watchdog_info orion_wdt_info = {
        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
        .identity = "Orion Watchdog",
@@ -366,7 +359,6 @@ static const struct watchdog_ops orion_wdt_ops = {
        .start = orion_wdt_start,
        .stop = orion_wdt_stop,
        .ping = orion_wdt_ping,
-       .set_timeout = orion_wdt_set_timeout,
        .get_timeleft = orion_wdt_get_timeleft,
 };
 
@@ -502,8 +494,7 @@ static int orion_wdt_get_regs(struct platform_device *pdev,
                   of_device_is_compatible(node, "marvell,armada-xp-wdt")) {
 
                /* Dedicated RSTOUT register, can be requested. */
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               dev->rstout = devm_ioremap_resource(&pdev->dev, res);
+               dev->rstout = devm_platform_ioremap_resource(pdev, 1);
                if (IS_ERR(dev->rstout))
                        return PTR_ERR(dev->rstout);
 
@@ -511,8 +502,7 @@ static int orion_wdt_get_regs(struct platform_device *pdev,
                   of_device_is_compatible(node, "marvell,armada-380-wdt")) {
 
                /* Dedicated RSTOUT register, can be requested. */
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               dev->rstout = devm_ioremap_resource(&pdev->dev, res);
+               dev->rstout = devm_platform_ioremap_resource(pdev, 1);
                if (IS_ERR(dev->rstout))
                        return PTR_ERR(dev->rstout);
 
index c797305f8338cb4ed61e64fecf71b3698994a36a..9a3c53e03c6089de76a10857f75a6a8fddf198c7 100644 (file)
@@ -168,70 +168,61 @@ static struct watchdog_device pic32_dmt_wdd = {
        .ops            = &pic32_dmt_fops,
 };
 
+static void pic32_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int pic32_dmt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        int ret;
        struct pic32_dmt *dmt;
-       struct resource *mem;
        struct watchdog_device *wdd = &pic32_dmt_wdd;
 
-       dmt = devm_kzalloc(&pdev->dev, sizeof(*dmt), GFP_KERNEL);
+       dmt = devm_kzalloc(dev, sizeof(*dmt), GFP_KERNEL);
        if (!dmt)
                return -ENOMEM;
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dmt->regs = devm_ioremap_resource(&pdev->dev, mem);
+       dmt->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(dmt->regs))
                return PTR_ERR(dmt->regs);
 
-       dmt->clk = devm_clk_get(&pdev->dev, NULL);
+       dmt->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(dmt->clk)) {
-               dev_err(&pdev->dev, "clk not found\n");
+               dev_err(dev, "clk not found\n");
                return PTR_ERR(dmt->clk);
        }
 
        ret = clk_prepare_enable(dmt->clk);
        if (ret)
                return ret;
+       ret = devm_add_action_or_reset(dev, pic32_clk_disable_unprepare,
+                                      dmt->clk);
+       if (ret)
+               return ret;
 
        wdd->timeout = pic32_dmt_get_timeout_secs(dmt);
        if (!wdd->timeout) {
-               dev_err(&pdev->dev,
-                       "failed to read watchdog register timeout\n");
-               ret = -EINVAL;
-               goto out_disable_clk;
+               dev_err(dev, "failed to read watchdog register timeout\n");
+               return -EINVAL;
        }
 
-       dev_info(&pdev->dev, "timeout %d\n", wdd->timeout);
+       dev_info(dev, "timeout %d\n", wdd->timeout);
 
        wdd->bootstatus = pic32_dmt_bootstatus(dmt) ? WDIOF_CARDRESET : 0;
 
        watchdog_set_nowayout(wdd, WATCHDOG_NOWAYOUT);
        watchdog_set_drvdata(wdd, dmt);
 
-       ret = watchdog_register_device(wdd);
+       ret = devm_watchdog_register_device(dev, wdd);
        if (ret) {
-               dev_err(&pdev->dev, "watchdog register failed, err %d\n", ret);
-               goto out_disable_clk;
+               dev_err(dev, "watchdog register failed, err %d\n", ret);
+               return ret;
        }
 
        platform_set_drvdata(pdev, wdd);
        return 0;
-
-out_disable_clk:
-       clk_disable_unprepare(dmt->clk);
-       return ret;
-}
-
-static int pic32_dmt_remove(struct platform_device *pdev)
-{
-       struct watchdog_device *wdd = platform_get_drvdata(pdev);
-       struct pic32_dmt *dmt = watchdog_get_drvdata(wdd);
-
-       watchdog_unregister_device(wdd);
-       clk_disable_unprepare(dmt->clk);
-
-       return 0;
 }
 
 static const struct of_device_id pic32_dmt_of_ids[] = {
@@ -242,7 +233,6 @@ MODULE_DEVICE_TABLE(of, pic32_dmt_of_ids);
 
 static struct platform_driver pic32_dmt_driver = {
        .probe          = pic32_dmt_probe,
-       .remove         = pic32_dmt_remove,
        .driver         = {
                .name           = "pic32-dmt",
                .of_match_table = of_match_ptr(pic32_dmt_of_ids),
index e2761068dc6f9c07dbdbbb4df17ebc3fe6442ee2..540500940cc04c49f0fd4016b92c24b6f31eb06c 100644 (file)
@@ -166,89 +166,77 @@ static const struct of_device_id pic32_wdt_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, pic32_wdt_dt_ids);
 
+static void pic32_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int pic32_wdt_drv_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        int ret;
        struct watchdog_device *wdd = &pic32_wdd;
        struct pic32_wdt *wdt;
-       struct resource *mem;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->regs = devm_ioremap_resource(&pdev->dev, mem);
+       wdt->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->regs))
                return PTR_ERR(wdt->regs);
 
-       wdt->rst_base = devm_ioremap(&pdev->dev, PIC32_BASE_RESET, 0x10);
+       wdt->rst_base = devm_ioremap(dev, PIC32_BASE_RESET, 0x10);
        if (!wdt->rst_base)
                return -ENOMEM;
 
-       wdt->clk = devm_clk_get(&pdev->dev, NULL);
+       wdt->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(wdt->clk)) {
-               dev_err(&pdev->dev, "clk not found\n");
+               dev_err(dev, "clk not found\n");
                return PTR_ERR(wdt->clk);
        }
 
        ret = clk_prepare_enable(wdt->clk);
        if (ret) {
-               dev_err(&pdev->dev, "clk enable failed\n");
+               dev_err(dev, "clk enable failed\n");
                return ret;
        }
+       ret = devm_add_action_or_reset(dev, pic32_clk_disable_unprepare,
+                                      wdt->clk);
+       if (ret)
+               return ret;
 
        if (pic32_wdt_is_win_enabled(wdt)) {
-               dev_err(&pdev->dev, "windowed-clear mode is not supported.\n");
-               ret = -ENODEV;
-               goto out_disable_clk;
+               dev_err(dev, "windowed-clear mode is not supported.\n");
+               return -ENODEV;
        }
 
-       wdd->timeout = pic32_wdt_get_timeout_secs(wdt, &pdev->dev);
+       wdd->timeout = pic32_wdt_get_timeout_secs(wdt, dev);
        if (!wdd->timeout) {
-               dev_err(&pdev->dev,
-                       "failed to read watchdog register timeout\n");
-               ret = -EINVAL;
-               goto out_disable_clk;
+               dev_err(dev, "failed to read watchdog register timeout\n");
+               return -EINVAL;
        }
 
-       dev_info(&pdev->dev, "timeout %d\n", wdd->timeout);
+       dev_info(dev, "timeout %d\n", wdd->timeout);
 
        wdd->bootstatus = pic32_wdt_bootstatus(wdt) ? WDIOF_CARDRESET : 0;
 
        watchdog_set_nowayout(wdd, WATCHDOG_NOWAYOUT);
        watchdog_set_drvdata(wdd, wdt);
 
-       ret = watchdog_register_device(wdd);
+       ret = devm_watchdog_register_device(dev, wdd);
        if (ret) {
-               dev_err(&pdev->dev, "watchdog register failed, err %d\n", ret);
-               goto out_disable_clk;
+               dev_err(dev, "watchdog register failed, err %d\n", ret);
+               return ret;
        }
 
        platform_set_drvdata(pdev, wdd);
 
-       return 0;
-
-out_disable_clk:
-       clk_disable_unprepare(wdt->clk);
-
-       return ret;
-}
-
-static int pic32_wdt_drv_remove(struct platform_device *pdev)
-{
-       struct watchdog_device *wdd = platform_get_drvdata(pdev);
-       struct pic32_wdt *wdt = watchdog_get_drvdata(wdd);
-
-       watchdog_unregister_device(wdd);
-       clk_disable_unprepare(wdt->clk);
-
        return 0;
 }
 
 static struct platform_driver pic32_wdt_driver = {
        .probe          = pic32_wdt_drv_probe,
-       .remove         = pic32_wdt_drv_remove,
        .driver         = {
                .name           = "pic32-wdt",
                .of_match_table = of_match_ptr(pic32_wdt_dt_ids),
index 7f10041fcf5b2ded99f996d5873e3bd0a0c29939..2d3652004e39c52d6fc73a4c15b98bafa8652e6f 100644 (file)
@@ -132,15 +132,16 @@ static const struct watchdog_ops pm8916_wdt_ops = {
 
 static int pm8916_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct pm8916_wdt *wdt;
        struct device *parent;
        int err, irq;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
-       parent = pdev->dev.parent;
+       parent = dev->parent;
 
        /*
         * The pm8916-pon-wdt is a child of the pon device, which is a child
@@ -150,20 +151,20 @@ static int pm8916_wdt_probe(struct platform_device *pdev)
         */
        wdt->regmap = dev_get_regmap(parent->parent, NULL);
        if (!wdt->regmap) {
-               dev_err(&pdev->dev, "failed to locate regmap\n");
+               dev_err(dev, "failed to locate regmap\n");
                return -ENODEV;
        }
 
        err = device_property_read_u32(parent, "reg", &wdt->baseaddr);
        if (err) {
-               dev_err(&pdev->dev, "failed to get pm8916-pon address\n");
+               dev_err(dev, "failed to get pm8916-pon address\n");
                return err;
        }
 
        irq = platform_get_irq(pdev, 0);
        if (irq > 0) {
-               if (devm_request_irq(&pdev->dev, irq, pm8916_wdt_isr, 0,
-                                    "pm8916_wdt", wdt))
+               if (devm_request_irq(dev, irq, pm8916_wdt_isr, 0, "pm8916_wdt",
+                                    wdt))
                        irq = 0;
        }
 
@@ -172,23 +173,23 @@ static int pm8916_wdt_probe(struct platform_device *pdev)
                           wdt->baseaddr + PON_PMIC_WD_RESET_S2_CTL,
                           RESET_TYPE_HARD);
        if (err) {
-               dev_err(&pdev->dev, "failed configure watchdog\n");
+               dev_err(dev, "failed configure watchdog\n");
                return err;
        }
 
        wdt->wdev.info = (irq > 0) ? &pm8916_wdt_pt_ident : &pm8916_wdt_ident,
        wdt->wdev.ops = &pm8916_wdt_ops,
-       wdt->wdev.parent = &pdev->dev;
+       wdt->wdev.parent = dev;
        wdt->wdev.min_timeout = PM8916_WDT_MIN_TIMEOUT;
        wdt->wdev.max_timeout = PM8916_WDT_MAX_TIMEOUT;
        wdt->wdev.timeout = PM8916_WDT_DEFAULT_TIMEOUT;
        wdt->wdev.pretimeout = 0;
        watchdog_set_drvdata(&wdt->wdev, wdt);
 
-       watchdog_init_timeout(&wdt->wdev, 0, &pdev->dev);
+       watchdog_init_timeout(&wdt->wdev, 0, dev);
        pm8916_wdt_configure_timers(&wdt->wdev);
 
-       return devm_watchdog_register_device(&pdev->dev, &wdt->wdev);
+       return devm_watchdog_register_device(dev, &wdt->wdev);
 }
 
 static const struct of_device_id pm8916_wdt_id_table[] = {
index 8e261799c84e356b9597f0996237875b11fe339c..d9e03544aeae653f7de727477c0a2064eb7182aa 100644 (file)
@@ -183,54 +183,50 @@ static struct watchdog_device pnx4008_wdd = {
        .max_timeout = MAX_HEARTBEAT,
 };
 
+static void pnx4008_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int pnx4008_wdt_probe(struct platform_device *pdev)
 {
-       struct resource *r;
+       struct device *dev = &pdev->dev;
        int ret = 0;
 
-       watchdog_init_timeout(&pnx4008_wdd, heartbeat, &pdev->dev);
+       watchdog_init_timeout(&pnx4008_wdd, heartbeat, dev);
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt_base = devm_ioremap_resource(&pdev->dev, r);
+       wdt_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt_base))
                return PTR_ERR(wdt_base);
 
-       wdt_clk = devm_clk_get(&pdev->dev, NULL);
+       wdt_clk = devm_clk_get(dev, NULL);
        if (IS_ERR(wdt_clk))
                return PTR_ERR(wdt_clk);
 
        ret = clk_prepare_enable(wdt_clk);
        if (ret)
                return ret;
+       ret = devm_add_action_or_reset(dev, pnx4008_clk_disable_unprepare,
+                                      wdt_clk);
+       if (ret)
+               return ret;
 
        pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
                        WDIOF_CARDRESET : 0;
-       pnx4008_wdd.parent = &pdev->dev;
+       pnx4008_wdd.parent = dev;
        watchdog_set_nowayout(&pnx4008_wdd, nowayout);
        watchdog_set_restart_priority(&pnx4008_wdd, 128);
 
-       pnx4008_wdt_stop(&pnx4008_wdd); /* disable for now */
+       if (readl(WDTIM_CTRL(wdt_base)) & COUNT_ENAB)
+               set_bit(WDOG_HW_RUNNING, &pnx4008_wdd.status);
 
-       ret = watchdog_register_device(&pnx4008_wdd);
+       ret = devm_watchdog_register_device(dev, &pnx4008_wdd);
        if (ret < 0) {
-               dev_err(&pdev->dev, "cannot register watchdog device\n");
-               goto disable_clk;
+               dev_err(dev, "cannot register watchdog device\n");
+               return ret;
        }
 
-       dev_info(&pdev->dev, "heartbeat %d sec\n", pnx4008_wdd.timeout);
-
-       return 0;
-
-disable_clk:
-       clk_disable_unprepare(wdt_clk);
-       return ret;
-}
-
-static int pnx4008_wdt_remove(struct platform_device *pdev)
-{
-       watchdog_unregister_device(&pnx4008_wdd);
-
-       clk_disable_unprepare(wdt_clk);
+       dev_info(dev, "heartbeat %d sec\n", pnx4008_wdd.timeout);
 
        return 0;
 }
@@ -249,7 +245,6 @@ static struct platform_driver platform_wdt_driver = {
                .of_match_table = of_match_ptr(pnx4008_wdt_match),
        },
        .probe = pnx4008_wdt_probe,
-       .remove = pnx4008_wdt_remove,
 };
 
 module_platform_driver(platform_wdt_driver);
index 5dfd604477a4873d4fd491a179842b5a0b495d91..6d29c33b131686a69e3a5de7bf875292f968d63c 100644 (file)
@@ -142,22 +142,28 @@ static const struct watchdog_info qcom_wdt_info = {
        .identity       = KBUILD_MODNAME,
 };
 
+static void qcom_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int qcom_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct qcom_wdt *wdt;
        struct resource *res;
-       struct device_node *np = pdev->dev.of_node;
+       struct device_node *np = dev->of_node;
        const u32 *regs;
        u32 percpu_offset;
        int ret;
 
-       regs = of_device_get_match_data(&pdev->dev);
+       regs = of_device_get_match_data(dev);
        if (!regs) {
-               dev_err(&pdev->dev, "Unsupported QCOM WDT module\n");
+               dev_err(dev, "Unsupported QCOM WDT module\n");
                return -ENODEV;
        }
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
@@ -172,21 +178,25 @@ static int qcom_wdt_probe(struct platform_device *pdev)
        res->start += percpu_offset;
        res->end += percpu_offset;
 
-       wdt->base = devm_ioremap_resource(&pdev->dev, res);
+       wdt->base = devm_ioremap_resource(dev, res);
        if (IS_ERR(wdt->base))
                return PTR_ERR(wdt->base);
 
-       wdt->clk = devm_clk_get(&pdev->dev, NULL);
+       wdt->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(wdt->clk)) {
-               dev_err(&pdev->dev, "failed to get input clock\n");
+               dev_err(dev, "failed to get input clock\n");
                return PTR_ERR(wdt->clk);
        }
 
        ret = clk_prepare_enable(wdt->clk);
        if (ret) {
-               dev_err(&pdev->dev, "failed to setup clock\n");
+               dev_err(dev, "failed to setup clock\n");
                return ret;
        }
+       ret = devm_add_action_or_reset(dev, qcom_clk_disable_unprepare,
+                                      wdt->clk);
+       if (ret)
+               return ret;
 
        /*
         * We use the clock rate to calculate the max timeout, so ensure it's
@@ -199,16 +209,15 @@ static int qcom_wdt_probe(struct platform_device *pdev)
        wdt->rate = clk_get_rate(wdt->clk);
        if (wdt->rate == 0 ||
            wdt->rate > 0x10000000U) {
-               dev_err(&pdev->dev, "invalid clock rate\n");
-               ret = -EINVAL;
-               goto err_clk_unprepare;
+               dev_err(dev, "invalid clock rate\n");
+               return -EINVAL;
        }
 
        wdt->wdd.info = &qcom_wdt_info;
        wdt->wdd.ops = &qcom_wdt_ops;
        wdt->wdd.min_timeout = 1;
        wdt->wdd.max_timeout = 0x10000000U / wdt->rate;
-       wdt->wdd.parent = &pdev->dev;
+       wdt->wdd.parent = dev;
        wdt->layout = regs;
 
        if (readl(wdt_addr(wdt, WDT_STS)) & 1)
@@ -220,29 +229,16 @@ static int qcom_wdt_probe(struct platform_device *pdev)
         * the max instead.
         */
        wdt->wdd.timeout = min(wdt->wdd.max_timeout, 30U);
-       watchdog_init_timeout(&wdt->wdd, 0, &pdev->dev);
+       watchdog_init_timeout(&wdt->wdd, 0, dev);
 
-       ret = watchdog_register_device(&wdt->wdd);
+       ret = devm_watchdog_register_device(dev, &wdt->wdd);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register watchdog\n");
-               goto err_clk_unprepare;
+               dev_err(dev, "failed to register watchdog\n");
+               return ret;
        }
 
        platform_set_drvdata(pdev, wdt);
        return 0;
-
-err_clk_unprepare:
-       clk_disable_unprepare(wdt->clk);
-       return ret;
-}
-
-static int qcom_wdt_remove(struct platform_device *pdev)
-{
-       struct qcom_wdt *wdt = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&wdt->wdd);
-       clk_disable_unprepare(wdt->clk);
-       return 0;
 }
 
 static int __maybe_unused qcom_wdt_suspend(struct device *dev)
@@ -277,7 +273,6 @@ MODULE_DEVICE_TABLE(of, qcom_wdt_of_table);
 
 static struct platform_driver qcom_watchdog_driver = {
        .probe  = qcom_wdt_probe,
-       .remove = qcom_wdt_remove,
        .driver = {
                .name           = KBUILD_MODNAME,
                .of_match_table = qcom_wdt_of_table,
index 622ede529912f47011c42c8e30cf508fcc5a502d..565dbc1ec6388fc9cf00ff158c7f72af78779af3 100644 (file)
@@ -151,7 +151,6 @@ static const struct soc_device_attribute rwdt_quirks_match[] = {
                .data = (void *)1,      /* needs single CPU */
        }, {
                .soc_id = "r8a7792",
-               .revision = "*",
                .data = (void *)0,      /* needs SMP disabled */
        },
        { /* sentinel */ }
@@ -177,7 +176,6 @@ static inline bool rwdt_blacklisted(struct device *dev) { return false; }
 static int rwdt_probe(struct platform_device *pdev)
 {
        struct rwdt_priv *priv;
-       struct resource *res;
        struct clk *clk;
        unsigned long clks_per_sec;
        int ret, i;
@@ -189,8 +187,7 @@ static int rwdt_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->base = devm_ioremap_resource(&pdev->dev, res);
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->base))
                return PTR_ERR(priv->base);
 
@@ -238,9 +235,7 @@ static int rwdt_probe(struct platform_device *pdev)
        watchdog_stop_on_unregister(&priv->wdev);
 
        /* This overrides the default timeout only if DT configuration was found */
-       ret = watchdog_init_timeout(&priv->wdev, 0, &pdev->dev);
-       if (ret)
-               dev_warn(&pdev->dev, "Specified timeout value invalid, using default\n");
+       watchdog_init_timeout(&priv->wdev, 0, &pdev->dev);
 
        ret = watchdog_register_device(&priv->wdev);
        if (ret < 0)
index e60f55702ab79d111078dae1b253799dfdc4684d..21fcb36f9074a4966b44ac13d2e82d5d0c556ff8 100644 (file)
@@ -146,11 +146,12 @@ static const struct watchdog_ops rn5t618_wdt_ops = {
 
 static int rn5t618_wdt_probe(struct platform_device *pdev)
 {
-       struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent);
+       struct device *dev = &pdev->dev;
+       struct rn5t618 *rn5t618 = dev_get_drvdata(dev->parent);
        struct rn5t618_wdt *wdt;
        int min_timeout, max_timeout;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(struct rn5t618_wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(struct rn5t618_wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
@@ -163,10 +164,10 @@ static int rn5t618_wdt_probe(struct platform_device *pdev)
        wdt->wdt_dev.min_timeout = min_timeout;
        wdt->wdt_dev.max_timeout = max_timeout;
        wdt->wdt_dev.timeout = max_timeout;
-       wdt->wdt_dev.parent = &pdev->dev;
+       wdt->wdt_dev.parent = dev;
 
        watchdog_set_drvdata(&wdt->wdt_dev, wdt);
-       watchdog_init_timeout(&wdt->wdt_dev, timeout, &pdev->dev);
+       watchdog_init_timeout(&wdt->wdt_dev, timeout, dev);
        watchdog_set_nowayout(&wdt->wdt_dev, nowayout);
 
        platform_set_drvdata(pdev, wdt);
index db7c57d82cfdc0201b9a49272c3dbb44db5961a7..905e60f45eecd818457cfdbefa6e9033b7ee9028 100644 (file)
@@ -141,19 +141,18 @@ static struct watchdog_device rt288x_wdt_dev = {
 
 static int rt288x_wdt_probe(struct platform_device *pdev)
 {
-       struct resource *res;
+       struct device *dev = &pdev->dev;
        int ret;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       rt288x_wdt_base = devm_ioremap_resource(&pdev->dev, res);
+       rt288x_wdt_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(rt288x_wdt_base))
                return PTR_ERR(rt288x_wdt_base);
 
-       rt288x_wdt_clk = devm_clk_get(&pdev->dev, NULL);
+       rt288x_wdt_clk = devm_clk_get(dev, NULL);
        if (IS_ERR(rt288x_wdt_clk))
                return PTR_ERR(rt288x_wdt_clk);
 
-       rt288x_wdt_reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+       rt288x_wdt_reset = devm_reset_control_get_exclusive(dev, NULL);
        if (!IS_ERR(rt288x_wdt_reset))
                reset_control_deassert(rt288x_wdt_reset);
 
@@ -161,31 +160,20 @@ static int rt288x_wdt_probe(struct platform_device *pdev)
 
        rt288x_wdt_dev.bootstatus = rt288x_wdt_bootcause();
        rt288x_wdt_dev.max_timeout = (0xfffful / rt288x_wdt_freq);
-       rt288x_wdt_dev.parent = &pdev->dev;
+       rt288x_wdt_dev.parent = dev;
 
        watchdog_init_timeout(&rt288x_wdt_dev, rt288x_wdt_dev.max_timeout,
-                             &pdev->dev);
+                             dev);
        watchdog_set_nowayout(&rt288x_wdt_dev, nowayout);
 
-       ret = watchdog_register_device(&rt288x_wdt_dev);
+       watchdog_stop_on_reboot(&rt288x_wdt_dev);
+       ret = devm_watchdog_register_device(dev, &rt288x_wdt_dev);
        if (!ret)
-               dev_info(&pdev->dev, "Initialized\n");
+               dev_info(dev, "Initialized\n");
 
        return 0;
 }
 
-static int rt288x_wdt_remove(struct platform_device *pdev)
-{
-       watchdog_unregister_device(&rt288x_wdt_dev);
-
-       return 0;
-}
-
-static void rt288x_wdt_shutdown(struct platform_device *pdev)
-{
-       rt288x_wdt_stop(&rt288x_wdt_dev);
-}
-
 static const struct of_device_id rt288x_wdt_match[] = {
        { .compatible = "ralink,rt2880-wdt" },
        {},
@@ -194,8 +182,6 @@ MODULE_DEVICE_TABLE(of, rt288x_wdt_match);
 
 static struct platform_driver rt288x_wdt_driver = {
        .probe          = rt288x_wdt_probe,
-       .remove         = rt288x_wdt_remove,
-       .shutdown       = rt288x_wdt_shutdown,
        .driver         = {
                .name           = KBUILD_MODNAME,
                .of_match_table = rt288x_wdt_match,
index d001c17ddfdeeea843e208682dbe8ca7fc57c441..834b94ff3f903ef93862eaebe298baee6faeebf2 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/bitops.h>
 #include <linux/clk.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
@@ -95,37 +94,43 @@ static const struct of_device_id rtd119x_wdt_dt_ids[] = {
         { }
 };
 
+static void rtd119x_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int rtd119x_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct rtd119x_watchdog_device *data;
-       struct resource *res;
        int ret;
 
-       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       data->base = devm_ioremap_resource(&pdev->dev, res);
+       data->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(data->base))
                return PTR_ERR(data->base);
 
-       data->clk = of_clk_get(pdev->dev.of_node, 0);
+       data->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(data->clk))
                return PTR_ERR(data->clk);
 
        ret = clk_prepare_enable(data->clk);
-       if (ret) {
-               clk_put(data->clk);
+       if (ret)
+               return ret;
+       ret = devm_add_action_or_reset(dev, rtd119x_clk_disable_unprepare,
+                                      data->clk);
+       if (ret)
                return ret;
-       }
 
        data->wdt_dev.info = &rtd119x_wdt_info;
        data->wdt_dev.ops = &rtd119x_wdt_ops;
        data->wdt_dev.timeout = 120;
        data->wdt_dev.max_timeout = 0xffffffff / clk_get_rate(data->clk);
        data->wdt_dev.min_timeout = 1;
-       data->wdt_dev.parent = &pdev->dev;
+       data->wdt_dev.parent = dev;
 
        watchdog_stop_on_reboot(&data->wdt_dev);
        watchdog_set_drvdata(&data->wdt_dev, data);
@@ -135,31 +140,11 @@ static int rtd119x_wdt_probe(struct platform_device *pdev)
        rtd119x_wdt_set_timeout(&data->wdt_dev, data->wdt_dev.timeout);
        rtd119x_wdt_stop(&data->wdt_dev);
 
-       ret = devm_watchdog_register_device(&pdev->dev, &data->wdt_dev);
-       if (ret) {
-               clk_disable_unprepare(data->clk);
-               clk_put(data->clk);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int rtd119x_wdt_remove(struct platform_device *pdev)
-{
-       struct rtd119x_watchdog_device *data = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&data->wdt_dev);
-
-       clk_disable_unprepare(data->clk);
-       clk_put(data->clk);
-
-       return 0;
+       return devm_watchdog_register_device(dev, &data->wdt_dev);
 }
 
 static struct platform_driver rtd119x_wdt_driver = {
        .probe = rtd119x_wdt_probe,
-       .remove = rtd119x_wdt_remove,
        .driver = {
                .name = "rtd1295-watchdog",
                .of_match_table = rtd119x_wdt_dt_ids,
index 781bb572e6af3de3f2d4caa3120df8d24a1090f1..7b6c365f7cd36297ffcf02c46c28e170862c8fcc 100644 (file)
@@ -166,35 +166,34 @@ static const struct watchdog_ops rza_wdt_ops = {
 
 static int rza_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct rza_wdt *priv;
-       struct resource *res;
        unsigned long rate;
        int ret;
 
-       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->base = devm_ioremap_resource(&pdev->dev, res);
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->base))
                return PTR_ERR(priv->base);
 
-       priv->clk = devm_clk_get(&pdev->dev, NULL);
+       priv->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(priv->clk))
                return PTR_ERR(priv->clk);
 
        rate = clk_get_rate(priv->clk);
        if (rate < 16384) {
-               dev_err(&pdev->dev, "invalid clock rate (%ld)\n", rate);
+               dev_err(dev, "invalid clock rate (%ld)\n", rate);
                return -ENOENT;
        }
 
        priv->wdev.info = &rza_wdt_ident,
        priv->wdev.ops = &rza_wdt_ops,
-       priv->wdev.parent = &pdev->dev;
+       priv->wdev.parent = dev;
 
-       priv->cks = (u8)(uintptr_t)of_device_get_match_data(&pdev->dev);
+       priv->cks = (u8)(uintptr_t) of_device_get_match_data(dev);
        if (priv->cks == CKS_4BIT) {
                /* Assume slowest clock rate possible (CKS=0xF) */
                priv->wdev.max_timeout = (DIVIDER_4BIT * U8_MAX) / rate;
@@ -209,19 +208,19 @@ static int rza_wdt_probe(struct platform_device *pdev)
                 * max_hw_heartbeat_ms.
                 */
                priv->wdev.max_hw_heartbeat_ms = (1000 * U8_MAX) / rate;
-               dev_dbg(&pdev->dev, "max hw timeout of %dms\n",
-                        priv->wdev.max_hw_heartbeat_ms);
+               dev_dbg(dev, "max hw timeout of %dms\n",
+                       priv->wdev.max_hw_heartbeat_ms);
        }
 
        priv->wdev.min_timeout = 1;
        priv->wdev.timeout = DEFAULT_TIMEOUT;
 
-       watchdog_init_timeout(&priv->wdev, 0, &pdev->dev);
+       watchdog_init_timeout(&priv->wdev, 0, dev);
        watchdog_set_drvdata(&priv->wdev, priv);
 
-       ret = devm_watchdog_register_device(&pdev->dev, &priv->wdev);
+       ret = devm_watchdog_register_device(dev, &priv->wdev);
        if (ret)
-               dev_err(&pdev->dev, "Cannot register watchdog device\n");
+               dev_err(dev, "Cannot register watchdog device\n");
 
        return ret;
 }
index adaa43543f0a7c2591ea0bf472926aa367567fa0..4267b9e8734b497cacb233d08f5ae4e8688889e4 100644 (file)
@@ -522,7 +522,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct s3c2410_wdt *wdt;
-       struct resource *wdt_mem;
        struct resource *wdt_irq;
        unsigned int wtcon;
        int started = 0;
@@ -554,8 +553,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
        }
 
        /* get the memory region for the watchdog timer */
-       wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->reg_base = devm_ioremap_resource(dev, wdt_mem);
+       wdt->reg_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->reg_base)) {
                ret = PTR_ERR(wdt->reg_base);
                goto err;
index 1e93c1b0e3cfc224f039c47407a54b6fd7dda7da..111695223aae27fcb9a4f9a3df788a675c91ff65 100644 (file)
@@ -199,15 +199,15 @@ static int sama5d4_wdt_init(struct sama5d4_wdt *wdt)
 
 static int sama5d4_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct watchdog_device *wdd;
        struct sama5d4_wdt *wdt;
-       struct resource *res;
        void __iomem *regs;
        u32 irq = 0;
        u32 timeout;
        int ret;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
@@ -221,33 +221,31 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
 
        watchdog_set_drvdata(wdd, wdt);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       regs = devm_ioremap_resource(&pdev->dev, res);
+       regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(regs))
                return PTR_ERR(regs);
 
        wdt->reg_base = regs;
 
-       irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+       irq = irq_of_parse_and_map(dev->of_node, 0);
        if (!irq)
-               dev_warn(&pdev->dev, "failed to get IRQ from DT\n");
+               dev_warn(dev, "failed to get IRQ from DT\n");
 
-       ret = of_sama5d4_wdt_init(pdev->dev.of_node, wdt);
+       ret = of_sama5d4_wdt_init(dev->of_node, wdt);
        if (ret)
                return ret;
 
        if ((wdt->mr & AT91_WDT_WDFIEN) && irq) {
-               ret = devm_request_irq(&pdev->dev, irq, sama5d4_wdt_irq_handler,
+               ret = devm_request_irq(dev, irq, sama5d4_wdt_irq_handler,
                                       IRQF_SHARED | IRQF_IRQPOLL |
                                       IRQF_NO_SUSPEND, pdev->name, pdev);
                if (ret) {
-                       dev_err(&pdev->dev,
-                               "cannot register interrupt handler\n");
+                       dev_err(dev, "cannot register interrupt handler\n");
                        return ret;
                }
        }
 
-       watchdog_init_timeout(wdd, wdt_timeout, &pdev->dev);
+       watchdog_init_timeout(wdd, wdt_timeout, dev);
 
        timeout = WDT_SEC2TICKS(wdd->timeout);
 
@@ -260,31 +258,21 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
 
        watchdog_set_nowayout(wdd, nowayout);
 
-       ret = watchdog_register_device(wdd);
+       watchdog_stop_on_unregister(wdd);
+       ret = devm_watchdog_register_device(dev, wdd);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register watchdog device\n");
+               dev_err(dev, "failed to register watchdog device\n");
                return ret;
        }
 
        platform_set_drvdata(pdev, wdt);
 
-       dev_info(&pdev->dev, "initialized (timeout = %d sec, nowayout = %d)\n",
+       dev_info(dev, "initialized (timeout = %d sec, nowayout = %d)\n",
                 wdd->timeout, nowayout);
 
        return 0;
 }
 
-static int sama5d4_wdt_remove(struct platform_device *pdev)
-{
-       struct sama5d4_wdt *wdt = platform_get_drvdata(pdev);
-
-       sama5d4_wdt_stop(&wdt->wdd);
-
-       watchdog_unregister_device(&wdt->wdd);
-
-       return 0;
-}
-
 static const struct of_device_id sama5d4_wdt_of_match[] = {
        { .compatible = "atmel,sama5d4-wdt", },
        { }
@@ -312,7 +300,6 @@ static SIMPLE_DEV_PM_OPS(sama5d4_wdt_pm_ops, NULL,
 
 static struct platform_driver sama5d4_wdt_driver = {
        .probe          = sama5d4_wdt_probe,
-       .remove         = sama5d4_wdt_remove,
        .driver         = {
                .name   = "sama5d4_wdt",
                .pm     = &sama5d4_wdt_pm_ops,
index 0692d42e5c67058d7f441611387200aa99cea3ad..5a6ced7a7e8f80a95ebc0ecba3e70c793caea701 100644 (file)
@@ -67,7 +67,7 @@ static DEFINE_SPINLOCK(sbwd_lock);
  *
  * wdog is the iomem address of the cfg register
  */
-void sbwdog_set(char __iomem *wdog, unsigned long t)
+static void sbwdog_set(char __iomem *wdog, unsigned long t)
 {
        spin_lock(&sbwd_lock);
        __raw_writeb(0, wdog);
@@ -81,7 +81,7 @@ void sbwdog_set(char __iomem *wdog, unsigned long t)
  *
  * wdog is the iomem address of the cfg register
  */
-void sbwdog_pet(char __iomem *wdog)
+static void sbwdog_pet(char __iomem *wdog)
 {
        spin_lock(&sbwd_lock);
        __raw_writeb(__raw_readb(wdog) | 1, wdog);
index e221e47396ab72ddd8615ce81c8c6f7d9247d941..3219422f67a962218a2a5e7ceff78abfae8531cc 100644 (file)
@@ -231,7 +231,6 @@ static int sbsa_gwdt_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct watchdog_device *wdd;
        struct sbsa_gwdt *gwdt;
-       struct resource *res;
        int ret, irq;
        u32 status;
 
@@ -240,13 +239,11 @@ static int sbsa_gwdt_probe(struct platform_device *pdev)
                return -ENOMEM;
        platform_set_drvdata(pdev, gwdt);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       cf_base = devm_ioremap_resource(dev, res);
+       cf_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(cf_base))
                return PTR_ERR(cf_base);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       rf_base = devm_ioremap_resource(dev, res);
+       rf_base = devm_platform_ioremap_resource(pdev, 1);
        if (IS_ERR(rf_base))
                return PTR_ERR(rf_base);
 
@@ -313,7 +310,8 @@ static int sbsa_gwdt_probe(struct platform_device *pdev)
         */
        sbsa_gwdt_set_timeout(wdd, wdd->timeout);
 
-       ret = watchdog_register_device(wdd);
+       watchdog_stop_on_reboot(wdd);
+       ret = devm_watchdog_register_device(dev, wdd);
        if (ret)
                return ret;
 
@@ -324,22 +322,6 @@ static int sbsa_gwdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-static void sbsa_gwdt_shutdown(struct platform_device *pdev)
-{
-       struct sbsa_gwdt *gwdt = platform_get_drvdata(pdev);
-
-       sbsa_gwdt_stop(&gwdt->wdd);
-}
-
-static int sbsa_gwdt_remove(struct platform_device *pdev)
-{
-       struct sbsa_gwdt *gwdt = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&gwdt->wdd);
-
-       return 0;
-}
-
 /* Disable watchdog if it is active during suspend */
 static int __maybe_unused sbsa_gwdt_suspend(struct device *dev)
 {
@@ -385,8 +367,6 @@ static struct platform_driver sbsa_gwdt_driver = {
                .of_match_table = sbsa_gwdt_of_match,
        },
        .probe = sbsa_gwdt_probe,
-       .remove = sbsa_gwdt_remove,
-       .shutdown = sbsa_gwdt_shutdown,
        .id_table = sbsa_gwdt_pdev_match,
 };
 
index a7d6425db807ff9d95c91aa24be73bbdfa15a9bd..e7617b7df70b3e4c3538a5d68fb1120c1e96a5e9 100644 (file)
@@ -220,7 +220,6 @@ static struct watchdog_device sh_wdt_dev = {
 static int sh_wdt_probe(struct platform_device *pdev)
 {
        struct sh_wdt *wdt;
-       struct resource *res;
        int rc;
 
        /*
@@ -245,8 +244,7 @@ static int sh_wdt_probe(struct platform_device *pdev)
                wdt->clk = NULL;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->base = devm_ioremap_resource(wdt->dev, res);
+       wdt->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->base))
                return PTR_ERR(wdt->base);
 
index ac0c9d2c4aee4ff8f14b92fd5b7a8c7e74fc0248..e79a4097d50be39ba0e7dff9ea8fdb1c6187a5af 100644 (file)
@@ -146,22 +146,23 @@ static struct watchdog_device sirfsoc_wdd = {
 
 static int sirfsoc_wdt_probe(struct platform_device *pdev)
 {
-       struct resource *res;
+       struct device *dev = &pdev->dev;
        int ret;
        void __iomem *base;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(&pdev->dev, res);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
        watchdog_set_drvdata(&sirfsoc_wdd, (__force void *)base);
 
-       watchdog_init_timeout(&sirfsoc_wdd, timeout, &pdev->dev);
+       watchdog_init_timeout(&sirfsoc_wdd, timeout, dev);
        watchdog_set_nowayout(&sirfsoc_wdd, nowayout);
-       sirfsoc_wdd.parent = &pdev->dev;
+       sirfsoc_wdd.parent = dev;
 
-       ret = watchdog_register_device(&sirfsoc_wdd);
+       watchdog_stop_on_reboot(&sirfsoc_wdd);
+       watchdog_stop_on_unregister(&sirfsoc_wdd);
+       ret = devm_watchdog_register_device(dev, &sirfsoc_wdd);
        if (ret)
                return ret;
 
@@ -170,19 +171,6 @@ static int sirfsoc_wdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-static void sirfsoc_wdt_shutdown(struct platform_device *pdev)
-{
-       struct watchdog_device *wdd = platform_get_drvdata(pdev);
-
-       sirfsoc_wdt_disable(wdd);
-}
-
-static int sirfsoc_wdt_remove(struct platform_device *pdev)
-{
-       sirfsoc_wdt_shutdown(pdev);
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int sirfsoc_wdt_suspend(struct device *dev)
 {
@@ -220,8 +208,6 @@ static struct platform_driver sirfsoc_wdt_driver = {
                .of_match_table = sirfsoc_wdt_of_match,
        },
        .probe = sirfsoc_wdt_probe,
-       .remove = sirfsoc_wdt_remove,
-       .shutdown = sirfsoc_wdt_shutdown,
 };
 module_platform_driver(sirfsoc_wdt_driver);
 
index 41aaae2d5287faae869fad5591b0290cc0c7dadf..553735b256e219b5428f55d0f5179e7214bf2821 100644 (file)
@@ -395,9 +395,7 @@ static int sp5100_tco_probe(struct platform_device *pdev)
        wdd->min_timeout = 1;
        wdd->max_timeout = 0xffff;
 
-       if (watchdog_init_timeout(wdd, heartbeat, NULL))
-               dev_info(dev, "timeout value invalid, using %d\n",
-                        wdd->timeout);
+       watchdog_init_timeout(wdd, heartbeat, NULL);
        watchdog_set_nowayout(wdd, nowayout);
        watchdog_stop_on_reboot(wdd);
        watchdog_stop_on_unregister(wdd);
index ff9397d9638a7b4a7745084ddd2654f98c8e8c06..14874e9b207b819c8e3c64b4f3f4a76f5e7d7a3c 100644 (file)
@@ -245,9 +245,7 @@ static u32 sprd_wdt_get_timeleft(struct watchdog_device *wdd)
        u32 val;
 
        val = sprd_wdt_get_cnt_value(wdt);
-       val = val / SPRD_WDT_CNT_STEP;
-
-       return val;
+       return val / SPRD_WDT_CNT_STEP;
 }
 
 static const struct watchdog_ops sprd_wdt_ops = {
@@ -269,70 +267,68 @@ static const struct watchdog_info sprd_wdt_info = {
 
 static int sprd_wdt_probe(struct platform_device *pdev)
 {
-       struct resource *wdt_res;
+       struct device *dev = &pdev->dev;
        struct sprd_wdt *wdt;
        int ret;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
-       wdt_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->base = devm_ioremap_resource(&pdev->dev, wdt_res);
+       wdt->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->base))
                return PTR_ERR(wdt->base);
 
-       wdt->enable = devm_clk_get(&pdev->dev, "enable");
+       wdt->enable = devm_clk_get(dev, "enable");
        if (IS_ERR(wdt->enable)) {
-               dev_err(&pdev->dev, "can't get the enable clock\n");
+               dev_err(dev, "can't get the enable clock\n");
                return PTR_ERR(wdt->enable);
        }
 
-       wdt->rtc_enable = devm_clk_get(&pdev->dev, "rtc_enable");
+       wdt->rtc_enable = devm_clk_get(dev, "rtc_enable");
        if (IS_ERR(wdt->rtc_enable)) {
-               dev_err(&pdev->dev, "can't get the rtc enable clock\n");
+               dev_err(dev, "can't get the rtc enable clock\n");
                return PTR_ERR(wdt->rtc_enable);
        }
 
        wdt->irq = platform_get_irq(pdev, 0);
        if (wdt->irq < 0) {
-               dev_err(&pdev->dev, "failed to get IRQ resource\n");
+               dev_err(dev, "failed to get IRQ resource\n");
                return wdt->irq;
        }
 
-       ret = devm_request_irq(&pdev->dev, wdt->irq, sprd_wdt_isr,
-                              IRQF_NO_SUSPEND, "sprd-wdt", (void *)wdt);
+       ret = devm_request_irq(dev, wdt->irq, sprd_wdt_isr, IRQF_NO_SUSPEND,
+                              "sprd-wdt", (void *)wdt);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register irq\n");
+               dev_err(dev, "failed to register irq\n");
                return ret;
        }
 
        wdt->wdd.info = &sprd_wdt_info;
        wdt->wdd.ops = &sprd_wdt_ops;
-       wdt->wdd.parent = &pdev->dev;
+       wdt->wdd.parent = dev;
        wdt->wdd.min_timeout = SPRD_WDT_MIN_TIMEOUT;
        wdt->wdd.max_timeout = SPRD_WDT_MAX_TIMEOUT;
        wdt->wdd.timeout = SPRD_WDT_MAX_TIMEOUT;
 
        ret = sprd_wdt_enable(wdt);
        if (ret) {
-               dev_err(&pdev->dev, "failed to enable wdt\n");
+               dev_err(dev, "failed to enable wdt\n");
                return ret;
        }
-       ret = devm_add_action(&pdev->dev, sprd_wdt_disable, wdt);
+       ret = devm_add_action_or_reset(dev, sprd_wdt_disable, wdt);
        if (ret) {
-               sprd_wdt_disable(wdt);
-               dev_err(&pdev->dev, "Failed to add wdt disable action\n");
+               dev_err(dev, "Failed to add wdt disable action\n");
                return ret;
        }
 
        watchdog_set_nowayout(&wdt->wdd, WATCHDOG_NOWAYOUT);
-       watchdog_init_timeout(&wdt->wdd, 0, &pdev->dev);
+       watchdog_init_timeout(&wdt->wdd, 0, dev);
 
-       ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdd);
+       ret = devm_watchdog_register_device(dev, &wdt->wdd);
        if (ret) {
                sprd_wdt_disable(wdt);
-               dev_err(&pdev->dev, "failed to register watchdog\n");
+               dev_err(dev, "failed to register watchdog\n");
                return ret;
        }
        platform_set_drvdata(pdev, wdt);
index 177829b379da0f74e637dcc5ce6f47d517e53362..7a90184eb9509fa979238d3239ad0c85aa539b79 100644 (file)
@@ -142,13 +142,18 @@ static struct watchdog_device st_wdog_dev = {
        .ops            = &st_wdog_ops,
 };
 
+static void st_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int st_wdog_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        const struct of_device_id *match;
-       struct device_node *np = pdev->dev.of_node;
+       struct device_node *np = dev->of_node;
        struct st_wdog *st_wdog;
        struct regmap *regmap;
-       struct resource *res;
        struct clk *clk;
        void __iomem *base;
        uint32_t mode;
@@ -156,7 +161,7 @@ static int st_wdog_probe(struct platform_device *pdev)
 
        ret = of_property_read_u32(np, "st,lpc-mode", &mode);
        if (ret) {
-               dev_err(&pdev->dev, "An LPC mode must be provided\n");
+               dev_err(dev, "An LPC mode must be provided\n");
                return -EINVAL;
        }
 
@@ -164,35 +169,34 @@ static int st_wdog_probe(struct platform_device *pdev)
        if (mode != ST_LPC_MODE_WDT)
                return -ENODEV;
 
-       st_wdog = devm_kzalloc(&pdev->dev, sizeof(*st_wdog), GFP_KERNEL);
+       st_wdog = devm_kzalloc(dev, sizeof(*st_wdog), GFP_KERNEL);
        if (!st_wdog)
                return -ENOMEM;
 
-       match = of_match_device(st_wdog_match, &pdev->dev);
+       match = of_match_device(st_wdog_match, dev);
        if (!match) {
-               dev_err(&pdev->dev, "Couldn't match device\n");
+               dev_err(dev, "Couldn't match device\n");
                return -ENODEV;
        }
        st_wdog->syscfg = (struct st_wdog_syscfg *)match->data;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(&pdev->dev, res);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
        regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
        if (IS_ERR(regmap)) {
-               dev_err(&pdev->dev, "No syscfg phandle specified\n");
+               dev_err(dev, "No syscfg phandle specified\n");
                return PTR_ERR(regmap);
        }
 
-       clk = devm_clk_get(&pdev->dev, NULL);
+       clk = devm_clk_get(dev, NULL);
        if (IS_ERR(clk)) {
-               dev_err(&pdev->dev, "Unable to request clock\n");
+               dev_err(dev, "Unable to request clock\n");
                return PTR_ERR(clk);
        }
 
-       st_wdog->dev            = &pdev->dev;
+       st_wdog->dev            = dev;
        st_wdog->base           = base;
        st_wdog->clk            = clk;
        st_wdog->regmap         = regmap;
@@ -200,39 +204,38 @@ static int st_wdog_probe(struct platform_device *pdev)
        st_wdog->clkrate        = clk_get_rate(st_wdog->clk);
 
        if (!st_wdog->clkrate) {
-               dev_err(&pdev->dev, "Unable to fetch clock rate\n");
+               dev_err(dev, "Unable to fetch clock rate\n");
                return -EINVAL;
        }
        st_wdog_dev.max_timeout = 0xFFFFFFFF / st_wdog->clkrate;
-       st_wdog_dev.parent = &pdev->dev;
+       st_wdog_dev.parent = dev;
 
        ret = clk_prepare_enable(clk);
        if (ret) {
-               dev_err(&pdev->dev, "Unable to enable clock\n");
+               dev_err(dev, "Unable to enable clock\n");
                return ret;
        }
+       ret = devm_add_action_or_reset(dev, st_clk_disable_unprepare, clk);
+       if (ret)
+               return ret;
 
        watchdog_set_drvdata(&st_wdog_dev, st_wdog);
        watchdog_set_nowayout(&st_wdog_dev, WATCHDOG_NOWAYOUT);
 
        /* Init Watchdog timeout with value in DT */
-       ret = watchdog_init_timeout(&st_wdog_dev, 0, &pdev->dev);
-       if (ret) {
-               dev_err(&pdev->dev, "Unable to initialise watchdog timeout\n");
-               clk_disable_unprepare(clk);
+       ret = watchdog_init_timeout(&st_wdog_dev, 0, dev);
+       if (ret)
                return ret;
-       }
 
-       ret = watchdog_register_device(&st_wdog_dev);
+       ret = devm_watchdog_register_device(dev, &st_wdog_dev);
        if (ret) {
-               dev_err(&pdev->dev, "Unable to register watchdog\n");
-               clk_disable_unprepare(clk);
+               dev_err(dev, "Unable to register watchdog\n");
                return ret;
        }
 
        st_wdog_setup(st_wdog, true);
 
-       dev_info(&pdev->dev, "LPC Watchdog driver registered, reset type is %s",
+       dev_info(dev, "LPC Watchdog driver registered, reset type is %s",
                 st_wdog->warm_reset ? "warm" : "cold");
 
        return ret;
@@ -243,8 +246,6 @@ static int st_wdog_remove(struct platform_device *pdev)
        struct st_wdog *st_wdog = watchdog_get_drvdata(&st_wdog_dev);
 
        st_wdog_setup(st_wdog, false);
-       watchdog_unregister_device(&st_wdog_dev);
-       clk_disable_unprepare(st_wdog->clk);
 
        return 0;
 }
index e00e3b3526c6e73220849553f8b0680c90811100..d569a3634d9b4b5e6fd3dbc7c73ddfea99186701 100644 (file)
 #define KR_KEY_EWA     0x5555 /* write access enable */
 #define KR_KEY_DWA     0x0000 /* write access disable */
 
-/* IWDG_PR register bit values */
-#define PR_4           0x00 /* prescaler set to 4 */
-#define PR_8           0x01 /* prescaler set to 8 */
-#define PR_16          0x02 /* prescaler set to 16 */
-#define PR_32          0x03 /* prescaler set to 32 */
-#define PR_64          0x04 /* prescaler set to 64 */
-#define PR_128         0x05 /* prescaler set to 128 */
-#define PR_256         0x06 /* prescaler set to 256 */
+/* IWDG_PR register */
+#define PR_SHIFT       2
+#define PR_MIN         BIT(PR_SHIFT)
 
 /* IWDG_RLR register values */
-#define RLR_MIN                0x07C /* min value supported by reload register */
-#define RLR_MAX                0xFFF /* max value supported by reload register */
+#define RLR_MIN                0x2             /* min value recommended */
+#define RLR_MAX                GENMASK(11, 0)  /* max value of reload register */
 
 /* IWDG_SR register bit mask */
-#define FLAG_PVU       BIT(0) /* Watchdog prescaler value update */
-#define FLAG_RVU       BIT(1) /* Watchdog counter reload value update */
+#define SR_PVU BIT(0) /* Watchdog prescaler value update */
+#define SR_RVU BIT(1) /* Watchdog counter reload value update */
 
 /* set timeout to 100000 us */
 #define TIMEOUT_US     100000
 #define SLEEP_US       1000
 
-#define HAS_PCLK       true
+struct stm32_iwdg_data {
+       bool has_pclk;
+       u32 max_prescaler;
+};
+
+static const struct stm32_iwdg_data stm32_iwdg_data = {
+       .has_pclk = false,
+       .max_prescaler = 256,
+};
+
+static const struct stm32_iwdg_data stm32mp1_iwdg_data = {
+       .has_pclk = true,
+       .max_prescaler = 1024,
+};
 
 struct stm32_iwdg {
        struct watchdog_device  wdd;
+       const struct stm32_iwdg_data *data;
        void __iomem            *regs;
        struct clk              *clk_lsi;
        struct clk              *clk_pclk;
        unsigned int            rate;
-       bool                    has_pclk;
 };
 
 static inline u32 reg_read(void __iomem *base, u32 reg)
@@ -79,31 +87,35 @@ static inline void reg_write(void __iomem *base, u32 reg, u32 val)
 static int stm32_iwdg_start(struct watchdog_device *wdd)
 {
        struct stm32_iwdg *wdt = watchdog_get_drvdata(wdd);
-       u32 val = FLAG_PVU | FLAG_RVU;
-       u32 reload;
+       u32 tout, presc, iwdg_rlr, iwdg_pr, iwdg_sr;
        int ret;
 
        dev_dbg(wdd->parent, "%s\n", __func__);
 
-       /* prescaler fixed to 256 */
-       reload = clamp_t(unsigned int, ((wdd->timeout * wdt->rate) / 256) - 1,
-                        RLR_MIN, RLR_MAX);
+       tout = clamp_t(unsigned int, wdd->timeout,
+                      wdd->min_timeout, wdd->max_hw_heartbeat_ms / 1000);
+
+       presc = DIV_ROUND_UP(tout * wdt->rate, RLR_MAX + 1);
+
+       /* The prescaler is align on power of 2 and start at 2 ^ PR_SHIFT. */
+       presc = roundup_pow_of_two(presc);
+       iwdg_pr = presc <= 1 << PR_SHIFT ? 0 : ilog2(presc) - PR_SHIFT;
+       iwdg_rlr = ((tout * wdt->rate) / presc) - 1;
 
        /* enable write access */
        reg_write(wdt->regs, IWDG_KR, KR_KEY_EWA);
 
        /* set prescaler & reload registers */
-       reg_write(wdt->regs, IWDG_PR, PR_256); /* prescaler fix to 256 */
-       reg_write(wdt->regs, IWDG_RLR, reload);
+       reg_write(wdt->regs, IWDG_PR, iwdg_pr);
+       reg_write(wdt->regs, IWDG_RLR, iwdg_rlr);
        reg_write(wdt->regs, IWDG_KR, KR_KEY_ENABLE);
 
        /* wait for the registers to be updated (max 100ms) */
-       ret = readl_relaxed_poll_timeout(wdt->regs + IWDG_SR, val,
-                                        !(val & (FLAG_PVU | FLAG_RVU)),
+       ret = readl_relaxed_poll_timeout(wdt->regs + IWDG_SR, iwdg_sr,
+                                        !(iwdg_sr & (SR_PVU | SR_RVU)),
                                         SLEEP_US, TIMEOUT_US);
        if (ret) {
-               dev_err(wdd->parent,
-                       "Fail to set prescaler or reload registers\n");
+               dev_err(wdd->parent, "Fail to set prescaler, reload regs\n");
                return ret;
        }
 
@@ -138,38 +150,52 @@ static int stm32_iwdg_set_timeout(struct watchdog_device *wdd,
        return 0;
 }
 
+static void stm32_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int stm32_iwdg_clk_init(struct platform_device *pdev,
                               struct stm32_iwdg *wdt)
 {
+       struct device *dev = &pdev->dev;
        u32 ret;
 
-       wdt->clk_lsi = devm_clk_get(&pdev->dev, "lsi");
+       wdt->clk_lsi = devm_clk_get(dev, "lsi");
        if (IS_ERR(wdt->clk_lsi)) {
-               dev_err(&pdev->dev, "Unable to get lsi clock\n");
+               dev_err(dev, "Unable to get lsi clock\n");
                return PTR_ERR(wdt->clk_lsi);
        }
 
        /* optional peripheral clock */
-       if (wdt->has_pclk) {
-               wdt->clk_pclk = devm_clk_get(&pdev->dev, "pclk");
+       if (wdt->data->has_pclk) {
+               wdt->clk_pclk = devm_clk_get(dev, "pclk");
                if (IS_ERR(wdt->clk_pclk)) {
-                       dev_err(&pdev->dev, "Unable to get pclk clock\n");
+                       dev_err(dev, "Unable to get pclk clock\n");
                        return PTR_ERR(wdt->clk_pclk);
                }
 
                ret = clk_prepare_enable(wdt->clk_pclk);
                if (ret) {
-                       dev_err(&pdev->dev, "Unable to prepare pclk clock\n");
+                       dev_err(dev, "Unable to prepare pclk clock\n");
                        return ret;
                }
+               ret = devm_add_action_or_reset(dev,
+                                              stm32_clk_disable_unprepare,
+                                              wdt->clk_pclk);
+               if (ret)
+                       return ret;
        }
 
        ret = clk_prepare_enable(wdt->clk_lsi);
        if (ret) {
-               dev_err(&pdev->dev, "Unable to prepare lsi clock\n");
-               clk_disable_unprepare(wdt->clk_pclk);
+               dev_err(dev, "Unable to prepare lsi clock\n");
                return ret;
        }
+       ret = devm_add_action_or_reset(dev, stm32_clk_disable_unprepare,
+                                      wdt->clk_lsi);
+       if (ret)
+               return ret;
 
        wdt->rate = clk_get_rate(wdt->clk_lsi);
 
@@ -191,35 +217,31 @@ static const struct watchdog_ops stm32_iwdg_ops = {
 };
 
 static const struct of_device_id stm32_iwdg_of_match[] = {
-       { .compatible = "st,stm32-iwdg", .data = (void *)!HAS_PCLK },
-       { .compatible = "st,stm32mp1-iwdg", .data = (void *)HAS_PCLK },
+       { .compatible = "st,stm32-iwdg", .data = &stm32_iwdg_data },
+       { .compatible = "st,stm32mp1-iwdg", .data = &stm32mp1_iwdg_data },
        { /* end node */ }
 };
 MODULE_DEVICE_TABLE(of, stm32_iwdg_of_match);
 
 static int stm32_iwdg_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct watchdog_device *wdd;
-       const struct of_device_id *match;
        struct stm32_iwdg *wdt;
-       struct resource *res;
        int ret;
 
-       match = of_match_device(stm32_iwdg_of_match, &pdev->dev);
-       if (!match)
-               return -ENODEV;
-
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
-       wdt->has_pclk = match->data;
+       wdt->data = of_device_get_match_data(&pdev->dev);
+       if (!wdt->data)
+               return -ENODEV;
 
        /* This is the timer base. */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->regs = devm_ioremap_resource(&pdev->dev, res);
+       wdt->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->regs)) {
-               dev_err(&pdev->dev, "Could not get resource\n");
+               dev_err(dev, "Could not get resource\n");
                return PTR_ERR(wdt->regs);
        }
 
@@ -229,50 +251,30 @@ static int stm32_iwdg_probe(struct platform_device *pdev)
 
        /* Initialize struct watchdog_device. */
        wdd = &wdt->wdd;
+       wdd->parent = dev;
        wdd->info = &stm32_iwdg_info;
        wdd->ops = &stm32_iwdg_ops;
-       wdd->min_timeout = ((RLR_MIN + 1) * 256) / wdt->rate;
-       wdd->max_hw_heartbeat_ms = ((RLR_MAX + 1) * 256 * 1000) / wdt->rate;
-       wdd->parent = &pdev->dev;
+       wdd->min_timeout = DIV_ROUND_UP((RLR_MIN + 1) * PR_MIN, wdt->rate);
+       wdd->max_hw_heartbeat_ms = ((RLR_MAX + 1) * wdt->data->max_prescaler *
+                                   1000) / wdt->rate;
 
        watchdog_set_drvdata(wdd, wdt);
        watchdog_set_nowayout(wdd, WATCHDOG_NOWAYOUT);
+       watchdog_init_timeout(wdd, 0, dev);
 
-       ret = watchdog_init_timeout(wdd, 0, &pdev->dev);
-       if (ret)
-               dev_warn(&pdev->dev,
-                        "unable to set timeout value, using default\n");
-
-       ret = watchdog_register_device(wdd);
+       ret = devm_watchdog_register_device(dev, wdd);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register watchdog device\n");
-               goto err;
+               dev_err(dev, "failed to register watchdog device\n");
+               return ret;
        }
 
        platform_set_drvdata(pdev, wdt);
 
-       return 0;
-err:
-       clk_disable_unprepare(wdt->clk_lsi);
-       clk_disable_unprepare(wdt->clk_pclk);
-
-       return ret;
-}
-
-static int stm32_iwdg_remove(struct platform_device *pdev)
-{
-       struct stm32_iwdg *wdt = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&wdt->wdd);
-       clk_disable_unprepare(wdt->clk_lsi);
-       clk_disable_unprepare(wdt->clk_pclk);
-
        return 0;
 }
 
 static struct platform_driver stm32_iwdg_driver = {
        .probe          = stm32_iwdg_probe,
-       .remove         = stm32_iwdg_remove,
        .driver = {
                .name   = "iwdg",
                .of_match_table = of_match_ptr(stm32_iwdg_of_match),
index 994c54cc68e9c930f628fc6ef0f4345181347245..671f4ba7b4ed67bac51497f430ecd07b683e4592 100644 (file)
@@ -89,31 +89,31 @@ static struct notifier_block wdt_notifier = {
 
 static int stmp3xxx_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        int ret;
 
-       watchdog_set_drvdata(&stmp3xxx_wdd, &pdev->dev);
+       watchdog_set_drvdata(&stmp3xxx_wdd, dev);
 
        stmp3xxx_wdd.timeout = clamp_t(unsigned, heartbeat, 1, STMP3XXX_MAX_TIMEOUT);
-       stmp3xxx_wdd.parent = &pdev->dev;
+       stmp3xxx_wdd.parent = dev;
 
-       ret = watchdog_register_device(&stmp3xxx_wdd);
+       ret = devm_watchdog_register_device(dev, &stmp3xxx_wdd);
        if (ret < 0) {
-               dev_err(&pdev->dev, "cannot register watchdog device\n");
+               dev_err(dev, "cannot register watchdog device\n");
                return ret;
        }
 
        if (register_reboot_notifier(&wdt_notifier))
-               dev_warn(&pdev->dev, "cannot register reboot notifier\n");
+               dev_warn(dev, "cannot register reboot notifier\n");
 
-       dev_info(&pdev->dev, "initialized watchdog with heartbeat %ds\n",
-                       stmp3xxx_wdd.timeout);
+       dev_info(dev, "initialized watchdog with heartbeat %ds\n",
+                stmp3xxx_wdd.timeout);
        return 0;
 }
 
 static int stmp3xxx_wdt_remove(struct platform_device *pdev)
 {
        unregister_reboot_notifier(&wdt_notifier);
-       watchdog_unregister_device(&stmp3xxx_wdd);
        return 0;
 }
 
index ad431d8ad95f704bc390a758fd38ab262d693126..45d0c543466fd20fbf1fdd5da44af5d33a10b979 100644 (file)
@@ -81,18 +81,19 @@ static const struct watchdog_ops pmic_watchdog_ops = {
 
 static int pmic_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        int ret;
        struct stpmic1 *pmic;
        struct stpmic1_wdt *wdt;
 
-       if (!pdev->dev.parent)
+       if (!dev->parent)
                return -EINVAL;
 
-       pmic = dev_get_drvdata(pdev->dev.parent);
+       pmic = dev_get_drvdata(dev->parent);
        if (!pmic)
                return -EINVAL;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(struct stpmic1_wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(struct stpmic1_wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
@@ -102,15 +103,15 @@ static int pmic_wdt_probe(struct platform_device *pdev)
        wdt->wdtdev.ops = &pmic_watchdog_ops;
        wdt->wdtdev.min_timeout = PMIC_WDT_MIN_TIMEOUT;
        wdt->wdtdev.max_timeout = PMIC_WDT_MAX_TIMEOUT;
-       wdt->wdtdev.parent = &pdev->dev;
+       wdt->wdtdev.parent = dev;
 
        wdt->wdtdev.timeout = PMIC_WDT_DEFAULT_TIMEOUT;
-       watchdog_init_timeout(&wdt->wdtdev, 0, &pdev->dev);
+       watchdog_init_timeout(&wdt->wdtdev, 0, dev);
 
        watchdog_set_nowayout(&wdt->wdtdev, nowayout);
        watchdog_set_drvdata(&wdt->wdtdev, wdt);
 
-       ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev);
+       ret = devm_watchdog_register_device(dev, &wdt->wdtdev);
        if (ret)
                return ret;
 
index c6c73656997efa933aaabb83ac23c7024b8b75ea..9c22f7753c6bbe8c0edd8a11af1650517aa9b265 100644 (file)
@@ -233,20 +233,19 @@ MODULE_DEVICE_TABLE(of, sunxi_wdt_dt_ids);
 
 static int sunxi_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct sunxi_wdt_dev *sunxi_wdt;
-       struct resource *res;
        int err;
 
-       sunxi_wdt = devm_kzalloc(&pdev->dev, sizeof(*sunxi_wdt), GFP_KERNEL);
+       sunxi_wdt = devm_kzalloc(dev, sizeof(*sunxi_wdt), GFP_KERNEL);
        if (!sunxi_wdt)
                return -EINVAL;
 
-       sunxi_wdt->wdt_regs = of_device_get_match_data(&pdev->dev);
+       sunxi_wdt->wdt_regs = of_device_get_match_data(dev);
        if (!sunxi_wdt->wdt_regs)
                return -ENODEV;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       sunxi_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res);
+       sunxi_wdt->wdt_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(sunxi_wdt->wdt_base))
                return PTR_ERR(sunxi_wdt->wdt_base);
 
@@ -255,9 +254,9 @@ static int sunxi_wdt_probe(struct platform_device *pdev)
        sunxi_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT;
        sunxi_wdt->wdt_dev.max_timeout = WDT_MAX_TIMEOUT;
        sunxi_wdt->wdt_dev.min_timeout = WDT_MIN_TIMEOUT;
-       sunxi_wdt->wdt_dev.parent = &pdev->dev;
+       sunxi_wdt->wdt_dev.parent = dev;
 
-       watchdog_init_timeout(&sunxi_wdt->wdt_dev, timeout, &pdev->dev);
+       watchdog_init_timeout(&sunxi_wdt->wdt_dev, timeout, dev);
        watchdog_set_nowayout(&sunxi_wdt->wdt_dev, nowayout);
        watchdog_set_restart_priority(&sunxi_wdt->wdt_dev, 128);
 
@@ -266,12 +265,12 @@ static int sunxi_wdt_probe(struct platform_device *pdev)
        sunxi_wdt_stop(&sunxi_wdt->wdt_dev);
 
        watchdog_stop_on_reboot(&sunxi_wdt->wdt_dev);
-       err = devm_watchdog_register_device(&pdev->dev, &sunxi_wdt->wdt_dev);
+       err = devm_watchdog_register_device(dev, &sunxi_wdt->wdt_dev);
        if (unlikely(err))
                return err;
 
-       dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)",
-                       sunxi_wdt->wdt_dev.timeout, nowayout);
+       dev_info(dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)",
+                sunxi_wdt->wdt_dev.timeout, nowayout);
 
        return 0;
 }
index d0b53f3c0d171ebaf8d796d371c31f36aa04a837..1afb0e9d808cf8a0a2e089117ee121c69def1582 100644 (file)
@@ -108,10 +108,14 @@ static const struct watchdog_ops tangox_wdt_ops = {
        .restart        = tangox_wdt_restart,
 };
 
+static void tangox_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int tangox_wdt_probe(struct platform_device *pdev)
 {
        struct tangox_wdt_device *dev;
-       struct resource *res;
        u32 config;
        int err;
 
@@ -119,8 +123,7 @@ static int tangox_wdt_probe(struct platform_device *pdev)
        if (!dev)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dev->base = devm_ioremap_resource(&pdev->dev, res);
+       dev->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(dev->base))
                return PTR_ERR(dev->base);
 
@@ -131,12 +134,14 @@ static int tangox_wdt_probe(struct platform_device *pdev)
        err = clk_prepare_enable(dev->clk);
        if (err)
                return err;
+       err = devm_add_action_or_reset(&pdev->dev,
+                                      tangox_clk_disable_unprepare, dev->clk);
+       if (err)
+               return err;
 
        dev->clk_rate = clk_get_rate(dev->clk);
-       if (!dev->clk_rate) {
-               err = -EINVAL;
-               goto err;
-       }
+       if (!dev->clk_rate)
+               return -EINVAL;
 
        dev->wdt.parent = &pdev->dev;
        dev->wdt.info = &tangox_wdt_info;
@@ -170,30 +175,15 @@ static int tangox_wdt_probe(struct platform_device *pdev)
 
        watchdog_set_restart_priority(&dev->wdt, 128);
 
-       err = watchdog_register_device(&dev->wdt);
+       watchdog_stop_on_unregister(&dev->wdt);
+       err = devm_watchdog_register_device(&pdev->dev, &dev->wdt);
        if (err)
-               goto err;
+               return err;
 
        platform_set_drvdata(pdev, dev);
 
        dev_info(&pdev->dev, "SMP86xx/SMP87xx watchdog registered\n");
 
-       return 0;
-
- err:
-       clk_disable_unprepare(dev->clk);
-       return err;
-}
-
-static int tangox_wdt_remove(struct platform_device *pdev)
-{
-       struct tangox_wdt_device *dev = platform_get_drvdata(pdev);
-
-       tangox_wdt_stop(&dev->wdt);
-       clk_disable_unprepare(dev->clk);
-
-       watchdog_unregister_device(&dev->wdt);
-
        return 0;
 }
 
@@ -206,7 +196,6 @@ MODULE_DEVICE_TABLE(of, tangox_wdt_dt_ids);
 
 static struct platform_driver tangox_wdt_driver = {
        .probe  = tangox_wdt_probe,
-       .remove = tangox_wdt_remove,
        .driver = {
                .name           = "tangox-wdt",
                .of_match_table = tangox_wdt_dt_ids,
index 877dd39bd41fc96ad26dcceb987597a453fff980..a58b000acc4f5a96b29c5e49f56fd4ef996c2577 100644 (file)
@@ -181,15 +181,14 @@ static const struct watchdog_ops tegra_wdt_ops = {
 
 static int tegra_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct watchdog_device *wdd;
        struct tegra_wdt *wdt;
-       struct resource *res;
        void __iomem *regs;
        int ret;
 
        /* This is the timer base. */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       regs = devm_ioremap_resource(&pdev->dev, res);
+       regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(regs))
                return PTR_ERR(regs);
 
@@ -197,7 +196,7 @@ static int tegra_wdt_probe(struct platform_device *pdev)
         * Allocate our watchdog driver data, which has the
         * struct watchdog_device nested within it.
         */
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
@@ -212,39 +211,27 @@ static int tegra_wdt_probe(struct platform_device *pdev)
        wdd->ops = &tegra_wdt_ops;
        wdd->min_timeout = MIN_WDT_TIMEOUT;
        wdd->max_timeout = MAX_WDT_TIMEOUT;
-       wdd->parent = &pdev->dev;
+       wdd->parent = dev;
 
        watchdog_set_drvdata(wdd, wdt);
 
        watchdog_set_nowayout(wdd, nowayout);
 
-       ret = devm_watchdog_register_device(&pdev->dev, wdd);
+       watchdog_stop_on_unregister(wdd);
+       ret = devm_watchdog_register_device(dev, wdd);
        if (ret) {
-               dev_err(&pdev->dev,
-                       "failed to register watchdog device\n");
+               dev_err(dev, "failed to register watchdog device\n");
                return ret;
        }
 
        platform_set_drvdata(pdev, wdt);
 
-       dev_info(&pdev->dev,
-                "initialized (heartbeat = %d sec, nowayout = %d)\n",
+       dev_info(dev, "initialized (heartbeat = %d sec, nowayout = %d)\n",
                 heartbeat, nowayout);
 
        return 0;
 }
 
-static int tegra_wdt_remove(struct platform_device *pdev)
-{
-       struct tegra_wdt *wdt = platform_get_drvdata(pdev);
-
-       tegra_wdt_stop(&wdt->wdd);
-
-       dev_info(&pdev->dev, "removed wdt\n");
-
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int tegra_wdt_runtime_suspend(struct device *dev)
 {
@@ -280,7 +267,6 @@ static const struct dev_pm_ops tegra_wdt_pm_ops = {
 
 static struct platform_driver tegra_wdt_driver = {
        .probe          = tegra_wdt_probe,
-       .remove         = tegra_wdt_remove,
        .driver         = {
                .name   = "tegra-wdt",
                .pm     = &tegra_wdt_pm_ops,
index 52941207a12aba71ea1694b23c1c5765d3a56b8b..72d0b0adde3889e0c014e3a8197d2083e5ee3e23 100644 (file)
@@ -70,11 +70,12 @@ static struct watchdog_ops tqmx86_wdt_ops = {
 
 static int tqmx86_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct tqmx86_wdt *priv;
        struct resource *res;
        int err;
 
-       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
@@ -82,14 +83,13 @@ static int tqmx86_wdt_probe(struct platform_device *pdev)
        if (!res)
                return -ENODEV;
 
-       priv->io_base = devm_ioport_map(&pdev->dev, res->start,
-                                       resource_size(res));
+       priv->io_base = devm_ioport_map(dev, res->start, resource_size(res));
        if (!priv->io_base)
                return -ENOMEM;
 
        watchdog_set_drvdata(&priv->wdd, priv);
 
-       priv->wdd.parent = &pdev->dev;
+       priv->wdd.parent = dev;
        priv->wdd.info = &tqmx86_wdt_info;
        priv->wdd.ops = &tqmx86_wdt_ops;
        priv->wdd.min_timeout = 1;
@@ -97,16 +97,16 @@ static int tqmx86_wdt_probe(struct platform_device *pdev)
        priv->wdd.max_hw_heartbeat_ms = 4096*1000;
        priv->wdd.timeout = WDT_TIMEOUT;
 
-       watchdog_init_timeout(&priv->wdd, timeout, &pdev->dev);
+       watchdog_init_timeout(&priv->wdd, timeout, dev);
        watchdog_set_nowayout(&priv->wdd, WATCHDOG_NOWAYOUT);
 
        tqmx86_wdt_set_timeout(&priv->wdd, priv->wdd.timeout);
 
-       err = devm_watchdog_register_device(&pdev->dev, &priv->wdd);
+       err = devm_watchdog_register_device(dev, &priv->wdd);
        if (err)
                return err;
 
-       dev_info(&pdev->dev, "TQMx86 watchdog\n");
+       dev_info(dev, "TQMx86 watchdog\n");
 
        return 0;
 }
index 89843b16b04acca00fca086e0af14cbab80c2fec..9dc6d7f45806dd2385df95c1b8a37a120cd15995 100644 (file)
@@ -108,7 +108,8 @@ static const struct watchdog_info ts4800_wdt_info = {
 
 static int ts4800_wdt_probe(struct platform_device *pdev)
 {
-       struct device_node *np = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
        struct device_node *syscon_np;
        struct watchdog_device *wdd;
        struct ts4800_wdt *wdt;
@@ -117,18 +118,18 @@ static int ts4800_wdt_probe(struct platform_device *pdev)
 
        syscon_np = of_parse_phandle(np, "syscon", 0);
        if (!syscon_np) {
-               dev_err(&pdev->dev, "no syscon property\n");
+               dev_err(dev, "no syscon property\n");
                return -ENODEV;
        }
 
        ret = of_property_read_u32_index(np, "syscon", 1, &reg);
        if (ret < 0) {
-               dev_err(&pdev->dev, "no offset in syscon\n");
+               dev_err(dev, "no offset in syscon\n");
                return ret;
        }
 
        /* allocate memory for watchdog struct */
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
@@ -137,13 +138,13 @@ static int ts4800_wdt_probe(struct platform_device *pdev)
        wdt->regmap = syscon_node_to_regmap(syscon_np);
        of_node_put(syscon_np);
        if (IS_ERR(wdt->regmap)) {
-               dev_err(&pdev->dev, "cannot get parent's regmap\n");
+               dev_err(dev, "cannot get parent's regmap\n");
                return PTR_ERR(wdt->regmap);
        }
 
        /* Initialize struct watchdog_device */
        wdd = &wdt->wdd;
-       wdd->parent = &pdev->dev;
+       wdd->parent = dev;
        wdd->info = &ts4800_wdt_info;
        wdd->ops = &ts4800_wdt_ops;
        wdd->min_timeout = ts4800_wdt_map[0].timeout;
@@ -151,7 +152,7 @@ static int ts4800_wdt_probe(struct platform_device *pdev)
 
        watchdog_set_drvdata(wdd, wdt);
        watchdog_set_nowayout(wdd, nowayout);
-       watchdog_init_timeout(wdd, 0, &pdev->dev);
+       watchdog_init_timeout(wdd, 0, dev);
 
        /*
         * As this watchdog supports only a few values, ts4800_wdt_set_timeout
@@ -169,31 +170,20 @@ static int ts4800_wdt_probe(struct platform_device *pdev)
         */
        ts4800_wdt_stop(wdd);
 
-       ret = watchdog_register_device(wdd);
+       ret = devm_watchdog_register_device(dev, wdd);
        if (ret) {
-               dev_err(&pdev->dev,
-                       "failed to register watchdog device\n");
+               dev_err(dev, "failed to register watchdog device\n");
                return ret;
        }
 
        platform_set_drvdata(pdev, wdt);
 
-       dev_info(&pdev->dev,
-                "initialized (timeout = %d sec, nowayout = %d)\n",
+       dev_info(dev, "initialized (timeout = %d sec, nowayout = %d)\n",
                 wdd->timeout, nowayout);
 
        return 0;
 }
 
-static int ts4800_wdt_remove(struct platform_device *pdev)
-{
-       struct ts4800_wdt *wdt = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&wdt->wdd);
-
-       return 0;
-}
-
 static const struct of_device_id ts4800_wdt_of_match[] = {
        { .compatible = "technologic,ts4800-wdt", },
        { },
@@ -202,7 +192,6 @@ MODULE_DEVICE_TABLE(of, ts4800_wdt_of_match);
 
 static struct platform_driver ts4800_wdt_driver = {
        .probe          = ts4800_wdt_probe,
-       .remove         = ts4800_wdt_remove,
        .driver         = {
                .name   = "ts4800_wdt",
                .of_match_table = ts4800_wdt_of_match,
index 811e43c39ec4e0322f4b98db7175c8ce1a3538de..bf918f5fa13175fca6e36154a649616d60a47330 100644 (file)
@@ -122,22 +122,20 @@ static const struct watchdog_ops ts72xx_wdt_ops = {
 
 static int ts72xx_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct ts72xx_wdt_priv *priv;
        struct watchdog_device *wdd;
-       struct resource *res;
        int ret;
 
-       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->control_reg = devm_ioremap_resource(&pdev->dev, res);
+       priv->control_reg = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->control_reg))
                return PTR_ERR(priv->control_reg);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       priv->feed_reg = devm_ioremap_resource(&pdev->dev, res);
+       priv->feed_reg = devm_platform_ioremap_resource(pdev, 1);
        if (IS_ERR(priv->feed_reg))
                return PTR_ERR(priv->feed_reg);
 
@@ -146,20 +144,20 @@ static int ts72xx_wdt_probe(struct platform_device *pdev)
        wdd->ops = &ts72xx_wdt_ops;
        wdd->min_timeout = 1;
        wdd->max_hw_heartbeat_ms = 8000;
-       wdd->parent = &pdev->dev;
+       wdd->parent = dev;
 
        watchdog_set_nowayout(wdd, nowayout);
 
        wdd->timeout = TS72XX_WDT_DEFAULT_TIMEOUT;
-       watchdog_init_timeout(wdd, timeout, &pdev->dev);
+       watchdog_init_timeout(wdd, timeout, dev);
 
        watchdog_set_drvdata(wdd, priv);
 
-       ret = devm_watchdog_register_device(&pdev->dev, wdd);
+       ret = devm_watchdog_register_device(dev, wdd);
        if (ret)
                return ret;
 
-       dev_info(&pdev->dev, "TS-72xx Watchdog driver\n");
+       dev_info(dev, "TS-72xx Watchdog driver\n");
 
        return 0;
 }
index 569fe85e52da75363e7a3b7f3239745521b9b7ff..74c5737cd934a00d3bc90ece5d05177c6dcd45ab 100644 (file)
@@ -70,10 +70,10 @@ static const struct watchdog_ops twl4030_wdt_ops = {
 
 static int twl4030_wdt_probe(struct platform_device *pdev)
 {
-       int ret = 0;
+       struct device *dev = &pdev->dev;
        struct watchdog_device *wdt;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
@@ -83,27 +83,14 @@ static int twl4030_wdt_probe(struct platform_device *pdev)
        wdt->timeout            = 30;
        wdt->min_timeout        = 1;
        wdt->max_timeout        = 30;
-       wdt->parent = &pdev->dev;
+       wdt->parent = dev;
 
        watchdog_set_nowayout(wdt, nowayout);
        platform_set_drvdata(pdev, wdt);
 
        twl4030_wdt_stop(wdt);
 
-       ret = watchdog_register_device(wdt);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static int twl4030_wdt_remove(struct platform_device *pdev)
-{
-       struct watchdog_device *wdt = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(wdt);
-
-       return 0;
+       return devm_watchdog_register_device(dev, wdt);
 }
 
 #ifdef CONFIG_PM
@@ -137,7 +124,6 @@ MODULE_DEVICE_TABLE(of, twl_wdt_of_match);
 
 static struct platform_driver twl4030_wdt_driver = {
        .probe          = twl4030_wdt_probe,
-       .remove         = twl4030_wdt_remove,
        .suspend        = twl4030_wdt_suspend,
        .resume         = twl4030_wdt_resume,
        .driver         = {
index 6f7a9deb27d05d25d9a261d9c69460c2dccb9528..fcb4da5b1f4c55558ba77fceb643761e8cc6bf40 100644 (file)
@@ -103,7 +103,6 @@ static struct watchdog_device txx9wdt = {
 
 static int __init txx9wdt_probe(struct platform_device *dev)
 {
-       struct resource *res;
        int ret;
 
        txx9_imclk = clk_get(NULL, "imbus_clk");
@@ -119,8 +118,7 @@ static int __init txx9wdt_probe(struct platform_device *dev)
                goto exit;
        }
 
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       txx9wdt_reg = devm_ioremap_resource(&dev->dev, res);
+       txx9wdt_reg = devm_platform_ioremap_resource(dev, 0);
        if (IS_ERR(txx9wdt_reg)) {
                ret = PTR_ERR(txx9wdt_reg);
                goto exit;
index e20a7a459d69eb41ee555134f5cca17f5d50f4a2..8e9242c2302222155094542461117d4f10068d0a 100644 (file)
@@ -191,8 +191,6 @@ static int uniphier_wdt_probe(struct platform_device *pdev)
        if (!wdev)
                return -ENOMEM;
 
-       platform_set_drvdata(pdev, wdev);
-
        parent = of_get_parent(dev->of_node); /* parent should be syscon node */
        regmap = syscon_node_to_regmap(parent);
        of_node_put(parent);
index 37c084353cce238f4e694a1be1520727530503c7..9fa7f95f75548ee6e60908c336df146d296706ee 100644 (file)
@@ -86,8 +86,9 @@ static struct watchdog_device ux500_wdt = {
 
 static int ux500_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        int ret;
-       struct ux500_wdt_data *pdata = dev_get_platdata(&pdev->dev);
+       struct ux500_wdt_data *pdata = dev_get_platdata(dev);
 
        if (pdata) {
                if (pdata->timeout > 0)
@@ -96,7 +97,7 @@ static int ux500_wdt_probe(struct platform_device *pdev)
                        ux500_wdt.max_timeout = WATCHDOG_MAX28;
        }
 
-       ux500_wdt.parent = &pdev->dev;
+       ux500_wdt.parent = dev;
        watchdog_set_nowayout(&ux500_wdt, nowayout);
 
        /* disable auto off on sleep */
@@ -105,18 +106,11 @@ static int ux500_wdt_probe(struct platform_device *pdev)
        /* set HW initial value */
        prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
 
-       ret = watchdog_register_device(&ux500_wdt);
+       ret = devm_watchdog_register_device(dev, &ux500_wdt);
        if (ret)
                return ret;
 
-       dev_info(&pdev->dev, "initialized\n");
-
-       return 0;
-}
-
-static int ux500_wdt_remove(struct platform_device *dev)
-{
-       watchdog_unregister_device(&ux500_wdt);
+       dev_info(dev, "initialized\n");
 
        return 0;
 }
@@ -153,7 +147,6 @@ static int ux500_wdt_resume(struct platform_device *pdev)
 
 static struct platform_driver ux500_wdt_driver = {
        .probe          = ux500_wdt_probe,
-       .remove         = ux500_wdt_remove,
        .suspend        = ux500_wdt_suspend,
        .resume         = ux500_wdt_resume,
        .driver         = {
index eb8fa25f8eb2957951195ec2ad0e94afb22f2319..62be9e52a4deaa30427fcb99ecee3ba899b2f4ce 100644 (file)
@@ -105,34 +105,48 @@ static void watchdog_check_min_max_timeout(struct watchdog_device *wdd)
  * timeout module parameter (if it is valid value) or the timeout-sec property
  * (only if it is a valid value and the timeout_parm is out of bounds).
  * If none of them are valid then we keep the old value (which should normally
- * be the default timeout value).
+ * be the default timeout value). Note that for the module parameter, '0' means
+ * 'use default' while it is an invalid value for the timeout-sec property.
+ * It should simply be dropped if you want to use the default value then.
  *
- * A zero is returned on success and -EINVAL for failure.
+ * A zero is returned on success or -EINVAL if all provided values are out of
+ * bounds.
  */
 int watchdog_init_timeout(struct watchdog_device *wdd,
                                unsigned int timeout_parm, struct device *dev)
 {
+       const char *dev_str = wdd->parent ? dev_name(wdd->parent) :
+                             (const char *)wdd->info->identity;
        unsigned int t = 0;
        int ret = 0;
 
        watchdog_check_min_max_timeout(wdd);
 
-       /* try to get the timeout module parameter first */
-       if (!watchdog_timeout_invalid(wdd, timeout_parm) && timeout_parm) {
-               wdd->timeout = timeout_parm;
-               return ret;
-       }
-       if (timeout_parm)
+       /* check the driver supplied value (likely a module parameter) first */
+       if (timeout_parm) {
+               if (!watchdog_timeout_invalid(wdd, timeout_parm)) {
+                       wdd->timeout = timeout_parm;
+                       return 0;
+               }
+               pr_err("%s: driver supplied timeout (%u) out of range\n",
+                       dev_str, timeout_parm);
                ret = -EINVAL;
+       }
 
        /* try to get the timeout_sec property */
-       if (dev == NULL || dev->of_node == NULL)
-               return ret;
-       of_property_read_u32(dev->of_node, "timeout-sec", &t);
-       if (!watchdog_timeout_invalid(wdd, t) && t)
-               wdd->timeout = t;
-       else
+       if (dev && dev->of_node &&
+           of_property_read_u32(dev->of_node, "timeout-sec", &t) == 0) {
+               if (t && !watchdog_timeout_invalid(wdd, t)) {
+                       wdd->timeout = t;
+                       return 0;
+               }
+               pr_err("%s: DT supplied timeout (%u) out of range\n", dev_str, t);
                ret = -EINVAL;
+       }
+
+       if (ret < 0 && wdd->timeout)
+               pr_warn("%s: falling back to default timeout (%u)\n", dev_str,
+                       wdd->timeout);
 
        return ret;
 }
index 56ad19608a9bed0ae43ffaa87e59c71ee85d104e..430ee4e9b1853fc2eaec8612b5a0a9e85197d928 100644 (file)
@@ -287,7 +287,7 @@ static unsigned int wdat_wdt_get_timeleft(struct watchdog_device *wdd)
        struct wdat_wdt *wdat = to_wdat_wdt(wdd);
        u32 periods = 0;
 
-       wdat_wdt_run_action(wdat, ACPI_WDAT_GET_COUNTDOWN, 0, &periods);
+       wdat_wdt_run_action(wdat, ACPI_WDAT_GET_CURRENT_COUNTDOWN, 0, &periods);
        return periods * wdat->period / 1000;
 }
 
@@ -308,6 +308,7 @@ static const struct watchdog_ops wdat_wdt_ops = {
 
 static int wdat_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        const struct acpi_wdat_entry *entries;
        const struct acpi_table_wdat *tbl;
        struct wdat_wdt *wdat;
@@ -321,11 +322,11 @@ static int wdat_wdt_probe(struct platform_device *pdev)
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
-       wdat = devm_kzalloc(&pdev->dev, sizeof(*wdat), GFP_KERNEL);
+       wdat = devm_kzalloc(dev, sizeof(*wdat), GFP_KERNEL);
        if (!wdat)
                return -ENOMEM;
 
-       regs = devm_kcalloc(&pdev->dev, pdev->num_resources, sizeof(*regs),
+       regs = devm_kcalloc(dev, pdev->num_resources, sizeof(*regs),
                            GFP_KERNEL);
        if (!regs)
                return -ENOMEM;
@@ -350,15 +351,15 @@ static int wdat_wdt_probe(struct platform_device *pdev)
 
                res = &pdev->resource[i];
                if (resource_type(res) == IORESOURCE_MEM) {
-                       reg = devm_ioremap_resource(&pdev->dev, res);
+                       reg = devm_ioremap_resource(dev, res);
                        if (IS_ERR(reg))
                                return PTR_ERR(reg);
                } else if (resource_type(res) == IORESOURCE_IO) {
-                       reg = devm_ioport_map(&pdev->dev, res->start, 1);
+                       reg = devm_ioport_map(dev, res->start, 1);
                        if (!reg)
                                return -ENOMEM;
                } else {
-                       dev_err(&pdev->dev, "Unsupported resource\n");
+                       dev_err(dev, "Unsupported resource\n");
                        return -EINVAL;
                }
 
@@ -376,12 +377,11 @@ static int wdat_wdt_probe(struct platform_device *pdev)
 
                action = entries[i].action;
                if (action >= MAX_WDAT_ACTIONS) {
-                       dev_dbg(&pdev->dev, "Skipping unknown action: %u\n",
-                               action);
+                       dev_dbg(dev, "Skipping unknown action: %u\n", action);
                        continue;
                }
 
-               instr = devm_kzalloc(&pdev->dev, sizeof(*instr), GFP_KERNEL);
+               instr = devm_kzalloc(dev, sizeof(*instr), GFP_KERNEL);
                if (!instr)
                        return -ENOMEM;
 
@@ -398,7 +398,7 @@ static int wdat_wdt_probe(struct platform_device *pdev)
                } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
                        r.flags = IORESOURCE_IO;
                } else {
-                       dev_dbg(&pdev->dev, "Unsupported address space: %d\n",
+                       dev_dbg(dev, "Unsupported address space: %d\n",
                                gas->space_id);
                        continue;
                }
@@ -413,14 +413,15 @@ static int wdat_wdt_probe(struct platform_device *pdev)
                }
 
                if (!instr->reg) {
-                       dev_err(&pdev->dev, "I/O resource not found\n");
+                       dev_err(dev, "I/O resource not found\n");
                        return -EINVAL;
                }
 
                instructions = wdat->instructions[action];
                if (!instructions) {
-                       instructions = devm_kzalloc(&pdev->dev,
-                                       sizeof(*instructions), GFP_KERNEL);
+                       instructions = devm_kzalloc(dev,
+                                                   sizeof(*instructions),
+                                                   GFP_KERNEL);
                        if (!instructions)
                                return -ENOMEM;
 
@@ -441,7 +442,7 @@ static int wdat_wdt_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, wdat);
 
        watchdog_set_nowayout(&wdat->wdd, nowayout);
-       return devm_watchdog_register_device(&pdev->dev, &wdat->wdd);
+       return devm_watchdog_register_device(dev, &wdat->wdd);
 }
 
 #ifdef CONFIG_PM_SLEEP
index 116c2f47b4637e2cf95eca8b9df0709af96fbd0f..9b6565a3fab40cc314bbeef0c9bb915bdd484788 100644 (file)
@@ -180,8 +180,9 @@ static const struct watchdog_ops wm831x_wdt_ops = {
 
 static int wm831x_wdt_probe(struct platform_device *pdev)
 {
-       struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-       struct wm831x_pdata *chip_pdata = dev_get_platdata(pdev->dev.parent);
+       struct device *dev = &pdev->dev;
+       struct wm831x *wm831x = dev_get_drvdata(dev->parent);
+       struct wm831x_pdata *chip_pdata = dev_get_platdata(dev->parent);
        struct wm831x_watchdog_pdata *pdata;
        struct wm831x_wdt_drvdata *driver_data;
        struct watchdog_device *wm831x_wdt;
@@ -198,8 +199,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
        if (reg & WM831X_WDOG_DEBUG)
                dev_warn(wm831x->dev, "Watchdog is paused\n");
 
-       driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
-                                  GFP_KERNEL);
+       driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);
        if (!driver_data)
                return -ENOMEM;
 
@@ -210,7 +210,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
 
        wm831x_wdt->info = &wm831x_wdt_info;
        wm831x_wdt->ops = &wm831x_wdt_ops;
-       wm831x_wdt->parent = &pdev->dev;
+       wm831x_wdt->parent = dev;
        watchdog_set_nowayout(wm831x_wdt, nowayout);
        watchdog_set_drvdata(wm831x_wdt, driver_data);
 
@@ -240,10 +240,9 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
                reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT;
 
                if (pdata->update_gpio) {
-                       ret = devm_gpio_request_one(&pdev->dev,
-                                               pdata->update_gpio,
-                                               GPIOF_OUT_INIT_LOW,
-                                               "Watchdog update");
+                       ret = devm_gpio_request_one(dev, pdata->update_gpio,
+                                                   GPIOF_OUT_INIT_LOW,
+                                                   "Watchdog update");
                        if (ret < 0) {
                                dev_err(wm831x->dev,
                                        "Failed to request update GPIO: %d\n",
@@ -268,7 +267,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
                }
        }
 
-       ret = devm_watchdog_register_device(&pdev->dev, &driver_data->wdt);
+       ret = devm_watchdog_register_device(dev, &driver_data->wdt);
        if (ret != 0) {
                dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n",
                        ret);
index f1c016d015b3bff4297ce7d245c92f89c14239a5..25a1af5e1787e198901b8b0bbdc897288c2fa518 100644 (file)
@@ -122,35 +122,33 @@ static struct watchdog_device xen_wdt_dev = {
 
 static int xen_wdt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct sched_watchdog wd = { .id = ~0 };
        int ret = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wd);
 
        if (ret == -ENOSYS) {
-               dev_err(&pdev->dev, "watchdog not supported by hypervisor\n");
+               dev_err(dev, "watchdog not supported by hypervisor\n");
                return -ENODEV;
        }
 
        if (ret != -EINVAL) {
-               dev_err(&pdev->dev, "unexpected hypervisor error (%d)\n", ret);
+               dev_err(dev, "unexpected hypervisor error (%d)\n", ret);
                return -ENODEV;
        }
 
-       if (watchdog_init_timeout(&xen_wdt_dev, timeout, NULL))
-               dev_info(&pdev->dev, "timeout value invalid, using %d\n",
-                       xen_wdt_dev.timeout);
+       watchdog_init_timeout(&xen_wdt_dev, timeout, NULL);
        watchdog_set_nowayout(&xen_wdt_dev, nowayout);
        watchdog_stop_on_reboot(&xen_wdt_dev);
        watchdog_stop_on_unregister(&xen_wdt_dev);
 
-       ret = devm_watchdog_register_device(&pdev->dev, &xen_wdt_dev);
+       ret = devm_watchdog_register_device(dev, &xen_wdt_dev);
        if (ret) {
-               dev_err(&pdev->dev, "cannot register watchdog device (%d)\n",
-                       ret);
+               dev_err(dev, "cannot register watchdog device (%d)\n", ret);
                return ret;
        }
 
-       dev_info(&pdev->dev, "initialized (timeout=%ds, nowayout=%d)\n",
-               xen_wdt_dev.timeout, nowayout);
+       dev_info(dev, "initialized (timeout=%ds, nowayout=%d)\n",
+                xen_wdt_dev.timeout, nowayout);
 
        return 0;
 }
index d3594aa3a3743dea1f67878a38bee4d75d43ce85..43e6b575c32c7ace3faf2f7190f92e1d2f963cb2 100644 (file)
@@ -658,11 +658,7 @@ static int ziirave_wdt_probe(struct i2c_client *client,
        w_priv->wdd.parent = &client->dev;
        w_priv->wdd.groups = ziirave_wdt_groups;
 
-       ret = watchdog_init_timeout(&w_priv->wdd, wdt_timeout, &client->dev);
-       if (ret) {
-               dev_info(&client->dev,
-                        "Unable to select timeout value, using default\n");
-       }
+       watchdog_init_timeout(&w_priv->wdd, wdt_timeout, &client->dev);
 
        /*
         * The default value set in the watchdog should be perfectly valid, so
index 9261f7c77f6de111006fe2f373f51dead5b50df1..c8549bf07cc9a4f3f7614981878fd731e0835df3 100644 (file)
@@ -188,11 +188,15 @@ static void zx2967_wdt_reset_sysctrl(struct device *dev)
        of_node_put(out_args.np);
 }
 
+static void zx2967_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int zx2967_wdt_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct zx2967_wdt *wdt;
-       struct resource *base;
        int ret;
        struct reset_control *rstc;
 
@@ -207,10 +211,9 @@ static int zx2967_wdt_probe(struct platform_device *pdev)
        wdt->wdt_device.timeout = ZX2967_WDT_DEFAULT_TIMEOUT;
        wdt->wdt_device.max_timeout = ZX2967_WDT_MAX_TIMEOUT;
        wdt->wdt_device.min_timeout = ZX2967_WDT_MIN_TIMEOUT;
-       wdt->wdt_device.parent = &pdev->dev;
+       wdt->wdt_device.parent = dev;
 
-       base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->reg_base = devm_ioremap_resource(dev, base);
+       wdt->reg_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->reg_base))
                return PTR_ERR(wdt->reg_base);
 
@@ -227,13 +230,16 @@ static int zx2967_wdt_probe(struct platform_device *pdev)
                dev_err(dev, "failed to enable clock\n");
                return ret;
        }
+       ret = devm_add_action_or_reset(dev, zx2967_clk_disable_unprepare,
+                                      wdt->clock);
+       if (ret)
+               return ret;
        clk_set_rate(wdt->clock, ZX2967_WDT_CLK_FREQ);
 
        rstc = devm_reset_control_get_exclusive(dev, NULL);
        if (IS_ERR(rstc)) {
                dev_err(dev, "failed to get rstc");
-               ret = PTR_ERR(rstc);
-               goto err;
+               return PTR_ERR(rstc);
        }
 
        reset_control_assert(rstc);
@@ -244,28 +250,14 @@ static int zx2967_wdt_probe(struct platform_device *pdev)
                        ZX2967_WDT_DEFAULT_TIMEOUT, dev);
        watchdog_set_nowayout(&wdt->wdt_device, WATCHDOG_NOWAYOUT);
 
-       ret = watchdog_register_device(&wdt->wdt_device);
+       ret = devm_watchdog_register_device(dev, &wdt->wdt_device);
        if (ret)
-               goto err;
+               return ret;
 
        dev_info(dev, "watchdog enabled (timeout=%d sec, nowayout=%d)",
                 wdt->wdt_device.timeout, WATCHDOG_NOWAYOUT);
 
        return 0;
-
-err:
-       clk_disable_unprepare(wdt->clock);
-       return ret;
-}
-
-static int zx2967_wdt_remove(struct platform_device *pdev)
-{
-       struct zx2967_wdt *wdt = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&wdt->wdt_device);
-       clk_disable_unprepare(wdt->clock);
-
-       return 0;
 }
 
 static const struct of_device_id zx2967_wdt_match[] = {
@@ -276,7 +268,6 @@ MODULE_DEVICE_TABLE(of, zx2967_wdt_match);
 
 static struct platform_driver zx2967_wdt_driver = {
        .probe          = zx2967_wdt_probe,
-       .remove         = zx2967_wdt_remove,
        .driver         = {
                .name   = "zx2967-wdt",
                .of_match_table = of_match_ptr(zx2967_wdt_match),
index 7cf9c51318aa0d8a970d703a7acd04135b7e5c85..469dfbd6cf90fb623af99c790be967e7127851eb 100644 (file)
@@ -526,20 +526,20 @@ static int mn_invl_range_start(struct mmu_notifier *mn,
        struct gntdev_grant_map *map;
        int ret = 0;
 
-       if (range->blockable)
+       if (mmu_notifier_range_blockable(range))
                mutex_lock(&priv->lock);
        else if (!mutex_trylock(&priv->lock))
                return -EAGAIN;
 
        list_for_each_entry(map, &priv->maps, next) {
                ret = unmap_if_in_range(map, range->start, range->end,
-                                       range->blockable);
+                                       mmu_notifier_range_blockable(range));
                if (ret)
                        goto out_unlock;
        }
        list_for_each_entry(map, &priv->freeable_maps, next) {
                ret = unmap_if_in_range(map, range->start, range->end,
-                                       range->blockable);
+                                       mmu_notifier_range_blockable(range));
                if (ret)
                        goto out_unlock;
        }
@@ -852,7 +852,7 @@ static int gntdev_get_page(struct gntdev_copy_batch *batch, void __user *virt,
        unsigned long xen_pfn;
        int ret;
 
-       ret = get_user_pages_fast(addr, 1, writeable, &page);
+       ret = get_user_pages_fast(addr, 1, writeable ? FOLL_WRITE : 0, &page);
        if (ret < 0)
                return ret;
 
@@ -1084,7 +1084,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
        int index = vma->vm_pgoff;
        int count = vma_pages(vma);
        struct gntdev_grant_map *map;
-       int i, err = -EINVAL;
+       int err = -EINVAL;
 
        if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED))
                return -EINVAL;
@@ -1145,12 +1145,9 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
                goto out_put_map;
 
        if (!use_ptemod) {
-               for (i = 0; i < count; i++) {
-                       err = vm_insert_page(vma, vma->vm_start + i*PAGE_SIZE,
-                               map->pages[i]);
-                       if (err)
-                               goto out_put_map;
-               }
+               err = vm_map_pages(vma, map->pages, map->count);
+               if (err)
+                       goto out_put_map;
        } else {
 #ifdef CONFIG_X86
                /*
index a1c61e351d3f7ee5cb8e82ba4a391559e6a8aef2..dd5bbb6e1b6b9d1033ae2bdbe60af5ca1de3e0de 100644 (file)
@@ -165,12 +165,8 @@ static int privcmd_buf_mmap(struct file *file, struct vm_area_struct *vma)
        if (vma_priv->n_pages != count)
                ret = -ENOMEM;
        else
-               for (i = 0; i < vma_priv->n_pages; i++) {
-                       ret = vm_insert_page(vma, vma->vm_start + i * PAGE_SIZE,
-                                            vma_priv->pages[i]);
-                       if (ret)
-                               break;
-               }
+               ret = vm_map_pages_zero(vma, vma_priv->pages,
+                                               vma_priv->n_pages);
 
        if (ret)
                privcmd_buf_vmapriv_free(vma_priv);
index 23f7f6ec7d1f12f431b43be29437032c55f171ff..833b2d2c4318f5f60d0b319a166ec721335ca81d 100644 (file)
@@ -697,7 +697,7 @@ static int xen_pcibk_xenbus_probe(struct xenbus_device *dev,
        /* We need to force a call to our callback here in case
         * xend already configured us!
         */
-       xen_pcibk_be_watch(&pdev->be_watch, NULL, 0);
+       xen_pcibk_be_watch(&pdev->be_watch, NULL, NULL);
 
 out:
        return err;
index 0782ff3c227352e7b92b595960cc62aee5c2c4ce..faf452d0edf0262198bad7519b25450ef815efb0 100644 (file)
@@ -465,7 +465,6 @@ static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u)
        struct watch_adapter *watch;
        char *path, *token;
        int err, rc;
-       LIST_HEAD(staging_q);
 
        path = u->u.buffer + sizeof(u->u.msg);
        token = memchr(path, 0, u->u.msg.len);
@@ -523,7 +522,6 @@ static ssize_t xenbus_file_write(struct file *filp,
        uint32_t msg_type;
        int rc = len;
        int ret;
-       LIST_HEAD(staging_q);
 
        /*
         * We're expecting usermode to be writing properly formed
index 967db336d11ae016324f4f15d7cbd33b809045c2..9eaff55df7b43ee490187b629856a4f35be6a46f 100644 (file)
@@ -251,7 +251,7 @@ struct afs_vlserver_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry
        _enter("%s", cell->name);
 
        ret = dns_query("afsdb", cell->name, cell->name_len, "srv=1",
-                       &result, _expiry);
+                       &result, _expiry, true);
        if (ret < 0) {
                _leave(" = %d [dns]", ret);
                return ERR_PTR(ret);
index d12ffb457e4745809460707c02176d2e4a657e4b..3f4e460c6655ab3e259d7e17e6b6bbe8dfdb0036 100644 (file)
@@ -23,6 +23,9 @@
 #define AFSPATHMAX             1024    /* Maximum length of a pathname plus NUL */
 #define AFSOPAQUEMAX           1024    /* Maximum length of an opaque field */
 
+#define AFS_VL_MAX_LIFESPAN    (120 * HZ)
+#define AFS_PROBE_MAX_LIFESPAN (30 * HZ)
+
 typedef u64                    afs_volid_t;
 typedef u64                    afs_vnodeid_t;
 typedef u64                    afs_dataversion_t;
@@ -69,8 +72,8 @@ typedef enum {
 
 struct afs_callback {
        time64_t                expires_at;     /* Time at which expires */
-       unsigned                version;        /* Callback version */
-       afs_callback_type_t     type;           /* Type of callback */
+       //unsigned              version;        /* Callback version */
+       //afs_callback_type_t   type;           /* Type of callback */
 };
 
 struct afs_callback_break {
@@ -144,6 +147,15 @@ struct afs_file_status {
        u32                     abort_code;     /* Abort if bulk-fetching this failed */
 };
 
+struct afs_status_cb {
+       struct afs_file_status  status;
+       struct afs_callback     callback;
+       unsigned int            cb_break;       /* Pre-op callback break counter */
+       bool                    have_status;    /* True if status record was retrieved */
+       bool                    have_cb;        /* True if cb record was retrieved */
+       bool                    have_error;     /* True if status.abort_code indicates an error */
+};
+
 /*
  * AFS file status change request
  */
index 128f2dbe256a4eb0f6124294f883b29d8a57e10e..d441bef72163289cfcde8ceff2d3271438d2c0f9 100644 (file)
@@ -94,15 +94,15 @@ int afs_register_server_cb_interest(struct afs_vnode *vnode,
        struct afs_server *server = entry->server;
 
 again:
-       if (vnode->cb_interest &&
-           likely(vnode->cb_interest == entry->cb_interest))
+       vcbi = rcu_dereference_protected(vnode->cb_interest,
+                                        lockdep_is_held(&vnode->io_lock));
+       if (vcbi && likely(vcbi == entry->cb_interest))
                return 0;
 
        read_lock(&slist->lock);
        cbi = afs_get_cb_interest(entry->cb_interest);
        read_unlock(&slist->lock);
 
-       vcbi = vnode->cb_interest;
        if (vcbi) {
                if (vcbi == cbi) {
                        afs_put_cb_interest(afs_v2net(vnode), cbi);
@@ -114,8 +114,9 @@ again:
                 */
                if (cbi && vcbi->server == cbi->server) {
                        write_seqlock(&vnode->cb_lock);
-                       old = vnode->cb_interest;
-                       vnode->cb_interest = cbi;
+                       old = rcu_dereference_protected(vnode->cb_interest,
+                                                       lockdep_is_held(&vnode->cb_lock.lock));
+                       rcu_assign_pointer(vnode->cb_interest, cbi);
                        write_sequnlock(&vnode->cb_lock);
                        afs_put_cb_interest(afs_v2net(vnode), old);
                        return 0;
@@ -160,8 +161,9 @@ again:
         */
        write_seqlock(&vnode->cb_lock);
 
-       old = vnode->cb_interest;
-       vnode->cb_interest = cbi;
+       old = rcu_dereference_protected(vnode->cb_interest,
+                                       lockdep_is_held(&vnode->cb_lock.lock));
+       rcu_assign_pointer(vnode->cb_interest, cbi);
        vnode->cb_s_break = cbi->server->cb_s_break;
        vnode->cb_v_break = vnode->volume->cb_v_break;
        clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
@@ -191,10 +193,11 @@ void afs_put_cb_interest(struct afs_net *net, struct afs_cb_interest *cbi)
                                vi = NULL;
 
                        write_unlock(&cbi->server->cb_break_lock);
-                       kfree(vi);
+                       if (vi)
+                               kfree_rcu(vi, rcu);
                        afs_put_server(net, cbi->server);
                }
-               kfree(cbi);
+               kfree_rcu(cbi, rcu);
        }
 }
 
@@ -218,14 +221,8 @@ void __afs_break_callback(struct afs_vnode *vnode)
                vnode->cb_break++;
                afs_clear_permits(vnode);
 
-               spin_lock(&vnode->lock);
-
-               _debug("break callback");
-
-               if (list_empty(&vnode->granted_locks) &&
-                   !list_empty(&vnode->pending_locks))
+               if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB)
                        afs_lock_may_be_available(vnode);
-               spin_unlock(&vnode->lock);
        }
 }
 
index 9de46116c7492a712ede0c8a241eea71ef94230b..9c3b07ba22221f80d5d59751c1fd994765b1b98a 100644 (file)
@@ -123,6 +123,7 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
                                       const char *name, unsigned int namelen,
                                       const char *addresses)
 {
+       struct afs_vlserver_list *vllist;
        struct afs_cell *cell;
        int i, ret;
 
@@ -151,18 +152,14 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
 
        atomic_set(&cell->usage, 2);
        INIT_WORK(&cell->manager, afs_manage_cell);
-       cell->flags = ((1 << AFS_CELL_FL_NOT_READY) |
-                      (1 << AFS_CELL_FL_NO_LOOKUP_YET));
        INIT_LIST_HEAD(&cell->proc_volumes);
        rwlock_init(&cell->proc_lock);
        rwlock_init(&cell->vl_servers_lock);
 
-       /* Fill in the VL server list if we were given a list of addresses to
-        * use.
+       /* Provide a VL server list, filling it in if we were given a list of
+        * addresses to use.
         */
        if (addresses) {
-               struct afs_vlserver_list *vllist;
-
                vllist = afs_parse_text_addrs(net,
                                              addresses, strlen(addresses), ':',
                                              VL_SERVICE, AFS_VL_PORT);
@@ -171,19 +168,32 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
                        goto parse_failed;
                }
 
-               rcu_assign_pointer(cell->vl_servers, vllist);
+               vllist->source = DNS_RECORD_FROM_CONFIG;
+               vllist->status = DNS_LOOKUP_NOT_DONE;
                cell->dns_expiry = TIME64_MAX;
-               __clear_bit(AFS_CELL_FL_NO_LOOKUP_YET, &cell->flags);
        } else {
+               ret = -ENOMEM;
+               vllist = afs_alloc_vlserver_list(0);
+               if (!vllist)
+                       goto error;
+               vllist->source = DNS_RECORD_UNAVAILABLE;
+               vllist->status = DNS_LOOKUP_NOT_DONE;
                cell->dns_expiry = ktime_get_real_seconds();
        }
 
+       rcu_assign_pointer(cell->vl_servers, vllist);
+
+       cell->dns_source = vllist->source;
+       cell->dns_status = vllist->status;
+       smp_store_release(&cell->dns_lookup_count, 1); /* vs source/status */
+
        _leave(" = %p", cell);
        return cell;
 
 parse_failed:
        if (ret == -EINVAL)
                printk(KERN_ERR "kAFS: bad VL server IP address\n");
+error:
        kfree(cell);
        _leave(" = %d", ret);
        return ERR_PTR(ret);
@@ -208,6 +218,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
 {
        struct afs_cell *cell, *candidate, *cursor;
        struct rb_node *parent, **pp;
+       enum afs_cell_state state;
        int ret, n;
 
        _enter("%s,%s", name, vllist);
@@ -267,18 +278,16 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
 
 wait_for_cell:
        _debug("wait_for_cell");
-       ret = wait_on_bit(&cell->flags, AFS_CELL_FL_NOT_READY, TASK_INTERRUPTIBLE);
-       smp_rmb();
-
-       switch (READ_ONCE(cell->state)) {
-       case AFS_CELL_FAILED:
+       wait_var_event(&cell->state,
+                      ({
+                              state = smp_load_acquire(&cell->state); /* vs error */
+                              state == AFS_CELL_ACTIVE || state == AFS_CELL_FAILED;
+                      }));
+
+       /* Check the state obtained from the wait check. */
+       if (state == AFS_CELL_FAILED) {
                ret = cell->error;
                goto error;
-       default:
-               _debug("weird %u %d", cell->state, cell->error);
-               goto error;
-       case AFS_CELL_ACTIVE:
-               break;
        }
 
        _leave(" = %p [cell]", cell);
@@ -360,16 +369,46 @@ int afs_cell_init(struct afs_net *net, const char *rootcell)
 /*
  * Update a cell's VL server address list from the DNS.
  */
-static void afs_update_cell(struct afs_cell *cell)
+static int afs_update_cell(struct afs_cell *cell)
 {
-       struct afs_vlserver_list *vllist, *old;
+       struct afs_vlserver_list *vllist, *old = NULL, *p;
        unsigned int min_ttl = READ_ONCE(afs_cell_min_ttl);
        unsigned int max_ttl = READ_ONCE(afs_cell_max_ttl);
        time64_t now, expiry = 0;
+       int ret = 0;
 
        _enter("%s", cell->name);
 
        vllist = afs_dns_query(cell, &expiry);
+       if (IS_ERR(vllist)) {
+               ret = PTR_ERR(vllist);
+
+               _debug("%s: fail %d", cell->name, ret);
+               if (ret == -ENOMEM)
+                       goto out_wake;
+
+               ret = -ENOMEM;
+               vllist = afs_alloc_vlserver_list(0);
+               if (!vllist)
+                       goto out_wake;
+
+               switch (ret) {
+               case -ENODATA:
+               case -EDESTADDRREQ:
+                       vllist->status = DNS_LOOKUP_GOT_NOT_FOUND;
+                       break;
+               case -EAGAIN:
+               case -ECONNREFUSED:
+                       vllist->status = DNS_LOOKUP_GOT_TEMP_FAILURE;
+                       break;
+               default:
+                       vllist->status = DNS_LOOKUP_GOT_LOCAL_FAILURE;
+                       break;
+               }
+       }
+
+       _debug("%s: got list %d %d", cell->name, vllist->source, vllist->status);
+       cell->dns_status = vllist->status;
 
        now = ktime_get_real_seconds();
        if (min_ttl > max_ttl)
@@ -379,48 +418,47 @@ static void afs_update_cell(struct afs_cell *cell)
        else if (expiry > now + max_ttl)
                expiry = now + max_ttl;
 
-       if (IS_ERR(vllist)) {
-               switch (PTR_ERR(vllist)) {
-               case -ENODATA:
-               case -EDESTADDRREQ:
+       _debug("%s: status %d", cell->name, vllist->status);
+       if (vllist->source == DNS_RECORD_UNAVAILABLE) {
+               switch (vllist->status) {
+               case DNS_LOOKUP_GOT_NOT_FOUND:
                        /* The DNS said that the cell does not exist or there
                         * weren't any addresses to be had.
                         */
-                       set_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags);
-                       clear_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
                        cell->dns_expiry = expiry;
                        break;
 
-               case -EAGAIN:
-               case -ECONNREFUSED:
+               case DNS_LOOKUP_BAD:
+               case DNS_LOOKUP_GOT_LOCAL_FAILURE:
+               case DNS_LOOKUP_GOT_TEMP_FAILURE:
+               case DNS_LOOKUP_GOT_NS_FAILURE:
                default:
-                       set_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
                        cell->dns_expiry = now + 10;
                        break;
                }
-
-               cell->error = -EDESTADDRREQ;
        } else {
-               clear_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
-               clear_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags);
-
-               /* Exclusion on changing vl_addrs is achieved by a
-                * non-reentrant work item.
-                */
-               old = rcu_dereference_protected(cell->vl_servers, true);
-               rcu_assign_pointer(cell->vl_servers, vllist);
                cell->dns_expiry = expiry;
-
-               if (old)
-                       afs_put_vlserverlist(cell->net, old);
        }
 
-       if (test_and_clear_bit(AFS_CELL_FL_NO_LOOKUP_YET, &cell->flags))
-               wake_up_bit(&cell->flags, AFS_CELL_FL_NO_LOOKUP_YET);
+       /* Replace the VL server list if the new record has servers or the old
+        * record doesn't.
+        */
+       write_lock(&cell->vl_servers_lock);
+       p = rcu_dereference_protected(cell->vl_servers, true);
+       if (vllist->nr_servers > 0 || p->nr_servers == 0) {
+               rcu_assign_pointer(cell->vl_servers, vllist);
+               cell->dns_source = vllist->source;
+               old = p;
+       }
+       write_unlock(&cell->vl_servers_lock);
+       afs_put_vlserverlist(cell->net, old);
 
-       now = ktime_get_real_seconds();
-       afs_set_cell_timer(cell->net, cell->dns_expiry - now);
-       _leave("");
+out_wake:
+       smp_store_release(&cell->dns_lookup_count,
+                         cell->dns_lookup_count + 1); /* vs source/status */
+       wake_up_var(&cell->dns_lookup_count);
+       _leave(" = %d", ret);
+       return ret;
 }
 
 /*
@@ -491,8 +529,7 @@ void afs_put_cell(struct afs_net *net, struct afs_cell *cell)
        now = ktime_get_real_seconds();
        cell->last_inactive = now;
        expire_delay = 0;
-       if (!test_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags) &&
-           !test_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags))
+       if (cell->vl_servers->nr_servers)
                expire_delay = afs_cell_gc_delay;
 
        if (atomic_dec_return(&cell->usage) > 1)
@@ -623,11 +660,13 @@ again:
                        goto final_destruction;
                if (cell->state == AFS_CELL_FAILED)
                        goto done;
-               cell->state = AFS_CELL_UNSET;
+               smp_store_release(&cell->state, AFS_CELL_UNSET);
+               wake_up_var(&cell->state);
                goto again;
 
        case AFS_CELL_UNSET:
-               cell->state = AFS_CELL_ACTIVATING;
+               smp_store_release(&cell->state, AFS_CELL_ACTIVATING);
+               wake_up_var(&cell->state);
                goto again;
 
        case AFS_CELL_ACTIVATING:
@@ -635,28 +674,29 @@ again:
                if (ret < 0)
                        goto activation_failed;
 
-               cell->state = AFS_CELL_ACTIVE;
-               smp_wmb();
-               clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
-               wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
+               smp_store_release(&cell->state, AFS_CELL_ACTIVE);
+               wake_up_var(&cell->state);
                goto again;
 
        case AFS_CELL_ACTIVE:
                if (atomic_read(&cell->usage) > 1) {
-                       time64_t now = ktime_get_real_seconds();
-                       if (cell->dns_expiry <= now && net->live)
-                               afs_update_cell(cell);
+                       if (test_and_clear_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags)) {
+                               ret = afs_update_cell(cell);
+                               if (ret < 0)
+                                       cell->error = ret;
+                       }
                        goto done;
                }
-               cell->state = AFS_CELL_DEACTIVATING;
+               smp_store_release(&cell->state, AFS_CELL_DEACTIVATING);
+               wake_up_var(&cell->state);
                goto again;
 
        case AFS_CELL_DEACTIVATING:
-               set_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
                if (atomic_read(&cell->usage) > 1)
                        goto reverse_deactivation;
                afs_deactivate_cell(net, cell);
-               cell->state = AFS_CELL_INACTIVE;
+               smp_store_release(&cell->state, AFS_CELL_INACTIVE);
+               wake_up_var(&cell->state);
                goto again;
 
        default:
@@ -669,17 +709,13 @@ activation_failed:
        cell->error = ret;
        afs_deactivate_cell(net, cell);
 
-       cell->state = AFS_CELL_FAILED;
-       smp_wmb();
-       if (test_and_clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags))
-               wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
+       smp_store_release(&cell->state, AFS_CELL_FAILED); /* vs error */
+       wake_up_var(&cell->state);
        goto again;
 
 reverse_deactivation:
-       cell->state = AFS_CELL_ACTIVE;
-       smp_wmb();
-       clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
-       wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
+       smp_store_release(&cell->state, AFS_CELL_ACTIVE);
+       wake_up_var(&cell->state);
        _leave(" [deact->act]");
        return;
 
@@ -739,11 +775,16 @@ void afs_manage_cells(struct work_struct *work)
                }
 
                if (usage == 1) {
+                       struct afs_vlserver_list *vllist;
                        time64_t expire_at = cell->last_inactive;
 
-                       if (!test_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags) &&
-                           !test_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags))
+                       read_lock(&cell->vl_servers_lock);
+                       vllist = rcu_dereference_protected(
+                               cell->vl_servers,
+                               lockdep_is_held(&cell->vl_servers_lock));
+                       if (vllist->nr_servers > 0)
                                expire_at += afs_cell_gc_delay;
+                       read_unlock(&cell->vl_servers_lock);
                        if (purging || expire_at <= now)
                                sched_cell = true;
                        else if (expire_at < next_manage)
@@ -751,10 +792,8 @@ void afs_manage_cells(struct work_struct *work)
                }
 
                if (!purging) {
-                       if (cell->dns_expiry <= now)
+                       if (test_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags))
                                sched_cell = true;
-                       else if (cell->dns_expiry <= next_manage)
-                               next_manage = cell->dns_expiry;
                }
 
                if (sched_cell)
index 748090014519d10af0152a8c695df7bdf77500b2..01437cfe54326e974cfdad81760f7d1d96b9d61b 100644 (file)
@@ -213,7 +213,7 @@ static int afs_find_cm_server_by_peer(struct afs_call *call)
                return 0;
        }
 
-       call->cm_server = server;
+       call->server = server;
        return afs_record_cm_probe(call, server);
 }
 
@@ -234,7 +234,7 @@ static int afs_find_cm_server_by_uuid(struct afs_call *call,
                return 0;
        }
 
-       call->cm_server = server;
+       call->server = server;
        return afs_record_cm_probe(call, server);
 }
 
@@ -260,8 +260,8 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
         * server holds up change visibility till it receives our reply so as
         * to maintain cache coherency.
         */
-       if (call->cm_server)
-               afs_break_callbacks(call->cm_server, call->count, call->request);
+       if (call->server)
+               afs_break_callbacks(call->server, call->count, call->request);
 
        afs_send_empty_reply(call);
        afs_put_call(call);
@@ -376,10 +376,10 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work)
 {
        struct afs_call *call = container_of(work, struct afs_call, work);
 
-       _enter("{%p}", call->cm_server);
+       _enter("{%p}", call->server);
 
-       if (call->cm_server)
-               afs_init_callback_state(call->cm_server);
+       if (call->server)
+               afs_init_callback_state(call->server);
        afs_send_empty_reply(call);
        afs_put_call(call);
        _leave("");
index 9a466be583d2a9e57ddaec723e9dae8f2be45580..79d93a26759ae7cc0dcf633a79f85efd5a2c7711 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/sched.h>
 #include <linux/task_io_accounting_ops.h>
 #include "internal.h"
+#include "afs_fs.h"
 #include "xdr_fs.h"
 
 static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
@@ -102,8 +103,8 @@ struct afs_lookup_cookie {
        bool                    found;
        bool                    one_only;
        unsigned short          nr_fids;
-       struct afs_file_status  *statuses;
-       struct afs_callback     *callbacks;
+       struct inode            **inodes;
+       struct afs_status_cb    *statuses;
        struct afs_fid          fids[50];
 };
 
@@ -638,12 +639,14 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
                                   struct key *key)
 {
        struct afs_lookup_cookie *cookie;
-       struct afs_cb_interest *cbi = NULL;
+       struct afs_cb_interest *dcbi, *cbi = NULL;
        struct afs_super_info *as = dir->i_sb->s_fs_info;
-       struct afs_iget_data data;
+       struct afs_status_cb *scb;
+       struct afs_iget_data iget_data;
        struct afs_fs_cursor fc;
-       struct afs_vnode *dvnode = AFS_FS_I(dir);
-       struct inode *inode = NULL;
+       struct afs_server *server;
+       struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode;
+       struct inode *inode = NULL, *ti;
        int ret, i;
 
        _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry);
@@ -657,10 +660,14 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
        cookie->nr_fids = 1; /* slot 0 is saved for the fid we actually want */
 
        read_seqlock_excl(&dvnode->cb_lock);
-       if (dvnode->cb_interest &&
-           dvnode->cb_interest->server &&
-           test_bit(AFS_SERVER_FL_NO_IBULK, &dvnode->cb_interest->server->flags))
-               cookie->one_only = true;
+       dcbi = rcu_dereference_protected(dvnode->cb_interest,
+                                        lockdep_is_held(&dvnode->cb_lock.lock));
+       if (dcbi) {
+               server = dcbi->server;
+               if (server &&
+                   test_bit(AFS_SERVER_FL_NO_IBULK, &server->flags))
+                       cookie->one_only = true;
+       }
        read_sequnlock_excl(&dvnode->cb_lock);
 
        for (i = 0; i < 50; i++)
@@ -678,24 +685,43 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
                goto out;
 
        /* Check to see if we already have an inode for the primary fid. */
-       data.volume = dvnode->volume;
-       data.fid = cookie->fids[0];
-       inode = ilookup5(dir->i_sb, cookie->fids[0].vnode, afs_iget5_test, &data);
+       iget_data.fid = cookie->fids[0];
+       iget_data.volume = dvnode->volume;
+       iget_data.cb_v_break = dvnode->volume->cb_v_break;
+       iget_data.cb_s_break = 0;
+       inode = ilookup5(dir->i_sb, cookie->fids[0].vnode,
+                        afs_iget5_test, &iget_data);
        if (inode)
                goto out;
 
        /* Need space for examining all the selected files */
        inode = ERR_PTR(-ENOMEM);
-       cookie->statuses = kcalloc(cookie->nr_fids, sizeof(struct afs_file_status),
-                                  GFP_KERNEL);
+       cookie->statuses = kvcalloc(cookie->nr_fids, sizeof(struct afs_status_cb),
+                                   GFP_KERNEL);
        if (!cookie->statuses)
                goto out;
 
-       cookie->callbacks = kcalloc(cookie->nr_fids, sizeof(struct afs_callback),
-                                   GFP_KERNEL);
-       if (!cookie->callbacks)
+       cookie->inodes = kcalloc(cookie->nr_fids, sizeof(struct inode *),
+                                GFP_KERNEL);
+       if (!cookie->inodes)
                goto out_s;
 
+       for (i = 1; i < cookie->nr_fids; i++) {
+               scb = &cookie->statuses[i];
+
+               /* Find any inodes that already exist and get their
+                * callback counters.
+                */
+               iget_data.fid = cookie->fids[i];
+               ti = ilookup5_nowait(dir->i_sb, iget_data.fid.vnode,
+                                    afs_iget5_test, &iget_data);
+               if (!IS_ERR_OR_NULL(ti)) {
+                       vnode = AFS_FS_I(ti);
+                       scb->cb_break = afs_calc_vnode_cb_break(vnode);
+                       cookie->inodes[i] = ti;
+               }
+       }
+
        /* Try FS.InlineBulkStatus first.  Abort codes for the individual
         * lookups contained therein are stored in the reply without aborting
         * the whole operation.
@@ -704,7 +730,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
                goto no_inline_bulk_status;
 
        inode = ERR_PTR(-ERESTARTSYS);
-       if (afs_begin_vnode_operation(&fc, dvnode, key)) {
+       if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
                while (afs_select_fileserver(&fc)) {
                        if (test_bit(AFS_SERVER_FL_NO_IBULK,
                                      &fc.cbi->server->flags)) {
@@ -712,11 +738,12 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
                                fc.ac.error = -ECONNABORTED;
                                break;
                        }
+                       iget_data.cb_v_break = dvnode->volume->cb_v_break;
+                       iget_data.cb_s_break = fc.cbi->server->cb_s_break;
                        afs_fs_inline_bulk_status(&fc,
                                                  afs_v2net(dvnode),
                                                  cookie->fids,
                                                  cookie->statuses,
-                                                 cookie->callbacks,
                                                  cookie->nr_fids, NULL);
                }
 
@@ -737,15 +764,16 @@ no_inline_bulk_status:
         * any of the lookups fails - so, for the moment, revert to
         * FS.FetchStatus for just the primary fid.
         */
-       cookie->nr_fids = 1;
        inode = ERR_PTR(-ERESTARTSYS);
-       if (afs_begin_vnode_operation(&fc, dvnode, key)) {
+       if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
                while (afs_select_fileserver(&fc)) {
+                       iget_data.cb_v_break = dvnode->volume->cb_v_break;
+                       iget_data.cb_s_break = fc.cbi->server->cb_s_break;
+                       scb = &cookie->statuses[0];
                        afs_fs_fetch_status(&fc,
                                            afs_v2net(dvnode),
                                            cookie->fids,
-                                           cookie->statuses,
-                                           cookie->callbacks,
+                                           scb,
                                            NULL);
                }
 
@@ -757,26 +785,36 @@ no_inline_bulk_status:
        if (IS_ERR(inode))
                goto out_c;
 
-       for (i = 0; i < cookie->nr_fids; i++)
-               cookie->statuses[i].abort_code = 0;
-
 success:
        /* Turn all the files into inodes and save the first one - which is the
         * one we actually want.
         */
-       if (cookie->statuses[0].abort_code != 0)
-               inode = ERR_PTR(afs_abort_to_error(cookie->statuses[0].abort_code));
+       scb = &cookie->statuses[0];
+       if (scb->status.abort_code != 0)
+               inode = ERR_PTR(afs_abort_to_error(scb->status.abort_code));
 
        for (i = 0; i < cookie->nr_fids; i++) {
-               struct inode *ti;
+               struct afs_status_cb *scb = &cookie->statuses[i];
+
+               if (!scb->have_status && !scb->have_error)
+                       continue;
+
+               if (cookie->inodes[i]) {
+                       afs_vnode_commit_status(&fc, AFS_FS_I(cookie->inodes[i]),
+                                               scb->cb_break, NULL, scb);
+                       continue;
+               }
 
-               if (cookie->statuses[i].abort_code != 0)
+               if (scb->status.abort_code != 0)
                        continue;
 
-               ti = afs_iget(dir->i_sb, key, &cookie->fids[i],
-                             &cookie->statuses[i],
-                             &cookie->callbacks[i],
-                             cbi, dvnode);
+               iget_data.fid = cookie->fids[i];
+               ti = afs_iget(dir->i_sb, key, &iget_data, scb, cbi, dvnode);
+               if (!IS_ERR(ti))
+                       afs_cache_permit(AFS_FS_I(ti), key,
+                                        0 /* Assume vnode->cb_break is 0 */ +
+                                        iget_data.cb_v_break,
+                                        scb);
                if (i == 0) {
                        inode = ti;
                } else {
@@ -787,9 +825,13 @@ success:
 
 out_c:
        afs_put_cb_interest(afs_v2net(dvnode), cbi);
-       kfree(cookie->callbacks);
+       if (cookie->inodes) {
+               for (i = 0; i < cookie->nr_fids; i++)
+                       iput(cookie->inodes[i]);
+               kfree(cookie->inodes);
+       }
 out_s:
-       kfree(cookie->statuses);
+       kvfree(cookie->statuses);
 out:
        kfree(cookie);
        return inode;
@@ -1114,9 +1156,8 @@ void afs_d_release(struct dentry *dentry)
  */
 static void afs_vnode_new_inode(struct afs_fs_cursor *fc,
                                struct dentry *new_dentry,
-                               struct afs_fid *newfid,
-                               struct afs_file_status *newstatus,
-                               struct afs_callback *newcb)
+                               struct afs_iget_data *new_data,
+                               struct afs_status_cb *new_scb)
 {
        struct afs_vnode *vnode;
        struct inode *inode;
@@ -1125,7 +1166,7 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc,
                return;
 
        inode = afs_iget(fc->vnode->vfs_inode.i_sb, fc->key,
-                        newfid, newstatus, newcb, fc->cbi, fc->vnode);
+                        new_data, new_scb, fc->cbi, fc->vnode);
        if (IS_ERR(inode)) {
                /* ENOMEM or EINTR at a really inconvenient time - just abandon
                 * the new directory on the server.
@@ -1136,22 +1177,29 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc,
 
        vnode = AFS_FS_I(inode);
        set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags);
-       afs_vnode_commit_status(fc, vnode, 0);
+       if (fc->ac.error == 0)
+               afs_cache_permit(vnode, fc->key, vnode->cb_break, new_scb);
        d_instantiate(new_dentry, inode);
 }
 
+static void afs_prep_for_new_inode(struct afs_fs_cursor *fc,
+                                  struct afs_iget_data *iget_data)
+{
+       iget_data->volume = fc->vnode->volume;
+       iget_data->cb_v_break = fc->vnode->volume->cb_v_break;
+       iget_data->cb_s_break = fc->cbi->server->cb_s_break;
+}
+
 /*
  * create a directory on an AFS filesystem
  */
 static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
-       struct afs_file_status newstatus;
+       struct afs_iget_data iget_data;
+       struct afs_status_cb *scb;
        struct afs_fs_cursor fc;
-       struct afs_callback newcb;
        struct afs_vnode *dvnode = AFS_FS_I(dir);
-       struct afs_fid newfid;
        struct key *key;
-       u64 data_version = dvnode->status.data_version;
        int ret;
 
        mode |= S_IFDIR;
@@ -1159,23 +1207,32 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        _enter("{%llx:%llu},{%pd},%ho",
               dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
 
+       ret = -ENOMEM;
+       scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               goto error;
+
        key = afs_request_key(dvnode->volume->cell);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
-               goto error;
+               goto error_scb;
        }
 
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, dvnode, key)) {
+       if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
+               afs_dataversion_t data_version = dvnode->status.data_version + 1;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(dvnode);
-                       afs_fs_create(&fc, dentry->d_name.name, mode, data_version,
-                                     &newfid, &newstatus, &newcb);
+                       afs_prep_for_new_inode(&fc, &iget_data);
+                       afs_fs_create(&fc, dentry->d_name.name, mode,
+                                     &scb[0], &iget_data.fid, &scb[1]);
                }
 
-               afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
-               afs_vnode_new_inode(&fc, dentry, &newfid, &newstatus, &newcb);
+               afs_check_for_remote_deletion(&fc, dvnode);
+               afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
+                                       &data_version, &scb[0]);
+               afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]);
                ret = afs_end_vnode_operation(&fc);
                if (ret < 0)
                        goto error_key;
@@ -1185,15 +1242,18 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 
        if (ret == 0 &&
            test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
-               afs_edit_dir_add(dvnode, &dentry->d_name, &newfid,
+               afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid,
                                 afs_edit_dir_for_create);
 
        key_put(key);
+       kfree(scb);
        _leave(" = 0");
        return 0;
 
 error_key:
        key_put(key);
+error_scb:
+       kfree(scb);
 error:
        d_drop(dentry);
        _leave(" = %d", ret);
@@ -1220,15 +1280,19 @@ static void afs_dir_remove_subdir(struct dentry *dentry)
  */
 static int afs_rmdir(struct inode *dir, struct dentry *dentry)
 {
+       struct afs_status_cb *scb;
        struct afs_fs_cursor fc;
        struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL;
        struct key *key;
-       u64 data_version = dvnode->status.data_version;
        int ret;
 
        _enter("{%llx:%llu},{%pd}",
               dvnode->fid.vid, dvnode->fid.vnode, dentry);
 
+       scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               return -ENOMEM;
+
        key = afs_request_key(dvnode->volume->cell);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
@@ -1250,14 +1314,16 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
        }
 
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, dvnode, key)) {
+       if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
+               afs_dataversion_t data_version = dvnode->status.data_version + 1;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(dvnode);
-                       afs_fs_remove(&fc, vnode, dentry->d_name.name, true,
-                                     data_version);
+                       afs_fs_remove(&fc, vnode, dentry->d_name.name, true, scb);
                }
 
-               afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
+               afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
+                                       &data_version, scb);
                ret = afs_end_vnode_operation(&fc);
                if (ret == 0) {
                        afs_dir_remove_subdir(dentry);
@@ -1272,6 +1338,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
 error_key:
        key_put(key);
 error:
+       kfree(scb);
        return ret;
 }
 
@@ -1285,32 +1352,27 @@ error:
  * However, if we didn't have a callback promise outstanding, or it was
  * outstanding on a different server, then it won't break it either...
  */
-int afs_dir_remove_link(struct dentry *dentry, struct key *key,
-                       unsigned long d_version_before,
-                       unsigned long d_version_after)
+static int afs_dir_remove_link(struct afs_vnode *dvnode, struct dentry *dentry,
+                              struct key *key)
 {
-       bool dir_valid;
        int ret = 0;
 
-       /* There were no intervening changes on the server if the version
-        * number we got back was incremented by exactly 1.
-        */
-       dir_valid = (d_version_after == d_version_before + 1);
-
        if (d_really_is_positive(dentry)) {
                struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
 
                if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
                        /* Already done */
-               } else if (dir_valid) {
+               } else if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) {
+                       write_seqlock(&vnode->cb_lock);
                        drop_nlink(&vnode->vfs_inode);
                        if (vnode->vfs_inode.i_nlink == 0) {
                                set_bit(AFS_VNODE_DELETED, &vnode->flags);
-                               clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
+                               __afs_break_callback(vnode);
                        }
+                       write_sequnlock(&vnode->cb_lock);
                        ret = 0;
                } else {
-                       clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
+                       afs_break_callback(vnode);
 
                        if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
                                kdebug("AFS_VNODE_DELETED");
@@ -1331,11 +1393,10 @@ int afs_dir_remove_link(struct dentry *dentry, struct key *key,
 static int afs_unlink(struct inode *dir, struct dentry *dentry)
 {
        struct afs_fs_cursor fc;
+       struct afs_status_cb *scb;
        struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL;
        struct key *key;
-       unsigned long d_version = (unsigned long)dentry->d_fsdata;
        bool need_rehash = false;
-       u64 data_version = dvnode->status.data_version;
        int ret;
 
        _enter("{%llx:%llu},{%pd}",
@@ -1344,10 +1405,15 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
        if (dentry->d_name.len >= AFSNAMEMAX)
                return -ENAMETOOLONG;
 
+       ret = -ENOMEM;
+       scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               goto error;
+
        key = afs_request_key(dvnode->volume->cell);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
-               goto error;
+               goto error_scb;
        }
 
        /* Try to make sure we have a callback promise on the victim. */
@@ -1374,30 +1440,34 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
        spin_unlock(&dentry->d_lock);
 
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, dvnode, key)) {
+       if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
+               afs_dataversion_t data_version = dvnode->status.data_version + 1;
+               afs_dataversion_t data_version_2 = vnode->status.data_version;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(dvnode);
+                       fc.cb_break_2 = afs_calc_vnode_cb_break(vnode);
 
                        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc.cbi->server->flags) &&
                            !test_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags)) {
                                yfs_fs_remove_file2(&fc, vnode, dentry->d_name.name,
-                                                   data_version);
+                                                   &scb[0], &scb[1]);
                                if (fc.ac.error != -ECONNABORTED ||
                                    fc.ac.abort_code != RXGEN_OPCODE)
                                        continue;
                                set_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags);
                        }
 
-                       afs_fs_remove(&fc, vnode, dentry->d_name.name, false,
-                                     data_version);
+                       afs_fs_remove(&fc, vnode, dentry->d_name.name, false, &scb[0]);
                }
 
-               afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
+               afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
+                                       &data_version, &scb[0]);
+               afs_vnode_commit_status(&fc, vnode, fc.cb_break_2,
+                                       &data_version_2, &scb[1]);
                ret = afs_end_vnode_operation(&fc);
-               if (ret == 0)
-                       ret = afs_dir_remove_link(
-                               dentry, key, d_version,
-                               (unsigned long)dvnode->status.data_version);
+               if (ret == 0 && !(scb[1].have_status || scb[1].have_error))
+                       ret = afs_dir_remove_link(dvnode, dentry, key);
                if (ret == 0 &&
                    test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
                        afs_edit_dir_remove(dvnode, &dentry->d_name,
@@ -1409,6 +1479,8 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
 
 error_key:
        key_put(key);
+error_scb:
+       kfree(scb);
 error:
        _leave(" = %d", ret);
        return ret;
@@ -1420,13 +1492,11 @@ error:
 static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
                      bool excl)
 {
+       struct afs_iget_data iget_data;
        struct afs_fs_cursor fc;
-       struct afs_file_status newstatus;
-       struct afs_callback newcb;
+       struct afs_status_cb *scb;
        struct afs_vnode *dvnode = AFS_FS_I(dir);
-       struct afs_fid newfid;
        struct key *key;
-       u64 data_version = dvnode->status.data_version;
        int ret;
 
        mode |= S_IFREG;
@@ -1444,17 +1514,26 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
                goto error;
        }
 
+       ret = -ENOMEM;
+       scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               goto error_scb;
+
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, dvnode, key)) {
+       if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
+               afs_dataversion_t data_version = dvnode->status.data_version + 1;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(dvnode);
-                       afs_fs_create(&fc, dentry->d_name.name, mode, data_version,
-                                     &newfid, &newstatus, &newcb);
+                       afs_prep_for_new_inode(&fc, &iget_data);
+                       afs_fs_create(&fc, dentry->d_name.name, mode,
+                                     &scb[0], &iget_data.fid, &scb[1]);
                }
 
-               afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
-               afs_vnode_new_inode(&fc, dentry, &newfid, &newstatus, &newcb);
+               afs_check_for_remote_deletion(&fc, dvnode);
+               afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
+                                       &data_version, &scb[0]);
+               afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]);
                ret = afs_end_vnode_operation(&fc);
                if (ret < 0)
                        goto error_key;
@@ -1463,13 +1542,16 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        }
 
        if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
-               afs_edit_dir_add(dvnode, &dentry->d_name, &newfid,
+               afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid,
                                 afs_edit_dir_for_create);
 
+       kfree(scb);
        key_put(key);
        _leave(" = 0");
        return 0;
 
+error_scb:
+       kfree(scb);
 error_key:
        key_put(key);
 error:
@@ -1485,15 +1567,12 @@ static int afs_link(struct dentry *from, struct inode *dir,
                    struct dentry *dentry)
 {
        struct afs_fs_cursor fc;
-       struct afs_vnode *dvnode, *vnode;
+       struct afs_status_cb *scb;
+       struct afs_vnode *dvnode = AFS_FS_I(dir);
+       struct afs_vnode *vnode = AFS_FS_I(d_inode(from));
        struct key *key;
-       u64 data_version;
        int ret;
 
-       vnode = AFS_FS_I(d_inode(from));
-       dvnode = AFS_FS_I(dir);
-       data_version = dvnode->status.data_version;
-
        _enter("{%llx:%llu},{%llx:%llu},{%pd}",
               vnode->fid.vid, vnode->fid.vnode,
               dvnode->fid.vid, dvnode->fid.vnode,
@@ -1503,14 +1582,21 @@ static int afs_link(struct dentry *from, struct inode *dir,
        if (dentry->d_name.len >= AFSNAMEMAX)
                goto error;
 
+       ret = -ENOMEM;
+       scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               goto error;
+
        key = afs_request_key(dvnode->volume->cell);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
-               goto error;
+               goto error_scb;
        }
 
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, dvnode, key)) {
+       if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
+               afs_dataversion_t data_version = dvnode->status.data_version + 1;
+
                if (mutex_lock_interruptible_nested(&vnode->io_lock, 1) < 0) {
                        afs_end_vnode_operation(&fc);
                        goto error_key;
@@ -1519,11 +1605,14 @@ static int afs_link(struct dentry *from, struct inode *dir,
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(dvnode);
                        fc.cb_break_2 = afs_calc_vnode_cb_break(vnode);
-                       afs_fs_link(&fc, vnode, dentry->d_name.name, data_version);
+                       afs_fs_link(&fc, vnode, dentry->d_name.name,
+                                   &scb[0], &scb[1]);
                }
 
-               afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
-               afs_vnode_commit_status(&fc, vnode, fc.cb_break_2);
+               afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
+                                       &data_version, &scb[0]);
+               afs_vnode_commit_status(&fc, vnode, fc.cb_break_2,
+                                       NULL, &scb[1]);
                ihold(&vnode->vfs_inode);
                d_instantiate(dentry, &vnode->vfs_inode);
 
@@ -1540,11 +1629,14 @@ static int afs_link(struct dentry *from, struct inode *dir,
                                 afs_edit_dir_for_link);
 
        key_put(key);
+       kfree(scb);
        _leave(" = 0");
        return 0;
 
 error_key:
        key_put(key);
+error_scb:
+       kfree(scb);
 error:
        d_drop(dentry);
        _leave(" = %d", ret);
@@ -1557,12 +1649,11 @@ error:
 static int afs_symlink(struct inode *dir, struct dentry *dentry,
                       const char *content)
 {
+       struct afs_iget_data iget_data;
        struct afs_fs_cursor fc;
-       struct afs_file_status newstatus;
+       struct afs_status_cb *scb;
        struct afs_vnode *dvnode = AFS_FS_I(dir);
-       struct afs_fid newfid;
        struct key *key;
-       u64 data_version = dvnode->status.data_version;
        int ret;
 
        _enter("{%llx:%llu},{%pd},%s",
@@ -1577,24 +1668,32 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
        if (strlen(content) >= AFSPATHMAX)
                goto error;
 
+       ret = -ENOMEM;
+       scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               goto error;
+
        key = afs_request_key(dvnode->volume->cell);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
-               goto error;
+               goto error_scb;
        }
 
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, dvnode, key)) {
+       if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
+               afs_dataversion_t data_version = dvnode->status.data_version + 1;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(dvnode);
-                       afs_fs_symlink(&fc, dentry->d_name.name,
-                                      content, data_version,
-                                      &newfid, &newstatus);
+                       afs_prep_for_new_inode(&fc, &iget_data);
+                       afs_fs_symlink(&fc, dentry->d_name.name, content,
+                                      &scb[0], &iget_data.fid, &scb[1]);
                }
 
-               afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
-               afs_vnode_new_inode(&fc, dentry, &newfid, &newstatus, NULL);
+               afs_check_for_remote_deletion(&fc, dvnode);
+               afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
+                                       &data_version, &scb[0]);
+               afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]);
                ret = afs_end_vnode_operation(&fc);
                if (ret < 0)
                        goto error_key;
@@ -1603,15 +1702,18 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
        }
 
        if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
-               afs_edit_dir_add(dvnode, &dentry->d_name, &newfid,
+               afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid,
                                 afs_edit_dir_for_symlink);
 
        key_put(key);
+       kfree(scb);
        _leave(" = 0");
        return 0;
 
 error_key:
        key_put(key);
+error_scb:
+       kfree(scb);
 error:
        d_drop(dentry);
        _leave(" = %d", ret);
@@ -1626,11 +1728,11 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
                      unsigned int flags)
 {
        struct afs_fs_cursor fc;
+       struct afs_status_cb *scb;
        struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
        struct dentry *tmp = NULL, *rehash = NULL;
        struct inode *new_inode;
        struct key *key;
-       u64 orig_data_version, new_data_version;
        bool new_negative = d_is_negative(new_dentry);
        int ret;
 
@@ -1644,8 +1746,6 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
        vnode = AFS_FS_I(d_inode(old_dentry));
        orig_dvnode = AFS_FS_I(old_dir);
        new_dvnode = AFS_FS_I(new_dir);
-       orig_data_version = orig_dvnode->status.data_version;
-       new_data_version = new_dvnode->status.data_version;
 
        _enter("{%llx:%llu},{%llx:%llu},{%llx:%llu},{%pd}",
               orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
@@ -1653,10 +1753,15 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
               new_dvnode->fid.vid, new_dvnode->fid.vnode,
               new_dentry);
 
+       ret = -ENOMEM;
+       scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               goto error;
+
        key = afs_request_key(orig_dvnode->volume->cell);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
-               goto error;
+               goto error_scb;
        }
 
        /* For non-directories, check whether the target is busy and if so,
@@ -1690,31 +1795,43 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        new_dentry = tmp;
                        rehash = NULL;
                        new_negative = true;
-                       orig_data_version = orig_dvnode->status.data_version;
-                       new_data_version = new_dvnode->status.data_version;
                }
        }
 
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, orig_dvnode, key)) {
+       if (afs_begin_vnode_operation(&fc, orig_dvnode, key, true)) {
+               afs_dataversion_t orig_data_version;
+               afs_dataversion_t new_data_version;
+               struct afs_status_cb *new_scb = &scb[1];
+
+               orig_data_version = orig_dvnode->status.data_version + 1;
+
                if (orig_dvnode != new_dvnode) {
                        if (mutex_lock_interruptible_nested(&new_dvnode->io_lock, 1) < 0) {
                                afs_end_vnode_operation(&fc);
                                goto error_rehash;
                        }
+                       new_data_version = new_dvnode->status.data_version;
+               } else {
+                       new_data_version = orig_data_version;
+                       new_scb = &scb[0];
                }
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(orig_dvnode);
                        fc.cb_break_2 = afs_calc_vnode_cb_break(new_dvnode);
                        afs_fs_rename(&fc, old_dentry->d_name.name,
                                      new_dvnode, new_dentry->d_name.name,
-                                     orig_data_version, new_data_version);
+                                     &scb[0], new_scb);
                }
 
-               afs_vnode_commit_status(&fc, orig_dvnode, fc.cb_break);
-               afs_vnode_commit_status(&fc, new_dvnode, fc.cb_break_2);
-               if (orig_dvnode != new_dvnode)
+               afs_vnode_commit_status(&fc, orig_dvnode, fc.cb_break,
+                                       &orig_data_version, &scb[0]);
+               if (new_dvnode != orig_dvnode) {
+                       afs_vnode_commit_status(&fc, new_dvnode, fc.cb_break_2,
+                                               &new_data_version, &scb[1]);
                        mutex_unlock(&new_dvnode->io_lock);
+               }
                ret = afs_end_vnode_operation(&fc);
                if (ret < 0)
                        goto error_rehash;
@@ -1754,6 +1871,8 @@ error_tmp:
        if (tmp)
                dput(tmp);
        key_put(key);
+error_scb:
+       kfree(scb);
 error:
        _leave(" = %d", ret);
        return ret;
index f6f89fdab6b2e6efe27c75d4efcbc9b4ae7505cf..28f4aa0152290555925cea03a4bba5a18ea28490 100644 (file)
@@ -24,21 +24,28 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode
                               struct key *key)
 {
        struct afs_fs_cursor fc;
-       u64 dir_data_version = dvnode->status.data_version;
+       struct afs_status_cb *scb;
        int ret = -ERESTARTSYS;
 
        _enter("%pd,%pd", old, new);
 
+       scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               return -ENOMEM;
+
        trace_afs_silly_rename(vnode, false);
-       if (afs_begin_vnode_operation(&fc, dvnode, key)) {
+       if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
+               afs_dataversion_t dir_data_version = dvnode->status.data_version + 1;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(dvnode);
                        afs_fs_rename(&fc, old->d_name.name,
                                      dvnode, new->d_name.name,
-                                     dir_data_version, dir_data_version);
+                                     scb, scb);
                }
 
-               afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
+               afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
+                                       &dir_data_version, scb);
                ret = afs_end_vnode_operation(&fc);
        }
 
@@ -64,6 +71,7 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode
                fsnotify_nameremove(old, 0);
        }
 
+       kfree(scb);
        _leave(" = %d", ret);
        return ret;
 }
@@ -143,31 +151,37 @@ static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode
                               struct dentry *dentry, struct key *key)
 {
        struct afs_fs_cursor fc;
-       u64 dir_data_version = dvnode->status.data_version;
+       struct afs_status_cb *scb;
        int ret = -ERESTARTSYS;
 
        _enter("");
 
+       scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               return -ENOMEM;
+
        trace_afs_silly_rename(vnode, true);
-       if (afs_begin_vnode_operation(&fc, dvnode, key)) {
+       if (afs_begin_vnode_operation(&fc, dvnode, key, false)) {
+               afs_dataversion_t dir_data_version = dvnode->status.data_version + 1;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(dvnode);
 
                        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc.cbi->server->flags) &&
                            !test_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags)) {
                                yfs_fs_remove_file2(&fc, vnode, dentry->d_name.name,
-                                                   dir_data_version);
+                                                   &scb[0], &scb[1]);
                                if (fc.ac.error != -ECONNABORTED ||
                                    fc.ac.abort_code != RXGEN_OPCODE)
                                        continue;
                                set_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags);
                        }
 
-                       afs_fs_remove(&fc, vnode, dentry->d_name.name, false,
-                                     dir_data_version);
+                       afs_fs_remove(&fc, vnode, dentry->d_name.name, false, &scb[0]);
                }
 
-               afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
+               afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
+                                       &dir_data_version, &scb[0]);
                ret = afs_end_vnode_operation(&fc);
                if (ret == 0) {
                        drop_nlink(&vnode->vfs_inode);
@@ -182,6 +196,7 @@ static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode
                                            afs_edit_dir_for_unlink);
        }
 
+       kfree(scb);
        _leave(" = %d", ret);
        return ret;
 }
index a9ba81ddf1546272d4a5cbb7e0885326c250c6ff..af1689d1f32e7e699e1ecd13e4b7f84443a0c4a6 100644 (file)
@@ -46,7 +46,7 @@ static int afs_probe_cell_name(struct dentry *dentry)
                return 0;
        }
 
-       ret = dns_query("afsdb", name, len, "srv=1", NULL, NULL);
+       ret = dns_query("afsdb", name, len, "srv=1", NULL, NULL, false);
        if (ret == -ENODATA)
                ret = -EDESTADDRREQ;
        return ret;
@@ -261,8 +261,7 @@ int afs_dynroot_populate(struct super_block *sb)
        struct afs_net *net = afs_sb2net(sb);
        int ret;
 
-       if (mutex_lock_interruptible(&net->proc_cells_lock) < 0)
-               return -ERESTARTSYS;
+       mutex_lock(&net->proc_cells_lock);
 
        net->dynroot_sb = sb;
        hlist_for_each_entry(cell, &net->proc_cells, proc_link) {
index e8d6619890a91bffb1d3ce12cf51c23547f55508..11e69c5fb7abb5554605fbb4974146d9f375af75 100644 (file)
@@ -170,11 +170,12 @@ int afs_release(struct inode *inode, struct file *file)
 {
        struct afs_vnode *vnode = AFS_FS_I(inode);
        struct afs_file *af = file->private_data;
+       int ret = 0;
 
        _enter("{%llx:%llu},", vnode->fid.vid, vnode->fid.vnode);
 
        if ((file->f_mode & FMODE_WRITE))
-               return vfs_fsync(file, 0);
+               ret = vfs_fsync(file, 0);
 
        file->private_data = NULL;
        if (af->wb)
@@ -182,8 +183,8 @@ int afs_release(struct inode *inode, struct file *file)
        key_put(af->key);
        kfree(af);
        afs_prune_wb_keys(vnode);
-       _leave(" = 0");
-       return 0;
+       _leave(" = %d", ret);
+       return ret;
 }
 
 /*
@@ -227,6 +228,7 @@ static void afs_file_readpage_read_complete(struct page *page,
 int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *desc)
 {
        struct afs_fs_cursor fc;
+       struct afs_status_cb *scb;
        int ret;
 
        _enter("%s{%llx:%llu.%u},%x,,,",
@@ -236,15 +238,22 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de
               vnode->fid.unique,
               key_serial(key));
 
+       scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               return -ENOMEM;
+
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, vnode, key)) {
+       if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
+               afs_dataversion_t data_version = vnode->status.data_version;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
-                       afs_fs_fetch_data(&fc, desc);
+                       afs_fs_fetch_data(&fc, scb, desc);
                }
 
-               afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, vnode, fc.cb_break);
+               afs_check_for_remote_deletion(&fc, vnode);
+               afs_vnode_commit_status(&fc, vnode, fc.cb_break,
+                                       &data_version, scb);
                ret = afs_end_vnode_operation(&fc);
        }
 
@@ -254,6 +263,7 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de
                                &afs_v2net(vnode)->n_fetch_bytes);
        }
 
+       kfree(scb);
        _leave(" = %d", ret);
        return ret;
 }
@@ -404,10 +414,10 @@ static int afs_readpage(struct file *file, struct page *page)
 /*
  * Make pages available as they're filled.
  */
-static void afs_readpages_page_done(struct afs_call *call, struct afs_read *req)
+static void afs_readpages_page_done(struct afs_read *req)
 {
 #ifdef CONFIG_AFS_FSCACHE
-       struct afs_vnode *vnode = call->reply[0];
+       struct afs_vnode *vnode = req->vnode;
 #endif
        struct page *page = req->pages[req->index];
 
@@ -461,6 +471,7 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping,
                return -ENOMEM;
 
        refcount_set(&req->usage, 1);
+       req->vnode = vnode;
        req->page_done = afs_readpages_page_done;
        req->pos = first->index;
        req->pos <<= PAGE_SHIFT;
index adc88eff7849e2f6ba2b0542fb27935be8eec799..ed3ac03682d70c3a71358297eace10b7846c6dc0 100644 (file)
@@ -41,9 +41,6 @@ void afs_lock_may_be_available(struct afs_vnode *vnode)
 {
        _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode);
 
-       if (vnode->lock_state != AFS_VNODE_LOCK_WAITING_FOR_CB)
-               return;
-
        spin_lock(&vnode->lock);
        if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB)
                afs_next_locker(vnode, 0);
@@ -77,7 +74,7 @@ static void afs_schedule_lock_extension(struct afs_vnode *vnode)
  */
 void afs_lock_op_done(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply[0];
+       struct afs_vnode *vnode = call->lvnode;
 
        if (call->error == 0) {
                spin_lock(&vnode->lock);
@@ -185,6 +182,7 @@ static void afs_kill_lockers_enoent(struct afs_vnode *vnode)
 static int afs_set_lock(struct afs_vnode *vnode, struct key *key,
                        afs_lock_type_t type)
 {
+       struct afs_status_cb *scb;
        struct afs_fs_cursor fc;
        int ret;
 
@@ -195,18 +193,23 @@ static int afs_set_lock(struct afs_vnode *vnode, struct key *key,
               vnode->fid.unique,
               key_serial(key), type);
 
+       scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               return -ENOMEM;
+
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, vnode, key)) {
+       if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
-                       afs_fs_set_lock(&fc, type);
+                       afs_fs_set_lock(&fc, type, scb);
                }
 
-               afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, vnode, fc.cb_break);
+               afs_check_for_remote_deletion(&fc, vnode);
+               afs_vnode_commit_status(&fc, vnode, fc.cb_break, NULL, scb);
                ret = afs_end_vnode_operation(&fc);
        }
 
+       kfree(scb);
        _leave(" = %d", ret);
        return ret;
 }
@@ -216,6 +219,7 @@ static int afs_set_lock(struct afs_vnode *vnode, struct key *key,
  */
 static int afs_extend_lock(struct afs_vnode *vnode, struct key *key)
 {
+       struct afs_status_cb *scb;
        struct afs_fs_cursor fc;
        int ret;
 
@@ -226,18 +230,23 @@ static int afs_extend_lock(struct afs_vnode *vnode, struct key *key)
               vnode->fid.unique,
               key_serial(key));
 
+       scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               return -ENOMEM;
+
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, vnode, key)) {
+       if (afs_begin_vnode_operation(&fc, vnode, key, false)) {
                while (afs_select_current_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
-                       afs_fs_extend_lock(&fc);
+                       afs_fs_extend_lock(&fc, scb);
                }
 
-               afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, vnode, fc.cb_break);
+               afs_check_for_remote_deletion(&fc, vnode);
+               afs_vnode_commit_status(&fc, vnode, fc.cb_break, NULL, scb);
                ret = afs_end_vnode_operation(&fc);
        }
 
+       kfree(scb);
        _leave(" = %d", ret);
        return ret;
 }
@@ -247,6 +256,7 @@ static int afs_extend_lock(struct afs_vnode *vnode, struct key *key)
  */
 static int afs_release_lock(struct afs_vnode *vnode, struct key *key)
 {
+       struct afs_status_cb *scb;
        struct afs_fs_cursor fc;
        int ret;
 
@@ -257,18 +267,23 @@ static int afs_release_lock(struct afs_vnode *vnode, struct key *key)
               vnode->fid.unique,
               key_serial(key));
 
+       scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               return -ENOMEM;
+
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, vnode, key)) {
+       if (afs_begin_vnode_operation(&fc, vnode, key, false)) {
                while (afs_select_current_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
-                       afs_fs_release_lock(&fc);
+                       afs_fs_release_lock(&fc, scb);
                }
 
-               afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, vnode, fc.cb_break);
+               afs_check_for_remote_deletion(&fc, vnode);
+               afs_vnode_commit_status(&fc, vnode, fc.cb_break, NULL, scb);
                ret = afs_end_vnode_operation(&fc);
        }
 
+       kfree(scb);
        _leave(" = %d", ret);
        return ret;
 }
@@ -736,7 +751,7 @@ static int afs_do_getlk(struct file *file, struct file_lock *fl)
        posix_test_lock(file, fl);
        if (fl->fl_type == F_UNLCK) {
                /* no local locks; consult the server */
-               ret = afs_fetch_status(vnode, key, false);
+               ret = afs_fetch_status(vnode, key, false, NULL);
                if (ret < 0)
                        goto error;
 
index 5d3abde52a0f094599aef6533f6b83f5ab3d97b6..9b72662093433ce126853354e7a9c7c6ce80b7ac 100644 (file)
@@ -33,8 +33,8 @@ static bool afs_fs_probe_done(struct afs_server *server)
 void afs_fileserver_probe_result(struct afs_call *call)
 {
        struct afs_addr_list *alist = call->alist;
-       struct afs_server *server = call->reply[0];
-       unsigned int server_index = (long)call->reply[1];
+       struct afs_server *server = call->server;
+       unsigned int server_index = call->server_index;
        unsigned int index = call->addr_ix;
        unsigned int rtt = UINT_MAX;
        bool have_result = false;
index 1296f5dc4c1e5f23e0019701646d35080dbbdf26..48298408d6ac7a944285a0f273e23b4925f8def4 100644 (file)
@@ -59,79 +59,18 @@ static void xdr_dump_bad(const __be32 *bp)
        pr_notice("0x50: %08x\n", ntohl(x[0]));
 }
 
-/*
- * Update the core inode struct from a returned status record.
- */
-void afs_update_inode_from_status(struct afs_vnode *vnode,
-                                 struct afs_file_status *status,
-                                 const afs_dataversion_t *expected_version,
-                                 u8 flags)
-{
-       struct timespec64 t;
-       umode_t mode;
-
-       t = status->mtime_client;
-       vnode->vfs_inode.i_ctime = t;
-       vnode->vfs_inode.i_mtime = t;
-       vnode->vfs_inode.i_atime = t;
-
-       if (flags & (AFS_VNODE_META_CHANGED | AFS_VNODE_NOT_YET_SET)) {
-               vnode->vfs_inode.i_uid = make_kuid(&init_user_ns, status->owner);
-               vnode->vfs_inode.i_gid = make_kgid(&init_user_ns, status->group);
-               set_nlink(&vnode->vfs_inode, status->nlink);
-
-               mode = vnode->vfs_inode.i_mode;
-               mode &= ~S_IALLUGO;
-               mode |= status->mode;
-               barrier();
-               vnode->vfs_inode.i_mode = mode;
-       }
-
-       if (!(flags & AFS_VNODE_NOT_YET_SET)) {
-               if (expected_version &&
-                   *expected_version != status->data_version) {
-                       _debug("vnode modified %llx on {%llx:%llu} [exp %llx]",
-                              (unsigned long long) status->data_version,
-                              vnode->fid.vid, vnode->fid.vnode,
-                              (unsigned long long) *expected_version);
-                       vnode->invalid_before = status->data_version;
-                       if (vnode->status.type == AFS_FTYPE_DIR) {
-                               if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
-                                       afs_stat_v(vnode, n_inval);
-                       } else {
-                               set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
-                       }
-               } else if (vnode->status.type == AFS_FTYPE_DIR) {
-                       /* Expected directory change is handled elsewhere so
-                        * that we can locally edit the directory and save on a
-                        * download.
-                        */
-                       if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
-                               flags &= ~AFS_VNODE_DATA_CHANGED;
-               }
-       }
-
-       if (flags & (AFS_VNODE_DATA_CHANGED | AFS_VNODE_NOT_YET_SET)) {
-               inode_set_iversion_raw(&vnode->vfs_inode, status->data_version);
-               i_size_write(&vnode->vfs_inode, status->size);
-       }
-}
-
 /*
  * decode an AFSFetchStatus block
  */
-static int xdr_decode_AFSFetchStatus(struct afs_call *call,
-                                    const __be32 **_bp,
-                                    struct afs_file_status *status,
-                                    struct afs_vnode *vnode,
-                                    const afs_dataversion_t *expected_version,
-                                    struct afs_read *read_req)
+static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
+                                    struct afs_call *call,
+                                    struct afs_status_cb *scb)
 {
        const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp;
+       struct afs_file_status *status = &scb->status;
        bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus);
        u64 data_version, size;
        u32 type, abort_code;
-       u8 flags = 0;
 
        abort_code = ntohl(xdr->abort_code);
 
@@ -144,6 +83,7 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
                         * case.
                         */
                        status->abort_code = abort_code;
+                       scb->have_error = true;
                        return 0;
                }
 
@@ -161,44 +101,25 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
        case AFS_FTYPE_FILE:
        case AFS_FTYPE_DIR:
        case AFS_FTYPE_SYMLINK:
-               if (type != status->type &&
-                   vnode &&
-                   !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
-                       pr_warning("Vnode %llx:%llx:%x changed type %u to %u\n",
-                                  vnode->fid.vid,
-                                  vnode->fid.vnode,
-                                  vnode->fid.unique,
-                                  status->type, type);
-                       goto bad;
-               }
                status->type = type;
                break;
        default:
                goto bad;
        }
 
-#define EXTRACT_M(FIELD)                                       \
-       do {                                                    \
-               u32 x = ntohl(xdr->FIELD);                      \
-               if (status->FIELD != x) {                       \
-                       flags |= AFS_VNODE_META_CHANGED;        \
-                       status->FIELD = x;                      \
-               }                                               \
-       } while (0)
-
-       EXTRACT_M(nlink);
-       EXTRACT_M(author);
-       EXTRACT_M(owner);
-       EXTRACT_M(caller_access); /* call ticket dependent */
-       EXTRACT_M(anon_access);
-       EXTRACT_M(mode);
-       EXTRACT_M(group);
+       status->nlink           = ntohl(xdr->nlink);
+       status->author          = ntohl(xdr->author);
+       status->owner           = ntohl(xdr->owner);
+       status->caller_access   = ntohl(xdr->caller_access); /* Ticket dependent */
+       status->anon_access     = ntohl(xdr->anon_access);
+       status->mode            = ntohl(xdr->mode) & S_IALLUGO;
+       status->group           = ntohl(xdr->group);
+       status->lock_count      = ntohl(xdr->lock_count);
 
        status->mtime_client.tv_sec = ntohl(xdr->mtime_client);
        status->mtime_client.tv_nsec = 0;
        status->mtime_server.tv_sec = ntohl(xdr->mtime_server);
        status->mtime_server.tv_nsec = 0;
-       status->lock_count   = ntohl(xdr->lock_count);
 
        size  = (u64)ntohl(xdr->size_lo);
        size |= (u64)ntohl(xdr->size_hi) << 32;
@@ -206,25 +127,10 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
 
        data_version  = (u64)ntohl(xdr->data_version_lo);
        data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
-       if (data_version != status->data_version) {
-               status->data_version = data_version;
-               flags |= AFS_VNODE_DATA_CHANGED;
-       }
-
-       if (read_req) {
-               read_req->data_version = data_version;
-               read_req->file_size = size;
-       }
+       status->data_version = data_version;
+       scb->have_status = true;
 
        *_bp = (const void *)*_bp + sizeof(*xdr);
-
-       if (vnode) {
-               if (test_bit(AFS_VNODE_UNSET, &vnode->flags))
-                       flags |= AFS_VNODE_NOT_YET_SET;
-               afs_update_inode_from_status(vnode, status, expected_version,
-                                            flags);
-       }
-
        return 0;
 
 bad:
@@ -232,77 +138,22 @@ bad:
        return afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status);
 }
 
-/*
- * Decode the file status.  We need to lock the target vnode if we're going to
- * update its status so that stat() sees the attributes update atomically.
- */
-static int afs_decode_status(struct afs_call *call,
-                            const __be32 **_bp,
-                            struct afs_file_status *status,
-                            struct afs_vnode *vnode,
-                            const afs_dataversion_t *expected_version,
-                            struct afs_read *read_req)
+static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
 {
-       int ret;
-
-       if (!vnode)
-               return xdr_decode_AFSFetchStatus(call, _bp, status, vnode,
-                                                expected_version, read_req);
-
-       write_seqlock(&vnode->cb_lock);
-       ret = xdr_decode_AFSFetchStatus(call, _bp, status, vnode,
-                                       expected_version, read_req);
-       write_sequnlock(&vnode->cb_lock);
-       return ret;
+       return ktime_divns(call->reply_time, NSEC_PER_SEC) + expiry;
 }
 
-/*
- * decode an AFSCallBack block
- */
-static void xdr_decode_AFSCallBack(struct afs_call *call,
-                                  struct afs_vnode *vnode,
-                                  const __be32 **_bp)
+static void xdr_decode_AFSCallBack(const __be32 **_bp,
+                                  struct afs_call *call,
+                                  struct afs_status_cb *scb)
 {
-       struct afs_cb_interest *old, *cbi = call->cbi;
+       struct afs_callback *cb = &scb->callback;
        const __be32 *bp = *_bp;
-       u32 cb_expiry;
-
-       write_seqlock(&vnode->cb_lock);
-
-       if (!afs_cb_is_broken(call->cb_break, vnode, cbi)) {
-               vnode->cb_version       = ntohl(*bp++);
-               cb_expiry               = ntohl(*bp++);
-               vnode->cb_type          = ntohl(*bp++);
-               vnode->cb_expires_at    = cb_expiry + ktime_get_real_seconds();
-               old = vnode->cb_interest;
-               if (old != call->cbi) {
-                       vnode->cb_interest = cbi;
-                       cbi = old;
-               }
-               set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
-       } else {
-               bp += 3;
-       }
 
-       write_sequnlock(&vnode->cb_lock);
-       call->cbi = cbi;
-       *_bp = bp;
-}
-
-static ktime_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
-{
-       return ktime_add_ns(call->reply_time, expiry * NSEC_PER_SEC);
-}
-
-static void xdr_decode_AFSCallBack_raw(struct afs_call *call,
-                                      const __be32 **_bp,
-                                      struct afs_callback *cb)
-{
-       const __be32 *bp = *_bp;
-
-       cb->version     = ntohl(*bp++);
+       bp++; /* version */
        cb->expires_at  = xdr_decode_expiry(call, ntohl(*bp++));
-       cb->type        = ntohl(*bp++);
+       bp++; /* type */
+       scb->have_cb    = true;
        *_bp = bp;
 }
 
@@ -395,7 +246,6 @@ static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
  */
 static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
@@ -403,16 +253,13 @@ static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call)
        if (ret < 0)
                return ret;
 
-       _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode);
-
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       ret = afs_decode_status(call, &bp, &vnode->status, vnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
        if (ret < 0)
                return ret;
-       xdr_decode_AFSCallBack(call, vnode, &bp);
-       xdr_decode_AFSVolSync(&bp, call->reply[1]);
+       xdr_decode_AFSCallBack(&bp, call, call->out_scb);
+       xdr_decode_AFSVolSync(&bp, call->out_volsync);
 
        _leave(" = 0 [done]");
        return 0;
@@ -431,8 +278,8 @@ static const struct afs_call_type afs_RXFSFetchStatus_vnode = {
 /*
  * fetch the status information for a file
  */
-int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsync,
-                            bool new_inode)
+int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_status_cb *scb,
+                            struct afs_volsync *volsync)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -440,7 +287,7 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy
        __be32 *bp;
 
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
-               return yfs_fs_fetch_file_status(fc, volsync, new_inode);
+               return yfs_fs_fetch_file_status(fc, scb, volsync);
 
        _enter(",%x,{%llx:%llu},,",
               key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
@@ -453,10 +300,8 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy
        }
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->reply[1] = volsync;
-       call->expected_version = new_inode ? 1 : vnode->status.data_version;
-       call->want_reply_time = true;
+       call->out_scb = scb;
+       call->out_volsync = volsync;
 
        /* marshall the parameters */
        bp = call->request;
@@ -465,10 +310,10 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy
        bp[2] = htonl(vnode->fid.vnode);
        bp[3] = htonl(vnode->fid.unique);
 
-       call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
 
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -478,8 +323,7 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy
  */
 static int afs_deliver_fs_fetch_data(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply[0];
-       struct afs_read *req = call->reply[2];
+       struct afs_read *req = call->read_request;
        const __be32 *bp;
        unsigned int size;
        int ret;
@@ -541,7 +385,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
                if (req->offset == PAGE_SIZE) {
                        req->offset = 0;
                        if (req->page_done)
-                               req->page_done(call, req);
+                               req->page_done(req);
                        req->index++;
                        if (req->remain > 0)
                                goto begin_page;
@@ -575,12 +419,14 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
                        return ret;
 
                bp = call->buffer;
-               ret = afs_decode_status(call, &bp, &vnode->status, vnode,
-                                       &vnode->status.data_version, req);
+               ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
                if (ret < 0)
                        return ret;
-               xdr_decode_AFSCallBack(call, vnode, &bp);
-               xdr_decode_AFSVolSync(&bp, call->reply[1]);
+               xdr_decode_AFSCallBack(&bp, call, call->out_scb);
+               xdr_decode_AFSVolSync(&bp, call->out_volsync);
+
+               req->data_version = call->out_scb->status.data_version;
+               req->file_size = call->out_scb->status.size;
 
                call->unmarshall++;
 
@@ -593,7 +439,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
                        zero_user_segment(req->pages[req->index],
                                          req->offset, PAGE_SIZE);
                if (req->page_done)
-                       req->page_done(call, req);
+                       req->page_done(req);
                req->offset = 0;
        }
 
@@ -603,7 +449,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
 
 static void afs_fetch_data_destructor(struct afs_call *call)
 {
-       struct afs_read *req = call->reply[2];
+       struct afs_read *req = call->read_request;
 
        afs_put_read(req);
        afs_flat_call_destructor(call);
@@ -629,7 +475,9 @@ static const struct afs_call_type afs_RXFSFetchData64 = {
 /*
  * fetch data from a very large file
  */
-static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req)
+static int afs_fs_fetch_data64(struct afs_fs_cursor *fc,
+                              struct afs_status_cb *scb,
+                              struct afs_read *req)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -643,11 +491,9 @@ static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req)
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->reply[1] = NULL; /* volsync */
-       call->reply[2] = req;
-       call->expected_version = vnode->status.data_version;
-       call->want_reply_time = true;
+       call->out_scb = scb;
+       call->out_volsync = NULL;
+       call->read_request = req;
 
        /* marshall the parameters */
        bp = call->request;
@@ -661,9 +507,9 @@ static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req)
        bp[7] = htonl(lower_32_bits(req->len));
 
        refcount_inc(&req->usage);
-       call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -671,7 +517,9 @@ static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req)
 /*
  * fetch data from a file
  */
-int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
+int afs_fs_fetch_data(struct afs_fs_cursor *fc,
+                     struct afs_status_cb *scb,
+                     struct afs_read *req)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -679,12 +527,12 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
        __be32 *bp;
 
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
-               return yfs_fs_fetch_data(fc, req);
+               return yfs_fs_fetch_data(fc, scb, req);
 
        if (upper_32_bits(req->pos) ||
            upper_32_bits(req->len) ||
            upper_32_bits(req->pos + req->len))
-               return afs_fs_fetch_data64(fc, req);
+               return afs_fs_fetch_data64(fc, scb, req);
 
        _enter("");
 
@@ -693,11 +541,9 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->reply[1] = NULL; /* volsync */
-       call->reply[2] = req;
-       call->expected_version = vnode->status.data_version;
-       call->want_reply_time = true;
+       call->out_scb = scb;
+       call->out_volsync = NULL;
+       call->read_request = req;
 
        /* marshall the parameters */
        bp = call->request;
@@ -709,9 +555,9 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
        bp[5] = htonl(lower_32_bits(req->len));
 
        refcount_inc(&req->usage);
-       call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -721,28 +567,24 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
  */
 static int afs_deliver_fs_create_vnode(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
-       _enter("{%u}", call->unmarshall);
-
        ret = afs_transfer_reply(call);
        if (ret < 0)
                return ret;
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       xdr_decode_AFSFid(&bp, call->reply[1]);
-       ret = afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL);
+       xdr_decode_AFSFid(&bp, call->out_fid);
+       ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
        if (ret < 0)
                return ret;
-       ret = afs_decode_status(call, &bp, &vnode->status, vnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
        if (ret < 0)
                return ret;
-       xdr_decode_AFSCallBack_raw(call, &bp, call->reply[3]);
-       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
+       xdr_decode_AFSCallBack(&bp, call, call->out_scb);
+       xdr_decode_AFSVolSync(&bp, call->out_volsync);
 
        _leave(" = 0 [done]");
        return 0;
@@ -771,24 +613,23 @@ static const struct afs_call_type afs_RXFSMakeDir = {
 int afs_fs_create(struct afs_fs_cursor *fc,
                  const char *name,
                  umode_t mode,
-                 u64 current_data_version,
+                 struct afs_status_cb *dvnode_scb,
                  struct afs_fid *newfid,
-                 struct afs_file_status *newstatus,
-                 struct afs_callback *newcb)
+                 struct afs_status_cb *new_scb)
 {
-       struct afs_vnode *vnode = fc->vnode;
+       struct afs_vnode *dvnode = fc->vnode;
        struct afs_call *call;
-       struct afs_net *net = afs_v2net(vnode);
+       struct afs_net *net = afs_v2net(dvnode);
        size_t namesz, reqsz, padsz;
        __be32 *bp;
 
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)){
                if (S_ISDIR(mode))
-                       return yfs_fs_make_dir(fc, name, mode, current_data_version,
-                                              newfid, newstatus, newcb);
+                       return yfs_fs_make_dir(fc, name, mode, dvnode_scb,
+                                              newfid, new_scb);
                else
-                       return yfs_fs_create_file(fc, name, mode, current_data_version,
-                                                 newfid, newstatus, newcb);
+                       return yfs_fs_create_file(fc, name, mode, dvnode_scb,
+                                                 newfid, new_scb);
        }
 
        _enter("");
@@ -804,19 +645,16 @@ int afs_fs_create(struct afs_fs_cursor *fc,
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->reply[1] = newfid;
-       call->reply[2] = newstatus;
-       call->reply[3] = newcb;
-       call->expected_version = current_data_version + 1;
-       call->want_reply_time = true;
+       call->out_dir_scb = dvnode_scb;
+       call->out_fid = newfid;
+       call->out_scb = new_scb;
 
        /* marshall the parameters */
        bp = call->request;
        *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
-       *bp++ = htonl(vnode->fid.vid);
-       *bp++ = htonl(vnode->fid.vnode);
-       *bp++ = htonl(vnode->fid.unique);
+       *bp++ = htonl(dvnode->fid.vid);
+       *bp++ = htonl(dvnode->fid.vnode);
+       *bp++ = htonl(dvnode->fid.unique);
        *bp++ = htonl(namesz);
        memcpy(bp, name, namesz);
        bp = (void *) bp + namesz;
@@ -825,41 +663,38 @@ int afs_fs_create(struct afs_fs_cursor *fc,
                bp = (void *) bp + padsz;
        }
        *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
-       *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
+       *bp++ = htonl(dvnode->vfs_inode.i_mtime.tv_sec); /* mtime */
        *bp++ = 0; /* owner */
        *bp++ = 0; /* group */
        *bp++ = htonl(mode & S_IALLUGO); /* unix mode */
        *bp++ = 0; /* segment size */
 
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call1(call, &vnode->fid, name);
+       trace_afs_make_fs_call1(call, &dvnode->fid, name);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
 
 /*
- * Deliver reply data to any operation that returns file status and volume
+ * Deliver reply data to any operation that returns directory status and volume
  * sync.
  */
-static int afs_deliver_fs_status_and_vol(struct afs_call *call)
+static int afs_deliver_fs_dir_status_and_vol(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
-       _enter("{%u}", call->unmarshall);
-
        ret = afs_transfer_reply(call);
        if (ret < 0)
                return ret;
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       ret = afs_decode_status(call, &bp, &vnode->status, vnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
        if (ret < 0)
                return ret;
-       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
+       xdr_decode_AFSVolSync(&bp, call->out_volsync);
 
        _leave(" = 0 [done]");
        return 0;
@@ -871,14 +706,14 @@ static int afs_deliver_fs_status_and_vol(struct afs_call *call)
 static const struct afs_call_type afs_RXFSRemoveFile = {
        .name           = "FS.RemoveFile",
        .op             = afs_FS_RemoveFile,
-       .deliver        = afs_deliver_fs_status_and_vol,
+       .deliver        = afs_deliver_fs_dir_status_and_vol,
        .destructor     = afs_flat_call_destructor,
 };
 
 static const struct afs_call_type afs_RXFSRemoveDir = {
        .name           = "FS.RemoveDir",
        .op             = afs_FS_RemoveDir,
-       .deliver        = afs_deliver_fs_status_and_vol,
+       .deliver        = afs_deliver_fs_dir_status_and_vol,
        .destructor     = afs_flat_call_destructor,
 };
 
@@ -886,7 +721,7 @@ static const struct afs_call_type afs_RXFSRemoveDir = {
  * remove a file or directory
  */
 int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
-                 const char *name, bool isdir, u64 current_data_version)
+                 const char *name, bool isdir, struct afs_status_cb *dvnode_scb)
 {
        struct afs_vnode *dvnode = fc->vnode;
        struct afs_call *call;
@@ -895,7 +730,7 @@ int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
        __be32 *bp;
 
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
-               return yfs_fs_remove(fc, vnode, name, isdir, current_data_version);
+               return yfs_fs_remove(fc, vnode, name, isdir, dvnode_scb);
 
        _enter("");
 
@@ -910,9 +745,7 @@ int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = dvnode;
-       call->reply[1] = vnode;
-       call->expected_version = current_data_version + 1;
+       call->out_dir_scb = dvnode_scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -930,6 +763,7 @@ int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call1(call, &dvnode->fid, name);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -939,7 +773,6 @@ int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
  */
 static int afs_deliver_fs_link(struct afs_call *call)
 {
-       struct afs_vnode *dvnode = call->reply[0], *vnode = call->reply[1];
        const __be32 *bp;
        int ret;
 
@@ -951,14 +784,13 @@ static int afs_deliver_fs_link(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       ret = afs_decode_status(call, &bp, &vnode->status, vnode, NULL, NULL);
+       ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
        if (ret < 0)
                return ret;
-       ret = afs_decode_status(call, &bp, &dvnode->status, dvnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
        if (ret < 0)
                return ret;
-       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
+       xdr_decode_AFSVolSync(&bp, call->out_volsync);
 
        _leave(" = 0 [done]");
        return 0;
@@ -978,7 +810,9 @@ static const struct afs_call_type afs_RXFSLink = {
  * make a hard link
  */
 int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
-               const char *name, u64 current_data_version)
+               const char *name,
+               struct afs_status_cb *dvnode_scb,
+               struct afs_status_cb *vnode_scb)
 {
        struct afs_vnode *dvnode = fc->vnode;
        struct afs_call *call;
@@ -987,7 +821,7 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
        __be32 *bp;
 
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
-               return yfs_fs_link(fc, vnode, name, current_data_version);
+               return yfs_fs_link(fc, vnode, name, dvnode_scb, vnode_scb);
 
        _enter("");
 
@@ -1000,9 +834,8 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = dvnode;
-       call->reply[1] = vnode;
-       call->expected_version = current_data_version + 1;
+       call->out_dir_scb = dvnode_scb;
+       call->out_scb = vnode_scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1023,6 +856,7 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call1(call, &vnode->fid, name);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1032,7 +866,6 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
  */
 static int afs_deliver_fs_symlink(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
@@ -1044,15 +877,14 @@ static int afs_deliver_fs_symlink(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       xdr_decode_AFSFid(&bp, call->reply[1]);
-       ret = afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL);
+       xdr_decode_AFSFid(&bp, call->out_fid);
+       ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
        if (ret < 0)
                return ret;
-       ret = afs_decode_status(call, &bp, &vnode->status, vnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
        if (ret < 0)
                return ret;
-       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
+       xdr_decode_AFSVolSync(&bp, call->out_volsync);
 
        _leave(" = 0 [done]");
        return 0;
@@ -1074,19 +906,19 @@ static const struct afs_call_type afs_RXFSSymlink = {
 int afs_fs_symlink(struct afs_fs_cursor *fc,
                   const char *name,
                   const char *contents,
-                  u64 current_data_version,
+                  struct afs_status_cb *dvnode_scb,
                   struct afs_fid *newfid,
-                  struct afs_file_status *newstatus)
+                  struct afs_status_cb *new_scb)
 {
-       struct afs_vnode *vnode = fc->vnode;
+       struct afs_vnode *dvnode = fc->vnode;
        struct afs_call *call;
-       struct afs_net *net = afs_v2net(vnode);
+       struct afs_net *net = afs_v2net(dvnode);
        size_t namesz, reqsz, padsz, c_namesz, c_padsz;
        __be32 *bp;
 
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
-               return yfs_fs_symlink(fc, name, contents, current_data_version,
-                                     newfid, newstatus);
+               return yfs_fs_symlink(fc, name, contents, dvnode_scb,
+                                     newfid, new_scb);
 
        _enter("");
 
@@ -1104,17 +936,16 @@ int afs_fs_symlink(struct afs_fs_cursor *fc,
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->reply[1] = newfid;
-       call->reply[2] = newstatus;
-       call->expected_version = current_data_version + 1;
+       call->out_dir_scb = dvnode_scb;
+       call->out_fid = newfid;
+       call->out_scb = new_scb;
 
        /* marshall the parameters */
        bp = call->request;
        *bp++ = htonl(FSSYMLINK);
-       *bp++ = htonl(vnode->fid.vid);
-       *bp++ = htonl(vnode->fid.vnode);
-       *bp++ = htonl(vnode->fid.unique);
+       *bp++ = htonl(dvnode->fid.vid);
+       *bp++ = htonl(dvnode->fid.vnode);
+       *bp++ = htonl(dvnode->fid.unique);
        *bp++ = htonl(namesz);
        memcpy(bp, name, namesz);
        bp = (void *) bp + namesz;
@@ -1130,14 +961,15 @@ int afs_fs_symlink(struct afs_fs_cursor *fc,
                bp = (void *) bp + c_padsz;
        }
        *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
-       *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
+       *bp++ = htonl(dvnode->vfs_inode.i_mtime.tv_sec); /* mtime */
        *bp++ = 0; /* owner */
        *bp++ = 0; /* group */
        *bp++ = htonl(S_IRWXUGO); /* unix mode */
        *bp++ = 0; /* segment size */
 
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call1(call, &vnode->fid, name);
+       trace_afs_make_fs_call1(call, &dvnode->fid, name);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1147,29 +979,24 @@ int afs_fs_symlink(struct afs_fs_cursor *fc,
  */
 static int afs_deliver_fs_rename(struct afs_call *call)
 {
-       struct afs_vnode *orig_dvnode = call->reply[0], *new_dvnode = call->reply[1];
        const __be32 *bp;
        int ret;
 
-       _enter("{%u}", call->unmarshall);
-
        ret = afs_transfer_reply(call);
        if (ret < 0)
                return ret;
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       ret = afs_decode_status(call, &bp, &orig_dvnode->status, orig_dvnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
        if (ret < 0)
                return ret;
-       if (new_dvnode != orig_dvnode) {
-               ret = afs_decode_status(call, &bp, &new_dvnode->status, new_dvnode,
-                                       &call->expected_version_2, NULL);
+       if (call->out_dir_scb != call->out_scb) {
+               ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
                if (ret < 0)
                        return ret;
        }
-       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
+       xdr_decode_AFSVolSync(&bp, call->out_volsync);
 
        _leave(" = 0 [done]");
        return 0;
@@ -1186,14 +1013,14 @@ static const struct afs_call_type afs_RXFSRename = {
 };
 
 /*
- * create a symbolic link
+ * Rename/move a file or directory.
  */
 int afs_fs_rename(struct afs_fs_cursor *fc,
                  const char *orig_name,
                  struct afs_vnode *new_dvnode,
                  const char *new_name,
-                 u64 current_orig_data_version,
-                 u64 current_new_data_version)
+                 struct afs_status_cb *orig_dvnode_scb,
+                 struct afs_status_cb *new_dvnode_scb)
 {
        struct afs_vnode *orig_dvnode = fc->vnode;
        struct afs_call *call;
@@ -1204,8 +1031,8 @@ int afs_fs_rename(struct afs_fs_cursor *fc,
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
                return yfs_fs_rename(fc, orig_name,
                                     new_dvnode, new_name,
-                                    current_orig_data_version,
-                                    current_new_data_version);
+                                    orig_dvnode_scb,
+                                    new_dvnode_scb);
 
        _enter("");
 
@@ -1225,10 +1052,8 @@ int afs_fs_rename(struct afs_fs_cursor *fc,
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = orig_dvnode;
-       call->reply[1] = new_dvnode;
-       call->expected_version = current_orig_data_version + 1;
-       call->expected_version_2 = current_new_data_version + 1;
+       call->out_dir_scb = orig_dvnode_scb;
+       call->out_scb = new_dvnode_scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1257,6 +1082,7 @@ int afs_fs_rename(struct afs_fs_cursor *fc,
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call2(call, &orig_dvnode->fid, orig_name, new_name);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1266,7 +1092,6 @@ int afs_fs_rename(struct afs_fs_cursor *fc,
  */
 static int afs_deliver_fs_store_data(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
@@ -1278,13 +1103,10 @@ static int afs_deliver_fs_store_data(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       ret = afs_decode_status(call, &bp, &vnode->status, vnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
        if (ret < 0)
                return ret;
-       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
-
-       afs_pages_written_back(vnode, call);
+       xdr_decode_AFSVolSync(&bp, call->out_volsync);
 
        _leave(" = 0 [done]");
        return 0;
@@ -1314,7 +1136,8 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc,
                               struct address_space *mapping,
                               pgoff_t first, pgoff_t last,
                               unsigned offset, unsigned to,
-                              loff_t size, loff_t pos, loff_t i_size)
+                              loff_t size, loff_t pos, loff_t i_size,
+                              struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -1332,13 +1155,12 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc,
 
        call->key = fc->key;
        call->mapping = mapping;
-       call->reply[0] = vnode;
        call->first = first;
        call->last = last;
        call->first_offset = offset;
        call->last_to = to;
        call->send_pages = true;
-       call->expected_version = vnode->status.data_version + 1;
+       call->out_scb = scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1362,6 +1184,7 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc,
        *bp++ = htonl((u32) i_size);
 
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1371,7 +1194,8 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc,
  */
 int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
                      pgoff_t first, pgoff_t last,
-                     unsigned offset, unsigned to)
+                     unsigned offset, unsigned to,
+                     struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -1380,7 +1204,7 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
        __be32 *bp;
 
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
-               return yfs_fs_store_data(fc, mapping, first, last, offset, to);
+               return yfs_fs_store_data(fc, mapping, first, last, offset, to, scb);
 
        _enter(",%x,{%llx:%llu},,",
               key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
@@ -1401,7 +1225,7 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
 
        if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
                return afs_fs_store_data64(fc, mapping, first, last, offset, to,
-                                          size, pos, i_size);
+                                          size, pos, i_size, scb);
 
        call = afs_alloc_flat_call(net, &afs_RXFSStoreData,
                                   (4 + 6 + 3) * 4,
@@ -1411,13 +1235,12 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
 
        call->key = fc->key;
        call->mapping = mapping;
-       call->reply[0] = vnode;
        call->first = first;
        call->last = last;
        call->first_offset = offset;
        call->last_to = to;
        call->send_pages = true;
-       call->expected_version = vnode->status.data_version + 1;
+       call->out_scb = scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1439,6 +1262,7 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1448,7 +1272,6 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
  */
 static int afs_deliver_fs_store_status(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
@@ -1460,11 +1283,10 @@ static int afs_deliver_fs_store_status(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       ret = afs_decode_status(call, &bp, &vnode->status, vnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
        if (ret < 0)
                return ret;
-       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
+       xdr_decode_AFSVolSync(&bp, call->out_volsync);
 
        _leave(" = 0 [done]");
        return 0;
@@ -1498,7 +1320,8 @@ static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
  * set the attributes on a very large file, using FS.StoreData rather than
  * FS.StoreStatus so as to alter the file size also
  */
-static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr)
+static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr,
+                                struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -1517,8 +1340,7 @@ static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr)
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->expected_version = vnode->status.data_version + 1;
+       call->out_scb = scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1538,6 +1360,7 @@ static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr)
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1546,7 +1369,8 @@ static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr)
  * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
  * so as to alter the file size also
  */
-static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
+static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr,
+                              struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -1558,7 +1382,7 @@ static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
 
        ASSERT(attr->ia_valid & ATTR_SIZE);
        if (attr->ia_size >> 32)
-               return afs_fs_setattr_size64(fc, attr);
+               return afs_fs_setattr_size64(fc, attr, scb);
 
        call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status,
                                   (4 + 6 + 3) * 4,
@@ -1567,8 +1391,7 @@ static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->expected_version = vnode->status.data_version + 1;
+       call->out_scb = scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1585,6 +1408,7 @@ static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1593,7 +1417,8 @@ static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
  * set the attributes on a file, using FS.StoreData if there's a change in file
  * size, and FS.StoreStatus otherwise
  */
-int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr)
+int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr,
+                  struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -1601,10 +1426,10 @@ int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr)
        __be32 *bp;
 
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
-               return yfs_fs_setattr(fc, attr);
+               return yfs_fs_setattr(fc, attr, scb);
 
        if (attr->ia_valid & ATTR_SIZE)
-               return afs_fs_setattr_size(fc, attr);
+               return afs_fs_setattr_size(fc, attr, scb);
 
        _enter(",%x,{%llx:%llu},,",
               key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
@@ -1616,8 +1441,7 @@ int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr)
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->expected_version = vnode->status.data_version;
+       call->out_scb = scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1630,6 +1454,7 @@ int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr)
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1659,7 +1484,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
                        return ret;
 
                bp = call->buffer;
-               xdr_decode_AFSFetchVolumeStatus(&bp, call->reply[1]);
+               xdr_decode_AFSFetchVolumeStatus(&bp, call->out_volstatus);
                call->unmarshall++;
                afs_extract_to_tmp(call);
 
@@ -1675,7 +1500,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
                        return afs_protocol_error(call, -EBADMSG,
                                                  afs_eproto_volname_len);
                size = (call->count + 3) & ~3; /* It's padded */
-               afs_extract_begin(call, call->reply[2], size);
+               afs_extract_to_buf(call, size);
                call->unmarshall++;
 
                /* Fall through - and extract the volume name */
@@ -1685,7 +1510,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
                if (ret < 0)
                        return ret;
 
-               p = call->reply[2];
+               p = call->buffer;
                p[call->count] = 0;
                _debug("volname '%s'", p);
                afs_extract_to_tmp(call);
@@ -1703,7 +1528,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
                        return afs_protocol_error(call, -EBADMSG,
                                                  afs_eproto_offline_msg_len);
                size = (call->count + 3) & ~3; /* It's padded */
-               afs_extract_begin(call, call->reply[2], size);
+               afs_extract_to_buf(call, size);
                call->unmarshall++;
 
                /* Fall through - and extract the offline message */
@@ -1713,7 +1538,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
                if (ret < 0)
                        return ret;
 
-               p = call->reply[2];
+               p = call->buffer;
                p[call->count] = 0;
                _debug("offline '%s'", p);
 
@@ -1732,7 +1557,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
                        return afs_protocol_error(call, -EBADMSG,
                                                  afs_eproto_motd_len);
                size = (call->count + 3) & ~3; /* It's padded */
-               afs_extract_begin(call, call->reply[2], size);
+               afs_extract_to_buf(call, size);
                call->unmarshall++;
 
                /* Fall through - and extract the message of the day */
@@ -1742,7 +1567,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
                if (ret < 0)
                        return ret;
 
-               p = call->reply[2];
+               p = call->buffer;
                p[call->count] = 0;
                _debug("motd '%s'", p);
 
@@ -1756,16 +1581,6 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
        return 0;
 }
 
-/*
- * destroy an FS.GetVolumeStatus call
- */
-static void afs_get_volume_status_call_destructor(struct afs_call *call)
-{
-       kfree(call->reply[2]);
-       call->reply[2] = NULL;
-       afs_flat_call_destructor(call);
-}
-
 /*
  * FS.GetVolumeStatus operation type
  */
@@ -1773,7 +1588,7 @@ static const struct afs_call_type afs_RXFSGetVolumeStatus = {
        .name           = "FS.GetVolumeStatus",
        .op             = afs_FS_GetVolumeStatus,
        .deliver        = afs_deliver_fs_get_volume_status,
-       .destructor     = afs_get_volume_status_call_destructor,
+       .destructor     = afs_flat_call_destructor,
 };
 
 /*
@@ -1786,27 +1601,19 @@ int afs_fs_get_volume_status(struct afs_fs_cursor *fc,
        struct afs_call *call;
        struct afs_net *net = afs_v2net(vnode);
        __be32 *bp;
-       void *tmpbuf;
 
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
                return yfs_fs_get_volume_status(fc, vs);
 
        _enter("");
 
-       tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
-       if (!tmpbuf)
-               return -ENOMEM;
-
-       call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
-       if (!call) {
-               kfree(tmpbuf);
+       call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4,
+                                  max(12 * 4, AFSOPAQUEMAX + 1));
+       if (!call)
                return -ENOMEM;
-       }
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->reply[1] = vs;
-       call->reply[2] = tmpbuf;
+       call->out_volstatus = vs;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1815,6 +1622,7 @@ int afs_fs_get_volume_status(struct afs_fs_cursor *fc,
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1835,7 +1643,7 @@ static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
+       xdr_decode_AFSVolSync(&bp, call->out_volsync);
 
        _leave(" = 0 [done]");
        return 0;
@@ -1876,7 +1684,8 @@ static const struct afs_call_type afs_RXFSReleaseLock = {
 /*
  * Set a lock on a file
  */
-int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
+int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type,
+                   struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -1884,7 +1693,7 @@ int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
        __be32 *bp;
 
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
-               return yfs_fs_set_lock(fc, type);
+               return yfs_fs_set_lock(fc, type, scb);
 
        _enter("");
 
@@ -1893,8 +1702,8 @@ int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->want_reply_time = true;
+       call->lvnode = vnode;
+       call->out_scb = scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1906,6 +1715,7 @@ int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_calli(call, &vnode->fid, type);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1913,7 +1723,7 @@ int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
 /*
  * extend a lock on a file
  */
-int afs_fs_extend_lock(struct afs_fs_cursor *fc)
+int afs_fs_extend_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -1921,7 +1731,7 @@ int afs_fs_extend_lock(struct afs_fs_cursor *fc)
        __be32 *bp;
 
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
-               return yfs_fs_extend_lock(fc);
+               return yfs_fs_extend_lock(fc, scb);
 
        _enter("");
 
@@ -1930,8 +1740,8 @@ int afs_fs_extend_lock(struct afs_fs_cursor *fc)
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->want_reply_time = true;
+       call->lvnode = vnode;
+       call->out_scb = scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1942,6 +1752,7 @@ int afs_fs_extend_lock(struct afs_fs_cursor *fc)
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1949,7 +1760,7 @@ int afs_fs_extend_lock(struct afs_fs_cursor *fc)
 /*
  * release a lock on a file
  */
-int afs_fs_release_lock(struct afs_fs_cursor *fc)
+int afs_fs_release_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -1957,7 +1768,7 @@ int afs_fs_release_lock(struct afs_fs_cursor *fc)
        __be32 *bp;
 
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
-               return yfs_fs_release_lock(fc);
+               return yfs_fs_release_lock(fc, scb);
 
        _enter("");
 
@@ -1966,7 +1777,8 @@ int afs_fs_release_lock(struct afs_fs_cursor *fc)
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
+       call->lvnode = vnode;
+       call->out_scb = scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1977,6 +1789,7 @@ int afs_fs_release_lock(struct afs_fs_cursor *fc)
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -2071,14 +1884,6 @@ static int afs_deliver_fs_get_capabilities(struct afs_call *call)
        return 0;
 }
 
-static void afs_destroy_fs_get_capabilities(struct afs_call *call)
-{
-       struct afs_server *server = call->reply[0];
-
-       afs_put_server(call->net, server);
-       afs_flat_call_destructor(call);
-}
-
 /*
  * FS.GetCapabilities operation type
  */
@@ -2087,7 +1892,7 @@ static const struct afs_call_type afs_RXFSGetCapabilities = {
        .op             = afs_FS_GetCapabilities,
        .deliver        = afs_deliver_fs_get_capabilities,
        .done           = afs_fileserver_probe_result,
-       .destructor     = afs_destroy_fs_get_capabilities,
+       .destructor     = afs_flat_call_destructor,
 };
 
 /*
@@ -2110,11 +1915,11 @@ struct afs_call *afs_fs_get_capabilities(struct afs_net *net,
                return ERR_PTR(-ENOMEM);
 
        call->key = key;
-       call->reply[0] = afs_get_server(server);
-       call->reply[1] = (void *)(long)server_index;
+       call->server = afs_get_server(server);
+       call->server_index = server_index;
        call->upgrade = true;
-       call->want_reply_time = true;
        call->async = true;
+       call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
 
        /* marshall the parameters */
        bp = call->request;
@@ -2131,10 +1936,6 @@ struct afs_call *afs_fs_get_capabilities(struct afs_net *net,
  */
 static int afs_deliver_fs_fetch_status(struct afs_call *call)
 {
-       struct afs_file_status *status = call->reply[1];
-       struct afs_callback *callback = call->reply[2];
-       struct afs_volsync *volsync = call->reply[3];
-       struct afs_fid *fid = call->reply[0];
        const __be32 *bp;
        int ret;
 
@@ -2142,16 +1943,13 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call)
        if (ret < 0)
                return ret;
 
-       _enter("{%llx:%llu}", fid->vid, fid->vnode);
-
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       ret = afs_decode_status(call, &bp, status, NULL,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
        if (ret < 0)
                return ret;
-       xdr_decode_AFSCallBack_raw(call, &bp, callback);
-       xdr_decode_AFSVolSync(&bp, volsync);
+       xdr_decode_AFSCallBack(&bp, call, call->out_scb);
+       xdr_decode_AFSVolSync(&bp, call->out_volsync);
 
        _leave(" = 0 [done]");
        return 0;
@@ -2173,15 +1971,14 @@ static const struct afs_call_type afs_RXFSFetchStatus = {
 int afs_fs_fetch_status(struct afs_fs_cursor *fc,
                        struct afs_net *net,
                        struct afs_fid *fid,
-                       struct afs_file_status *status,
-                       struct afs_callback *callback,
+                       struct afs_status_cb *scb,
                        struct afs_volsync *volsync)
 {
        struct afs_call *call;
        __be32 *bp;
 
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
-               return yfs_fs_fetch_status(fc, net, fid, status, callback, volsync);
+               return yfs_fs_fetch_status(fc, net, fid, scb, volsync);
 
        _enter(",%x,{%llx:%llu},,",
               key_serial(fc->key), fid->vid, fid->vnode);
@@ -2193,12 +1990,9 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc,
        }
 
        call->key = fc->key;
-       call->reply[0] = fid;
-       call->reply[1] = status;
-       call->reply[2] = callback;
-       call->reply[3] = volsync;
-       call->expected_version = 1; /* vnode->status.data_version */
-       call->want_reply_time = true;
+       call->out_fid = fid;
+       call->out_scb = scb;
+       call->out_volsync = volsync;
 
        /* marshall the parameters */
        bp = call->request;
@@ -2207,9 +2001,9 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc,
        bp[2] = htonl(fid->vnode);
        bp[3] = htonl(fid->unique);
 
-       call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -2219,9 +2013,7 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc,
  */
 static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
 {
-       struct afs_file_status *statuses;
-       struct afs_callback *callbacks;
-       struct afs_vnode *vnode = call->reply[0];
+       struct afs_status_cb *scb;
        const __be32 *bp;
        u32 tmp;
        int ret;
@@ -2260,10 +2052,8 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
                        return ret;
 
                bp = call->buffer;
-               statuses = call->reply[1];
-               ret = afs_decode_status(call, &bp, &statuses[call->count],
-                                       call->count == 0 ? vnode : NULL,
-                                       NULL, NULL);
+               scb = &call->out_scb[call->count];
+               ret = xdr_decode_AFSFetchStatus(&bp, call, scb);
                if (ret < 0)
                        return ret;
 
@@ -2302,13 +2092,8 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
 
                _debug("unmarshall CB array");
                bp = call->buffer;
-               callbacks = call->reply[2];
-               callbacks[call->count].version  = ntohl(bp[0]);
-               callbacks[call->count].expires_at = xdr_decode_expiry(call, ntohl(bp[1]));
-               callbacks[call->count].type     = ntohl(bp[2]);
-               statuses = call->reply[1];
-               if (call->count == 0 && vnode && statuses[0].abort_code == 0)
-                       xdr_decode_AFSCallBack(call, vnode, &bp);
+               scb = &call->out_scb[call->count];
+               xdr_decode_AFSCallBack(&bp, call, scb);
                call->count++;
                if (call->count < call->count2)
                        goto more_cbs;
@@ -2323,7 +2108,7 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
                        return ret;
 
                bp = call->buffer;
-               xdr_decode_AFSVolSync(&bp, call->reply[3]);
+               xdr_decode_AFSVolSync(&bp, call->out_volsync);
 
                call->unmarshall++;
 
@@ -2351,8 +2136,7 @@ static const struct afs_call_type afs_RXFSInlineBulkStatus = {
 int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
                              struct afs_net *net,
                              struct afs_fid *fids,
-                             struct afs_file_status *statuses,
-                             struct afs_callback *callbacks,
+                             struct afs_status_cb *statuses,
                              unsigned int nr_fids,
                              struct afs_volsync *volsync)
 {
@@ -2361,7 +2145,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
        int i;
 
        if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
-               return yfs_fs_inline_bulk_status(fc, net, fids, statuses, callbacks,
+               return yfs_fs_inline_bulk_status(fc, net, fids, statuses,
                                                 nr_fids, volsync);
 
        _enter(",%x,{%llx:%llu},%u",
@@ -2376,12 +2160,9 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
        }
 
        call->key = fc->key;
-       call->reply[0] = NULL; /* vnode for fid[0] */
-       call->reply[1] = statuses;
-       call->reply[2] = callbacks;
-       call->reply[3] = volsync;
+       call->out_scb = statuses;
+       call->out_volsync = volsync;
        call->count2 = nr_fids;
-       call->want_reply_time = true;
 
        /* marshall the parameters */
        bp = call->request;
@@ -2393,9 +2174,9 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
                *bp++ = htonl(fids[i].unique);
        }
 
-       call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &fids[0]);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -2405,7 +2186,6 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
  */
 static int afs_deliver_fs_fetch_acl(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply[1];
        struct afs_acl *acl;
        const __be32 *bp;
        unsigned int size;
@@ -2430,7 +2210,7 @@ static int afs_deliver_fs_fetch_acl(struct afs_call *call)
                acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
                if (!acl)
                        return -ENOMEM;
-               call->reply[0] = acl;
+               call->ret_acl = acl;
                acl->size = call->count2;
                afs_extract_begin(call, acl->data, size);
                call->unmarshall++;
@@ -2451,11 +2231,10 @@ static int afs_deliver_fs_fetch_acl(struct afs_call *call)
                        return ret;
 
                bp = call->buffer;
-               ret = afs_decode_status(call, &bp, &vnode->status, vnode,
-                                       &vnode->status.data_version, NULL);
+               ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
                if (ret < 0)
                        return ret;
-               xdr_decode_AFSVolSync(&bp, call->reply[2]);
+               xdr_decode_AFSVolSync(&bp, call->out_volsync);
 
                call->unmarshall++;
 
@@ -2469,7 +2248,7 @@ static int afs_deliver_fs_fetch_acl(struct afs_call *call)
 
 static void afs_destroy_fs_fetch_acl(struct afs_call *call)
 {
-       kfree(call->reply[0]);
+       kfree(call->ret_acl);
        afs_flat_call_destructor(call);
 }
 
@@ -2486,7 +2265,8 @@ static const struct afs_call_type afs_RXFSFetchACL = {
 /*
  * Fetch the ACL for a file.
  */
-struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc)
+struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc,
+                                struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -2503,10 +2283,9 @@ struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc)
        }
 
        call->key = fc->key;
-       call->reply[0] = NULL;
-       call->reply[1] = vnode;
-       call->reply[2] = NULL; /* volsync */
-       call->ret_reply0 = true;
+       call->ret_acl = NULL;
+       call->out_scb = scb;
+       call->out_volsync = NULL;
 
        /* marshall the parameters */
        bp = call->request;
@@ -2515,27 +2294,50 @@ struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc)
        bp[2] = htonl(vnode->fid.vnode);
        bp[3] = htonl(vnode->fid.unique);
 
-       call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
        afs_make_call(&fc->ac, call, GFP_KERNEL);
        return (struct afs_acl *)afs_wait_for_call_to_complete(call, &fc->ac);
 }
 
+/*
+ * Deliver reply data to any operation that returns file status and volume
+ * sync.
+ */
+static int afs_deliver_fs_file_status_and_vol(struct afs_call *call)
+{
+       const __be32 *bp;
+       int ret;
+
+       ret = afs_transfer_reply(call);
+       if (ret < 0)
+               return ret;
+
+       bp = call->buffer;
+       ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
+       if (ret < 0)
+               return ret;
+       xdr_decode_AFSVolSync(&bp, call->out_volsync);
+
+       _leave(" = 0 [done]");
+       return 0;
+}
+
 /*
  * FS.StoreACL operation type
  */
 static const struct afs_call_type afs_RXFSStoreACL = {
        .name           = "FS.StoreACL",
        .op             = afs_FS_StoreACL,
-       .deliver        = afs_deliver_fs_status_and_vol,
+       .deliver        = afs_deliver_fs_file_status_and_vol,
        .destructor     = afs_flat_call_destructor,
 };
 
 /*
  * Fetch the ACL for a file.
  */
-int afs_fs_store_acl(struct afs_fs_cursor *fc, const struct afs_acl *acl)
+int afs_fs_store_acl(struct afs_fs_cursor *fc, const struct afs_acl *acl,
+                    struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -2555,8 +2357,8 @@ int afs_fs_store_acl(struct afs_fs_cursor *fc, const struct afs_acl *acl)
        }
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->reply[2] = NULL; /* volsync */
+       call->out_scb = scb;
+       call->out_volsync = NULL;
 
        /* marshall the parameters */
        bp = call->request;
index c4652b42d545ffa8b5999e3fe7358601969b79c3..b42d9d09669c863ce51ef463bc695085c072eccd 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/namei.h>
 #include <linux/iversion.h>
 #include "internal.h"
+#include "afs_fs.h"
 
 static const struct inode_operations afs_symlink_inode_operations = {
        .get_link       = page_get_link,
@@ -58,38 +59,50 @@ static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *paren
  * Initialise an inode from the vnode status.
  */
 static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key,
-                                     struct afs_vnode *parent_vnode)
+                                     struct afs_cb_interest *cbi,
+                                     struct afs_vnode *parent_vnode,
+                                     struct afs_status_cb *scb)
 {
+       struct afs_cb_interest *old_cbi = NULL;
+       struct afs_file_status *status = &scb->status;
        struct inode *inode = AFS_VNODE_TO_I(vnode);
+       struct timespec64 t;
 
        _debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu",
-              vnode->status.type,
-              vnode->status.nlink,
-              (unsigned long long) vnode->status.size,
-              vnode->status.data_version,
-              vnode->status.mode);
+              status->type,
+              status->nlink,
+              (unsigned long long) status->size,
+              status->data_version,
+              status->mode);
 
-       read_seqlock_excl(&vnode->cb_lock);
+       write_seqlock(&vnode->cb_lock);
 
-       afs_update_inode_from_status(vnode, &vnode->status, NULL,
-                                    AFS_VNODE_NOT_YET_SET);
+       vnode->status = *status;
 
-       switch (vnode->status.type) {
+       t = status->mtime_client;
+       inode->i_ctime = t;
+       inode->i_mtime = t;
+       inode->i_atime = t;
+       inode->i_uid = make_kuid(&init_user_ns, status->owner);
+       inode->i_gid = make_kgid(&init_user_ns, status->group);
+       set_nlink(&vnode->vfs_inode, status->nlink);
+
+       switch (status->type) {
        case AFS_FTYPE_FILE:
-               inode->i_mode   = S_IFREG | vnode->status.mode;
+               inode->i_mode   = S_IFREG | status->mode;
                inode->i_op     = &afs_file_inode_operations;
                inode->i_fop    = &afs_file_operations;
                inode->i_mapping->a_ops = &afs_fs_aops;
                break;
        case AFS_FTYPE_DIR:
-               inode->i_mode   = S_IFDIR | vnode->status.mode;
+               inode->i_mode   = S_IFDIR | status->mode;
                inode->i_op     = &afs_dir_inode_operations;
                inode->i_fop    = &afs_dir_file_operations;
                inode->i_mapping->a_ops = &afs_dir_aops;
                break;
        case AFS_FTYPE_SYMLINK:
                /* Symlinks with a mode of 0644 are actually mountpoints. */
-               if ((vnode->status.mode & 0777) == 0644) {
+               if ((status->mode & 0777) == 0644) {
                        inode->i_flags |= S_AUTOMOUNT;
 
                        set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
@@ -99,7 +112,7 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key,
                        inode->i_fop    = &afs_mntpt_file_operations;
                        inode->i_mapping->a_ops = &afs_fs_aops;
                } else {
-                       inode->i_mode   = S_IFLNK | vnode->status.mode;
+                       inode->i_mode   = S_IFLNK | status->mode;
                        inode->i_op     = &afs_symlink_inode_operations;
                        inode->i_mapping->a_ops = &afs_fs_aops;
                }
@@ -107,7 +120,7 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key,
                break;
        default:
                dump_vnode(vnode, parent_vnode);
-               read_sequnlock_excl(&vnode->cb_lock);
+               write_sequnlock(&vnode->cb_lock);
                return afs_protocol_error(NULL, -EBADMSG, afs_eproto_file_type);
        }
 
@@ -116,17 +129,175 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key,
         * for consistency with other AFS clients.
         */
        inode->i_blocks         = ((i_size_read(inode) + 1023) >> 10) << 1;
-       vnode->invalid_before   = vnode->status.data_version;
+       i_size_write(&vnode->vfs_inode, status->size);
+
+       vnode->invalid_before   = status->data_version;
+       inode_set_iversion_raw(&vnode->vfs_inode, status->data_version);
+
+       if (!scb->have_cb) {
+               /* it's a symlink we just created (the fileserver
+                * didn't give us a callback) */
+               vnode->cb_expires_at = ktime_get_real_seconds();
+       } else {
+               vnode->cb_expires_at = scb->callback.expires_at;
+               old_cbi = rcu_dereference_protected(vnode->cb_interest,
+                                                   lockdep_is_held(&vnode->cb_lock.lock));
+               if (cbi != old_cbi)
+                       rcu_assign_pointer(vnode->cb_interest, afs_get_cb_interest(cbi));
+               else
+                       old_cbi = NULL;
+               set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
+       }
 
-       read_sequnlock_excl(&vnode->cb_lock);
+       write_sequnlock(&vnode->cb_lock);
+       afs_put_cb_interest(afs_v2net(vnode), old_cbi);
        return 0;
 }
 
+/*
+ * Update the core inode struct from a returned status record.
+ */
+static void afs_apply_status(struct afs_fs_cursor *fc,
+                            struct afs_vnode *vnode,
+                            struct afs_status_cb *scb,
+                            const afs_dataversion_t *expected_version)
+{
+       struct afs_file_status *status = &scb->status;
+       struct timespec64 t;
+       umode_t mode;
+       bool data_changed = false;
+
+       BUG_ON(test_bit(AFS_VNODE_UNSET, &vnode->flags));
+
+       if (status->type != vnode->status.type) {
+               pr_warning("Vnode %llx:%llx:%x changed type %u to %u\n",
+                          vnode->fid.vid,
+                          vnode->fid.vnode,
+                          vnode->fid.unique,
+                          status->type, vnode->status.type);
+               afs_protocol_error(NULL, -EBADMSG, afs_eproto_bad_status);
+               return;
+       }
+
+       if (status->nlink != vnode->status.nlink)
+               set_nlink(&vnode->vfs_inode, status->nlink);
+
+       if (status->owner != vnode->status.owner)
+               vnode->vfs_inode.i_uid = make_kuid(&init_user_ns, status->owner);
+
+       if (status->group != vnode->status.group)
+               vnode->vfs_inode.i_gid = make_kgid(&init_user_ns, status->group);
+
+       if (status->mode != vnode->status.mode) {
+               mode = vnode->vfs_inode.i_mode;
+               mode &= ~S_IALLUGO;
+               mode |= status->mode;
+               WRITE_ONCE(vnode->vfs_inode.i_mode, mode);
+       }
+
+       t = status->mtime_client;
+       vnode->vfs_inode.i_ctime = t;
+       vnode->vfs_inode.i_mtime = t;
+       vnode->vfs_inode.i_atime = t;
+
+       if (vnode->status.data_version != status->data_version)
+               data_changed = true;
+
+       vnode->status = *status;
+
+       if (expected_version &&
+           *expected_version != status->data_version) {
+               kdebug("vnode modified %llx on {%llx:%llu} [exp %llx] %s",
+                      (unsigned long long) status->data_version,
+                      vnode->fid.vid, vnode->fid.vnode,
+                      (unsigned long long) *expected_version,
+                      fc->type ? fc->type->name : "???");
+               vnode->invalid_before = status->data_version;
+               if (vnode->status.type == AFS_FTYPE_DIR) {
+                       if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
+                               afs_stat_v(vnode, n_inval);
+               } else {
+                       set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
+               }
+       } else if (vnode->status.type == AFS_FTYPE_DIR) {
+               /* Expected directory change is handled elsewhere so
+                * that we can locally edit the directory and save on a
+                * download.
+                */
+               if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
+                       data_changed = false;
+       }
+
+       if (data_changed) {
+               inode_set_iversion_raw(&vnode->vfs_inode, status->data_version);
+               i_size_write(&vnode->vfs_inode, status->size);
+       }
+}
+
+/*
+ * Apply a callback to a vnode.
+ */
+static void afs_apply_callback(struct afs_fs_cursor *fc,
+                              struct afs_vnode *vnode,
+                              struct afs_status_cb *scb,
+                              unsigned int cb_break)
+{
+       struct afs_cb_interest *old;
+       struct afs_callback *cb = &scb->callback;
+
+       if (!afs_cb_is_broken(cb_break, vnode, fc->cbi)) {
+               vnode->cb_expires_at    = cb->expires_at;
+               old = rcu_dereference_protected(vnode->cb_interest,
+                                               lockdep_is_held(&vnode->cb_lock.lock));
+               if (old != fc->cbi) {
+                       rcu_assign_pointer(vnode->cb_interest, afs_get_cb_interest(fc->cbi));
+                       afs_put_cb_interest(afs_v2net(vnode), old);
+               }
+               set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
+       }
+}
+
+/*
+ * Apply the received status and callback to an inode all in the same critical
+ * section to avoid races with afs_validate().
+ */
+void afs_vnode_commit_status(struct afs_fs_cursor *fc,
+                            struct afs_vnode *vnode,
+                            unsigned int cb_break,
+                            const afs_dataversion_t *expected_version,
+                            struct afs_status_cb *scb)
+{
+       if (fc->ac.error != 0)
+               return;
+
+       write_seqlock(&vnode->cb_lock);
+
+       if (scb->have_error) {
+               if (scb->status.abort_code == VNOVNODE) {
+                       set_bit(AFS_VNODE_DELETED, &vnode->flags);
+                       clear_nlink(&vnode->vfs_inode);
+                       __afs_break_callback(vnode);
+               }
+       } else {
+               if (scb->have_status)
+                       afs_apply_status(fc, vnode, scb, expected_version);
+               if (scb->have_cb)
+                       afs_apply_callback(fc, vnode, scb, cb_break);
+       }
+
+       write_sequnlock(&vnode->cb_lock);
+
+       if (fc->ac.error == 0 && scb->have_status)
+               afs_cache_permit(vnode, fc->key, cb_break, scb);
+}
+
 /*
  * Fetch file status from the volume.
  */
-int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode)
+int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool is_new,
+                    afs_access_t *_caller_access)
 {
+       struct afs_status_cb *scb;
        struct afs_fs_cursor fc;
        int ret;
 
@@ -135,18 +306,38 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode)
               vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique,
               vnode->flags);
 
+       scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               return -ENOMEM;
+
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, vnode, key)) {
+       if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
+               afs_dataversion_t data_version = vnode->status.data_version;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
-                       afs_fs_fetch_file_status(&fc, NULL, new_inode);
+                       afs_fs_fetch_file_status(&fc, scb, NULL);
                }
 
-               afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, vnode, fc.cb_break);
+               if (fc.error) {
+                       /* Do nothing. */
+               } else if (is_new) {
+                       ret = afs_inode_init_from_status(vnode, key, fc.cbi,
+                                                        NULL, scb);
+                       fc.error = ret;
+                       if (ret == 0)
+                               afs_cache_permit(vnode, key, fc.cb_break, scb);
+               } else {
+                       afs_vnode_commit_status(&fc, vnode, fc.cb_break,
+                                               &data_version, scb);
+               }
+               afs_check_for_remote_deletion(&fc, vnode);
                ret = afs_end_vnode_operation(&fc);
        }
 
+       if (ret == 0 && _caller_access)
+               *_caller_access = scb->status.caller_access;
+       kfree(scb);
        _leave(" = %d", ret);
        return ret;
 }
@@ -156,10 +347,10 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode)
  */
 int afs_iget5_test(struct inode *inode, void *opaque)
 {
-       struct afs_iget_data *data = opaque;
+       struct afs_iget_data *iget_data = opaque;
        struct afs_vnode *vnode = AFS_FS_I(inode);
 
-       return memcmp(&vnode->fid, &data->fid, sizeof(data->fid)) == 0;
+       return memcmp(&vnode->fid, &iget_data->fid, sizeof(iget_data->fid)) == 0;
 }
 
 /*
@@ -177,17 +368,19 @@ static int afs_iget5_pseudo_dir_test(struct inode *inode, void *opaque)
  */
 static int afs_iget5_set(struct inode *inode, void *opaque)
 {
-       struct afs_iget_data *data = opaque;
+       struct afs_iget_data *iget_data = opaque;
        struct afs_vnode *vnode = AFS_FS_I(inode);
 
-       vnode->fid = data->fid;
-       vnode->volume = data->volume;
+       vnode->fid              = iget_data->fid;
+       vnode->volume           = iget_data->volume;
+       vnode->cb_v_break       = iget_data->cb_v_break;
+       vnode->cb_s_break       = iget_data->cb_s_break;
 
        /* YFS supports 96-bit vnode IDs, but Linux only supports
         * 64-bit inode numbers.
         */
-       inode->i_ino data->fid.vnode;
-       inode->i_generation data->fid.unique;
+       inode->i_ino            = iget_data->fid.vnode;
+       inode->i_generation     = iget_data->fid.unique;
        return 0;
 }
 
@@ -197,38 +390,42 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
  */
 struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root)
 {
-       struct afs_iget_data data;
        struct afs_super_info *as;
        struct afs_vnode *vnode;
        struct inode *inode;
        static atomic_t afs_autocell_ino;
 
+       struct afs_iget_data iget_data = {
+               .cb_v_break = 0,
+               .cb_s_break = 0,
+       };
+
        _enter("");
 
        as = sb->s_fs_info;
        if (as->volume) {
-               data.volume = as->volume;
-               data.fid.vid = as->volume->vid;
+               iget_data.volume = as->volume;
+               iget_data.fid.vid = as->volume->vid;
        }
        if (root) {
-               data.fid.vnode = 1;
-               data.fid.unique = 1;
+               iget_data.fid.vnode = 1;
+               iget_data.fid.unique = 1;
        } else {
-               data.fid.vnode = atomic_inc_return(&afs_autocell_ino);
-               data.fid.unique = 0;
+               iget_data.fid.vnode = atomic_inc_return(&afs_autocell_ino);
+               iget_data.fid.unique = 0;
        }
 
-       inode = iget5_locked(sb, data.fid.vnode,
+       inode = iget5_locked(sb, iget_data.fid.vnode,
                             afs_iget5_pseudo_dir_test, afs_iget5_set,
-                            &data);
+                            &iget_data);
        if (!inode) {
                _leave(" = -ENOMEM");
                return ERR_PTR(-ENOMEM);
        }
 
        _debug("GOT INODE %p { ino=%lu, vl=%llx, vn=%llx, u=%x }",
-              inode, inode->i_ino, data.fid.vid, data.fid.vnode,
-              data.fid.unique);
+              inode, inode->i_ino, iget_data.fid.vid, iget_data.fid.vnode,
+              iget_data.fid.unique);
 
        vnode = AFS_FS_I(inode);
 
@@ -299,23 +496,24 @@ static void afs_get_inode_cache(struct afs_vnode *vnode)
  * inode retrieval
  */
 struct inode *afs_iget(struct super_block *sb, struct key *key,
-                      struct afs_fid *fid, struct afs_file_status *status,
-                      struct afs_callback *cb, struct afs_cb_interest *cbi,
+                      struct afs_iget_data *iget_data,
+                      struct afs_status_cb *scb,
+                      struct afs_cb_interest *cbi,
                       struct afs_vnode *parent_vnode)
 {
-       struct afs_iget_data data = { .fid = *fid };
        struct afs_super_info *as;
        struct afs_vnode *vnode;
+       struct afs_fid *fid = &iget_data->fid;
        struct inode *inode;
        int ret;
 
        _enter(",{%llx:%llu.%u},,", fid->vid, fid->vnode, fid->unique);
 
        as = sb->s_fs_info;
-       data.volume = as->volume;
+       iget_data->volume = as->volume;
 
        inode = iget5_locked(sb, fid->vnode, afs_iget5_test, afs_iget5_set,
-                            &data);
+                            iget_data);
        if (!inode) {
                _leave(" = -ENOMEM");
                return ERR_PTR(-ENOMEM);
@@ -332,43 +530,25 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
                return inode;
        }
 
-       if (!status) {
+       if (!scb) {
                /* it's a remotely extant inode */
-               ret = afs_fetch_status(vnode, key, true);
+               ret = afs_fetch_status(vnode, key, true, NULL);
                if (ret < 0)
                        goto bad_inode;
        } else {
-               /* it's an inode we just created */
-               memcpy(&vnode->status, status, sizeof(vnode->status));
-
-               if (!cb) {
-                       /* it's a symlink we just created (the fileserver
-                        * didn't give us a callback) */
-                       vnode->cb_version = 0;
-                       vnode->cb_type = 0;
-                       vnode->cb_expires_at = ktime_get();
-               } else {
-                       vnode->cb_version = cb->version;
-                       vnode->cb_type = cb->type;
-                       vnode->cb_expires_at = cb->expires_at;
-                       vnode->cb_interest = afs_get_cb_interest(cbi);
-                       set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
-               }
-
-               vnode->cb_expires_at += ktime_get_real_seconds();
+               ret = afs_inode_init_from_status(vnode, key, cbi, parent_vnode,
+                                                scb);
+               if (ret < 0)
+                       goto bad_inode;
        }
 
-       ret = afs_inode_init_from_status(vnode, key, parent_vnode);
-       if (ret < 0)
-               goto bad_inode;
-
        afs_get_inode_cache(vnode);
 
        /* success */
        clear_bit(AFS_VNODE_UNSET, &vnode->flags);
        inode->i_flags |= S_NOATIME;
        unlock_new_inode(inode);
-       _leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type);
+       _leave(" = %p", inode);
        return inode;
 
        /* failure */
@@ -399,6 +579,66 @@ void afs_zap_data(struct afs_vnode *vnode)
                invalidate_inode_pages2(vnode->vfs_inode.i_mapping);
 }
 
+/*
+ * Check the validity of a vnode/inode.
+ */
+bool afs_check_validity(struct afs_vnode *vnode)
+{
+       struct afs_cb_interest *cbi;
+       struct afs_server *server;
+       struct afs_volume *volume = vnode->volume;
+       time64_t now = ktime_get_real_seconds();
+       bool valid, need_clear = false;
+       unsigned int cb_break, cb_s_break, cb_v_break;
+       int seq = 0;
+
+       do {
+               read_seqbegin_or_lock(&vnode->cb_lock, &seq);
+               cb_v_break = READ_ONCE(volume->cb_v_break);
+               cb_break = vnode->cb_break;
+
+               if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
+                       cbi = rcu_dereference(vnode->cb_interest);
+                       server = rcu_dereference(cbi->server);
+                       cb_s_break = READ_ONCE(server->cb_s_break);
+
+                       if (vnode->cb_s_break != cb_s_break ||
+                           vnode->cb_v_break != cb_v_break) {
+                               vnode->cb_s_break = cb_s_break;
+                               vnode->cb_v_break = cb_v_break;
+                               need_clear = true;
+                               valid = false;
+                       } else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
+                               need_clear = true;
+                               valid = false;
+                       } else if (vnode->cb_expires_at - 10 <= now) {
+                               need_clear = true;
+                               valid = false;
+                       } else {
+                               valid = true;
+                       }
+               } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
+                       valid = true;
+               } else {
+                       vnode->cb_v_break = cb_v_break;
+                       valid = false;
+               }
+
+       } while (need_seqretry(&vnode->cb_lock, seq));
+
+       done_seqretry(&vnode->cb_lock, seq);
+
+       if (need_clear) {
+               write_seqlock(&vnode->cb_lock);
+               if (cb_break == vnode->cb_break)
+                       __afs_break_callback(vnode);
+               write_sequnlock(&vnode->cb_lock);
+               valid = false;
+       }
+
+       return valid;
+}
+
 /*
  * validate a vnode/inode
  * - there are several things we need to check
@@ -410,7 +650,6 @@ void afs_zap_data(struct afs_vnode *vnode)
  */
 int afs_validate(struct afs_vnode *vnode, struct key *key)
 {
-       time64_t now = ktime_get_real_seconds();
        bool valid;
        int ret;
 
@@ -418,36 +657,9 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
               vnode->fid.vid, vnode->fid.vnode, vnode->flags,
               key_serial(key));
 
-       /* Quickly check the callback state.  Ideally, we'd use read_seqbegin
-        * here, but we have no way to pass the net namespace to the RCU
-        * cleanup for the server record.
-        */
-       read_seqlock_excl(&vnode->cb_lock);
-
-       if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
-               if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break ||
-                   vnode->cb_v_break != vnode->volume->cb_v_break) {
-                       vnode->cb_s_break = vnode->cb_interest->server->cb_s_break;
-                       vnode->cb_v_break = vnode->volume->cb_v_break;
-                       valid = false;
-               } else if (vnode->status.type == AFS_FTYPE_DIR &&
-                          (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) ||
-                           vnode->cb_expires_at - 10 <= now)) {
-                       valid = false;
-               } else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) ||
-                          vnode->cb_expires_at - 10 <= now) {
-                       valid = false;
-               } else {
-                       valid = true;
-               }
-       } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
-               valid = true;
-       } else {
-               vnode->cb_v_break = vnode->volume->cb_v_break;
-               valid = false;
-       }
-
-       read_sequnlock_excl(&vnode->cb_lock);
+       rcu_read_lock();
+       valid = afs_check_validity(vnode);
+       rcu_read_unlock();
 
        if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
                clear_nlink(&vnode->vfs_inode);
@@ -463,7 +675,7 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
         * access */
        if (!test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
                _debug("not promised");
-               ret = afs_fetch_status(vnode, key, false);
+               ret = afs_fetch_status(vnode, key, false, NULL);
                if (ret < 0) {
                        if (ret == -ENOENT) {
                                set_bit(AFS_VNODE_DELETED, &vnode->flags);
@@ -534,6 +746,7 @@ int afs_drop_inode(struct inode *inode)
  */
 void afs_evict_inode(struct inode *inode)
 {
+       struct afs_cb_interest *cbi;
        struct afs_vnode *vnode;
 
        vnode = AFS_FS_I(inode);
@@ -550,10 +763,14 @@ void afs_evict_inode(struct inode *inode)
        truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
 
-       if (vnode->cb_interest) {
-               afs_put_cb_interest(afs_i2net(inode), vnode->cb_interest);
-               vnode->cb_interest = NULL;
+       write_seqlock(&vnode->cb_lock);
+       cbi = rcu_dereference_protected(vnode->cb_interest,
+                                       lockdep_is_held(&vnode->cb_lock.lock));
+       if (cbi) {
+               afs_put_cb_interest(afs_i2net(inode), cbi);
+               rcu_assign_pointer(vnode->cb_interest, NULL);
        }
+       write_sequnlock(&vnode->cb_lock);
 
        while (!list_empty(&vnode->wb_keys)) {
                struct afs_wb_key *wbk = list_entry(vnode->wb_keys.next,
@@ -573,6 +790,7 @@ void afs_evict_inode(struct inode *inode)
        }
 #endif
 
+       afs_prune_wb_keys(vnode);
        afs_put_permits(rcu_access_pointer(vnode->permit_cache));
        key_put(vnode->silly_key);
        vnode->silly_key = NULL;
@@ -587,9 +805,10 @@ void afs_evict_inode(struct inode *inode)
 int afs_setattr(struct dentry *dentry, struct iattr *attr)
 {
        struct afs_fs_cursor fc;
+       struct afs_status_cb *scb;
        struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
        struct key *key;
-       int ret;
+       int ret = -ENOMEM;
 
        _enter("{%llx:%llu},{n=%pd},%x",
               vnode->fid.vid, vnode->fid.vnode, dentry,
@@ -601,6 +820,10 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
                return 0;
        }
 
+       scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL);
+       if (!scb)
+               goto error;
+
        /* flush any dirty data outstanding on a regular file */
        if (S_ISREG(vnode->vfs_inode.i_mode))
                filemap_write_and_wait(vnode->vfs_inode.i_mapping);
@@ -611,25 +834,33 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
                key = afs_request_key(vnode->volume->cell);
                if (IS_ERR(key)) {
                        ret = PTR_ERR(key);
-                       goto error;
+                       goto error_scb;
                }
        }
 
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, vnode, key)) {
+       if (afs_begin_vnode_operation(&fc, vnode, key, false)) {
+               afs_dataversion_t data_version = vnode->status.data_version;
+
+               if (attr->ia_valid & ATTR_SIZE)
+                       data_version++;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
-                       afs_fs_setattr(&fc, attr);
+                       afs_fs_setattr(&fc, attr, scb);
                }
 
-               afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, vnode, fc.cb_break);
+               afs_check_for_remote_deletion(&fc, vnode);
+               afs_vnode_commit_status(&fc, vnode, fc.cb_break,
+                                       &data_version, scb);
                ret = afs_end_vnode_operation(&fc);
        }
 
        if (!(attr->ia_valid & ATTR_FILE))
                key_put(key);
 
+error_scb:
+       kfree(scb);
 error:
        _leave(" = %d", ret);
        return ret;
index b3cd6e8ad59d1ea91fe7dd03ac7e63e6d036bfdf..2073c1a3ab4b658606c42b52a153d057de72cd1c 100644 (file)
@@ -66,6 +66,8 @@ struct afs_fs_context {
 struct afs_iget_data {
        struct afs_fid          fid;
        struct afs_volume       *volume;        /* volume on which resides */
+       unsigned int            cb_v_break;     /* Pre-fetch volume break count */
+       unsigned int            cb_s_break;     /* Pre-fetch server break count */
 };
 
 enum afs_call_state {
@@ -111,8 +113,12 @@ struct afs_call {
        struct rxrpc_call       *rxcall;        /* RxRPC call handle */
        struct key              *key;           /* security for this call */
        struct afs_net          *net;           /* The network namespace */
-       struct afs_server       *cm_server;     /* Server affected by incoming CM call */
+       union {
+               struct afs_server       *server;
+               struct afs_vlserver     *vlserver;
+       };
        struct afs_cb_interest  *cbi;           /* Callback interest for server used */
+       struct afs_vnode        *lvnode;        /* vnode being locked */
        void                    *request;       /* request data (first part) */
        struct address_space    *mapping;       /* Pages being written from */
        struct iov_iter         iter;           /* Buffer iterator */
@@ -122,7 +128,20 @@ struct afs_call {
                struct bio_vec  bvec[1];
        };
        void                    *buffer;        /* reply receive buffer */
-       void                    *reply[4];      /* Where to put the reply */
+       union {
+               long                    ret0;   /* Value to reply with instead of 0 */
+               struct afs_addr_list    *ret_alist;
+               struct afs_vldb_entry   *ret_vldb;
+               struct afs_acl          *ret_acl;
+       };
+       struct afs_fid          *out_fid;
+       struct afs_status_cb    *out_dir_scb;
+       struct afs_status_cb    *out_scb;
+       struct yfs_acl          *out_yacl;
+       struct afs_volsync      *out_volsync;
+       struct afs_volume_status *out_volstatus;
+       struct afs_read         *read_request;
+       unsigned int            server_index;
        pgoff_t                 first;          /* first page in mapping to deal with */
        pgoff_t                 last;           /* last page in mapping to deal with */
        atomic_t                usage;
@@ -131,10 +150,10 @@ struct afs_call {
        int                     error;          /* error code */
        u32                     abort_code;     /* Remote abort ID or 0 */
        u32                     epoch;
+       unsigned int            max_lifespan;   /* Maximum lifespan to set if not 0 */
        unsigned                request_size;   /* size of request data */
        unsigned                reply_max;      /* maximum size of reply */
        unsigned                first_offset;   /* offset into mapping[first] */
-       unsigned int            cb_break;       /* cb_break + cb_s_break before the call */
        union {
                unsigned        last_to;        /* amount of mapping[last] */
                unsigned        count2;         /* count used in unmarshalling */
@@ -145,9 +164,9 @@ struct afs_call {
        bool                    send_pages;     /* T if data from mapping should be sent */
        bool                    need_attention; /* T if RxRPC poked us */
        bool                    async;          /* T if asynchronous */
-       bool                    ret_reply0;     /* T if should return reply[0] on success */
        bool                    upgrade;        /* T to request service upgrade */
-       bool                    want_reply_time; /* T if want reply_time */
+       bool                    have_reply_time; /* T if have got reply_time */
+       bool                    intr;           /* T if interruptible */
        u16                     service_id;     /* Actual service ID (after upgrade) */
        unsigned int            debug_id;       /* Trace ID */
        u32                     operation_ID;   /* operation ID for an incoming call */
@@ -159,8 +178,6 @@ struct afs_call {
                } __attribute__((packed));
                __be64          tmp64;
        };
-       afs_dataversion_t       expected_version; /* Updated version expected from store */
-       afs_dataversion_t       expected_version_2; /* 2nd updated version expected from store */
        ktime_t                 reply_time;     /* Time of first reply packet */
 };
 
@@ -221,7 +238,8 @@ struct afs_read {
        unsigned int            index;          /* Which page we're reading into */
        unsigned int            nr_pages;
        unsigned int            offset;         /* offset into current page */
-       void (*page_done)(struct afs_call *, struct afs_read *);
+       struct afs_vnode        *vnode;
+       void (*page_done)(struct afs_read *);
        struct page             **pages;
        struct page             *array[];
 };
@@ -367,13 +385,13 @@ struct afs_cell {
        time64_t                last_inactive;  /* Time of last drop of usage count */
        atomic_t                usage;
        unsigned long           flags;
-#define AFS_CELL_FL_NOT_READY  0               /* The cell record is not ready for use */
-#define AFS_CELL_FL_NO_GC      1               /* The cell was added manually, don't auto-gc */
-#define AFS_CELL_FL_NOT_FOUND  2               /* Permanent DNS error */
-#define AFS_CELL_FL_DNS_FAIL   3               /* Failed to access DNS */
-#define AFS_CELL_FL_NO_LOOKUP_YET 4            /* Not completed first DNS lookup yet */
+#define AFS_CELL_FL_NO_GC      0               /* The cell was added manually, don't auto-gc */
+#define AFS_CELL_FL_DO_LOOKUP  1               /* DNS lookup requested */
        enum afs_cell_state     state;
        short                   error;
+       enum dns_record_source  dns_source:8;   /* Latest source of data from lookup */
+       enum dns_lookup_status  dns_status:8;   /* Latest status of data from lookup */
+       unsigned int            dns_lookup_count; /* Counter of DNS lookups */
 
        /* Active fileserver interaction state. */
        struct list_head        proc_volumes;   /* procfs volume list */
@@ -538,7 +556,10 @@ struct afs_server {
 struct afs_vol_interest {
        struct hlist_node       srv_link;       /* Link in server->cb_volumes */
        struct hlist_head       cb_interests;   /* List of callback interests on the server */
-       afs_volid_t             vid;            /* Volume ID to match */
+       union {
+               struct rcu_head rcu;
+               afs_volid_t     vid;            /* Volume ID to match */
+       };
        unsigned int            usage;
 };
 
@@ -550,7 +571,10 @@ struct afs_cb_interest {
        struct afs_vol_interest *vol_interest;
        struct afs_server       *server;        /* Server on which this interest resides */
        struct super_block      *sb;            /* Superblock on which inodes reside */
-       afs_volid_t             vid;            /* Volume ID to match */
+       union {
+               struct rcu_head rcu;
+               afs_volid_t     vid;            /* Volume ID to match */
+       };
        refcount_t              usage;
 };
 
@@ -660,15 +684,13 @@ struct afs_vnode {
        afs_lock_type_t         lock_type : 8;
 
        /* outstanding callback notification on this file */
-       struct afs_cb_interest  *cb_interest;   /* Server on which this resides */
+       struct afs_cb_interest __rcu *cb_interest; /* Server on which this resides */
        unsigned int            cb_s_break;     /* Mass break counter on ->server */
        unsigned int            cb_v_break;     /* Mass break counter on ->volume */
        unsigned int            cb_break;       /* Break counter on vnode */
        seqlock_t               cb_lock;        /* Lock for ->cb_interest, ->status, ->cb_*break */
 
        time64_t                cb_expires_at;  /* time at which callback expires */
-       unsigned                cb_version;     /* callback version */
-       afs_callback_type_t     cb_type;        /* type of callback */
 };
 
 static inline struct fscache_cookie *afs_vnode_cache(struct afs_vnode *vnode)
@@ -755,6 +777,7 @@ struct afs_vl_cursor {
  * Cursor for iterating over a set of fileservers.
  */
 struct afs_fs_cursor {
+       const struct afs_call_type *type;       /* Type of call done */
        struct afs_addr_cursor  ac;
        struct afs_vnode        *vnode;
        struct afs_server_list  *server_list;   /* Current server list (pins ref) */
@@ -772,6 +795,7 @@ struct afs_fs_cursor {
 #define AFS_FS_CURSOR_VNOVOL   0x0008          /* Set if seen VNOVOL */
 #define AFS_FS_CURSOR_CUR_ONLY 0x0010          /* Set if current server only (file lock held) */
 #define AFS_FS_CURSOR_NO_VSLEEP        0x0020          /* Set to prevent sleep on VBUSY, VOFFLINE, ... */
+#define AFS_FS_CURSOR_INTR     0x0040          /* Set if op is interruptible */
        unsigned short          nr_iterations;  /* Number of server iterations */
 };
 
@@ -882,7 +906,6 @@ extern const struct address_space_operations afs_dir_aops;
 extern const struct dentry_operations afs_fs_dentry_operations;
 
 extern void afs_d_release(struct dentry *);
-extern int afs_dir_remove_link(struct dentry *, struct key *, unsigned long, unsigned long);
 
 /*
  * dir_edit.c
@@ -940,50 +963,48 @@ extern int afs_flock(struct file *, int, struct file_lock *);
 /*
  * fsclient.c
  */
-#define AFS_VNODE_NOT_YET_SET  0x01
-#define AFS_VNODE_META_CHANGED 0x02
-#define AFS_VNODE_DATA_CHANGED 0x04
-extern void afs_update_inode_from_status(struct afs_vnode *, struct afs_file_status *,
-                                        const afs_dataversion_t *, u8);
-
-extern int afs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_volsync *, bool);
+extern int afs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_status_cb *,
+                                   struct afs_volsync *);
 extern int afs_fs_give_up_callbacks(struct afs_net *, struct afs_server *);
-extern int afs_fs_fetch_data(struct afs_fs_cursor *, struct afs_read *);
-extern int afs_fs_create(struct afs_fs_cursor *, const char *, umode_t, u64,
-                        struct afs_fid *, struct afs_file_status *, struct afs_callback *);
-extern int afs_fs_remove(struct afs_fs_cursor *, struct afs_vnode *, const char *, bool, u64);
-extern int afs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *, u64);
-extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, u64,
-                         struct afs_fid *, struct afs_file_status *);
+extern int afs_fs_fetch_data(struct afs_fs_cursor *, struct afs_status_cb *, struct afs_read *);
+extern int afs_fs_create(struct afs_fs_cursor *, const char *, umode_t,
+                        struct afs_status_cb *, struct afs_fid *, struct afs_status_cb *);
+extern int afs_fs_remove(struct afs_fs_cursor *, struct afs_vnode *, const char *, bool,
+                        struct afs_status_cb *);
+extern int afs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *,
+                      struct afs_status_cb *, struct afs_status_cb *);
+extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *,
+                         struct afs_status_cb *, struct afs_fid *, struct afs_status_cb *);
 extern int afs_fs_rename(struct afs_fs_cursor *, const char *,
-                        struct afs_vnode *, const char *, u64, u64);
+                        struct afs_vnode *, const char *,
+                        struct afs_status_cb *, struct afs_status_cb *);
 extern int afs_fs_store_data(struct afs_fs_cursor *, struct address_space *,
-                            pgoff_t, pgoff_t, unsigned, unsigned);
-extern int afs_fs_setattr(struct afs_fs_cursor *, struct iattr *);
+                            pgoff_t, pgoff_t, unsigned, unsigned, struct afs_status_cb *);
+extern int afs_fs_setattr(struct afs_fs_cursor *, struct iattr *, struct afs_status_cb *);
 extern int afs_fs_get_volume_status(struct afs_fs_cursor *, struct afs_volume_status *);
-extern int afs_fs_set_lock(struct afs_fs_cursor *, afs_lock_type_t);
-extern int afs_fs_extend_lock(struct afs_fs_cursor *);
-extern int afs_fs_release_lock(struct afs_fs_cursor *);
+extern int afs_fs_set_lock(struct afs_fs_cursor *, afs_lock_type_t, struct afs_status_cb *);
+extern int afs_fs_extend_lock(struct afs_fs_cursor *, struct afs_status_cb *);
+extern int afs_fs_release_lock(struct afs_fs_cursor *, struct afs_status_cb *);
 extern int afs_fs_give_up_all_callbacks(struct afs_net *, struct afs_server *,
                                        struct afs_addr_cursor *, struct key *);
 extern struct afs_call *afs_fs_get_capabilities(struct afs_net *, struct afs_server *,
                                                struct afs_addr_cursor *, struct key *,
                                                unsigned int);
 extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
-                                    struct afs_fid *, struct afs_file_status *,
-                                    struct afs_callback *, unsigned int,
-                                    struct afs_volsync *);
+                                    struct afs_fid *, struct afs_status_cb *,
+                                    unsigned int, struct afs_volsync *);
 extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
-                              struct afs_fid *, struct afs_file_status *,
-                              struct afs_callback *, struct afs_volsync *);
+                              struct afs_fid *, struct afs_status_cb *,
+                              struct afs_volsync *);
 
 struct afs_acl {
        u32     size;
        u8      data[];
 };
 
-extern struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *);
-extern int afs_fs_store_acl(struct afs_fs_cursor *, const struct afs_acl *);
+extern struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *, struct afs_status_cb *);
+extern int afs_fs_store_acl(struct afs_fs_cursor *, const struct afs_acl *,
+                           struct afs_status_cb *);
 
 /*
  * fs_probe.c
@@ -995,15 +1016,20 @@ extern int afs_wait_for_fs_probes(struct afs_server_list *, unsigned long);
 /*
  * inode.c
  */
-extern int afs_fetch_status(struct afs_vnode *, struct key *, bool);
+extern void afs_vnode_commit_status(struct afs_fs_cursor *,
+                                   struct afs_vnode *,
+                                   unsigned int,
+                                   const afs_dataversion_t *,
+                                   struct afs_status_cb *);
+extern int afs_fetch_status(struct afs_vnode *, struct key *, bool, afs_access_t *);
 extern int afs_iget5_test(struct inode *, void *);
 extern struct inode *afs_iget_pseudo_dir(struct super_block *, bool);
 extern struct inode *afs_iget(struct super_block *, struct key *,
-                             struct afs_fid *, struct afs_file_status *,
-                             struct afs_callback *,
+                             struct afs_iget_data *, struct afs_status_cb *,
                              struct afs_cb_interest *,
                              struct afs_vnode *);
 extern void afs_zap_data(struct afs_vnode *);
+extern bool afs_check_validity(struct afs_vnode *);
 extern int afs_validate(struct afs_vnode *, struct key *);
 extern int afs_getattr(const struct path *, struct kstat *, u32, unsigned int);
 extern int afs_setattr(struct dentry *, struct iattr *);
@@ -1096,7 +1122,7 @@ static inline void afs_put_sysnames(struct afs_sysnames *sysnames) {}
  * rotate.c
  */
 extern bool afs_begin_vnode_operation(struct afs_fs_cursor *, struct afs_vnode *,
-                                     struct key *);
+                                     struct key *, bool);
 extern bool afs_select_fileserver(struct afs_fs_cursor *);
 extern bool afs_select_current_fileserver(struct afs_fs_cursor *);
 extern int afs_end_vnode_operation(struct afs_fs_cursor *);
@@ -1121,6 +1147,12 @@ extern void afs_send_simple_reply(struct afs_call *, const void *, size_t);
 extern int afs_extract_data(struct afs_call *, bool);
 extern int afs_protocol_error(struct afs_call *, int, enum afs_eproto_cause);
 
+static inline void afs_set_fc_call(struct afs_call *call, struct afs_fs_cursor *fc)
+{
+       call->intr = fc->flags & AFS_FS_CURSOR_INTR;
+       fc->type = call->type;
+}
+
 static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)
 {
        call->kvec[0].iov_base = buf;
@@ -1201,7 +1233,8 @@ static inline void afs_set_call_complete(struct afs_call *call,
  */
 extern void afs_put_permits(struct afs_permits *);
 extern void afs_clear_permits(struct afs_vnode *);
-extern void afs_cache_permit(struct afs_vnode *, struct key *, unsigned int);
+extern void afs_cache_permit(struct afs_vnode *, struct key *, unsigned int,
+                            struct afs_status_cb *);
 extern void afs_zap_permits(struct rcu_head *);
 extern struct key *afs_request_key(struct afs_cell *);
 extern int afs_check_permit(struct afs_vnode *, struct key *, afs_access_t *);
@@ -1327,7 +1360,6 @@ extern int afs_write_end(struct file *file, struct address_space *mapping,
                        struct page *page, void *fsdata);
 extern int afs_writepage(struct page *, struct writeback_control *);
 extern int afs_writepages(struct address_space *, struct writeback_control *);
-extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *);
 extern ssize_t afs_file_write(struct kiocb *, struct iov_iter *);
 extern int afs_fsync(struct file *, loff_t, loff_t, int);
 extern vm_fault_t afs_page_mkwrite(struct vm_fault *vmf);
@@ -1343,33 +1375,36 @@ extern ssize_t afs_listxattr(struct dentry *, char *, size_t);
 /*
  * yfsclient.c
  */
-extern int yfs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_volsync *, bool);
-extern int yfs_fs_fetch_data(struct afs_fs_cursor *, struct afs_read *);
-extern int yfs_fs_create_file(struct afs_fs_cursor *, const char *, umode_t, u64,
-                             struct afs_fid *, struct afs_file_status *, struct afs_callback *);
-extern int yfs_fs_make_dir(struct afs_fs_cursor *, const char *, umode_t, u64,
-                        struct afs_fid *, struct afs_file_status *, struct afs_callback *);
-extern int yfs_fs_remove_file2(struct afs_fs_cursor *, struct afs_vnode *, const char *, u64);
-extern int yfs_fs_remove(struct afs_fs_cursor *, struct afs_vnode *, const char *, bool, u64);
-extern int yfs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *, u64);
-extern int yfs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, u64,
-                         struct afs_fid *, struct afs_file_status *);
-extern int yfs_fs_rename(struct afs_fs_cursor *, const char *,
-                        struct afs_vnode *, const char *, u64, u64);
+extern int yfs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_status_cb *,
+                                   struct afs_volsync *);
+extern int yfs_fs_fetch_data(struct afs_fs_cursor *, struct afs_status_cb *, struct afs_read *);
+extern int yfs_fs_create_file(struct afs_fs_cursor *, const char *, umode_t, struct afs_status_cb *,
+                             struct afs_fid *, struct afs_status_cb *);
+extern int yfs_fs_make_dir(struct afs_fs_cursor *, const char *, umode_t, struct afs_status_cb *,
+                          struct afs_fid *, struct afs_status_cb *);
+extern int yfs_fs_remove_file2(struct afs_fs_cursor *, struct afs_vnode *, const char *,
+                              struct afs_status_cb *, struct afs_status_cb *);
+extern int yfs_fs_remove(struct afs_fs_cursor *, struct afs_vnode *, const char *, bool,
+                        struct afs_status_cb *);
+extern int yfs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *,
+                      struct afs_status_cb *, struct afs_status_cb *);
+extern int yfs_fs_symlink(struct afs_fs_cursor *, const char *, const char *,
+                         struct afs_status_cb *, struct afs_fid *, struct afs_status_cb *);
+extern int yfs_fs_rename(struct afs_fs_cursor *, const char *, struct afs_vnode *, const char *,
+                        struct afs_status_cb *, struct afs_status_cb *);
 extern int yfs_fs_store_data(struct afs_fs_cursor *, struct address_space *,
-                            pgoff_t, pgoff_t, unsigned, unsigned);
-extern int yfs_fs_setattr(struct afs_fs_cursor *, struct iattr *);
+                            pgoff_t, pgoff_t, unsigned, unsigned, struct afs_status_cb *);
+extern int yfs_fs_setattr(struct afs_fs_cursor *, struct iattr *, struct afs_status_cb *);
 extern int yfs_fs_get_volume_status(struct afs_fs_cursor *, struct afs_volume_status *);
-extern int yfs_fs_set_lock(struct afs_fs_cursor *, afs_lock_type_t);
-extern int yfs_fs_extend_lock(struct afs_fs_cursor *);
-extern int yfs_fs_release_lock(struct afs_fs_cursor *);
+extern int yfs_fs_set_lock(struct afs_fs_cursor *, afs_lock_type_t, struct afs_status_cb *);
+extern int yfs_fs_extend_lock(struct afs_fs_cursor *, struct afs_status_cb *);
+extern int yfs_fs_release_lock(struct afs_fs_cursor *, struct afs_status_cb *);
 extern int yfs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
-                              struct afs_fid *, struct afs_file_status *,
-                              struct afs_callback *, struct afs_volsync *);
+                              struct afs_fid *, struct afs_status_cb *,
+                              struct afs_volsync *);
 extern int yfs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
-                                    struct afs_fid *, struct afs_file_status *,
-                                    struct afs_callback *, unsigned int,
-                                    struct afs_volsync *);
+                                    struct afs_fid *, struct afs_status_cb *,
+                                    unsigned int, struct afs_volsync *);
 
 struct yfs_acl {
        struct afs_acl  *acl;           /* Dir/file/symlink ACL */
@@ -1382,8 +1417,10 @@ struct yfs_acl {
 };
 
 extern void yfs_free_opaque_acl(struct yfs_acl *);
-extern struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *, unsigned int);
-extern int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *, const struct afs_acl *);
+extern struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *, struct yfs_acl *,
+                                              struct afs_status_cb *);
+extern int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *, const struct afs_acl *,
+                                   struct afs_status_cb *);
 
 /*
  * Miscellaneous inline functions.
@@ -1398,14 +1435,6 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode)
        return &vnode->vfs_inode;
 }
 
-static inline void afs_vnode_commit_status(struct afs_fs_cursor *fc,
-                                          struct afs_vnode *vnode,
-                                          unsigned int cb_break)
-{
-       if (fc->ac.error == 0)
-               afs_cache_permit(vnode, fc->key, cb_break);
-}
-
 static inline void afs_check_for_remote_deletion(struct afs_fs_cursor *fc,
                                                 struct afs_vnode *vnode)
 {
index be2ee3bbd0a953349ccba4a30eecbd2366b840c1..371501d28e08752a7e012361a53724fb41297c8a 100644 (file)
@@ -53,7 +53,7 @@ static int afs_proc_cells_show(struct seq_file *m, void *v)
        seq_printf(m, "%3u %6lld %2u %s\n",
                   atomic_read(&cell->usage),
                   cell->dns_expiry - ktime_get_real_seconds(),
-                  vllist ? vllist->nr_servers : 0,
+                  vllist->nr_servers,
                   cell->name);
        return 0;
 }
@@ -296,8 +296,8 @@ static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
 
        if (v == SEQ_START_TOKEN) {
                seq_printf(m, "# source %s, status %s\n",
-                          dns_record_sources[vllist->source],
-                          dns_lookup_statuses[vllist->status]);
+                          dns_record_sources[vllist ? vllist->source : 0],
+                          dns_lookup_statuses[vllist ? vllist->status : 0]);
                return 0;
        }
 
@@ -336,7 +336,7 @@ static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
        if (pos == 0)
                return SEQ_START_TOKEN;
 
-       if (!vllist || pos - 1 >= vllist->nr_servers)
+       if (pos - 1 >= vllist->nr_servers)
                return NULL;
 
        return &vllist->servers[pos - 1];
index c3ae324781f846b8122b6b0a80085efaafdcaaba..b00c739e0e63aaf03d288ad94096e0ab075ee9b4 100644 (file)
@@ -25,7 +25,7 @@
  * them here also using the io_lock.
  */
 bool afs_begin_vnode_operation(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
-                              struct key *key)
+                              struct key *key, bool intr)
 {
        memset(fc, 0, sizeof(*fc));
        fc->vnode = vnode;
@@ -33,10 +33,15 @@ bool afs_begin_vnode_operation(struct afs_fs_cursor *fc, struct afs_vnode *vnode
        fc->ac.error = SHRT_MAX;
        fc->error = -EDESTADDRREQ;
 
-       if (mutex_lock_interruptible(&vnode->io_lock) < 0) {
-               fc->error = -EINTR;
-               fc->flags |= AFS_FS_CURSOR_STOP;
-               return false;
+       if (intr) {
+               fc->flags |= AFS_FS_CURSOR_INTR;
+               if (mutex_lock_interruptible(&vnode->io_lock) < 0) {
+                       fc->error = -EINTR;
+                       fc->flags |= AFS_FS_CURSOR_STOP;
+                       return false;
+               }
+       } else {
+               mutex_lock(&vnode->io_lock);
        }
 
        if (vnode->lock_state != AFS_VNODE_LOCK_NONE)
@@ -61,7 +66,8 @@ static bool afs_start_fs_iteration(struct afs_fs_cursor *fc,
        fc->untried = (1UL << fc->server_list->nr_servers) - 1;
        fc->index = READ_ONCE(fc->server_list->preferred);
 
-       cbi = vnode->cb_interest;
+       cbi = rcu_dereference_protected(vnode->cb_interest,
+                                       lockdep_is_held(&vnode->io_lock));
        if (cbi) {
                /* See if the vnode's preferred record is still available */
                for (i = 0; i < fc->server_list->nr_servers; i++) {
@@ -82,8 +88,8 @@ static bool afs_start_fs_iteration(struct afs_fs_cursor *fc,
 
                /* Note that the callback promise is effectively broken */
                write_seqlock(&vnode->cb_lock);
-               ASSERTCMP(cbi, ==, vnode->cb_interest);
-               vnode->cb_interest = NULL;
+               ASSERTCMP(cbi, ==, rcu_access_pointer(vnode->cb_interest));
+               rcu_assign_pointer(vnode->cb_interest, NULL);
                if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags))
                        vnode->cb_break++;
                write_sequnlock(&vnode->cb_lock);
@@ -118,10 +124,14 @@ static void afs_busy(struct afs_volume *volume, u32 abort_code)
  */
 static bool afs_sleep_and_retry(struct afs_fs_cursor *fc)
 {
-       msleep_interruptible(1000);
-       if (signal_pending(current)) {
-               fc->error = -ERESTARTSYS;
-               return false;
+       if (fc->flags & AFS_FS_CURSOR_INTR) {
+               msleep_interruptible(1000);
+               if (signal_pending(current)) {
+                       fc->error = -ERESTARTSYS;
+                       return false;
+               }
+       } else {
+               msleep(1000);
        }
 
        return true;
@@ -408,7 +418,9 @@ selected_server:
        if (error < 0)
                goto failed_set_error;
 
-       fc->cbi = afs_get_cb_interest(vnode->cb_interest);
+       fc->cbi = afs_get_cb_interest(
+               rcu_dereference_protected(vnode->cb_interest,
+                                         lockdep_is_held(&vnode->io_lock)));
 
        read_lock(&server->fs_lock);
        alist = rcu_dereference_protected(server->addresses,
@@ -459,6 +471,8 @@ no_more_servers:
                                     s->probe.abort_code);
        }
 
+       error = e.error;
+
 failed_set_error:
        fc->error = error;
 failed:
@@ -476,12 +490,15 @@ failed:
 bool afs_select_current_fileserver(struct afs_fs_cursor *fc)
 {
        struct afs_vnode *vnode = fc->vnode;
-       struct afs_cb_interest *cbi = vnode->cb_interest;
+       struct afs_cb_interest *cbi;
        struct afs_addr_list *alist;
        int error = fc->ac.error;
 
        _enter("");
 
+       cbi = rcu_dereference_protected(vnode->cb_interest,
+                                       lockdep_is_held(&vnode->io_lock));
+
        switch (error) {
        case SHRT_MAX:
                if (!cbi) {
@@ -490,7 +507,7 @@ bool afs_select_current_fileserver(struct afs_fs_cursor *fc)
                        return false;
                }
 
-               fc->cbi = afs_get_cb_interest(vnode->cb_interest);
+               fc->cbi = afs_get_cb_interest(cbi);
 
                read_lock(&cbi->server->fs_lock);
                alist = rcu_dereference_protected(cbi->server->addresses,
index a34a89c75c6ac6e75195c0b9f5675aff10008bbf..4fa5ce92b9b97339f0cb2094c73a0223f9dd4da0 100644 (file)
@@ -188,7 +188,7 @@ void afs_put_call(struct afs_call *call)
                if (call->type->destructor)
                        call->type->destructor(call);
 
-               afs_put_server(call->net, call->cm_server);
+               afs_put_server(call->net, call->server);
                afs_put_cb_interest(call->net, call->cbi);
                afs_put_addrlist(call->alist);
                kfree(call->request);
@@ -417,6 +417,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
                                          afs_wake_up_async_call :
                                          afs_wake_up_call_waiter),
                                         call->upgrade,
+                                        call->intr,
                                         call->debug_id);
        if (IS_ERR(rxcall)) {
                ret = PTR_ERR(rxcall);
@@ -426,6 +427,10 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
 
        call->rxcall = rxcall;
 
+       if (call->max_lifespan)
+               rxrpc_kernel_set_max_life(call->net->socket, rxcall,
+                                         call->max_lifespan);
+
        /* send the request */
        iov[0].iov_base = call->request;
        iov[0].iov_len  = call->request_size;
@@ -529,11 +534,11 @@ static void afs_deliver_to_call(struct afs_call *call)
                        return;
                }
 
-               if (call->want_reply_time &&
+               if (!call->have_reply_time &&
                    rxrpc_kernel_get_reply_time(call->net->socket,
                                                call->rxcall,
                                                &call->reply_time))
-                       call->want_reply_time = false;
+                       call->have_reply_time = true;
 
                ret = call->type->deliver(call);
                state = READ_ONCE(call->state);
@@ -648,7 +653,7 @@ long afs_wait_for_call_to_complete(struct afs_call *call,
                        break;
                }
 
-               if (timeout == 0 &&
+               if (call->intr && timeout == 0 &&
                    life == last_life && signal_pending(current)) {
                        if (stalled)
                                break;
@@ -691,10 +696,9 @@ long afs_wait_for_call_to_complete(struct afs_call *call,
        ret = ac->error;
        switch (ret) {
        case 0:
-               if (call->ret_reply0) {
-                       ret = (long)call->reply[0];
-                       call->reply[0] = NULL;
-               }
+               ret = call->ret0;
+               call->ret0 = 0;
+
                /* Fall through */
        case -ECONNABORTED:
                ac->responded = true;
index 5f58a9a17e694a09dbe0d0b70d9dbc0cc9833aa4..5d8ece98561e6cde9eea417a155fa7be1c5ca07b 100644 (file)
@@ -87,11 +87,9 @@ void afs_clear_permits(struct afs_vnode *vnode)
        permits = rcu_dereference_protected(vnode->permit_cache,
                                            lockdep_is_held(&vnode->lock));
        RCU_INIT_POINTER(vnode->permit_cache, NULL);
-       vnode->cb_break++;
        spin_unlock(&vnode->lock);
 
-       if (permits)
-               afs_put_permits(permits);
+       afs_put_permits(permits);
 }
 
 /*
@@ -118,10 +116,10 @@ static void afs_hash_permits(struct afs_permits *permits)
  * as the ACL *may* have changed.
  */
 void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
-                     unsigned int cb_break)
+                     unsigned int cb_break, struct afs_status_cb *scb)
 {
        struct afs_permits *permits, *xpermits, *replacement, *zap, *new = NULL;
-       afs_access_t caller_access = READ_ONCE(vnode->status.caller_access);
+       afs_access_t caller_access = scb->status.caller_access;
        size_t size = 0;
        bool changed = false;
        int i, j;
@@ -148,7 +146,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
                                }
 
                                if (afs_cb_is_broken(cb_break, vnode,
-                                                    vnode->cb_interest)) {
+                                                    rcu_dereference(vnode->cb_interest))) {
                                        changed = true;
                                        break;
                                }
@@ -178,7 +176,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
                }
        }
 
-       if (afs_cb_is_broken(cb_break, vnode, vnode->cb_interest))
+       if (afs_cb_is_broken(cb_break, vnode, rcu_dereference(vnode->cb_interest)))
                goto someone_else_changed_it;
 
        /* We need a ref on any permits list we want to copy as we'll have to
@@ -255,14 +253,16 @@ found:
 
        kfree(new);
 
+       rcu_read_lock();
        spin_lock(&vnode->lock);
        zap = rcu_access_pointer(vnode->permit_cache);
-       if (!afs_cb_is_broken(cb_break, vnode, vnode->cb_interest) &&
+       if (!afs_cb_is_broken(cb_break, vnode, rcu_dereference(vnode->cb_interest)) &&
            zap == permits)
                rcu_assign_pointer(vnode->permit_cache, replacement);
        else
                zap = replacement;
        spin_unlock(&vnode->lock);
+       rcu_read_unlock();
        afs_put_permits(zap);
 out_put:
        afs_put_permits(permits);
@@ -322,13 +322,12 @@ int afs_check_permit(struct afs_vnode *vnode, struct key *key,
                 */
                _debug("no valid permit");
 
-               ret = afs_fetch_status(vnode, key, false);
+               ret = afs_fetch_status(vnode, key, false, _access);
                if (ret < 0) {
                        *_access = 0;
                        _leave(" = %d", ret);
                        return ret;
                }
-               *_access = vnode->status.caller_access;
        }
 
        _leave(" = 0 [access %x]", *_access);
index 65b33b6da48b9411c8385a27869785d5076713b1..52c170b59cfdca4202d58c243cd7a3b986f06d61 100644 (file)
@@ -521,8 +521,15 @@ static noinline bool afs_update_server_record(struct afs_fs_cursor *fc, struct a
        alist = afs_vl_lookup_addrs(fc->vnode->volume->cell, fc->key,
                                    &server->uuid);
        if (IS_ERR(alist)) {
-               fc->ac.error = PTR_ERR(alist);
-               _leave(" = f [%d]", fc->ac.error);
+               if ((PTR_ERR(alist) == -ERESTARTSYS ||
+                    PTR_ERR(alist) == -EINTR) &&
+                   !(fc->flags & AFS_FS_CURSOR_INTR) &&
+                   server->addresses) {
+                       _leave(" = t [intr]");
+                       return true;
+               }
+               fc->error = PTR_ERR(alist);
+               _leave(" = f [%d]", fc->error);
                return false;
        }
 
@@ -574,7 +581,11 @@ retry:
        ret = wait_on_bit(&server->flags, AFS_SERVER_FL_UPDATING,
                          TASK_INTERRUPTIBLE);
        if (ret == -ERESTARTSYS) {
-               fc->ac.error = ret;
+               if (!(fc->flags & AFS_FS_CURSOR_INTR) && server->addresses) {
+                       _leave(" = t [intr]");
+                       return true;
+               }
+               fc->error = ret;
                _leave(" = f [intr]");
                return false;
        }
index 783c68cd1a3587de5474ddaa67aff6a6d783e41c..f18911e8d77035f4fe757c03343eb8ce06b5e13c 100644 (file)
@@ -426,7 +426,7 @@ static int afs_set_super(struct super_block *sb, struct fs_context *fc)
 static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx)
 {
        struct afs_super_info *as = AFS_FS_S(sb);
-       struct afs_fid fid;
+       struct afs_iget_data iget_data;
        struct inode *inode = NULL;
        int ret;
 
@@ -451,11 +451,13 @@ static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx)
        } else {
                sprintf(sb->s_id, "%llu", as->volume->vid);
                afs_activate_volume(as->volume);
-               fid.vid         = as->volume->vid;
-               fid.vnode       = 1;
-               fid.vnode_hi    = 0;
-               fid.unique      = 1;
-               inode = afs_iget(sb, ctx->key, &fid, NULL, NULL, NULL, NULL);
+               iget_data.fid.vid       = as->volume->vid;
+               iget_data.fid.vnode     = 1;
+               iget_data.fid.vnode_hi  = 0;
+               iget_data.fid.unique    = 1;
+               iget_data.cb_v_break    = as->volume->cb_v_break;
+               iget_data.cb_s_break    = 0;
+               inode = afs_iget(sb, ctx->key, &iget_data, NULL, NULL, NULL);
        }
 
        if (IS_ERR(inode))
@@ -677,13 +679,12 @@ static struct inode *afs_alloc_inode(struct super_block *sb)
        vnode->volume           = NULL;
        vnode->lock_key         = NULL;
        vnode->permit_cache     = NULL;
-       vnode->cb_interest      = NULL;
+       RCU_INIT_POINTER(vnode->cb_interest, NULL);
 #ifdef CONFIG_AFS_FSCACHE
        vnode->cache            = NULL;
 #endif
 
        vnode->flags            = 1 << AFS_VNODE_UNSET;
-       vnode->cb_type          = 0;
        vnode->lock_state       = AFS_VNODE_LOCK_NONE;
 
        init_rwsem(&vnode->rmdir_lock);
@@ -708,7 +709,7 @@ static void afs_destroy_inode(struct inode *inode)
 
        _debug("DESTROY INODE %p", inode);
 
-       ASSERTCMP(vnode->cb_interest, ==, NULL);
+       ASSERTCMP(rcu_access_pointer(vnode->cb_interest), ==, NULL);
 
        atomic_dec(&afs_count_active_inodes);
 }
@@ -741,7 +742,7 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf)
                return PTR_ERR(key);
 
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, vnode, key)) {
+       if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
                fc.flags |= AFS_FS_CURSOR_NO_VSLEEP;
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
@@ -749,7 +750,6 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf)
                }
 
                afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, vnode, fc.cb_break);
                ret = afs_end_vnode_operation(&fc);
        }
 
index b4f1a84519b952dfe65295aea24cae30d2b9aa9e..61e25010ff335c2be12c6ff85e582d353b6eac95 100644 (file)
@@ -232,18 +232,16 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell,
                if (bs.status > NR__dns_lookup_status)
                        bs.status = NR__dns_lookup_status;
 
+               /* See if we can update an old server record */
                server = NULL;
-               if (previous) {
-                       /* See if we can update an old server record */
-                       for (i = 0; i < previous->nr_servers; i++) {
-                               struct afs_vlserver *p = previous->servers[i].server;
-
-                               if (p->name_len == bs.name_len &&
-                                   p->port == bs.port &&
-                                   strncasecmp(b, p->name, bs.name_len) == 0) {
-                                       server = afs_get_vlserver(p);
-                                       break;
-                               }
+               for (i = 0; i < previous->nr_servers; i++) {
+                       struct afs_vlserver *p = previous->servers[i].server;
+
+                       if (p->name_len == bs.name_len &&
+                           p->port == bs.port &&
+                           strncasecmp(b, p->name, bs.name_len) == 0) {
+                               server = afs_get_vlserver(p);
+                               break;
                        }
                }
 
index b05e0de04f422a1f7f8122e245cc3cb2a8958776..beb991563939aebbb799ba852b2d0411929cd131 100644 (file)
@@ -33,8 +33,8 @@ static bool afs_vl_probe_done(struct afs_vlserver *server)
 void afs_vlserver_probe_result(struct afs_call *call)
 {
        struct afs_addr_list *alist = call->alist;
-       struct afs_vlserver *server = call->reply[0];
-       unsigned int server_index = (long)call->reply[1];
+       struct afs_vlserver *server = call->vlserver;
+       unsigned int server_index = call->server_index;
        unsigned int index = call->addr_ix;
        unsigned int rtt = UINT_MAX;
        bool have_result = false;
index 7adde83a06482b56c555c18c3629c335a2315397..3f845489a9f0eba96ae86b657d58170b1ff92df0 100644 (file)
@@ -43,11 +43,29 @@ bool afs_begin_vlserver_operation(struct afs_vl_cursor *vc, struct afs_cell *cel
 static bool afs_start_vl_iteration(struct afs_vl_cursor *vc)
 {
        struct afs_cell *cell = vc->cell;
+       unsigned int dns_lookup_count;
+
+       if (cell->dns_source == DNS_RECORD_UNAVAILABLE ||
+           cell->dns_expiry <= ktime_get_real_seconds()) {
+               dns_lookup_count = smp_load_acquire(&cell->dns_lookup_count);
+               set_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags);
+               queue_work(afs_wq, &cell->manager);
+
+               if (cell->dns_source == DNS_RECORD_UNAVAILABLE) {
+                       if (wait_var_event_interruptible(
+                                   &cell->dns_lookup_count,
+                                   smp_load_acquire(&cell->dns_lookup_count)
+                                   != dns_lookup_count) < 0) {
+                               vc->error = -ERESTARTSYS;
+                               return false;
+                       }
+               }
 
-       if (wait_on_bit(&cell->flags, AFS_CELL_FL_NO_LOOKUP_YET,
-                       TASK_INTERRUPTIBLE)) {
-               vc->error = -ERESTARTSYS;
-               return false;
+               /* Status load is ordered after lookup counter load */
+               if (cell->dns_source == DNS_RECORD_UNAVAILABLE) {
+                       vc->error = -EDESTADDRREQ;
+                       return false;
+               }
        }
 
        read_lock(&cell->vl_servers_lock);
@@ -55,7 +73,7 @@ static bool afs_start_vl_iteration(struct afs_vl_cursor *vc)
                rcu_dereference_protected(cell->vl_servers,
                                          lockdep_is_held(&cell->vl_servers_lock)));
        read_unlock(&cell->vl_servers_lock);
-       if (!vc->server_list || !vc->server_list->nr_servers)
+       if (!vc->server_list->nr_servers)
                return false;
 
        vc->untried = (1UL << vc->server_list->nr_servers) - 1;
index dd9ba4e96fb3ecc14d2fe4552fe209a09e6b2abc..3d4b9836a2e2f0ef0f5eb13f1ce49b90e2605284 100644 (file)
@@ -34,7 +34,7 @@ static int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        uvldb = call->buffer;
-       entry = call->reply[0];
+       entry = call->ret_vldb;
 
        nr_servers = ntohl(uvldb->nServers);
        if (nr_servers > AFS_NMAXNSERVERS)
@@ -110,7 +110,7 @@ static int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call)
 
 static void afs_destroy_vl_get_entry_by_name_u(struct afs_call *call)
 {
-       kfree(call->reply[0]);
+       kfree(call->ret_vldb);
        afs_flat_call_destructor(call);
 }
 
@@ -155,8 +155,8 @@ struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc,
        }
 
        call->key = vc->key;
-       call->reply[0] = entry;
-       call->ret_reply0 = true;
+       call->ret_vldb = entry;
+       call->max_lifespan = AFS_VL_MAX_LIFESPAN;
 
        /* Marshall the parameters */
        bp = call->request;
@@ -214,7 +214,7 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call)
                if (!alist)
                        return -ENOMEM;
                alist->version = uniquifier;
-               call->reply[0] = alist;
+               call->ret_alist = alist;
                call->count = count;
                call->count2 = nentries;
                call->unmarshall++;
@@ -229,7 +229,7 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call)
                if (ret < 0)
                        return ret;
 
-               alist = call->reply[0];
+               alist = call->ret_alist;
                bp = call->buffer;
                count = min(call->count, 4U);
                for (i = 0; i < count; i++)
@@ -249,8 +249,7 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call)
 
 static void afs_vl_get_addrs_u_destructor(struct afs_call *call)
 {
-       afs_put_server(call->net, (struct afs_server *)call->reply[0]);
-       kfree(call->reply[1]);
+       afs_put_addrlist(call->ret_alist);
        return afs_flat_call_destructor(call);
 }
 
@@ -287,8 +286,8 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc,
                return ERR_PTR(-ENOMEM);
 
        call->key = vc->key;
-       call->reply[0] = NULL;
-       call->ret_reply0 = true;
+       call->ret_alist = NULL;
+       call->max_lifespan = AFS_VL_MAX_LIFESPAN;
 
        /* Marshall the parameters */
        bp = call->request;
@@ -358,9 +357,7 @@ static int afs_deliver_vl_get_capabilities(struct afs_call *call)
 
 static void afs_destroy_vl_get_capabilities(struct afs_call *call)
 {
-       struct afs_vlserver *server = call->reply[0];
-
-       afs_put_vlserver(call->net, server);
+       afs_put_vlserver(call->net, call->vlserver);
        afs_flat_call_destructor(call);
 }
 
@@ -398,11 +395,11 @@ struct afs_call *afs_vl_get_capabilities(struct afs_net *net,
                return ERR_PTR(-ENOMEM);
 
        call->key = key;
-       call->reply[0] = afs_get_vlserver(server);
-       call->reply[1] = (void *)(long)server_index;
+       call->vlserver = afs_get_vlserver(server);
+       call->server_index = server_index;
        call->upgrade = true;
-       call->want_reply_time = true;
        call->async = true;
+       call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
 
        /* marshall the parameters */
        bp = call->request;
@@ -460,7 +457,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
                if (!alist)
                        return -ENOMEM;
                alist->version = uniquifier;
-               call->reply[0] = alist;
+               call->ret_alist = alist;
 
                if (call->count == 0)
                        goto extract_volendpoints;
@@ -488,7 +485,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
                if (ret < 0)
                        return ret;
 
-               alist = call->reply[0];
+               alist = call->ret_alist;
                bp = call->buffer;
                switch (call->count2) {
                case YFS_ENDPOINT_IPV4:
@@ -609,7 +606,6 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
                break;
        }
 
-       alist = call->reply[0];
        _leave(" = 0 [done]");
        return 0;
 }
@@ -644,8 +640,8 @@ struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc,
                return ERR_PTR(-ENOMEM);
 
        call->key = vc->key;
-       call->reply[0] = NULL;
-       call->ret_reply0 = true;
+       call->ret_alist = NULL;
+       call->max_lifespan = AFS_VL_MAX_LIFESPAN;
 
        /* Marshall the parameters */
        bp = call->request;
index 0122d7445fba1e07eaf62b4be1d1e69c66e5f7c4..8bcab95f11273aeeb94e0347b9696960e0f1138a 100644 (file)
@@ -313,6 +313,46 @@ static void afs_redirty_pages(struct writeback_control *wbc,
        _leave("");
 }
 
+/*
+ * completion of write to server
+ */
+static void afs_pages_written_back(struct afs_vnode *vnode,
+                                  pgoff_t first, pgoff_t last)
+{
+       struct pagevec pv;
+       unsigned long priv;
+       unsigned count, loop;
+
+       _enter("{%llx:%llu},{%lx-%lx}",
+              vnode->fid.vid, vnode->fid.vnode, first, last);
+
+       pagevec_init(&pv);
+
+       do {
+               _debug("done %lx-%lx", first, last);
+
+               count = last - first + 1;
+               if (count > PAGEVEC_SIZE)
+                       count = PAGEVEC_SIZE;
+               pv.nr = find_get_pages_contig(vnode->vfs_inode.i_mapping,
+                                             first, count, pv.pages);
+               ASSERTCMP(pv.nr, ==, count);
+
+               for (loop = 0; loop < count; loop++) {
+                       priv = page_private(pv.pages[loop]);
+                       trace_afs_page_dirty(vnode, tracepoint_string("clear"),
+                                            pv.pages[loop]->index, priv);
+                       set_page_private(pv.pages[loop], 0);
+                       end_page_writeback(pv.pages[loop]);
+               }
+               first += count;
+               __pagevec_release(&pv);
+       } while (first <= last);
+
+       afs_prune_wb_keys(vnode);
+       _leave("");
+}
+
 /*
  * write to a file
  */
@@ -322,6 +362,7 @@ static int afs_store_data(struct address_space *mapping,
 {
        struct afs_vnode *vnode = AFS_FS_I(mapping->host);
        struct afs_fs_cursor fc;
+       struct afs_status_cb *scb;
        struct afs_wb_key *wbk = NULL;
        struct list_head *p;
        int ret = -ENOKEY, ret2;
@@ -333,6 +374,10 @@ static int afs_store_data(struct address_space *mapping,
               vnode->fid.unique,
               first, last, offset, to);
 
+       scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
+       if (!scb)
+               return -ENOMEM;
+
        spin_lock(&vnode->wb_lock);
        p = vnode->wb_keys.next;
 
@@ -351,6 +396,7 @@ try_next_key:
 
        spin_unlock(&vnode->wb_lock);
        afs_put_wb_key(wbk);
+       kfree(scb);
        _leave(" = %d [no keys]", ret);
        return ret;
 
@@ -361,14 +407,19 @@ found_key:
        _debug("USE WB KEY %u", key_serial(wbk->key));
 
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, vnode, wbk->key)) {
+       if (afs_begin_vnode_operation(&fc, vnode, wbk->key, false)) {
+               afs_dataversion_t data_version = vnode->status.data_version + 1;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
-                       afs_fs_store_data(&fc, mapping, first, last, offset, to);
+                       afs_fs_store_data(&fc, mapping, first, last, offset, to, scb);
                }
 
-               afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, vnode, fc.cb_break);
+               afs_check_for_remote_deletion(&fc, vnode);
+               afs_vnode_commit_status(&fc, vnode, fc.cb_break,
+                                       &data_version, scb);
+               if (fc.ac.error == 0)
+                       afs_pages_written_back(vnode, first, last);
                ret = afs_end_vnode_operation(&fc);
        }
 
@@ -393,6 +444,7 @@ found_key:
        }
 
        afs_put_wb_key(wbk);
+       kfree(scb);
        _leave(" = %d", ret);
        return ret;
 }
@@ -678,46 +730,6 @@ int afs_writepages(struct address_space *mapping,
        return ret;
 }
 
-/*
- * completion of write to server
- */
-void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call)
-{
-       struct pagevec pv;
-       unsigned long priv;
-       unsigned count, loop;
-       pgoff_t first = call->first, last = call->last;
-
-       _enter("{%llx:%llu},{%lx-%lx}",
-              vnode->fid.vid, vnode->fid.vnode, first, last);
-
-       pagevec_init(&pv);
-
-       do {
-               _debug("done %lx-%lx", first, last);
-
-               count = last - first + 1;
-               if (count > PAGEVEC_SIZE)
-                       count = PAGEVEC_SIZE;
-               pv.nr = find_get_pages_contig(vnode->vfs_inode.i_mapping,
-                                             first, count, pv.pages);
-               ASSERTCMP(pv.nr, ==, count);
-
-               for (loop = 0; loop < count; loop++) {
-                       priv = page_private(pv.pages[loop]);
-                       trace_afs_page_dirty(vnode, tracepoint_string("clear"),
-                                            pv.pages[loop]->index, priv);
-                       set_page_private(pv.pages[loop], 0);
-                       end_page_writeback(pv.pages[loop]);
-               }
-               first += count;
-               __pagevec_release(&pv);
-       } while (first <= last);
-
-       afs_prune_wb_keys(vnode);
-       _leave("");
-}
-
 /*
  * write to an AFS file
  */
index c81f85003fc7dbe012d3c1efe1910a102e6476ac..17f58fea7ec1f0f8d82811142597c0fa0520e821 100644 (file)
@@ -47,40 +47,52 @@ static int afs_xattr_get_acl(const struct xattr_handler *handler,
                             void *buffer, size_t size)
 {
        struct afs_fs_cursor fc;
+       struct afs_status_cb *scb;
        struct afs_vnode *vnode = AFS_FS_I(inode);
        struct afs_acl *acl = NULL;
        struct key *key;
-       int ret;
+       int ret = -ENOMEM;
+
+       scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
+       if (!scb)
+               goto error;
 
        key = afs_request_key(vnode->volume->cell);
-       if (IS_ERR(key))
-               return PTR_ERR(key);
+       if (IS_ERR(key)) {
+               ret = PTR_ERR(key);
+               goto error_scb;
+       }
 
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, vnode, key)) {
+       if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
+               afs_dataversion_t data_version = vnode->status.data_version;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
-                       acl = afs_fs_fetch_acl(&fc);
+                       acl = afs_fs_fetch_acl(&fc, scb);
                }
 
                afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, vnode, fc.cb_break);
+               afs_vnode_commit_status(&fc, vnode, fc.cb_break,
+                                       &data_version, scb);
                ret = afs_end_vnode_operation(&fc);
        }
 
        if (ret == 0) {
                ret = acl->size;
                if (size > 0) {
-                       ret = -ERANGE;
-                       if (acl->size > size)
-                               return -ERANGE;
-                       memcpy(buffer, acl->data, acl->size);
-                       ret = acl->size;
+                       if (acl->size <= size)
+                               memcpy(buffer, acl->data, acl->size);
+                       else
+                               ret = -ERANGE;
                }
                kfree(acl);
        }
 
        key_put(key);
+error_scb:
+       kfree(scb);
+error:
        return ret;
 }
 
@@ -93,41 +105,53 @@ static int afs_xattr_set_acl(const struct xattr_handler *handler,
                              const void *buffer, size_t size, int flags)
 {
        struct afs_fs_cursor fc;
+       struct afs_status_cb *scb;
        struct afs_vnode *vnode = AFS_FS_I(inode);
        struct afs_acl *acl = NULL;
        struct key *key;
-       int ret;
+       int ret = -ENOMEM;
 
        if (flags == XATTR_CREATE)
                return -EINVAL;
 
-       key = afs_request_key(vnode->volume->cell);
-       if (IS_ERR(key))
-               return PTR_ERR(key);
+       scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
+       if (!scb)
+               goto error;
 
        acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
-       if (!acl) {
-               key_put(key);
-               return -ENOMEM;
+       if (!acl)
+               goto error_scb;
+
+       key = afs_request_key(vnode->volume->cell);
+       if (IS_ERR(key)) {
+               ret = PTR_ERR(key);
+               goto error_acl;
        }
 
        acl->size = size;
        memcpy(acl->data, buffer, size);
 
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, vnode, key)) {
+       if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
+               afs_dataversion_t data_version = vnode->status.data_version;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
-                       afs_fs_store_acl(&fc, acl);
+                       afs_fs_store_acl(&fc, acl, scb);
                }
 
                afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, vnode, fc.cb_break);
+               afs_vnode_commit_status(&fc, vnode, fc.cb_break,
+                                       &data_version, scb);
                ret = afs_end_vnode_operation(&fc);
        }
 
-       kfree(acl);
        key_put(key);
+error_acl:
+       kfree(acl);
+error_scb:
+       kfree(scb);
+error:
        return ret;
 }
 
@@ -146,12 +170,12 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler,
                             void *buffer, size_t size)
 {
        struct afs_fs_cursor fc;
+       struct afs_status_cb *scb;
        struct afs_vnode *vnode = AFS_FS_I(inode);
        struct yfs_acl *yacl = NULL;
        struct key *key;
-       unsigned int flags = 0;
        char buf[16], *data;
-       int which = 0, dsize, ret;
+       int which = 0, dsize, ret = -ENOMEM;
 
        if (strcmp(name, "acl") == 0)
                which = 0;
@@ -164,65 +188,81 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler,
        else
                return -EOPNOTSUPP;
 
+       yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);
+       if (!yacl)
+               goto error;
+
        if (which == 0)
-               flags |= YFS_ACL_WANT_ACL;
+               yacl->flags |= YFS_ACL_WANT_ACL;
        else if (which == 3)
-               flags |= YFS_ACL_WANT_VOL_ACL;
+               yacl->flags |= YFS_ACL_WANT_VOL_ACL;
+
+       scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
+       if (!scb)
+               goto error_yacl;
 
        key = afs_request_key(vnode->volume->cell);
-       if (IS_ERR(key))
-               return PTR_ERR(key);
+       if (IS_ERR(key)) {
+               ret = PTR_ERR(key);
+               goto error_scb;
+       }
 
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, vnode, key)) {
+       if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
+               afs_dataversion_t data_version = vnode->status.data_version;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
-                       yacl = yfs_fs_fetch_opaque_acl(&fc, flags);
+                       yfs_fs_fetch_opaque_acl(&fc, yacl, scb);
                }
 
                afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, vnode, fc.cb_break);
+               afs_vnode_commit_status(&fc, vnode, fc.cb_break,
+                                       &data_version, scb);
                ret = afs_end_vnode_operation(&fc);
        }
 
-       if (ret == 0) {
-               switch (which) {
-               case 0:
-                       data = yacl->acl->data;
-                       dsize = yacl->acl->size;
-                       break;
-               case 1:
-                       data = buf;
-                       dsize = snprintf(buf, sizeof(buf), "%u",
-                                        yacl->inherit_flag);
-                       break;
-               case 2:
-                       data = buf;
-                       dsize = snprintf(buf, sizeof(buf), "%u",
-                                        yacl->num_cleaned);
-                       break;
-               case 3:
-                       data = yacl->vol_acl->data;
-                       dsize = yacl->vol_acl->size;
-                       break;
-               default:
-                       ret = -EOPNOTSUPP;
-                       goto out;
-               }
+       if (ret < 0)
+               goto error_key;
+
+       switch (which) {
+       case 0:
+               data = yacl->acl->data;
+               dsize = yacl->acl->size;
+               break;
+       case 1:
+               data = buf;
+               dsize = snprintf(buf, sizeof(buf), "%u", yacl->inherit_flag);
+               break;
+       case 2:
+               data = buf;
+               dsize = snprintf(buf, sizeof(buf), "%u", yacl->num_cleaned);
+               break;
+       case 3:
+               data = yacl->vol_acl->data;
+               dsize = yacl->vol_acl->size;
+               break;
+       default:
+               ret = -EOPNOTSUPP;
+               goto error_key;
+       }
 
-               ret = dsize;
-               if (size > 0) {
-                       if (dsize > size) {
-                               ret = -ERANGE;
-                               goto out;
-                       }
-                       memcpy(buffer, data, dsize);
+       ret = dsize;
+       if (size > 0) {
+               if (dsize > size) {
+                       ret = -ERANGE;
+                       goto error_key;
                }
+               memcpy(buffer, data, dsize);
        }
 
-out:
-       yfs_free_opaque_acl(yacl);
+error_key:
        key_put(key);
+error_scb:
+       kfree(scb);
+error_yacl:
+       yfs_free_opaque_acl(yacl);
+error:
        return ret;
 }
 
@@ -235,42 +275,54 @@ static int afs_xattr_set_yfs(const struct xattr_handler *handler,
                              const void *buffer, size_t size, int flags)
 {
        struct afs_fs_cursor fc;
+       struct afs_status_cb *scb;
        struct afs_vnode *vnode = AFS_FS_I(inode);
        struct afs_acl *acl = NULL;
        struct key *key;
-       int ret;
+       int ret = -ENOMEM;
 
        if (flags == XATTR_CREATE ||
            strcmp(name, "acl") != 0)
                return -EINVAL;
 
-       key = afs_request_key(vnode->volume->cell);
-       if (IS_ERR(key))
-               return PTR_ERR(key);
+       scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
+       if (!scb)
+               goto error;
 
        acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
-       if (!acl) {
-               key_put(key);
-               return -ENOMEM;
-       }
+       if (!acl)
+               goto error_scb;
 
        acl->size = size;
        memcpy(acl->data, buffer, size);
 
+       key = afs_request_key(vnode->volume->cell);
+       if (IS_ERR(key)) {
+               ret = PTR_ERR(key);
+               goto error_acl;
+       }
+
        ret = -ERESTARTSYS;
-       if (afs_begin_vnode_operation(&fc, vnode, key)) {
+       if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
+               afs_dataversion_t data_version = vnode->status.data_version;
+
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
-                       yfs_fs_store_opaque_acl2(&fc, acl);
+                       yfs_fs_store_opaque_acl2(&fc, acl, scb);
                }
 
                afs_check_for_remote_deletion(&fc, fc.vnode);
-               afs_vnode_commit_status(&fc, vnode, fc.cb_break);
+               afs_vnode_commit_status(&fc, vnode, fc.cb_break,
+                                       &data_version, scb);
                ret = afs_end_vnode_operation(&fc);
        }
 
+error_acl:
        kfree(acl);
        key_put(key);
+error_scb:
+       kfree(scb);
+error:
        return ret;
 }
 
index 6cf7d161baa1ecd3d069ecf1d30b214e8d6f8c37..10de675dc6fcaa0839a997bc1636434787cde0ee 100644 (file)
@@ -183,24 +183,19 @@ static void xdr_dump_bad(const __be32 *bp)
 /*
  * Decode a YFSFetchStatus block
  */
-static int xdr_decode_YFSFetchStatus(struct afs_call *call,
-                                    const __be32 **_bp,
-                                    struct afs_file_status *status,
-                                    struct afs_vnode *vnode,
-                                    const afs_dataversion_t *expected_version,
-                                    struct afs_read *read_req)
+static int xdr_decode_YFSFetchStatus(const __be32 **_bp,
+                                    struct afs_call *call,
+                                    struct afs_status_cb *scb)
 {
        const struct yfs_xdr_YFSFetchStatus *xdr = (const void *)*_bp;
+       struct afs_file_status *status = &scb->status;
        u32 type;
-       u8 flags = 0;
 
        status->abort_code = ntohl(xdr->abort_code);
        if (status->abort_code != 0) {
-               if (vnode && status->abort_code == VNOVNODE) {
-                       set_bit(AFS_VNODE_DELETED, &vnode->flags);
+               if (status->abort_code == VNOVNODE)
                        status->nlink = 0;
-                       __afs_break_callback(vnode);
-               }
+               scb->have_error = true;
                return 0;
        }
 
@@ -209,77 +204,28 @@ static int xdr_decode_YFSFetchStatus(struct afs_call *call,
        case AFS_FTYPE_FILE:
        case AFS_FTYPE_DIR:
        case AFS_FTYPE_SYMLINK:
-               if (type != status->type &&
-                   vnode &&
-                   !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
-                       pr_warning("Vnode %llx:%llx:%x changed type %u to %u\n",
-                                  vnode->fid.vid,
-                                  vnode->fid.vnode,
-                                  vnode->fid.unique,
-                                  status->type, type);
-                       goto bad;
-               }
                status->type = type;
                break;
        default:
                goto bad;
        }
 
-#define EXTRACT_M4(FIELD)                                      \
-       do {                                                    \
-               u32 x = ntohl(xdr->FIELD);                      \
-               if (status->FIELD != x) {                       \
-                       flags |= AFS_VNODE_META_CHANGED;        \
-                       status->FIELD = x;                      \
-               }                                               \
-       } while (0)
-
-#define EXTRACT_M8(FIELD)                                      \
-       do {                                                    \
-               u64 x = xdr_to_u64(xdr->FIELD);                 \
-               if (status->FIELD != x) {                       \
-                       flags |= AFS_VNODE_META_CHANGED;        \
-                       status->FIELD = x;                      \
-               }                                               \
-       } while (0)
-
-#define EXTRACT_D8(FIELD)                                      \
-       do {                                                    \
-               u64 x = xdr_to_u64(xdr->FIELD);                 \
-               if (status->FIELD != x) {                       \
-                       flags |= AFS_VNODE_DATA_CHANGED;        \
-                       status->FIELD = x;                      \
-               }                                               \
-       } while (0)
-
-       EXTRACT_M4(nlink);
-       EXTRACT_D8(size);
-       EXTRACT_D8(data_version);
-       EXTRACT_M8(author);
-       EXTRACT_M8(owner);
-       EXTRACT_M8(group);
-       EXTRACT_M4(mode);
-       EXTRACT_M4(caller_access); /* call ticket dependent */
-       EXTRACT_M4(anon_access);
-
-       status->mtime_client = xdr_to_time(xdr->mtime_client);
-       status->mtime_server = xdr_to_time(xdr->mtime_server);
-       status->lock_count   = ntohl(xdr->lock_count);
-
-       if (read_req) {
-               read_req->data_version = status->data_version;
-               read_req->file_size = status->size;
-       }
+       status->nlink           = ntohl(xdr->nlink);
+       status->author          = xdr_to_u64(xdr->author);
+       status->owner           = xdr_to_u64(xdr->owner);
+       status->caller_access   = ntohl(xdr->caller_access); /* Ticket dependent */
+       status->anon_access     = ntohl(xdr->anon_access);
+       status->mode            = ntohl(xdr->mode) & S_IALLUGO;
+       status->group           = xdr_to_u64(xdr->group);
+       status->lock_count      = ntohl(xdr->lock_count);
+
+       status->mtime_client    = xdr_to_time(xdr->mtime_client);
+       status->mtime_server    = xdr_to_time(xdr->mtime_server);
+       status->size            = xdr_to_u64(xdr->size);
+       status->data_version    = xdr_to_u64(xdr->data_version);
+       scb->have_status        = true;
 
        *_bp += xdr_size(xdr);
-
-       if (vnode) {
-               if (test_bit(AFS_VNODE_UNSET, &vnode->flags))
-                       flags |= AFS_VNODE_NOT_YET_SET;
-               afs_update_inode_from_status(vnode, status, expected_version,
-                                            flags);
-       }
-
        return 0;
 
 bad:
@@ -287,74 +233,21 @@ bad:
        return afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status);
 }
 
-/*
- * Decode the file status.  We need to lock the target vnode if we're going to
- * update its status so that stat() sees the attributes update atomically.
- */
-static int yfs_decode_status(struct afs_call *call,
-                            const __be32 **_bp,
-                            struct afs_file_status *status,
-                            struct afs_vnode *vnode,
-                            const afs_dataversion_t *expected_version,
-                            struct afs_read *read_req)
-{
-       int ret;
-
-       if (!vnode)
-               return xdr_decode_YFSFetchStatus(call, _bp, status, vnode,
-                                                expected_version, read_req);
-
-       write_seqlock(&vnode->cb_lock);
-       ret = xdr_decode_YFSFetchStatus(call, _bp, status, vnode,
-                                       expected_version, read_req);
-       write_sequnlock(&vnode->cb_lock);
-       return ret;
-}
-
 /*
  * Decode a YFSCallBack block
  */
-static void xdr_decode_YFSCallBack(struct afs_call *call,
-                                  struct afs_vnode *vnode,
-                                  const __be32 **_bp)
-{
-       struct yfs_xdr_YFSCallBack *xdr = (void *)*_bp;
-       struct afs_cb_interest *old, *cbi = call->cbi;
-       u64 cb_expiry;
-
-       write_seqlock(&vnode->cb_lock);
-
-       if (!afs_cb_is_broken(call->cb_break, vnode, cbi)) {
-               cb_expiry = xdr_to_u64(xdr->expiration_time);
-               do_div(cb_expiry, 10 * 1000 * 1000);
-               vnode->cb_version       = ntohl(xdr->version);
-               vnode->cb_type          = ntohl(xdr->type);
-               vnode->cb_expires_at    = cb_expiry + ktime_get_real_seconds();
-               old = vnode->cb_interest;
-               if (old != call->cbi) {
-                       vnode->cb_interest = cbi;
-                       cbi = old;
-               }
-               set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
-       }
-
-       write_sequnlock(&vnode->cb_lock);
-       call->cbi = cbi;
-       *_bp += xdr_size(xdr);
-}
-
-static void xdr_decode_YFSCallBack_raw(const __be32 **_bp,
-                                      struct afs_callback *cb)
+static void xdr_decode_YFSCallBack(const __be32 **_bp,
+                                  struct afs_call *call,
+                                  struct afs_status_cb *scb)
 {
        struct yfs_xdr_YFSCallBack *x = (void *)*_bp;
-       u64 cb_expiry;
-
-       cb_expiry = xdr_to_u64(x->expiration_time);
-       do_div(cb_expiry, 10 * 1000 * 1000);
-       cb->version     = ntohl(x->version);
-       cb->type        = ntohl(x->type);
-       cb->expires_at  = cb_expiry + ktime_get_real_seconds();
+       struct afs_callback *cb = &scb->callback;
+       ktime_t cb_expiry;
 
+       cb_expiry = call->reply_time;
+       cb_expiry = ktime_add(cb_expiry, xdr_to_u64(x->expiration_time) * 100);
+       cb->expires_at  = ktime_divns(cb_expiry, NSEC_PER_SEC);
+       scb->have_cb    = true;
        *_bp += xdr_size(x);
 }
 
@@ -442,11 +335,10 @@ static void xdr_decode_YFSFetchVolumeStatus(const __be32 **_bp,
 }
 
 /*
- * deliver reply data to an FS.FetchStatus
+ * Deliver a reply that's a status, callback and volsync.
  */
-static int yfs_deliver_fs_fetch_status_vnode(struct afs_call *call)
+static int yfs_deliver_fs_status_cb_and_volsync(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
@@ -454,16 +346,36 @@ static int yfs_deliver_fs_fetch_status_vnode(struct afs_call *call)
        if (ret < 0)
                return ret;
 
-       _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode);
-
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       ret = yfs_decode_status(call, &bp, &vnode->status, vnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb);
        if (ret < 0)
                return ret;
-       xdr_decode_YFSCallBack(call, vnode, &bp);
-       xdr_decode_YFSVolSync(&bp, call->reply[1]);
+       xdr_decode_YFSCallBack(&bp, call, call->out_scb);
+       xdr_decode_YFSVolSync(&bp, call->out_volsync);
+
+       _leave(" = 0 [done]");
+       return 0;
+}
+
+/*
+ * Deliver reply data to operations that just return a file status and a volume
+ * sync record.
+ */
+static int yfs_deliver_status_and_volsync(struct afs_call *call)
+{
+       const __be32 *bp;
+       int ret;
+
+       ret = afs_transfer_reply(call);
+       if (ret < 0)
+               return ret;
+
+       bp = call->buffer;
+       ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb);
+       if (ret < 0)
+               return ret;
+       xdr_decode_YFSVolSync(&bp, call->out_volsync);
 
        _leave(" = 0 [done]");
        return 0;
@@ -475,15 +387,15 @@ static int yfs_deliver_fs_fetch_status_vnode(struct afs_call *call)
 static const struct afs_call_type yfs_RXYFSFetchStatus_vnode = {
        .name           = "YFS.FetchStatus(vnode)",
        .op             = yfs_FS_FetchStatus,
-       .deliver        = yfs_deliver_fs_fetch_status_vnode,
+       .deliver        = yfs_deliver_fs_status_cb_and_volsync,
        .destructor     = afs_flat_call_destructor,
 };
 
 /*
  * Fetch the status information for a file.
  */
-int yfs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsync,
-                            bool new_inode)
+int yfs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_status_cb *scb,
+                            struct afs_volsync *volsync)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -505,9 +417,8 @@ int yfs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy
        }
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->reply[1] = volsync;
-       call->expected_version = new_inode ? 1 : vnode->status.data_version;
+       call->out_scb = scb;
+       call->out_volsync = volsync;
 
        /* marshall the parameters */
        bp = call->request;
@@ -516,9 +427,9 @@ int yfs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy
        bp = xdr_encode_YFSFid(bp, &vnode->fid);
        yfs_check_req(call, bp);
 
-       call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -528,8 +439,7 @@ int yfs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy
  */
 static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply[0];
-       struct afs_read *req = call->reply[2];
+       struct afs_read *req = call->read_request;
        const __be32 *bp;
        unsigned int size;
        int ret;
@@ -586,7 +496,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
                if (req->offset == PAGE_SIZE) {
                        req->offset = 0;
                        if (req->page_done)
-                               req->page_done(call, req);
+                               req->page_done(req);
                        req->index++;
                        if (req->remain > 0)
                                goto begin_page;
@@ -623,12 +533,14 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
                        return ret;
 
                bp = call->buffer;
-               ret = yfs_decode_status(call, &bp, &vnode->status, vnode,
-                                       &vnode->status.data_version, req);
+               ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb);
                if (ret < 0)
                        return ret;
-               xdr_decode_YFSCallBack(call, vnode, &bp);
-               xdr_decode_YFSVolSync(&bp, call->reply[1]);
+               xdr_decode_YFSCallBack(&bp, call, call->out_scb);
+               xdr_decode_YFSVolSync(&bp, call->out_volsync);
+
+               req->data_version = call->out_scb->status.data_version;
+               req->file_size = call->out_scb->status.size;
 
                call->unmarshall++;
 
@@ -642,7 +554,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
                        zero_user_segment(req->pages[req->index],
                                          req->offset, PAGE_SIZE);
                if (req->page_done)
-                       req->page_done(call, req);
+                       req->page_done(req);
                req->offset = 0;
        }
 
@@ -652,9 +564,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
 
 static void yfs_fetch_data_destructor(struct afs_call *call)
 {
-       struct afs_read *req = call->reply[2];
-
-       afs_put_read(req);
+       afs_put_read(call->read_request);
        afs_flat_call_destructor(call);
 }
 
@@ -671,7 +581,8 @@ static const struct afs_call_type yfs_RXYFSFetchData64 = {
 /*
  * Fetch data from a file.
  */
-int yfs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
+int yfs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_status_cb *scb,
+                     struct afs_read *req)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -693,11 +604,9 @@ int yfs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->reply[1] = NULL; /* volsync */
-       call->reply[2] = req;
-       call->expected_version = vnode->status.data_version;
-       call->want_reply_time = true;
+       call->out_scb = scb;
+       call->out_volsync = NULL;
+       call->read_request = req;
 
        /* marshall the parameters */
        bp = call->request;
@@ -709,9 +618,9 @@ int yfs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
        yfs_check_req(call, bp);
 
        refcount_inc(&req->usage);
-       call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -721,7 +630,6 @@ int yfs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
  */
 static int yfs_deliver_fs_create_vnode(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
@@ -733,16 +641,15 @@ static int yfs_deliver_fs_create_vnode(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       xdr_decode_YFSFid(&bp, call->reply[1]);
-       ret = yfs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL);
+       xdr_decode_YFSFid(&bp, call->out_fid);
+       ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb);
        if (ret < 0)
                return ret;
-       ret = yfs_decode_status(call, &bp, &vnode->status, vnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_dir_scb);
        if (ret < 0)
                return ret;
-       xdr_decode_YFSCallBack_raw(&bp, call->reply[3]);
-       xdr_decode_YFSVolSync(&bp, NULL);
+       xdr_decode_YFSCallBack(&bp, call, call->out_scb);
+       xdr_decode_YFSVolSync(&bp, call->out_volsync);
 
        _leave(" = 0 [done]");
        return 0;
@@ -764,14 +671,13 @@ static const struct afs_call_type afs_RXFSCreateFile = {
 int yfs_fs_create_file(struct afs_fs_cursor *fc,
                       const char *name,
                       umode_t mode,
-                      u64 current_data_version,
+                      struct afs_status_cb *dvnode_scb,
                       struct afs_fid *newfid,
-                      struct afs_file_status *newstatus,
-                      struct afs_callback *newcb)
+                      struct afs_status_cb *new_scb)
 {
-       struct afs_vnode *vnode = fc->vnode;
+       struct afs_vnode *dvnode = fc->vnode;
        struct afs_call *call;
-       struct afs_net *net = afs_v2net(vnode);
+       struct afs_net *net = afs_v2net(dvnode);
        size_t namesz, reqsz, rplsz;
        __be32 *bp;
 
@@ -795,24 +701,23 @@ int yfs_fs_create_file(struct afs_fs_cursor *fc,
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->reply[1] = newfid;
-       call->reply[2] = newstatus;
-       call->reply[3] = newcb;
-       call->expected_version = current_data_version + 1;
+       call->out_dir_scb = dvnode_scb;
+       call->out_fid = newfid;
+       call->out_scb = new_scb;
 
        /* marshall the parameters */
        bp = call->request;
        bp = xdr_encode_u32(bp, YFSCREATEFILE);
        bp = xdr_encode_u32(bp, 0); /* RPC flags */
-       bp = xdr_encode_YFSFid(bp, &vnode->fid);
+       bp = xdr_encode_YFSFid(bp, &dvnode->fid);
        bp = xdr_encode_string(bp, name, namesz);
        bp = xdr_encode_YFSStoreStatus_mode(bp, mode);
        bp = xdr_encode_u32(bp, yfs_LockNone); /* ViceLockType */
        yfs_check_req(call, bp);
 
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call1(call, &vnode->fid, name);
+       trace_afs_make_fs_call1(call, &dvnode->fid, name);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -830,14 +735,13 @@ static const struct afs_call_type yfs_RXFSMakeDir = {
 int yfs_fs_make_dir(struct afs_fs_cursor *fc,
                    const char *name,
                    umode_t mode,
-                   u64 current_data_version,
+                   struct afs_status_cb *dvnode_scb,
                    struct afs_fid *newfid,
-                   struct afs_file_status *newstatus,
-                   struct afs_callback *newcb)
+                   struct afs_status_cb *new_scb)
 {
-       struct afs_vnode *vnode = fc->vnode;
+       struct afs_vnode *dvnode = fc->vnode;
        struct afs_call *call;
-       struct afs_net *net = afs_v2net(vnode);
+       struct afs_net *net = afs_v2net(dvnode);
        size_t namesz, reqsz, rplsz;
        __be32 *bp;
 
@@ -860,23 +764,22 @@ int yfs_fs_make_dir(struct afs_fs_cursor *fc,
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->reply[1] = newfid;
-       call->reply[2] = newstatus;
-       call->reply[3] = newcb;
-       call->expected_version = current_data_version + 1;
+       call->out_dir_scb = dvnode_scb;
+       call->out_fid = newfid;
+       call->out_scb = new_scb;
 
        /* marshall the parameters */
        bp = call->request;
        bp = xdr_encode_u32(bp, YFSMAKEDIR);
        bp = xdr_encode_u32(bp, 0); /* RPC flags */
-       bp = xdr_encode_YFSFid(bp, &vnode->fid);
+       bp = xdr_encode_YFSFid(bp, &dvnode->fid);
        bp = xdr_encode_string(bp, name, namesz);
        bp = xdr_encode_YFSStoreStatus_mode(bp, mode);
        yfs_check_req(call, bp);
 
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call1(call, &vnode->fid, name);
+       trace_afs_make_fs_call1(call, &dvnode->fid, name);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -886,8 +789,6 @@ int yfs_fs_make_dir(struct afs_fs_cursor *fc,
  */
 static int yfs_deliver_fs_remove_file2(struct afs_call *call)
 {
-       struct afs_vnode *dvnode = call->reply[0];
-       struct afs_vnode *vnode = call->reply[1];
        struct afs_fid fid;
        const __be32 *bp;
        int ret;
@@ -898,20 +799,18 @@ static int yfs_deliver_fs_remove_file2(struct afs_call *call)
        if (ret < 0)
                return ret;
 
-       /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       ret = yfs_decode_status(call, &bp, &dvnode->status, dvnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_dir_scb);
        if (ret < 0)
                return ret;
 
        xdr_decode_YFSFid(&bp, &fid);
-       ret = yfs_decode_status(call, &bp, &vnode->status, vnode, NULL, NULL);
+       ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb);
        if (ret < 0)
                return ret;
        /* Was deleted if vnode->status.abort_code == VNOVNODE. */
 
-       xdr_decode_YFSVolSync(&bp, NULL);
+       xdr_decode_YFSVolSync(&bp, call->out_volsync);
        return 0;
 }
 
@@ -929,7 +828,8 @@ static const struct afs_call_type yfs_RXYFSRemoveFile2 = {
  * Remove a file and retrieve new file status.
  */
 int yfs_fs_remove_file2(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
-                       const char *name, u64 current_data_version)
+                       const char *name, struct afs_status_cb *dvnode_scb,
+                       struct afs_status_cb *vnode_scb)
 {
        struct afs_vnode *dvnode = fc->vnode;
        struct afs_call *call;
@@ -954,9 +854,8 @@ int yfs_fs_remove_file2(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = dvnode;
-       call->reply[1] = vnode;
-       call->expected_version = current_data_version + 1;
+       call->out_dir_scb = dvnode_scb;
+       call->out_scb = vnode_scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -968,6 +867,7 @@ int yfs_fs_remove_file2(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call1(call, &dvnode->fid, name);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -977,7 +877,6 @@ int yfs_fs_remove_file2(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
  */
 static int yfs_deliver_fs_remove(struct afs_call *call)
 {
-       struct afs_vnode *dvnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
@@ -987,14 +886,12 @@ static int yfs_deliver_fs_remove(struct afs_call *call)
        if (ret < 0)
                return ret;
 
-       /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       ret = yfs_decode_status(call, &bp, &dvnode->status, dvnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_dir_scb);
        if (ret < 0)
                return ret;
 
-       xdr_decode_YFSVolSync(&bp, NULL);
+       xdr_decode_YFSVolSync(&bp, call->out_volsync);
        return 0;
 }
 
@@ -1019,7 +916,8 @@ static const struct afs_call_type yfs_RXYFSRemoveDir = {
  * remove a file or directory
  */
 int yfs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
-                 const char *name, bool isdir, u64 current_data_version)
+                 const char *name, bool isdir,
+                 struct afs_status_cb *dvnode_scb)
 {
        struct afs_vnode *dvnode = fc->vnode;
        struct afs_call *call;
@@ -1042,9 +940,7 @@ int yfs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = dvnode;
-       call->reply[1] = vnode;
-       call->expected_version = current_data_version + 1;
+       call->out_dir_scb = dvnode_scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1056,6 +952,7 @@ int yfs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call1(call, &dvnode->fid, name);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1065,7 +962,6 @@ int yfs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
  */
 static int yfs_deliver_fs_link(struct afs_call *call)
 {
-       struct afs_vnode *dvnode = call->reply[0], *vnode = call->reply[1];
        const __be32 *bp;
        int ret;
 
@@ -1075,16 +971,14 @@ static int yfs_deliver_fs_link(struct afs_call *call)
        if (ret < 0)
                return ret;
 
-       /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       ret = yfs_decode_status(call, &bp, &vnode->status, vnode, NULL, NULL);
+       ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb);
        if (ret < 0)
                return ret;
-       ret = yfs_decode_status(call, &bp, &dvnode->status, dvnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_dir_scb);
        if (ret < 0)
                return ret;
-       xdr_decode_YFSVolSync(&bp, NULL);
+       xdr_decode_YFSVolSync(&bp, call->out_volsync);
        _leave(" = 0 [done]");
        return 0;
 }
@@ -1103,7 +997,9 @@ static const struct afs_call_type yfs_RXYFSLink = {
  * Make a hard link.
  */
 int yfs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
-               const char *name, u64 current_data_version)
+               const char *name,
+               struct afs_status_cb *dvnode_scb,
+               struct afs_status_cb *vnode_scb)
 {
        struct afs_vnode *dvnode = fc->vnode;
        struct afs_call *call;
@@ -1127,9 +1023,8 @@ int yfs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = dvnode;
-       call->reply[1] = vnode;
-       call->expected_version = current_data_version + 1;
+       call->out_dir_scb = dvnode_scb;
+       call->out_scb = vnode_scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1142,6 +1037,7 @@ int yfs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call1(call, &vnode->fid, name);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1151,7 +1047,6 @@ int yfs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
  */
 static int yfs_deliver_fs_symlink(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
@@ -1163,15 +1058,14 @@ static int yfs_deliver_fs_symlink(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       xdr_decode_YFSFid(&bp, call->reply[1]);
-       ret = yfs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL);
+       xdr_decode_YFSFid(&bp, call->out_fid);
+       ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb);
        if (ret < 0)
                return ret;
-       ret = yfs_decode_status(call, &bp, &vnode->status, vnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_dir_scb);
        if (ret < 0)
                return ret;
-       xdr_decode_YFSVolSync(&bp, NULL);
+       xdr_decode_YFSVolSync(&bp, call->out_volsync);
 
        _leave(" = 0 [done]");
        return 0;
@@ -1193,9 +1087,9 @@ static const struct afs_call_type yfs_RXYFSSymlink = {
 int yfs_fs_symlink(struct afs_fs_cursor *fc,
                   const char *name,
                   const char *contents,
-                  u64 current_data_version,
+                  struct afs_status_cb *dvnode_scb,
                   struct afs_fid *newfid,
-                  struct afs_file_status *newstatus)
+                  struct afs_status_cb *vnode_scb)
 {
        struct afs_vnode *dvnode = fc->vnode;
        struct afs_call *call;
@@ -1222,10 +1116,9 @@ int yfs_fs_symlink(struct afs_fs_cursor *fc,
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = dvnode;
-       call->reply[1] = newfid;
-       call->reply[2] = newstatus;
-       call->expected_version = current_data_version + 1;
+       call->out_dir_scb = dvnode_scb;
+       call->out_fid = newfid;
+       call->out_scb = vnode_scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1239,6 +1132,7 @@ int yfs_fs_symlink(struct afs_fs_cursor *fc,
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call1(call, &dvnode->fid, name);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1248,8 +1142,6 @@ int yfs_fs_symlink(struct afs_fs_cursor *fc,
  */
 static int yfs_deliver_fs_rename(struct afs_call *call)
 {
-       struct afs_vnode *orig_dvnode = call->reply[0];
-       struct afs_vnode *new_dvnode = call->reply[1];
        const __be32 *bp;
        int ret;
 
@@ -1259,20 +1151,17 @@ static int yfs_deliver_fs_rename(struct afs_call *call)
        if (ret < 0)
                return ret;
 
-       /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       ret = yfs_decode_status(call, &bp, &orig_dvnode->status, orig_dvnode,
-                               &call->expected_version, NULL);
+       ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_dir_scb);
        if (ret < 0)
                return ret;
-       if (new_dvnode != orig_dvnode) {
-               ret = yfs_decode_status(call, &bp, &new_dvnode->status, new_dvnode,
-                                       &call->expected_version_2, NULL);
+       if (call->out_dir_scb != call->out_scb) {
+               ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb);
                if (ret < 0)
                        return ret;
        }
 
-       xdr_decode_YFSVolSync(&bp, NULL);
+       xdr_decode_YFSVolSync(&bp, call->out_volsync);
        _leave(" = 0 [done]");
        return 0;
 }
@@ -1294,8 +1183,8 @@ int yfs_fs_rename(struct afs_fs_cursor *fc,
                  const char *orig_name,
                  struct afs_vnode *new_dvnode,
                  const char *new_name,
-                 u64 current_orig_data_version,
-                 u64 current_new_data_version)
+                 struct afs_status_cb *orig_dvnode_scb,
+                 struct afs_status_cb *new_dvnode_scb)
 {
        struct afs_vnode *orig_dvnode = fc->vnode;
        struct afs_call *call;
@@ -1321,10 +1210,8 @@ int yfs_fs_rename(struct afs_fs_cursor *fc,
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = orig_dvnode;
-       call->reply[1] = new_dvnode;
-       call->expected_version = current_orig_data_version + 1;
-       call->expected_version_2 = current_new_data_version + 1;
+       call->out_dir_scb = orig_dvnode_scb;
+       call->out_scb = new_dvnode_scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1338,46 +1225,18 @@ int yfs_fs_rename(struct afs_fs_cursor *fc,
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call2(call, &orig_dvnode->fid, orig_name, new_name);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
 
-/*
- * Deliver reply data to a YFS.StoreData64 operation.
- */
-static int yfs_deliver_fs_store_data(struct afs_call *call)
-{
-       struct afs_vnode *vnode = call->reply[0];
-       const __be32 *bp;
-       int ret;
-
-       _enter("");
-
-       ret = afs_transfer_reply(call);
-       if (ret < 0)
-               return ret;
-
-       /* unmarshall the reply once we've received all of it */
-       bp = call->buffer;
-       ret = yfs_decode_status(call, &bp, &vnode->status, vnode,
-                               &call->expected_version, NULL);
-       if (ret < 0)
-               return ret;
-       xdr_decode_YFSVolSync(&bp, NULL);
-
-       afs_pages_written_back(vnode, call);
-
-       _leave(" = 0 [done]");
-       return 0;
-}
-
 /*
  * YFS.StoreData64 operation type.
  */
 static const struct afs_call_type yfs_RXYFSStoreData64 = {
        .name           = "YFS.StoreData64",
        .op             = yfs_FS_StoreData64,
-       .deliver        = yfs_deliver_fs_store_data,
+       .deliver        = yfs_deliver_status_and_volsync,
        .destructor     = afs_flat_call_destructor,
 };
 
@@ -1386,7 +1245,8 @@ static const struct afs_call_type yfs_RXYFSStoreData64 = {
  */
 int yfs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
                      pgoff_t first, pgoff_t last,
-                     unsigned offset, unsigned to)
+                     unsigned offset, unsigned to,
+                     struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -1424,13 +1284,12 @@ int yfs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
 
        call->key = fc->key;
        call->mapping = mapping;
-       call->reply[0] = vnode;
        call->first = first;
        call->last = last;
        call->first_offset = offset;
        call->last_to = to;
        call->send_pages = true;
-       call->expected_version = vnode->status.data_version + 1;
+       call->out_scb = scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1445,51 +1304,25 @@ int yfs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
 
-/*
- * deliver reply data to an FS.StoreStatus
- */
-static int yfs_deliver_fs_store_status(struct afs_call *call)
-{
-       struct afs_vnode *vnode = call->reply[0];
-       const __be32 *bp;
-       int ret;
-
-       _enter("");
-
-       ret = afs_transfer_reply(call);
-       if (ret < 0)
-               return ret;
-
-       /* unmarshall the reply once we've received all of it */
-       bp = call->buffer;
-       ret = yfs_decode_status(call, &bp, &vnode->status, vnode,
-                               &call->expected_version, NULL);
-       if (ret < 0)
-               return ret;
-       xdr_decode_YFSVolSync(&bp, NULL);
-
-       _leave(" = 0 [done]");
-       return 0;
-}
-
 /*
  * YFS.StoreStatus operation type
  */
 static const struct afs_call_type yfs_RXYFSStoreStatus = {
        .name           = "YFS.StoreStatus",
        .op             = yfs_FS_StoreStatus,
-       .deliver        = yfs_deliver_fs_store_status,
+       .deliver        = yfs_deliver_status_and_volsync,
        .destructor     = afs_flat_call_destructor,
 };
 
 static const struct afs_call_type yfs_RXYFSStoreData64_as_Status = {
        .name           = "YFS.StoreData64",
        .op             = yfs_FS_StoreData64,
-       .deliver        = yfs_deliver_fs_store_status,
+       .deliver        = yfs_deliver_status_and_volsync,
        .destructor     = afs_flat_call_destructor,
 };
 
@@ -1497,7 +1330,8 @@ static const struct afs_call_type yfs_RXYFSStoreData64_as_Status = {
  * Set the attributes on a file, using YFS.StoreData64 rather than
  * YFS.StoreStatus so as to alter the file size also.
  */
-static int yfs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
+static int yfs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr,
+                              struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -1518,8 +1352,7 @@ static int yfs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->expected_version = vnode->status.data_version + 1;
+       call->out_scb = scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1534,6 +1367,7 @@ static int yfs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1542,7 +1376,8 @@ static int yfs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
  * Set the attributes on a file, using YFS.StoreData64 if there's a change in
  * file size, and YFS.StoreStatus otherwise.
  */
-int yfs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr)
+int yfs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr,
+                  struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -1550,7 +1385,7 @@ int yfs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr)
        __be32 *bp;
 
        if (attr->ia_valid & ATTR_SIZE)
-               return yfs_fs_setattr_size(fc, attr);
+               return yfs_fs_setattr_size(fc, attr, scb);
 
        _enter(",%x,{%llx:%llu},,",
               key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
@@ -1565,8 +1400,7 @@ int yfs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr)
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->expected_version = vnode->status.data_version;
+       call->out_scb = scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1578,6 +1412,7 @@ int yfs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr)
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1607,7 +1442,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
                        return ret;
 
                bp = call->buffer;
-               xdr_decode_YFSFetchVolumeStatus(&bp, call->reply[1]);
+               xdr_decode_YFSFetchVolumeStatus(&bp, call->out_volstatus);
                call->unmarshall++;
                afs_extract_to_tmp(call);
 
@@ -1623,7 +1458,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
                        return afs_protocol_error(call, -EBADMSG,
                                                  afs_eproto_volname_len);
                size = (call->count + 3) & ~3; /* It's padded */
-               afs_extract_begin(call, call->reply[2], size);
+               afs_extract_to_buf(call, size);
                call->unmarshall++;
 
                /* Fall through - and extract the volume name */
@@ -1633,7 +1468,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
                if (ret < 0)
                        return ret;
 
-               p = call->reply[2];
+               p = call->buffer;
                p[call->count] = 0;
                _debug("volname '%s'", p);
                afs_extract_to_tmp(call);
@@ -1651,7 +1486,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
                        return afs_protocol_error(call, -EBADMSG,
                                                  afs_eproto_offline_msg_len);
                size = (call->count + 3) & ~3; /* It's padded */
-               afs_extract_begin(call, call->reply[2], size);
+               afs_extract_to_buf(call, size);
                call->unmarshall++;
 
                /* Fall through - and extract the offline message */
@@ -1661,7 +1496,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
                if (ret < 0)
                        return ret;
 
-               p = call->reply[2];
+               p = call->buffer;
                p[call->count] = 0;
                _debug("offline '%s'", p);
 
@@ -1680,7 +1515,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
                        return afs_protocol_error(call, -EBADMSG,
                                                  afs_eproto_motd_len);
                size = (call->count + 3) & ~3; /* It's padded */
-               afs_extract_begin(call, call->reply[2], size);
+               afs_extract_to_buf(call, size);
                call->unmarshall++;
 
                /* Fall through - and extract the message of the day */
@@ -1690,7 +1525,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
                if (ret < 0)
                        return ret;
 
-               p = call->reply[2];
+               p = call->buffer;
                p[call->count] = 0;
                _debug("motd '%s'", p);
 
@@ -1705,16 +1540,6 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
        return 0;
 }
 
-/*
- * Destroy a YFS.GetVolumeStatus call.
- */
-static void yfs_get_volume_status_call_destructor(struct afs_call *call)
-{
-       kfree(call->reply[2]);
-       call->reply[2] = NULL;
-       afs_flat_call_destructor(call);
-}
-
 /*
  * YFS.GetVolumeStatus operation type
  */
@@ -1722,7 +1547,7 @@ static const struct afs_call_type yfs_RXYFSGetVolumeStatus = {
        .name           = "YFS.GetVolumeStatus",
        .op             = yfs_FS_GetVolumeStatus,
        .deliver        = yfs_deliver_fs_get_volume_status,
-       .destructor     = yfs_get_volume_status_call_destructor,
+       .destructor     = afs_flat_call_destructor,
 };
 
 /*
@@ -1735,28 +1560,21 @@ int yfs_fs_get_volume_status(struct afs_fs_cursor *fc,
        struct afs_call *call;
        struct afs_net *net = afs_v2net(vnode);
        __be32 *bp;
-       void *tmpbuf;
 
        _enter("");
 
-       tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
-       if (!tmpbuf)
-               return -ENOMEM;
-
        call = afs_alloc_flat_call(net, &yfs_RXYFSGetVolumeStatus,
                                   sizeof(__be32) * 2 +
                                   sizeof(struct yfs_xdr_u64),
-                                  sizeof(struct yfs_xdr_YFSFetchVolumeStatus) +
-                                  sizeof(__be32));
-       if (!call) {
-               kfree(tmpbuf);
+                                  max_t(size_t,
+                                        sizeof(struct yfs_xdr_YFSFetchVolumeStatus) +
+                                        sizeof(__be32),
+                                        AFSOPAQUEMAX + 1));
+       if (!call)
                return -ENOMEM;
-       }
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->reply[1] = vs;
-       call->reply[2] = tmpbuf;
+       call->out_volstatus = vs;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1767,38 +1585,11 @@ int yfs_fs_get_volume_status(struct afs_fs_cursor *fc,
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
 
-/*
- * Deliver reply data to operations that just return a file status and a volume
- * sync record.
- */
-static int yfs_deliver_status_and_volsync(struct afs_call *call)
-{
-       struct afs_vnode *vnode = call->reply[0];
-       const __be32 *bp;
-       int ret;
-
-       _enter("{%u}", call->unmarshall);
-
-       ret = afs_transfer_reply(call);
-       if (ret < 0)
-               return ret;
-
-       /* unmarshall the reply once we've received all of it */
-       bp = call->buffer;
-       ret = yfs_decode_status(call, &bp, &vnode->status, vnode,
-                               &call->expected_version, NULL);
-       if (ret < 0)
-               return ret;
-       xdr_decode_YFSVolSync(&bp, NULL);
-
-       _leave(" = 0 [done]");
-       return 0;
-}
-
 /*
  * YFS.SetLock operation type
  */
@@ -1834,7 +1625,8 @@ static const struct afs_call_type yfs_RXYFSReleaseLock = {
 /*
  * Set a lock on a file
  */
-int yfs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
+int yfs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type,
+                   struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -1853,8 +1645,8 @@ int yfs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->want_reply_time = true;
+       call->lvnode = vnode;
+       call->out_scb = scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1866,6 +1658,7 @@ int yfs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_calli(call, &vnode->fid, type);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1873,7 +1666,7 @@ int yfs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
 /*
  * extend a lock on a file
  */
-int yfs_fs_extend_lock(struct afs_fs_cursor *fc)
+int yfs_fs_extend_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -1891,8 +1684,8 @@ int yfs_fs_extend_lock(struct afs_fs_cursor *fc)
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->want_reply_time = true;
+       call->lvnode = vnode;
+       call->out_scb = scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1903,6 +1696,7 @@ int yfs_fs_extend_lock(struct afs_fs_cursor *fc)
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -1910,7 +1704,7 @@ int yfs_fs_extend_lock(struct afs_fs_cursor *fc)
 /*
  * release a lock on a file
  */
-int yfs_fs_release_lock(struct afs_fs_cursor *fc)
+int yfs_fs_release_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -1928,7 +1722,8 @@ int yfs_fs_release_lock(struct afs_fs_cursor *fc)
                return -ENOMEM;
 
        call->key = fc->key;
-       call->reply[0] = vnode;
+       call->lvnode = vnode;
+       call->out_scb = scb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1939,48 +1734,18 @@ int yfs_fs_release_lock(struct afs_fs_cursor *fc)
 
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
 
-/*
- * Deliver reply data to an FS.FetchStatus with no vnode.
- */
-static int yfs_deliver_fs_fetch_status(struct afs_call *call)
-{
-       struct afs_file_status *status = call->reply[1];
-       struct afs_callback *callback = call->reply[2];
-       struct afs_volsync *volsync = call->reply[3];
-       struct afs_vnode *vnode = call->reply[0];
-       const __be32 *bp;
-       int ret;
-
-       ret = afs_transfer_reply(call);
-       if (ret < 0)
-               return ret;
-
-       _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode);
-
-       /* unmarshall the reply once we've received all of it */
-       bp = call->buffer;
-       ret = yfs_decode_status(call, &bp, status, vnode,
-                               &call->expected_version, NULL);
-       if (ret < 0)
-               return ret;
-       xdr_decode_YFSCallBack_raw(&bp, callback);
-       xdr_decode_YFSVolSync(&bp, volsync);
-
-       _leave(" = 0 [done]");
-       return 0;
-}
-
 /*
  * YFS.FetchStatus operation type
  */
 static const struct afs_call_type yfs_RXYFSFetchStatus = {
        .name           = "YFS.FetchStatus",
        .op             = yfs_FS_FetchStatus,
-       .deliver        = yfs_deliver_fs_fetch_status,
+       .deliver        = yfs_deliver_fs_status_cb_and_volsync,
        .destructor     = afs_flat_call_destructor,
 };
 
@@ -1990,8 +1755,7 @@ static const struct afs_call_type yfs_RXYFSFetchStatus = {
 int yfs_fs_fetch_status(struct afs_fs_cursor *fc,
                        struct afs_net *net,
                        struct afs_fid *fid,
-                       struct afs_file_status *status,
-                       struct afs_callback *callback,
+                       struct afs_status_cb *scb,
                        struct afs_volsync *volsync)
 {
        struct afs_call *call;
@@ -2012,11 +1776,8 @@ int yfs_fs_fetch_status(struct afs_fs_cursor *fc,
        }
 
        call->key = fc->key;
-       call->reply[0] = NULL; /* vnode for fid[0] */
-       call->reply[1] = status;
-       call->reply[2] = callback;
-       call->reply[3] = volsync;
-       call->expected_version = 1; /* vnode->status.data_version */
+       call->out_scb = scb;
+       call->out_volsync = volsync;
 
        /* marshall the parameters */
        bp = call->request;
@@ -2025,9 +1786,9 @@ int yfs_fs_fetch_status(struct afs_fs_cursor *fc,
        bp = xdr_encode_YFSFid(bp, fid);
        yfs_check_req(call, bp);
 
-       call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, fid);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -2037,9 +1798,7 @@ int yfs_fs_fetch_status(struct afs_fs_cursor *fc,
  */
 static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
 {
-       struct afs_file_status *statuses;
-       struct afs_callback *callbacks;
-       struct afs_vnode *vnode = call->reply[0];
+       struct afs_status_cb *scb;
        const __be32 *bp;
        u32 tmp;
        int ret;
@@ -2078,10 +1837,8 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
                        return ret;
 
                bp = call->buffer;
-               statuses = call->reply[1];
-               ret = yfs_decode_status(call, &bp, &statuses[call->count],
-                                       call->count == 0 ? vnode : NULL,
-                                       NULL, NULL);
+               scb = &call->out_scb[call->count];
+               ret = xdr_decode_YFSFetchStatus(&bp, call, scb);
                if (ret < 0)
                        return ret;
 
@@ -2120,13 +1877,8 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
 
                _debug("unmarshall CB array");
                bp = call->buffer;
-               callbacks = call->reply[2];
-               xdr_decode_YFSCallBack_raw(&bp, &callbacks[call->count]);
-               statuses = call->reply[1];
-               if (call->count == 0 && vnode && statuses[0].abort_code == 0) {
-                       bp = call->buffer;
-                       xdr_decode_YFSCallBack(call, vnode, &bp);
-               }
+               scb = &call->out_scb[call->count];
+               xdr_decode_YFSCallBack(&bp, call, scb);
                call->count++;
                if (call->count < call->count2)
                        goto more_cbs;
@@ -2141,7 +1893,7 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
                        return ret;
 
                bp = call->buffer;
-               xdr_decode_YFSVolSync(&bp, call->reply[3]);
+               xdr_decode_YFSVolSync(&bp, call->out_volsync);
 
                call->unmarshall++;
 
@@ -2170,8 +1922,7 @@ static const struct afs_call_type yfs_RXYFSInlineBulkStatus = {
 int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
                              struct afs_net *net,
                              struct afs_fid *fids,
-                             struct afs_file_status *statuses,
-                             struct afs_callback *callbacks,
+                             struct afs_status_cb *statuses,
                              unsigned int nr_fids,
                              struct afs_volsync *volsync)
 {
@@ -2194,10 +1945,8 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
        }
 
        call->key = fc->key;
-       call->reply[0] = NULL; /* vnode for fid[0] */
-       call->reply[1] = statuses;
-       call->reply[2] = callbacks;
-       call->reply[3] = volsync;
+       call->out_scb = statuses;
+       call->out_volsync = volsync;
        call->count2 = nr_fids;
 
        /* marshall the parameters */
@@ -2209,9 +1958,9 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
                bp = xdr_encode_YFSFid(bp, &fids[i]);
        yfs_check_req(call, bp);
 
-       call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &fids[0]);
+       afs_set_fc_call(call, fc);
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
@@ -2221,9 +1970,7 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
  */
 static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call)
 {
-       struct afs_volsync *volsync = call->reply[2];
-       struct afs_vnode *vnode = call->reply[1];
-       struct yfs_acl *yacl =  call->reply[0];
+       struct yfs_acl *yacl = call->out_yacl;
        struct afs_acl *acl;
        const __be32 *bp;
        unsigned int size;
@@ -2308,11 +2055,10 @@ static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call)
                bp = call->buffer;
                yacl->inherit_flag = ntohl(*bp++);
                yacl->num_cleaned = ntohl(*bp++);
-               ret = yfs_decode_status(call, &bp, &vnode->status, vnode,
-                                       &call->expected_version, NULL);
+               ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb);
                if (ret < 0)
                        return ret;
-               xdr_decode_YFSVolSync(&bp, volsync);
+               xdr_decode_YFSVolSync(&bp, call->out_volsync);
 
                call->unmarshall++;
 
@@ -2333,12 +2079,6 @@ void yfs_free_opaque_acl(struct yfs_acl *yacl)
        }
 }
 
-static void yfs_destroy_fs_fetch_opaque_acl(struct afs_call *call)
-{
-       yfs_free_opaque_acl(call->reply[0]);
-       afs_flat_call_destructor(call);
-}
-
 /*
  * YFS.FetchOpaqueACL operation type
  */
@@ -2346,18 +2086,18 @@ static const struct afs_call_type yfs_RXYFSFetchOpaqueACL = {
        .name           = "YFS.FetchOpaqueACL",
        .op             = yfs_FS_FetchOpaqueACL,
        .deliver        = yfs_deliver_fs_fetch_opaque_acl,
-       .destructor     = yfs_destroy_fs_fetch_opaque_acl,
+       .destructor     = afs_flat_call_destructor,
 };
 
 /*
  * Fetch the YFS advanced ACLs for a file.
  */
 struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *fc,
-                                       unsigned int flags)
+                                       struct yfs_acl *yacl,
+                                       struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
-       struct yfs_acl *yacl;
        struct afs_net *net = afs_v2net(vnode);
        __be32 *bp;
 
@@ -2370,19 +2110,15 @@ struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *fc,
                                   sizeof(__be32) * 2 +
                                   sizeof(struct yfs_xdr_YFSFetchStatus) +
                                   sizeof(struct yfs_xdr_YFSVolSync));
-       if (!call)
-               goto nomem;
-
-       yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);
-       if (!yacl)
-               goto nomem_call;
+       if (!call) {
+               fc->ac.error = -ENOMEM;
+               return ERR_PTR(-ENOMEM);
+       }
 
-       yacl->flags = flags;
        call->key = fc->key;
-       call->reply[0] = yacl;
-       call->reply[1] = vnode;
-       call->reply[2] = NULL; /* volsync */
-       call->ret_reply0 = true;
+       call->out_yacl = yacl;
+       call->out_scb = scb;
+       call->out_volsync = NULL;
 
        /* marshall the parameters */
        bp = call->request;
@@ -2391,17 +2127,10 @@ struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *fc,
        bp = xdr_encode_YFSFid(bp, &vnode->fid);
        yfs_check_req(call, bp);
 
-       call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
        afs_make_call(&fc->ac, call, GFP_KERNEL);
        return (struct yfs_acl *)afs_wait_for_call_to_complete(call, &fc->ac);
-
-nomem_call:
-       afs_put_call(call);
-nomem:
-       fc->ac.error = -ENOMEM;
-       return ERR_PTR(-ENOMEM);
 }
 
 /*
@@ -2417,7 +2146,8 @@ static const struct afs_call_type yfs_RXYFSStoreOpaqueACL2 = {
 /*
  * Fetch the YFS ACL for a file.
  */
-int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *fc, const struct afs_acl *acl)
+int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *fc, const struct afs_acl *acl,
+                            struct afs_status_cb *scb)
 {
        struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
@@ -2441,8 +2171,8 @@ int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *fc, const struct afs_acl *acl
        }
 
        call->key = fc->key;
-       call->reply[0] = vnode;
-       call->reply[2] = NULL; /* volsync */
+       call->out_scb = scb;
+       call->out_volsync = NULL;
 
        /* marshall the parameters */
        bp = call->request;
index 7d09d125f1481f200e67b51fd453603e2c7ce325..fa9e99a962e001bd44b10e42d7cb167c5ad1feb7 100644 (file)
@@ -524,6 +524,19 @@ static inline int arch_check_elf(struct elfhdr *ehdr, bool has_interp,
 
 #endif /* !CONFIG_ARCH_BINFMT_ELF_STATE */
 
+static inline int make_prot(u32 p_flags)
+{
+       int prot = 0;
+
+       if (p_flags & PF_R)
+               prot |= PROT_READ;
+       if (p_flags & PF_W)
+               prot |= PROT_WRITE;
+       if (p_flags & PF_X)
+               prot |= PROT_EXEC;
+       return prot;
+}
+
 /* This is much more generalized than the library routine read function,
    so we keep this separate.  Technically the library read function
    is only provided so that we can read a.out libraries that have
@@ -563,16 +576,10 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
        for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
                if (eppnt->p_type == PT_LOAD) {
                        int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
-                       int elf_prot = 0;
+                       int elf_prot = make_prot(eppnt->p_flags);
                        unsigned long vaddr = 0;
                        unsigned long k, map_addr;
 
-                       if (eppnt->p_flags & PF_R)
-                               elf_prot = PROT_READ;
-                       if (eppnt->p_flags & PF_W)
-                               elf_prot |= PROT_WRITE;
-                       if (eppnt->p_flags & PF_X)
-                               elf_prot |= PROT_EXEC;
                        vaddr = eppnt->p_vaddr;
                        if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
                                elf_type |= MAP_FIXED_NOREPLACE;
@@ -687,7 +694,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
        struct file *interpreter = NULL; /* to shut gcc up */
        unsigned long load_addr = 0, load_bias = 0;
        int load_addr_set = 0;
-       char * elf_interpreter = NULL;
        unsigned long error;
        struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL;
        unsigned long elf_bss, elf_brk;
@@ -698,13 +704,12 @@ static int load_elf_binary(struct linux_binprm *bprm)
        unsigned long start_code, end_code, start_data, end_data;
        unsigned long reloc_func_desc __maybe_unused = 0;
        int executable_stack = EXSTACK_DEFAULT;
-       struct pt_regs *regs = current_pt_regs();
        struct {
                struct elfhdr elf_ex;
                struct elfhdr interp_elf_ex;
        } *loc;
        struct arch_elf_state arch_state = INIT_ARCH_ELF_STATE;
-       loff_t pos;
+       struct pt_regs *regs;
 
        loc = kmalloc(sizeof(*loc), GFP_KERNEL);
        if (!loc) {
@@ -734,69 +739,66 @@ static int load_elf_binary(struct linux_binprm *bprm)
                goto out;
 
        elf_ppnt = elf_phdata;
-       elf_bss = 0;
-       elf_brk = 0;
+       for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
+               char *elf_interpreter;
+               loff_t pos;
 
-       start_code = ~0UL;
-       end_code = 0;
-       start_data = 0;
-       end_data = 0;
+               if (elf_ppnt->p_type != PT_INTERP)
+                       continue;
 
-       for (i = 0; i < loc->elf_ex.e_phnum; i++) {
-               if (elf_ppnt->p_type == PT_INTERP) {
-                       /* This is the program interpreter used for
-                        * shared libraries - for now assume that this
-                        * is an a.out format binary
-                        */
-                       retval = -ENOEXEC;
-                       if (elf_ppnt->p_filesz > PATH_MAX || 
-                           elf_ppnt->p_filesz < 2)
-                               goto out_free_ph;
-
-                       retval = -ENOMEM;
-                       elf_interpreter = kmalloc(elf_ppnt->p_filesz,
-                                                 GFP_KERNEL);
-                       if (!elf_interpreter)
-                               goto out_free_ph;
-
-                       pos = elf_ppnt->p_offset;
-                       retval = kernel_read(bprm->file, elf_interpreter,
-                                            elf_ppnt->p_filesz, &pos);
-                       if (retval != elf_ppnt->p_filesz) {
-                               if (retval >= 0)
-                                       retval = -EIO;
-                               goto out_free_interp;
-                       }
-                       /* make sure path is NULL terminated */
-                       retval = -ENOEXEC;
-                       if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0')
-                               goto out_free_interp;
+               /*
+                * This is the program interpreter used for shared libraries -
+                * for now assume that this is an a.out format binary.
+                */
+               retval = -ENOEXEC;
+               if (elf_ppnt->p_filesz > PATH_MAX || elf_ppnt->p_filesz < 2)
+                       goto out_free_ph;
 
-                       interpreter = open_exec(elf_interpreter);
-                       retval = PTR_ERR(interpreter);
-                       if (IS_ERR(interpreter))
-                               goto out_free_interp;
+               retval = -ENOMEM;
+               elf_interpreter = kmalloc(elf_ppnt->p_filesz, GFP_KERNEL);
+               if (!elf_interpreter)
+                       goto out_free_ph;
 
-                       /*
-                        * If the binary is not readable then enforce
-                        * mm->dumpable = 0 regardless of the interpreter's
-                        * permissions.
-                        */
-                       would_dump(bprm, interpreter);
-
-                       /* Get the exec headers */
-                       pos = 0;
-                       retval = kernel_read(interpreter, &loc->interp_elf_ex,
-                                            sizeof(loc->interp_elf_ex), &pos);
-                       if (retval != sizeof(loc->interp_elf_ex)) {
-                               if (retval >= 0)
-                                       retval = -EIO;
-                               goto out_free_dentry;
-                       }
+               pos = elf_ppnt->p_offset;
+               retval = kernel_read(bprm->file, elf_interpreter,
+                                    elf_ppnt->p_filesz, &pos);
+               if (retval != elf_ppnt->p_filesz) {
+                       if (retval >= 0)
+                               retval = -EIO;
+                       goto out_free_interp;
+               }
+               /* make sure path is NULL terminated */
+               retval = -ENOEXEC;
+               if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0')
+                       goto out_free_interp;
 
-                       break;
+               interpreter = open_exec(elf_interpreter);
+               kfree(elf_interpreter);
+               retval = PTR_ERR(interpreter);
+               if (IS_ERR(interpreter))
+                       goto out_free_ph;
+
+               /*
+                * If the binary is not readable then enforce mm->dumpable = 0
+                * regardless of the interpreter's permissions.
+                */
+               would_dump(bprm, interpreter);
+
+               /* Get the exec headers */
+               pos = 0;
+               retval = kernel_read(interpreter, &loc->interp_elf_ex,
+                                    sizeof(loc->interp_elf_ex), &pos);
+               if (retval != sizeof(loc->interp_elf_ex)) {
+                       if (retval >= 0)
+                               retval = -EIO;
+                       goto out_free_dentry;
                }
-               elf_ppnt++;
+
+               break;
+
+out_free_interp:
+               kfree(elf_interpreter);
+               goto out_free_ph;
        }
 
        elf_ppnt = elf_phdata;
@@ -819,7 +821,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
                }
 
        /* Some simple consistency checks for the interpreter */
-       if (elf_interpreter) {
+       if (interpreter) {
                retval = -ELIBBAD;
                /* Not an ELF interpreter */
                if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
@@ -884,13 +886,19 @@ static int load_elf_binary(struct linux_binprm *bprm)
        if (retval < 0)
                goto out_free_dentry;
        
-       current->mm->start_stack = bprm->p;
+       elf_bss = 0;
+       elf_brk = 0;
+
+       start_code = ~0UL;
+       end_code = 0;
+       start_data = 0;
+       end_data = 0;
 
        /* Now we do a little grungy work by mmapping the ELF image into
           the correct location in memory. */
        for(i = 0, elf_ppnt = elf_phdata;
            i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
-               int elf_prot = 0, elf_flags, elf_fixed = MAP_FIXED_NOREPLACE;
+               int elf_prot, elf_flags, elf_fixed = MAP_FIXED_NOREPLACE;
                unsigned long k, vaddr;
                unsigned long total_size = 0;
 
@@ -931,12 +939,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
                        elf_fixed = MAP_FIXED;
                }
 
-               if (elf_ppnt->p_flags & PF_R)
-                       elf_prot |= PROT_READ;
-               if (elf_ppnt->p_flags & PF_W)
-                       elf_prot |= PROT_WRITE;
-               if (elf_ppnt->p_flags & PF_X)
-                       elf_prot |= PROT_EXEC;
+               elf_prot = make_prot(elf_ppnt->p_flags);
 
                elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE;
 
@@ -978,7 +981,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
                         * independently randomized mmap region (0 load_bias
                         * without MAP_FIXED).
                         */
-                       if (elf_interpreter) {
+                       if (interpreter) {
                                load_bias = ELF_ET_DYN_BASE;
                                if (current->flags & PF_RANDOMIZE)
                                        load_bias += arch_mmap_rnd();
@@ -1076,7 +1079,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
                goto out_free_dentry;
        }
 
-       if (elf_interpreter) {
+       if (interpreter) {
                unsigned long interp_map_addr = 0;
 
                elf_entry = load_elf_interp(&loc->interp_elf_ex,
@@ -1100,7 +1103,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
 
                allow_write_access(interpreter);
                fput(interpreter);
-               kfree(elf_interpreter);
        } else {
                elf_entry = loc->elf_ex.e_entry;
                if (BAD_ADDR(elf_entry)) {
@@ -1115,7 +1117,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
        set_binfmt(&elf_format);
 
 #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES
-       retval = arch_setup_additional_pages(bprm, !!elf_interpreter);
+       retval = arch_setup_additional_pages(bprm, !!interpreter);
        if (retval < 0)
                goto out;
 #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
@@ -1132,6 +1134,17 @@ static int load_elf_binary(struct linux_binprm *bprm)
        current->mm->start_stack = bprm->p;
 
        if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) {
+               /*
+                * For architectures with ELF randomization, when executing
+                * a loader directly (i.e. no interpreter listed in ELF
+                * headers), move the brk area out of the mmap region
+                * (since it grows up, and may collide early with the stack
+                * growing down), and into the unused ELF_ET_DYN_BASE region.
+                */
+               if (IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) && !interpreter)
+                       current->mm->brk = current->mm->start_brk =
+                               ELF_ET_DYN_BASE;
+
                current->mm->brk = current->mm->start_brk =
                        arch_randomize_brk(current->mm);
 #ifdef compat_brk_randomized
@@ -1148,6 +1161,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
                                MAP_FIXED | MAP_PRIVATE, 0);
        }
 
+       regs = current_pt_regs();
 #ifdef ELF_PLAT_INIT
        /*
         * The ABI may specify that certain registers be set up in special
@@ -1176,8 +1190,6 @@ out_free_dentry:
        allow_write_access(interpreter);
        if (interpreter)
                fput(interpreter);
-out_free_interp:
-       kfree(elf_interpreter);
 out_free_ph:
        kfree(elf_phdata);
        goto out;
@@ -1456,8 +1468,6 @@ static void fill_elf_header(struct elfhdr *elf, int segs,
        elf->e_ehsize = sizeof(struct elfhdr);
        elf->e_phentsize = sizeof(struct elf_phdr);
        elf->e_phnum = segs;
-
-       return;
 }
 
 static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset)
@@ -1470,7 +1480,6 @@ static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset)
        phdr->p_memsz = 0;
        phdr->p_flags = 0;
        phdr->p_align = 0;
-       return;
 }
 
 static void fill_note(struct memelfnote *note, const char *name, int type, 
@@ -1480,7 +1489,6 @@ static void fill_note(struct memelfnote *note, const char *name, int type,
        note->type = type;
        note->datasz = sz;
        note->data = data;
-       return;
 }
 
 /*
index f80045048bb7c00686a4fc34bf8632735c672baf..0f7552a87d5447c118d1873f8249eeaa73321457 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/namei.h>
 #include <linux/log2.h>
 #include <linux/cleancache.h>
-#include <linux/dax.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/falloc.h>
 #include <linux/uaccess.h>
index 1645fcfd9691c33bb58114546c262911edfdf25c..d27720cd3664aee8e35ea5091238046be83798b0 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/namei.h>
 #include <linux/security.h>
 #include <linux/slab.h>
-#include <linux/xattr.h>
 #include "internal.h"
 
 #define CACHEFILES_KEYBUF_SIZE 512
index 36a8dc699448c66eead329bea2b1b43ca0966d8e..72f8e131139241fa89f9eeab64b42645079c0b84 100644 (file)
@@ -892,8 +892,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch)
        int have = ci->i_snap_caps;
 
        if ((have & mask) == mask) {
-               dout("__ceph_caps_issued_mask %p snap issued %s"
-                    " (mask %s)\n", &ci->vfs_inode,
+               dout("__ceph_caps_issued_mask ino 0x%lx snap issued %s"
+                    " (mask %s)\n", ci->vfs_inode.i_ino,
                     ceph_cap_string(have),
                     ceph_cap_string(mask));
                return 1;
@@ -904,8 +904,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch)
                if (!__cap_is_valid(cap))
                        continue;
                if ((cap->issued & mask) == mask) {
-                       dout("__ceph_caps_issued_mask %p cap %p issued %s"
-                            " (mask %s)\n", &ci->vfs_inode, cap,
+                       dout("__ceph_caps_issued_mask ino 0x%lx cap %p issued %s"
+                            " (mask %s)\n", ci->vfs_inode.i_ino, cap,
                             ceph_cap_string(cap->issued),
                             ceph_cap_string(mask));
                        if (touch)
@@ -916,8 +916,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch)
                /* does a combination of caps satisfy mask? */
                have |= cap->issued;
                if ((have & mask) == mask) {
-                       dout("__ceph_caps_issued_mask %p combo issued %s"
-                            " (mask %s)\n", &ci->vfs_inode,
+                       dout("__ceph_caps_issued_mask ino 0x%lx combo issued %s"
+                            " (mask %s)\n", ci->vfs_inode.i_ino,
                             ceph_cap_string(cap->issued),
                             ceph_cap_string(mask));
                        if (touch) {
@@ -2257,8 +2257,6 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
        if (datasync)
                goto out;
 
-       inode_lock(inode);
-
        dirty = try_flush_caps(inode, &flush_tid);
        dout("fsync dirty caps are %s\n", ceph_cap_string(dirty));
 
@@ -2273,7 +2271,6 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
                ret = wait_event_interruptible(ci->i_cap_wq,
                                        caps_are_flushed(inode, flush_tid));
        }
-       inode_unlock(inode);
 out:
        dout("fsync %p%s result=%d\n", inode, datasync ? " datasync" : "", ret);
        return ret;
@@ -2528,9 +2525,14 @@ static void __take_cap_refs(struct ceph_inode_info *ci, int got,
  * to (when applicable), and check against max_size here as well.
  * Note that caller is responsible for ensuring max_size increases are
  * requested from the MDS.
+ *
+ * Returns 0 if caps were not able to be acquired (yet), a 1 if they were,
+ * or a negative error code.
+ *
+ * FIXME: how does a 0 return differ from -EAGAIN?
  */
 static int try_get_cap_refs(struct ceph_inode_info *ci, int need, int want,
-                           loff_t endoff, bool nonblock, int *got, int *err)
+                           loff_t endoff, bool nonblock, int *got)
 {
        struct inode *inode = &ci->vfs_inode;
        struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
@@ -2550,8 +2552,7 @@ again:
        if ((file_wanted & need) != need) {
                dout("try_get_cap_refs need %s file_wanted %s, EBADF\n",
                     ceph_cap_string(need), ceph_cap_string(file_wanted));
-               *err = -EBADF;
-               ret = 1;
+               ret = -EBADF;
                goto out_unlock;
        }
 
@@ -2572,10 +2573,8 @@ again:
                if (endoff >= 0 && endoff > (loff_t)ci->i_max_size) {
                        dout("get_cap_refs %p endoff %llu > maxsize %llu\n",
                             inode, endoff, ci->i_max_size);
-                       if (endoff > ci->i_requested_max_size) {
-                               *err = -EAGAIN;
-                               ret = 1;
-                       }
+                       if (endoff > ci->i_requested_max_size)
+                               ret = -EAGAIN;
                        goto out_unlock;
                }
                /*
@@ -2610,8 +2609,7 @@ again:
                                         * task isn't in TASK_RUNNING state
                                         */
                                        if (nonblock) {
-                                               *err = -EAGAIN;
-                                               ret = 1;
+                                               ret = -EAGAIN;
                                                goto out_unlock;
                                        }
 
@@ -2640,8 +2638,7 @@ again:
                if (session_readonly) {
                        dout("get_cap_refs %p needed %s but mds%d readonly\n",
                             inode, ceph_cap_string(need), ci->i_auth_cap->mds);
-                       *err = -EROFS;
-                       ret = 1;
+                       ret = -EROFS;
                        goto out_unlock;
                }
 
@@ -2650,16 +2647,14 @@ again:
                        if (READ_ONCE(mdsc->fsc->mount_state) ==
                            CEPH_MOUNT_SHUTDOWN) {
                                dout("get_cap_refs %p forced umount\n", inode);
-                               *err = -EIO;
-                               ret = 1;
+                               ret = -EIO;
                                goto out_unlock;
                        }
                        mds_wanted = __ceph_caps_mds_wanted(ci, false);
                        if (need & ~(mds_wanted & need)) {
                                dout("get_cap_refs %p caps were dropped"
                                     " (session killed?)\n", inode);
-                               *err = -ESTALE;
-                               ret = 1;
+                               ret = -ESTALE;
                                goto out_unlock;
                        }
                        if (!(file_wanted & ~mds_wanted))
@@ -2710,7 +2705,7 @@ static void check_max_size(struct inode *inode, loff_t endoff)
 int ceph_try_get_caps(struct ceph_inode_info *ci, int need, int want,
                      bool nonblock, int *got)
 {
-       int ret, err = 0;
+       int ret;
 
        BUG_ON(need & ~CEPH_CAP_FILE_RD);
        BUG_ON(want & ~(CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO|CEPH_CAP_FILE_SHARED));
@@ -2718,15 +2713,8 @@ int ceph_try_get_caps(struct ceph_inode_info *ci, int need, int want,
        if (ret < 0)
                return ret;
 
-       ret = try_get_cap_refs(ci, need, want, 0, nonblock, got, &err);
-       if (ret) {
-               if (err == -EAGAIN) {
-                       ret = 0;
-               } else if (err < 0) {
-                       ret = err;
-               }
-       }
-       return ret;
+       ret = try_get_cap_refs(ci, need, want, 0, nonblock, got);
+       return ret == -EAGAIN ? 0 : ret;
 }
 
 /*
@@ -2737,7 +2725,7 @@ int ceph_try_get_caps(struct ceph_inode_info *ci, int need, int want,
 int ceph_get_caps(struct ceph_inode_info *ci, int need, int want,
                  loff_t endoff, int *got, struct page **pinned_page)
 {
-       int _got, ret, err = 0;
+       int _got, ret;
 
        ret = ceph_pool_perm_check(ci, need);
        if (ret < 0)
@@ -2747,21 +2735,19 @@ int ceph_get_caps(struct ceph_inode_info *ci, int need, int want,
                if (endoff > 0)
                        check_max_size(&ci->vfs_inode, endoff);
 
-               err = 0;
                _got = 0;
                ret = try_get_cap_refs(ci, need, want, endoff,
-                                      false, &_got, &err);
-               if (ret) {
-                       if (err == -EAGAIN)
-                               continue;
-                       if (err < 0)
-                               ret = err;
-               } else {
+                                      false, &_got);
+               if (ret == -EAGAIN) {
+                       continue;
+               } else if (!ret) {
+                       int err;
+
                        DEFINE_WAIT_FUNC(wait, woken_wake_function);
                        add_wait_queue(&ci->i_cap_wq, &wait);
 
-                       while (!try_get_cap_refs(ci, need, want, endoff,
-                                                true, &_got, &err)) {
+                       while (!(err = try_get_cap_refs(ci, need, want, endoff,
+                                                       true, &_got))) {
                                if (signal_pending(current)) {
                                        ret = -ERESTARTSYS;
                                        break;
@@ -2770,19 +2756,14 @@ int ceph_get_caps(struct ceph_inode_info *ci, int need, int want,
                        }
 
                        remove_wait_queue(&ci->i_cap_wq, &wait);
-
                        if (err == -EAGAIN)
                                continue;
-                       if (err < 0)
-                               ret = err;
                }
-               if (ret < 0) {
-                       if (err == -ESTALE) {
-                               /* session was killed, try renew caps */
-                               ret = ceph_renew_caps(&ci->vfs_inode);
-                               if (ret == 0)
-                                       continue;
-                       }
+               if (ret == -ESTALE) {
+                       /* session was killed, try renew caps */
+                       ret = ceph_renew_caps(&ci->vfs_inode);
+                       if (ret == 0)
+                               continue;
                        return ret;
                }
 
@@ -4099,7 +4080,7 @@ void ceph_put_fmode(struct ceph_inode_info *ci, int fmode)
 }
 
 /*
- * For a soon-to-be unlinked file, drop the AUTH_RDCACHE caps. If it
+ * For a soon-to-be unlinked file, drop the LINK caps. If it
  * looks like the link count will hit 0, drop any other caps (other
  * than PIN) we don't specifically want (due to the file still being
  * open).
index 98365e74cb4aa12cb5b80daa18f4e83956798f27..b3fc5fe26a1ab47a1094194cb1835c6b18d2aefb 100644 (file)
@@ -37,7 +37,7 @@ static int mdsmap_show(struct seq_file *s, void *p)
                struct ceph_entity_addr *addr = &mdsmap->m_info[i].addr;
                int state = mdsmap->m_info[i].state;
                seq_printf(s, "\tmds%d\t%s\t(%s)\n", i,
-                              ceph_pr_addr(&addr->in_addr),
+                              ceph_pr_addr(addr),
                               ceph_mds_state_name(state));
        }
        return 0;
@@ -88,7 +88,7 @@ static int mdsc_show(struct seq_file *s, void *p)
                                   req->r_dentry,
                                   path ? path : "");
                        spin_unlock(&req->r_dentry->d_lock);
-                       kfree(path);
+                       ceph_mdsc_free_path(path, pathlen);
                } else if (req->r_path1) {
                        seq_printf(s, " #%llx/%s", req->r_ino1.ino,
                                   req->r_path1);
@@ -108,7 +108,7 @@ static int mdsc_show(struct seq_file *s, void *p)
                                   req->r_old_dentry,
                                   path ? path : "");
                        spin_unlock(&req->r_old_dentry->d_lock);
-                       kfree(path);
+                       ceph_mdsc_free_path(path, pathlen);
                } else if (req->r_path2 && req->r_op != CEPH_MDS_OP_SYMLINK) {
                        if (req->r_ino2.ino)
                                seq_printf(s, " #%llx/%s", req->r_ino2.ino,
@@ -124,18 +124,48 @@ static int mdsc_show(struct seq_file *s, void *p)
        return 0;
 }
 
+static int caps_show_cb(struct inode *inode, struct ceph_cap *cap, void *p)
+{
+       struct seq_file *s = p;
+
+       seq_printf(s, "0x%-17lx%-17s%-17s\n", inode->i_ino,
+                  ceph_cap_string(cap->issued),
+                  ceph_cap_string(cap->implemented));
+       return 0;
+}
+
 static int caps_show(struct seq_file *s, void *p)
 {
        struct ceph_fs_client *fsc = s->private;
-       int total, avail, used, reserved, min;
+       struct ceph_mds_client *mdsc = fsc->mdsc;
+       int total, avail, used, reserved, min, i;
 
        ceph_reservation_status(fsc, &total, &avail, &used, &reserved, &min);
        seq_printf(s, "total\t\t%d\n"
                   "avail\t\t%d\n"
                   "used\t\t%d\n"
                   "reserved\t%d\n"
-                  "min\t%d\n",
+                  "min\t\t%d\n\n",
                   total, avail, used, reserved, min);
+       seq_printf(s, "ino                issued           implemented\n");
+       seq_printf(s, "-----------------------------------------------\n");
+
+       mutex_lock(&mdsc->mutex);
+       for (i = 0; i < mdsc->max_sessions; i++) {
+               struct ceph_mds_session *session;
+
+               session = __ceph_lookup_mds_session(mdsc, i);
+               if (!session)
+                       continue;
+               mutex_unlock(&mdsc->mutex);
+               mutex_lock(&session->s_mutex);
+               ceph_iterate_session_caps(session, caps_show_cb, s);
+               mutex_unlock(&session->s_mutex);
+               ceph_put_mds_session(session);
+               mutex_lock(&mdsc->mutex);
+       }
+       mutex_unlock(&mdsc->mutex);
+
        return 0;
 }
 
index 3c59ad180ef0bb5b9dfb09528e5c1dc363f9b94e..d3ef7ee429ec03d3a4209260df0c396ab433f77d 100644 (file)
@@ -22,18 +22,77 @@ struct ceph_nfs_confh {
        u64 ino, parent_ino;
 } __attribute__ ((packed));
 
+/*
+ * fh for snapped inode
+ */
+struct ceph_nfs_snapfh {
+       u64 ino;
+       u64 snapid;
+       u64 parent_ino;
+       u32 hash;
+} __attribute__ ((packed));
+
+static int ceph_encode_snapfh(struct inode *inode, u32 *rawfh, int *max_len,
+                             struct inode *parent_inode)
+{
+       const static int snap_handle_length =
+               sizeof(struct ceph_nfs_snapfh) >> 2;
+       struct ceph_nfs_snapfh *sfh = (void *)rawfh;
+       u64 snapid = ceph_snap(inode);
+       int ret;
+       bool no_parent = true;
+
+       if (*max_len < snap_handle_length) {
+               *max_len = snap_handle_length;
+               ret = FILEID_INVALID;
+               goto out;
+       }
+
+       ret =  -EINVAL;
+       if (snapid != CEPH_SNAPDIR) {
+               struct inode *dir;
+               struct dentry *dentry = d_find_alias(inode);
+               if (!dentry)
+                       goto out;
+
+               rcu_read_lock();
+               dir = d_inode_rcu(dentry->d_parent);
+               if (ceph_snap(dir) != CEPH_SNAPDIR) {
+                       sfh->parent_ino = ceph_ino(dir);
+                       sfh->hash = ceph_dentry_hash(dir, dentry);
+                       no_parent = false;
+               }
+               rcu_read_unlock();
+               dput(dentry);
+       }
+
+       if (no_parent) {
+               if (!S_ISDIR(inode->i_mode))
+                       goto out;
+               sfh->parent_ino = sfh->ino;
+               sfh->hash = 0;
+       }
+       sfh->ino = ceph_ino(inode);
+       sfh->snapid = snapid;
+
+       *max_len = snap_handle_length;
+       ret = FILEID_BTRFS_WITH_PARENT;
+out:
+       dout("encode_snapfh %llx.%llx ret=%d\n", ceph_vinop(inode), ret);
+       return ret;
+}
+
 static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
                          struct inode *parent_inode)
 {
+       const static int handle_length =
+               sizeof(struct ceph_nfs_fh) >> 2;
+       const static int connected_handle_length =
+               sizeof(struct ceph_nfs_confh) >> 2;
        int type;
-       struct ceph_nfs_fh *fh = (void *)rawfh;
-       struct ceph_nfs_confh *cfh = (void *)rawfh;
-       int connected_handle_length = sizeof(*cfh)/4;
-       int handle_length = sizeof(*fh)/4;
 
-       /* don't re-export snaps */
        if (ceph_snap(inode) != CEPH_NOSNAP)
-               return -EINVAL;
+               return ceph_encode_snapfh(inode, rawfh, max_len, parent_inode);
 
        if (parent_inode && (*max_len < connected_handle_length)) {
                *max_len = connected_handle_length;
@@ -44,6 +103,7 @@ static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
        }
 
        if (parent_inode) {
+               struct ceph_nfs_confh *cfh = (void *)rawfh;
                dout("encode_fh %llx with parent %llx\n",
                     ceph_ino(inode), ceph_ino(parent_inode));
                cfh->ino = ceph_ino(inode);
@@ -51,6 +111,7 @@ static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
                *max_len = connected_handle_length;
                type = FILEID_INO32_GEN_PARENT;
        } else {
+               struct ceph_nfs_fh *fh = (void *)rawfh;
                dout("encode_fh %llx\n", ceph_ino(inode));
                fh->ino = ceph_ino(inode);
                *max_len = handle_length;
@@ -59,7 +120,7 @@ static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
        return type;
 }
 
-static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
+static struct inode *__lookup_inode(struct super_block *sb, u64 ino)
 {
        struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
        struct inode *inode;
@@ -81,7 +142,7 @@ static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
                mask = CEPH_STAT_CAP_INODE;
                if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
                        mask |= CEPH_CAP_XATTR_SHARED;
-               req->r_args.getattr.mask = cpu_to_le32(mask);
+               req->r_args.lookupino.mask = cpu_to_le32(mask);
 
                req->r_ino1 = vino;
                req->r_num_caps = 1;
@@ -91,16 +152,114 @@ static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
                        ihold(inode);
                ceph_mdsc_put_request(req);
                if (!inode)
-                       return ERR_PTR(-ESTALE);
-               if (inode->i_nlink == 0) {
-                       iput(inode);
-                       return ERR_PTR(-ESTALE);
-               }
+                       return err < 0 ? ERR_PTR(err) : ERR_PTR(-ESTALE);
        }
+       return inode;
+}
+
+struct inode *ceph_lookup_inode(struct super_block *sb, u64 ino)
+{
+       struct inode *inode = __lookup_inode(sb, ino);
+       if (IS_ERR(inode))
+               return inode;
+       if (inode->i_nlink == 0) {
+               iput(inode);
+               return ERR_PTR(-ESTALE);
+       }
+       return inode;
+}
 
+static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
+{
+       struct inode *inode = __lookup_inode(sb, ino);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
+       if (inode->i_nlink == 0) {
+               iput(inode);
+               return ERR_PTR(-ESTALE);
+       }
        return d_obtain_alias(inode);
 }
 
+static struct dentry *__snapfh_to_dentry(struct super_block *sb,
+                                         struct ceph_nfs_snapfh *sfh,
+                                         bool want_parent)
+{
+       struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
+       struct ceph_mds_request *req;
+       struct inode *inode;
+       struct ceph_vino vino;
+       int mask;
+       int err;
+       bool unlinked = false;
+
+       if (want_parent) {
+               vino.ino = sfh->parent_ino;
+               if (sfh->snapid == CEPH_SNAPDIR)
+                       vino.snap = CEPH_NOSNAP;
+               else if (sfh->ino == sfh->parent_ino)
+                       vino.snap = CEPH_SNAPDIR;
+               else
+                       vino.snap = sfh->snapid;
+       } else {
+               vino.ino = sfh->ino;
+               vino.snap = sfh->snapid;
+       }
+       inode = ceph_find_inode(sb, vino);
+       if (inode)
+               return d_obtain_alias(inode);
+
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
+                                      USE_ANY_MDS);
+       if (IS_ERR(req))
+               return ERR_CAST(req);
+
+       mask = CEPH_STAT_CAP_INODE;
+       if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
+               mask |= CEPH_CAP_XATTR_SHARED;
+       req->r_args.lookupino.mask = cpu_to_le32(mask);
+       if (vino.snap < CEPH_NOSNAP) {
+               req->r_args.lookupino.snapid = cpu_to_le64(vino.snap);
+               if (!want_parent && sfh->ino != sfh->parent_ino) {
+                       req->r_args.lookupino.parent =
+                                       cpu_to_le64(sfh->parent_ino);
+                       req->r_args.lookupino.hash =
+                                       cpu_to_le32(sfh->hash);
+               }
+       }
+
+       req->r_ino1 = vino;
+       req->r_num_caps = 1;
+       err = ceph_mdsc_do_request(mdsc, NULL, req);
+       inode = req->r_target_inode;
+       if (inode) {
+               if (vino.snap == CEPH_SNAPDIR) {
+                       if (inode->i_nlink == 0)
+                               unlinked = true;
+                       inode = ceph_get_snapdir(inode);
+               } else if (ceph_snap(inode) == vino.snap) {
+                       ihold(inode);
+               } else {
+                       /* mds does not support lookup snapped inode */
+                       err = -EOPNOTSUPP;
+                       inode = NULL;
+               }
+       }
+       ceph_mdsc_put_request(req);
+
+       if (want_parent) {
+               dout("snapfh_to_parent %llx.%llx\n err=%d\n",
+                    vino.ino, vino.snap, err);
+       } else {
+               dout("snapfh_to_dentry %llx.%llx parent %llx hash %x err=%d",
+                     vino.ino, vino.snap, sfh->parent_ino, sfh->hash, err);
+       }
+       if (!inode)
+               return ERR_PTR(-ESTALE);
+       /* see comments in ceph_get_parent() */
+       return unlinked ? d_obtain_root(inode) : d_obtain_alias(inode);
+}
+
 /*
  * convert regular fh to dentry
  */
@@ -110,6 +269,11 @@ static struct dentry *ceph_fh_to_dentry(struct super_block *sb,
 {
        struct ceph_nfs_fh *fh = (void *)fid->raw;
 
+       if (fh_type == FILEID_BTRFS_WITH_PARENT) {
+               struct ceph_nfs_snapfh *sfh = (void *)fid->raw;
+               return __snapfh_to_dentry(sb, sfh, false);
+       }
+
        if (fh_type != FILEID_INO32_GEN  &&
            fh_type != FILEID_INO32_GEN_PARENT)
                return NULL;
@@ -163,13 +327,49 @@ static struct dentry *__get_parent(struct super_block *sb,
 
 static struct dentry *ceph_get_parent(struct dentry *child)
 {
-       /* don't re-export snaps */
-       if (ceph_snap(d_inode(child)) != CEPH_NOSNAP)
-               return ERR_PTR(-EINVAL);
-
-       dout("get_parent %p ino %llx.%llx\n",
-            child, ceph_vinop(d_inode(child)));
-       return __get_parent(child->d_sb, child, 0);
+       struct inode *inode = d_inode(child);
+       struct dentry *dn;
+
+       if (ceph_snap(inode) != CEPH_NOSNAP) {
+               struct inode* dir;
+               bool unlinked = false;
+               /* do not support non-directory */
+               if (!d_is_dir(child)) {
+                       dn = ERR_PTR(-EINVAL);
+                       goto out;
+               }
+               dir = __lookup_inode(inode->i_sb, ceph_ino(inode));
+               if (IS_ERR(dir)) {
+                       dn = ERR_CAST(dir);
+                       goto out;
+               }
+               /* There can be multiple paths to access snapped inode.
+                * For simplicity, treat snapdir of head inode as parent */
+               if (ceph_snap(inode) != CEPH_SNAPDIR) {
+                       struct inode *snapdir = ceph_get_snapdir(dir);
+                       if (dir->i_nlink == 0)
+                               unlinked = true;
+                       iput(dir);
+                       if (IS_ERR(snapdir)) {
+                               dn = ERR_CAST(snapdir);
+                               goto out;
+                       }
+                       dir = snapdir;
+               }
+               /* If directory has already been deleted, futher get_parent
+                * will fail. Do not mark snapdir dentry as disconnected,
+                * this prevent exportfs from doing futher get_parent. */
+               if (unlinked)
+                       dn = d_obtain_root(dir);
+               else
+                       dn = d_obtain_alias(dir);
+       } else {
+               dn = __get_parent(child->d_sb, child, 0);
+       }
+out:
+       dout("get_parent %p ino %llx.%llx err=%ld\n",
+            child, ceph_vinop(inode), (IS_ERR(dn) ? PTR_ERR(dn) : 0));
+       return dn;
 }
 
 /*
@@ -182,6 +382,11 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb,
        struct ceph_nfs_confh *cfh = (void *)fid->raw;
        struct dentry *dentry;
 
+       if (fh_type == FILEID_BTRFS_WITH_PARENT) {
+               struct ceph_nfs_snapfh *sfh = (void *)fid->raw;
+               return __snapfh_to_dentry(sb, sfh, true);
+       }
+
        if (fh_type != FILEID_INO32_GEN_PARENT)
                return NULL;
        if (fh_len < sizeof(*cfh) / 4)
@@ -194,14 +399,115 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb,
        return dentry;
 }
 
+static int __get_snap_name(struct dentry *parent, char *name,
+                          struct dentry *child)
+{
+       struct inode *inode = d_inode(child);
+       struct inode *dir = d_inode(parent);
+       struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
+       struct ceph_mds_request *req = NULL;
+       char *last_name = NULL;
+       unsigned next_offset = 2;
+       int err = -EINVAL;
+
+       if (ceph_ino(inode) != ceph_ino(dir))
+               goto out;
+       if (ceph_snap(inode) == CEPH_SNAPDIR) {
+               if (ceph_snap(dir) == CEPH_NOSNAP) {
+                       strcpy(name, fsc->mount_options->snapdir_name);
+                       err = 0;
+               }
+               goto out;
+       }
+       if (ceph_snap(dir) != CEPH_SNAPDIR)
+               goto out;
+
+       while (1) {
+               struct ceph_mds_reply_info_parsed *rinfo;
+               struct ceph_mds_reply_dir_entry *rde;
+               int i;
+
+               req = ceph_mdsc_create_request(fsc->mdsc, CEPH_MDS_OP_LSSNAP,
+                                              USE_AUTH_MDS);
+               if (IS_ERR(req)) {
+                       err = PTR_ERR(req);
+                       req = NULL;
+                       goto out;
+               }
+               err = ceph_alloc_readdir_reply_buffer(req, inode);
+               if (err)
+                       goto out;
+
+               req->r_direct_mode = USE_AUTH_MDS;
+               req->r_readdir_offset = next_offset;
+               req->r_args.readdir.flags =
+                               cpu_to_le16(CEPH_READDIR_REPLY_BITFLAGS);
+               if (last_name) {
+                       req->r_path2 = last_name;
+                       last_name = NULL;
+               }
+
+               req->r_inode = dir;
+               ihold(dir);
+               req->r_dentry = dget(parent);
+
+               inode_lock(dir);
+               err = ceph_mdsc_do_request(fsc->mdsc, NULL, req);
+               inode_unlock(dir);
+
+               if (err < 0)
+                       goto out;
+
+                rinfo = &req->r_reply_info;
+                for (i = 0; i < rinfo->dir_nr; i++) {
+                        rde = rinfo->dir_entries + i;
+                        BUG_ON(!rde->inode.in);
+                        if (ceph_snap(inode) ==
+                            le64_to_cpu(rde->inode.in->snapid)) {
+                                memcpy(name, rde->name, rde->name_len);
+                                name[rde->name_len] = '\0';
+                                err = 0;
+                                goto out;
+                        }
+                }
+
+                if (rinfo->dir_end)
+                        break;
+
+                BUG_ON(rinfo->dir_nr <= 0);
+                rde = rinfo->dir_entries + (rinfo->dir_nr - 1);
+                next_offset += rinfo->dir_nr;
+                last_name = kstrndup(rde->name, rde->name_len, GFP_KERNEL);
+                if (!last_name) {
+                        err = -ENOMEM;
+                        goto out;
+                }
+
+                ceph_mdsc_put_request(req);
+                req = NULL;
+       }
+       err = -ENOENT;
+out:
+       if (req)
+               ceph_mdsc_put_request(req);
+       kfree(last_name);
+       dout("get_snap_name %p ino %llx.%llx err=%d\n",
+            child, ceph_vinop(inode), err);
+       return err;
+}
+
 static int ceph_get_name(struct dentry *parent, char *name,
                         struct dentry *child)
 {
        struct ceph_mds_client *mdsc;
        struct ceph_mds_request *req;
+       struct inode *inode = d_inode(child);
        int err;
 
-       mdsc = ceph_inode_to_client(d_inode(child))->mdsc;
+       if (ceph_snap(inode) != CEPH_NOSNAP)
+               return __get_snap_name(parent, name, child);
+
+       mdsc = ceph_inode_to_client(inode)->mdsc;
        req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME,
                                       USE_ANY_MDS);
        if (IS_ERR(req))
@@ -209,8 +515,8 @@ static int ceph_get_name(struct dentry *parent, char *name,
 
        inode_lock(d_inode(parent));
 
-       req->r_inode = d_inode(child);
-       ihold(d_inode(child));
+       req->r_inode = inode;
+       ihold(inode);
        req->r_ino2 = ceph_vino(d_inode(parent));
        req->r_parent = d_inode(parent);
        set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
@@ -224,10 +530,10 @@ static int ceph_get_name(struct dentry *parent, char *name,
                memcpy(name, rinfo->dname, rinfo->dname_len);
                name[rinfo->dname_len] = 0;
                dout("get_name %p ino %llx.%llx name %s\n",
-                    child, ceph_vinop(d_inode(child)), name);
+                    child, ceph_vinop(inode), name);
        } else {
                dout("get_name %p ino %llx.%llx err %d\n",
-                    child, ceph_vinop(d_inode(child)), err);
+                    child, ceph_vinop(inode), err);
        }
 
        ceph_mdsc_put_request(req);
index 84725b53ac2190e423c3233aaac7d9adc2a745f4..305daf043eb0eaca81e17dfbd405cd784edaab81 100644 (file)
@@ -929,7 +929,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
 
        dout("sync_direct_%s on file %p %lld~%u snapc %p seq %lld\n",
             (write ? "write" : "read"), file, pos, (unsigned)count,
-            snapc, snapc->seq);
+            snapc, snapc ? snapc->seq : 0);
 
        ret = filemap_write_and_wait_range(inode->i_mapping,
                                           pos, pos + count - 1);
index 35dae6d5493a8eb59e51c2a67f8171d444a44319..f85355bf49c4c7b3830822264c16f7b25c31d731 100644 (file)
@@ -2266,43 +2266,72 @@ int ceph_permission(struct inode *inode, int mask)
        return err;
 }
 
+/* Craft a mask of needed caps given a set of requested statx attrs. */
+static int statx_to_caps(u32 want)
+{
+       int mask = 0;
+
+       if (want & (STATX_MODE|STATX_UID|STATX_GID|STATX_CTIME))
+               mask |= CEPH_CAP_AUTH_SHARED;
+
+       if (want & (STATX_NLINK|STATX_CTIME))
+               mask |= CEPH_CAP_LINK_SHARED;
+
+       if (want & (STATX_ATIME|STATX_MTIME|STATX_CTIME|STATX_SIZE|
+                   STATX_BLOCKS))
+               mask |= CEPH_CAP_FILE_SHARED;
+
+       if (want & (STATX_CTIME))
+               mask |= CEPH_CAP_XATTR_SHARED;
+
+       return mask;
+}
+
 /*
- * Get all attributes.  Hopefully somedata we'll have a statlite()
- * and can limit the fields we require to be accurate.
+ * Get all the attributes. If we have sufficient caps for the requested attrs,
+ * then we can avoid talking to the MDS at all.
  */
 int ceph_getattr(const struct path *path, struct kstat *stat,
                 u32 request_mask, unsigned int flags)
 {
        struct inode *inode = d_inode(path->dentry);
        struct ceph_inode_info *ci = ceph_inode(inode);
-       int err;
+       int err = 0;
 
-       err = ceph_do_getattr(inode, CEPH_STAT_CAP_INODE_ALL, false);
-       if (!err) {
-               generic_fillattr(inode, stat);
-               stat->ino = ceph_translate_ino(inode->i_sb, inode->i_ino);
-               if (ceph_snap(inode) == CEPH_NOSNAP)
-                       stat->dev = inode->i_sb->s_dev;
+       /* Skip the getattr altogether if we're asked not to sync */
+       if (!(flags & AT_STATX_DONT_SYNC)) {
+               err = ceph_do_getattr(inode, statx_to_caps(request_mask),
+                                     flags & AT_STATX_FORCE_SYNC);
+               if (err)
+                       return err;
+       }
+
+       generic_fillattr(inode, stat);
+       stat->ino = ceph_translate_ino(inode->i_sb, inode->i_ino);
+       if (ceph_snap(inode) == CEPH_NOSNAP)
+               stat->dev = inode->i_sb->s_dev;
+       else
+               stat->dev = ci->i_snapid_map ? ci->i_snapid_map->dev : 0;
+
+       if (S_ISDIR(inode->i_mode)) {
+               if (ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb),
+                                       RBYTES))
+                       stat->size = ci->i_rbytes;
                else
-                       stat->dev = ci->i_snapid_map ? ci->i_snapid_map->dev : 0;
-
-               if (S_ISDIR(inode->i_mode)) {
-                       if (ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb),
-                                               RBYTES))
-                               stat->size = ci->i_rbytes;
-                       else
-                               stat->size = ci->i_files + ci->i_subdirs;
-                       stat->blocks = 0;
-                       stat->blksize = 65536;
-                       /*
-                        * Some applications rely on the number of st_nlink
-                        * value on directories to be either 0 (if unlinked)
-                        * or 2 + number of subdirectories.
-                        */
-                       if (stat->nlink == 1)
-                               /* '.' + '..' + subdirs */
-                               stat->nlink = 1 + 1 + ci->i_subdirs;
-               }
+                       stat->size = ci->i_files + ci->i_subdirs;
+               stat->blocks = 0;
+               stat->blksize = 65536;
+               /*
+                * Some applications rely on the number of st_nlink
+                * value on directories to be either 0 (if unlinked)
+                * or 2 + number of subdirectories.
+                */
+               if (stat->nlink == 1)
+                       /* '.' + '..' + subdirs */
+                       stat->nlink = 1 + 1 + ci->i_subdirs;
        }
+
+       /* Mask off any higher bits (e.g. btime) until we have support */
+       stat->result_mask = request_mask & STATX_BASIC_STATS;
        return err;
 }
index 9dae2ec7e1fa89705f649b1c3349520b8bb23543..ac9b53b893650270b80ccf5a69a954e55346922f 100644 (file)
@@ -237,15 +237,6 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
        spin_lock(&ci->i_ceph_lock);
        if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) {
                err = -EIO;
-       } else if (op == CEPH_MDS_OP_SETFILELOCK) {
-               /*
-                * increasing i_filelock_ref closes race window between
-                * handling request reply and adding file_lock struct to
-                * inode. Otherwise, i_auth_cap may get trimmed in the
-                * window. Caller function will decrease the counter.
-                */
-               fl->fl_ops = &ceph_fl_lock_ops;
-               atomic_inc(&ci->i_filelock_ref);
        }
        spin_unlock(&ci->i_ceph_lock);
        if (err < 0) {
@@ -299,10 +290,6 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
        spin_lock(&ci->i_ceph_lock);
        if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) {
                err = -EIO;
-       } else {
-               /* see comment in ceph_lock */
-               fl->fl_ops = &ceph_fl_lock_ops;
-               atomic_inc(&ci->i_filelock_ref);
        }
        spin_unlock(&ci->i_ceph_lock);
        if (err < 0) {
index 9049c2a3e972f499ea1371e8c4b8112ead98a6e3..959b1bf7c327d0e66454b570c31c36db076cfa0a 100644 (file)
@@ -550,15 +550,9 @@ void ceph_put_mds_session(struct ceph_mds_session *s)
 struct ceph_mds_session *__ceph_lookup_mds_session(struct ceph_mds_client *mdsc,
                                                   int mds)
 {
-       struct ceph_mds_session *session;
-
        if (mds >= mdsc->max_sessions || !mdsc->sessions[mds])
                return NULL;
-       session = mdsc->sessions[mds];
-       dout("lookup_mds_session %p %d\n", session,
-            refcount_read(&session->s_ref));
-       get_session(session);
-       return session;
+       return get_session(mdsc->sessions[mds]);
 }
 
 static bool __have_session(struct ceph_mds_client *mdsc, int mds)
@@ -1284,9 +1278,9 @@ static void cleanup_session_requests(struct ceph_mds_client *mdsc,
  *
  * Caller must hold session s_mutex.
  */
-static int iterate_session_caps(struct ceph_mds_session *session,
-                                int (*cb)(struct inode *, struct ceph_cap *,
-                                           void *), void *arg)
+int ceph_iterate_session_caps(struct ceph_mds_session *session,
+                             int (*cb)(struct inode *, struct ceph_cap *,
+                                       void *), void *arg)
 {
        struct list_head *p;
        struct ceph_cap *cap;
@@ -1451,7 +1445,7 @@ static void remove_session_caps(struct ceph_mds_session *session)
        LIST_HEAD(dispose);
 
        dout("remove_session_caps on %p\n", session);
-       iterate_session_caps(session, remove_session_caps_cb, fsc);
+       ceph_iterate_session_caps(session, remove_session_caps_cb, fsc);
 
        wake_up_all(&fsc->mdsc->cap_flushing_wq);
 
@@ -1534,8 +1528,8 @@ static int wake_up_session_cb(struct inode *inode, struct ceph_cap *cap,
 static void wake_up_session_caps(struct ceph_mds_session *session, int ev)
 {
        dout("wake_up_session_caps %p mds%d\n", session, session->s_mds);
-       iterate_session_caps(session, wake_up_session_cb,
-                            (void *)(unsigned long)ev);
+       ceph_iterate_session_caps(session, wake_up_session_cb,
+                                 (void *)(unsigned long)ev);
 }
 
 /*
@@ -1768,7 +1762,7 @@ int ceph_trim_caps(struct ceph_mds_client *mdsc,
             session->s_mds, session->s_nr_caps, max_caps, trim_caps);
        if (trim_caps > 0) {
                session->s_trim_caps = trim_caps;
-               iterate_session_caps(session, trim_caps_cb, session);
+               ceph_iterate_session_caps(session, trim_caps_cb, session);
                dout("trim_caps mds%d done: %d / %d, trimmed %d\n",
                     session->s_mds, session->s_nr_caps, max_caps,
                        trim_caps - session->s_trim_caps);
@@ -1861,7 +1855,8 @@ again:
                num_cap_releases--;
 
                head = msg->front.iov_base;
-               le32_add_cpu(&head->num, 1);
+               put_unaligned_le32(get_unaligned_le32(&head->num) + 1,
+                                  &head->num);
                item = msg->front.iov_base + msg->front.iov_len;
                item->ino = cpu_to_le64(cap->cap_ino);
                item->cap_id = cpu_to_le64(cap->cap_id);
@@ -2089,43 +2084,29 @@ static inline  u64 __get_oldest_tid(struct ceph_mds_client *mdsc)
  * Encode hidden .snap dirs as a double /, i.e.
  *   foo/.snap/bar -> foo//bar
  */
-char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
+char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase,
                           int stop_on_nosnap)
 {
        struct dentry *temp;
        char *path;
-       int len, pos;
+       int pos;
        unsigned seq;
+       u64 base;
 
        if (!dentry)
                return ERR_PTR(-EINVAL);
 
-retry:
-       len = 0;
-       seq = read_seqbegin(&rename_lock);
-       rcu_read_lock();
-       for (temp = dentry; !IS_ROOT(temp);) {
-               struct inode *inode = d_inode(temp);
-               if (inode && ceph_snap(inode) == CEPH_SNAPDIR)
-                       len++;  /* slash only */
-               else if (stop_on_nosnap && inode &&
-                        ceph_snap(inode) == CEPH_NOSNAP)
-                       break;
-               else
-                       len += 1 + temp->d_name.len;
-               temp = temp->d_parent;
-       }
-       rcu_read_unlock();
-       if (len)
-               len--;  /* no leading '/' */
-
-       path = kmalloc(len+1, GFP_NOFS);
+       path = __getname();
        if (!path)
                return ERR_PTR(-ENOMEM);
-       pos = len;
-       path[pos] = 0;  /* trailing null */
+retry:
+       pos = PATH_MAX - 1;
+       path[pos] = '\0';
+
+       seq = read_seqbegin(&rename_lock);
        rcu_read_lock();
-       for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) {
+       temp = dentry;
+       for (;;) {
                struct inode *inode;
 
                spin_lock(&temp->d_lock);
@@ -2143,83 +2124,54 @@ retry:
                                spin_unlock(&temp->d_lock);
                                break;
                        }
-                       strncpy(path + pos, temp->d_name.name,
-                               temp->d_name.len);
+                       memcpy(path + pos, temp->d_name.name, temp->d_name.len);
                }
                spin_unlock(&temp->d_lock);
-               if (pos)
-                       path[--pos] = '/';
                temp = temp->d_parent;
+
+               /* Are we at the root? */
+               if (IS_ROOT(temp))
+                       break;
+
+               /* Are we out of buffer? */
+               if (--pos < 0)
+                       break;
+
+               path[pos] = '/';
        }
+       base = ceph_ino(d_inode(temp));
        rcu_read_unlock();
-       if (pos != 0 || read_seqretry(&rename_lock, seq)) {
+       if (pos < 0 || read_seqretry(&rename_lock, seq)) {
                pr_err("build_path did not end path lookup where "
-                      "expected, namelen is %d, pos is %d\n", len, pos);
+                      "expected, pos is %d\n", pos);
                /* presumably this is only possible if racing with a
                   rename of one of the parent directories (we can not
                   lock the dentries above us to prevent this, but
                   retrying should be harmless) */
-               kfree(path);
                goto retry;
        }
 
-       *base = ceph_ino(d_inode(temp));
-       *plen = len;
+       *pbase = base;
+       *plen = PATH_MAX - 1 - pos;
        dout("build_path on %p %d built %llx '%.*s'\n",
-            dentry, d_count(dentry), *base, len, path);
-       return path;
-}
-
-/* Duplicate the dentry->d_name.name safely */
-static int clone_dentry_name(struct dentry *dentry, const char **ppath,
-                            int *ppathlen)
-{
-       u32 len;
-       char *name;
-
-retry:
-       len = READ_ONCE(dentry->d_name.len);
-       name = kmalloc(len + 1, GFP_NOFS);
-       if (!name)
-               return -ENOMEM;
-
-       spin_lock(&dentry->d_lock);
-       if (dentry->d_name.len != len) {
-               spin_unlock(&dentry->d_lock);
-               kfree(name);
-               goto retry;
-       }
-       memcpy(name, dentry->d_name.name, len);
-       spin_unlock(&dentry->d_lock);
-
-       name[len] = '\0';
-       *ppath = name;
-       *ppathlen = len;
-       return 0;
+            dentry, d_count(dentry), base, *plen, path + pos);
+       return path + pos;
 }
 
 static int build_dentry_path(struct dentry *dentry, struct inode *dir,
                             const char **ppath, int *ppathlen, u64 *pino,
                             bool *pfreepath, bool parent_locked)
 {
-       int ret;
        char *path;
 
        rcu_read_lock();
        if (!dir)
                dir = d_inode_rcu(dentry->d_parent);
-       if (dir && ceph_snap(dir) == CEPH_NOSNAP) {
+       if (dir && parent_locked && ceph_snap(dir) == CEPH_NOSNAP) {
                *pino = ceph_ino(dir);
                rcu_read_unlock();
-               if (parent_locked) {
-                       *ppath = dentry->d_name.name;
-                       *ppathlen = dentry->d_name.len;
-               } else {
-                       ret = clone_dentry_name(dentry, ppath, ppathlen);
-                       if (ret)
-                               return ret;
-                       *pfreepath = true;
-               }
+               *ppath = dentry->d_name.name;
+               *ppathlen = dentry->d_name.len;
                return 0;
        }
        rcu_read_unlock();
@@ -2331,9 +2283,9 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
                (!!req->r_inode_drop + !!req->r_dentry_drop +
                 !!req->r_old_inode_drop + !!req->r_old_dentry_drop);
        if (req->r_dentry_drop)
-               len += req->r_dentry->d_name.len;
+               len += pathlen1;
        if (req->r_old_dentry_drop)
-               len += req->r_old_dentry->d_name.len;
+               len += pathlen2;
 
        msg = ceph_msg_new2(CEPH_MSG_CLIENT_REQUEST, len, 1, GFP_NOFS, false);
        if (!msg) {
@@ -2410,10 +2362,10 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
 
 out_free2:
        if (freepath2)
-               kfree((char *)path2);
+               ceph_mdsc_free_path((char *)path2, pathlen2);
 out_free1:
        if (freepath1)
-               kfree((char *)path1);
+               ceph_mdsc_free_path((char *)path1, pathlen1);
 out:
        return msg;
 }
@@ -2427,8 +2379,7 @@ static void complete_request(struct ceph_mds_client *mdsc,
 {
        if (req->r_callback)
                req->r_callback(mdsc, req);
-       else
-               complete_all(&req->r_completion);
+       complete_all(&req->r_completion);
 }
 
 /*
@@ -2670,28 +2621,11 @@ static void kick_requests(struct ceph_mds_client *mdsc, int mds)
        }
 }
 
-void ceph_mdsc_submit_request(struct ceph_mds_client *mdsc,
+int ceph_mdsc_submit_request(struct ceph_mds_client *mdsc, struct inode *dir,
                              struct ceph_mds_request *req)
-{
-       dout("submit_request on %p\n", req);
-       mutex_lock(&mdsc->mutex);
-       __register_request(mdsc, req, NULL);
-       __do_request(mdsc, req);
-       mutex_unlock(&mdsc->mutex);
-}
-
-/*
- * Synchrously perform an mds request.  Take care of all of the
- * session setup, forwarding, retry details.
- */
-int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
-                        struct inode *dir,
-                        struct ceph_mds_request *req)
 {
        int err;
 
-       dout("do_request on %p\n", req);
-
        /* take CAP_PIN refs for r_inode, r_parent, r_old_dentry */
        if (req->r_inode)
                ceph_get_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN);
@@ -2701,18 +2635,21 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
                ceph_get_cap_refs(ceph_inode(req->r_old_dentry_dir),
                                  CEPH_CAP_PIN);
 
-       /* issue */
+       dout("submit_request on %p for inode %p\n", req, dir);
        mutex_lock(&mdsc->mutex);
        __register_request(mdsc, req, dir);
        __do_request(mdsc, req);
+       err = req->r_err;
+       mutex_unlock(&mdsc->mutex);
+       return err;
+}
 
-       if (req->r_err) {
-               err = req->r_err;
-               goto out;
-       }
+static int ceph_mdsc_wait_request(struct ceph_mds_client *mdsc,
+                                 struct ceph_mds_request *req)
+{
+       int err;
 
        /* wait */
-       mutex_unlock(&mdsc->mutex);
        dout("do_request waiting\n");
        if (!req->r_timeout && req->r_wait_for_completion) {
                err = req->r_wait_for_completion(mdsc, req);
@@ -2753,8 +2690,26 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
                err = req->r_err;
        }
 
-out:
        mutex_unlock(&mdsc->mutex);
+       return err;
+}
+
+/*
+ * Synchrously perform an mds request.  Take care of all of the
+ * session setup, forwarding, retry details.
+ */
+int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
+                        struct inode *dir,
+                        struct ceph_mds_request *req)
+{
+       int err;
+
+       dout("do_request on %p\n", req);
+
+       /* issue */
+       err = ceph_mdsc_submit_request(mdsc, dir, req);
+       if (!err)
+               err = ceph_mdsc_wait_request(mdsc, req);
        dout("do_request %p done, result %d\n", req, err);
        return err;
 }
@@ -3485,7 +3440,7 @@ out_freeflocks:
                ceph_pagelist_encode_string(pagelist, path, pathlen);
                ceph_pagelist_append(pagelist, &rec, sizeof(rec.v1));
 out_freepath:
-               kfree(path);
+               ceph_mdsc_free_path(path, pathlen);
        }
 
 out_err:
@@ -3642,7 +3597,7 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
                recon_state.msg_version = 2;
        }
        /* trsaverse this session's caps */
-       err = iterate_session_caps(session, encode_caps_cb, &recon_state);
+       err = ceph_iterate_session_caps(session, encode_caps_cb, &recon_state);
 
        spin_lock(&session->s_cap_lock);
        session->s_cap_reconnect = 0;
@@ -4125,6 +4080,8 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
        mdsc->max_sessions = 0;
        mdsc->stopping = 0;
        atomic64_set(&mdsc->quotarealms_count, 0);
+       mdsc->quotarealms_inodes = RB_ROOT;
+       mutex_init(&mdsc->quotarealms_inodes_mutex);
        mdsc->last_snap_seq = 0;
        init_rwsem(&mdsc->snap_rwsem);
        mdsc->snap_realms = RB_ROOT;
@@ -4216,6 +4173,8 @@ void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc)
         * their inode/dcache refs
         */
        ceph_msgr_flush();
+
+       ceph_cleanup_quotarealms_inodes(mdsc);
 }
 
 /*
index 50385a481fdbb9b2764257ddec68cc5acb4a9ff3..a83f28bc23870ee1c65c7ac50d265c52e8f2a08a 100644 (file)
@@ -325,6 +325,18 @@ struct ceph_snapid_map {
        unsigned long last_used;
 };
 
+/*
+ * node for list of quotarealm inodes that are not visible from the filesystem
+ * mountpoint, but required to handle, e.g. quotas.
+ */
+struct ceph_quotarealm_inode {
+       struct rb_node node;
+       u64 ino;
+       unsigned long timeout; /* last time a lookup failed for this inode */
+       struct mutex mutex;
+       struct inode *inode;
+};
+
 /*
  * mds client state
  */
@@ -344,6 +356,12 @@ struct ceph_mds_client {
        int                     stopping;      /* true if shutting down */
 
        atomic64_t              quotarealms_count; /* # realms with quota */
+       /*
+        * We keep a list of inodes we don't see in the mountpoint but that we
+        * need to track quota realms.
+        */
+       struct rb_root          quotarealms_inodes;
+       struct mutex            quotarealms_inodes_mutex;
 
        /*
         * snap_rwsem will cover cap linkage into snaprealms, and
@@ -447,8 +465,9 @@ extern int ceph_alloc_readdir_reply_buffer(struct ceph_mds_request *req,
                                           struct inode *dir);
 extern struct ceph_mds_request *
 ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode);
-extern void ceph_mdsc_submit_request(struct ceph_mds_client *mdsc,
-                                    struct ceph_mds_request *req);
+extern int ceph_mdsc_submit_request(struct ceph_mds_client *mdsc,
+                                   struct inode *dir,
+                                   struct ceph_mds_request *req);
 extern int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
                                struct inode *dir,
                                struct ceph_mds_request *req);
@@ -468,8 +487,18 @@ extern void ceph_flush_cap_releases(struct ceph_mds_client *mdsc,
                                    struct ceph_mds_session *session);
 extern void ceph_queue_cap_reclaim_work(struct ceph_mds_client *mdsc);
 extern void ceph_reclaim_caps_nr(struct ceph_mds_client *mdsc, int nr);
+extern int ceph_iterate_session_caps(struct ceph_mds_session *session,
+                                    int (*cb)(struct inode *,
+                                              struct ceph_cap *, void *),
+                                    void *arg);
 extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc);
 
+static inline void ceph_mdsc_free_path(char *path, int len)
+{
+       if (path)
+               __putname(path - (PATH_MAX - 1 - len));
+}
+
 extern char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
                                  int stop_on_nosnap);
 
index 1a2c5d390f7f184705b3bde1f68f36074b6bf39e..701b4fb0fb5a4cd576880139ca2e183dc0b39e98 100644 (file)
@@ -205,7 +205,7 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end)
 
                dout("mdsmap_decode %d/%d %lld mds%d.%d %s %s\n",
                     i+1, n, global_id, mds, inc,
-                    ceph_pr_addr(&addr.in_addr),
+                    ceph_pr_addr(&addr),
                     ceph_mds_state_name(state));
 
                if (mds < 0 || state <= 0)
index 9455d3aef0c3c1b50f5be96e3a804424e55597b4..c4522212872c9fe5f5a3dd4515b19e688cce805a 100644 (file)
@@ -22,7 +22,16 @@ void ceph_adjust_quota_realms_count(struct inode *inode, bool inc)
 static inline bool ceph_has_realms_with_quotas(struct inode *inode)
 {
        struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
-       return atomic64_read(&mdsc->quotarealms_count) > 0;
+       struct super_block *sb = mdsc->fsc->sb;
+
+       if (atomic64_read(&mdsc->quotarealms_count) > 0)
+               return true;
+       /* if root is the real CephFS root, we don't have quota realms */
+       if (sb->s_root->d_inode &&
+           (sb->s_root->d_inode->i_ino == CEPH_INO_ROOT))
+               return false;
+       /* otherwise, we can't know for sure */
+       return true;
 }
 
 void ceph_handle_quota(struct ceph_mds_client *mdsc,
@@ -68,6 +77,108 @@ void ceph_handle_quota(struct ceph_mds_client *mdsc,
        iput(inode);
 }
 
+static struct ceph_quotarealm_inode *
+find_quotarealm_inode(struct ceph_mds_client *mdsc, u64 ino)
+{
+       struct ceph_quotarealm_inode *qri = NULL;
+       struct rb_node **node, *parent = NULL;
+
+       mutex_lock(&mdsc->quotarealms_inodes_mutex);
+       node = &(mdsc->quotarealms_inodes.rb_node);
+       while (*node) {
+               parent = *node;
+               qri = container_of(*node, struct ceph_quotarealm_inode, node);
+
+               if (ino < qri->ino)
+                       node = &((*node)->rb_left);
+               else if (ino > qri->ino)
+                       node = &((*node)->rb_right);
+               else
+                       break;
+       }
+       if (!qri || (qri->ino != ino)) {
+               /* Not found, create a new one and insert it */
+               qri = kmalloc(sizeof(*qri), GFP_KERNEL);
+               if (qri) {
+                       qri->ino = ino;
+                       qri->inode = NULL;
+                       qri->timeout = 0;
+                       mutex_init(&qri->mutex);
+                       rb_link_node(&qri->node, parent, node);
+                       rb_insert_color(&qri->node, &mdsc->quotarealms_inodes);
+               } else
+                       pr_warn("Failed to alloc quotarealms_inode\n");
+       }
+       mutex_unlock(&mdsc->quotarealms_inodes_mutex);
+
+       return qri;
+}
+
+/*
+ * This function will try to lookup a realm inode which isn't visible in the
+ * filesystem mountpoint.  A list of these kind of inodes (not visible) is
+ * maintained in the mdsc and freed only when the filesystem is umounted.
+ *
+ * Note that these inodes are kept in this list even if the lookup fails, which
+ * allows to prevent useless lookup requests.
+ */
+static struct inode *lookup_quotarealm_inode(struct ceph_mds_client *mdsc,
+                                            struct super_block *sb,
+                                            struct ceph_snap_realm *realm)
+{
+       struct ceph_quotarealm_inode *qri;
+       struct inode *in;
+
+       qri = find_quotarealm_inode(mdsc, realm->ino);
+       if (!qri)
+               return NULL;
+
+       mutex_lock(&qri->mutex);
+       if (qri->inode) {
+               /* A request has already returned the inode */
+               mutex_unlock(&qri->mutex);
+               return qri->inode;
+       }
+       /* Check if this inode lookup has failed recently */
+       if (qri->timeout &&
+           time_before_eq(jiffies, qri->timeout)) {
+               mutex_unlock(&qri->mutex);
+               return NULL;
+       }
+       in = ceph_lookup_inode(sb, realm->ino);
+       if (IS_ERR(in)) {
+               pr_warn("Can't lookup inode %llx (err: %ld)\n",
+                       realm->ino, PTR_ERR(in));
+               qri->timeout = jiffies + msecs_to_jiffies(60 * 1000); /* XXX */
+       } else {
+               qri->timeout = 0;
+               qri->inode = in;
+       }
+       mutex_unlock(&qri->mutex);
+
+       return in;
+}
+
+void ceph_cleanup_quotarealms_inodes(struct ceph_mds_client *mdsc)
+{
+       struct ceph_quotarealm_inode *qri;
+       struct rb_node *node;
+
+       /*
+        * It should now be safe to clean quotarealms_inode tree without holding
+        * mdsc->quotarealms_inodes_mutex...
+        */
+       mutex_lock(&mdsc->quotarealms_inodes_mutex);
+       while (!RB_EMPTY_ROOT(&mdsc->quotarealms_inodes)) {
+               node = rb_first(&mdsc->quotarealms_inodes);
+               qri = rb_entry(node, struct ceph_quotarealm_inode, node);
+               rb_erase(node, &mdsc->quotarealms_inodes);
+               iput(qri->inode);
+               kfree(qri);
+       }
+       mutex_unlock(&mdsc->quotarealms_inodes_mutex);
+}
+
 /*
  * This function walks through the snaprealm for an inode and returns the
  * ceph_snap_realm for the first snaprealm that has quotas set (either max_files
@@ -76,9 +187,15 @@ void ceph_handle_quota(struct ceph_mds_client *mdsc,
  *
  * Note that the caller is responsible for calling ceph_put_snap_realm() on the
  * returned realm.
+ *
+ * Callers of this function need to hold mdsc->snap_rwsem.  However, if there's
+ * a need to do an inode lookup, this rwsem will be temporarily dropped.  Hence
+ * the 'retry' argument: if rwsem needs to be dropped and 'retry' is 'false'
+ * this function will return -EAGAIN; otherwise, the snaprealms walk-through
+ * will be restarted.
  */
 static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
-                                              struct inode *inode)
+                                              struct inode *inode, bool retry)
 {
        struct ceph_inode_info *ci = NULL;
        struct ceph_snap_realm *realm, *next;
@@ -88,6 +205,7 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
        if (ceph_snap(inode) != CEPH_NOSNAP)
                return NULL;
 
+restart:
        realm = ceph_inode(inode)->i_snap_realm;
        if (realm)
                ceph_get_snap_realm(mdsc, realm);
@@ -95,11 +213,25 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
                pr_err_ratelimited("get_quota_realm: ino (%llx.%llx) "
                                   "null i_snap_realm\n", ceph_vinop(inode));
        while (realm) {
+               bool has_inode;
+
                spin_lock(&realm->inodes_with_caps_lock);
-               in = realm->inode ? igrab(realm->inode) : NULL;
+               has_inode = realm->inode;
+               in = has_inode ? igrab(realm->inode) : NULL;
                spin_unlock(&realm->inodes_with_caps_lock);
-               if (!in)
+               if (has_inode && !in)
                        break;
+               if (!in) {
+                       up_read(&mdsc->snap_rwsem);
+                       in = lookup_quotarealm_inode(mdsc, inode->i_sb, realm);
+                       down_read(&mdsc->snap_rwsem);
+                       if (IS_ERR_OR_NULL(in))
+                               break;
+                       ceph_put_snap_realm(mdsc, realm);
+                       if (!retry)
+                               return ERR_PTR(-EAGAIN);
+                       goto restart;
+               }
 
                ci = ceph_inode(in);
                has_quota = __ceph_has_any_quota(ci);
@@ -125,9 +257,22 @@ bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
        struct ceph_snap_realm *old_realm, *new_realm;
        bool is_same;
 
+restart:
+       /*
+        * We need to lookup 2 quota realms atomically, i.e. with snap_rwsem.
+        * However, get_quota_realm may drop it temporarily.  By setting the
+        * 'retry' parameter to 'false', we'll get -EAGAIN if the rwsem was
+        * dropped and we can then restart the whole operation.
+        */
        down_read(&mdsc->snap_rwsem);
-       old_realm = get_quota_realm(mdsc, old);
-       new_realm = get_quota_realm(mdsc, new);
+       old_realm = get_quota_realm(mdsc, old, true);
+       new_realm = get_quota_realm(mdsc, new, false);
+       if (PTR_ERR(new_realm) == -EAGAIN) {
+               up_read(&mdsc->snap_rwsem);
+               if (old_realm)
+                       ceph_put_snap_realm(mdsc, old_realm);
+               goto restart;
+       }
        is_same = (old_realm == new_realm);
        up_read(&mdsc->snap_rwsem);
 
@@ -166,6 +311,7 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op,
                return false;
 
        down_read(&mdsc->snap_rwsem);
+restart:
        realm = ceph_inode(inode)->i_snap_realm;
        if (realm)
                ceph_get_snap_realm(mdsc, realm);
@@ -173,12 +319,23 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op,
                pr_err_ratelimited("check_quota_exceeded: ino (%llx.%llx) "
                                   "null i_snap_realm\n", ceph_vinop(inode));
        while (realm) {
+               bool has_inode;
+
                spin_lock(&realm->inodes_with_caps_lock);
-               in = realm->inode ? igrab(realm->inode) : NULL;
+               has_inode = realm->inode;
+               in = has_inode ? igrab(realm->inode) : NULL;
                spin_unlock(&realm->inodes_with_caps_lock);
-               if (!in)
+               if (has_inode && !in)
                        break;
-
+               if (!in) {
+                       up_read(&mdsc->snap_rwsem);
+                       in = lookup_quotarealm_inode(mdsc, inode->i_sb, realm);
+                       down_read(&mdsc->snap_rwsem);
+                       if (IS_ERR_OR_NULL(in))
+                               break;
+                       ceph_put_snap_realm(mdsc, realm);
+                       goto restart;
+               }
                ci = ceph_inode(in);
                spin_lock(&ci->i_ceph_lock);
                if (op == QUOTA_CHECK_MAX_FILES_OP) {
@@ -314,7 +471,7 @@ bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf)
        bool is_updated = false;
 
        down_read(&mdsc->snap_rwsem);
-       realm = get_quota_realm(mdsc, d_inode(fsc->sb->s_root));
+       realm = get_quota_realm(mdsc, d_inode(fsc->sb->s_root), true);
        up_read(&mdsc->snap_rwsem);
        if (!realm)
                return false;
index 285edda4fc3b4ec122975062f09d6497e41a0cbe..c864b44c8341d4ec211175d9efe0c75905067e14 100644 (file)
@@ -845,6 +845,12 @@ static void ceph_umount_begin(struct super_block *sb)
        return;
 }
 
+static int ceph_remount(struct super_block *sb, int *flags, char *data)
+{
+       sync_filesystem(sb);
+       return 0;
+}
+
 static const struct super_operations ceph_super_ops = {
        .alloc_inode    = ceph_alloc_inode,
        .destroy_inode  = ceph_destroy_inode,
@@ -853,6 +859,7 @@ static const struct super_operations ceph_super_ops = {
        .drop_inode     = ceph_drop_inode,
        .sync_fs        = ceph_sync_fs,
        .put_super      = ceph_put_super,
+       .remount_fs     = ceph_remount,
        .show_options   = ceph_show_options,
        .statfs         = ceph_statfs,
        .umount_begin   = ceph_umount_begin,
index c5b4a05905c01f7ce738a7123fe6db23945c2c7e..6edab9a750f8a00211f7ccf2aa659982c684330a 100644 (file)
@@ -1083,6 +1083,7 @@ extern long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 
 /* export.c */
 extern const struct export_operations ceph_export_ops;
+struct inode *ceph_lookup_inode(struct super_block *sb, u64 ino);
 
 /* locks.c */
 extern __init void ceph_flock_init(void);
@@ -1133,5 +1134,6 @@ extern bool ceph_quota_is_max_bytes_approaching(struct inode *inode,
                                                loff_t newlen);
 extern bool ceph_quota_update_statfs(struct ceph_fs_client *fsc,
                                     struct kstatfs *buf);
+extern void ceph_cleanup_quotarealms_inodes(struct ceph_mds_client *mdsc);
 
 #endif /* _FS_CEPH_SUPER_H */
index 7ede7306599f47449bdd02533db47bfede2c81df..1e21b2528cfb3e8397db38ab0d927ef047ab3e37 100644 (file)
@@ -77,7 +77,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
                goto name_is_IP_address;
 
        /* Perform the upcall */
-       rc = dns_query(NULL, hostname, len, NULL, ip_addr, NULL);
+       rc = dns_query(NULL, hostname, len, NULL, ip_addr, NULL, false);
        if (rc < 0)
                cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n",
                         __func__, len, len, hostname);
index c5234c21b539405a452417ce4d9cb9e977186637..f2bb7985d21c22e9973bcfb09080ee8c68e3ecef 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/device.h>
 #include <linux/pid_namespace.h>
 #include <asm/io.h>
-#include <linux/poll.h>
 #include <linux/uaccess.h>
 
 #include <linux/coda.h>
index 591e82ba443cd36bae59cb621acd2fad178d23ac..5e7932d668ab74b87e063af86694ff4de3cdc924 100644 (file)
@@ -1757,12 +1757,19 @@ int configfs_register_group(struct config_group *parent_group,
 
        inode_lock_nested(d_inode(parent), I_MUTEX_PARENT);
        ret = create_default_group(parent_group, group);
-       if (!ret) {
-               spin_lock(&configfs_dirent_lock);
-               configfs_dir_set_ready(group->cg_item.ci_dentry->d_fsdata);
-               spin_unlock(&configfs_dirent_lock);
-       }
+       if (ret)
+               goto err_out;
+
+       spin_lock(&configfs_dirent_lock);
+       configfs_dir_set_ready(group->cg_item.ci_dentry->d_fsdata);
+       spin_unlock(&configfs_dirent_lock);
+       inode_unlock(d_inode(parent));
+       return 0;
+err_out:
        inode_unlock(d_inode(parent));
+       mutex_lock(&subsys->su_mutex);
+       unlink_group(group);
+       mutex_unlock(&subsys->su_mutex);
        return ret;
 }
 EXPORT_SYMBOL(configfs_register_group);
index e5e54da1715f630cf1471e625e72045b6f31e112..f74386293632da785edab5cbd699d5bd15c1ecdb 100644 (file)
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -814,7 +814,7 @@ static void dax_entry_mkclean(struct address_space *mapping, pgoff_t index,
                                goto unlock_pmd;
 
                        flush_cache_page(vma, address, pfn);
-                       pmd = pmdp_huge_clear_flush(vma, address, pmdp);
+                       pmd = pmdp_invalidate(vma, address, pmdp);
                        pmd = pmd_wrprotect(pmd);
                        pmd = pmd_mkclean(pmd);
                        set_pmd_at(vma->vm_mm, address, pmdp, pmd);
@@ -1575,8 +1575,7 @@ static vm_fault_t dax_iomap_pmd_fault(struct vm_fault *vmf, pfn_t *pfnp,
                }
 
                trace_dax_pmd_insert_mapping(inode, vmf, PMD_SIZE, pfn, entry);
-               result = vmf_insert_pfn_pmd(vma, vmf->address, vmf->pmd, pfn,
-                                           write);
+               result = vmf_insert_pfn_pmd(vmf, pfn, write);
                break;
        case IOMAP_UNWRITTEN:
        case IOMAP_HOLE:
@@ -1686,8 +1685,7 @@ dax_insert_pfn_mkwrite(struct vm_fault *vmf, pfn_t pfn, unsigned int order)
                ret = vmf_insert_mixed_mkwrite(vmf->vma, vmf->address, pfn);
 #ifdef CONFIG_FS_DAX_PMD
        else if (order == PMD_ORDER)
-               ret = vmf_insert_pfn_pmd(vmf->vma, vmf->address, vmf->pmd,
-                       pfn, true);
+               ret = vmf_insert_pfn_pmd(vmf, pfn, FAULT_FLAG_WRITE);
 #endif
        else
                ret = VM_FAULT_FALLBACK;
index 08d3bd602f73d8f219ee1f259c0cbaa839245c56..93b1fa7bb2984a88be622f97a7c462b25c8871c0 100644 (file)
@@ -21,6 +21,9 @@
 #include <linux/eventfd.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/idr.h>
+
+static DEFINE_IDA(eventfd_ida);
 
 struct eventfd_ctx {
        struct kref kref;
@@ -35,6 +38,7 @@ struct eventfd_ctx {
         */
        __u64 count;
        unsigned int flags;
+       int id;
 };
 
 /**
@@ -69,6 +73,8 @@ EXPORT_SYMBOL_GPL(eventfd_signal);
 
 static void eventfd_free_ctx(struct eventfd_ctx *ctx)
 {
+       if (ctx->id >= 0)
+               ida_simple_remove(&eventfd_ida, ctx->id);
        kfree(ctx);
 }
 
@@ -297,6 +303,7 @@ static void eventfd_show_fdinfo(struct seq_file *m, struct file *f)
        seq_printf(m, "eventfd-count: %16llx\n",
                   (unsigned long long)ctx->count);
        spin_unlock_irq(&ctx->wqh.lock);
+       seq_printf(m, "eventfd-id: %d\n", ctx->id);
 }
 #endif
 
@@ -400,6 +407,7 @@ static int do_eventfd(unsigned int count, int flags)
        init_waitqueue_head(&ctx->wqh);
        ctx->count = count;
        ctx->flags = flags;
+       ctx->id = ida_simple_get(&eventfd_ida, 0, 0, GFP_KERNEL);
 
        fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx,
                              O_RDWR | (flags & EFD_SHARED_FCNTL_FLAGS));
index 2e0033348d8e10c02a5c3928caec876798edb1fd..d88584ebf07f310a89ceef07e3ead8351e6931fd 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1652,11 +1652,13 @@ int search_binary_handler(struct linux_binprm *bprm)
                if (!try_module_get(fmt->module))
                        continue;
                read_unlock(&binfmt_lock);
+
                bprm->recursion_depth++;
                retval = fmt->load_binary(bprm);
+               bprm->recursion_depth--;
+
                read_lock(&binfmt_lock);
                put_binfmt(fmt);
-               bprm->recursion_depth--;
                if (retval < 0 && !bprm->mm) {
                        /* we got to flush_old_exec() and failed after it */
                        read_unlock(&binfmt_lock);
index c27c27300d95894c9de2ae0614e36c3df11bad47..e474127dd255605df4ab498997111ac1cf63fafa 100644 (file)
@@ -451,7 +451,9 @@ failed_out:
 /**
  *     ext2_alloc_branch - allocate and set up a chain of blocks.
  *     @inode: owner
- *     @num: depth of the chain (number of blocks to allocate)
+ *     @indirect_blks: depth of the chain (number of blocks to allocate)
+ *     @blks: number of allocated direct blocks
+ *     @goal: preferred place for allocation
  *     @offsets: offsets (in the blocks) to store the pointers to next.
  *     @branch: place to store the chain in.
  *
index 63e599524085bbd8a83447cacd759fb42f885490..217b290ae3a5520c120e9e2226e4da195f76f3b0 100644 (file)
@@ -285,7 +285,7 @@ static int f2fs_acl_create_masq(struct posix_acl *acl, umode_t *mode_p)
        /* assert(atomic_read(acl->a_refcount) == 1); */
 
        FOREACH_ACL_ENTRY(pa, acl, pe) {
-               switch(pa->e_tag) {
+               switch (pa->e_tag) {
                case ACL_USER_OBJ:
                        pa->e_perm &= (mode >> 6) | ~S_IRWXO;
                        mode &= (pa->e_perm << 6) | ~S_IRWXU;
@@ -326,7 +326,7 @@ static int f2fs_acl_create_masq(struct posix_acl *acl, umode_t *mode_p)
        }
 
        *mode_p = (*mode_p & ~S_IRWXUGO) | mode;
-        return not_equiv;
+       return not_equiv;
 }
 
 static int f2fs_acl_create(struct inode *dir, umode_t *mode,
index a98e1b02279ea1cb85fde3744206e9228f9d3783..ed70b68b2b382c6886645dcb5ce301b573e7f5f0 100644 (file)
@@ -66,7 +66,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index,
                .old_blkaddr = index,
                .new_blkaddr = index,
                .encrypted_page = NULL,
-               .is_meta = is_meta,
+               .is_por = !is_meta,
        };
        int err;
 
@@ -130,6 +130,30 @@ struct page *f2fs_get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index)
        return __get_meta_page(sbi, index, false);
 }
 
+static bool __is_bitmap_valid(struct f2fs_sb_info *sbi, block_t blkaddr,
+                                                       int type)
+{
+       struct seg_entry *se;
+       unsigned int segno, offset;
+       bool exist;
+
+       if (type != DATA_GENERIC_ENHANCE && type != DATA_GENERIC_ENHANCE_READ)
+               return true;
+
+       segno = GET_SEGNO(sbi, blkaddr);
+       offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr);
+       se = get_seg_entry(sbi, segno);
+
+       exist = f2fs_test_bit(offset, se->cur_valid_map);
+       if (!exist && type == DATA_GENERIC_ENHANCE) {
+               f2fs_msg(sbi->sb, KERN_ERR, "Inconsistent error "
+                       "blkaddr:%u, sit bitmap:%d", blkaddr, exist);
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+               WARN_ON(1);
+       }
+       return exist;
+}
+
 bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
                                        block_t blkaddr, int type)
 {
@@ -151,15 +175,22 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
                        return false;
                break;
        case META_POR:
+               if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
+                       blkaddr < MAIN_BLKADDR(sbi)))
+                       return false;
+               break;
        case DATA_GENERIC:
+       case DATA_GENERIC_ENHANCE:
+       case DATA_GENERIC_ENHANCE_READ:
                if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
-                       blkaddr < MAIN_BLKADDR(sbi))) {
-                       if (type == DATA_GENERIC) {
-                               f2fs_msg(sbi->sb, KERN_WARNING,
-                                       "access invalid blkaddr:%u", blkaddr);
-                               WARN_ON(1);
-                       }
+                               blkaddr < MAIN_BLKADDR(sbi))) {
+                       f2fs_msg(sbi->sb, KERN_WARNING,
+                               "access invalid blkaddr:%u", blkaddr);
+                       set_sbi_flag(sbi, SBI_NEED_FSCK);
+                       WARN_ON(1);
                        return false;
+               } else {
+                       return __is_bitmap_valid(sbi, blkaddr, type);
                }
                break;
        case META_GENERIC:
@@ -189,7 +220,7 @@ int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
                .op_flags = sync ? (REQ_META | REQ_PRIO) : REQ_RAHEAD,
                .encrypted_page = NULL,
                .in_list = false,
-               .is_meta = (type != META_POR),
+               .is_por = (type == META_POR),
        };
        struct blk_plug plug;
 
@@ -644,6 +675,12 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi)
        if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
                return 0;
 
+       if (bdev_read_only(sbi->sb->s_bdev)) {
+               f2fs_msg(sbi->sb, KERN_INFO, "write access "
+                       "unavailable, skipping orphan cleanup");
+               return 0;
+       }
+
        if (s_flags & SB_RDONLY) {
                f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs");
                sbi->sb->s_flags &= ~SB_RDONLY;
@@ -758,13 +795,27 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
        }
 }
 
+static __u32 f2fs_checkpoint_chksum(struct f2fs_sb_info *sbi,
+                                               struct f2fs_checkpoint *ckpt)
+{
+       unsigned int chksum_ofs = le32_to_cpu(ckpt->checksum_offset);
+       __u32 chksum;
+
+       chksum = f2fs_crc32(sbi, ckpt, chksum_ofs);
+       if (chksum_ofs < CP_CHKSUM_OFFSET) {
+               chksum_ofs += sizeof(chksum);
+               chksum = f2fs_chksum(sbi, chksum, (__u8 *)ckpt + chksum_ofs,
+                                               F2FS_BLKSIZE - chksum_ofs);
+       }
+       return chksum;
+}
+
 static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,
                struct f2fs_checkpoint **cp_block, struct page **cp_page,
                unsigned long long *version)
 {
-       unsigned long blk_size = sbi->blocksize;
        size_t crc_offset = 0;
-       __u32 crc = 0;
+       __u32 crc;
 
        *cp_page = f2fs_get_meta_page(sbi, cp_addr);
        if (IS_ERR(*cp_page))
@@ -773,15 +824,27 @@ static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,
        *cp_block = (struct f2fs_checkpoint *)page_address(*cp_page);
 
        crc_offset = le32_to_cpu((*cp_block)->checksum_offset);
-       if (crc_offset > (blk_size - sizeof(__le32))) {
+       if (crc_offset < CP_MIN_CHKSUM_OFFSET ||
+                       crc_offset > CP_CHKSUM_OFFSET) {
                f2fs_put_page(*cp_page, 1);
                f2fs_msg(sbi->sb, KERN_WARNING,
                        "invalid crc_offset: %zu", crc_offset);
                return -EINVAL;
        }
 
-       crc = cur_cp_crc(*cp_block);
-       if (!f2fs_crc_valid(sbi, crc, *cp_block, crc_offset)) {
+       if (__is_set_ckpt_flags(*cp_block, CP_LARGE_NAT_BITMAP_FLAG)) {
+               if (crc_offset != CP_MIN_CHKSUM_OFFSET) {
+                       f2fs_put_page(*cp_page, 1);
+                       f2fs_msg(sbi->sb, KERN_WARNING,
+                               "layout of large_nat_bitmap is deprecated, "
+                               "run fsck to repair, chksum_offset: %zu",
+                               crc_offset);
+                       return -EINVAL;
+               }
+       }
+
+       crc = f2fs_checkpoint_chksum(sbi, *cp_block);
+       if (crc != cur_cp_crc(*cp_block)) {
                f2fs_put_page(*cp_page, 1);
                f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value");
                return -EINVAL;
@@ -1009,13 +1072,11 @@ retry:
        if (inode) {
                unsigned long cur_ino = inode->i_ino;
 
-               if (is_dir)
-                       F2FS_I(inode)->cp_task = current;
+               F2FS_I(inode)->cp_task = current;
 
                filemap_fdatawrite(inode->i_mapping);
 
-               if (is_dir)
-                       F2FS_I(inode)->cp_task = NULL;
+               F2FS_I(inode)->cp_task = NULL;
 
                iput(inode);
                /* We need to give cpu to another writers. */
@@ -1391,7 +1452,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP));
        get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP));
 
-       crc32 = f2fs_crc32(sbi, ckpt, le32_to_cpu(ckpt->checksum_offset));
+       crc32 = f2fs_checkpoint_chksum(sbi, ckpt);
        *((__le32 *)((unsigned char *)ckpt +
                                le32_to_cpu(ckpt->checksum_offset)))
                                = cpu_to_le32(crc32);
@@ -1475,7 +1536,11 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        clear_sbi_flag(sbi, SBI_IS_DIRTY);
        clear_sbi_flag(sbi, SBI_NEED_CP);
        clear_sbi_flag(sbi, SBI_QUOTA_SKIP_FLUSH);
+
+       spin_lock(&sbi->stat_lock);
        sbi->unusable_block_count = 0;
+       spin_unlock(&sbi->stat_lock);
+
        __set_cp_next_pack(sbi);
 
        /*
@@ -1500,6 +1565,9 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        unsigned long long ckpt_ver;
        int err = 0;
 
+       if (f2fs_readonly(sbi->sb) || f2fs_hw_is_readonly(sbi))
+               return -EROFS;
+
        if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
                if (cpc->reason != CP_PAUSE)
                        return 0;
@@ -1516,10 +1584,6 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                err = -EIO;
                goto out;
        }
-       if (f2fs_readonly(sbi->sb)) {
-               err = -EROFS;
-               goto out;
-       }
 
        trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "start block_ops");
 
index 64040e99843942a5f083bddd671556974795284d..eda4181d20926bd59903f9feea6e57f5108612dc 100644 (file)
@@ -218,12 +218,14 @@ struct block_device *f2fs_target_device(struct f2fs_sb_info *sbi,
        struct block_device *bdev = sbi->sb->s_bdev;
        int i;
 
-       for (i = 0; i < sbi->s_ndevs; i++) {
-               if (FDEV(i).start_blk <= blk_addr &&
-                                       FDEV(i).end_blk >= blk_addr) {
-                       blk_addr -= FDEV(i).start_blk;
-                       bdev = FDEV(i).bdev;
-                       break;
+       if (f2fs_is_multi_device(sbi)) {
+               for (i = 0; i < sbi->s_ndevs; i++) {
+                       if (FDEV(i).start_blk <= blk_addr &&
+                           FDEV(i).end_blk >= blk_addr) {
+                               blk_addr -= FDEV(i).start_blk;
+                               bdev = FDEV(i).bdev;
+                               break;
+                       }
                }
        }
        if (bio) {
@@ -237,6 +239,9 @@ int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr)
 {
        int i;
 
+       if (!f2fs_is_multi_device(sbi))
+               return 0;
+
        for (i = 0; i < sbi->s_ndevs; i++)
                if (FDEV(i).start_blk <= blkaddr && FDEV(i).end_blk >= blkaddr)
                        return i;
@@ -420,7 +425,7 @@ static void __submit_merged_write_cond(struct f2fs_sb_info *sbi,
 
 void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type)
 {
-       __submit_merged_write_cond(sbi, NULL, 0, 0, type, true);
+       __submit_merged_write_cond(sbi, NULL, NULL, 0, type, true);
 }
 
 void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi,
@@ -448,7 +453,8 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
                        fio->encrypted_page : fio->page;
 
        if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,
-                       __is_meta_io(fio) ? META_GENERIC : DATA_GENERIC))
+                       fio->is_por ? META_POR : (__is_meta_io(fio) ?
+                       META_GENERIC : DATA_GENERIC_ENHANCE)))
                return -EFAULT;
 
        trace_f2fs_submit_page_bio(page, fio);
@@ -498,9 +504,7 @@ next:
                spin_unlock(&io->io_lock);
        }
 
-       if (__is_valid_data_blkaddr(fio->old_blkaddr))
-               verify_block_addr(fio, fio->old_blkaddr);
-       verify_block_addr(fio, fio->new_blkaddr);
+       verify_fio_blkaddr(fio);
 
        bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page;
 
@@ -557,9 +561,6 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
        struct bio_post_read_ctx *ctx;
        unsigned int post_read_steps = 0;
 
-       if (!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC))
-               return ERR_PTR(-EFAULT);
-
        bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false);
        if (!bio)
                return ERR_PTR(-ENOMEM);
@@ -587,8 +588,10 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
 static int f2fs_submit_page_read(struct inode *inode, struct page *page,
                                                        block_t blkaddr)
 {
-       struct bio *bio = f2fs_grab_read_bio(inode, blkaddr, 1, 0);
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       struct bio *bio;
 
+       bio = f2fs_grab_read_bio(inode, blkaddr, 1, 0);
        if (IS_ERR(bio))
                return PTR_ERR(bio);
 
@@ -600,8 +603,8 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page,
                return -EFAULT;
        }
        ClearPageError(page);
-       inc_page_count(F2FS_I_SB(inode), F2FS_RD_DATA);
-       __submit_bio(F2FS_I_SB(inode), bio, DATA);
+       inc_page_count(sbi, F2FS_RD_DATA);
+       __submit_bio(sbi, bio, DATA);
        return 0;
 }
 
@@ -729,6 +732,11 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
 
        if (f2fs_lookup_extent_cache(inode, index, &ei)) {
                dn.data_blkaddr = ei.blk + index - ei.fofs;
+               if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), dn.data_blkaddr,
+                                               DATA_GENERIC_ENHANCE_READ)) {
+                       err = -EFAULT;
+                       goto put_err;
+               }
                goto got_it;
        }
 
@@ -742,6 +750,13 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
                err = -ENOENT;
                goto put_err;
        }
+       if (dn.data_blkaddr != NEW_ADDR &&
+                       !f2fs_is_valid_blkaddr(F2FS_I_SB(inode),
+                                               dn.data_blkaddr,
+                                               DATA_GENERIC_ENHANCE)) {
+               err = -EFAULT;
+               goto put_err;
+       }
 got_it:
        if (PageUptodate(page)) {
                unlock_page(page);
@@ -1084,12 +1099,12 @@ next_block:
        blkaddr = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node);
 
        if (__is_valid_data_blkaddr(blkaddr) &&
-               !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC)) {
+               !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) {
                err = -EFAULT;
                goto sync_out;
        }
 
-       if (is_valid_data_blkaddr(sbi, blkaddr)) {
+       if (__is_valid_data_blkaddr(blkaddr)) {
                /* use out-place-update for driect IO under LFS mode */
                if (test_opt(sbi, LFS) && flag == F2FS_GET_BLOCK_DIO &&
                                                        map->m_may_create) {
@@ -1499,6 +1514,118 @@ out:
        return ret;
 }
 
+static int f2fs_read_single_page(struct inode *inode, struct page *page,
+                                       unsigned nr_pages,
+                                       struct f2fs_map_blocks *map,
+                                       struct bio **bio_ret,
+                                       sector_t *last_block_in_bio,
+                                       bool is_readahead)
+{
+       struct bio *bio = *bio_ret;
+       const unsigned blkbits = inode->i_blkbits;
+       const unsigned blocksize = 1 << blkbits;
+       sector_t block_in_file;
+       sector_t last_block;
+       sector_t last_block_in_file;
+       sector_t block_nr;
+       int ret = 0;
+
+       block_in_file = (sector_t)page->index;
+       last_block = block_in_file + nr_pages;
+       last_block_in_file = (i_size_read(inode) + blocksize - 1) >>
+                                                       blkbits;
+       if (last_block > last_block_in_file)
+               last_block = last_block_in_file;
+
+       /* just zeroing out page which is beyond EOF */
+       if (block_in_file >= last_block)
+               goto zero_out;
+       /*
+        * Map blocks using the previous result first.
+        */
+       if ((map->m_flags & F2FS_MAP_MAPPED) &&
+                       block_in_file > map->m_lblk &&
+                       block_in_file < (map->m_lblk + map->m_len))
+               goto got_it;
+
+       /*
+        * Then do more f2fs_map_blocks() calls until we are
+        * done with this page.
+        */
+       map->m_lblk = block_in_file;
+       map->m_len = last_block - block_in_file;
+
+       ret = f2fs_map_blocks(inode, map, 0, F2FS_GET_BLOCK_DEFAULT);
+       if (ret)
+               goto out;
+got_it:
+       if ((map->m_flags & F2FS_MAP_MAPPED)) {
+               block_nr = map->m_pblk + block_in_file - map->m_lblk;
+               SetPageMappedToDisk(page);
+
+               if (!PageUptodate(page) && !cleancache_get_page(page)) {
+                       SetPageUptodate(page);
+                       goto confused;
+               }
+
+               if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), block_nr,
+                                               DATA_GENERIC_ENHANCE_READ)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+       } else {
+zero_out:
+               zero_user_segment(page, 0, PAGE_SIZE);
+               if (!PageUptodate(page))
+                       SetPageUptodate(page);
+               unlock_page(page);
+               goto out;
+       }
+
+       /*
+        * This page will go to BIO.  Do we need to send this
+        * BIO off first?
+        */
+       if (bio && (*last_block_in_bio != block_nr - 1 ||
+               !__same_bdev(F2FS_I_SB(inode), block_nr, bio))) {
+submit_and_realloc:
+               __submit_bio(F2FS_I_SB(inode), bio, DATA);
+               bio = NULL;
+       }
+       if (bio == NULL) {
+               bio = f2fs_grab_read_bio(inode, block_nr, nr_pages,
+                               is_readahead ? REQ_RAHEAD : 0);
+               if (IS_ERR(bio)) {
+                       ret = PTR_ERR(bio);
+                       bio = NULL;
+                       goto out;
+               }
+       }
+
+       /*
+        * If the page is under writeback, we need to wait for
+        * its completion to see the correct decrypted data.
+        */
+       f2fs_wait_on_block_writeback(inode, block_nr);
+
+       if (bio_add_page(bio, page, blocksize, 0) < blocksize)
+               goto submit_and_realloc;
+
+       inc_page_count(F2FS_I_SB(inode), F2FS_RD_DATA);
+       ClearPageError(page);
+       *last_block_in_bio = block_nr;
+       goto out;
+confused:
+       if (bio) {
+               __submit_bio(F2FS_I_SB(inode), bio, DATA);
+               bio = NULL;
+       }
+       unlock_page(page);
+out:
+       *bio_ret = bio;
+       return ret;
+}
+
 /*
  * This function was originally taken from fs/mpage.c, and customized for f2fs.
  * Major change was from block_size == page_size in f2fs by default.
@@ -1515,13 +1642,8 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
        struct bio *bio = NULL;
        sector_t last_block_in_bio = 0;
        struct inode *inode = mapping->host;
-       const unsigned blkbits = inode->i_blkbits;
-       const unsigned blocksize = 1 << blkbits;
-       sector_t block_in_file;
-       sector_t last_block;
-       sector_t last_block_in_file;
-       sector_t block_nr;
        struct f2fs_map_blocks map;
+       int ret = 0;
 
        map.m_pblk = 0;
        map.m_lblk = 0;
@@ -1544,98 +1666,13 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
                                goto next_page;
                }
 
-               block_in_file = (sector_t)page->index;
-               last_block = block_in_file + nr_pages;
-               last_block_in_file = (i_size_read(inode) + blocksize - 1) >>
-                                                               blkbits;
-               if (last_block > last_block_in_file)
-                       last_block = last_block_in_file;
-
-               /* just zeroing out page which is beyond EOF */
-               if (block_in_file >= last_block)
-                       goto zero_out;
-               /*
-                * Map blocks using the previous result first.
-                */
-               if ((map.m_flags & F2FS_MAP_MAPPED) &&
-                               block_in_file > map.m_lblk &&
-                               block_in_file < (map.m_lblk + map.m_len))
-                       goto got_it;
-
-               /*
-                * Then do more f2fs_map_blocks() calls until we are
-                * done with this page.
-                */
-               map.m_lblk = block_in_file;
-               map.m_len = last_block - block_in_file;
-
-               if (f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT))
-                       goto set_error_page;
-got_it:
-               if ((map.m_flags & F2FS_MAP_MAPPED)) {
-                       block_nr = map.m_pblk + block_in_file - map.m_lblk;
-                       SetPageMappedToDisk(page);
-
-                       if (!PageUptodate(page) && !cleancache_get_page(page)) {
-                               SetPageUptodate(page);
-                               goto confused;
-                       }
-
-                       if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), block_nr,
-                                                               DATA_GENERIC))
-                               goto set_error_page;
-               } else {
-zero_out:
+               ret = f2fs_read_single_page(inode, page, nr_pages, &map, &bio,
+                                       &last_block_in_bio, is_readahead);
+               if (ret) {
+                       SetPageError(page);
                        zero_user_segment(page, 0, PAGE_SIZE);
-                       if (!PageUptodate(page))
-                               SetPageUptodate(page);
                        unlock_page(page);
-                       goto next_page;
                }
-
-               /*
-                * This page will go to BIO.  Do we need to send this
-                * BIO off first?
-                */
-               if (bio && (last_block_in_bio != block_nr - 1 ||
-                       !__same_bdev(F2FS_I_SB(inode), block_nr, bio))) {
-submit_and_realloc:
-                       __submit_bio(F2FS_I_SB(inode), bio, DATA);
-                       bio = NULL;
-               }
-               if (bio == NULL) {
-                       bio = f2fs_grab_read_bio(inode, block_nr, nr_pages,
-                                       is_readahead ? REQ_RAHEAD : 0);
-                       if (IS_ERR(bio)) {
-                               bio = NULL;
-                               goto set_error_page;
-                       }
-               }
-
-               /*
-                * If the page is under writeback, we need to wait for
-                * its completion to see the correct decrypted data.
-                */
-               f2fs_wait_on_block_writeback(inode, block_nr);
-
-               if (bio_add_page(bio, page, blocksize, 0) < blocksize)
-                       goto submit_and_realloc;
-
-               inc_page_count(F2FS_I_SB(inode), F2FS_RD_DATA);
-               ClearPageError(page);
-               last_block_in_bio = block_nr;
-               goto next_page;
-set_error_page:
-               SetPageError(page);
-               zero_user_segment(page, 0, PAGE_SIZE);
-               unlock_page(page);
-               goto next_page;
-confused:
-               if (bio) {
-                       __submit_bio(F2FS_I_SB(inode), bio, DATA);
-                       bio = NULL;
-               }
-               unlock_page(page);
 next_page:
                if (pages)
                        put_page(page);
@@ -1643,7 +1680,7 @@ next_page:
        BUG_ON(pages && !list_empty(pages));
        if (bio)
                __submit_bio(F2FS_I_SB(inode), bio, DATA);
-       return 0;
+       return pages ? 0 : ret;
 }
 
 static int f2fs_read_data_page(struct file *file, struct page *page)
@@ -1813,7 +1850,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
                fio->old_blkaddr = ei.blk + page->index - ei.fofs;
 
                if (!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
-                                                       DATA_GENERIC))
+                                               DATA_GENERIC_ENHANCE))
                        return -EFAULT;
 
                ipu_force = true;
@@ -1840,7 +1877,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
 got_it:
        if (__is_valid_data_blkaddr(fio->old_blkaddr) &&
                !f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
-                                                       DATA_GENERIC)) {
+                                               DATA_GENERIC_ENHANCE)) {
                err = -EFAULT;
                goto out_writepage;
        }
@@ -1848,7 +1885,8 @@ got_it:
         * If current allocation needs SSR,
         * it had better in-place writes for updated data.
         */
-       if (ipu_force || (is_valid_data_blkaddr(fio->sbi, fio->old_blkaddr) &&
+       if (ipu_force ||
+               (__is_valid_data_blkaddr(fio->old_blkaddr) &&
                                        need_inplace_update(fio))) {
                err = encrypt_one_page(fio);
                if (err)
@@ -1866,9 +1904,10 @@ got_it:
                                                                        true);
                        if (PageWriteback(page))
                                end_page_writeback(page);
+               } else {
+                       set_inode_flag(inode, FI_UPDATE_WRITE);
                }
                trace_f2fs_do_write_data_page(fio->page, IPU);
-               set_inode_flag(inode, FI_UPDATE_WRITE);
                return err;
        }
 
@@ -2030,7 +2069,8 @@ out:
        }
 
        unlock_page(page);
-       if (!S_ISDIR(inode->i_mode) && !IS_NOQUOTA(inode))
+       if (!S_ISDIR(inode->i_mode) && !IS_NOQUOTA(inode) &&
+                                       !F2FS_I(inode)->cp_task)
                f2fs_balance_fs(sbi, need_balance_fs);
 
        if (unlikely(f2fs_cp_error(sbi))) {
@@ -2491,6 +2531,11 @@ repeat:
                zero_user_segment(page, 0, PAGE_SIZE);
                SetPageUptodate(page);
        } else {
+               if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
+                               DATA_GENERIC_ENHANCE_READ)) {
+                       err = -EFAULT;
+                       goto fail;
+               }
                err = f2fs_submit_page_read(inode, page, blkaddr);
                if (err)
                        goto fail;
index bacf5c2a8850b832e1fc73ae501fea8fd3d976e6..06b89a9862ab2bb42bea7a067a455d497fc73e51 100644 (file)
@@ -210,7 +210,14 @@ enum {
        META_SSA,
        META_MAX,
        META_POR,
-       DATA_GENERIC,
+       DATA_GENERIC,           /* check range only */
+       DATA_GENERIC_ENHANCE,   /* strong check on range and segment bitmap */
+       DATA_GENERIC_ENHANCE_READ,      /*
+                                        * strong check on range and segment
+                                        * bitmap but no warning due to race
+                                        * condition of read on truncated area
+                                        * by extent_cache
+                                        */
        META_GENERIC,
 };
 
@@ -1041,7 +1048,7 @@ struct f2fs_io_info {
        bool submitted;         /* indicate IO submission */
        int need_lock;          /* indicate we need to lock cp_rwsem */
        bool in_list;           /* indicate fio is in io_list */
-       bool is_meta;           /* indicate borrow meta inode mapping or not */
+       bool is_por;            /* indicate IO is from recovery or not */
        bool retry;             /* need to reallocate block address */
        enum iostat_type io_type;       /* io type */
        struct writeback_control *io_wbc; /* writeback control */
@@ -1068,8 +1075,8 @@ struct f2fs_dev_info {
        block_t start_blk;
        block_t end_blk;
 #ifdef CONFIG_BLK_DEV_ZONED
-       unsigned int nr_blkz;                   /* Total number of zones */
-       u8 *blkz_type;                          /* Array of zones type */
+       unsigned int nr_blkz;           /* Total number of zones */
+       unsigned long *blkz_seq;        /* Bitmap indicating sequential zones */
 #endif
 };
 
@@ -1366,6 +1373,17 @@ static inline bool time_to_inject(struct f2fs_sb_info *sbi, int type)
 }
 #endif
 
+/*
+ * Test if the mounted volume is a multi-device volume.
+ *   - For a single regular disk volume, sbi->s_ndevs is 0.
+ *   - For a single zoned disk volume, sbi->s_ndevs is 1.
+ *   - For a multi-device volume, sbi->s_ndevs is always 2 or more.
+ */
+static inline bool f2fs_is_multi_device(struct f2fs_sb_info *sbi)
+{
+       return sbi->s_ndevs > 1;
+}
+
 /* For write statistics. Suppose sector size is 512 bytes,
  * and the return value is in kbytes. s is of struct f2fs_sb_info.
  */
@@ -1777,6 +1795,7 @@ enospc:
        return -ENOSPC;
 }
 
+void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...);
 static inline void dec_valid_block_count(struct f2fs_sb_info *sbi,
                                                struct inode *inode,
                                                block_t count)
@@ -1785,13 +1804,21 @@ static inline void dec_valid_block_count(struct f2fs_sb_info *sbi,
 
        spin_lock(&sbi->stat_lock);
        f2fs_bug_on(sbi, sbi->total_valid_block_count < (block_t) count);
-       f2fs_bug_on(sbi, inode->i_blocks < sectors);
        sbi->total_valid_block_count -= (block_t)count;
        if (sbi->reserved_blocks &&
                sbi->current_reserved_blocks < sbi->reserved_blocks)
                sbi->current_reserved_blocks = min(sbi->reserved_blocks,
                                        sbi->current_reserved_blocks + count);
        spin_unlock(&sbi->stat_lock);
+       if (unlikely(inode->i_blocks < sectors)) {
+               f2fs_msg(sbi->sb, KERN_WARNING,
+                       "Inconsistent i_blocks, ino:%lu, iblocks:%llu, sectors:%llu",
+                       inode->i_ino,
+                       (unsigned long long)inode->i_blocks,
+                       (unsigned long long)sectors);
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+               return;
+       }
        f2fs_i_blocks_write(inode, count, false, true);
 }
 
@@ -1889,7 +1916,11 @@ static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag)
        if (is_set_ckpt_flags(sbi, CP_LARGE_NAT_BITMAP_FLAG)) {
                offset = (flag == SIT_BITMAP) ?
                        le32_to_cpu(ckpt->nat_ver_bitmap_bytesize) : 0;
-               return &ckpt->sit_nat_version_bitmap + offset;
+               /*
+                * if large_nat_bitmap feature is enabled, leave checksum
+                * protection for all nat/sit bitmaps.
+                */
+               return &ckpt->sit_nat_version_bitmap + offset + sizeof(__le32);
        }
 
        if (__cp_payload(sbi) > 0) {
@@ -2008,7 +2039,6 @@ static inline void dec_valid_node_count(struct f2fs_sb_info *sbi,
 
        f2fs_bug_on(sbi, !sbi->total_valid_block_count);
        f2fs_bug_on(sbi, !sbi->total_valid_node_count);
-       f2fs_bug_on(sbi, !is_inode && !inode->i_blocks);
 
        sbi->total_valid_node_count--;
        sbi->total_valid_block_count--;
@@ -2018,10 +2048,19 @@ static inline void dec_valid_node_count(struct f2fs_sb_info *sbi,
 
        spin_unlock(&sbi->stat_lock);
 
-       if (is_inode)
+       if (is_inode) {
                dquot_free_inode(inode);
-       else
+       } else {
+               if (unlikely(inode->i_blocks == 0)) {
+                       f2fs_msg(sbi->sb, KERN_WARNING,
+                               "Inconsistent i_blocks, ino:%lu, iblocks:%llu",
+                               inode->i_ino,
+                               (unsigned long long)inode->i_blocks);
+                       set_sbi_flag(sbi, SBI_NEED_FSCK);
+                       return;
+               }
                f2fs_i_blocks_write(inode, 1, false, true);
+       }
 }
 
 static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi)
@@ -2545,7 +2584,14 @@ static inline int f2fs_has_inline_xattr(struct inode *inode)
 
 static inline unsigned int addrs_per_inode(struct inode *inode)
 {
-       return CUR_ADDRS_PER_INODE(inode) - get_inline_xattr_addrs(inode);
+       unsigned int addrs = CUR_ADDRS_PER_INODE(inode) -
+                               get_inline_xattr_addrs(inode);
+       return ALIGN_DOWN(addrs, 1);
+}
+
+static inline unsigned int addrs_per_block(struct inode *inode)
+{
+       return ALIGN_DOWN(DEF_ADDRS_PER_BLOCK, 1);
 }
 
 static inline void *inline_xattr_addr(struct inode *inode, struct page *page)
@@ -2558,7 +2604,9 @@ static inline void *inline_xattr_addr(struct inode *inode, struct page *page)
 
 static inline int inline_xattr_size(struct inode *inode)
 {
-       return get_inline_xattr_addrs(inode) * sizeof(__le32);
+       if (f2fs_has_inline_xattr(inode))
+               return get_inline_xattr_addrs(inode) * sizeof(__le32);
+       return 0;
 }
 
 static inline int f2fs_has_inline_data(struct inode *inode)
@@ -2800,12 +2848,10 @@ static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi,
 
 #define __is_large_section(sbi)                ((sbi)->segs_per_sec > 1)
 
-#define __is_meta_io(fio) (PAGE_TYPE_OF_BIO((fio)->type) == META &&    \
-                               (!is_read_io((fio)->op) || (fio)->is_meta))
+#define __is_meta_io(fio) (PAGE_TYPE_OF_BIO((fio)->type) == META)
 
 bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
                                        block_t blkaddr, int type);
-void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...);
 static inline void verify_blkaddr(struct f2fs_sb_info *sbi,
                                        block_t blkaddr, int type)
 {
@@ -2824,15 +2870,6 @@ static inline bool __is_valid_data_blkaddr(block_t blkaddr)
        return true;
 }
 
-static inline bool is_valid_data_blkaddr(struct f2fs_sb_info *sbi,
-                                               block_t blkaddr)
-{
-       if (!__is_valid_data_blkaddr(blkaddr))
-               return false;
-       verify_blkaddr(sbi, blkaddr, DATA_GENERIC);
-       return true;
-}
-
 static inline void f2fs_set_page_private(struct page *page,
                                                unsigned long data)
 {
@@ -3530,16 +3567,12 @@ F2FS_FEATURE_FUNCS(lost_found, LOST_FOUND);
 F2FS_FEATURE_FUNCS(sb_chksum, SB_CHKSUM);
 
 #ifdef CONFIG_BLK_DEV_ZONED
-static inline int get_blkz_type(struct f2fs_sb_info *sbi,
-                       struct block_device *bdev, block_t blkaddr)
+static inline bool f2fs_blkz_is_seq(struct f2fs_sb_info *sbi, int devi,
+                                   block_t blkaddr)
 {
        unsigned int zno = blkaddr >> sbi->log_blocks_per_blkz;
-       int i;
 
-       for (i = 0; i < sbi->s_ndevs; i++)
-               if (FDEV(i).bdev == bdev)
-                       return FDEV(i).blkz_type[zno];
-       return -EINVAL;
+       return test_bit(zno, FDEV(devi).blkz_seq);
 }
 #endif
 
@@ -3548,9 +3581,23 @@ static inline bool f2fs_hw_should_discard(struct f2fs_sb_info *sbi)
        return f2fs_sb_has_blkzoned(sbi);
 }
 
+static inline bool f2fs_bdev_support_discard(struct block_device *bdev)
+{
+       return blk_queue_discard(bdev_get_queue(bdev)) ||
+              bdev_is_zoned(bdev);
+}
+
 static inline bool f2fs_hw_support_discard(struct f2fs_sb_info *sbi)
 {
-       return blk_queue_discard(bdev_get_queue(sbi->sb->s_bdev));
+       int i;
+
+       if (!f2fs_is_multi_device(sbi))
+               return f2fs_bdev_support_discard(sbi->sb->s_bdev);
+
+       for (i = 0; i < sbi->s_ndevs; i++)
+               if (f2fs_bdev_support_discard(FDEV(i).bdev))
+                       return true;
+       return false;
 }
 
 static inline bool f2fs_realtime_discard_enable(struct f2fs_sb_info *sbi)
@@ -3559,6 +3606,20 @@ static inline bool f2fs_realtime_discard_enable(struct f2fs_sb_info *sbi)
                                        f2fs_hw_should_discard(sbi);
 }
 
+static inline bool f2fs_hw_is_readonly(struct f2fs_sb_info *sbi)
+{
+       int i;
+
+       if (!f2fs_is_multi_device(sbi))
+               return bdev_read_only(sbi->sb->s_bdev);
+
+       for (i = 0; i < sbi->s_ndevs; i++)
+               if (bdev_read_only(FDEV(i).bdev))
+                       return true;
+       return false;
+}
+
+
 static inline void set_opt_mode(struct f2fs_sb_info *sbi, unsigned int mt)
 {
        clear_opt(sbi, ADAPTIVE);
@@ -3614,7 +3675,7 @@ static inline bool f2fs_force_buffered_io(struct inode *inode,
 
        if (f2fs_post_read_required(inode))
                return true;
-       if (sbi->s_ndevs)
+       if (f2fs_is_multi_device(sbi))
                return true;
        /*
         * for blkzoned device, fallback direct IO to buffered IO, so
@@ -3651,4 +3712,4 @@ static inline bool is_journalled_quota(struct f2fs_sb_info *sbi)
        return false;
 }
 
-#endif
+#endif /* _LINUX_F2FS_H */
index 5742ab8b57dc6798cdf11af401ab11092f399705..45b45f37d347e47f8e5cf3857f5c2734a6ae1d98 100644 (file)
@@ -39,6 +39,8 @@ static vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf)
        ret = filemap_fault(vmf);
        up_read(&F2FS_I(inode)->i_mmap_sem);
 
+       trace_f2fs_filemap_fault(inode, vmf->pgoff, (unsigned long)ret);
+
        return ret;
 }
 
@@ -356,7 +358,7 @@ static bool __found_offset(struct f2fs_sb_info *sbi, block_t blkaddr,
        switch (whence) {
        case SEEK_DATA:
                if ((blkaddr == NEW_ADDR && dirty == pgofs) ||
-                       is_valid_data_blkaddr(sbi, blkaddr))
+                       __is_valid_data_blkaddr(blkaddr))
                        return true;
                break;
        case SEEK_HOLE:
@@ -422,7 +424,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
 
                        if (__is_valid_data_blkaddr(blkaddr) &&
                                !f2fs_is_valid_blkaddr(F2FS_I_SB(inode),
-                                               blkaddr, DATA_GENERIC)) {
+                                       blkaddr, DATA_GENERIC_ENHANCE)) {
                                f2fs_put_dnode(&dn);
                                goto fail;
                        }
@@ -523,7 +525,8 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
                f2fs_set_data_blkaddr(dn);
 
                if (__is_valid_data_blkaddr(blkaddr) &&
-                       !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC))
+                       !f2fs_is_valid_blkaddr(sbi, blkaddr,
+                                       DATA_GENERIC_ENHANCE))
                        continue;
 
                f2fs_invalidate_blocks(sbi, blkaddr);
@@ -552,7 +555,7 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
 
 void f2fs_truncate_data_blocks(struct dnode_of_data *dn)
 {
-       f2fs_truncate_data_blocks_range(dn, ADDRS_PER_BLOCK);
+       f2fs_truncate_data_blocks_range(dn, ADDRS_PER_BLOCK(dn->inode));
 }
 
 static int truncate_partial_data_page(struct inode *inode, u64 from,
@@ -1006,7 +1009,8 @@ next_dnode:
        } else if (ret == -ENOENT) {
                if (dn.max_level == 0)
                        return -ENOENT;
-               done = min((pgoff_t)ADDRS_PER_BLOCK - dn.ofs_in_node, len);
+               done = min((pgoff_t)ADDRS_PER_BLOCK(inode) - dn.ofs_in_node,
+                                                                       len);
                blkaddr += done;
                do_replace += done;
                goto next;
@@ -1017,6 +1021,14 @@ next_dnode:
        for (i = 0; i < done; i++, blkaddr++, do_replace++, dn.ofs_in_node++) {
                *blkaddr = datablock_addr(dn.inode,
                                        dn.node_page, dn.ofs_in_node);
+
+               if (__is_valid_data_blkaddr(*blkaddr) &&
+                       !f2fs_is_valid_blkaddr(sbi, *blkaddr,
+                                       DATA_GENERIC_ENHANCE)) {
+                       f2fs_put_dnode(&dn);
+                       return -EFAULT;
+               }
+
                if (!f2fs_is_checkpointed_data(sbi, *blkaddr)) {
 
                        if (test_opt(sbi, LFS)) {
@@ -1157,7 +1169,7 @@ static int __exchange_data_block(struct inode *src_inode,
        int ret;
 
        while (len) {
-               olen = min((pgoff_t)4 * ADDRS_PER_BLOCK, len);
+               olen = min((pgoff_t)4 * ADDRS_PER_BLOCK(src_inode), len);
 
                src_blkaddr = f2fs_kvzalloc(F2FS_I_SB(src_inode),
                                        array_size(olen, sizeof(block_t)),
@@ -2573,10 +2585,10 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg)
                                                        sizeof(range)))
                return -EFAULT;
 
-       if (sbi->s_ndevs <= 1 || sbi->s_ndevs - 1 <= range.dev_num ||
+       if (!f2fs_is_multi_device(sbi) || sbi->s_ndevs - 1 <= range.dev_num ||
                        __is_large_section(sbi)) {
                f2fs_msg(sbi->sb, KERN_WARNING,
-                       "Can't flush %u in %d for segs_per_sec %u != 1\n",
+                       "Can't flush %u in %d for segs_per_sec %u != 1",
                                range.dev_num, sbi->s_ndevs,
                                sbi->segs_per_sec);
                return -EINVAL;
@@ -2858,7 +2870,7 @@ int f2fs_pin_file_control(struct inode *inode, bool inc)
 
        if (fi->i_gc_failures[GC_FAILURE_PIN] > sbi->gc_pin_file_threshold) {
                f2fs_msg(sbi->sb, KERN_WARNING,
-                       "%s: Enable GC = ino %lx after %x GC trials\n",
+                       "%s: Enable GC = ino %lx after %x GC trials",
                        __func__, inode->i_ino,
                        fi->i_gc_failures[GC_FAILURE_PIN]);
                clear_inode_flag(inode, FI_PIN_FILE);
@@ -3035,15 +3047,21 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
        struct inode *inode = file_inode(file);
        ssize_t ret;
 
-       if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
-               return -EIO;
+       if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) {
+               ret = -EIO;
+               goto out;
+       }
 
-       if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT))
-               return -EINVAL;
+       if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT)) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        if (!inode_trylock(inode)) {
-               if (iocb->ki_flags & IOCB_NOWAIT)
-                       return -EAGAIN;
+               if (iocb->ki_flags & IOCB_NOWAIT) {
+                       ret = -EAGAIN;
+                       goto out;
+               }
                inode_lock(inode);
        }
 
@@ -3056,19 +3074,16 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
                if (iov_iter_fault_in_readable(from, iov_iter_count(from)))
                        set_inode_flag(inode, FI_NO_PREALLOC);
 
-               if ((iocb->ki_flags & IOCB_NOWAIT) &&
-                       (iocb->ki_flags & IOCB_DIRECT)) {
-                               if (!f2fs_overwrite_io(inode, iocb->ki_pos,
+               if ((iocb->ki_flags & IOCB_NOWAIT)) {
+                       if (!f2fs_overwrite_io(inode, iocb->ki_pos,
                                                iov_iter_count(from)) ||
-                                       f2fs_has_inline_data(inode) ||
-                                       f2fs_force_buffered_io(inode,
-                                                       iocb, from)) {
-                                               clear_inode_flag(inode,
-                                                               FI_NO_PREALLOC);
-                                               inode_unlock(inode);
-                                               return -EAGAIN;
-                               }
-
+                               f2fs_has_inline_data(inode) ||
+                               f2fs_force_buffered_io(inode, iocb, from)) {
+                               clear_inode_flag(inode, FI_NO_PREALLOC);
+                               inode_unlock(inode);
+                               ret = -EAGAIN;
+                               goto out;
+                       }
                } else {
                        preallocated = true;
                        target_size = iocb->ki_pos + iov_iter_count(from);
@@ -3077,7 +3092,8 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
                        if (err) {
                                clear_inode_flag(inode, FI_NO_PREALLOC);
                                inode_unlock(inode);
-                               return err;
+                               ret = err;
+                               goto out;
                        }
                }
                ret = __generic_file_write_iter(iocb, from);
@@ -3091,7 +3107,9 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
                        f2fs_update_iostat(F2FS_I_SB(inode), APP_WRITE_IO, ret);
        }
        inode_unlock(inode);
-
+out:
+       trace_f2fs_file_write_iter(inode, iocb->ki_pos,
+                                       iov_iter_count(from), ret);
        if (ret > 0)
                ret = generic_write_sync(iocb, ret);
        return ret;
index 195cf0f9d9ef90794e2b9a80649729511ea4ab60..963fb4571fd984a75e0f32fba612c416a4330db8 100644 (file)
@@ -591,7 +591,7 @@ block_t f2fs_start_bidx_of_node(unsigned int node_ofs, struct inode *inode)
                int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1);
                bidx = node_ofs - 5 - dec;
        }
-       return bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE(inode);
+       return bidx * ADDRS_PER_BLOCK(inode) + ADDRS_PER_INODE(inode);
 }
 
 static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
@@ -656,6 +656,11 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
 
        if (f2fs_lookup_extent_cache(inode, index, &ei)) {
                dn.data_blkaddr = ei.blk + index - ei.fofs;
+               if (unlikely(!f2fs_is_valid_blkaddr(sbi, dn.data_blkaddr,
+                                               DATA_GENERIC_ENHANCE_READ))) {
+                       err = -EFAULT;
+                       goto put_page;
+               }
                goto got_it;
        }
 
@@ -665,8 +670,12 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
                goto put_page;
        f2fs_put_dnode(&dn);
 
+       if (!__is_valid_data_blkaddr(dn.data_blkaddr)) {
+               err = -ENOENT;
+               goto put_page;
+       }
        if (unlikely(!f2fs_is_valid_blkaddr(sbi, dn.data_blkaddr,
-                                               DATA_GENERIC))) {
+                                               DATA_GENERIC_ENHANCE))) {
                err = -EFAULT;
                goto put_page;
        }
@@ -1175,6 +1184,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
                                "type [%d, %d] in SSA and SIT",
                                segno, type, GET_SUM_TYPE((&sum->footer)));
                        set_sbi_flag(sbi, SBI_NEED_FSCK);
+                       f2fs_stop_checkpoint(sbi, false);
                        goto skip;
                }
 
@@ -1346,7 +1356,7 @@ void f2fs_build_gc_manager(struct f2fs_sb_info *sbi)
        sbi->gc_pin_file_threshold = DEF_GC_FAILED_PINNED_FILES;
 
        /* give warm/cold data area from slower device */
-       if (sbi->s_ndevs && !__is_large_section(sbi))
+       if (f2fs_is_multi_device(sbi) && !__is_large_section(sbi))
                SIT_I(sbi)->last_victim[ALLOC_NEXT] =
                                GET_SEGNO(sbi, FDEV(0).end_blk) + 1;
 }
index bb6a152310ef437109a3a2b03a6c5413411e4308..404d2462a0fe625f08ec04a4a39df6d8cc7100d8 100644 (file)
@@ -420,6 +420,14 @@ static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage,
        stat_dec_inline_dir(dir);
        clear_inode_flag(dir, FI_INLINE_DENTRY);
 
+       /*
+        * should retrieve reserved space which was used to keep
+        * inline_dentry's structure for backward compatibility.
+        */
+       if (!f2fs_sb_has_flexible_inline_xattr(F2FS_I_SB(dir)) &&
+                       !f2fs_has_inline_xattr(dir))
+               F2FS_I(dir)->i_inline_xattr_size = 0;
+
        f2fs_i_depth_write(dir, 1);
        if (i_size_read(dir) < PAGE_SIZE)
                f2fs_i_size_write(dir, PAGE_SIZE);
@@ -501,6 +509,15 @@ static int f2fs_move_rehashed_dirents(struct inode *dir, struct page *ipage,
 
        stat_dec_inline_dir(dir);
        clear_inode_flag(dir, FI_INLINE_DENTRY);
+
+       /*
+        * should retrieve reserved space which was used to keep
+        * inline_dentry's structure for backward compatibility.
+        */
+       if (!f2fs_sb_has_flexible_inline_xattr(F2FS_I_SB(dir)) &&
+                       !f2fs_has_inline_xattr(dir))
+               F2FS_I(dir)->i_inline_xattr_size = 0;
+
        kvfree(backup_dentry);
        return 0;
 recover:
index e7f2e8759315636431ae7795be7cbe002b155fc4..ccb02226dd2c0c28722ecafd61ce657975e441cd 100644 (file)
@@ -73,7 +73,7 @@ static int __written_first_block(struct f2fs_sb_info *sbi,
 
        if (!__is_valid_data_blkaddr(addr))
                return 1;
-       if (!f2fs_is_valid_blkaddr(sbi, addr, DATA_GENERIC))
+       if (!f2fs_is_valid_blkaddr(sbi, addr, DATA_GENERIC_ENHANCE))
                return -EFAULT;
        return 0;
 }
@@ -177,8 +177,8 @@ bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page)
 
        if (provided != calculated)
                f2fs_msg(sbi->sb, KERN_WARNING,
-                       "checksum invalid, ino = %x, %x vs. %x",
-                       ino_of_node(page), provided, calculated);
+                       "checksum invalid, nid = %lu, ino_of_node = %x, %x vs. %x",
+                       page->index, ino_of_node(page), provided, calculated);
 
        return provided == calculated;
 }
@@ -267,9 +267,10 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)
                struct extent_info *ei = &F2FS_I(inode)->extent_tree->largest;
 
                if (ei->len &&
-                       (!f2fs_is_valid_blkaddr(sbi, ei->blk, DATA_GENERIC) ||
+                       (!f2fs_is_valid_blkaddr(sbi, ei->blk,
+                                               DATA_GENERIC_ENHANCE) ||
                        !f2fs_is_valid_blkaddr(sbi, ei->blk + ei->len - 1,
-                                                       DATA_GENERIC))) {
+                                               DATA_GENERIC_ENHANCE))) {
                        set_sbi_flag(sbi, SBI_NEED_FSCK);
                        f2fs_msg(sbi->sb, KERN_WARNING,
                                "%s: inode (ino=%lx) extent info [%u, %u, %u] "
@@ -488,6 +489,7 @@ make_now:
        return inode;
 
 bad_inode:
+       f2fs_inode_synced(inode);
        iget_failed(inode);
        trace_f2fs_iget_exit(inode, ret);
        return ERR_PTR(ret);
index c3e8a901d47ac27476b6a49dd9dfd173412b8882..0f77f92427515f3062201bc972efd2aebb80bea7 100644 (file)
@@ -143,7 +143,7 @@ fail_drop:
        return ERR_PTR(err);
 }
 
-static int is_extension_exist(const unsigned char *s, const char *sub)
+static inline int is_extension_exist(const unsigned char *s, const char *sub)
 {
        size_t slen = strlen(s);
        size_t sublen = strlen(sub);
index d6e48a6487d511fa08c9bd99906106fcc86540b8..18a038a2a9fabf02f015094faa0d99a38c44426c 100644 (file)
@@ -454,7 +454,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
                        new_blkaddr == NULL_ADDR);
        f2fs_bug_on(sbi, nat_get_blkaddr(e) == NEW_ADDR &&
                        new_blkaddr == NEW_ADDR);
-       f2fs_bug_on(sbi, is_valid_data_blkaddr(sbi, nat_get_blkaddr(e)) &&
+       f2fs_bug_on(sbi, __is_valid_data_blkaddr(nat_get_blkaddr(e)) &&
                        new_blkaddr == NEW_ADDR);
 
        /* increment version no as node is removed */
@@ -465,7 +465,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
 
        /* change address */
        nat_set_blkaddr(e, new_blkaddr);
-       if (!is_valid_data_blkaddr(sbi, new_blkaddr))
+       if (!__is_valid_data_blkaddr(new_blkaddr))
                set_nat_flag(e, IS_CHECKPOINTED, false);
        __set_nat_cache_dirty(nm_i, e);
 
@@ -526,6 +526,7 @@ int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
        struct f2fs_nat_entry ne;
        struct nat_entry *e;
        pgoff_t index;
+       block_t blkaddr;
        int i;
 
        ni->nid = nid;
@@ -569,6 +570,11 @@ int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
        node_info_from_raw_nat(ni, &ne);
        f2fs_put_page(page, 1);
 cache:
+       blkaddr = le32_to_cpu(ne.block_addr);
+       if (__is_valid_data_blkaddr(blkaddr) &&
+               !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE))
+               return -EFAULT;
+
        /* cache nat entry */
        cache_nat_entry(sbi, nid, &ne);
        return 0;
@@ -600,9 +606,9 @@ static void f2fs_ra_node_pages(struct page *parent, int start, int n)
 pgoff_t f2fs_get_next_page_offset(struct dnode_of_data *dn, pgoff_t pgofs)
 {
        const long direct_index = ADDRS_PER_INODE(dn->inode);
-       const long direct_blks = ADDRS_PER_BLOCK;
-       const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK;
-       unsigned int skipped_unit = ADDRS_PER_BLOCK;
+       const long direct_blks = ADDRS_PER_BLOCK(dn->inode);
+       const long indirect_blks = ADDRS_PER_BLOCK(dn->inode) * NIDS_PER_BLOCK;
+       unsigned int skipped_unit = ADDRS_PER_BLOCK(dn->inode);
        int cur_level = dn->cur_level;
        int max_level = dn->max_level;
        pgoff_t base = 0;
@@ -638,9 +644,9 @@ static int get_node_path(struct inode *inode, long block,
                                int offset[4], unsigned int noffset[4])
 {
        const long direct_index = ADDRS_PER_INODE(inode);
-       const long direct_blks = ADDRS_PER_BLOCK;
+       const long direct_blks = ADDRS_PER_BLOCK(inode);
        const long dptrs_per_blk = NIDS_PER_BLOCK;
-       const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK;
+       const long indirect_blks = ADDRS_PER_BLOCK(inode) * NIDS_PER_BLOCK;
        const long dindirect_blks = indirect_blks * NIDS_PER_BLOCK;
        int n = 0;
        int level = 0;
@@ -1181,8 +1187,14 @@ int f2fs_remove_inode_page(struct inode *inode)
                f2fs_put_dnode(&dn);
                return -EIO;
        }
-       f2fs_bug_on(F2FS_I_SB(inode),
-                       inode->i_blocks != 0 && inode->i_blocks != 8);
+
+       if (unlikely(inode->i_blocks != 0 && inode->i_blocks != 8)) {
+               f2fs_msg(F2FS_I_SB(inode)->sb, KERN_WARNING,
+                       "Inconsistent i_blocks, ino:%lu, iblocks:%llu",
+                       inode->i_ino,
+                       (unsigned long long)inode->i_blocks);
+               set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
+       }
 
        /* will put inode & node pages */
        err = truncate_node(&dn);
@@ -1277,9 +1289,10 @@ static int read_node_page(struct page *page, int op_flags)
        int err;
 
        if (PageUptodate(page)) {
-#ifdef CONFIG_F2FS_CHECK_FS
-               f2fs_bug_on(sbi, !f2fs_inode_chksum_verify(sbi, page));
-#endif
+               if (!f2fs_inode_chksum_verify(sbi, page)) {
+                       ClearPageUptodate(page);
+                       return -EBADMSG;
+               }
                return LOCKED_PAGE;
        }
 
@@ -1543,7 +1556,8 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
        }
 
        if (__is_valid_data_blkaddr(ni.blk_addr) &&
-               !f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC)) {
+               !f2fs_is_valid_blkaddr(sbi, ni.blk_addr,
+                                       DATA_GENERIC_ENHANCE)) {
                up_read(&sbi->node_write);
                goto redirty_out;
        }
@@ -2078,6 +2092,9 @@ static bool add_free_nid(struct f2fs_sb_info *sbi,
        if (unlikely(nid == 0))
                return false;
 
+       if (unlikely(f2fs_check_nid_range(sbi, nid)))
+               return false;
+
        i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS);
        i->nid = nid;
        i->state = FREE_NID;
index e3883db868d81ee6fa92fb6cbd6e68dc2e1bf367..e04f82b3f4fc82ec0e0c943fb57970d55ce89f5f 100644 (file)
@@ -325,8 +325,10 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
                        break;
                }
 
-               if (!is_recoverable_dnode(page))
+               if (!is_recoverable_dnode(page)) {
+                       f2fs_put_page(page, 1);
                        break;
+               }
 
                if (!is_fsync_dnode(page))
                        goto next;
@@ -338,8 +340,10 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
                        if (!check_only &&
                                        IS_INODE(page) && is_dent_dnode(page)) {
                                err = f2fs_recover_inode_page(sbi, page);
-                               if (err)
+                               if (err) {
+                                       f2fs_put_page(page, 1);
                                        break;
+                               }
                                quota_inode = true;
                        }
 
@@ -355,6 +359,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
                                        err = 0;
                                        goto next;
                                }
+                               f2fs_put_page(page, 1);
                                break;
                        }
                }
@@ -370,6 +375,7 @@ next:
                                "%s: detect looped node chain, "
                                "blkaddr:%u, next:%u",
                                __func__, blkaddr, next_blkaddr_of_node(page));
+                       f2fs_put_page(page, 1);
                        err = -EINVAL;
                        break;
                }
@@ -380,7 +386,6 @@ next:
 
                f2fs_ra_meta_pages_cond(sbi, blkaddr);
        }
-       f2fs_put_page(page, 1);
        return err;
 }
 
@@ -546,7 +551,15 @@ retry_dn:
                goto err;
 
        f2fs_bug_on(sbi, ni.ino != ino_of_node(page));
-       f2fs_bug_on(sbi, ofs_of_node(dn.node_page) != ofs_of_node(page));
+
+       if (ofs_of_node(dn.node_page) != ofs_of_node(page)) {
+               f2fs_msg(sbi->sb, KERN_WARNING,
+                       "Inconsistent ofs_of_node, ino:%lu, ofs:%u, %u",
+                       inode->i_ino, ofs_of_node(dn.node_page),
+                       ofs_of_node(page));
+               err = -EFAULT;
+               goto err;
+       }
 
        for (; start < end; start++, dn.ofs_in_node++) {
                block_t src, dest;
@@ -554,6 +567,18 @@ retry_dn:
                src = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node);
                dest = datablock_addr(dn.inode, page, dn.ofs_in_node);
 
+               if (__is_valid_data_blkaddr(src) &&
+                       !f2fs_is_valid_blkaddr(sbi, src, META_POR)) {
+                       err = -EFAULT;
+                       goto err;
+               }
+
+               if (__is_valid_data_blkaddr(dest) &&
+                       !f2fs_is_valid_blkaddr(sbi, dest, META_POR)) {
+                       err = -EFAULT;
+                       goto err;
+               }
+
                /* skip recovering if dest is the same as src */
                if (src == dest)
                        continue;
@@ -666,8 +691,10 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
                 */
                if (IS_INODE(page)) {
                        err = recover_inode(entry->inode, page);
-                       if (err)
+                       if (err) {
+                               f2fs_put_page(page, 1);
                                break;
+                       }
                }
                if (entry->last_dentry == blkaddr) {
                        err = recover_dentry(entry->inode, page, dir_list);
index aa7fe79b62b2e0c386e4a44a947db076b78cf2f0..8dee063c833fa8fb2c6fedc91859c7600226fe8c 100644 (file)
@@ -580,7 +580,7 @@ static int submit_flush_wait(struct f2fs_sb_info *sbi, nid_t ino)
        int ret = 0;
        int i;
 
-       if (!sbi->s_ndevs)
+       if (!f2fs_is_multi_device(sbi))
                return __submit_flush_wait(sbi, sbi->sb->s_bdev);
 
        for (i = 0; i < sbi->s_ndevs; i++) {
@@ -648,7 +648,8 @@ int f2fs_issue_flush(struct f2fs_sb_info *sbi, nid_t ino)
                return ret;
        }
 
-       if (atomic_inc_return(&fcc->queued_flush) == 1 || sbi->s_ndevs > 1) {
+       if (atomic_inc_return(&fcc->queued_flush) == 1 ||
+           f2fs_is_multi_device(sbi)) {
                ret = submit_flush_wait(sbi, ino);
                atomic_dec(&fcc->queued_flush);
 
@@ -754,7 +755,7 @@ int f2fs_flush_device_cache(struct f2fs_sb_info *sbi)
 {
        int ret = 0, i;
 
-       if (!sbi->s_ndevs)
+       if (!f2fs_is_multi_device(sbi))
                return 0;
 
        for (i = 1; i < sbi->s_ndevs; i++) {
@@ -1367,9 +1368,12 @@ static int __queue_discard_cmd(struct f2fs_sb_info *sbi,
 {
        block_t lblkstart = blkstart;
 
+       if (!f2fs_bdev_support_discard(bdev))
+               return 0;
+
        trace_f2fs_queue_discard(bdev, blkstart, blklen);
 
-       if (sbi->s_ndevs) {
+       if (f2fs_is_multi_device(sbi)) {
                int devi = f2fs_target_device_index(sbi, blkstart);
 
                blkstart -= FDEV(devi).start_blk;
@@ -1732,42 +1736,36 @@ static int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi,
        block_t lblkstart = blkstart;
        int devi = 0;
 
-       if (sbi->s_ndevs) {
+       if (f2fs_is_multi_device(sbi)) {
                devi = f2fs_target_device_index(sbi, blkstart);
+               if (blkstart < FDEV(devi).start_blk ||
+                   blkstart > FDEV(devi).end_blk) {
+                       f2fs_msg(sbi->sb, KERN_ERR, "Invalid block %x",
+                                blkstart);
+                       return -EIO;
+               }
                blkstart -= FDEV(devi).start_blk;
        }
 
-       /*
-        * We need to know the type of the zone: for conventional zones,
-        * use regular discard if the drive supports it. For sequential
-        * zones, reset the zone write pointer.
-        */
-       switch (get_blkz_type(sbi, bdev, blkstart)) {
-
-       case BLK_ZONE_TYPE_CONVENTIONAL:
-               if (!blk_queue_discard(bdev_get_queue(bdev)))
-                       return 0;
-               return __queue_discard_cmd(sbi, bdev, lblkstart, blklen);
-       case BLK_ZONE_TYPE_SEQWRITE_REQ:
-       case BLK_ZONE_TYPE_SEQWRITE_PREF:
+       /* For sequential zones, reset the zone write pointer */
+       if (f2fs_blkz_is_seq(sbi, devi, blkstart)) {
                sector = SECTOR_FROM_BLOCK(blkstart);
                nr_sects = SECTOR_FROM_BLOCK(blklen);
 
                if (sector & (bdev_zone_sectors(bdev) - 1) ||
                                nr_sects != bdev_zone_sectors(bdev)) {
-                       f2fs_msg(sbi->sb, KERN_INFO,
-                               "(%d) %s: Unaligned discard attempted (block %x + %x)",
+                       f2fs_msg(sbi->sb, KERN_ERR,
+                               "(%d) %s: Unaligned zone reset attempted (block %x + %x)",
                                devi, sbi->s_ndevs ? FDEV(devi).path: "",
                                blkstart, blklen);
                        return -EIO;
                }
                trace_f2fs_issue_reset_zone(bdev, blkstart);
-               return blkdev_reset_zones(bdev, sector,
-                                         nr_sects, GFP_NOFS);
-       default:
-               /* Unknown zone type: broken device ? */
-               return -EIO;
+               return blkdev_reset_zones(bdev, sector, nr_sects, GFP_NOFS);
        }
+
+       /* For conventional zones, use regular discard if supported */
+       return __queue_discard_cmd(sbi, bdev, lblkstart, blklen);
 }
 #endif
 
@@ -1775,8 +1773,7 @@ static int __issue_discard_async(struct f2fs_sb_info *sbi,
                struct block_device *bdev, block_t blkstart, block_t blklen)
 {
 #ifdef CONFIG_BLK_DEV_ZONED
-       if (f2fs_sb_has_blkzoned(sbi) &&
-                               bdev_zoned_model(bdev) != BLK_ZONED_NONE)
+       if (f2fs_sb_has_blkzoned(sbi) && bdev_is_zoned(bdev))
                return __f2fs_issue_discard_zone(sbi, bdev, blkstart, blklen);
 #endif
        return __queue_discard_cmd(sbi, bdev, blkstart, blklen);
@@ -2172,8 +2169,11 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
                         * before, we must track that to know how much space we
                         * really have.
                         */
-                       if (f2fs_test_bit(offset, se->ckpt_valid_map))
+                       if (f2fs_test_bit(offset, se->ckpt_valid_map)) {
+                               spin_lock(&sbi->stat_lock);
                                sbi->unusable_block_count++;
+                               spin_unlock(&sbi->stat_lock);
+                       }
                }
 
                if (f2fs_test_and_clear_bit(offset, se->discard_map))
@@ -2220,7 +2220,7 @@ bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr)
        struct seg_entry *se;
        bool is_cp = false;
 
-       if (!is_valid_data_blkaddr(sbi, blkaddr))
+       if (!__is_valid_data_blkaddr(blkaddr))
                return true;
 
        down_read(&sit_i->sentry_lock);
@@ -3089,7 +3089,7 @@ static void update_device_state(struct f2fs_io_info *fio)
        struct f2fs_sb_info *sbi = fio->sbi;
        unsigned int devidx;
 
-       if (!sbi->s_ndevs)
+       if (!f2fs_is_multi_device(sbi))
                return;
 
        devidx = f2fs_target_device_index(sbi, fio->new_blkaddr);
@@ -3187,13 +3187,18 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)
 {
        int err;
        struct f2fs_sb_info *sbi = fio->sbi;
+       unsigned int segno;
 
        fio->new_blkaddr = fio->old_blkaddr;
        /* i/o temperature is needed for passing down write hints */
        __get_segment_type(fio);
 
-       f2fs_bug_on(sbi, !IS_DATASEG(get_seg_entry(sbi,
-                       GET_SEGNO(sbi, fio->new_blkaddr))->type));
+       segno = GET_SEGNO(sbi, fio->new_blkaddr);
+
+       if (!IS_DATASEG(get_seg_entry(sbi, segno)->type)) {
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+               return -EFAULT;
+       }
 
        stat_inc_inplace_blocks(fio->sbi);
 
@@ -3336,7 +3341,7 @@ void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr)
        if (!f2fs_post_read_required(inode))
                return;
 
-       if (!is_valid_data_blkaddr(sbi, blkaddr))
+       if (!__is_valid_data_blkaddr(blkaddr))
                return;
 
        cpage = find_lock_page(META_MAPPING(sbi), blkaddr);
index 5c7ed0442d6e25dd08caa73efb4a506ecfd2d894..429007b8036ebfe6e65af989b2666be4bd76610b 100644 (file)
@@ -82,7 +82,7 @@
        (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & ((sbi)->blocks_per_seg - 1))
 
 #define GET_SEGNO(sbi, blk_addr)                                       \
-       ((!is_valid_data_blkaddr(sbi, blk_addr)) ?                      \
+       ((!__is_valid_data_blkaddr(blk_addr)) ?                 \
        NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi),                 \
                GET_SEGNO_FROM_SEG0(sbi, blk_addr)))
 #define BLKS_PER_SEC(sbi)                                      \
@@ -656,14 +656,15 @@ static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
        f2fs_bug_on(sbi, segno > TOTAL_SEGS(sbi) - 1);
 }
 
-static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr)
+static inline void verify_fio_blkaddr(struct f2fs_io_info *fio)
 {
        struct f2fs_sb_info *sbi = fio->sbi;
 
-       if (__is_meta_io(fio))
-               verify_blkaddr(sbi, blk_addr, META_GENERIC);
-       else
-               verify_blkaddr(sbi, blk_addr, DATA_GENERIC);
+       if (__is_valid_data_blkaddr(fio->old_blkaddr))
+               verify_blkaddr(sbi, fio->old_blkaddr, __is_meta_io(fio) ?
+                                       META_GENERIC : DATA_GENERIC);
+       verify_blkaddr(sbi, fio->new_blkaddr, __is_meta_io(fio) ?
+                                       META_GENERIC : DATA_GENERIC_ENHANCE);
 }
 
 /*
@@ -672,7 +673,6 @@ static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr)
 static inline int check_block_count(struct f2fs_sb_info *sbi,
                int segno, struct f2fs_sit_entry *raw_sit)
 {
-#ifdef CONFIG_F2FS_CHECK_FS
        bool is_valid  = test_bit_le(0, raw_sit->valid_map) ? true : false;
        int valid_blocks = 0;
        int cur_pos = 0, next_pos;
@@ -699,7 +699,7 @@ static inline int check_block_count(struct f2fs_sb_info *sbi,
                set_sbi_flag(sbi, SBI_NEED_FSCK);
                return -EINVAL;
        }
-#endif
+
        /* check segment usage, and check boundary of a given segment number */
        if (unlikely(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg
                                        || segno > TOTAL_SEGS(sbi) - 1)) {
index 4c55d2ea9df3679d97325f0f4124e62930ac63d7..6b959bbb336a30543bd24a87e92d7cb28da1f274 100644 (file)
@@ -1019,7 +1019,7 @@ static void destroy_device_list(struct f2fs_sb_info *sbi)
        for (i = 0; i < sbi->s_ndevs; i++) {
                blkdev_put(FDEV(i).bdev, FMODE_EXCL);
 #ifdef CONFIG_BLK_DEV_ZONED
-               kvfree(FDEV(i).blkz_type);
+               kvfree(FDEV(i).blkz_seq);
 #endif
        }
        kvfree(sbi->devs);
@@ -1221,10 +1221,13 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_blocks = total_count - start_count;
        buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
                                                sbi->current_reserved_blocks;
+
+       spin_lock(&sbi->stat_lock);
        if (unlikely(buf->f_bfree <= sbi->unusable_block_count))
                buf->f_bfree = 0;
        else
                buf->f_bfree -= sbi->unusable_block_count;
+       spin_unlock(&sbi->stat_lock);
 
        if (buf->f_bfree > F2FS_OPTION(sbi).root_reserved_blocks)
                buf->f_bavail = buf->f_bfree -
@@ -1499,9 +1502,15 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
        mutex_lock(&sbi->gc_mutex);
        cpc.reason = CP_PAUSE;
        set_sbi_flag(sbi, SBI_CP_DISABLED);
-       f2fs_write_checkpoint(sbi, &cpc);
+       err = f2fs_write_checkpoint(sbi, &cpc);
+       if (err)
+               goto out_unlock;
 
+       spin_lock(&sbi->stat_lock);
        sbi->unusable_block_count = 0;
+       spin_unlock(&sbi->stat_lock);
+
+out_unlock:
        mutex_unlock(&sbi->gc_mutex);
 restore_flag:
        sbi->sb->s_flags = s_flags;     /* Restore MS_RDONLY status */
@@ -2271,7 +2280,7 @@ static const struct export_operations f2fs_export_ops = {
 static loff_t max_file_blocks(void)
 {
        loff_t result = 0;
-       loff_t leaf_count = ADDRS_PER_BLOCK;
+       loff_t leaf_count = DEF_ADDRS_PER_BLOCK;
 
        /*
         * note: previously, result is equal to (DEF_ADDRS_PER_INODE -
@@ -2449,7 +2458,7 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
        /* Currently, support only 4KB page cache size */
        if (F2FS_BLKSIZE != PAGE_SIZE) {
                f2fs_msg(sb, KERN_INFO,
-                       "Invalid page_cache_size (%lu), supports only 4KB\n",
+                       "Invalid page_cache_size (%lu), supports only 4KB",
                        PAGE_SIZE);
                return 1;
        }
@@ -2458,7 +2467,7 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
        blocksize = 1 << le32_to_cpu(raw_super->log_blocksize);
        if (blocksize != F2FS_BLKSIZE) {
                f2fs_msg(sb, KERN_INFO,
-                       "Invalid blocksize (%u), supports only 4KB\n",
+                       "Invalid blocksize (%u), supports only 4KB",
                        blocksize);
                return 1;
        }
@@ -2466,7 +2475,7 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
        /* check log blocks per segment */
        if (le32_to_cpu(raw_super->log_blocks_per_seg) != 9) {
                f2fs_msg(sb, KERN_INFO,
-                       "Invalid log blocks per segment (%u)\n",
+                       "Invalid log blocks per segment (%u)",
                        le32_to_cpu(raw_super->log_blocks_per_seg));
                return 1;
        }
@@ -2587,7 +2596,8 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
        unsigned int log_blocks_per_seg;
        unsigned int segment_count_main;
        unsigned int cp_pack_start_sum, cp_payload;
-       block_t user_block_count;
+       block_t user_block_count, valid_user_blocks;
+       block_t avail_node_count, valid_node_count;
        int i, j;
 
        total = le32_to_cpu(raw_super->segment_count);
@@ -2622,6 +2632,24 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
                return 1;
        }
 
+       valid_user_blocks = le64_to_cpu(ckpt->valid_block_count);
+       if (valid_user_blocks > user_block_count) {
+               f2fs_msg(sbi->sb, KERN_ERR,
+                       "Wrong valid_user_blocks: %u, user_block_count: %u",
+                       valid_user_blocks, user_block_count);
+               return 1;
+       }
+
+       valid_node_count = le32_to_cpu(ckpt->valid_node_count);
+       avail_node_count = sbi->total_node_count - sbi->nquota_files -
+                                               F2FS_RESERVED_NODE_NUM;
+       if (valid_node_count > avail_node_count) {
+               f2fs_msg(sbi->sb, KERN_ERR,
+                       "Wrong valid_node_count: %u, avail_node_count: %u",
+                       valid_node_count, avail_node_count);
+               return 1;
+       }
+
        main_segs = le32_to_cpu(raw_super->segment_count_main);
        blocks_per_seg = sbi->blocks_per_seg;
 
@@ -2793,9 +2821,11 @@ static int init_blkz_info(struct f2fs_sb_info *sbi, int devi)
        if (nr_sectors & (bdev_zone_sectors(bdev) - 1))
                FDEV(devi).nr_blkz++;
 
-       FDEV(devi).blkz_type = f2fs_kmalloc(sbi, FDEV(devi).nr_blkz,
-                                                               GFP_KERNEL);
-       if (!FDEV(devi).blkz_type)
+       FDEV(devi).blkz_seq = f2fs_kzalloc(sbi,
+                                       BITS_TO_LONGS(FDEV(devi).nr_blkz)
+                                       * sizeof(unsigned long),
+                                       GFP_KERNEL);
+       if (!FDEV(devi).blkz_seq)
                return -ENOMEM;
 
 #define F2FS_REPORT_NR_ZONES   4096
@@ -2822,7 +2852,8 @@ static int init_blkz_info(struct f2fs_sb_info *sbi, int devi)
                }
 
                for (i = 0; i < nr_zones; i++) {
-                       FDEV(devi).blkz_type[n] = zones[i].type;
+                       if (zones[i].type != BLK_ZONE_TYPE_CONVENTIONAL)
+                               set_bit(n, FDEV(devi).blkz_seq);
                        sector += zones[i].len;
                        n++;
                }
@@ -3105,7 +3136,7 @@ try_onemore:
 #ifndef CONFIG_BLK_DEV_ZONED
        if (f2fs_sb_has_blkzoned(sbi)) {
                f2fs_msg(sb, KERN_ERR,
-                        "Zoned block device support is not enabled\n");
+                        "Zoned block device support is not enabled");
                err = -EOPNOTSUPP;
                goto free_sb_buf;
        }
@@ -3350,10 +3381,17 @@ try_onemore:
                 * mount should be failed, when device has readonly mode, and
                 * previous checkpoint was not done by clean system shutdown.
                 */
-               if (bdev_read_only(sb->s_bdev) &&
-                               !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
-                       err = -EROFS;
-                       goto free_meta;
+               if (f2fs_hw_is_readonly(sbi)) {
+                       if (!is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
+                               err = -EROFS;
+                               f2fs_msg(sb, KERN_ERR,
+                                       "Need to recover fsync data, but "
+                                       "write access unavailable");
+                               goto free_meta;
+                       }
+                       f2fs_msg(sbi->sb, KERN_INFO, "write access "
+                               "unavailable, skipping recovery");
+                       goto reset_checkpoint;
                }
 
                if (need_fsck)
index 848a785abe253c0bfea21644407a842f317ea4b7..e791741d193b8b3623c3be613ebd61f432631e7c 100644 (file)
@@ -202,12 +202,17 @@ static inline const struct xattr_handler *f2fs_xattr_handler(int index)
        return handler;
 }
 
-static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
-                                       size_t len, const char *name)
+static struct f2fs_xattr_entry *__find_xattr(void *base_addr,
+                               void *last_base_addr, int index,
+                               size_t len, const char *name)
 {
        struct f2fs_xattr_entry *entry;
 
        list_for_each_xattr(entry, base_addr) {
+               if ((void *)(entry) + sizeof(__u32) > last_base_addr ||
+                       (void *)XATTR_NEXT_ENTRY(entry) > last_base_addr)
+                       return NULL;
+
                if (entry->e_name_index != index)
                        continue;
                if (entry->e_name_len != len)
@@ -297,20 +302,22 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
                                const char *name, struct f2fs_xattr_entry **xe,
                                void **base_addr, int *base_size)
 {
-       void *cur_addr, *txattr_addr, *last_addr = NULL;
+       void *cur_addr, *txattr_addr, *last_txattr_addr;
+       void *last_addr = NULL;
        nid_t xnid = F2FS_I(inode)->i_xattr_nid;
-       unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
        unsigned int inline_size = inline_xattr_size(inode);
        int err = 0;
 
-       if (!size && !inline_size)
+       if (!xnid && !inline_size)
                return -ENODATA;
 
-       *base_size = inline_size + size + XATTR_PADDING_SIZE;
+       *base_size = XATTR_SIZE(xnid, inode) + XATTR_PADDING_SIZE;
        txattr_addr = f2fs_kzalloc(F2FS_I_SB(inode), *base_size, GFP_NOFS);
        if (!txattr_addr)
                return -ENOMEM;
 
+       last_txattr_addr = (void *)txattr_addr + XATTR_SIZE(xnid, inode);
+
        /* read from inline xattr */
        if (inline_size) {
                err = read_inline_xattr(inode, ipage, txattr_addr);
@@ -337,7 +344,11 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
        else
                cur_addr = txattr_addr;
 
-       *xe = __find_xattr(cur_addr, index, len, name);
+       *xe = __find_xattr(cur_addr, last_txattr_addr, index, len, name);
+       if (!*xe) {
+               err = -EFAULT;
+               goto out;
+       }
 check:
        if (IS_XATTR_LAST_ENTRY(*xe)) {
                err = -ENODATA;
@@ -581,7 +592,8 @@ static int __f2fs_setxattr(struct inode *inode, int index,
                        struct page *ipage, int flags)
 {
        struct f2fs_xattr_entry *here, *last;
-       void *base_addr;
+       void *base_addr, *last_base_addr;
+       nid_t xnid = F2FS_I(inode)->i_xattr_nid;
        int found, newsize;
        size_t len;
        __u32 new_hsize;
@@ -605,8 +617,14 @@ static int __f2fs_setxattr(struct inode *inode, int index,
        if (error)
                return error;
 
+       last_base_addr = (void *)base_addr + XATTR_SIZE(xnid, inode);
+
        /* find entry with wanted name. */
-       here = __find_xattr(base_addr, index, len, name);
+       here = __find_xattr(base_addr, last_base_addr, index, len, name);
+       if (!here) {
+               error = -EFAULT;
+               goto exit;
+       }
 
        found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;
 
index 9172ee082ca830f9159f5a7ac73b3fca52cfa4e4..a90920e2f9498098dd6e4add9be1bf26b8a1f368 100644 (file)
@@ -71,6 +71,8 @@ struct f2fs_xattr_entry {
                                entry = XATTR_NEXT_ENTRY(entry))
 #define VALID_XATTR_BLOCK_SIZE (PAGE_SIZE - sizeof(struct node_footer))
 #define XATTR_PADDING_SIZE     (sizeof(__u32))
+#define XATTR_SIZE(x,i)                (((x) ? VALID_XATTR_BLOCK_SIZE : 0) +   \
+                                               (inline_xattr_size(i)))
 #define MIN_OFFSET(i)          XATTR_ALIGN(inline_xattr_size(i) +      \
                                                VALID_XATTR_BLOCK_SIZE)
 
index b3bed32946b1d862de5e6f5e42eff37f83f7df9b..0e3ed79fcc3f1bd69bcb214de76e1fa0864f14fc 100644 (file)
@@ -193,12 +193,17 @@ static int fat_file_release(struct inode *inode, struct file *filp)
 int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = filp->f_mapping->host;
-       int res, err;
+       int err;
+
+       err = __generic_file_fsync(filp, start, end, datasync);
+       if (err)
+               return err;
 
-       res = generic_file_fsync(filp, start, end, datasync);
        err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping);
+       if (err)
+               return err;
 
-       return res ? res : err;
+       return blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
 }
 
 
index 3bb9c0c8cbcc2f6d8ede5ccad01ca1bb903ad418..c2891e933ef17e2fe326bc3eef2a11cb4c982cd3 100644 (file)
@@ -92,7 +92,7 @@ static int fscontext_create_fd(struct fs_context *fc, unsigned int o_flags)
 {
        int fd;
 
-       fd = anon_inode_getfd("fscontext", &fscontext_fops, fc,
+       fd = anon_inode_getfd("[fscontext]", &fscontext_fops, fc,
                              O_RDWR | o_flags);
        if (fd < 0)
                put_fs_context(fc);
index fe80bea4ad8969e4b0cd7ed6488e57a49b4ff61d..14ce1e47f980e905b7ad806dbdcbeb6522ad8ffe 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/fs_context.h>
 
 #define FUSE_CTL_SUPER_MAGIC 0x65735543
 
@@ -317,7 +318,7 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc)
        drop_nlink(d_inode(fuse_control_sb->s_root));
 }
 
-static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent)
+static int fuse_ctl_fill_super(struct super_block *sb, struct fs_context *fctx)
 {
        static const struct tree_descr empty_descr = {""};
        struct fuse_conn *fc;
@@ -343,10 +344,19 @@ static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent)
        return 0;
 }
 
-static struct dentry *fuse_ctl_mount(struct file_system_type *fs_type,
-                       int flags, const char *dev_name, void *raw_data)
+static int fuse_ctl_get_tree(struct fs_context *fc)
 {
-       return mount_single(fs_type, flags, raw_data, fuse_ctl_fill_super);
+       return vfs_get_super(fc, vfs_get_single_super, fuse_ctl_fill_super);
+}
+
+static const struct fs_context_operations fuse_ctl_context_ops = {
+       .get_tree       = fuse_ctl_get_tree,
+};
+
+static int fuse_ctl_init_fs_context(struct fs_context *fc)
+{
+       fc->ops = &fuse_ctl_context_ops;
+       return 0;
 }
 
 static void fuse_ctl_kill_sb(struct super_block *sb)
@@ -365,7 +375,7 @@ static void fuse_ctl_kill_sb(struct super_block *sb)
 static struct file_system_type fuse_ctl_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "fusectl",
-       .mount          = fuse_ctl_mount,
+       .init_fs_context = fuse_ctl_init_fs_context,
        .kill_sb        = fuse_ctl_kill_sb,
 };
 MODULE_ALIAS_FS("fusectl");
index 55a26f3514671ebb2aa0ab5b6eefdf753afe1ee0..4b41df1d464264a420e327af3a7858c65e091645 100644 (file)
@@ -33,6 +33,8 @@
  * closed.
  */
 
+#define pr_fmt(fmt) "CUSE: " fmt
+
 #include <linux/fuse.h>
 #include <linux/cdev.h>
 #include <linux/device.h>
@@ -225,7 +227,7 @@ static int cuse_parse_one(char **pp, char *end, char **keyp, char **valp)
                return 0;
 
        if (end[-1] != '\0') {
-               printk(KERN_ERR "CUSE: info not properly terminated\n");
+               pr_err("info not properly terminated\n");
                return -EINVAL;
        }
 
@@ -242,7 +244,7 @@ static int cuse_parse_one(char **pp, char *end, char **keyp, char **valp)
                key = strstrip(key);
 
        if (!strlen(key)) {
-               printk(KERN_ERR "CUSE: zero length info key specified\n");
+               pr_err("zero length info key specified\n");
                return -EINVAL;
        }
 
@@ -282,12 +284,11 @@ static int cuse_parse_devinfo(char *p, size_t len, struct cuse_devinfo *devinfo)
                if (strcmp(key, "DEVNAME") == 0)
                        devinfo->name = val;
                else
-                       printk(KERN_WARNING "CUSE: unknown device info \"%s\"\n",
-                              key);
+                       pr_warn("unknown device info \"%s\"\n", key);
        }
 
        if (!devinfo->name || !strlen(devinfo->name)) {
-               printk(KERN_ERR "CUSE: DEVNAME unspecified\n");
+               pr_err("DEVNAME unspecified\n");
                return -EINVAL;
        }
 
@@ -341,7 +342,7 @@ static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
        else
                rc = register_chrdev_region(devt, 1, devinfo.name);
        if (rc) {
-               printk(KERN_ERR "CUSE: failed to register chrdev region\n");
+               pr_err("failed to register chrdev region\n");
                goto err;
        }
 
index 9971a35cf1ef66c960862ef550197814052b9267..24ea19cfe07e216b650aa407c4ad8ffff85fa6b1 100644 (file)
@@ -906,8 +906,8 @@ static int fuse_check_page(struct page *page)
               1 << PG_lru |
               1 << PG_active |
               1 << PG_reclaim))) {
-               printk(KERN_WARNING "fuse: trying to steal weird page\n");
-               printk(KERN_WARNING "  page=%p index=%li flags=%08lx, count=%i, mapcount=%i, mapping=%p\n", page, page->index, page->flags, page_count(page), page_mapcount(page), page->mapping);
+               pr_warn("trying to steal weird page\n");
+               pr_warn("  page=%p index=%li flags=%08lx, count=%i, mapcount=%i, mapping=%p\n", page, page->index, page->flags, page_count(page), page_mapcount(page), page->mapping);
                return 1;
        }
        return 0;
@@ -1317,6 +1317,16 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
        unsigned reqsize;
        unsigned int hash;
 
+       /*
+        * Require sane minimum read buffer - that has capacity for fixed part
+        * of any request header + negotated max_write room for data. If the
+        * requirement is not satisfied return EINVAL to the filesystem server
+        * to indicate that it is not following FUSE server/client contract.
+        * Don't dequeue / abort any request.
+        */
+       if (nbytes < max_t(size_t, FUSE_MIN_READ_BUFFER, 4096 + fc->max_write))
+               return -EINVAL;
+
  restart:
        spin_lock(&fiq->waitq.lock);
        err = -EAGAIN;
@@ -1749,7 +1759,7 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode,
        offset = outarg->offset & ~PAGE_MASK;
        file_size = i_size_read(inode);
 
-       num = outarg->size;
+       num = min(outarg->size, fc->max_write);
        if (outarg->offset > file_size)
                num = 0;
        else if (outarg->offset + num > file_size)
index 06096b60f1df23cb60234fe2fe3ce2ddc2b39c4e..3959f08279e6fe0deff9bb71bc7b08d56fd4fc77 100644 (file)
@@ -178,7 +178,9 @@ void fuse_finish_open(struct inode *inode, struct file *file)
 
        if (!(ff->open_flags & FOPEN_KEEP_CACHE))
                invalidate_inode_pages2(inode->i_mapping);
-       if (ff->open_flags & FOPEN_NONSEEKABLE)
+       if (ff->open_flags & FOPEN_STREAM)
+               stream_open(inode, file);
+       else if (ff->open_flags & FOPEN_NONSEEKABLE)
                nonseekable_open(inode, file);
        if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) {
                struct fuse_inode *fi = get_fuse_inode(inode);
@@ -462,7 +464,7 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end,
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.fh = ff->fh;
-       inarg.fsync_flags = datasync ? 1 : 0;
+       inarg.fsync_flags = datasync ? FUSE_FSYNC_FDATASYNC : 0;
        args.in.h.opcode = opcode;
        args.in.h.nodeid = get_node_id(inode);
        args.in.numargs = 1;
@@ -1586,7 +1588,7 @@ __acquires(fi->lock)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_inode *fi = get_fuse_inode(inode);
-       size_t crop = i_size_read(inode);
+       loff_t crop = i_size_read(inode);
        struct fuse_req *req;
 
        while (fi->writectr >= 0 && !list_empty(&fi->queued_writes)) {
@@ -2576,8 +2578,13 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
 #if BITS_PER_LONG == 32
        inarg.flags |= FUSE_IOCTL_32BIT;
 #else
-       if (flags & FUSE_IOCTL_COMPAT)
+       if (flags & FUSE_IOCTL_COMPAT) {
                inarg.flags |= FUSE_IOCTL_32BIT;
+#ifdef CONFIG_X86_X32
+               if (in_x32_syscall())
+                       inarg.flags |= FUSE_IOCTL_COMPAT_X32;
+#endif
+       }
 #endif
 
        /* assume all the iovs returned by client always fits in a page */
@@ -3044,6 +3051,13 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
                }
        }
 
+       if (!(mode & FALLOC_FL_KEEP_SIZE) &&
+           offset + length > i_size_read(inode)) {
+               err = inode_newsize_ok(inode, offset + length);
+               if (err)
+                       return err;
+       }
+
        if (!(mode & FALLOC_FL_KEEP_SIZE))
                set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
 
index 0920c0c032a087e5a8a08c0e6566a4001174ccc5..24dbca777775130536b97b984e4348e9068230d6 100644 (file)
@@ -9,6 +9,10 @@
 #ifndef _FS_FUSE_I_H
 #define _FS_FUSE_I_H
 
+#ifndef pr_fmt
+# define pr_fmt(fmt) "fuse: " fmt
+#endif
+
 #include <linux/fuse.h>
 #include <linux/fs.h>
 #include <linux/mount.h>
@@ -690,6 +694,9 @@ struct fuse_conn {
        /** Use enhanced/automatic page cache invalidation. */
        unsigned auto_inval_data:1;
 
+       /** Filesystem is fully reponsible for page cache invalidation. */
+       unsigned explicit_inval_data:1;
+
        /** Does the filesystem support readdirplus? */
        unsigned do_readdirplus:1;
 
index f485d09d14df7c8ebb2aa7c6f90612050fee7ec4..4bb885b0f03224e9f793612ea05f74c1d9c0038e 100644 (file)
@@ -81,14 +81,12 @@ struct fuse_forget_link *fuse_alloc_forget(void)
 
 static struct inode *fuse_alloc_inode(struct super_block *sb)
 {
-       struct inode *inode;
        struct fuse_inode *fi;
 
-       inode = kmem_cache_alloc(fuse_inode_cachep, GFP_KERNEL);
-       if (!inode)
+       fi = kmem_cache_alloc(fuse_inode_cachep, GFP_KERNEL);
+       if (!fi)
                return NULL;
 
-       fi = get_fuse_inode(inode);
        fi->i_time = 0;
        fi->inval_mask = 0;
        fi->nodeid = 0;
@@ -100,11 +98,11 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
        spin_lock_init(&fi->lock);
        fi->forget = fuse_alloc_forget();
        if (!fi->forget) {
-               kmem_cache_free(fuse_inode_cachep, inode);
+               kmem_cache_free(fuse_inode_cachep, fi);
                return NULL;
        }
 
-       return inode;
+       return &fi->inode;
 }
 
 static void fuse_free_inode(struct inode *inode)
@@ -233,7 +231,8 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
 
                if (oldsize != attr->size) {
                        truncate_pagecache(inode, attr->size);
-                       inval = true;
+                       if (!fc->explicit_inval_data)
+                               inval = true;
                } else if (fc->auto_inval_data) {
                        struct timespec64 new_mtime = {
                                .tv_sec = attr->mtime,
@@ -908,6 +907,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
                                fc->dont_mask = 1;
                        if (arg->flags & FUSE_AUTO_INVAL_DATA)
                                fc->auto_inval_data = 1;
+                       else if (arg->flags & FUSE_EXPLICIT_INVAL_DATA)
+                               fc->explicit_inval_data = 1;
                        if (arg->flags & FUSE_DO_READDIRPLUS) {
                                fc->do_readdirplus = 1;
                                if (arg->flags & FUSE_READDIRPLUS_AUTO)
@@ -969,7 +970,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
                FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT |
                FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL |
                FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS |
-               FUSE_NO_OPENDIR_SUPPORT;
+               FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA;
        req->in.h.opcode = FUSE_INIT;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(*arg);
@@ -1393,8 +1394,8 @@ static int __init fuse_init(void)
 {
        int res;
 
-       printk(KERN_INFO "fuse init (API version %i.%i)\n",
-              FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
+       pr_info("init (API version %i.%i)\n",
+               FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
 
        INIT_LIST_HEAD(&fuse_conn_list);
        res = fuse_fs_init();
@@ -1430,7 +1431,7 @@ static int __init fuse_init(void)
 
 static void __exit fuse_exit(void)
 {
-       printk(KERN_DEBUG "fuse exit\n");
+       pr_debug("exit\n");
 
        fuse_ctl_cleanup();
        fuse_sysfs_cleanup();
index 1787d295834e7add8e590cc76afa87f08ec533e0..08e4996adc231d61a26a7b588449bcd3fcd4f99c 100644 (file)
@@ -650,7 +650,6 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
        char ro[20];
        char spectator[20];
        char *envp[] = { ro, spectator, NULL };
-       int sysfs_frees_sdp = 0;
 
        sprintf(ro, "RDONLY=%d", sb_rdonly(sb));
        sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0);
@@ -661,8 +660,6 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
        if (error)
                goto fail_reg;
 
-       sysfs_frees_sdp = 1; /* Freeing sdp is now done by sysfs calling
-                               function gfs2_sbd_release. */
        error = sysfs_create_group(&sdp->sd_kobj, &tune_group);
        if (error)
                goto fail_reg;
@@ -687,10 +684,7 @@ fail_tune:
 fail_reg:
        free_percpu(sdp->sd_lkstats);
        fs_err(sdp, "error %d adding sysfs files\n", error);
-       if (sysfs_frees_sdp)
-               kobject_put(&sdp->sd_kobj);
-       else
-               kfree(sdp);
+       kobject_put(&sdp->sd_kobj);
        sb->s_fs_info = NULL;
        return error;
 }
index 33b8423ef0c994a307a3bb9bf8ec63121cfd64fb..f4295aa1935031439d3b1ded21c4c78a7dc5ed7a 100644 (file)
@@ -87,7 +87,7 @@ extern int do_mkdir(const char *file, int mode);
 extern int hostfs_do_rmdir(const char *file);
 extern int do_mknod(const char *file, int mode, unsigned int major,
                    unsigned int minor);
-extern int link_file(const char *from, const char *to);
+extern int link_file(const char *to, const char *from);
 extern int hostfs_do_readlink(char *file, char *buf, int size);
 extern int rename_file(char *from, char *to);
 extern int rename2_file(char *from, char *to, unsigned int flags);
index c74ef4426282ecf5d64bc0f63f3c5ed617a49e08..1dcc57189382bc5c16b6e06dd82d32a342ec944f 100644 (file)
@@ -440,9 +440,7 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
                        u32 hash;
 
                        index = page->index;
-                       hash = hugetlb_fault_mutex_hash(h, current->mm,
-                                                       &pseudo_vma,
-                                                       mapping, index, 0);
+                       hash = hugetlb_fault_mutex_hash(h, mapping, index, 0);
                        mutex_lock(&hugetlb_fault_mutex_table[hash]);
 
                        /*
@@ -499,8 +497,15 @@ static void hugetlbfs_evict_inode(struct inode *inode)
        struct resv_map *resv_map;
 
        remove_inode_hugepages(inode, 0, LLONG_MAX);
-       resv_map = (struct resv_map *)inode->i_mapping->private_data;
-       /* root inode doesn't have the resv_map, so we should check it */
+
+       /*
+        * Get the resv_map from the address space embedded in the inode.
+        * This is the address space which points to any resv_map allocated
+        * at inode creation time.  If this is a device special inode,
+        * i_mapping may not point to the original address space.
+        */
+       resv_map = (struct resv_map *)(&inode->i_data)->private_data;
+       /* Only regular and link inodes have associated reserve maps */
        if (resv_map)
                resv_map_release(&resv_map->refs);
        clear_inode(inode);
@@ -639,8 +644,7 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
                addr = index * hpage_size;
 
                /* mutex taken here, fault path and hole punch */
-               hash = hugetlb_fault_mutex_hash(h, mm, &pseudo_vma, mapping,
-                                               index, addr);
+               hash = hugetlb_fault_mutex_hash(h, mapping, index, addr);
                mutex_lock(&hugetlb_fault_mutex_table[hash]);
 
                /* See if already present in mapping to avoid alloc/free */
index 48ea3977012a903b9fbcdc79ca98a76ef05b68e8..310f8d17c53ec2724f29ef89869fb88e06278985 100644 (file)
@@ -231,7 +231,6 @@ struct io_ring_ctx {
        struct task_struct      *sqo_thread;    /* if using sq thread polling */
        struct mm_struct        *sqo_mm;
        wait_queue_head_t       sqo_wait;
-       unsigned                sqo_stop;
 
        struct {
                /* CQ ring */
@@ -329,9 +328,8 @@ struct io_kiocb {
 #define REQ_F_IOPOLL_COMPLETED 2       /* polled IO has completed */
 #define REQ_F_FIXED_FILE       4       /* ctx owns file */
 #define REQ_F_SEQ_PREV         8       /* sequential with previous */
-#define REQ_F_PREPPED          16      /* prep already done */
-#define REQ_F_IO_DRAIN         32      /* drain existing IO first */
-#define REQ_F_IO_DRAINED       64      /* drain done */
+#define REQ_F_IO_DRAIN         16      /* drain existing IO first */
+#define REQ_F_IO_DRAINED       32      /* drain done */
        u64                     user_data;
        u32                     error;  /* iopoll result from callback */
        u32                     sequence;
@@ -490,7 +488,7 @@ static struct io_uring_cqe *io_get_cqring(struct io_ring_ctx *ctx)
 }
 
 static void io_cqring_fill_event(struct io_ring_ctx *ctx, u64 ki_user_data,
-                                long res, unsigned ev_flags)
+                                long res)
 {
        struct io_uring_cqe *cqe;
 
@@ -503,7 +501,7 @@ static void io_cqring_fill_event(struct io_ring_ctx *ctx, u64 ki_user_data,
        if (cqe) {
                WRITE_ONCE(cqe->user_data, ki_user_data);
                WRITE_ONCE(cqe->res, res);
-               WRITE_ONCE(cqe->flags, ev_flags);
+               WRITE_ONCE(cqe->flags, 0);
        } else {
                unsigned overflow = READ_ONCE(ctx->cq_ring->overflow);
 
@@ -522,12 +520,12 @@ static void io_cqring_ev_posted(struct io_ring_ctx *ctx)
 }
 
 static void io_cqring_add_event(struct io_ring_ctx *ctx, u64 user_data,
-                               long res, unsigned ev_flags)
+                               long res)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&ctx->completion_lock, flags);
-       io_cqring_fill_event(ctx, user_data, res, ev_flags);
+       io_cqring_fill_event(ctx, user_data, res);
        io_commit_cqring(ctx);
        spin_unlock_irqrestore(&ctx->completion_lock, flags);
 
@@ -629,7 +627,7 @@ static void io_iopoll_complete(struct io_ring_ctx *ctx, unsigned int *nr_events,
                req = list_first_entry(done, struct io_kiocb, list);
                list_del(&req->list);
 
-               io_cqring_fill_event(ctx, req->user_data, req->error, 0);
+               io_cqring_fill_event(ctx, req->user_data, req->error);
                (*nr_events)++;
 
                if (refcount_dec_and_test(&req->refs)) {
@@ -777,7 +775,7 @@ static void io_complete_rw(struct kiocb *kiocb, long res, long res2)
 
        kiocb_end_write(kiocb);
 
-       io_cqring_add_event(req->ctx, req->user_data, res, 0);
+       io_cqring_add_event(req->ctx, req->user_data, res);
        io_put_req(req);
 }
 
@@ -896,9 +894,6 @@ static int io_prep_rw(struct io_kiocb *req, const struct sqe_submit *s,
 
        if (!req->file)
                return -EBADF;
-       /* For -EAGAIN retry, everything is already prepped */
-       if (req->flags & REQ_F_PREPPED)
-               return 0;
 
        if (force_nonblock && !io_file_supports_async(req->file))
                force_nonblock = false;
@@ -941,7 +936,6 @@ static int io_prep_rw(struct io_kiocb *req, const struct sqe_submit *s,
                        return -EINVAL;
                kiocb->ki_complete = io_complete_rw;
        }
-       req->flags |= REQ_F_PREPPED;
        return 0;
 }
 
@@ -1216,7 +1210,7 @@ static int io_nop(struct io_kiocb *req, u64 user_data)
        if (unlikely(ctx->flags & IORING_SETUP_IOPOLL))
                return -EINVAL;
 
-       io_cqring_add_event(ctx, user_data, err, 0);
+       io_cqring_add_event(ctx, user_data, err);
        io_put_req(req);
        return 0;
 }
@@ -1227,16 +1221,12 @@ static int io_prep_fsync(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 
        if (!req->file)
                return -EBADF;
-       /* Prep already done (EAGAIN retry) */
-       if (req->flags & REQ_F_PREPPED)
-               return 0;
 
        if (unlikely(ctx->flags & IORING_SETUP_IOPOLL))
                return -EINVAL;
        if (unlikely(sqe->addr || sqe->ioprio || sqe->buf_index))
                return -EINVAL;
 
-       req->flags |= REQ_F_PREPPED;
        return 0;
 }
 
@@ -1265,7 +1255,7 @@ static int io_fsync(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                                end > 0 ? end : LLONG_MAX,
                                fsync_flags & IORING_FSYNC_DATASYNC);
 
-       io_cqring_add_event(req->ctx, sqe->user_data, ret, 0);
+       io_cqring_add_event(req->ctx, sqe->user_data, ret);
        io_put_req(req);
        return 0;
 }
@@ -1277,16 +1267,12 @@ static int io_prep_sfr(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 
        if (!req->file)
                return -EBADF;
-       /* Prep already done (EAGAIN retry) */
-       if (req->flags & REQ_F_PREPPED)
-               return 0;
 
        if (unlikely(ctx->flags & IORING_SETUP_IOPOLL))
                return -EINVAL;
        if (unlikely(sqe->addr || sqe->ioprio || sqe->buf_index))
                return -EINVAL;
 
-       req->flags |= REQ_F_PREPPED;
        return ret;
 }
 
@@ -1313,7 +1299,7 @@ static int io_sync_file_range(struct io_kiocb *req,
 
        ret = sync_file_range(req->rw.ki_filp, sqe_off, sqe_len, flags);
 
-       io_cqring_add_event(req->ctx, sqe->user_data, ret, 0);
+       io_cqring_add_event(req->ctx, sqe->user_data, ret);
        io_put_req(req);
        return 0;
 }
@@ -1371,7 +1357,7 @@ static int io_poll_remove(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        }
        spin_unlock_irq(&ctx->completion_lock);
 
-       io_cqring_add_event(req->ctx, sqe->user_data, ret, 0);
+       io_cqring_add_event(req->ctx, sqe->user_data, ret);
        io_put_req(req);
        return 0;
 }
@@ -1380,7 +1366,7 @@ static void io_poll_complete(struct io_ring_ctx *ctx, struct io_kiocb *req,
                             __poll_t mask)
 {
        req->poll.done = true;
-       io_cqring_fill_event(ctx, req->user_data, mangle_poll(mask), 0);
+       io_cqring_fill_event(ctx, req->user_data, mangle_poll(mask));
        io_commit_cqring(ctx);
 }
 
@@ -1700,7 +1686,7 @@ restart:
                io_put_req(req);
 
                if (ret) {
-                       io_cqring_add_event(ctx, sqe->user_data, ret, 0);
+                       io_cqring_add_event(ctx, sqe->user_data, ret);
                        io_put_req(req);
                }
 
@@ -2005,7 +1991,7 @@ static int io_submit_sqes(struct io_ring_ctx *ctx, struct sqe_submit *sqes,
                        continue;
                }
 
-               io_cqring_add_event(ctx, sqes[i].sqe->user_data, ret, 0);
+               io_cqring_add_event(ctx, sqes[i].sqe->user_data, ret);
        }
 
        if (statep)
@@ -2028,7 +2014,7 @@ static int io_sq_thread(void *data)
        set_fs(USER_DS);
 
        timeout = inflight = 0;
-       while (!kthread_should_stop() && !ctx->sqo_stop) {
+       while (!kthread_should_park()) {
                bool all_fixed, mm_fault = false;
                int i;
 
@@ -2090,7 +2076,7 @@ static int io_sq_thread(void *data)
                        smp_mb();
 
                        if (!io_get_sqring(ctx, &sqes[0])) {
-                               if (kthread_should_stop()) {
+                               if (kthread_should_park()) {
                                        finish_wait(&ctx->sqo_wait, &wait);
                                        break;
                                }
@@ -2140,8 +2126,7 @@ static int io_sq_thread(void *data)
                mmput(cur_mm);
        }
 
-       if (kthread_should_park())
-               kthread_parkme();
+       kthread_parkme();
 
        return 0;
 }
@@ -2170,7 +2155,7 @@ static int io_ring_submit(struct io_ring_ctx *ctx, unsigned int to_submit)
 
                ret = io_submit_sqe(ctx, &s, statep);
                if (ret)
-                       io_cqring_add_event(ctx, s.sqe->user_data, ret, 0);
+                       io_cqring_add_event(ctx, s.sqe->user_data, ret);
        }
        io_commit_sqring(ctx);
 
@@ -2182,6 +2167,8 @@ static int io_ring_submit(struct io_ring_ctx *ctx, unsigned int to_submit)
 
 static unsigned io_cqring_events(struct io_cq_ring *ring)
 {
+       /* See comment at the top of this file */
+       smp_rmb();
        return READ_ONCE(ring->r.tail) - READ_ONCE(ring->r.head);
 }
 
@@ -2194,11 +2181,8 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
 {
        struct io_cq_ring *ring = ctx->cq_ring;
        sigset_t ksigmask, sigsaved;
-       DEFINE_WAIT(wait);
        int ret;
 
-       /* See comment at the top of this file */
-       smp_rmb();
        if (io_cqring_events(ring) >= min_events)
                return 0;
 
@@ -2216,23 +2200,9 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
                        return ret;
        }
 
-       do {
-               prepare_to_wait(&ctx->wait, &wait, TASK_INTERRUPTIBLE);
-
-               ret = 0;
-               /* See comment at the top of this file */
-               smp_rmb();
-               if (io_cqring_events(ring) >= min_events)
-                       break;
-
-               schedule();
-
+       ret = wait_event_interruptible(ctx->wait, io_cqring_events(ring) >= min_events);
+       if (ret == -ERESTARTSYS)
                ret = -EINTR;
-               if (signal_pending(current))
-                       break;
-       } while (1);
-
-       finish_wait(&ctx->wait, &wait);
 
        if (sig)
                restore_user_sigmask(sig, &sigsaved);
@@ -2273,8 +2243,11 @@ static int io_sqe_files_unregister(struct io_ring_ctx *ctx)
 static void io_sq_thread_stop(struct io_ring_ctx *ctx)
 {
        if (ctx->sqo_thread) {
-               ctx->sqo_stop = 1;
-               mb();
+               /*
+                * The park is a bit of a work-around, without it we get
+                * warning spews on shutdown with SQPOLL set and affinity
+                * set to a single CPU.
+                */
                kthread_park(ctx->sqo_thread);
                kthread_stop(ctx->sqo_thread);
                ctx->sqo_thread = NULL;
@@ -2467,10 +2440,11 @@ static int io_sq_offload_start(struct io_ring_ctx *ctx,
                        ctx->sq_thread_idle = HZ;
 
                if (p->flags & IORING_SETUP_SQ_AFF) {
-                       int cpu = array_index_nospec(p->sq_thread_cpu,
-                                                       nr_cpu_ids);
+                       int cpu = p->sq_thread_cpu;
 
                        ret = -EINVAL;
+                       if (cpu >= nr_cpu_ids)
+                               goto err;
                        if (!cpu_online(cpu))
                                goto err;
 
@@ -2697,8 +2671,9 @@ static int io_sqe_buffer_register(struct io_ring_ctx *ctx, void __user *arg,
 
                ret = 0;
                down_read(&current->mm->mmap_sem);
-               pret = get_user_pages_longterm(ubuf, nr_pages, FOLL_WRITE,
-                                               pages, vmas);
+               pret = get_user_pages(ubuf, nr_pages,
+                                     FOLL_WRITE | FOLL_LONGTERM,
+                                     pages, vmas);
                if (pret == nr_pages) {
                        /* don't support file backed memory */
                        for (j = 0; j < nr_pages; j++) {
index 70f520b41a195da5c0720ab8976be49e4ea532cd..5fb4f8910aab942201218471c060a0d5d29fff29 100644 (file)
@@ -56,7 +56,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
        u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4;
        int status;
 
-       status = lockd_up(nlm_init->net);
+       status = lockd_up(nlm_init->net, nlm_init->cred);
        if (status < 0)
                return ERR_PTR(status);
 
@@ -241,7 +241,7 @@ reclaimer(void *ptr)
        allow_signal(SIGKILL);
 
        down_write(&host->h_rwsem);
-       lockd_up(net);  /* note: this cannot fail as lockd is already running */
+       lockd_up(net, NULL);    /* note: this cannot fail as lockd is already running */
 
        dprintk("lockd: reclaiming locks for host %s\n", host->h_name);
 
index 346ed161756dbca1d712f1ac389888ddc0ea1bf6..3056f3a0c27079706230ea56b9a064b17d75cd76 100644 (file)
@@ -188,28 +188,31 @@ lockd(void *vrqstp)
 
 static int create_lockd_listener(struct svc_serv *serv, const char *name,
                                 struct net *net, const int family,
-                                const unsigned short port)
+                                const unsigned short port,
+                                const struct cred *cred)
 {
        struct svc_xprt *xprt;
 
        xprt = svc_find_xprt(serv, name, net, family, 0);
        if (xprt == NULL)
                return svc_create_xprt(serv, name, net, family, port,
-                                               SVC_SOCK_DEFAULTS);
+                                               SVC_SOCK_DEFAULTS, cred);
        svc_xprt_put(xprt);
        return 0;
 }
 
 static int create_lockd_family(struct svc_serv *serv, struct net *net,
-                              const int family)
+                              const int family, const struct cred *cred)
 {
        int err;
 
-       err = create_lockd_listener(serv, "udp", net, family, nlm_udpport);
+       err = create_lockd_listener(serv, "udp", net, family, nlm_udpport,
+                       cred);
        if (err < 0)
                return err;
 
-       return create_lockd_listener(serv, "tcp", net, family, nlm_tcpport);
+       return create_lockd_listener(serv, "tcp", net, family, nlm_tcpport,
+                       cred);
 }
 
 /*
@@ -222,16 +225,17 @@ static int create_lockd_family(struct svc_serv *serv, struct net *net,
  * Returns zero if all listeners are available; otherwise a
  * negative errno value is returned.
  */
-static int make_socks(struct svc_serv *serv, struct net *net)
+static int make_socks(struct svc_serv *serv, struct net *net,
+               const struct cred *cred)
 {
        static int warned;
        int err;
 
-       err = create_lockd_family(serv, net, PF_INET);
+       err = create_lockd_family(serv, net, PF_INET, cred);
        if (err < 0)
                goto out_err;
 
-       err = create_lockd_family(serv, net, PF_INET6);
+       err = create_lockd_family(serv, net, PF_INET6, cred);
        if (err < 0 && err != -EAFNOSUPPORT)
                goto out_err;
 
@@ -246,7 +250,8 @@ out_err:
        return err;
 }
 
-static int lockd_up_net(struct svc_serv *serv, struct net *net)
+static int lockd_up_net(struct svc_serv *serv, struct net *net,
+               const struct cred *cred)
 {
        struct lockd_net *ln = net_generic(net, lockd_net_id);
        int error;
@@ -258,7 +263,7 @@ static int lockd_up_net(struct svc_serv *serv, struct net *net)
        if (error)
                goto err_bind;
 
-       error = make_socks(serv, net);
+       error = make_socks(serv, net, cred);
        if (error < 0)
                goto err_bind;
        set_grace_period(net);
@@ -461,7 +466,7 @@ static struct svc_serv *lockd_create_svc(void)
 /*
  * Bring up the lockd process if it's not already up.
  */
-int lockd_up(struct net *net)
+int lockd_up(struct net *net, const struct cred *cred)
 {
        struct svc_serv *serv;
        int error;
@@ -474,7 +479,7 @@ int lockd_up(struct net *net)
                goto err_create;
        }
 
-       error = lockd_up_net(serv, net);
+       error = lockd_up_net(serv, net, cred);
        if (error < 0) {
                lockd_unregister_notifiers();
                goto err_put;
@@ -807,5 +812,7 @@ static struct svc_program   nlmsvc_program = {
        .pg_name                = "lockd",              /* service name */
        .pg_class               = "nfsd",               /* share authentication with nfsd */
        .pg_stats               = &nlmsvc_stats,        /* stats table */
-       .pg_authenticate = &lockd_authenticate  /* export authentication */
+       .pg_authenticate        = &lockd_authenticate,  /* export authentication */
+       .pg_init_request        = svc_generic_init_request,
+       .pg_rpcbind_set         = svc_generic_rpcbind_set,
 };
index d7c05dde4ed86ee316fe42a286b42fb06f36e22d..8af49f89ac2f0d3974972a57ff8d1164459e697c 100644 (file)
@@ -352,6 +352,12 @@ EXPORT_SYMBOL_GPL(locks_alloc_lock);
 
 void locks_release_private(struct file_lock *fl)
 {
+       BUG_ON(waitqueue_active(&fl->fl_wait));
+       BUG_ON(!list_empty(&fl->fl_list));
+       BUG_ON(!list_empty(&fl->fl_blocked_requests));
+       BUG_ON(!list_empty(&fl->fl_blocked_member));
+       BUG_ON(!hlist_unhashed(&fl->fl_link));
+
        if (fl->fl_ops) {
                if (fl->fl_ops->fl_release_private)
                        fl->fl_ops->fl_release_private(fl);
@@ -371,12 +377,6 @@ EXPORT_SYMBOL_GPL(locks_release_private);
 /* Free a lock which is not in use. */
 void locks_free_lock(struct file_lock *fl)
 {
-       BUG_ON(waitqueue_active(&fl->fl_wait));
-       BUG_ON(!list_empty(&fl->fl_list));
-       BUG_ON(!list_empty(&fl->fl_blocked_requests));
-       BUG_ON(!list_empty(&fl->fl_blocked_member));
-       BUG_ON(!hlist_unhashed(&fl->fl_link));
-
        locks_release_private(fl);
        kmem_cache_free(filelock_cache, fl);
 }
index 0b602a39dd7132f5ba3d678c0279ff68bd3e341b..7817ad94a6bae5417b3aa7dcfe631b61870b32f8 100644 (file)
@@ -41,11 +41,13 @@ static struct svc_program nfs4_callback_program;
 
 static int nfs4_callback_up_net(struct svc_serv *serv, struct net *net)
 {
+       const struct cred *cred = current_cred();
        int ret;
        struct nfs_net *nn = net_generic(net, nfs_net_id);
 
        ret = svc_create_xprt(serv, "tcp", net, PF_INET,
-                               nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
+                               nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS,
+                               cred);
        if (ret <= 0)
                goto out_err;
        nn->nfs_callback_tcpport = ret;
@@ -53,7 +55,8 @@ static int nfs4_callback_up_net(struct svc_serv *serv, struct net *net)
                nn->nfs_callback_tcpport, PF_INET, net->ns.inum);
 
        ret = svc_create_xprt(serv, "tcp", net, PF_INET6,
-                               nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
+                               nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS,
+                               cred);
        if (ret > 0) {
                nn->nfs_callback_tcpport6 = ret;
                dprintk("NFS: Callback listener port = %u (af %u, net %x)\n",
@@ -457,4 +460,6 @@ static struct svc_program nfs4_callback_program = {
        .pg_class = "nfs",                              /* authentication class */
        .pg_stats = &nfs4_callback_stats,
        .pg_authenticate = nfs_callback_authenticate,
+       .pg_init_request = svc_generic_init_request,
+       .pg_rpcbind_set = svc_generic_rpcbind_set,
 };
index 06233bfa6d73884ed7e52a30c64054c6b97b7457..73a5a5ea2976680559bc59293ccb554598557a80 100644 (file)
@@ -983,7 +983,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp)
 
 out_invalidcred:
        pr_warn_ratelimited("NFS: NFSv4 callback contains invalid cred\n");
-       return rpc_autherr_badcred;
+       return svc_return_autherr(rqstp, rpc_autherr_badcred);
 }
 
 /*
index da74c4c4a244cfd7ecd585f2b8a9e03e4c4b846c..3d04cb0b839eb36c8392ee9aca63bf8b935a6eef 100644 (file)
@@ -558,6 +558,7 @@ static int nfs_start_lockd(struct nfs_server *server)
                                        1 : 0,
                .net            = clp->cl_net,
                .nlmclnt_ops    = clp->cl_nfs_mod->rpc_ops->nlmclnt_ops,
+               .cred           = current_cred(),
        };
 
        if (nlm_init.nfs_version > 3)
index a7d3df85736dfba49c461ed54a17b5db0d3bfa44..e6a700f014528088ef0e15260b9a5d4d95822a64 100644 (file)
@@ -22,7 +22,7 @@ ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen,
        char *ip_addr = NULL;
        int ip_len;
 
-       ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL);
+       ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL, false);
        if (ip_len > 0)
                ret = rpc_pton(net, ip_addr, ip_len, sa, salen);
        else
index 802993d8912f79f6a70ab1661ff13ea41815bbbf..baa01956a5b3dda259202a0486e99f89a3543376 100644 (file)
@@ -570,13 +570,13 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
                err = get_int(&mesg, &an_int);
                if (err)
                        goto out3;
-               exp.ex_anon_uid= make_kuid(&init_user_ns, an_int);
+               exp.ex_anon_uid= make_kuid(current_user_ns(), an_int);
 
                /* anon gid */
                err = get_int(&mesg, &an_int);
                if (err)
                        goto out3;
-               exp.ex_anon_gid= make_kgid(&init_user_ns, an_int);
+               exp.ex_anon_gid= make_kgid(current_user_ns(), an_int);
 
                /* fsid */
                err = get_int(&mesg, &an_int);
@@ -1170,15 +1170,17 @@ static void show_secinfo(struct seq_file *m, struct svc_export *exp)
 static void exp_flags(struct seq_file *m, int flag, int fsid,
                kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fsloc)
 {
+       struct user_namespace *userns = m->file->f_cred->user_ns;
+
        show_expflags(m, flag, NFSEXP_ALLFLAGS);
        if (flag & NFSEXP_FSID)
                seq_printf(m, ",fsid=%d", fsid);
-       if (!uid_eq(anonu, make_kuid(&init_user_ns, (uid_t)-2)) &&
-           !uid_eq(anonu, make_kuid(&init_user_ns, 0x10000-2)))
-               seq_printf(m, ",anonuid=%u", from_kuid(&init_user_ns, anonu));
-       if (!gid_eq(anong, make_kgid(&init_user_ns, (gid_t)-2)) &&
-           !gid_eq(anong, make_kgid(&init_user_ns, 0x10000-2)))
-               seq_printf(m, ",anongid=%u", from_kgid(&init_user_ns, anong));
+       if (!uid_eq(anonu, make_kuid(userns, (uid_t)-2)) &&
+           !uid_eq(anonu, make_kuid(userns, 0x10000-2)))
+               seq_printf(m, ",anonuid=%u", from_kuid_munged(userns, anonu));
+       if (!gid_eq(anong, make_kgid(userns, (gid_t)-2)) &&
+           !gid_eq(anong, make_kgid(userns, 0x10000-2)))
+               seq_printf(m, ",anongid=%u", from_kgid_munged(userns, anong));
        if (fsloc && fsloc->locations_count > 0) {
                char *loctype = (fsloc->migrated) ? "refer" : "replicas";
                int i;
index 32cb8c027483e943d930117ba037c572597a7ee4..789abc4dd1d2592a819c09bfd1a10c9b17374b51 100644 (file)
@@ -104,6 +104,9 @@ struct nfsd_net {
        time_t nfsd4_grace;
        bool somebody_reclaimed;
 
+       bool track_reclaim_completes;
+       atomic_t nr_reclaim_complete;
+
        bool nfsd_net_up;
        bool lockd_up;
 
@@ -131,10 +134,18 @@ struct nfsd_net {
        u32             s2s_cp_cl_id;
        struct idr      s2s_cp_stateids;
        spinlock_t      s2s_cp_lock;
+
+       /*
+        * Version information
+        */
+       bool *nfsd_versions;
+       bool *nfsd4_minorversions;
 };
 
 /* Simple check to find out if a given net was properly initialized */
 #define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl)
 
+extern void nfsd_netns_free_versions(struct nfsd_net *nn);
+
 extern unsigned int nfsd_net_id;
 #endif /* __NFSD_NETNS_H__ */
index 8d789124ed3c18d187eea569e350e6d40a43ad7a..fcf31822c74c0b6e04616e45fbe915eacd9fc3ac 100644 (file)
@@ -96,7 +96,7 @@ decode_filename(__be32 *p, char **namp, unsigned int *lenp)
 }
 
 static __be32 *
-decode_sattr3(__be32 *p, struct iattr *iap)
+decode_sattr3(__be32 *p, struct iattr *iap, struct user_namespace *userns)
 {
        u32     tmp;
 
@@ -107,12 +107,12 @@ decode_sattr3(__be32 *p, struct iattr *iap)
                iap->ia_mode = ntohl(*p++);
        }
        if (*p++) {
-               iap->ia_uid = make_kuid(&init_user_ns, ntohl(*p++));
+               iap->ia_uid = make_kuid(userns, ntohl(*p++));
                if (uid_valid(iap->ia_uid))
                        iap->ia_valid |= ATTR_UID;
        }
        if (*p++) {
-               iap->ia_gid = make_kgid(&init_user_ns, ntohl(*p++));
+               iap->ia_gid = make_kgid(userns, ntohl(*p++));
                if (gid_valid(iap->ia_gid))
                        iap->ia_valid |= ATTR_GID;
        }
@@ -165,12 +165,13 @@ static __be32 *
 encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
              struct kstat *stat)
 {
+       struct user_namespace *userns = nfsd_user_namespace(rqstp);
        struct timespec ts;
        *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
        *p++ = htonl((u32) (stat->mode & S_IALLUGO));
        *p++ = htonl((u32) stat->nlink);
-       *p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid));
-       *p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid));
+       *p++ = htonl((u32) from_kuid_munged(userns, stat->uid));
+       *p++ = htonl((u32) from_kgid_munged(userns, stat->gid));
        if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {
                p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
        } else {
@@ -325,7 +326,7 @@ nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p)
        p = decode_fh(p, &args->fh);
        if (!p)
                return 0;
-       p = decode_sattr3(p, &args->attrs);
+       p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
 
        if ((args->check_guard = ntohl(*p++)) != 0) { 
                struct timespec time; 
@@ -455,7 +456,7 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p)
        switch (args->createmode = ntohl(*p++)) {
        case NFS3_CREATE_UNCHECKED:
        case NFS3_CREATE_GUARDED:
-               p = decode_sattr3(p, &args->attrs);
+               p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
                break;
        case NFS3_CREATE_EXCLUSIVE:
                args->verf = p;
@@ -476,7 +477,7 @@ nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p)
        if (!(p = decode_fh(p, &args->fh)) ||
            !(p = decode_filename(p, &args->name, &args->len)))
                return 0;
-       p = decode_sattr3(p, &args->attrs);
+       p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
 
        return xdr_argsize_check(rqstp, p);
 }
@@ -491,7 +492,7 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p)
        if (!(p = decode_fh(p, &args->ffh)) ||
            !(p = decode_filename(p, &args->fname, &args->flen)))
                return 0;
-       p = decode_sattr3(p, &args->attrs);
+       p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
 
        args->tlen = ntohl(*p++);
 
@@ -519,7 +520,7 @@ nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p)
 
        if (args->ftype == NF3BLK  || args->ftype == NF3CHR
         || args->ftype == NF3SOCK || args->ftype == NF3FIFO)
-               p = decode_sattr3(p, &args->attrs);
+               p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
 
        if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
                args->major = ntohl(*p++);
index 9b93e7a9a26df59fb31a9a3ad2a71a62b283fc07..397eb7820929b31f8827adc74c5aa1d8540f32d9 100644 (file)
@@ -1123,10 +1123,11 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
                rpc_restart_call_prepare(task);
                return;
        case 1:
-               break;
-       case -1:
-               /* Network partition? */
-               nfsd4_mark_cb_down(clp, task->tk_status);
+               switch (task->tk_status) {
+               case -EIO:
+               case -ETIMEDOUT:
+                       nfsd4_mark_cb_down(clp, task->tk_status);
+               }
                break;
        default:
                BUG();
index bf137fec33ff916558ca7c95e2662a46c5880163..2961016097ac5588c8162a7f854f37a1d1c1ad7f 100644 (file)
@@ -634,7 +634,7 @@ nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
                return nfserr_inval;
 
        status = do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, &id);
-       *uid = make_kuid(&init_user_ns, id);
+       *uid = make_kuid(nfsd_user_namespace(rqstp), id);
        if (!uid_valid(*uid))
                status = nfserr_badowner;
        return status;
@@ -651,7 +651,7 @@ nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
                return nfserr_inval;
 
        status = do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, &id);
-       *gid = make_kgid(&init_user_ns, id);
+       *gid = make_kgid(nfsd_user_namespace(rqstp), id);
        if (!gid_valid(*gid))
                status = nfserr_badowner;
        return status;
@@ -660,13 +660,13 @@ nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
 __be32 nfsd4_encode_user(struct xdr_stream *xdr, struct svc_rqst *rqstp,
                         kuid_t uid)
 {
-       u32 id = from_kuid(&init_user_ns, uid);
+       u32 id = from_kuid_munged(nfsd_user_namespace(rqstp), uid);
        return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_USER, id);
 }
 
 __be32 nfsd4_encode_group(struct xdr_stream *xdr, struct svc_rqst *rqstp,
                          kgid_t gid)
 {
-       u32 id = from_kgid(&init_user_ns, gid);
+       u32 id = from_kgid_munged(nfsd_user_namespace(rqstp), gid);
        return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_GROUP, id);
 }
index 44517fb5c0dedaa284dcae4cd83ef38dab3518eb..a79e24b79095a26f68aa9dee1fd91db400ff243f 100644 (file)
@@ -693,7 +693,7 @@ nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task)
                        ops->fence_client(ls);
                else
                        nfsd4_cb_layout_fail(ls);
-               return -1;
+               return 1;
        case -NFS4ERR_NOMATCHING_LAYOUT:
                trace_nfsd_layout_recall_done(&ls->ls_stid.sc_stateid);
                task->tk_status = 0;
index 4680ad3bf55b27108aa9d11a33fb73d02239b4ba..8beda999e1346e8917bc3b624f33fed22e710d7b 100644 (file)
@@ -1927,6 +1927,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
        struct nfsd4_compound_state *cstate = &resp->cstate;
        struct svc_fh *current_fh = &cstate->current_fh;
        struct svc_fh *save_fh = &cstate->save_fh;
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
        __be32          status;
 
        svcxdr_init_encode(rqstp, resp);
@@ -1949,7 +1950,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
         * According to RFC3010, this takes precedence over all other errors.
         */
        status = nfserr_minor_vers_mismatch;
-       if (nfsd_minorversion(args->minorversion, NFSD_TEST) <= 0)
+       if (nfsd_minorversion(nn, args->minorversion, NFSD_TEST) <= 0)
                goto out;
        status = nfserr_resource;
        if (args->opcnt > NFSD_MAX_OPS_PER_COMPOUND)
index 8c8563441208f368c23512044563354aeff08bab..87679557d0d6a1e05aa41ebbe7b1926fb3ae95bf 100644 (file)
@@ -168,13 +168,34 @@ legacy_recdir_name_error(struct nfs4_client *clp, int error)
        }
 }
 
+static void
+__nfsd4_create_reclaim_record_grace(struct nfs4_client *clp,
+               const char *dname, int len, struct nfsd_net *nn)
+{
+       struct xdr_netobj name;
+       struct nfs4_client_reclaim *crp;
+
+       name.data = kmemdup(dname, len, GFP_KERNEL);
+       if (!name.data) {
+               dprintk("%s: failed to allocate memory for name.data!\n",
+                       __func__);
+               return;
+       }
+       name.len = len;
+       crp = nfs4_client_to_reclaim(name, nn);
+       if (!crp) {
+               kfree(name.data);
+               return;
+       }
+       crp->cr_clp = clp;
+}
+
 static void
 nfsd4_create_clid_dir(struct nfs4_client *clp)
 {
        const struct cred *original_cred;
        char dname[HEXDIR_LEN];
        struct dentry *dir, *dentry;
-       struct nfs4_client_reclaim *crp;
        int status;
        struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
@@ -220,11 +241,9 @@ out_put:
 out_unlock:
        inode_unlock(d_inode(dir));
        if (status == 0) {
-               if (nn->in_grace) {
-                       crp = nfs4_client_to_reclaim(dname, nn);
-                       if (crp)
-                               crp->cr_clp = clp;
-               }
+               if (nn->in_grace)
+                       __nfsd4_create_reclaim_record_grace(clp, dname,
+                                       HEXDIR_LEN, nn);
                vfs_fsync(nn->rec_file, 0);
        } else {
                printk(KERN_ERR "NFSD: failed to write recovery record"
@@ -344,11 +363,30 @@ out_unlock:
        return status;
 }
 
+static void
+__nfsd4_remove_reclaim_record_grace(const char *dname, int len,
+               struct nfsd_net *nn)
+{
+       struct xdr_netobj name;
+       struct nfs4_client_reclaim *crp;
+
+       name.data = kmemdup(dname, len, GFP_KERNEL);
+       if (!name.data) {
+               dprintk("%s: failed to allocate memory for name.data!\n",
+                       __func__);
+               return;
+       }
+       name.len = len;
+       crp = nfsd4_find_reclaim_client(name, nn);
+       kfree(name.data);
+       if (crp)
+               nfs4_remove_reclaim_record(crp, nn);
+}
+
 static void
 nfsd4_remove_clid_dir(struct nfs4_client *clp)
 {
        const struct cred *original_cred;
-       struct nfs4_client_reclaim *crp;
        char dname[HEXDIR_LEN];
        int status;
        struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
@@ -373,12 +411,9 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
        nfs4_reset_creds(original_cred);
        if (status == 0) {
                vfs_fsync(nn->rec_file, 0);
-               if (nn->in_grace) {
-                       /* remove reclaim record */
-                       crp = nfsd4_find_reclaim_client(dname, nn);
-                       if (crp)
-                               nfs4_remove_reclaim_record(crp, nn);
-               }
+               if (nn->in_grace)
+                       __nfsd4_remove_reclaim_record_grace(dname,
+                                       HEXDIR_LEN, nn);
        }
 out_drop_write:
        mnt_drop_write_file(nn->rec_file);
@@ -392,14 +427,31 @@ static int
 purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
 {
        int status;
+       struct xdr_netobj name;
 
-       if (nfs4_has_reclaimed_state(child->d_name.name, nn))
+       if (child->d_name.len != HEXDIR_LEN - 1) {
+               printk("%s: illegal name %pd in recovery directory\n",
+                               __func__, child);
+               /* Keep trying; maybe the others are OK: */
                return 0;
+       }
+       name.data = kmemdup_nul(child->d_name.name, child->d_name.len, GFP_KERNEL);
+       if (!name.data) {
+               dprintk("%s: failed to allocate memory for name.data!\n",
+                       __func__);
+               goto out;
+       }
+       name.len = HEXDIR_LEN;
+       if (nfs4_has_reclaimed_state(name, nn))
+               goto out_free;
 
        status = vfs_rmdir(d_inode(parent), child);
        if (status)
                printk("failed to remove client recovery directory %pd\n",
                                child);
+out_free:
+       kfree(name.data);
+out:
        /* Keep trying, success or failure: */
        return 0;
 }
@@ -429,13 +481,24 @@ out:
 static int
 load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
 {
+       struct xdr_netobj name;
+
        if (child->d_name.len != HEXDIR_LEN - 1) {
-               printk("nfsd4: illegal name %pd in recovery directory\n",
-                               child);
+               printk("%s: illegal name %pd in recovery directory\n",
+                               __func__, child);
                /* Keep trying; maybe the others are OK: */
                return 0;
        }
-       nfs4_client_to_reclaim(child->d_name.name, nn);
+       name.data = kmemdup_nul(child->d_name.name, child->d_name.len, GFP_KERNEL);
+       if (!name.data) {
+               dprintk("%s: failed to allocate memory for name.data!\n",
+                       __func__);
+               goto out;
+       }
+       name.len = HEXDIR_LEN;
+       if (!nfs4_client_to_reclaim(name, nn))
+               kfree(name.data);
+out:
        return 0;
 }
 
@@ -564,6 +627,7 @@ nfsd4_legacy_tracking_init(struct net *net)
        status = nfsd4_load_reboot_recovery_data(net);
        if (status)
                goto err;
+       printk("NFSD: Using legacy client tracking operations.\n");
        return 0;
 
 err:
@@ -615,6 +679,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp)
        char dname[HEXDIR_LEN];
        struct nfs4_client_reclaim *crp;
        struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+       struct xdr_netobj name;
 
        /* did we already find that this client is stable? */
        if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
@@ -627,13 +692,22 @@ nfsd4_check_legacy_client(struct nfs4_client *clp)
        }
 
        /* look for it in the reclaim hashtable otherwise */
-       crp = nfsd4_find_reclaim_client(dname, nn);
+       name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL);
+       if (!name.data) {
+               dprintk("%s: failed to allocate memory for name.data!\n",
+                       __func__);
+               goto out_enoent;
+       }
+       name.len = HEXDIR_LEN;
+       crp = nfsd4_find_reclaim_client(name, nn);
+       kfree(name.data);
        if (crp) {
                set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
                crp->cr_clp = clp;
                return 0;
        }
 
+out_enoent:
        return -ENOENT;
 }
 
@@ -656,6 +730,7 @@ struct cld_net {
        spinlock_t               cn_lock;
        struct list_head         cn_list;
        unsigned int             cn_xid;
+       bool                     cn_has_legacy;
 };
 
 struct cld_upcall {
@@ -705,6 +780,40 @@ cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
        return ret;
 }
 
+static ssize_t
+__cld_pipe_inprogress_downcall(const struct cld_msg __user *cmsg,
+               struct nfsd_net *nn)
+{
+       uint8_t cmd;
+       struct xdr_netobj name;
+       uint16_t namelen;
+       struct cld_net *cn = nn->cld_net;
+
+       if (get_user(cmd, &cmsg->cm_cmd)) {
+               dprintk("%s: error when copying cmd from userspace", __func__);
+               return -EFAULT;
+       }
+       if (cmd == Cld_GraceStart) {
+               if (get_user(namelen, &cmsg->cm_u.cm_name.cn_len))
+                       return -EFAULT;
+               name.data = memdup_user(&cmsg->cm_u.cm_name.cn_id, namelen);
+               if (IS_ERR_OR_NULL(name.data))
+                       return -EFAULT;
+               name.len = namelen;
+               if (name.len > 5 && memcmp(name.data, "hash:", 5) == 0) {
+                       name.len = name.len - 5;
+                       memmove(name.data, name.data + 5, name.len);
+                       cn->cn_has_legacy = true;
+               }
+               if (!nfs4_client_to_reclaim(name, nn)) {
+                       kfree(name.data);
+                       return -EFAULT;
+               }
+               return sizeof(*cmsg);
+       }
+       return -EFAULT;
+}
+
 static ssize_t
 cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
 {
@@ -714,6 +823,7 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
        struct nfsd_net *nn = net_generic(file_inode(filp)->i_sb->s_fs_info,
                                                nfsd_net_id);
        struct cld_net *cn = nn->cld_net;
+       int16_t status;
 
        if (mlen != sizeof(*cmsg)) {
                dprintk("%s: got %zu bytes, expected %zu\n", __func__, mlen,
@@ -727,13 +837,24 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
                return -EFAULT;
        }
 
+       /*
+        * copy the status so we know whether to remove the upcall from the
+        * list (for -EINPROGRESS, we just want to make sure the xid is
+        * valid, not remove the upcall from the list)
+        */
+       if (get_user(status, &cmsg->cm_status)) {
+               dprintk("%s: error when copying status from userspace", __func__);
+               return -EFAULT;
+       }
+
        /* walk the list and find corresponding xid */
        cup = NULL;
        spin_lock(&cn->cn_lock);
        list_for_each_entry(tmp, &cn->cn_list, cu_list) {
                if (get_unaligned(&tmp->cu_msg.cm_xid) == xid) {
                        cup = tmp;
-                       list_del_init(&cup->cu_list);
+                       if (status != -EINPROGRESS)
+                               list_del_init(&cup->cu_list);
                        break;
                }
        }
@@ -745,6 +866,9 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
                return -EINVAL;
        }
 
+       if (status == -EINPROGRESS)
+               return __cld_pipe_inprogress_downcall(cmsg, nn);
+
        if (copy_from_user(&cup->cu_msg, src, mlen) != 0)
                return -EFAULT;
 
@@ -820,7 +944,7 @@ nfsd4_cld_unregister_net(struct net *net, struct rpc_pipe *pipe)
 
 /* Initialize rpc_pipefs pipe for communication with client tracking daemon */
 static int
-nfsd4_init_cld_pipe(struct net *net)
+__nfsd4_init_cld_pipe(struct net *net)
 {
        int ret;
        struct dentry *dentry;
@@ -851,6 +975,7 @@ nfsd4_init_cld_pipe(struct net *net)
        }
 
        cn->cn_pipe->dentry = dentry;
+       cn->cn_has_legacy = false;
        nn->cld_net = cn;
        return 0;
 
@@ -863,6 +988,17 @@ err:
        return ret;
 }
 
+static int
+nfsd4_init_cld_pipe(struct net *net)
+{
+       int status;
+
+       status = __nfsd4_init_cld_pipe(net);
+       if (!status)
+               printk("NFSD: Using old nfsdcld client tracking operations.\n");
+       return status;
+}
+
 static void
 nfsd4_remove_cld_pipe(struct net *net)
 {
@@ -991,9 +1127,14 @@ out_err:
                                "record from stable storage: %d\n", ret);
 }
 
-/* Check for presence of a record, and update its timestamp */
+/*
+ * For older nfsdcld's that do not allow us to "slurp" the clients
+ * from the tracking database during startup.
+ *
+ * Check for presence of a record, and update its timestamp
+ */
 static int
-nfsd4_cld_check(struct nfs4_client *clp)
+nfsd4_cld_check_v0(struct nfs4_client *clp)
 {
        int ret;
        struct cld_upcall *cup;
@@ -1026,8 +1167,84 @@ nfsd4_cld_check(struct nfs4_client *clp)
        return ret;
 }
 
+/*
+ * For newer nfsdcld's that allow us to "slurp" the clients
+ * from the tracking database during startup.
+ *
+ * Check for presence of a record in the reclaim_str_hashtbl
+ */
+static int
+nfsd4_cld_check(struct nfs4_client *clp)
+{
+       struct nfs4_client_reclaim *crp;
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+       struct cld_net *cn = nn->cld_net;
+       int status;
+       char dname[HEXDIR_LEN];
+       struct xdr_netobj name;
+
+       /* did we already find that this client is stable? */
+       if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
+               return 0;
+
+       /* look for it in the reclaim hashtable otherwise */
+       crp = nfsd4_find_reclaim_client(clp->cl_name, nn);
+       if (crp)
+               goto found;
+
+       if (cn->cn_has_legacy) {
+               status = nfs4_make_rec_clidname(dname, &clp->cl_name);
+               if (status)
+                       return -ENOENT;
+
+               name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL);
+               if (!name.data) {
+                       dprintk("%s: failed to allocate memory for name.data!\n",
+                               __func__);
+                       return -ENOENT;
+               }
+               name.len = HEXDIR_LEN;
+               crp = nfsd4_find_reclaim_client(name, nn);
+               kfree(name.data);
+               if (crp)
+                       goto found;
+
+       }
+       return -ENOENT;
+found:
+       crp->cr_clp = clp;
+       return 0;
+}
+
+static int
+nfsd4_cld_grace_start(struct nfsd_net *nn)
+{
+       int ret;
+       struct cld_upcall *cup;
+       struct cld_net *cn = nn->cld_net;
+
+       cup = alloc_cld_upcall(cn);
+       if (!cup) {
+               ret = -ENOMEM;
+               goto out_err;
+       }
+
+       cup->cu_msg.cm_cmd = Cld_GraceStart;
+       ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
+       if (!ret)
+               ret = cup->cu_msg.cm_status;
+
+       free_cld_upcall(cup);
+out_err:
+       if (ret)
+               dprintk("%s: Unable to get clients from userspace: %d\n",
+                       __func__, ret);
+       return ret;
+}
+
+/* For older nfsdcld's that need cm_gracetime */
 static void
-nfsd4_cld_grace_done(struct nfsd_net *nn)
+nfsd4_cld_grace_done_v0(struct nfsd_net *nn)
 {
        int ret;
        struct cld_upcall *cup;
@@ -1051,11 +1268,149 @@ out_err:
                printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
 }
 
-static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
+/*
+ * For newer nfsdcld's that do not need cm_gracetime.  We also need to call
+ * nfs4_release_reclaim() to clear out the reclaim_str_hashtbl.
+ */
+static void
+nfsd4_cld_grace_done(struct nfsd_net *nn)
+{
+       int ret;
+       struct cld_upcall *cup;
+       struct cld_net *cn = nn->cld_net;
+
+       cup = alloc_cld_upcall(cn);
+       if (!cup) {
+               ret = -ENOMEM;
+               goto out_err;
+       }
+
+       cup->cu_msg.cm_cmd = Cld_GraceDone;
+       ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
+       if (!ret)
+               ret = cup->cu_msg.cm_status;
+
+       free_cld_upcall(cup);
+out_err:
+       nfs4_release_reclaim(nn);
+       if (ret)
+               printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
+}
+
+static int
+nfs4_cld_state_init(struct net *net)
+{
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       int i;
+
+       nn->reclaim_str_hashtbl = kmalloc_array(CLIENT_HASH_SIZE,
+                                               sizeof(struct list_head),
+                                               GFP_KERNEL);
+       if (!nn->reclaim_str_hashtbl)
+               return -ENOMEM;
+
+       for (i = 0; i < CLIENT_HASH_SIZE; i++)
+               INIT_LIST_HEAD(&nn->reclaim_str_hashtbl[i]);
+       nn->reclaim_str_hashtbl_size = 0;
+       nn->track_reclaim_completes = true;
+       atomic_set(&nn->nr_reclaim_complete, 0);
+
+       return 0;
+}
+
+static void
+nfs4_cld_state_shutdown(struct net *net)
+{
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
+       nn->track_reclaim_completes = false;
+       kfree(nn->reclaim_str_hashtbl);
+}
+
+static bool
+cld_running(struct nfsd_net *nn)
+{
+       struct cld_net *cn = nn->cld_net;
+       struct rpc_pipe *pipe = cn->cn_pipe;
+
+       return pipe->nreaders || pipe->nwriters;
+}
+
+static int
+nfsd4_cld_tracking_init(struct net *net)
+{
+       int status;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       bool running;
+       int retries = 10;
+
+       status = nfs4_cld_state_init(net);
+       if (status)
+               return status;
+
+       status = __nfsd4_init_cld_pipe(net);
+       if (status)
+               goto err_shutdown;
+
+       /*
+        * rpc pipe upcalls take 30 seconds to time out, so we don't want to
+        * queue an upcall unless we know that nfsdcld is running (because we
+        * want this to fail fast so that nfsd4_client_tracking_init() can try
+        * the next client tracking method).  nfsdcld should already be running
+        * before nfsd is started, so the wait here is for nfsdcld to open the
+        * pipefs file we just created.
+        */
+       while (!(running = cld_running(nn)) && retries--)
+               msleep(100);
+
+       if (!running) {
+               status = -ETIMEDOUT;
+               goto err_remove;
+       }
+
+       status = nfsd4_cld_grace_start(nn);
+       if (status) {
+               if (status == -EOPNOTSUPP)
+                       printk(KERN_WARNING "NFSD: Please upgrade nfsdcld.\n");
+               nfs4_release_reclaim(nn);
+               goto err_remove;
+       } else
+               printk("NFSD: Using nfsdcld client tracking operations.\n");
+       return 0;
+
+err_remove:
+       nfsd4_remove_cld_pipe(net);
+err_shutdown:
+       nfs4_cld_state_shutdown(net);
+       return status;
+}
+
+static void
+nfsd4_cld_tracking_exit(struct net *net)
+{
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
+       nfs4_release_reclaim(nn);
+       nfsd4_remove_cld_pipe(net);
+       nfs4_cld_state_shutdown(net);
+}
+
+/* For older nfsdcld's */
+static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v0 = {
        .init           = nfsd4_init_cld_pipe,
        .exit           = nfsd4_remove_cld_pipe,
        .create         = nfsd4_cld_create,
        .remove         = nfsd4_cld_remove,
+       .check          = nfsd4_cld_check_v0,
+       .grace_done     = nfsd4_cld_grace_done_v0,
+};
+
+/* For newer nfsdcld's */
+static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
+       .init           = nfsd4_cld_tracking_init,
+       .exit           = nfsd4_cld_tracking_exit,
+       .create         = nfsd4_cld_create,
+       .remove         = nfsd4_cld_remove,
        .check          = nfsd4_cld_check,
        .grace_done     = nfsd4_cld_grace_done,
 };
@@ -1267,6 +1622,8 @@ nfsd4_umh_cltrack_init(struct net *net)
 
        ret = nfsd4_umh_cltrack_upcall("init", NULL, grace_start, NULL);
        kfree(grace_start);
+       if (!ret)
+               printk("NFSD: Using UMH upcall client tracking operations.\n");
        return ret;
 }
 
@@ -1416,9 +1773,20 @@ nfsd4_client_tracking_init(struct net *net)
        if (nn->client_tracking_ops)
                goto do_init;
 
+       /* First, try to use nfsdcld */
+       nn->client_tracking_ops = &nfsd4_cld_tracking_ops;
+       status = nn->client_tracking_ops->init(net);
+       if (!status)
+               return status;
+       if (status != -ETIMEDOUT) {
+               nn->client_tracking_ops = &nfsd4_cld_tracking_ops_v0;
+               status = nn->client_tracking_ops->init(net);
+               if (!status)
+                       return status;
+       }
+
        /*
-        * First, try a UMH upcall. It should succeed or fail quickly, so
-        * there's little harm in trying that first.
+        * Next, try the UMH upcall.
         */
        nn->client_tracking_ops = &nfsd4_umh_tracking_ops;
        status = nn->client_tracking_ops->init(net);
@@ -1426,25 +1794,23 @@ nfsd4_client_tracking_init(struct net *net)
                return status;
 
        /*
-        * See if the recoverydir exists and is a directory. If it is,
-        * then use the legacy ops.
+        * Finally, See if the recoverydir exists and is a directory.
+        * If it is, then use the legacy ops.
         */
        nn->client_tracking_ops = &nfsd4_legacy_tracking_ops;
        status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path);
        if (!status) {
                status = d_is_dir(path.dentry);
                path_put(&path);
-               if (status)
-                       goto do_init;
+               if (!status) {
+                       status = -EINVAL;
+                       goto out;
+               }
        }
 
-       /* Finally, try to use nfsdcld */
-       nn->client_tracking_ops = &nfsd4_cld_tracking_ops;
-       printk(KERN_WARNING "NFSD: the nfsdcld client tracking upcall will be "
-                       "removed in 3.10. Please transition to using "
-                       "nfsdcltrack.\n");
 do_init:
        status = nn->client_tracking_ops->init(net);
+out:
        if (status) {
                printk(KERN_WARNING "NFSD: Unable to initialize client "
                                    "recovery tracking! (%d)\n", status);
index eca4a23f93c885d0df1ab5f9f7a4d8064a13d9f1..618e66078ee5da6802e99921241d65e87371370a 100644 (file)
@@ -77,6 +77,7 @@ static u64 current_sessionid = 1;
 /* forward declarations */
 static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
 static void nfs4_free_ol_stateid(struct nfs4_stid *stid);
+void nfsd4_end_grace(struct nfsd_net *nn);
 
 /* Locking: */
 
@@ -1067,9 +1068,9 @@ static unsigned int clientid_hashval(u32 id)
        return id & CLIENT_HASH_MASK;
 }
 
-static unsigned int clientstr_hashval(const char *name)
+static unsigned int clientstr_hashval(struct xdr_netobj name)
 {
-       return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
+       return opaque_hashval(name.data, 8) & CLIENT_HASH_MASK;
 }
 
 /*
@@ -1997,6 +1998,22 @@ destroy_client(struct nfs4_client *clp)
        __destroy_client(clp);
 }
 
+static void inc_reclaim_complete(struct nfs4_client *clp)
+{
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+       if (!nn->track_reclaim_completes)
+               return;
+       if (!nfsd4_find_reclaim_client(clp->cl_name, nn))
+               return;
+       if (atomic_inc_return(&nn->nr_reclaim_complete) ==
+                       nn->reclaim_str_hashtbl_size) {
+               printk(KERN_INFO "NFSD: all clients done reclaiming, ending NFSv4 grace period (net %x)\n",
+                               clp->net->ns.inum);
+               nfsd4_end_grace(nn);
+       }
+}
+
 static void expire_client(struct nfs4_client *clp)
 {
        unhash_client(clp);
@@ -2048,11 +2065,6 @@ compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2)
        return memcmp(o1->data, o2->data, o1->len);
 }
 
-static int same_name(const char *n1, const char *n2)
-{
-       return 0 == memcmp(n1, n2, HEXDIR_LEN);
-}
-
 static int
 same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
 {
@@ -3354,6 +3366,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp,
 
        status = nfs_ok;
        nfsd4_client_record_create(cstate->session->se_client);
+       inc_reclaim_complete(cstate->session->se_client);
 out:
        return status;
 }
@@ -3958,6 +3971,9 @@ static int nfsd4_cb_recall_done(struct nfsd4_callback *cb,
        switch (task->tk_status) {
        case 0:
                return 1;
+       case -NFS4ERR_DELAY:
+               rpc_delay(task, 2 * HZ);
+               return 0;
        case -EBADHANDLE:
        case -NFS4ERR_BAD_STATEID:
                /*
@@ -3970,7 +3986,7 @@ static int nfsd4_cb_recall_done(struct nfsd4_callback *cb,
                }
                /*FALLTHRU*/
        default:
-               return -1;
+               return 1;
        }
 }
 
@@ -4713,7 +4729,6 @@ nfsd4_end_grace(struct nfsd_net *nn)
        if (nn->grace_ended)
                return;
 
-       dprintk("NFSD: end of grace period\n");
        nn->grace_ended = true;
        /*
         * If the server goes down again right now, an NFSv4
@@ -4749,6 +4764,10 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
        unsigned long double_grace_period_end = nn->boot_time +
                                                2 * nn->nfsd4_lease;
 
+       if (nn->track_reclaim_completes &&
+                       atomic_read(&nn->nr_reclaim_complete) ==
+                       nn->reclaim_str_hashtbl_size)
+               return false;
        if (!nn->somebody_reclaimed)
                return false;
        nn->somebody_reclaimed = false;
@@ -4779,6 +4798,7 @@ nfs4_laundromat(struct nfsd_net *nn)
                new_timeo = 0;
                goto out;
        }
+       dprintk("NFSD: end of grace period\n");
        nfsd4_end_grace(nn);
        INIT_LIST_HEAD(&reaplist);
        spin_lock(&nn->client_lock);
@@ -6458,7 +6478,7 @@ alloc_reclaim(void)
 }
 
 bool
-nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn)
+nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn)
 {
        struct nfs4_client_reclaim *crp;
 
@@ -6468,20 +6488,24 @@ nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn)
 
 /*
  * failure => all reset bets are off, nfserr_no_grace...
+ *
+ * The caller is responsible for freeing name.data if NULL is returned (it
+ * will be freed in nfs4_remove_reclaim_record in the normal case).
  */
 struct nfs4_client_reclaim *
-nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn)
+nfs4_client_to_reclaim(struct xdr_netobj name, struct nfsd_net *nn)
 {
        unsigned int strhashval;
        struct nfs4_client_reclaim *crp;
 
-       dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
+       dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", name.len, name.data);
        crp = alloc_reclaim();
        if (crp) {
                strhashval = clientstr_hashval(name);
                INIT_LIST_HEAD(&crp->cr_strhash);
                list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]);
-               memcpy(crp->cr_recdir, name, HEXDIR_LEN);
+               crp->cr_name.data = name.data;
+               crp->cr_name.len = name.len;
                crp->cr_clp = NULL;
                nn->reclaim_str_hashtbl_size++;
        }
@@ -6492,6 +6516,7 @@ void
 nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn)
 {
        list_del(&crp->cr_strhash);
+       kfree(crp->cr_name.data);
        kfree(crp);
        nn->reclaim_str_hashtbl_size--;
 }
@@ -6515,16 +6540,16 @@ nfs4_release_reclaim(struct nfsd_net *nn)
 /*
  * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
 struct nfs4_client_reclaim *
-nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn)
+nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn)
 {
        unsigned int strhashval;
        struct nfs4_client_reclaim *crp = NULL;
 
-       dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir);
+       dprintk("NFSD: nfs4_find_reclaim_client for name %.*s\n", name.len, name.data);
 
-       strhashval = clientstr_hashval(recdir);
+       strhashval = clientstr_hashval(name);
        list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) {
-               if (same_name(crp->cr_recdir, recdir)) {
+               if (compare_blob(&crp->cr_name, &name) == 0) {
                        return crp;
                }
        }
@@ -7262,10 +7287,19 @@ nfs4_state_start_net(struct net *net)
                return ret;
        locks_start_grace(net, &nn->nfsd4_manager);
        nfsd4_client_tracking_init(net);
+       if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0)
+               goto skip_grace;
        printk(KERN_INFO "NFSD: starting %ld-second grace period (net %x)\n",
               nn->nfsd4_grace, net->ns.inum);
        queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ);
        return 0;
+
+skip_grace:
+       printk(KERN_INFO "NFSD: no clients to reclaim, skipping NFSv4 grace period (net %x)\n",
+                       net->ns.inum);
+       queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_lease * HZ);
+       nfsd4_end_grace(nn);
+       return 0;
 }
 
 /* initialization to perform when the nfsd service is started: */
index 3de42a7290939eac692cc57b66d4e515576641ec..52c4f6daa649a5f4cdf8562c27457efea712fdbe 100644 (file)
@@ -521,6 +521,7 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access
 static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs)
 {
        DECODE_HEAD;
+       struct user_namespace *userns = nfsd_user_namespace(argp->rqstp);
        u32 dummy, uid, gid;
        char *machine_name;
        int i;
@@ -563,8 +564,8 @@ static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_
                        dummy = be32_to_cpup(p++);
                        READ_BUF(dummy * 4);
                        if (cbs->flavor == (u32)(-1)) {
-                               kuid_t kuid = make_kuid(&init_user_ns, uid);
-                               kgid_t kgid = make_kgid(&init_user_ns, gid);
+                               kuid_t kuid = make_kuid(userns, uid);
+                               kgid_t kgid = make_kgid(userns, gid);
                                if (uid_valid(kuid) && gid_valid(kgid)) {
                                        cbs->uid = kuid;
                                        cbs->gid = kgid;
@@ -2420,8 +2421,10 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
        __be32 status;
        int err;
        struct nfs4_acl *acl = NULL;
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
        void *context = NULL;
        int contextlen;
+#endif
        bool contextsupport = false;
        struct nfsd4_compoundres *resp = rqstp->rq_resp;
        u32 minorversion = resp->cstate.minorversion;
@@ -2906,12 +2909,14 @@ out_acl:
                        *p++ = cpu_to_be32(NFS4_CHANGE_TYPE_IS_TIME_METADATA);
        }
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
        if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
                status = nfsd4_encode_security_label(xdr, rqstp, context,
                                                                contextlen);
                if (status)
                        goto out;
        }
+#endif
 
        attrlen = htonl(xdr->buf->len - attrlen_offset - 4);
        write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4);
index f2feb2d11baefaeb3de3ce0559f5d5690af6f2a2..90972e1fd7850346661e3afbcc41ee7bad212d9d 100644 (file)
@@ -439,7 +439,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
                        return rv;
                if (newthreads < 0)
                        return -EINVAL;
-               rv = nfsd_svc(newthreads, net);
+               rv = nfsd_svc(newthreads, net, file->f_cred);
                if (rv < 0)
                        return rv;
        } else
@@ -537,14 +537,14 @@ out_free:
 }
 
 static ssize_t
-nfsd_print_version_support(char *buf, int remaining, const char *sep,
-               unsigned vers, int minor)
+nfsd_print_version_support(struct nfsd_net *nn, char *buf, int remaining,
+               const char *sep, unsigned vers, int minor)
 {
        const char *format = minor < 0 ? "%s%c%u" : "%s%c%u.%u";
-       bool supported = !!nfsd_vers(vers, NFSD_TEST);
+       bool supported = !!nfsd_vers(nn, vers, NFSD_TEST);
 
        if (vers == 4 && minor >= 0 &&
-           !nfsd_minorversion(minor, NFSD_TEST))
+           !nfsd_minorversion(nn, minor, NFSD_TEST))
                supported = false;
        if (minor == 0 && supported)
                /*
@@ -599,20 +599,20 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
                        switch(num) {
                        case 2:
                        case 3:
-                               nfsd_vers(num, cmd);
+                               nfsd_vers(nn, num, cmd);
                                break;
                        case 4:
                                if (*minorp == '.') {
-                                       if (nfsd_minorversion(minor, cmd) < 0)
+                                       if (nfsd_minorversion(nn, minor, cmd) < 0)
                                                return -EINVAL;
-                               } else if ((cmd == NFSD_SET) != nfsd_vers(num, NFSD_TEST)) {
+                               } else if ((cmd == NFSD_SET) != nfsd_vers(nn, num, NFSD_TEST)) {
                                        /*
                                         * Either we have +4 and no minors are enabled,
                                         * or we have -4 and at least one minor is enabled.
                                         * In either case, propagate 'cmd' to all minors.
                                         */
                                        minor = 0;
-                                       while (nfsd_minorversion(minor, cmd) >= 0)
+                                       while (nfsd_minorversion(nn, minor, cmd) >= 0)
                                                minor++;
                                }
                                break;
@@ -624,7 +624,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
                /* If all get turned off, turn them back on, as
                 * having no versions is BAD
                 */
-               nfsd_reset_versions();
+               nfsd_reset_versions(nn);
        }
 
        /* Now write current state into reply buffer */
@@ -633,12 +633,12 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
        remaining = SIMPLE_TRANSACTION_LIMIT;
        for (num=2 ; num <= 4 ; num++) {
                int minor;
-               if (!nfsd_vers(num, NFSD_AVAIL))
+               if (!nfsd_vers(nn, num, NFSD_AVAIL))
                        continue;
 
                minor = -1;
                do {
-                       len = nfsd_print_version_support(buf, remaining,
+                       len = nfsd_print_version_support(nn, buf, remaining,
                                        sep, num, minor);
                        if (len >= remaining)
                                goto out;
@@ -717,7 +717,7 @@ static ssize_t __write_ports_names(char *buf, struct net *net)
  * a socket of a supported family/protocol, and we use it as an
  * nfsd listener.
  */
-static ssize_t __write_ports_addfd(char *buf, struct net *net)
+static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred *cred)
 {
        char *mesg = buf;
        int fd, err;
@@ -736,7 +736,7 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net)
        if (err != 0)
                return err;
 
-       err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
+       err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred);
        if (err < 0) {
                nfsd_destroy(net);
                return err;
@@ -751,7 +751,7 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net)
  * A transport listener is added by writing it's transport name and
  * a port number.
  */
-static ssize_t __write_ports_addxprt(char *buf, struct net *net)
+static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cred *cred)
 {
        char transport[16];
        struct svc_xprt *xprt;
@@ -769,12 +769,12 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net)
                return err;
 
        err = svc_create_xprt(nn->nfsd_serv, transport, net,
-                               PF_INET, port, SVC_SOCK_ANONYMOUS);
+                               PF_INET, port, SVC_SOCK_ANONYMOUS, cred);
        if (err < 0)
                goto out_err;
 
        err = svc_create_xprt(nn->nfsd_serv, transport, net,
-                               PF_INET6, port, SVC_SOCK_ANONYMOUS);
+                               PF_INET6, port, SVC_SOCK_ANONYMOUS, cred);
        if (err < 0 && err != -EAFNOSUPPORT)
                goto out_close;
 
@@ -799,10 +799,10 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size,
                return __write_ports_names(buf, net);
 
        if (isdigit(buf[0]))
-               return __write_ports_addfd(buf, net);
+               return __write_ports_addfd(buf, net, file->f_cred);
 
        if (isalpha(buf[0]))
-               return __write_ports_addxprt(buf, net);
+               return __write_ports_addxprt(buf, net, file->f_cred);
 
        return -EINVAL;
 }
@@ -1239,9 +1239,12 @@ static __net_init int nfsd_init_net(struct net *net)
        retval = nfsd_idmap_init(net);
        if (retval)
                goto out_idmap_error;
+       nn->nfsd_versions = NULL;
+       nn->nfsd4_minorversions = NULL;
        nn->nfsd4_lease = 90;   /* default lease time */
        nn->nfsd4_grace = 90;
        nn->somebody_reclaimed = false;
+       nn->track_reclaim_completes = false;
        nn->clverifier_counter = prandom_u32();
        nn->clientid_counter = prandom_u32();
        nn->s2s_cp_cl_id = nn->clientid_counter++;
@@ -1260,6 +1263,7 @@ static __net_exit void nfsd_exit_net(struct net *net)
 {
        nfsd_idmap_shutdown(net);
        nfsd_export_shutdown(net);
+       nfsd_netns_free_versions(net_generic(net, nfsd_net_id));
 }
 
 static struct pernet_operations nfsd_net_ops = {
index 066899929863c020f8a87a94f0399b770c46eb78..24187b5dd638c5e3e858bd2de74b8f9daaa30a80 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/nfs3.h>
 #include <linux/nfs4.h>
 #include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/svc_xprt.h>
 #include <linux/sunrpc/msg_prot.h>
 
 #include <uapi/linux/nfsd/debug.h>
@@ -73,7 +74,7 @@ extern const struct seq_operations nfs_exports_op;
 /*
  * Function prototypes.
  */
-int            nfsd_svc(int nrservs, struct net *net);
+int            nfsd_svc(int nrservs, struct net *net, const struct cred *cred);
 int            nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
 
 int            nfsd_nrthreads(struct net *);
@@ -98,10 +99,12 @@ extern const struct svc_version nfsd_acl_version3;
 #endif
 #endif
 
+struct nfsd_net;
+
 enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
-int nfsd_vers(int vers, enum vers_op change);
-int nfsd_minorversion(u32 minorversion, enum vers_op change);
-void nfsd_reset_versions(void);
+int nfsd_vers(struct nfsd_net *nn, int vers, enum vers_op change);
+int nfsd_minorversion(struct nfsd_net *nn, u32 minorversion, enum vers_op change);
+void nfsd_reset_versions(struct nfsd_net *nn);
 int nfsd_create_serv(struct net *net);
 
 extern int nfsd_max_blksize;
@@ -110,6 +113,12 @@ static inline int nfsd_v4client(struct svc_rqst *rq)
 {
        return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4;
 }
+static inline struct user_namespace *
+nfsd_user_namespace(const struct svc_rqst *rqstp)
+{
+       const struct cred *cred = rqstp->rq_xprt->xpt_cred;
+       return cred ? cred->user_ns : &init_user_ns;
+}
 
 /* 
  * NFSv4 State
index 89cb484f1cfbeccde41d872298c7e08aaadd5b87..18d94ea984ba4add43d1af0ca90ed155fc67c700 100644 (file)
 
 extern struct svc_program      nfsd_program;
 static int                     nfsd(void *vrqstp);
+#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+static int                     nfsd_acl_rpcbind_set(struct net *,
+                                                    const struct svc_program *,
+                                                    u32, int,
+                                                    unsigned short,
+                                                    unsigned short);
+static __be32                  nfsd_acl_init_request(struct svc_rqst *,
+                                               const struct svc_program *,
+                                               struct svc_process_info *);
+#endif
+static int                     nfsd_rpcbind_set(struct net *,
+                                                const struct svc_program *,
+                                                u32, int,
+                                                unsigned short,
+                                                unsigned short);
+static __be32                  nfsd_init_request(struct svc_rqst *,
+                                               const struct svc_program *,
+                                               struct svc_process_info *);
 
 /*
  * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members
@@ -86,6 +104,8 @@ static struct svc_program    nfsd_acl_program = {
        .pg_class               = "nfsd",
        .pg_stats               = &nfsd_acl_svcstats,
        .pg_authenticate        = &svc_set_client,
+       .pg_init_request        = nfsd_acl_init_request,
+       .pg_rpcbind_set         = nfsd_acl_rpcbind_set,
 };
 
 static struct svc_stat nfsd_acl_svcstats = {
@@ -105,7 +125,6 @@ static const struct svc_version *nfsd_version[] = {
 
 #define NFSD_MINVERS           2
 #define NFSD_NRVERS            ARRAY_SIZE(nfsd_version)
-static const struct svc_version *nfsd_versions[NFSD_NRVERS];
 
 struct svc_program             nfsd_program = {
 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
@@ -113,77 +132,136 @@ struct svc_program               nfsd_program = {
 #endif
        .pg_prog                = NFS_PROGRAM,          /* program number */
        .pg_nvers               = NFSD_NRVERS,          /* nr of entries in nfsd_version */
-       .pg_vers                = nfsd_versions,        /* version table */
+       .pg_vers                = nfsd_version        /* version table */
        .pg_name                = "nfsd",               /* program name */
        .pg_class               = "nfsd",               /* authentication class */
        .pg_stats               = &nfsd_svcstats,       /* version table */
        .pg_authenticate        = &svc_set_client,      /* export authentication */
-
+       .pg_init_request        = nfsd_init_request,
+       .pg_rpcbind_set         = nfsd_rpcbind_set,
 };
 
-static bool nfsd_supported_minorversions[NFSD_SUPPORTED_MINOR_VERSION + 1] = {
-       [0] = 1,
-       [1] = 1,
-       [2] = 1,
-};
+static bool
+nfsd_support_version(int vers)
+{
+       if (vers >= NFSD_MINVERS && vers < NFSD_NRVERS)
+               return nfsd_version[vers] != NULL;
+       return false;
+}
+
+static bool *
+nfsd_alloc_versions(void)
+{
+       bool *vers = kmalloc_array(NFSD_NRVERS, sizeof(bool), GFP_KERNEL);
+       unsigned i;
+
+       if (vers) {
+               /* All compiled versions are enabled by default */
+               for (i = 0; i < NFSD_NRVERS; i++)
+                       vers[i] = nfsd_support_version(i);
+       }
+       return vers;
+}
+
+static bool *
+nfsd_alloc_minorversions(void)
+{
+       bool *vers = kmalloc_array(NFSD_SUPPORTED_MINOR_VERSION + 1,
+                       sizeof(bool), GFP_KERNEL);
+       unsigned i;
+
+       if (vers) {
+               /* All minor versions are enabled by default */
+               for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++)
+                       vers[i] = nfsd_support_version(4);
+       }
+       return vers;
+}
 
-int nfsd_vers(int vers, enum vers_op change)
+void
+nfsd_netns_free_versions(struct nfsd_net *nn)
+{
+       kfree(nn->nfsd_versions);
+       kfree(nn->nfsd4_minorversions);
+       nn->nfsd_versions = NULL;
+       nn->nfsd4_minorversions = NULL;
+}
+
+static void
+nfsd_netns_init_versions(struct nfsd_net *nn)
+{
+       if (!nn->nfsd_versions) {
+               nn->nfsd_versions = nfsd_alloc_versions();
+               nn->nfsd4_minorversions = nfsd_alloc_minorversions();
+               if (!nn->nfsd_versions || !nn->nfsd4_minorversions)
+                       nfsd_netns_free_versions(nn);
+       }
+}
+
+int nfsd_vers(struct nfsd_net *nn, int vers, enum vers_op change)
 {
        if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS)
                return 0;
        switch(change) {
        case NFSD_SET:
-               nfsd_versions[vers] = nfsd_version[vers];
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
-               if (vers < NFSD_ACL_NRVERS)
-                       nfsd_acl_versions[vers] = nfsd_acl_version[vers];
-#endif
+               if (nn->nfsd_versions)
+                       nn->nfsd_versions[vers] = nfsd_support_version(vers);
                break;
        case NFSD_CLEAR:
-               nfsd_versions[vers] = NULL;
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
-               if (vers < NFSD_ACL_NRVERS)
-                       nfsd_acl_versions[vers] = NULL;
-#endif
+               nfsd_netns_init_versions(nn);
+               if (nn->nfsd_versions)
+                       nn->nfsd_versions[vers] = false;
                break;
        case NFSD_TEST:
-               return nfsd_versions[vers] != NULL;
+               if (nn->nfsd_versions)
+                       return nn->nfsd_versions[vers];
+               /* Fallthrough */
        case NFSD_AVAIL:
-               return nfsd_version[vers] != NULL;
+               return nfsd_support_version(vers);
        }
        return 0;
 }
 
 static void
-nfsd_adjust_nfsd_versions4(void)
+nfsd_adjust_nfsd_versions4(struct nfsd_net *nn)
 {
        unsigned i;
 
        for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++) {
-               if (nfsd_supported_minorversions[i])
+               if (nn->nfsd4_minorversions[i])
                        return;
        }
-       nfsd_vers(4, NFSD_CLEAR);
+       nfsd_vers(nn, 4, NFSD_CLEAR);
 }
 
-int nfsd_minorversion(u32 minorversion, enum vers_op change)
+int nfsd_minorversion(struct nfsd_net *nn, u32 minorversion, enum vers_op change)
 {
        if (minorversion > NFSD_SUPPORTED_MINOR_VERSION &&
            change != NFSD_AVAIL)
                return -1;
+
        switch(change) {
        case NFSD_SET:
-               nfsd_supported_minorversions[minorversion] = true;
-               nfsd_vers(4, NFSD_SET);
+               if (nn->nfsd4_minorversions) {
+                       nfsd_vers(nn, 4, NFSD_SET);
+                       nn->nfsd4_minorversions[minorversion] =
+                               nfsd_vers(nn, 4, NFSD_TEST);
+               }
                break;
        case NFSD_CLEAR:
-               nfsd_supported_minorversions[minorversion] = false;
-               nfsd_adjust_nfsd_versions4();
+               nfsd_netns_init_versions(nn);
+               if (nn->nfsd4_minorversions) {
+                       nn->nfsd4_minorversions[minorversion] = false;
+                       nfsd_adjust_nfsd_versions4(nn);
+               }
                break;
        case NFSD_TEST:
-               return nfsd_supported_minorversions[minorversion];
+               if (nn->nfsd4_minorversions)
+                       return nn->nfsd4_minorversions[minorversion];
+               return nfsd_vers(nn, 4, NFSD_TEST);
        case NFSD_AVAIL:
-               return minorversion <= NFSD_SUPPORTED_MINOR_VERSION;
+               return minorversion <= NFSD_SUPPORTED_MINOR_VERSION &&
+                       nfsd_vers(nn, 4, NFSD_AVAIL);
        }
        return 0;
 }
@@ -205,7 +283,7 @@ int nfsd_nrthreads(struct net *net)
        return rv;
 }
 
-static int nfsd_init_socks(struct net *net)
+static int nfsd_init_socks(struct net *net, const struct cred *cred)
 {
        int error;
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
@@ -214,12 +292,12 @@ static int nfsd_init_socks(struct net *net)
                return 0;
 
        error = svc_create_xprt(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT,
-                                       SVC_SOCK_DEFAULTS);
+                                       SVC_SOCK_DEFAULTS, cred);
        if (error < 0)
                return error;
 
        error = svc_create_xprt(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT,
-                                       SVC_SOCK_DEFAULTS);
+                                       SVC_SOCK_DEFAULTS, cred);
        if (error < 0)
                return error;
 
@@ -265,16 +343,12 @@ static void nfsd_shutdown_generic(void)
        nfsd_racache_shutdown();
 }
 
-static bool nfsd_needs_lockd(void)
+static bool nfsd_needs_lockd(struct nfsd_net *nn)
 {
-#if defined(CONFIG_NFSD_V3)
-       return (nfsd_versions[2] != NULL) || (nfsd_versions[3] != NULL);
-#else
-       return (nfsd_versions[2] != NULL);
-#endif
+       return nfsd_vers(nn, 2, NFSD_TEST) || nfsd_vers(nn, 3, NFSD_TEST);
 }
 
-static int nfsd_startup_net(int nrservs, struct net *net)
+static int nfsd_startup_net(int nrservs, struct net *net, const struct cred *cred)
 {
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
        int ret;
@@ -285,12 +359,12 @@ static int nfsd_startup_net(int nrservs, struct net *net)
        ret = nfsd_startup_generic(nrservs);
        if (ret)
                return ret;
-       ret = nfsd_init_socks(net);
+       ret = nfsd_init_socks(net, cred);
        if (ret)
                goto out_socks;
 
-       if (nfsd_needs_lockd() && !nn->lockd_up) {
-               ret = lockd_up(net);
+       if (nfsd_needs_lockd(nn) && !nn->lockd_up) {
+               ret = lockd_up(net, cred);
                if (ret)
                        goto out_socks;
                nn->lockd_up = 1;
@@ -422,20 +496,20 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
        nfsd_export_flush(net);
 }
 
-void nfsd_reset_versions(void)
+void nfsd_reset_versions(struct nfsd_net *nn)
 {
        int i;
 
        for (i = 0; i < NFSD_NRVERS; i++)
-               if (nfsd_vers(i, NFSD_TEST))
+               if (nfsd_vers(nn, i, NFSD_TEST))
                        return;
 
        for (i = 0; i < NFSD_NRVERS; i++)
                if (i != 4)
-                       nfsd_vers(i, NFSD_SET);
+                       nfsd_vers(nn, i, NFSD_SET);
                else {
                        int minor = 0;
-                       while (nfsd_minorversion(minor, NFSD_SET) >= 0)
+                       while (nfsd_minorversion(nn, minor, NFSD_SET) >= 0)
                                minor++;
                }
 }
@@ -503,7 +577,7 @@ int nfsd_create_serv(struct net *net)
        }
        if (nfsd_max_blksize == 0)
                nfsd_max_blksize = nfsd_get_default_max_blksize();
-       nfsd_reset_versions();
+       nfsd_reset_versions(nn);
        nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
                                                &nfsd_thread_sv_ops);
        if (nn->nfsd_serv == NULL)
@@ -623,7 +697,7 @@ int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
  * this is the first time nrservs is nonzero.
  */
 int
-nfsd_svc(int nrservs, struct net *net)
+nfsd_svc(int nrservs, struct net *net, const struct cred *cred)
 {
        int     error;
        bool    nfsd_up_before;
@@ -645,7 +719,7 @@ nfsd_svc(int nrservs, struct net *net)
 
        nfsd_up_before = nn->nfsd_net_up;
 
-       error = nfsd_startup_net(nrservs, net);
+       error = nfsd_startup_net(nrservs, net, cred);
        if (error)
                goto out_destroy;
        error = nn->nfsd_serv->sv_ops->svo_setup(nn->nfsd_serv,
@@ -667,6 +741,101 @@ out:
        return error;
 }
 
+#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+static bool
+nfsd_support_acl_version(int vers)
+{
+       if (vers >= NFSD_ACL_MINVERS && vers < NFSD_ACL_NRVERS)
+               return nfsd_acl_version[vers] != NULL;
+       return false;
+}
+
+static int
+nfsd_acl_rpcbind_set(struct net *net, const struct svc_program *progp,
+                    u32 version, int family, unsigned short proto,
+                    unsigned short port)
+{
+       if (!nfsd_support_acl_version(version) ||
+           !nfsd_vers(net_generic(net, nfsd_net_id), version, NFSD_TEST))
+               return 0;
+       return svc_generic_rpcbind_set(net, progp, version, family,
+                       proto, port);
+}
+
+static __be32
+nfsd_acl_init_request(struct svc_rqst *rqstp,
+                     const struct svc_program *progp,
+                     struct svc_process_info *ret)
+{
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+       int i;
+
+       if (likely(nfsd_support_acl_version(rqstp->rq_vers) &&
+           nfsd_vers(nn, rqstp->rq_vers, NFSD_TEST)))
+               return svc_generic_init_request(rqstp, progp, ret);
+
+       ret->mismatch.lovers = NFSD_ACL_NRVERS;
+       for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) {
+               if (nfsd_support_acl_version(rqstp->rq_vers) &&
+                   nfsd_vers(nn, i, NFSD_TEST)) {
+                       ret->mismatch.lovers = i;
+                       break;
+               }
+       }
+       if (ret->mismatch.lovers == NFSD_ACL_NRVERS)
+               return rpc_prog_unavail;
+       ret->mismatch.hivers = NFSD_ACL_MINVERS;
+       for (i = NFSD_ACL_NRVERS - 1; i >= NFSD_ACL_MINVERS; i--) {
+               if (nfsd_support_acl_version(rqstp->rq_vers) &&
+                   nfsd_vers(nn, i, NFSD_TEST)) {
+                       ret->mismatch.hivers = i;
+                       break;
+               }
+       }
+       return rpc_prog_mismatch;
+}
+#endif
+
+static int
+nfsd_rpcbind_set(struct net *net, const struct svc_program *progp,
+                u32 version, int family, unsigned short proto,
+                unsigned short port)
+{
+       if (!nfsd_vers(net_generic(net, nfsd_net_id), version, NFSD_TEST))
+               return 0;
+       return svc_generic_rpcbind_set(net, progp, version, family,
+                       proto, port);
+}
+
+static __be32
+nfsd_init_request(struct svc_rqst *rqstp,
+                 const struct svc_program *progp,
+                 struct svc_process_info *ret)
+{
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+       int i;
+
+       if (likely(nfsd_vers(nn, rqstp->rq_vers, NFSD_TEST)))
+               return svc_generic_init_request(rqstp, progp, ret);
+
+       ret->mismatch.lovers = NFSD_NRVERS;
+       for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) {
+               if (nfsd_vers(nn, i, NFSD_TEST)) {
+                       ret->mismatch.lovers = i;
+                       break;
+               }
+       }
+       if (ret->mismatch.lovers == NFSD_NRVERS)
+               return rpc_prog_unavail;
+       ret->mismatch.hivers = NFSD_MINVERS;
+       for (i = NFSD_NRVERS - 1; i >= NFSD_MINVERS; i--) {
+               if (nfsd_vers(nn, i, NFSD_TEST)) {
+                       ret->mismatch.hivers = i;
+                       break;
+               }
+       }
+       return rpc_prog_mismatch;
+}
 
 /*
  * This is the NFS server kernel thread
index 6b2e8b73d36e3a4459e6b76bf057543884673a86..b51fe515f06fe443839085ec033b733ca357e60d 100644 (file)
@@ -71,7 +71,7 @@ decode_filename(__be32 *p, char **namp, unsigned int *lenp)
 }
 
 static __be32 *
-decode_sattr(__be32 *p, struct iattr *iap)
+decode_sattr(__be32 *p, struct iattr *iap, struct user_namespace *userns)
 {
        u32     tmp, tmp1;
 
@@ -86,12 +86,12 @@ decode_sattr(__be32 *p, struct iattr *iap)
                iap->ia_mode = tmp;
        }
        if ((tmp = ntohl(*p++)) != (u32)-1) {
-               iap->ia_uid = make_kuid(&init_user_ns, tmp);
+               iap->ia_uid = make_kuid(userns, tmp);
                if (uid_valid(iap->ia_uid))
                        iap->ia_valid |= ATTR_UID;
        }
        if ((tmp = ntohl(*p++)) != (u32)-1) {
-               iap->ia_gid = make_kgid(&init_user_ns, tmp);
+               iap->ia_gid = make_kgid(userns, tmp);
                if (gid_valid(iap->ia_gid))
                        iap->ia_valid |= ATTR_GID;
        }
@@ -129,6 +129,7 @@ static __be32 *
 encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
             struct kstat *stat)
 {
+       struct user_namespace *userns = nfsd_user_namespace(rqstp);
        struct dentry   *dentry = fhp->fh_dentry;
        int type;
        struct timespec64 time;
@@ -139,8 +140,8 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
        *p++ = htonl(nfs_ftypes[type >> 12]);
        *p++ = htonl((u32) stat->mode);
        *p++ = htonl((u32) stat->nlink);
-       *p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid));
-       *p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid));
+       *p++ = htonl((u32) from_kuid_munged(userns, stat->uid));
+       *p++ = htonl((u32) from_kgid_munged(userns, stat->gid));
 
        if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) {
                *p++ = htonl(NFS_MAXPATHLEN);
@@ -216,7 +217,7 @@ nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p)
        p = decode_fh(p, &args->fh);
        if (!p)
                return 0;
-       p = decode_sattr(p, &args->attrs);
+       p = decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
 
        return xdr_argsize_check(rqstp, p);
 }
@@ -319,7 +320,7 @@ nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p)
        if (   !(p = decode_fh(p, &args->fh))
            || !(p = decode_filename(p, &args->name, &args->len)))
                return 0;
-       p = decode_sattr(p, &args->attrs);
+       p = decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
 
        return xdr_argsize_check(rqstp, p);
 }
@@ -398,7 +399,7 @@ nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p)
                        return 0;
                p += xdrlen;
        }
-       decode_sattr(p, &args->attrs);
+       decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
 
        return 1;
 }
index 9d6cb246c6c55737967011a919023fc2dad9c861..0b74d371ed670076a22da2f5bab6d9581e542ac3 100644 (file)
@@ -368,7 +368,7 @@ struct nfs4_client {
 struct nfs4_client_reclaim {
        struct list_head        cr_strhash;     /* hash by cr_name */
        struct nfs4_client      *cr_clp;        /* pointer to associated clp */
-       char                    cr_recdir[HEXDIR_LEN]; /* recover dir */
+       struct xdr_netobj       cr_name;        /* recovery dir name */
 };
 
 /* A reasonable value for REPLAY_ISIZE was estimated as follows:  
@@ -620,7 +620,7 @@ void nfs4_put_stid(struct nfs4_stid *s);
 void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);
 void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *);
 extern void nfs4_release_reclaim(struct nfsd_net *);
-extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir,
+extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct xdr_netobj name,
                                                        struct nfsd_net *nn);
 extern __be32 nfs4_check_open_reclaim(clientid_t *clid,
                struct nfsd4_compound_state *cstate, struct nfsd_net *nn);
@@ -635,9 +635,9 @@ extern void nfsd4_destroy_callback_queue(void);
 extern void nfsd4_shutdown_callback(struct nfs4_client *);
 extern void nfsd4_shutdown_copy(struct nfs4_client *clp);
 extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp);
-extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name,
+extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name,
                                                        struct nfsd_net *nn);
-extern bool nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn);
+extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn);
 
 struct nfs4_file *find_file(struct knfsd_fh *fh);
 void put_nfs4_file(struct nfs4_file *fi);
index 7dc98e14655df9af314cfec2f3df1ba3fbb32d10..fc24ee47eab51ad4bc486ba9f9b04c357089f2d0 100644 (file)
@@ -1786,12 +1786,12 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        rdentry = lookup_one_len(fname, dentry, flen);
        host_err = PTR_ERR(rdentry);
        if (IS_ERR(rdentry))
-               goto out_nfserr;
+               goto out_drop_write;
 
        if (d_really_is_negative(rdentry)) {
                dput(rdentry);
-               err = nfserr_noent;
-               goto out;
+               host_err = -ENOENT;
+               goto out_drop_write;
        }
 
        if (!type)
@@ -1805,6 +1805,8 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
                host_err = commit_metadata(fhp);
        dput(rdentry);
 
+out_drop_write:
+       fh_drop_write(fhp);
 out_nfserr:
        err = nfserrno(host_err);
 out:
index a7e107309f767d33bd24ecf1aa7a1e1d30dc916d..db351247892d05155e9cc2d2517229b071e807a1 100644 (file)
@@ -120,8 +120,11 @@ void               nfsd_put_raparams(struct file *file, struct raparms *ra);
 
 static inline int fh_want_write(struct svc_fh *fh)
 {
-       int ret = mnt_want_write(fh->fh_export->ex_path.mnt);
+       int ret;
 
+       if (fh->fh_want_write)
+               return 0;
+       ret = mnt_want_write(fh->fh_export->ex_path.mnt);
        if (!ret)
                fh->fh_want_write = true;
        return ret;
index 5433e37fb0c52e7629a6d209325252900d0f6f24..8c7cbac7183c13e923fe26b0ed2f052b00fe5e8a 100644 (file)
@@ -107,6 +107,47 @@ void fsnotify_sb_delete(struct super_block *sb)
        fsnotify_clear_marks_by_sb(sb);
 }
 
+/*
+ * fsnotify_nameremove - a filename was removed from a directory
+ *
+ * This is mostly called under parent vfs inode lock so name and
+ * dentry->d_parent should be stable. However there are some corner cases where
+ * inode lock is not held. So to be on the safe side and be reselient to future
+ * callers and out of tree users of d_delete(), we do not assume that d_parent
+ * and d_name are stable and we use dget_parent() and
+ * take_dentry_name_snapshot() to grab stable references.
+ */
+void fsnotify_nameremove(struct dentry *dentry, int isdir)
+{
+       struct dentry *parent;
+       struct name_snapshot name;
+       __u32 mask = FS_DELETE;
+
+       /* d_delete() of pseudo inode? (e.g. __ns_get_path() playing tricks) */
+       if (IS_ROOT(dentry))
+               return;
+
+       if (isdir)
+               mask |= FS_ISDIR;
+
+       parent = dget_parent(dentry);
+       /* Avoid unneeded take_dentry_name_snapshot() */
+       if (!(d_inode(parent)->i_fsnotify_mask & FS_DELETE) &&
+           !(dentry->d_sb->s_fsnotify_mask & FS_DELETE))
+               goto out_dput;
+
+       take_dentry_name_snapshot(&name, dentry);
+
+       fsnotify(d_inode(parent), mask, d_inode(dentry), FSNOTIFY_EVENT_INODE,
+                &name.name, 0);
+
+       release_dentry_name_snapshot(&name);
+
+out_dput:
+       dput(parent);
+}
+EXPORT_SYMBOL(fsnotify_nameremove);
+
 /*
  * 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
index 22acb0a79b532eb7541e3f90a1b4753acd733518..b251105f646f132b8d01c2af3c0d7cf69ae8f34e 100644 (file)
@@ -619,6 +619,11 @@ restart:
        /* mark should be the last entry.  last is the current last entry */
        hlist_add_behind_rcu(&mark->obj_list, &last->obj_list);
 added:
+       /*
+        * Since connector is attached to object using cmpxchg() we are
+        * guaranteed that connector initialization is fully visible by anyone
+        * seeing mark->connector set.
+        */
        WRITE_ONCE(mark->connector, conn);
 out_err:
        spin_unlock(&conn->lock);
index c121abbdfc7dbcfb28675aa7e62a4cb9a70633a1..85f21caaa6ec20ba78d093cba07ce63da60079e3 100644 (file)
 #define NAMEI_RA_BLOCKS  4
 #define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
 
-static unsigned char ocfs2_filetype_table[] = {
-       DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
-};
-
 static int ocfs2_do_extend_dir(struct super_block *sb,
                               handle_t *handle,
                               struct inode *dir,
@@ -1718,7 +1714,7 @@ int __ocfs2_add_entry(handle_t *handle,
                                de->rec_len = cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
                                de = de1;
                        }
-                       de->file_type = OCFS2_FT_UNKNOWN;
+                       de->file_type = FT_UNKNOWN;
                        if (blkno) {
                                de->inode = cpu_to_le64(blkno);
                                ocfs2_set_de_type(de, inode->i_mode);
@@ -1803,13 +1799,9 @@ static int ocfs2_dir_foreach_blk_id(struct inode *inode,
                }
                offset += le16_to_cpu(de->rec_len);
                if (le64_to_cpu(de->inode)) {
-                       unsigned char d_type = DT_UNKNOWN;
-
-                       if (de->file_type < OCFS2_FT_MAX)
-                               d_type = ocfs2_filetype_table[de->file_type];
-
                        if (!dir_emit(ctx, de->name, de->name_len,
-                                     le64_to_cpu(de->inode), d_type))
+                                     le64_to_cpu(de->inode),
+                                     fs_ftype_to_dtype(de->file_type)))
                                goto out;
                }
                ctx->pos += le16_to_cpu(de->rec_len);
@@ -1900,14 +1892,10 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode,
                                break;
                        }
                        if (le64_to_cpu(de->inode)) {
-                               unsigned char d_type = DT_UNKNOWN;
-
-                               if (de->file_type < OCFS2_FT_MAX)
-                                       d_type = ocfs2_filetype_table[de->file_type];
                                if (!dir_emit(ctx, de->name,
                                                de->name_len,
                                                le64_to_cpu(de->inode),
-                                               d_type)) {
+                                       fs_ftype_to_dtype(de->file_type))) {
                                        brelse(bh);
                                        return 0;
                                }
index 4bf8d5854b2711ebcac47c5c1f38d49f120d0eb5..af2888d23de38fbc59270f21a7322118bbb7810e 100644 (file)
@@ -148,16 +148,24 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
        u64 blkno;
        struct dentry *parent;
        struct inode *dir = d_inode(child);
+       int set;
 
        trace_ocfs2_get_parent(child, child->d_name.len, child->d_name.name,
                               (unsigned long long)OCFS2_I(dir)->ip_blkno);
 
+       status = ocfs2_nfs_sync_lock(OCFS2_SB(dir->i_sb), 1);
+       if (status < 0) {
+               mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
+               parent = ERR_PTR(status);
+               goto bail;
+       }
+
        status = ocfs2_inode_lock(dir, NULL, 0);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
                parent = ERR_PTR(status);
-               goto bail;
+               goto unlock_nfs_sync;
        }
 
        status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno);
@@ -166,11 +174,31 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
                goto bail_unlock;
        }
 
+       status = ocfs2_test_inode_bit(OCFS2_SB(dir->i_sb), blkno, &set);
+       if (status < 0) {
+               if (status == -EINVAL) {
+                       status = -ESTALE;
+               } else
+                       mlog(ML_ERROR, "test inode bit failed %d\n", status);
+               parent = ERR_PTR(status);
+               goto bail_unlock;
+       }
+
+       trace_ocfs2_get_dentry_test_bit(status, set);
+       if (!set) {
+               status = -ESTALE;
+               parent = ERR_PTR(status);
+               goto bail_unlock;
+       }
+
        parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0));
 
 bail_unlock:
        ocfs2_inode_unlock(dir, 0);
 
+unlock_nfs_sync:
+       ocfs2_nfs_sync_unlock(OCFS2_SB(dir->i_sb), 1);
+
 bail:
        trace_ocfs2_get_parent_end(parent);
 
index 7071ad0dec900051b1e98dce260a1002c8dea06b..b86bf5e743484d27c2d7a1640408e277f20c7c0a 100644 (file)
@@ -391,21 +391,6 @@ static struct ocfs2_system_inode_info ocfs2_system_inodes[NUM_SYSTEM_INODES] = {
 #define OCFS2_HB_LOCAL                 "heartbeat=local"
 #define OCFS2_HB_GLOBAL                        "heartbeat=global"
 
-/*
- * OCFS2 directory file types.  Only the low 3 bits are used.  The
- * other bits are reserved for now.
- */
-#define OCFS2_FT_UNKNOWN       0
-#define OCFS2_FT_REG_FILE      1
-#define OCFS2_FT_DIR           2
-#define OCFS2_FT_CHRDEV                3
-#define OCFS2_FT_BLKDEV                4
-#define OCFS2_FT_FIFO          5
-#define OCFS2_FT_SOCK          6
-#define OCFS2_FT_SYMLINK       7
-
-#define OCFS2_FT_MAX           8
-
 /*
  * OCFS2_DIR_PAD defines the directory entries boundaries
  *
@@ -424,17 +409,6 @@ static struct ocfs2_system_inode_info ocfs2_system_inodes[NUM_SYSTEM_INODES] = {
 #define        OCFS2_LINKS_HI_SHIFT    16
 #define        OCFS2_DX_ENTRIES_MAX    (0xffffffffU)
 
-#define S_SHIFT                        12
-static unsigned char ocfs2_type_by_mode[S_IFMT >> S_SHIFT] = {
-       [S_IFREG >> S_SHIFT]  = OCFS2_FT_REG_FILE,
-       [S_IFDIR >> S_SHIFT]  = OCFS2_FT_DIR,
-       [S_IFCHR >> S_SHIFT]  = OCFS2_FT_CHRDEV,
-       [S_IFBLK >> S_SHIFT]  = OCFS2_FT_BLKDEV,
-       [S_IFIFO >> S_SHIFT]  = OCFS2_FT_FIFO,
-       [S_IFSOCK >> S_SHIFT] = OCFS2_FT_SOCK,
-       [S_IFLNK >> S_SHIFT]  = OCFS2_FT_SYMLINK,
-};
-
 
 /*
  * Convenience casts
@@ -1629,7 +1603,7 @@ static inline int ocfs2_sprintf_system_inode_name(char *buf, int len,
 static inline void ocfs2_set_de_type(struct ocfs2_dir_entry *de,
                                    umode_t mode)
 {
-       de->file_type = ocfs2_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
+       de->file_type = fs_umode_to_ftype(mode);
 }
 
 static inline int ocfs2_gd_is_discontig(struct ocfs2_group_desc *gd)
index d4811f981608325c3a5ef964a9c73a1d1e3f5c7a..2bb916d68576fa01e4431017fa812907e117049b 100644 (file)
@@ -269,7 +269,7 @@ orangefs_bufmap_map(struct orangefs_bufmap *bufmap,
 
        /* map the pages */
        ret = get_user_pages_fast((unsigned long)user_desc->ptr,
-                            bufmap->page_count, 1, bufmap->page_array);
+                            bufmap->page_count, FOLL_WRITE, bufmap->page_array);
 
        if (ret < 0)
                return ret;
index 68b3303e4b46f75280439b83568f9694c1330dec..56feaa739979766aa8aab02546c38757a63a4de5 100644 (file)
@@ -909,14 +909,14 @@ static bool ovl_open_need_copy_up(struct dentry *dentry, int flags)
        return true;
 }
 
-int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags)
+int ovl_maybe_copy_up(struct dentry *dentry, int flags)
 {
        int err = 0;
 
-       if (ovl_open_need_copy_up(dentry, file_flags)) {
+       if (ovl_open_need_copy_up(dentry, flags)) {
                err = ovl_want_write(dentry);
                if (!err) {
-                       err = ovl_copy_up_flags(dentry, file_flags);
+                       err = ovl_copy_up_flags(dentry, flags);
                        ovl_drop_write(dentry);
                }
        }
index 82c129bfe58d9e3a8be301fecc9bbbb4e1de88d5..93872bb502303c396e0a175ec86a74a3daa88d8b 100644 (file)
@@ -260,7 +260,7 @@ static int ovl_instantiate(struct dentry *dentry, struct inode *inode,
                 * hashed directory inode aliases.
                 */
                inode = ovl_get_inode(dentry->d_sb, &oip);
-               if (WARN_ON(IS_ERR(inode)))
+               if (IS_ERR(inode))
                        return PTR_ERR(inode);
        } else {
                WARN_ON(ovl_inode_real(inode) != d_inode(newdentry));
index 84dd957efa24a17e8a66416117790896fd1d04ff..540a8b8451452f2b624121556e55066b507c353c 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mount.h>
 #include <linux/xattr.h>
 #include <linux/uio.h>
+#include <linux/uaccess.h>
 #include "overlayfs.h"
 
 static char ovl_whatisit(struct inode *inode, struct inode *realinode)
@@ -29,10 +30,11 @@ static struct file *ovl_open_realfile(const struct file *file,
        struct inode *inode = file_inode(file);
        struct file *realfile;
        const struct cred *old_cred;
+       int flags = file->f_flags | O_NOATIME | FMODE_NONOTIFY;
 
        old_cred = ovl_override_creds(inode->i_sb);
-       realfile = open_with_fake_path(&file->f_path, file->f_flags | O_NOATIME,
-                                      realinode, current_cred());
+       realfile = open_with_fake_path(&file->f_path, flags, realinode,
+                                      current_cred());
        revert_creds(old_cred);
 
        pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n",
@@ -50,7 +52,7 @@ static int ovl_change_flags(struct file *file, unsigned int flags)
        int err;
 
        /* No atime modificaton on underlying */
-       flags |= O_NOATIME;
+       flags |= O_NOATIME | FMODE_NONOTIFY;
 
        /* If some flag changed that cannot be changed then something's amiss */
        if (WARN_ON((file->f_flags ^ flags) & ~OVL_SETFL_MASK))
@@ -116,11 +118,10 @@ static int ovl_real_fdget(const struct file *file, struct fd *real)
 
 static int ovl_open(struct inode *inode, struct file *file)
 {
-       struct dentry *dentry = file_dentry(file);
        struct file *realfile;
        int err;
 
-       err = ovl_open_maybe_copy_up(dentry, file->f_flags);
+       err = ovl_maybe_copy_up(file_dentry(file), file->f_flags);
        if (err)
                return err;
 
@@ -145,11 +146,47 @@ static int ovl_release(struct inode *inode, struct file *file)
 
 static loff_t ovl_llseek(struct file *file, loff_t offset, int whence)
 {
-       struct inode *realinode = ovl_inode_real(file_inode(file));
+       struct inode *inode = file_inode(file);
+       struct fd real;
+       const struct cred *old_cred;
+       ssize_t ret;
+
+       /*
+        * The two special cases below do not need to involve real fs,
+        * so we can optimizing concurrent callers.
+        */
+       if (offset == 0) {
+               if (whence == SEEK_CUR)
+                       return file->f_pos;
+
+               if (whence == SEEK_SET)
+                       return vfs_setpos(file, 0, 0);
+       }
+
+       ret = ovl_real_fdget(file, &real);
+       if (ret)
+               return ret;
+
+       /*
+        * Overlay file f_pos is the master copy that is preserved
+        * through copy up and modified on read/write, but only real
+        * fs knows how to SEEK_HOLE/SEEK_DATA and real fs may impose
+        * limitations that are more strict than ->s_maxbytes for specific
+        * files, so we use the real file to perform seeks.
+        */
+       inode_lock(inode);
+       real.file->f_pos = file->f_pos;
+
+       old_cred = ovl_override_creds(inode->i_sb);
+       ret = vfs_llseek(real.file, offset, whence);
+       revert_creds(old_cred);
+
+       file->f_pos = real.file->f_pos;
+       inode_unlock(inode);
+
+       fdput(real);
 
-       return generic_file_llseek_size(file, offset, whence,
-                                       realinode->i_sb->s_maxbytes,
-                                       i_size_read(realinode));
+       return ret;
 }
 
 static void ovl_file_accessed(struct file *file)
@@ -372,10 +409,68 @@ static long ovl_real_ioctl(struct file *file, unsigned int cmd,
        return ret;
 }
 
-static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static unsigned int ovl_get_inode_flags(struct inode *inode)
+{
+       unsigned int flags = READ_ONCE(inode->i_flags);
+       unsigned int ovl_iflags = 0;
+
+       if (flags & S_SYNC)
+               ovl_iflags |= FS_SYNC_FL;
+       if (flags & S_APPEND)
+               ovl_iflags |= FS_APPEND_FL;
+       if (flags & S_IMMUTABLE)
+               ovl_iflags |= FS_IMMUTABLE_FL;
+       if (flags & S_NOATIME)
+               ovl_iflags |= FS_NOATIME_FL;
+
+       return ovl_iflags;
+}
+
+static long ovl_ioctl_set_flags(struct file *file, unsigned long arg)
 {
        long ret;
        struct inode *inode = file_inode(file);
+       unsigned int flags;
+       unsigned int old_flags;
+
+       if (!inode_owner_or_capable(inode))
+               return -EACCES;
+
+       if (get_user(flags, (int __user *) arg))
+               return -EFAULT;
+
+       ret = mnt_want_write_file(file);
+       if (ret)
+               return ret;
+
+       inode_lock(inode);
+
+       /* Check the capability before cred override */
+       ret = -EPERM;
+       old_flags = ovl_get_inode_flags(inode);
+       if (((flags ^ old_flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) &&
+           !capable(CAP_LINUX_IMMUTABLE))
+               goto unlock;
+
+       ret = ovl_maybe_copy_up(file_dentry(file), O_WRONLY);
+       if (ret)
+               goto unlock;
+
+       ret = ovl_real_ioctl(file, FS_IOC_SETFLAGS, arg);
+
+       ovl_copyflags(ovl_inode_real(inode), inode);
+unlock:
+       inode_unlock(inode);
+
+       mnt_drop_write_file(file);
+
+       return ret;
+
+}
+
+static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       long ret;
 
        switch (cmd) {
        case FS_IOC_GETFLAGS:
@@ -383,23 +478,7 @@ static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                break;
 
        case FS_IOC_SETFLAGS:
-               if (!inode_owner_or_capable(inode))
-                       return -EACCES;
-
-               ret = mnt_want_write_file(file);
-               if (ret)
-                       return ret;
-
-               ret = ovl_copy_up_with_data(file_dentry(file));
-               if (!ret) {
-                       ret = ovl_real_ioctl(file, cmd, arg);
-
-                       inode_lock(inode);
-                       ovl_copyflags(ovl_inode_real(inode), inode);
-                       inode_unlock(inode);
-               }
-
-               mnt_drop_write_file(file);
+               ret = ovl_ioctl_set_flags(file, arg);
                break;
 
        default:
index 3b7ed5d2279c6a8efde8180471bde94ef1020964..b48273e846adc524eeaa50bde608a93b8bdeb102 100644 (file)
@@ -832,7 +832,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
        int fsid = bylower ? oip->lowerpath->layer->fsid : 0;
        bool is_dir, metacopy = false;
        unsigned long ino = 0;
-       int err = -ENOMEM;
+       int err = oip->newinode ? -EEXIST : -ENOMEM;
 
        if (!realinode)
                realinode = d_inode(lowerdentry);
@@ -917,6 +917,7 @@ out:
        return inode;
 
 out_err:
+       pr_warn_ratelimited("overlayfs: failed to get inode (%i)\n", err);
        inode = ERR_PTR(err);
        goto out;
 }
index 9c6018287d571ee349cacbb4be13a1a033ee016c..d26efed9f80af753767fbac1b28f38edacc491ea 100644 (file)
@@ -421,7 +421,7 @@ extern const struct file_operations ovl_file_operations;
 int ovl_copy_up(struct dentry *dentry);
 int ovl_copy_up_with_data(struct dentry *dentry);
 int ovl_copy_up_flags(struct dentry *dentry, int flags);
-int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags);
+int ovl_maybe_copy_up(struct dentry *dentry, int flags);
 int ovl_copy_xattr(struct dentry *old, struct dentry *new);
 int ovl_set_attr(struct dentry *upper, struct kstat *stat);
 struct ovl_fh *ovl_encode_real_fh(struct dentry *real, bool is_upper);
index b6ccb6c57706be39c1911b832f19ab91d87f644a..9c8ca6cd3ce42d19809f3104482ac01cee2b5ce1 100644 (file)
@@ -510,7 +510,7 @@ static ssize_t lstats_write(struct file *file, const char __user *buf,
 
        if (!task)
                return -ESRCH;
-       clear_all_latency_tracing(task);
+       clear_tsk_latency_tracing(task);
        put_task_struct(task);
 
        return count;
index 95ca1fe7283cff265247c6f3a84e5fa573299fca..01d4eb0e6bd1155f38df153915bfaf20b96406c8 100644 (file)
@@ -1169,7 +1169,8 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
                                break;
                        }
 
-                       mmu_notifier_range_init(&range, mm, 0, -1UL);
+                       mmu_notifier_range_init(&range, MMU_NOTIFY_SOFT_DIRTY,
+                                               0, NULL, mm, 0, -1UL);
                        mmu_notifier_invalidate_range_start(&range);
                }
                walk_page_range(0, mm->highest_vm_end, &clear_refs_walk);
index fc20e06c56ba55bf229db78cb5b5077c21935931..9ad72ea7f71f5d71608c470992c871aa7bbe2f15 100644 (file)
@@ -9,7 +9,7 @@
  * on the Melbourne quota system as used on BSD derived systems. The internal
  * implementation is based on one of the several variants of the LINUX
  * inode-subsystem with added complexity of the diskquota system.
- * 
+ *
  * Author:     Marco van Wieringen <mvw@planets.elm.net>
  *
  * Fixes:   Dmitry Gorodchanin <pgmdsg@ibi.com>, 11 Feb 96
@@ -51,7 +51,7 @@
  *             Added journalled quota support, fix lock inversion problems
  *             Jan Kara, <jack@suse.cz>, 2003,2004
  *
- * (C) Copyright 1994 - 1997 Marco van Wieringen 
+ * (C) Copyright 1994 - 1997 Marco van Wieringen
  */
 
 #include <linux/errno.h>
@@ -197,7 +197,7 @@ static struct quota_format_type *find_quota_format(int id)
                int qm;
 
                spin_unlock(&dq_list_lock);
-               
+
                for (qm = 0; module_names[qm].qm_fmt_id &&
                             module_names[qm].qm_fmt_id != id; qm++)
                        ;
@@ -424,10 +424,11 @@ int dquot_acquire(struct dquot *dquot)
        struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
 
        mutex_lock(&dquot->dq_lock);
-       if (!test_bit(DQ_READ_B, &dquot->dq_flags))
+       if (!test_bit(DQ_READ_B, &dquot->dq_flags)) {
                ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot);
-       if (ret < 0)
-               goto out_iolock;
+               if (ret < 0)
+                       goto out_iolock;
+       }
        /* Make sure flags update is visible after dquot has been filled */
        smp_mb__before_atomic();
        set_bit(DQ_READ_B, &dquot->dq_flags);
@@ -1049,7 +1050,9 @@ static void remove_dquot_ref(struct super_block *sb, int type,
                struct list_head *tofree_head)
 {
        struct inode *inode;
+#ifdef CONFIG_QUOTA_DEBUG
        int reserved = 0;
+#endif
 
        spin_lock(&sb->s_inode_list_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
@@ -1061,8 +1064,10 @@ static void remove_dquot_ref(struct super_block *sb, int type,
                 */
                spin_lock(&dq_data_lock);
                if (!IS_NOQUOTA(inode)) {
+#ifdef CONFIG_QUOTA_DEBUG
                        if (unlikely(inode_get_rsv_space(inode) > 0))
                                reserved = 1;
+#endif
                        remove_inode_dquot_ref(inode, type, tofree_head);
                }
                spin_unlock(&dq_data_lock);
@@ -1663,7 +1668,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (!dquots[cnt])
                        continue;
-               if (flags & DQUOT_SPACE_RESERVE) {
+               if (reserve) {
                        ret = dquot_add_space(dquots[cnt], 0, number, flags,
                                              &warn[cnt]);
                } else {
@@ -1676,13 +1681,11 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
                                if (!dquots[cnt])
                                        continue;
                                spin_lock(&dquots[cnt]->dq_dqb_lock);
-                               if (flags & DQUOT_SPACE_RESERVE) {
-                                       dquots[cnt]->dq_dqb.dqb_rsvspace -=
-                                                                       number;
-                               } else {
-                                       dquots[cnt]->dq_dqb.dqb_curspace -=
-                                                                       number;
-                               }
+                               if (reserve)
+                                       dquot_free_reserved_space(dquots[cnt],
+                                                                 number);
+                               else
+                                       dquot_decr_space(dquots[cnt], number);
                                spin_unlock(&dquots[cnt]->dq_dqb_lock);
                        }
                        spin_unlock(&inode->i_lock);
@@ -1733,7 +1736,7 @@ int dquot_alloc_inode(struct inode *inode)
                                        continue;
                                /* Back out changes we already did */
                                spin_lock(&dquots[cnt]->dq_dqb_lock);
-                               dquots[cnt]->dq_dqb.dqb_curinodes--;
+                               dquot_decr_inodes(dquots[cnt], 1);
                                spin_unlock(&dquots[cnt]->dq_dqb_lock);
                        }
                        goto warn_put_all;
@@ -2397,7 +2400,7 @@ out_file_flags:
 out_fmt:
        put_quota_format(fmt);
 
-       return error; 
+       return error;
 }
 
 /* Reenable quotas on remount RW */
@@ -2775,7 +2778,7 @@ int dquot_get_state(struct super_block *sb, struct qc_state *state)
        struct qc_type_state *tstate;
        struct quota_info *dqopt = sb_dqopt(sb);
        int type;
-  
+
        memset(state, 0, sizeof(*state));
        for (type = 0; type < MAXQUOTAS; type++) {
                if (!sb_has_quota_active(sb, type))
index 7ac5298aba70bc7d48c96d85fae88759a7680eb8..9f2b2573b83cc1bf90e35cfdf656636d9224075e 100644 (file)
@@ -127,7 +127,7 @@ static int v1_check_quota_file(struct super_block *sb, int type)
 {
        struct inode *inode = sb_dqopt(sb)->files[type];
        ulong blocks;
-       size_t off; 
+       size_t off;
        struct v2_disk_dqheader dqhead;
        ssize_t size;
        loff_t isize;
index a73e5b34db4181272bc943c4e0ea406797ff0311..3c30034e733f40abcc8f26849afde4ee1b3df4ae 100644 (file)
@@ -78,7 +78,7 @@ static int v2_check_quota_file(struct super_block *sb, int type)
        struct v2_disk_dqheader dqhead;
        static const uint quota_magics[] = V2_INITQMAGICS;
        static const uint quota_versions[] = V2_INITQVERSIONS;
+
        if (v2_read_header(sb, type, &dqhead))
                return 0;
        if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
index 8a76f9d14bc661c5a6760d7815ac1e97352f8e0c..36346dc4cec0ee5a144c1394850ef4f526885d47 100644 (file)
@@ -1844,7 +1844,7 @@ static int flush_used_journal_lists(struct super_block *s,
  * removes any nodes in table with name block and dev as bh.
  * only touchs the hnext and hprev pointers.
  */
-void remove_journal_hash(struct super_block *sb,
+static void remove_journal_hash(struct super_block *sb,
                         struct reiserfs_journal_cnode **table,
                         struct reiserfs_journal_list *jl,
                         unsigned long block, int remove_freed)
index 32d8986c26fb1fa2d3c5140d9fb7629eaf9b865f..b5b26d8a192c4ae71d5a958bd4968183f3ca010a 100644 (file)
@@ -450,6 +450,15 @@ fail:
 
 static inline __u32 xattr_hash(const char *msg, int len)
 {
+       /*
+        * csum_partial() gives different results for little-endian and
+        * big endian hosts. Images created on little-endian hosts and
+        * mounted on big-endian hosts(and vice versa) will see csum mismatches
+        * when trying to fetch xattrs. Treating the hash as __wsum_t would
+        * lower the frequency of mismatch.  This is an endianness bug in
+        * reiserfs.  The return statement would result in a sparse warning. Do
+        * not fix the sparse warning so as to not hide a reminder of the bug.
+        */
        return csum_partial(msg, len, 0);
 }
 
index 01e82170545a3037e0499ddd896b6c0489fbca8e..4d1ff010bc5afcd6acee1e4dbd736e8bfbd9081a 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -292,8 +292,14 @@ int sync_file_range(struct file *file, loff_t offset, loff_t nbytes,
        }
 
        if (flags & SYNC_FILE_RANGE_WRITE) {
+               int sync_mode = WB_SYNC_NONE;
+
+               if ((flags & SYNC_FILE_RANGE_WRITE_AND_WAIT) ==
+                            SYNC_FILE_RANGE_WRITE_AND_WAIT)
+                       sync_mode = WB_SYNC_ALL;
+
                ret = __filemap_fdatawrite_range(mapping, offset, endbyte,
-                                                WB_SYNC_NONE);
+                                                sync_mode);
                if (ret < 0)
                        goto out;
        }
@@ -306,9 +312,9 @@ out:
 }
 
 /*
- * sys_sync_file_range() permits finely controlled syncing over a segment of
+ * ksys_sync_file_range() permits finely controlled syncing over a segment of
  * a file in the range offset .. (offset+nbytes-1) inclusive.  If nbytes is
- * zero then sys_sync_file_range() will operate from offset out to EOF.
+ * zero then ksys_sync_file_range() will operate from offset out to EOF.
  *
  * The flag bits are:
  *
@@ -325,7 +331,7 @@ out:
  * Useful combinations of the flag bits are:
  *
  * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE: ensures that all pages
- * in the range which were dirty on entry to sys_sync_file_range() are placed
+ * in the range which were dirty on entry to ksys_sync_file_range() are placed
  * under writeout.  This is a start-write-for-data-integrity operation.
  *
  * SYNC_FILE_RANGE_WRITE: start writeout of all dirty pages in the range which
@@ -337,10 +343,13 @@ out:
  * earlier SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE operation to wait
  * for that operation to complete and to return the result.
  *
- * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER:
+ * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER
+ * (a.k.a. SYNC_FILE_RANGE_WRITE_AND_WAIT):
  * a traditional sync() operation.  This is a write-for-data-integrity operation
  * which will ensure that all pages in the range which were dirty on entry to
- * sys_sync_file_range() are committed to disk.
+ * ksys_sync_file_range() are written to disk.  It should be noted that disk
+ * caches are not flushed by this call, so there are no guarantees here that the
+ * data will be available on disk after a crash.
  *
  *
  * SYNC_FILE_RANGE_WAIT_BEFORE and SYNC_FILE_RANGE_WAIT_AFTER will detect any
index b758004085c4758c0127c1d51c7fc172db8c7ac1..60f43b93d06e4b479fa2543f90619ffa841d0fe7 100644 (file)
@@ -76,7 +76,6 @@ static int ubifs_hash_calc_hmac(const struct ubifs_info *c, const u8 *hash,
 int ubifs_prepare_auth_node(struct ubifs_info *c, void *node,
                             struct shash_desc *inhash)
 {
-       SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm);
        struct ubifs_auth_node *auth = node;
        u8 *hash;
        int err;
@@ -85,12 +84,16 @@ int ubifs_prepare_auth_node(struct ubifs_info *c, void *node,
        if (!hash)
                return -ENOMEM;
 
-       hash_desc->tfm = c->hash_tfm;
-       ubifs_shash_copy_state(c, inhash, hash_desc);
+       {
+               SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm);
 
-       err = crypto_shash_final(hash_desc, hash);
-       if (err)
-               goto out;
+               hash_desc->tfm = c->hash_tfm;
+               ubifs_shash_copy_state(c, inhash, hash_desc);
+
+               err = crypto_shash_final(hash_desc, hash);
+               if (err)
+                       goto out;
+       }
 
        err = ubifs_hash_calc_hmac(c, hash, auth->hmac);
        if (err)
@@ -142,24 +145,6 @@ struct shash_desc *__ubifs_hash_get_desc(const struct ubifs_info *c)
        return ubifs_get_desc(c, c->hash_tfm);
 }
 
-/**
- * __ubifs_shash_final - finalize shash
- * @c: UBIFS file-system description object
- * @desc: the descriptor
- * @out: the output hash
- *
- * Simple wrapper around crypto_shash_final(), safe to be called with
- * disabled authentication.
- */
-int __ubifs_shash_final(const struct ubifs_info *c, struct shash_desc *desc,
-                       u8 *out)
-{
-       if (ubifs_authenticated(c))
-               return crypto_shash_final(desc, out);
-
-       return 0;
-}
-
 /**
  * ubifs_bad_hash - Report hash mismatches
  * @c: UBIFS file-system description object
index c49ff50fdceb1d8f90f059099cd87d6e4334555b..3a2613038e8875abc7d4c704d01495e5cce9babf 100644 (file)
@@ -1603,7 +1603,6 @@ int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
                                err = PTR_ERR(child);
                                goto out_unlock;
                        }
-                       zbr->znode = child;
                }
 
                znode = child;
index b73de6d04fa3e29adc96aba300fa56eb301e0a3d..1a379b596b0d42119a163707d00741684d7deadd 100644 (file)
@@ -790,16 +790,14 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
                dentry, inode->i_ino,
                inode->i_nlink, dir->i_ino);
 
-       if (ubifs_crypt_is_encrypted(dir)) {
-               err = fscrypt_get_encryption_info(dir);
-               if (err && err != -ENOKEY)
-                       return err;
-       }
-
        err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
        if (err)
                return err;
 
+       err = ubifs_purge_xattrs(inode);
+       if (err)
+               return err;
+
        sz_change = CALC_DENT_SIZE(fname_len(&nm));
 
        ubifs_assert(c, inode_is_locked(dir));
@@ -900,16 +898,14 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
        if (err)
                return err;
 
-       if (ubifs_crypt_is_encrypted(dir)) {
-               err = fscrypt_get_encryption_info(dir);
-               if (err && err != -ENOKEY)
-                       return err;
-       }
-
        err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
        if (err)
                return err;
 
+       err = ubifs_purge_xattrs(inode);
+       if (err)
+               return err;
+
        sz_change = CALC_DENT_SIZE(fname_len(&nm));
 
        err = ubifs_budget_space(c, &req);
@@ -1292,9 +1288,14 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
                old_dentry, old_inode->i_ino, old_dir->i_ino,
                new_dentry, new_dir->i_ino, flags);
 
-       if (unlink)
+       if (unlink) {
                ubifs_assert(c, inode_is_locked(new_inode));
 
+               err = ubifs_purge_xattrs(new_inode);
+               if (err)
+                       return err;
+       }
+
        if (unlink && is_dir) {
                err = ubifs_check_dir_empty(new_inode);
                if (err)
@@ -1650,9 +1651,7 @@ const struct inode_operations ubifs_dir_inode_operations = {
 #ifdef CONFIG_UBIFS_FS_XATTR
        .listxattr   = ubifs_listxattr,
 #endif
-#ifdef CONFIG_UBIFS_ATIME_SUPPORT
        .update_time = ubifs_update_time,
-#endif
        .tmpfile     = ubifs_tmpfile,
 };
 
index 5d2ffb1a45fcfcc37cd857a613484aee99da13aa..512e7d9c60cd281e777743ce86f30d042a7adb88 100644 (file)
@@ -1375,7 +1375,6 @@ static inline int mctime_update_needed(const struct inode *inode,
        return 0;
 }
 
-#ifdef CONFIG_UBIFS_ATIME_SUPPORT
 /**
  * ubifs_update_time - update time of inode.
  * @inode: inode to update
@@ -1392,6 +1391,9 @@ int ubifs_update_time(struct inode *inode, struct timespec64 *time,
        int iflags = I_DIRTY_TIME;
        int err, release;
 
+       if (!IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
+               return generic_update_time(inode, time, flags);
+
        err = ubifs_budget_space(c, &req);
        if (err)
                return err;
@@ -1414,7 +1416,6 @@ int ubifs_update_time(struct inode *inode, struct timespec64 *time,
                ubifs_release_budget(c, &req);
        return 0;
 }
-#endif
 
 /**
  * update_mctime - update mtime and ctime of an inode.
@@ -1623,9 +1624,10 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
        if (err)
                return err;
        vma->vm_ops = &ubifs_file_vm_ops;
-#ifdef CONFIG_UBIFS_ATIME_SUPPORT
-       file_accessed(file);
-#endif
+
+       if (IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
+               file_accessed(file);
+
        return 0;
 }
 
@@ -1663,9 +1665,7 @@ const struct inode_operations ubifs_file_inode_operations = {
 #ifdef CONFIG_UBIFS_FS_XATTR
        .listxattr   = ubifs_listxattr,
 #endif
-#ifdef CONFIG_UBIFS_ATIME_SUPPORT
        .update_time = ubifs_update_time,
-#endif
 };
 
 const struct inode_operations ubifs_symlink_inode_operations = {
@@ -1675,9 +1675,7 @@ const struct inode_operations ubifs_symlink_inode_operations = {
 #ifdef CONFIG_UBIFS_FS_XATTR
        .listxattr   = ubifs_listxattr,
 #endif
-#ifdef CONFIG_UBIFS_ATIME_SUPPORT
        .update_time = ubifs_update_time,
-#endif
 };
 
 const struct file_operations ubifs_file_operations = {
index f9646835b0269c2347e73ceabd146253b8f42abd..5deaae7fceadba871a21283eaba68a06eb2c75f6 100644 (file)
@@ -747,12 +747,6 @@ static int cmp_dirty_idx(const struct ubifs_lprops **a,
        return lpa->dirty + lpa->free - lpb->dirty - lpb->free;
 }
 
-static void swap_dirty_idx(struct ubifs_lprops **a, struct ubifs_lprops **b,
-                          int size)
-{
-       swap(*a, *b);
-}
-
 /**
  * ubifs_save_dirty_idx_lnums - save an array of the most dirty index LEB nos.
  * @c: the UBIFS file-system description object
@@ -772,8 +766,7 @@ int ubifs_save_dirty_idx_lnums(struct ubifs_info *c)
               sizeof(void *) * c->dirty_idx.cnt);
        /* Sort it so that the dirtiest is now at the end */
        sort(c->dirty_idx.arr, c->dirty_idx.cnt, sizeof(void *),
-            (int (*)(const void *, const void *))cmp_dirty_idx,
-            (void (*)(void *, void *, int))swap_dirty_idx);
+            (int (*)(const void *, const void *))cmp_dirty_idx, NULL);
        dbg_find("found %d dirty index LEBs", c->dirty_idx.cnt);
        if (c->dirty_idx.cnt)
                dbg_find("dirtiest index LEB is %d with dirty %d and free %d",
index 82e4e6a30b0446eb7e3d3ae743d5a758b0f5b8e9..6b05b3ec500e11345daeb53dda8677b8838258b7 100644 (file)
@@ -193,7 +193,6 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                return err;
        }
        case FS_IOC_SET_ENCRYPTION_POLICY: {
-#ifdef CONFIG_FS_ENCRYPTION
                struct ubifs_info *c = inode->i_sb->s_fs_info;
 
                err = ubifs_enable_encryption(c);
@@ -201,17 +200,9 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        return err;
 
                return fscrypt_ioctl_set_policy(file, (const void __user *)arg);
-#else
-               return -EOPNOTSUPP;
-#endif
        }
-       case FS_IOC_GET_ENCRYPTION_POLICY: {
-#ifdef CONFIG_FS_ENCRYPTION
+       case FS_IOC_GET_ENCRYPTION_POLICY:
                return fscrypt_ioctl_get_policy(file, (void __user *)arg);
-#else
-               return -EOPNOTSUPP;
-#endif
-       }
 
        default:
                return -ENOTTY;
index 729dc76c83dffb850354521f96f7cdfabf860051..74a7306978d0e114b1d94ad771b0e49a600dc76c 100644 (file)
@@ -852,10 +852,11 @@ out_free:
 int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
 {
        int err, lnum, offs;
-       struct ubifs_ino_node *ino;
+       struct ubifs_ino_node *ino, *ino_start;
        struct ubifs_inode *ui = ubifs_inode(inode);
-       int sync = 0, write_len, ilen = UBIFS_INO_NODE_SZ;
+       int sync = 0, write_len = 0, ilen = UBIFS_INO_NODE_SZ;
        int last_reference = !inode->i_nlink;
+       int kill_xattrs = ui->xattr_cnt && last_reference;
        u8 hash[UBIFS_HASH_ARR_SZ];
 
        dbg_jnl("ino %lu, nlink %u", inode->i_ino, inode->i_nlink);
@@ -867,14 +868,16 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
        if (!last_reference) {
                ilen += ui->data_len;
                sync = IS_SYNC(inode);
+       } else if (kill_xattrs) {
+               write_len += UBIFS_INO_NODE_SZ * ui->xattr_cnt;
        }
 
        if (ubifs_authenticated(c))
-               write_len = ALIGN(ilen, 8) + ubifs_auth_node_sz(c);
+               write_len += ALIGN(ilen, 8) + ubifs_auth_node_sz(c);
        else
-               write_len = ilen;
+               write_len += ilen;
 
-       ino = kmalloc(write_len, GFP_NOFS);
+       ino_start = ino = kmalloc(write_len, GFP_NOFS);
        if (!ino)
                return -ENOMEM;
 
@@ -883,12 +886,59 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
        if (err)
                goto out_free;
 
+       if (kill_xattrs) {
+               union ubifs_key key;
+               struct fscrypt_name nm = {0};
+               struct inode *xino;
+               struct ubifs_dent_node *xent, *pxent = NULL;
+
+               if (ui->xattr_cnt >= ubifs_xattr_max_cnt(c)) {
+                       ubifs_err(c, "Cannot delete inode, it has too much xattrs!");
+                       goto out_release;
+               }
+
+               lowest_xent_key(c, &key, inode->i_ino);
+               while (1) {
+                       xent = ubifs_tnc_next_ent(c, &key, &nm);
+                       if (IS_ERR(xent)) {
+                               err = PTR_ERR(xent);
+                               if (err == -ENOENT)
+                                       break;
+
+                               goto out_release;
+                       }
+
+                       fname_name(&nm) = xent->name;
+                       fname_len(&nm) = le16_to_cpu(xent->nlen);
+
+                       xino = ubifs_iget(c->vfs_sb, xent->inum);
+                       if (IS_ERR(xino)) {
+                               err = PTR_ERR(xino);
+                               ubifs_err(c, "dead directory entry '%s', error %d",
+                                         xent->name, err);
+                               ubifs_ro_mode(c, err);
+                               goto out_release;
+                       }
+                       ubifs_assert(c, ubifs_inode(xino)->xattr);
+
+                       clear_nlink(xino);
+                       pack_inode(c, ino, xino, 0);
+                       ino = (void *)ino + UBIFS_INO_NODE_SZ;
+                       iput(xino);
+
+                       kfree(pxent);
+                       pxent = xent;
+                       key_read(c, &xent->key, &key);
+               }
+               kfree(pxent);
+       }
+
        pack_inode(c, ino, inode, 1);
        err = ubifs_node_calc_hash(c, ino, hash);
        if (err)
                goto out_release;
 
-       err = write_head(c, BASEHD, ino, write_len, &lnum, &offs, sync);
+       err = write_head(c, BASEHD, ino_start, write_len, &lnum, &offs, sync);
        if (err)
                goto out_release;
        if (!sync)
@@ -903,7 +953,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
                if (err)
                        goto out_ro;
                ubifs_delete_orphan(c, inode->i_ino);
-               err = ubifs_add_dirt(c, lnum, ilen);
+               err = ubifs_add_dirt(c, lnum, write_len);
        } else {
                union ubifs_key key;
 
@@ -917,7 +967,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
        spin_lock(&ui->ui_lock);
        ui->synced_i_size = ui->ui_size;
        spin_unlock(&ui->ui_lock);
-       kfree(ino);
+       kfree(ino_start);
        return 0;
 
 out_release:
@@ -926,7 +976,7 @@ out_ro:
        ubifs_ro_mode(c, err);
        finish_reservation(c);
 out_free:
-       kfree(ino);
+       kfree(ino_start);
        return err;
 }
 
@@ -966,8 +1016,8 @@ int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode)
 
        ubifs_assert(c, inode->i_nlink == 0);
 
-       if (ui->del_cmtno != c->cmt_no)
-               /* A commit happened for sure */
+       if (ui->xattr_cnt || ui->del_cmtno != c->cmt_no)
+               /* A commit happened for sure or inode hosts xattrs */
                return ubifs_jnl_write_inode(c, inode);
 
        down_read(&c->commit_sem);
index 6f87237fdbf43bddc1455df20edf91abfca60caa..78a6e97f846eed04d18aca1cc933027154980883 100644 (file)
@@ -288,6 +288,14 @@ static inline int ubifs_next_log_lnum(const struct ubifs_info *c, int lnum)
        return lnum;
 }
 
+static inline int ubifs_xattr_max_cnt(struct ubifs_info *c)
+{
+       int max_xattrs = (c->leb_size / 2) / UBIFS_INO_NODE_SZ;
+
+       ubifs_assert(c, max_xattrs < c->max_orphans);
+       return max_xattrs;
+}
+
 const char *ubifs_assert_action_name(struct ubifs_info *c);
 
 #endif /* __UBIFS_MISC_H__ */
index 8f70494efb0c65123f55d4633dd515b205549a2f..2f1618f300fb087b889cc8382db935072a91a677 100644 (file)
 
 static int dbg_check_orphans(struct ubifs_info *c);
 
-/**
- * ubifs_add_orphan - add an orphan.
- * @c: UBIFS file-system description object
- * @inum: orphan inode number
- *
- * Add an orphan. This function is called when an inodes link count drops to
- * zero.
- */
-int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
+static struct ubifs_orphan *orphan_add(struct ubifs_info *c, ino_t inum,
+                                      struct ubifs_orphan *parent_orphan)
 {
        struct ubifs_orphan *orphan, *o;
        struct rb_node **p, *parent = NULL;
 
        orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_NOFS);
        if (!orphan)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
        orphan->inum = inum;
        orphan->new = 1;
+       INIT_LIST_HEAD(&orphan->child_list);
 
        spin_lock(&c->orphan_lock);
        if (c->tot_orphans >= c->max_orphans) {
                spin_unlock(&c->orphan_lock);
                kfree(orphan);
-               return -ENFILE;
+               return ERR_PTR(-ENFILE);
        }
        p = &c->orph_tree.rb_node;
        while (*p) {
@@ -91,7 +85,7 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
                        ubifs_err(c, "orphaned twice");
                        spin_unlock(&c->orphan_lock);
                        kfree(orphan);
-                       return 0;
+                       return ERR_PTR(-EINVAL);
                }
        }
        c->tot_orphans += 1;
@@ -100,24 +94,22 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
        rb_insert_color(&orphan->rb, &c->orph_tree);
        list_add_tail(&orphan->list, &c->orph_list);
        list_add_tail(&orphan->new_list, &c->orph_new);
+
+       if (parent_orphan) {
+               list_add_tail(&orphan->child_list,
+                             &parent_orphan->child_list);
+       }
+
        spin_unlock(&c->orphan_lock);
        dbg_gen("ino %lu", (unsigned long)inum);
-       return 0;
+       return orphan;
 }
 
-/**
- * ubifs_delete_orphan - delete an orphan.
- * @c: UBIFS file-system description object
- * @inum: orphan inode number
- *
- * Delete an orphan. This function is called when an inode is deleted.
- */
-void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum)
+static struct ubifs_orphan *lookup_orphan(struct ubifs_info *c, ino_t inum)
 {
        struct ubifs_orphan *o;
        struct rb_node *p;
 
-       spin_lock(&c->orphan_lock);
        p = c->orph_tree.rb_node;
        while (p) {
                o = rb_entry(p, struct ubifs_orphan, rb);
@@ -126,37 +118,124 @@ void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum)
                else if (inum > o->inum)
                        p = p->rb_right;
                else {
-                       if (o->del) {
-                               spin_unlock(&c->orphan_lock);
-                               dbg_gen("deleted twice ino %lu",
-                                       (unsigned long)inum);
-                               return;
-                       }
-                       if (o->cmt) {
-                               o->del = 1;
-                               o->dnext = c->orph_dnext;
-                               c->orph_dnext = o;
-                               spin_unlock(&c->orphan_lock);
-                               dbg_gen("delete later ino %lu",
-                                       (unsigned long)inum);
-                               return;
-                       }
-                       rb_erase(p, &c->orph_tree);
-                       list_del(&o->list);
-                       c->tot_orphans -= 1;
-                       if (o->new) {
-                               list_del(&o->new_list);
-                               c->new_orphans -= 1;
-                       }
-                       spin_unlock(&c->orphan_lock);
-                       kfree(o);
-                       dbg_gen("inum %lu", (unsigned long)inum);
-                       return;
+                       return o;
                }
        }
+       return NULL;
+}
+
+static void __orphan_drop(struct ubifs_info *c, struct ubifs_orphan *o)
+{
+       rb_erase(&o->rb, &c->orph_tree);
+       list_del(&o->list);
+       c->tot_orphans -= 1;
+
+       if (o->new) {
+               list_del(&o->new_list);
+               c->new_orphans -= 1;
+       }
+
+       kfree(o);
+}
+
+static void orphan_delete(struct ubifs_info *c, ino_t inum)
+{
+       struct ubifs_orphan *orph, *child_orph, *tmp_o;
+
+       spin_lock(&c->orphan_lock);
+
+       orph = lookup_orphan(c, inum);
+       if (!orph) {
+               spin_unlock(&c->orphan_lock);
+               ubifs_err(c, "missing orphan ino %lu", (unsigned long)inum);
+               dump_stack();
+
+               return;
+       }
+
+       if (orph->del) {
+               spin_unlock(&c->orphan_lock);
+               dbg_gen("deleted twice ino %lu",
+                       (unsigned long)inum);
+               return;
+       }
+
+       if (orph->cmt) {
+               orph->del = 1;
+               orph->dnext = c->orph_dnext;
+               c->orph_dnext = orph;
+               spin_unlock(&c->orphan_lock);
+               dbg_gen("delete later ino %lu",
+                       (unsigned long)inum);
+               return;
+       }
+
+       list_for_each_entry_safe(child_orph, tmp_o, &orph->child_list, child_list) {
+               list_del(&child_orph->child_list);
+               __orphan_drop(c, child_orph);
+       }
+
+       __orphan_drop(c, orph);
+
        spin_unlock(&c->orphan_lock);
-       ubifs_err(c, "missing orphan ino %lu", (unsigned long)inum);
-       dump_stack();
+}
+
+/**
+ * ubifs_add_orphan - add an orphan.
+ * @c: UBIFS file-system description object
+ * @inum: orphan inode number
+ *
+ * Add an orphan. This function is called when an inodes link count drops to
+ * zero.
+ */
+int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
+{
+       int err = 0;
+       ino_t xattr_inum;
+       union ubifs_key key;
+       struct ubifs_dent_node *xent;
+       struct fscrypt_name nm = {0};
+       struct ubifs_orphan *xattr_orphan;
+       struct ubifs_orphan *orphan;
+
+       orphan = orphan_add(c, inum, NULL);
+       if (IS_ERR(orphan))
+               return PTR_ERR(orphan);
+
+       lowest_xent_key(c, &key, inum);
+       while (1) {
+               xent = ubifs_tnc_next_ent(c, &key, &nm);
+               if (IS_ERR(xent)) {
+                       err = PTR_ERR(xent);
+                       if (err == -ENOENT)
+                               break;
+                       return err;
+               }
+
+               fname_name(&nm) = xent->name;
+               fname_len(&nm) = le16_to_cpu(xent->nlen);
+               xattr_inum = le64_to_cpu(xent->inum);
+
+               xattr_orphan = orphan_add(c, xattr_inum, orphan);
+               if (IS_ERR(xattr_orphan))
+                       return PTR_ERR(xattr_orphan);
+
+               key_read(c, &xent->key, &key);
+       }
+
+       return 0;
+}
+
+/**
+ * ubifs_delete_orphan - delete an orphan.
+ * @c: UBIFS file-system description object
+ * @inum: orphan inode number
+ *
+ * Delete an orphan. This function is called when an inode is deleted.
+ */
+void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum)
+{
+       orphan_delete(c, inum);
 }
 
 /**
@@ -611,10 +690,16 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 
                n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3;
                for (i = 0; i < n; i++) {
+                       union ubifs_key key1, key2;
+
                        inum = le64_to_cpu(orph->inos[i]);
                        dbg_rcvry("deleting orphaned inode %lu",
                                  (unsigned long)inum);
-                       err = ubifs_tnc_remove_ino(c, inum);
+
+                       lowest_ino_key(c, &key1, inum);
+                       highest_ino_key(c, &key2, inum);
+
+                       err = ubifs_tnc_remove_range(c, &key1, &key2);
                        if (err)
                                return err;
                        err = insert_dead_orphan(c, inum);
@@ -744,26 +829,15 @@ struct check_info {
        struct rb_root root;
 };
 
-static int dbg_find_orphan(struct ubifs_info *c, ino_t inum)
+static bool dbg_find_orphan(struct ubifs_info *c, ino_t inum)
 {
-       struct ubifs_orphan *o;
-       struct rb_node *p;
+       bool found = false;
 
        spin_lock(&c->orphan_lock);
-       p = c->orph_tree.rb_node;
-       while (p) {
-               o = rb_entry(p, struct ubifs_orphan, rb);
-               if (inum < o->inum)
-                       p = p->rb_left;
-               else if (inum > o->inum)
-                       p = p->rb_right;
-               else {
-                       spin_unlock(&c->orphan_lock);
-                       return 1;
-               }
-       }
+       found = !!lookup_orphan(c, inum);
        spin_unlock(&c->orphan_lock);
-       return 0;
+
+       return found;
 }
 
 static int dbg_ins_check_orphan(struct rb_root *root, ino_t inum)
index 67fac1e8adfbf4d02da3a9f3d92bf40450c9b31c..2afc8b1d4c3b6b5128fc3cd9b74ebd345cbc6794 100644 (file)
@@ -748,14 +748,12 @@ int ubifs_read_superblock(struct ubifs_info *c)
                goto out;
        }
 
-#ifndef CONFIG_FS_ENCRYPTION
-       if (c->encrypted) {
+       if (!IS_ENABLED(CONFIG_UBIFS_FS_ENCRYPTION) && c->encrypted) {
                ubifs_err(c, "file system contains encrypted files but UBIFS"
                             " was built without crypto support.");
                err = -EINVAL;
                goto out;
        }
-#endif
 
        /* Automatically increase file system size to the maximum size */
        c->old_leb_cnt = c->leb_cnt;
@@ -943,6 +941,9 @@ int ubifs_enable_encryption(struct ubifs_info *c)
        int err;
        struct ubifs_sb_node *sup = c->sup_node;
 
+       if (!IS_ENABLED(CONFIG_UBIFS_FS_ENCRYPTION))
+               return -EOPNOTSUPP;
+
        if (c->encrypted)
                return 0;
 
index 632f02d4d660d73456f5bfa277423da0a5c0cea4..04b8ecfd347013540ef53dc7c607b431f15626d5 100644 (file)
@@ -129,9 +129,10 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
                goto out_ino;
 
        inode->i_flags |= S_NOCMTIME;
-#ifndef CONFIG_UBIFS_ATIME_SUPPORT
-       inode->i_flags |= S_NOATIME;
-#endif
+
+       if (!IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
+               inode->i_flags |= S_NOATIME;
+
        set_nlink(inode, le32_to_cpu(ino->nlink));
        i_uid_write(inode, le32_to_cpu(ino->uid));
        i_gid_write(inode, le32_to_cpu(ino->gid));
@@ -1545,6 +1546,8 @@ static int mount_ubifs(struct ubifs_info *c)
                c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20);
        dbg_gen("max. seq. number:    %llu", c->max_sqnum);
        dbg_gen("commit number:       %llu", c->cmt_no);
+       dbg_gen("max. xattrs per inode: %d", ubifs_xattr_max_cnt(c));
+       dbg_gen("max orphans:           %d", c->max_orphans);
 
        return 0;
 
@@ -2141,9 +2144,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
 #ifdef CONFIG_UBIFS_FS_XATTR
        sb->s_xattr = ubifs_xattr_handlers;
 #endif
-#ifdef CONFIG_FS_ENCRYPTION
-       sb->s_cop = &ubifs_crypt_operations;
-#endif
+       fscrypt_set_ops(sb, &ubifs_crypt_operations);
 
        mutex_lock(&c->umount_mutex);
        err = mount_ubifs(c);
@@ -2245,11 +2246,10 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
                        goto out_deact;
                /* We do not support atime */
                sb->s_flags |= SB_ACTIVE;
-#ifndef CONFIG_UBIFS_ATIME_SUPPORT
-               sb->s_flags |= SB_NOATIME;
-#else
-               ubifs_msg(c, "full atime support is enabled.");
-#endif
+               if (IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
+                       ubifs_msg(c, "full atime support is enabled.");
+               else
+                       sb->s_flags |= SB_NOATIME;
        }
 
        /* 'fill_super()' opens ubi again so we must close it here */
index 25572ffea1634964785aee3b05590cf439dddd6d..ebf8c26f5b22f1722118252dc250c2b25e16b1b2 100644 (file)
@@ -479,14 +479,13 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
        if (node_len != len)
                return 0;
 
-       if (type == UBIFS_DATA_NODE && c->no_chk_data_crc && !c->mounting &&
-           !c->remounting_rw)
-               return 1;
-
-       crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
-       node_crc = le32_to_cpu(ch->crc);
-       if (crc != node_crc)
-               return 0;
+       if (type != UBIFS_DATA_NODE || !c->no_chk_data_crc || c->mounting ||
+           c->remounting_rw) {
+               crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
+               node_crc = le32_to_cpu(ch->crc);
+               if (crc != node_crc)
+                       return 0;
+       }
 
        err = ubifs_node_check_hash(c, buf, zbr->hash);
        if (err) {
index 1ae12900e01d3ac6cab7601d2188baa5613e40ff..379b9f791ff63edc9890c5f43438630a1e67c3ad 100644 (file)
@@ -924,6 +924,8 @@ struct ubifs_budget_req {
  * @rb: rb-tree node of rb-tree of orphans sorted by inode number
  * @list: list head of list of orphans in order added
  * @new_list: list head of list of orphans added since the last commit
+ * @child_list: list of xattr childs if this orphan hosts xattrs, list head
+ * if this orphan is a xattr, not used otherwise.
  * @cnext: next orphan to commit
  * @dnext: next orphan to delete
  * @inum: inode number
@@ -935,6 +937,7 @@ struct ubifs_orphan {
        struct rb_node rb;
        struct list_head list;
        struct list_head new_list;
+       struct list_head child_list;
        struct ubifs_orphan *cnext;
        struct ubifs_orphan *dnext;
        ino_t inum;
@@ -1996,9 +1999,7 @@ int ubifs_calc_dark(const struct ubifs_info *c, int spc);
 /* file.c */
 int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync);
 int ubifs_setattr(struct dentry *dentry, struct iattr *attr);
-#ifdef CONFIG_UBIFS_ATIME_SUPPORT
 int ubifs_update_time(struct inode *inode, struct timespec64 *time, int flags);
-#endif
 
 /* dir.c */
 struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
@@ -2014,6 +2015,7 @@ int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
                    size_t size, int flags, bool check_lock);
 ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
                        size_t size);
+int ubifs_purge_xattrs(struct inode *host);
 
 #ifdef CONFIG_UBIFS_FS_XATTR
 void ubifs_evict_xattr_inode(struct ubifs_info *c, ino_t xattr_inum);
index f5ad1ede7990789518d96ec45218dd667476fb87..acab3181ab35f655e858a93558309be854d1d1b7 100644 (file)
 #include <linux/slab.h>
 #include <linux/xattr.h>
 
-/*
- * Limit the number of extended attributes per inode so that the total size
- * (@xattr_size) is guaranteeded to fit in an 'unsigned int'.
- */
-#define MAX_XATTRS_PER_INODE 65535
-
 /*
  * Extended attribute type constants.
  *
@@ -106,7 +100,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
                                .new_ino_d = ALIGN(size, 8), .dirtied_ino = 1,
                                .dirtied_ino_d = ALIGN(host_ui->data_len, 8) };
 
-       if (host_ui->xattr_cnt >= MAX_XATTRS_PER_INODE) {
+       if (host_ui->xattr_cnt >= ubifs_xattr_max_cnt(c)) {
                ubifs_err(c, "inode %lu already has too many xattrs (%d), cannot create more",
                          host->i_ino, host_ui->xattr_cnt);
                return -ENOSPC;
@@ -507,6 +501,69 @@ out_cancel:
        return err;
 }
 
+int ubifs_purge_xattrs(struct inode *host)
+{
+       union ubifs_key key;
+       struct ubifs_info *c = host->i_sb->s_fs_info;
+       struct ubifs_dent_node *xent, *pxent = NULL;
+       struct inode *xino;
+       struct fscrypt_name nm = {0};
+       int err;
+
+       if (ubifs_inode(host)->xattr_cnt < ubifs_xattr_max_cnt(c))
+               return 0;
+
+       ubifs_warn(c, "inode %lu has too many xattrs, doing a non-atomic deletion",
+                  host->i_ino);
+
+       lowest_xent_key(c, &key, host->i_ino);
+       while (1) {
+               xent = ubifs_tnc_next_ent(c, &key, &nm);
+               if (IS_ERR(xent)) {
+                       err = PTR_ERR(xent);
+                       break;
+               }
+
+               fname_name(&nm) = xent->name;
+               fname_len(&nm) = le16_to_cpu(xent->nlen);
+
+               xino = ubifs_iget(c->vfs_sb, xent->inum);
+               if (IS_ERR(xino)) {
+                       err = PTR_ERR(xino);
+                       ubifs_err(c, "dead directory entry '%s', error %d",
+                                 xent->name, err);
+                       ubifs_ro_mode(c, err);
+                       kfree(pxent);
+                       return err;
+               }
+
+               ubifs_assert(c, ubifs_inode(xino)->xattr);
+
+               clear_nlink(xino);
+               err = remove_xattr(c, host, xino, &nm);
+               if (err) {
+                       kfree(pxent);
+                       iput(xino);
+                       ubifs_err(c, "cannot remove xattr, error %d", err);
+                       return err;
+               }
+
+               iput(xino);
+
+               kfree(pxent);
+               pxent = xent;
+               key_read(c, &xent->key, &key);
+       }
+
+       kfree(pxent);
+       if (err != -ENOENT) {
+               ubifs_err(c, "cannot find next direntry, error %d", err);
+               return err;
+       }
+
+       return 0;
+}
+
 /**
  * ubifs_evict_xattr_inode - Evict an xattr inode.
  * @c: UBIFS file-system description object
index 58cc2414992b673296ff2d9408c62f3bd07b6f35..77b6d89b9bcdd154c14768afd5aa458ece5f9234 100644 (file)
@@ -304,21 +304,6 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
        if (dentry->d_name.len > UDF_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
 
-#ifdef UDF_RECOVERY
-       /* temporary shorthand for specifying files by inode number */
-       if (!strncmp(dentry->d_name.name, ".B=", 3)) {
-               struct kernel_lb_addr lb = {
-                       .logicalBlockNum = 0,
-                       .partitionReferenceNum =
-                               simple_strtoul(dentry->d_name.name + 3,
-                                               NULL, 0),
-               };
-               inode = udf_iget(dir->i_sb, lb);
-               if (IS_ERR(inode))
-                       return inode;
-       } else
-#endif /* UDF_RECOVERY */
-
        fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
        if (IS_ERR(fi))
                return ERR_CAST(fi);
index f64691f2168a3b8d8e1515f89e7ef5e60fefd7b5..a143461373614bd295f37739036a6edb54a48885 100644 (file)
@@ -566,6 +566,11 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
                        if (!remount) {
                                if (uopt->nls_map)
                                        unload_nls(uopt->nls_map);
+                               /*
+                                * load_nls() failure is handled later in
+                                * udf_fill_super() after all options are
+                                * parsed.
+                                */
                                uopt->nls_map = load_nls(args[0].from);
                                uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
                        }
index f5de1e726356a51c27ff529f98d99032650eb839..3b30301c90ec309ac17c608e1db2c7742e29c173 100644 (file)
@@ -30,6 +30,8 @@
 #include <linux/security.h>
 #include <linux/hugetlb.h>
 
+int sysctl_unprivileged_userfaultfd __read_mostly = 1;
+
 static struct kmem_cache *userfaultfd_ctx_cachep __read_mostly;
 
 enum userfaultfd_state {
@@ -1930,6 +1932,9 @@ SYSCALL_DEFINE1(userfaultfd, int, flags)
        struct userfaultfd_ctx *ctx;
        int fd;
 
+       if (!sysctl_unprivileged_userfaultfd && !capable(CAP_SYS_PTRACE))
+               return -EPERM;
+
        BUG_ON(!current->mm);
 
        /* Check the UFFD_* constants for consistency.  */
index 2a462cf4eaa928c6c31216741948a44a3b3505b9..52d4375bde9d3e49c91e0659bdc64613b1e7f656 100644 (file)
@@ -230,7 +230,7 @@ struct acpi_device_dir {
 /* Plug and Play */
 
 typedef char acpi_bus_id[8];
-typedef unsigned long acpi_bus_address;
+typedef u64 acpi_bus_address;
 typedef char acpi_device_name[40];
 typedef char acpi_device_class[20];
 
index 3b1b1d0e4c33fc7b309cfb68f600a07fc1e8b5cc..4a8a05401fb53cef2e21d62c02ffac7edf143eb8 100644 (file)
@@ -12,7 +12,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20190405
+#define ACPI_CA_VERSION                 0x20190509
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
index 624b90b340852c65104d8de894fb7d9a5a555f53..310501994c028561c2dda7feeed24efc9ecddad2 100644 (file)
 
 #define ACPI_INIT_FUNCTION __init
 
+/* Use a specific bugging default separate from ACPICA */
+
+#undef ACPI_DEBUG_DEFAULT
+#define ACPI_DEBUG_DEFAULT          (ACPI_LV_INFO | ACPI_LV_REPAIR)
+
 #ifndef CONFIG_ACPI
 
 /* External globals for __KERNEL__, stubs is needed */
 #define ACPI_NO_ERROR_MESSAGES
 #undef ACPI_DEBUG_OUTPUT
 
-/* Use a specific bugging default separate from ACPICA */
-
-#undef ACPI_DEBUG_DEFAULT
-#define ACPI_DEBUG_DEFAULT          (ACPI_LV_INFO | ACPI_LV_REPAIR)
-
 /* External interface for __KERNEL__, stub is needed */
 
 #define ACPI_EXTERNAL_RETURN_STATUS(prototype) \
index 71d7b77eea50f9c8724d0220fdad17bf4f67db7e..822f433ac95cb665387cffe17198d0d860836d64 100644 (file)
@@ -126,4 +126,11 @@ static inline pte_t huge_ptep_get(pte_t *ptep)
 }
 #endif
 
+#ifndef __HAVE_ARCH_GIGANTIC_PAGE_RUNTIME_SUPPORTED
+static inline bool gigantic_page_runtime_supported(void)
+{
+       return IS_ENABLED(CONFIG_ARCH_HAS_GIGANTIC_PAGE);
+}
+#endif /* __HAVE_ARCH_GIGANTIC_PAGE_RUNTIME_SUPPORTED */
+
 #endif /* _ASM_GENERIC_HUGETLB_H */
diff --git a/include/asm-generic/segment.h b/include/asm-generic/segment.h
deleted file mode 100644 (file)
index 5580eac..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __ASM_GENERIC_SEGMENT_H
-#define __ASM_GENERIC_SEGMENT_H
-/*
- * Only here because we have some old header files that expect it...
- *
- * New architectures probably don't want to have their own version.
- */
-
-#endif /* __ASM_GENERIC_SEGMENT_H */
index 8b78c0ba08b1f4a2326e677827b7e6d95ab39d9e..b8f9035ffc2c38ecf7d24412dc3f023ccdd5e48f 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* SPDX-License-Identifier: GPL-2.0 */
 #ifndef __ASM_GENERIC_SHMPARAM_H
 #define __ASM_GENERIC_SHMPARAM_H
 
diff --git a/include/asm-generic/sizes.h b/include/asm-generic/sizes.h
deleted file mode 100644 (file)
index 1dcfad9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/* This is a placeholder, to be removed over time */
-#include <linux/sizes.h>
index b3d2241e03f81c5d11d8bfb9bacb8f2e6676292f..e935318804f8aedb6319c4f63f89e5bf8a46c5b0 100644 (file)
@@ -9,7 +9,63 @@
  */
 #include <linux/string.h>
 
-#include <asm/segment.h>
+#ifdef CONFIG_UACCESS_MEMCPY
+static inline __must_check unsigned long
+raw_copy_from_user(void *to, const void __user * from, unsigned long n)
+{
+       if (__builtin_constant_p(n)) {
+               switch(n) {
+               case 1:
+                       *(u8 *)to = *(u8 __force *)from;
+                       return 0;
+               case 2:
+                       *(u16 *)to = *(u16 __force *)from;
+                       return 0;
+               case 4:
+                       *(u32 *)to = *(u32 __force *)from;
+                       return 0;
+#ifdef CONFIG_64BIT
+               case 8:
+                       *(u64 *)to = *(u64 __force *)from;
+                       return 0;
+#endif
+               }
+       }
+
+       memcpy(to, (const void __force *)from, n);
+       return 0;
+}
+
+static inline __must_check unsigned long
+raw_copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+       if (__builtin_constant_p(n)) {
+               switch(n) {
+               case 1:
+                       *(u8 __force *)to = *(u8 *)from;
+                       return 0;
+               case 2:
+                       *(u16 __force *)to = *(u16 *)from;
+                       return 0;
+               case 4:
+                       *(u32 __force *)to = *(u32 *)from;
+                       return 0;
+#ifdef CONFIG_64BIT
+               case 8:
+                       *(u64 __force *)to = *(u64 *)from;
+                       return 0;
+#endif
+               default:
+                       break;
+               }
+       }
+
+       memcpy((void __force *)to, from, n);
+       return 0;
+}
+#define INLINE_COPY_FROM_USER
+#define INLINE_COPY_TO_USER
+#endif /* CONFIG_UACCESS_MEMCPY */
 
 #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
 
index bbb9e332f2fe6c4a0f7171e1549a3c0153db3150..088987e9a3eaa3417ce2f4ca104caab2b5496c77 100644 (file)
                __start_rodata = .;                                     \
                *(.rodata) *(.rodata.*)                                 \
                RO_AFTER_INIT_DATA      /* Read only after init */      \
-               KEEP(*(__vermagic))     /* Kernel version magic */      \
                . = ALIGN(8);                                           \
                __start___tracepoints_ptrs = .;                         \
                KEEP(*(__tracepoints_ptrs)) /* Tracepoints: pointer array */ \
diff --git a/include/dt-bindings/clock/xlnx,zynqmp-clk.h b/include/dt-bindings/clock/xlnx,zynqmp-clk.h
deleted file mode 100644 (file)
index 4aebe6e..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Xilinx Zynq MPSoC Firmware layer
- *
- *  Copyright (C) 2014-2018 Xilinx, Inc.
- *
- */
-
-#ifndef _DT_BINDINGS_CLK_ZYNQMP_H
-#define _DT_BINDINGS_CLK_ZYNQMP_H
-
-#define IOPLL                  0
-#define RPLL                   1
-#define APLL                   2
-#define DPLL                   3
-#define VPLL                   4
-#define IOPLL_TO_FPD           5
-#define RPLL_TO_FPD            6
-#define APLL_TO_LPD            7
-#define DPLL_TO_LPD            8
-#define VPLL_TO_LPD            9
-#define ACPU                   10
-#define ACPU_HALF              11
-#define DBF_FPD                        12
-#define DBF_LPD                        13
-#define DBG_TRACE              14
-#define DBG_TSTMP              15
-#define DP_VIDEO_REF           16
-#define DP_AUDIO_REF           17
-#define DP_STC_REF             18
-#define GDMA_REF               19
-#define DPDMA_REF              20
-#define DDR_REF                        21
-#define SATA_REF               22
-#define PCIE_REF               23
-#define GPU_REF                        24
-#define GPU_PP0_REF            25
-#define GPU_PP1_REF            26
-#define TOPSW_MAIN             27
-#define TOPSW_LSBUS            28
-#define GTGREF0_REF            29
-#define LPD_SWITCH             30
-#define LPD_LSBUS              31
-#define USB0_BUS_REF           32
-#define USB1_BUS_REF           33
-#define USB3_DUAL_REF          34
-#define USB0                   35
-#define USB1                   36
-#define CPU_R5                 37
-#define CPU_R5_CORE            38
-#define CSU_SPB                        39
-#define CSU_PLL                        40
-#define PCAP                   41
-#define IOU_SWITCH             42
-#define GEM_TSU_REF            43
-#define GEM_TSU                        44
-#define GEM0_REF               45
-#define GEM1_REF               46
-#define GEM2_REF               47
-#define GEM3_REF               48
-#define GEM0_TX                        49
-#define GEM1_TX                        50
-#define GEM2_TX                        51
-#define GEM3_TX                        52
-#define QSPI_REF               53
-#define SDIO0_REF              54
-#define SDIO1_REF              55
-#define UART0_REF              56
-#define UART1_REF              57
-#define SPI0_REF               58
-#define SPI1_REF               59
-#define NAND_REF               60
-#define I2C0_REF               61
-#define I2C1_REF               62
-#define CAN0_REF               63
-#define CAN1_REF               64
-#define CAN0                   65
-#define CAN1                   66
-#define DLL_REF                        67
-#define ADMA_REF               68
-#define TIMESTAMP_REF          69
-#define AMS_REF                        70
-#define PL0_REF                        71
-#define PL1_REF                        72
-#define PL2_REF                        73
-#define PL3_REF                        74
-#define WDT                    75
-#define IOPLL_INT              76
-#define IOPLL_PRE_SRC          77
-#define IOPLL_HALF             78
-#define IOPLL_INT_MUX          79
-#define IOPLL_POST_SRC         80
-#define RPLL_INT               81
-#define RPLL_PRE_SRC           82
-#define RPLL_HALF              83
-#define RPLL_INT_MUX           84
-#define RPLL_POST_SRC          85
-#define APLL_INT               86
-#define APLL_PRE_SRC           87
-#define APLL_HALF              88
-#define APLL_INT_MUX           89
-#define APLL_POST_SRC          90
-#define DPLL_INT               91
-#define DPLL_PRE_SRC           92
-#define DPLL_HALF              93
-#define DPLL_INT_MUX           94
-#define DPLL_POST_SRC          95
-#define VPLL_INT               96
-#define VPLL_PRE_SRC           97
-#define VPLL_HALF              98
-#define VPLL_INT_MUX           99
-#define VPLL_POST_SRC          100
-#define CAN0_MIO               101
-#define CAN1_MIO               102
-
-#endif
diff --git a/include/dt-bindings/clock/xlnx-zynqmp-clk.h b/include/dt-bindings/clock/xlnx-zynqmp-clk.h
new file mode 100644 (file)
index 0000000..cdc4c0b
--- /dev/null
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Xilinx Zynq MPSoC Firmware layer
+ *
+ *  Copyright (C) 2014-2018 Xilinx, Inc.
+ *
+ */
+
+#ifndef _DT_BINDINGS_CLK_ZYNQMP_H
+#define _DT_BINDINGS_CLK_ZYNQMP_H
+
+#define IOPLL                  0
+#define RPLL                   1
+#define APLL                   2
+#define DPLL                   3
+#define VPLL                   4
+#define IOPLL_TO_FPD           5
+#define RPLL_TO_FPD            6
+#define APLL_TO_LPD            7
+#define DPLL_TO_LPD            8
+#define VPLL_TO_LPD            9
+#define ACPU                   10
+#define ACPU_HALF              11
+#define DBF_FPD                        12
+#define DBF_LPD                        13
+#define DBG_TRACE              14
+#define DBG_TSTMP              15
+#define DP_VIDEO_REF           16
+#define DP_AUDIO_REF           17
+#define DP_STC_REF             18
+#define GDMA_REF               19
+#define DPDMA_REF              20
+#define DDR_REF                        21
+#define SATA_REF               22
+#define PCIE_REF               23
+#define GPU_REF                        24
+#define GPU_PP0_REF            25
+#define GPU_PP1_REF            26
+#define TOPSW_MAIN             27
+#define TOPSW_LSBUS            28
+#define GTGREF0_REF            29
+#define LPD_SWITCH             30
+#define LPD_LSBUS              31
+#define USB0_BUS_REF           32
+#define USB1_BUS_REF           33
+#define USB3_DUAL_REF          34
+#define USB0                   35
+#define USB1                   36
+#define CPU_R5                 37
+#define CPU_R5_CORE            38
+#define CSU_SPB                        39
+#define CSU_PLL                        40
+#define PCAP                   41
+#define IOU_SWITCH             42
+#define GEM_TSU_REF            43
+#define GEM_TSU                        44
+#define GEM0_TX                        45
+#define GEM1_TX                        46
+#define GEM2_TX                        47
+#define GEM3_TX                        48
+#define GEM0_RX                        49
+#define GEM1_RX                        50
+#define GEM2_RX                        51
+#define GEM3_RX                        52
+#define QSPI_REF               53
+#define SDIO0_REF              54
+#define SDIO1_REF              55
+#define UART0_REF              56
+#define UART1_REF              57
+#define SPI0_REF               58
+#define SPI1_REF               59
+#define NAND_REF               60
+#define I2C0_REF               61
+#define I2C1_REF               62
+#define CAN0_REF               63
+#define CAN1_REF               64
+#define CAN0                   65
+#define CAN1                   66
+#define DLL_REF                        67
+#define ADMA_REF               68
+#define TIMESTAMP_REF          69
+#define AMS_REF                        70
+#define PL0_REF                        71
+#define PL1_REF                        72
+#define PL2_REF                        73
+#define PL3_REF                        74
+#define WDT                    75
+#define IOPLL_INT              76
+#define IOPLL_PRE_SRC          77
+#define IOPLL_HALF             78
+#define IOPLL_INT_MUX          79
+#define IOPLL_POST_SRC         80
+#define RPLL_INT               81
+#define RPLL_PRE_SRC           82
+#define RPLL_HALF              83
+#define RPLL_INT_MUX           84
+#define RPLL_POST_SRC          85
+#define APLL_INT               86
+#define APLL_PRE_SRC           87
+#define APLL_HALF              88
+#define APLL_INT_MUX           89
+#define APLL_POST_SRC          90
+#define DPLL_INT               91
+#define DPLL_PRE_SRC           92
+#define DPLL_HALF              93
+#define DPLL_INT_MUX           94
+#define DPLL_POST_SRC          95
+#define VPLL_INT               96
+#define VPLL_PRE_SRC           97
+#define VPLL_HALF              98
+#define VPLL_INT_MUX           99
+#define VPLL_POST_SRC          100
+#define CAN0_MIO               101
+#define CAN1_MIO               102
+#define ACPU_FULL              103
+#define GEM0_REF               104
+#define GEM1_REF               105
+#define GEM2_REF               106
+#define GEM3_REF               107
+#define GEM0_REF_UNG           108
+#define GEM1_REF_UNG           109
+#define GEM2_REF_UNG           110
+#define GEM3_REF_UNG           111
+#define LPD_WDT                        112
+
+#endif
index 4481f2d60d6538442bf7b615c89c7bf3c64ca0ef..4e61f64850975e274ed50a9ec403a1086e0babca 100644 (file)
 #define IMX_SC_R_DC_0_BLIT1            20
 #define IMX_SC_R_DC_0_BLIT2            21
 #define IMX_SC_R_DC_0_BLIT_OUT         22
-#define IMX_SC_R_DC_0_CAPTURE0         23
-#define IMX_SC_R_DC_0_CAPTURE1         24
+#define IMX_SC_R_PERF                  23
 #define IMX_SC_R_DC_0_WARP             25
-#define IMX_SC_R_DC_0_INTEGRAL0                26
-#define IMX_SC_R_DC_0_INTEGRAL1                27
 #define IMX_SC_R_DC_0_VIDEO0           28
 #define IMX_SC_R_DC_0_VIDEO1           29
 #define IMX_SC_R_DC_0_FRAC0            30
-#define IMX_SC_R_DC_0_FRAC1            31
 #define IMX_SC_R_DC_0                  32
 #define IMX_SC_R_GPU_2_PID0            33
 #define IMX_SC_R_DC_0_PLL_0            34
 #define IMX_SC_R_DC_1_BLIT1            37
 #define IMX_SC_R_DC_1_BLIT2            38
 #define IMX_SC_R_DC_1_BLIT_OUT         39
-#define IMX_SC_R_DC_1_CAPTURE0         40
-#define IMX_SC_R_DC_1_CAPTURE1         41
 #define IMX_SC_R_DC_1_WARP             42
-#define IMX_SC_R_DC_1_INTEGRAL0                43
-#define IMX_SC_R_DC_1_INTEGRAL1                44
 #define IMX_SC_R_DC_1_VIDEO0           45
 #define IMX_SC_R_DC_1_VIDEO1           46
 #define IMX_SC_R_DC_1_FRAC0            47
-#define IMX_SC_R_DC_1_FRAC1            48
 #define IMX_SC_R_DC_1                  49
-#define IMX_SC_R_GPU_3_PID0            50
 #define IMX_SC_R_DC_1_PLL_0            51
 #define IMX_SC_R_DC_1_PLL_1            52
 #define IMX_SC_R_SPI_0                 53
 #define IMX_SC_R_M4_0_UART             287
 #define IMX_SC_R_M4_0_I2C              288
 #define IMX_SC_R_M4_0_INTMUX           289
-#define IMX_SC_R_M4_0_SIM              290
-#define IMX_SC_R_M4_0_WDOG             291
 #define IMX_SC_R_M4_0_MU_0B            292
 #define IMX_SC_R_M4_0_MU_0A0           293
 #define IMX_SC_R_M4_0_MU_0A1           294
 #define IMX_SC_R_M4_1_UART             307
 #define IMX_SC_R_M4_1_I2C              308
 #define IMX_SC_R_M4_1_INTMUX           309
-#define IMX_SC_R_M4_1_SIM              310
-#define IMX_SC_R_M4_1_WDOG             311
 #define IMX_SC_R_M4_1_MU_0B            312
 #define IMX_SC_R_M4_1_MU_0A0           313
 #define IMX_SC_R_M4_1_MU_0A1           314
 #define IMX_SC_R_IRQSTR_SCU2           321
 #define IMX_SC_R_IRQSTR_DSP            322
 #define IMX_SC_R_ELCDIF_PLL            323
-#define IMX_SC_R_UNUSED6               324
+#define IMX_SC_R_OCRAM                 324
 #define IMX_SC_R_AUDIO_PLL_0           325
 #define IMX_SC_R_PI_0                  326
 #define IMX_SC_R_PI_0_PWM_0            327
 #define IMX_SC_R_VPU_MU_3              538
 #define IMX_SC_R_VPU_ENC_1             539
 #define IMX_SC_R_VPU                   540
-#define IMX_SC_R_LAST                  541
+#define IMX_SC_R_DMA_5_CH0             541
+#define IMX_SC_R_DMA_5_CH1             542
+#define IMX_SC_R_DMA_5_CH2             543
+#define IMX_SC_R_DMA_5_CH3             544
+#define IMX_SC_R_ATTESTATION           545
+#define IMX_SC_R_LAST                  546
 
 #endif /* __DT_BINDINGS_RSCRC_IMX_H */
index 7d947a597220922a66f4776ff86db4751e016735..17877e85980b290137d12f23a08cf41e743d2325 100644 (file)
 #undef PIN_OFF_INPUT_PULLDOWN
 #undef PIN_OFF_WAKEUPENABLE
 
-#endif
+#define AM335X_PIN_OFFSET_MIN                  0x0800U
+
+#define AM335X_PIN_GPMC_AD0                    0x800
+#define AM335X_PIN_GPMC_AD1                    0x804
+#define AM335X_PIN_GPMC_AD2                    0x808
+#define AM335X_PIN_GPMC_AD3                    0x80c
+#define AM335X_PIN_GPMC_AD4                    0x810
+#define AM335X_PIN_GPMC_AD5                    0x814
+#define AM335X_PIN_GPMC_AD6                    0x818
+#define AM335X_PIN_GPMC_AD7                    0x81c
+#define AM335X_PIN_GPMC_AD8                    0x820
+#define AM335X_PIN_GPMC_AD9                    0x824
+#define AM335X_PIN_GPMC_AD10                   0x828
+#define AM335X_PIN_GPMC_AD11                   0x82c
+#define AM335X_PIN_GPMC_AD12                   0x830
+#define AM335X_PIN_GPMC_AD13                   0x834
+#define AM335X_PIN_GPMC_AD14                   0x838
+#define AM335X_PIN_GPMC_AD15                   0x83c
+#define AM335X_PIN_GPMC_A0                     0x840
+#define AM335X_PIN_GPMC_A1                     0x844
+#define AM335X_PIN_GPMC_A2                     0x848
+#define AM335X_PIN_GPMC_A3                     0x84c
+#define AM335X_PIN_GPMC_A4                     0x850
+#define AM335X_PIN_GPMC_A5                     0x854
+#define AM335X_PIN_GPMC_A6                     0x858
+#define AM335X_PIN_GPMC_A7                     0x85c
+#define AM335X_PIN_GPMC_A8                     0x860
+#define AM335X_PIN_GPMC_A9                     0x864
+#define AM335X_PIN_GPMC_A10                    0x868
+#define AM335X_PIN_GPMC_A11                    0x86c
+#define AM335X_PIN_GPMC_WAIT0                  0x870
+#define AM335X_PIN_GPMC_WPN                    0x874
+#define AM335X_PIN_GPMC_BEN1                   0x878
+#define AM335X_PIN_GPMC_CSN0                   0x87c
+#define AM335X_PIN_GPMC_CSN1                   0x880
+#define AM335X_PIN_GPMC_CSN2                   0x884
+#define AM335X_PIN_GPMC_CSN3                   0x888
+#define AM335X_PIN_GPMC_CLK                    0x88c
+#define AM335X_PIN_GPMC_ADVN_ALE               0x890
+#define AM335X_PIN_GPMC_OEN_REN                        0x894
+#define AM335X_PIN_GPMC_WEN                    0x898
+#define AM335X_PIN_GPMC_BEN0_CLE               0x89c
+#define AM335X_PIN_LCD_DATA0                   0x8a0
+#define AM335X_PIN_LCD_DATA1                   0x8a4
+#define AM335X_PIN_LCD_DATA2                   0x8a8
+#define AM335X_PIN_LCD_DATA3                   0x8ac
+#define AM335X_PIN_LCD_DATA4                   0x8b0
+#define AM335X_PIN_LCD_DATA5                   0x8b4
+#define AM335X_PIN_LCD_DATA6                   0x8b8
+#define AM335X_PIN_LCD_DATA7                   0x8bc
+#define AM335X_PIN_LCD_DATA8                   0x8c0
+#define AM335X_PIN_LCD_DATA9                   0x8c4
+#define AM335X_PIN_LCD_DATA10                  0x8c8
+#define AM335X_PIN_LCD_DATA11                  0x8cc
+#define AM335X_PIN_LCD_DATA12                  0x8d0
+#define AM335X_PIN_LCD_DATA13                  0x8d4
+#define AM335X_PIN_LCD_DATA14                  0x8d8
+#define AM335X_PIN_LCD_DATA15                  0x8dc
+#define AM335X_PIN_LCD_VSYNC                   0x8e0
+#define AM335X_PIN_LCD_HSYNC                   0x8e4
+#define AM335X_PIN_LCD_PCLK                    0x8e8
+#define AM335X_PIN_LCD_AC_BIAS_EN              0x8ec
+#define AM335X_PIN_MMC0_DAT3                   0x8f0
+#define AM335X_PIN_MMC0_DAT2                   0x8f4
+#define AM335X_PIN_MMC0_DAT1                   0x8f8
+#define AM335X_PIN_MMC0_DAT0                   0x8fc
+#define AM335X_PIN_MMC0_CLK                    0x900
+#define AM335X_PIN_MMC0_CMD                    0x904
+#define AM335X_PIN_MII1_COL                    0x908
+#define AM335X_PIN_MII1_CRS                    0x90c
+#define AM335X_PIN_MII1_RX_ER                  0x910
+#define AM335X_PIN_MII1_TX_EN                  0x914
+#define AM335X_PIN_MII1_RX_DV                  0x918
+#define AM335X_PIN_MII1_TXD3                   0x91c
+#define AM335X_PIN_MII1_TXD2                   0x920
+#define AM335X_PIN_MII1_TXD1                   0x924
+#define AM335X_PIN_MII1_TXD0                   0x928
+#define AM335X_PIN_MII1_TX_CLK                 0x92c
+#define AM335X_PIN_MII1_RX_CLK                 0x930
+#define AM335X_PIN_MII1_RXD3                   0x934
+#define AM335X_PIN_MII1_RXD2                   0x938
+#define AM335X_PIN_MII1_RXD1                   0x93c
+#define AM335X_PIN_MII1_RXD0                   0x940
+#define AM335X_PIN_RMII1_REF_CLK               0x944
+#define AM335X_PIN_MDIO                                0x948
+#define AM335X_PIN_MDC                         0x94c
+#define AM335X_PIN_SPI0_SCLK                   0x950
+#define AM335X_PIN_SPI0_D0                     0x954
+#define AM335X_PIN_SPI0_D1                     0x958
+#define AM335X_PIN_SPI0_CS0                    0x95c
+#define AM335X_PIN_SPI0_CS1                    0x960
+#define AM335X_PIN_ECAP0_IN_PWM0_OUT           0x964
+#define AM335X_PIN_UART0_CTSN                  0x968
+#define AM335X_PIN_UART0_RTSN                  0x96c
+#define AM335X_PIN_UART0_RXD                   0x970
+#define AM335X_PIN_UART0_TXD                   0x974
+#define AM335X_PIN_UART1_CTSN                  0x978
+#define AM335X_PIN_UART1_RTSN                  0x97c
+#define AM335X_PIN_UART1_RXD                   0x980
+#define AM335X_PIN_UART1_TXD                   0x984
+#define AM335X_PIN_I2C0_SDA                    0x988
+#define AM335X_PIN_I2C0_SCL                    0x98c
+#define AM335X_PIN_MCASP0_ACLKX                        0x990
+#define AM335X_PIN_MCASP0_FSX                  0x994
+#define AM335X_PIN_MCASP0_AXR0                 0x998
+#define AM335X_PIN_MCASP0_AHCLKR               0x99c
+#define AM335X_PIN_MCASP0_ACLKR                        0x9a0
+#define AM335X_PIN_MCASP0_FSR                  0x9a4
+#define AM335X_PIN_MCASP0_AXR1                 0x9a8
+#define AM335X_PIN_MCASP0_AHCLKX               0x9ac
+#define AM335X_PIN_XDMA_EVENT_INTR0            0x9b0
+#define AM335X_PIN_XDMA_EVENT_INTR1            0x9b4
+#define AM335X_PIN_WARMRSTN                    0x9b8
+#define AM335X_PIN_NNMI                                0x9c0
+#define AM335X_PIN_TMS                         0x9d0
+#define AM335X_PIN_TDI                         0x9d4
+#define AM335X_PIN_TDO                         0x9d8
+#define AM335X_PIN_TCK                         0x9dc
+#define AM335X_PIN_TRSTN                       0x9e0
+#define AM335X_PIN_EMU0                                0x9e4
+#define AM335X_PIN_EMU1                                0x9e8
+#define AM335X_PIN_RTC_PWRONRSTN               0x9f8
+#define AM335X_PIN_PMIC_POWER_EN               0x9fc
+#define AM335X_PIN_EXT_WAKEUP                  0xa00
+#define AM335X_PIN_USB0_DRVVBUS                        0xa1c
+#define AM335X_PIN_USB1_DRVVBUS                        0xa34
 
+#define AM335X_PIN_OFFSET_MAX                  0x0a34U
+
+#endif
index 49b5dea2b38800c528899d22bf8b21a76f7ce6d5..6257180424132a70d2ffb0d6f80c3f29f29d78a2 100644 (file)
@@ -65,6 +65,7 @@
 #define DM814X_IOPAD(pa, val)          OMAP_IOPAD_OFFSET((pa), 0x0800) (val)
 #define DM816X_IOPAD(pa, val)          OMAP_IOPAD_OFFSET((pa), 0x0800) (val)
 #define AM33XX_IOPAD(pa, val)          OMAP_IOPAD_OFFSET((pa), 0x0800) (val)
+#define AM33XX_PADCONF(pa, dir, mux)   OMAP_IOPAD_OFFSET((pa), 0x0800) ((dir) | (mux))
 
 /*
  * Macros to allow using the offset from the padconf physical address
index 05a4b5917314791a4554ae4e74ced18ada7cd4f0..de82d8a15ea13a85cc12eb118ad4cc8722533d2f 100644 (file)
@@ -21,7 +21,6 @@
 #define R8A77965_PD_A3VC               14
 #define R8A77965_PD_3DG_A              17
 #define R8A77965_PD_3DG_B              18
-#define R8A77965_PD_A3IR               24
 #define R8A77965_PD_A2VC1              26
 
 /* Always-on power area */
index c15e8b709a0de6d7a9c9dd0a042d3d956e1a27f4..444c7bdde146ed932246b11c45a1f9ff34e4c0b2 100644 (file)
@@ -12,9 +12,9 @@
 #define TEGRA124_SOCTHERM_SENSOR_PLLX 3
 #define TEGRA124_SOCTHERM_SENSOR_NUM 4
 
-#define TEGRA_SOCTHERM_THROT_LEVEL_LOW  0
-#define TEGRA_SOCTHERM_THROT_LEVEL_MED  1
-#define TEGRA_SOCTHERM_THROT_LEVEL_HIGH 2
-#define TEGRA_SOCTHERM_THROT_LEVEL_NONE -1
+#define TEGRA_SOCTHERM_THROT_LEVEL_NONE 0
+#define TEGRA_SOCTHERM_THROT_LEVEL_LOW  1
+#define TEGRA_SOCTHERM_THROT_LEVEL_MED  2
+#define TEGRA_SOCTHERM_THROT_LEVEL_HIGH 3
 
 #endif
index e22c237be46aefbbca6d2c39277d20d8874259c9..98440df7fe42fb8cccf52248d8f1d6b43c03c492 100644 (file)
@@ -517,7 +517,8 @@ extern bool osc_pc_lpi_support_confirmed;
 #define OSC_PCI_CLOCK_PM_SUPPORT               0x00000004
 #define OSC_PCI_SEGMENT_GROUPS_SUPPORT         0x00000008
 #define OSC_PCI_MSI_SUPPORT                    0x00000010
-#define OSC_PCI_SUPPORT_MASKS                  0x0000001f
+#define OSC_PCI_HPX_TYPE_3_SUPPORT             0x00000100
+#define OSC_PCI_SUPPORT_MASKS                  0x0000011f
 
 /* PCI Host Bridge _OSC: Capabilities DWORD 3: Control Field */
 #define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL      0x00000001
index d0c3be77c18e96060cc1616e4e93cb1a2cde3eb9..b6e0cbeaf533e536ef548b948e9670f996d572ea 100644 (file)
@@ -124,38 +124,11 @@ struct clcd_board {
 struct amba_device;
 struct clk;
 
-/**
- * struct clcd_vendor_data - holds hardware (IP-block) vendor-specific
- * variant information
- *
- * @clock_timregs: the CLCD needs to be clocked when accessing the
- * timer registers, or the hardware will hang.
- * @packed_24_bit_pixels: this variant supports 24bit packed pixel data,
- * so that RGB accesses 3 bytes at a time, not just on even 32bit
- * boundaries, packing the pixel data in memory. ST Microelectronics
- * have this.
- * @st_bitmux_control: ST Microelectronics have implemented output
- * bit line multiplexing into the CLCD control register. This indicates
- * that we need to use this.
- * @init_board: custom board init function for this variant
- * @init_panel: custom panel init function for this variant
- */
-struct clcd_vendor_data {
-       bool    clock_timregs;
-       bool    packed_24_bit_pixels;
-       bool    st_bitmux_control;
-       int     (*init_board)(struct amba_device *adev,
-                             struct clcd_board *board);
-       int     (*init_panel)(struct clcd_fb *fb,
-                             struct device_node *panel);
-};
-
 /* this data structure describes each frame buffer device we find */
 struct clcd_fb {
        struct fb_info          fb;
        struct amba_device      *dev;
        struct clk              *clk;
-       struct clcd_vendor_data *vendor;
        struct clcd_panel       *panel;
        struct clcd_board       *board;
        void                    *board_data;
@@ -257,10 +230,6 @@ static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
                else
                        val |= CNTL_LCDBPP16_444;
                break;
-       case 24:
-               /* Modified variant supporting 24 bit packed pixels */
-               val |= CNTL_ST_LCDBPP24_PACKED;
-               break;
        case 32:
                val |= CNTL_LCDBPP24;
                break;
diff --git a/include/linux/armada-37xx-rwtm-mailbox.h b/include/linux/armada-37xx-rwtm-mailbox.h
new file mode 100644 (file)
index 0000000..57bb54f
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * rWTM BIU Mailbox driver for Armada 37xx
+ *
+ * Author: Marek Behun <marek.behun@nic.cz>
+ */
+
+#ifndef _LINUX_ARMADA_37XX_RWTM_MAILBOX_H_
+#define _LINUX_ARMADA_37XX_RWTM_MAILBOX_H_
+
+#include <linux/types.h>
+
+struct armada_37xx_rwtm_tx_msg {
+       u16 command;
+       u32 args[16];
+};
+
+struct armada_37xx_rwtm_rx_msg {
+       u32 retval;
+       u32 status[16];
+};
+
+#endif /* _LINUX_ARMADA_37XX_RWTM_MAILBOX_H_ */
index f111c780ef1df31bf0806d2f76f41b15e94339f3..f31521dcb09ad6e9b7d293d1503fd81958823255 100644 (file)
@@ -151,21 +151,6 @@ static inline void balloon_page_delete(struct page *page)
        list_del(&page->lru);
 }
 
-static inline bool __is_movable_balloon_page(struct page *page)
-{
-       return false;
-}
-
-static inline bool balloon_page_movable(struct page *page)
-{
-       return false;
-}
-
-static inline bool isolated_balloon_page(struct page *page)
-{
-       return false;
-}
-
 static inline bool balloon_page_isolate(struct page *page)
 {
        return false;
index 688ab0de7810c2ed8e2b1698d472e67e43862780..b40fc633f3be678b992faf08d537f82244744a37 100644 (file)
@@ -15,7 +15,6 @@ struct filename;
  * This structure is used to hold the arguments that are used when loading binaries.
  */
 struct linux_binprm {
-       char buf[BINPRM_BUF_SIZE];
 #ifdef CONFIG_MMU
        struct vm_area_struct *vma;
        unsigned long vma_pages;
@@ -64,6 +63,8 @@ struct linux_binprm {
        unsigned long loader, exec;
 
        struct rlimit rlim_stack; /* Saved RLIMIT_STACK used during exec. */
+
+       char buf[BINPRM_BUF_SIZE];
 } __randomize_layout;
 
 #define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
index 602af23b98c7856af4c7ee0473630b4866b3e54d..cf074bce3eb322c2ced7e3e05641f4c87d080ee0 100644 (file)
@@ -60,7 +60,7 @@ static __always_inline unsigned long hweight_long(unsigned long w)
  */
 static inline __u64 rol64(__u64 word, unsigned int shift)
 {
-       return (word << shift) | (word >> (64 - shift));
+       return (word << (shift & 63)) | (word >> ((-shift) & 63));
 }
 
 /**
@@ -70,7 +70,7 @@ static inline __u64 rol64(__u64 word, unsigned int shift)
  */
 static inline __u64 ror64(__u64 word, unsigned int shift)
 {
-       return (word >> shift) | (word << (64 - shift));
+       return (word >> (shift & 63)) | (word << ((-shift) & 63));
 }
 
 /**
@@ -80,7 +80,7 @@ static inline __u64 ror64(__u64 word, unsigned int shift)
  */
 static inline __u32 rol32(__u32 word, unsigned int shift)
 {
-       return (word << shift) | (word >> ((-shift) & 31));
+       return (word << (shift & 31)) | (word >> ((-shift) & 31));
 }
 
 /**
@@ -90,7 +90,7 @@ static inline __u32 rol32(__u32 word, unsigned int shift)
  */
 static inline __u32 ror32(__u32 word, unsigned int shift)
 {
-       return (word >> shift) | (word << (32 - shift));
+       return (word >> (shift & 31)) | (word << ((-shift) & 31));
 }
 
 /**
@@ -100,7 +100,7 @@ static inline __u32 ror32(__u32 word, unsigned int shift)
  */
 static inline __u16 rol16(__u16 word, unsigned int shift)
 {
-       return (word << shift) | (word >> (16 - shift));
+       return (word << (shift & 15)) | (word >> ((-shift) & 15));
 }
 
 /**
@@ -110,7 +110,7 @@ static inline __u16 rol16(__u16 word, unsigned int shift)
  */
 static inline __u16 ror16(__u16 word, unsigned int shift)
 {
-       return (word >> shift) | (word << (16 - shift));
+       return (word >> (shift & 15)) | (word << ((-shift) & 15));
 }
 
 /**
@@ -120,7 +120,7 @@ static inline __u16 ror16(__u16 word, unsigned int shift)
  */
 static inline __u8 rol8(__u8 word, unsigned int shift)
 {
-       return (word << shift) | (word >> (8 - shift));
+       return (word << (shift & 7)) | (word >> ((-shift) & 7));
 }
 
 /**
@@ -130,7 +130,7 @@ static inline __u8 rol8(__u8 word, unsigned int shift)
  */
 static inline __u8 ror8(__u8 word, unsigned int shift)
 {
-       return (word >> shift) | (word << (8 - shift));
+       return (word >> (shift & 7)) | (word << ((-shift) & 7));
 }
 
 /**
index 4903deb0777a746068ecd7f5cc5a472276885cfe..3ac0feaf2b5ee044f5c457a8c6642bb4037069b6 100644 (file)
@@ -436,6 +436,12 @@ union ceph_mds_request_args {
                __le64 length; /* num bytes to lock from start */
                __u8 wait; /* will caller wait for lock to become available? */
        } __attribute__ ((packed)) filelock_change;
+       struct {
+               __le32 mask;                 /* CEPH_CAP_* */
+               __le64 snapid;
+               __le64 parent;
+               __le32 hash;
+       } __attribute__ ((packed)) lookupino;
 } __attribute__ ((packed));
 
 #define CEPH_MDS_FLAG_REPLAY        1  /* this is a replayed op */
index 800a2128d411b3a1f39ec0ab4f2068a4b4d76a52..23895d178149bd2ec5fb7984419976e8e13cbc1a 100644 (file)
@@ -323,7 +323,8 @@ struct ceph_connection {
 };
 
 
-extern const char *ceph_pr_addr(const struct sockaddr_storage *ss);
+extern const char *ceph_pr_addr(const struct ceph_entity_addr *addr);
+
 extern int ceph_parse_ips(const char *c, const char *end,
                          struct ceph_entity_addr *addr,
                          int max_count, int *count);
index 5675b1f09bc5c2fa813f4e8e714a791f2666ab1c..e081b56f1c1dacf60a850cbafface5e8e481f7e3 100644 (file)
@@ -110,17 +110,16 @@ struct ceph_object_id {
        int name_len;
 };
 
+#define __CEPH_OID_INITIALIZER(oid) { .name = (oid).inline_name }
+
+#define CEPH_DEFINE_OID_ONSTACK(oid)                           \
+       struct ceph_object_id oid = __CEPH_OID_INITIALIZER(oid)
+
 static inline void ceph_oid_init(struct ceph_object_id *oid)
 {
-       oid->name = oid->inline_name;
-       oid->name_len = 0;
+       *oid = (struct ceph_object_id) __CEPH_OID_INITIALIZER(*oid);
 }
 
-#define CEPH_OID_INIT_ONSTACK(oid)                                     \
-    ({ ceph_oid_init(&oid); oid; })
-#define CEPH_DEFINE_OID_ONSTACK(oid)                                   \
-       struct ceph_object_id oid = CEPH_OID_INIT_ONSTACK(oid)
-
 static inline bool ceph_oid_empty(const struct ceph_object_id *oid)
 {
        return oid->name == oid->inline_name && !oid->name_len;
index 491d992d045d4fded2cf11397de471efcbb51cc9..bb6118f797844591fb8f870dedbf404737c5f675 100644 (file)
@@ -6,7 +6,6 @@
 #ifndef __LINUX_CLK_PROVIDER_H
 #define __LINUX_CLK_PROVIDER_H
 
-#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_clk.h>
 
index d58aa0db05f9438cbe3639a7d47788b6acdd4f33..8aaf7cd026b06a2a12fa09aebc3b2685d6584fe2 100644 (file)
@@ -53,23 +53,24 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
  * "Define 'is'", Bill Clinton
  * "Define 'if'", Steven Rostedt
  */
-#define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
-#define __trace_if(cond) \
-       if (__builtin_constant_p(!!(cond)) ? !!(cond) :                 \
-       ({                                                              \
-               int ______r;                                            \
-               static struct ftrace_branch_data                        \
-                       __aligned(4)                                    \
-                       __section("_ftrace_branch")                     \
-                       ______f = {                                     \
-                               .func = __func__,                       \
-                               .file = __FILE__,                       \
-                               .line = __LINE__,                       \
-                       };                                              \
-               ______r = !!(cond);                                     \
-               ______r ? ______f.miss_hit[1]++ : ______f.miss_hit[0]++;\
-               ______r;                                                \
-       }))
+#define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
+
+#define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
+
+#define __trace_if_value(cond) ({                      \
+       static struct ftrace_branch_data                \
+               __aligned(4)                            \
+               __section("_ftrace_branch")             \
+               __if_trace = {                          \
+                       .func = __func__,               \
+                       .file = __FILE__,               \
+                       .line = __LINE__,               \
+               };                                      \
+       (cond) ?                                        \
+               (__if_trace.miss_hit[1]++,1) :          \
+               (__if_trace.miss_hit[0]++,0);           \
+})
+
 #endif /* CONFIG_PROFILE_ALL_BRANCHES */
 
 #else
index ba814f18cb4ce240d53b9d42aaa4a5117591dab8..19e58b9138a04db090ebf3ec787de45529fe2d64 100644 (file)
@@ -140,8 +140,7 @@ struct ftrace_likely_data {
  * Do not use __always_inline here, since currently it expands to inline again
  * (which would break users of __always_inline).
  */
-#if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) || \
-       !defined(CONFIG_OPTIMIZE_INLINING)
+#if !defined(CONFIG_OPTIMIZE_INLINING)
 #define inline inline __attribute__((__always_inline__)) __gnu_inline \
        __maybe_unused notrace
 #else
index 9c703a0abe6edcb6d7613ffc2c2fade60f44095e..cc4980bb0f65a5776382481a16b35a5993e8d352 100644 (file)
@@ -44,7 +44,7 @@
  */
 #define CPER_REC_LEN                                   256
 /*
- * Severity difinition for error_severity in struct cper_record_header
+ * Severity definition for error_severity in struct cper_record_header
  * and section_severity in struct cper_section_descriptor
  */
 enum {
@@ -55,24 +55,21 @@ enum {
 };
 
 /*
- * Validation bits difinition for validation_bits in struct
+ * Validation bits definition for validation_bits in struct
  * cper_record_header. If set, corresponding fields in struct
  * cper_record_header contain valid information.
- *
- * corresponds platform_id
  */
 #define CPER_VALID_PLATFORM_ID                 0x0001
-/* corresponds timestamp */
 #define CPER_VALID_TIMESTAMP                   0x0002
-/* corresponds partition_id */
 #define CPER_VALID_PARTITION_ID                        0x0004
 
 /*
  * Notification type used to generate error record, used in
- * notification_type in struct cper_record_header
- *
- * Corrected Machine Check
+ * notification_type in struct cper_record_header.  These UUIDs are defined
+ * in the UEFI spec v2.7, sec N.2.1.
  */
+
+/* Corrected Machine Check */
 #define CPER_NOTIFY_CMC                                                        \
        GUID_INIT(0x2DCE8BB1, 0xBDD7, 0x450e, 0xB9, 0xAD, 0x9C, 0xF4,   \
                  0xEB, 0xD4, 0xF8, 0x90)
@@ -122,14 +119,11 @@ enum {
 #define CPER_SEC_REV                           0x0100
 
 /*
- * Validation bits difinition for validation_bits in struct
+ * Validation bits definition for validation_bits in struct
  * cper_section_descriptor. If set, corresponding fields in struct
  * cper_section_descriptor contain valid information.
- *
- * corresponds fru_id
  */
 #define CPER_SEC_VALID_FRU_ID                  0x1
-/* corresponds fru_text */
 #define CPER_SEC_VALID_FRU_TEXT                        0x2
 
 /*
@@ -165,10 +159,11 @@ enum {
 
 /*
  * Section type definitions, used in section_type field in struct
- * cper_section_descriptor
- *
- * Processor Generic
+ * cper_section_descriptor.  These UUIDs are defined in the UEFI spec
+ * v2.7, sec N.2.2.
  */
+
+/* Processor Generic */
 #define CPER_SEC_PROC_GENERIC                                          \
        GUID_INIT(0x9876CCAD, 0x47B4, 0x4bdb, 0xB6, 0x5E, 0x16, 0xF1,   \
                  0x93, 0xC4, 0xF3, 0xDB)
@@ -325,220 +320,223 @@ enum {
  */
 #pragma pack(1)
 
+/* Record Header, UEFI v2.7 sec N.2.1 */
 struct cper_record_header {
        char    signature[CPER_SIG_SIZE];       /* must be CPER_SIG_RECORD */
-       __u16   revision;                       /* must be CPER_RECORD_REV */
-       __u32   signature_end;                  /* must be CPER_SIG_END */
-       __u16   section_count;
-       __u32   error_severity;
-       __u32   validation_bits;
-       __u32   record_length;
-       __u64   timestamp;
+       u16     revision;                       /* must be CPER_RECORD_REV */
+       u32     signature_end;                  /* must be CPER_SIG_END */
+       u16     section_count;
+       u32     error_severity;
+       u32     validation_bits;
+       u32     record_length;
+       u64     timestamp;
        guid_t  platform_id;
        guid_t  partition_id;
        guid_t  creator_id;
        guid_t  notification_type;
-       __u64   record_id;
-       __u32   flags;
-       __u64   persistence_information;
-       __u8    reserved[12];                   /* must be zero */
+       u64     record_id;
+       u32     flags;
+       u64     persistence_information;
+       u8      reserved[12];                   /* must be zero */
 };
 
+/* Section Descriptor, UEFI v2.7 sec N.2.2 */
 struct cper_section_descriptor {
-       __u32   section_offset;         /* Offset in bytes of the
+       u32     section_offset;         /* Offset in bytes of the
                                         *  section body from the base
                                         *  of the record header */
-       __u32   section_length;
-       __u16   revision;               /* must be CPER_RECORD_REV */
-       __u8    validation_bits;
-       __u8    reserved;               /* must be zero */
-       __u32   flags;
+       u32     section_length;
+       u16     revision;               /* must be CPER_RECORD_REV */
+       u8      validation_bits;
+       u8      reserved;               /* must be zero */
+       u32     flags;
        guid_t  section_type;
        guid_t  fru_id;
-       __u32   section_severity;
-       __u8    fru_text[20];
+       u32     section_severity;
+       u8      fru_text[20];
 };
 
-/* Generic Processor Error Section */
+/* Generic Processor Error Section, UEFI v2.7 sec N.2.4.1 */
 struct cper_sec_proc_generic {
-       __u64   validation_bits;
-       __u8    proc_type;
-       __u8    proc_isa;
-       __u8    proc_error_type;
-       __u8    operation;
-       __u8    flags;
-       __u8    level;
-       __u16   reserved;
-       __u64   cpu_version;
+       u64     validation_bits;
+       u8      proc_type;
+       u8      proc_isa;
+       u8      proc_error_type;
+       u8      operation;
+       u8      flags;
+       u8      level;
+       u16     reserved;
+       u64     cpu_version;
        char    cpu_brand[128];
-       __u64   proc_id;
-       __u64   target_addr;
-       __u64   requestor_id;
-       __u64   responder_id;
-       __u64   ip;
+       u64     proc_id;
+       u64     target_addr;
+       u64     requestor_id;
+       u64     responder_id;
+       u64     ip;
 };
 
-/* IA32/X64 Processor Error Section */
+/* IA32/X64 Processor Error Section, UEFI v2.7 sec N.2.4.2 */
 struct cper_sec_proc_ia {
-       __u64   validation_bits;
-       __u64   lapic_id;
-       __u8    cpuid[48];
+       u64     validation_bits;
+       u64     lapic_id;
+       u8      cpuid[48];
 };
 
-/* IA32/X64 Processor Error Information Structure */
+/* IA32/X64 Processor Error Information Structure, UEFI v2.7 sec N.2.4.2.1 */
 struct cper_ia_err_info {
        guid_t  err_type;
-       __u64   validation_bits;
-       __u64   check_info;
-       __u64   target_id;
-       __u64   requestor_id;
-       __u64   responder_id;
-       __u64   ip;
+       u64     validation_bits;
+       u64     check_info;
+       u64     target_id;
+       u64     requestor_id;
+       u64     responder_id;
+       u64     ip;
 };
 
-/* IA32/X64 Processor Context Information Structure */
+/* IA32/X64 Processor Context Information Structure, UEFI v2.7 sec N.2.4.2.2 */
 struct cper_ia_proc_ctx {
-       __u16   reg_ctx_type;
-       __u16   reg_arr_size;
-       __u32   msr_addr;
-       __u64   mm_reg_addr;
+       u16     reg_ctx_type;
+       u16     reg_arr_size;
+       u32     msr_addr;
+       u64     mm_reg_addr;
 };
 
-/* ARM Processor Error Section */
+/* ARM Processor Error Section, UEFI v2.7 sec N.2.4.4 */
 struct cper_sec_proc_arm {
-       __u32   validation_bits;
-       __u16   err_info_num;           /* Number of Processor Error Info */
-       __u16   context_info_num;       /* Number of Processor Context Info Records*/
-       __u32   section_length;
-       __u8    affinity_level;
-       __u8    reserved[3];            /* must be zero */
-       __u64   mpidr;
-       __u64   midr;
-       __u32   running_state;          /* Bit 0 set - Processor running. PSCI = 0 */
-       __u32   psci_state;
+       u32     validation_bits;
+       u16     err_info_num;           /* Number of Processor Error Info */
+       u16     context_info_num;       /* Number of Processor Context Info Records*/
+       u32     section_length;
+       u8      affinity_level;
+       u8      reserved[3];            /* must be zero */
+       u64     mpidr;
+       u64     midr;
+       u32     running_state;          /* Bit 0 set - Processor running. PSCI = 0 */
+       u32     psci_state;
 };
 
-/* ARM Processor Error Information Structure */
+/* ARM Processor Error Information Structure, UEFI v2.7 sec N.2.4.4.1 */
 struct cper_arm_err_info {
-       __u8    version;
-       __u8    length;
-       __u16   validation_bits;
-       __u8    type;
-       __u16   multiple_error;
-       __u8    flags;
-       __u64   error_info;
-       __u64   virt_fault_addr;
-       __u64   physical_fault_addr;
+       u8      version;
+       u8      length;
+       u16     validation_bits;
+       u8      type;
+       u16     multiple_error;
+       u8      flags;
+       u64     error_info;
+       u64     virt_fault_addr;
+       u64     physical_fault_addr;
 };
 
-/* ARM Processor Context Information Structure */
+/* ARM Processor Context Information Structure, UEFI v2.7 sec N.2.4.4.2 */
 struct cper_arm_ctx_info {
-       __u16   version;
-       __u16   type;
-       __u32   size;
+       u16     version;
+       u16     type;
+       u32     size;
 };
 
-/* Old Memory Error Section UEFI 2.1, 2.2 */
+/* Old Memory Error Section, UEFI v2.1, v2.2 */
 struct cper_sec_mem_err_old {
-       __u64   validation_bits;
-       __u64   error_status;
-       __u64   physical_addr;
-       __u64   physical_addr_mask;
-       __u16   node;
-       __u16   card;
-       __u16   module;
-       __u16   bank;
-       __u16   device;
-       __u16   row;
-       __u16   column;
-       __u16   bit_pos;
-       __u64   requestor_id;
-       __u64   responder_id;
-       __u64   target_id;
-       __u8    error_type;
+       u64     validation_bits;
+       u64     error_status;
+       u64     physical_addr;
+       u64     physical_addr_mask;
+       u16     node;
+       u16     card;
+       u16     module;
+       u16     bank;
+       u16     device;
+       u16     row;
+       u16     column;
+       u16     bit_pos;
+       u64     requestor_id;
+       u64     responder_id;
+       u64     target_id;
+       u8      error_type;
 };
 
-/* Memory Error Section UEFI >= 2.3 */
+/* Memory Error Section (UEFI >= v2.3), UEFI v2.7 sec N.2.5 */
 struct cper_sec_mem_err {
-       __u64   validation_bits;
-       __u64   error_status;
-       __u64   physical_addr;
-       __u64   physical_addr_mask;
-       __u16   node;
-       __u16   card;
-       __u16   module;
-       __u16   bank;
-       __u16   device;
-       __u16   row;
-       __u16   column;
-       __u16   bit_pos;
-       __u64   requestor_id;
-       __u64   responder_id;
-       __u64   target_id;
-       __u8    error_type;
-       __u8    reserved;
-       __u16   rank;
-       __u16   mem_array_handle;       /* card handle in UEFI 2.4 */
-       __u16   mem_dev_handle;         /* module handle in UEFI 2.4 */
+       u64     validation_bits;
+       u64     error_status;
+       u64     physical_addr;
+       u64     physical_addr_mask;
+       u16     node;
+       u16     card;
+       u16     module;
+       u16     bank;
+       u16     device;
+       u16     row;
+       u16     column;
+       u16     bit_pos;
+       u64     requestor_id;
+       u64     responder_id;
+       u64     target_id;
+       u8      error_type;
+       u8      reserved;
+       u16     rank;
+       u16     mem_array_handle;       /* "card handle" in UEFI 2.4 */
+       u16     mem_dev_handle;         /* "module handle" in UEFI 2.4 */
 };
 
 struct cper_mem_err_compact {
-       __u64   validation_bits;
-       __u16   node;
-       __u16   card;
-       __u16   module;
-       __u16   bank;
-       __u16   device;
-       __u16   row;
-       __u16   column;
-       __u16   bit_pos;
-       __u64   requestor_id;
-       __u64   responder_id;
-       __u64   target_id;
-       __u16   rank;
-       __u16   mem_array_handle;
-       __u16   mem_dev_handle;
+       u64     validation_bits;
+       u16     node;
+       u16     card;
+       u16     module;
+       u16     bank;
+       u16     device;
+       u16     row;
+       u16     column;
+       u16     bit_pos;
+       u64     requestor_id;
+       u64     responder_id;
+       u64     target_id;
+       u16     rank;
+       u16     mem_array_handle;
+       u16     mem_dev_handle;
 };
 
+/* PCI Express Error Section, UEFI v2.7 sec N.2.7 */
 struct cper_sec_pcie {
-       __u64           validation_bits;
-       __u32           port_type;
+       u64             validation_bits;
+       u32             port_type;
        struct {
-               __u8    minor;
-               __u8    major;
-               __u8    reserved[2];
+               u8      minor;
+               u8      major;
+               u8      reserved[2];
        }               version;
-       __u16           command;
-       __u16           status;
-       __u32           reserved;
+       u16             command;
+       u16             status;
+       u32             reserved;
        struct {
-               __u16   vendor_id;
-               __u16   device_id;
-               __u8    class_code[3];
-               __u8    function;
-               __u8    device;
-               __u16   segment;
-               __u8    bus;
-               __u8    secondary_bus;
-               __u16   slot;
-               __u8    reserved;
+               u16     vendor_id;
+               u16     device_id;
+               u8      class_code[3];
+               u8      function;
+               u8      device;
+               u16     segment;
+               u8      bus;
+               u8      secondary_bus;
+               u16     slot;
+               u8      reserved;
        }               device_id;
        struct {
-               __u32   lower;
-               __u32   upper;
+               u32     lower;
+               u32     upper;
        }               serial_number;
        struct {
-               __u16   secondary_status;
-               __u16   control;
+               u16     secondary_status;
+               u16     control;
        }               bridge;
-       __u8    capability[60];
-       __u8    aer_info[96];
+       u8      capability[60];
+       u8      aer_info[96];
 };
 
 /* Reset to default packing */
 #pragma pack()
 
-extern const char * const cper_proc_error_type_strs[4];
+extern const char *const cper_proc_error_type_strs[4];
 
 u64 cper_next_record_id(void);
 const char *cper_severity_str(unsigned int);
index 732745f865b7e02f94832c128f0d8b4a83ea2ed9..3813fe45effdc9e274842d42544bfda14555bdac 100644 (file)
@@ -57,6 +57,8 @@ extern ssize_t cpu_show_spec_store_bypass(struct device *dev,
                                          struct device_attribute *attr, char *buf);
 extern ssize_t cpu_show_l1tf(struct device *dev,
                             struct device_attribute *attr, char *buf);
+extern ssize_t cpu_show_mds(struct device *dev,
+                           struct device_attribute *attr, char *buf);
 
 extern __printf(4, 5)
 struct device *cpu_device_create(struct device *parent, void *drvdata,
index 684caf067003b0b3c45424f914e821f6797531ca..d01a74fbc4db624187f2c42b0dc304162081fc12 100644 (file)
@@ -42,13 +42,6 @@ enum cpufreq_table_sorting {
        CPUFREQ_TABLE_SORTED_DESCENDING
 };
 
-struct cpufreq_freqs {
-       unsigned int cpu;       /* cpu nr */
-       unsigned int old;
-       unsigned int new;
-       u8 flags;               /* flags of cpufreq_driver, see below. */
-};
-
 struct cpufreq_cpuinfo {
        unsigned int            max_freq;
        unsigned int            min_freq;
@@ -156,6 +149,13 @@ struct cpufreq_policy {
        struct thermal_cooling_device *cdev;
 };
 
+struct cpufreq_freqs {
+       struct cpufreq_policy *policy;
+       unsigned int old;
+       unsigned int new;
+       u8 flags;               /* flags of cpufreq_driver, see below. */
+};
+
 /* Only for ACPI */
 #define CPUFREQ_SHARED_TYPE_NONE (0) /* None */
 #define CPUFREQ_SHARED_TYPE_HW  (1) /* HW does needed coordination */
index 147bdec42215d54f6f17686492bbdcc6162f1c8b..21755471b1c317c2abb8a8daae830d7fabb44093 100644 (file)
@@ -633,8 +633,7 @@ static inline int cpumask_parselist_user(const char __user *buf, int len,
  */
 static inline int cpumask_parse(const char *buf, struct cpumask *dstp)
 {
-       char *nl = strchr(buf, '\n');
-       unsigned int len = nl ? (unsigned int)(nl - buf) : strlen(buf);
+       unsigned int len = strchrnul(buf, '\n') - buf;
 
        return bitmap_parse(buf, len, cpumask_bits(dstp), nr_cpumask_bits);
 }
index b0672756d0562697238cb9cf53775c3c48d87a4a..e1f51d607cc541924cc54c43aaa7b80c06a6322e 100644 (file)
@@ -62,7 +62,8 @@ typedef int (*dm_clone_and_map_request_fn) (struct dm_target *ti,
                                            struct request *rq,
                                            union map_info *map_context,
                                            struct request **clone);
-typedef void (*dm_release_clone_request_fn) (struct request *clone);
+typedef void (*dm_release_clone_request_fn) (struct request *clone,
+                                            union map_info *map_context);
 
 /*
  * Returns:
index 34a744a1bafcbc84c4e2992435f14b71610a4c88..f2b3ae22e6b77bf3ba37ed7b42abc94ca95222cb 100644 (file)
@@ -27,6 +27,7 @@
 #include <uapi/linux/dns_resolver.h>
 
 extern int dns_query(const char *type, const char *name, size_t namelen,
-                    const char *options, char **_result, time64_t *_expiry);
+                    const char *options, char **_result, time64_t *_expiry,
+                    bool invalidate);
 
 #endif /* _LINUX_DNS_RESOLVER_H */
index f5740423b0023e9abf5c5023a5f146a5da59012a..65559900d4d76e24c7bd337571d839ee6252274a 100644 (file)
@@ -164,6 +164,10 @@ struct f2fs_checkpoint {
        unsigned char sit_nat_version_bitmap[1];
 } __packed;
 
+#define CP_CHKSUM_OFFSET       4092    /* default chksum offset in checkpoint */
+#define CP_MIN_CHKSUM_OFFSET                                           \
+       (offsetof(struct f2fs_checkpoint, sit_nat_version_bitmap))
+
 /*
  * For orphan inode management
  */
@@ -198,11 +202,12 @@ struct f2fs_extent {
                                        get_extra_isize(inode))
 #define DEF_NIDS_PER_INODE     5       /* Node IDs in an Inode */
 #define ADDRS_PER_INODE(inode) addrs_per_inode(inode)
-#define ADDRS_PER_BLOCK                1018    /* Address Pointers in a Direct Block */
+#define DEF_ADDRS_PER_BLOCK    1018    /* Address Pointers in a Direct Block */
+#define ADDRS_PER_BLOCK(inode) addrs_per_block(inode)
 #define NIDS_PER_BLOCK         1018    /* Node IDs in an Indirect Block */
 
 #define ADDRS_PER_PAGE(page, inode)    \
-       (IS_INODE(page) ? ADDRS_PER_INODE(inode) : ADDRS_PER_BLOCK)
+       (IS_INODE(page) ? ADDRS_PER_INODE(inode) : ADDRS_PER_BLOCK(inode))
 
 #define        NODE_DIR1_BLOCK         (DEF_ADDRS_PER_INODE + 1)
 #define        NODE_DIR2_BLOCK         (DEF_ADDRS_PER_INODE + 2)
@@ -267,7 +272,7 @@ struct f2fs_inode {
 } __packed;
 
 struct direct_node {
-       __le32 addr[ADDRS_PER_BLOCK];   /* array of data block address */
+       __le32 addr[DEF_ADDRS_PER_BLOCK];       /* array of data block address */
 } __packed;
 
 struct indirect_node {
index ebc55098faee29134fa8be693b69d081fe2f1a9a..17ba4e405129d927b424dc58e33e7e0bb2c0cb12 100644 (file)
@@ -15,4 +15,9 @@
 
 #include <linux/firmware/imx/svc/misc.h>
 #include <linux/firmware/imx/svc/pm.h>
+
+int imx_scu_enable_general_irq_channel(struct device *dev);
+int imx_scu_irq_register_notifier(struct notifier_block *nb);
+int imx_scu_irq_unregister_notifier(struct notifier_block *nb);
+int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable);
 #endif /* _SC_SCI_H */
diff --git a/include/linux/firmware/trusted_foundations.h b/include/linux/firmware/trusted_foundations.h
new file mode 100644 (file)
index 0000000..4064e7c
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013, NVIDIA 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; 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.
+ */
+
+/*
+ * Support for the Trusted Foundations secure monitor.
+ *
+ * Trusted Foundation comes active on some ARM consumer devices (most
+ * Tegra-based devices sold on the market are concerned). Such devices can only
+ * perform some basic operations, like setting the CPU reset vector, through
+ * SMC calls to the secure monitor. The calls are completely specific to
+ * Trusted Foundations, and do *not* follow the SMC calling convention or the
+ * PSCI standard.
+ */
+
+#ifndef __FIRMWARE_TRUSTED_FOUNDATIONS_H
+#define __FIRMWARE_TRUSTED_FOUNDATIONS_H
+
+#include <linux/printk.h>
+#include <linux/bug.h>
+#include <linux/of.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/outercache.h>
+
+#define TF_PM_MODE_LP0                 0
+#define TF_PM_MODE_LP1                 1
+#define TF_PM_MODE_LP1_NO_MC_CLK       2
+#define TF_PM_MODE_LP2                 3
+#define TF_PM_MODE_LP2_NOFLUSH_L2      4
+
+struct trusted_foundations_platform_data {
+       unsigned int version_major;
+       unsigned int version_minor;
+};
+
+#if IS_ENABLED(CONFIG_TRUSTED_FOUNDATIONS)
+
+void register_trusted_foundations(struct trusted_foundations_platform_data *pd);
+void of_register_trusted_foundations(void);
+bool trusted_foundations_registered(void);
+
+#else /* CONFIG_TRUSTED_FOUNDATIONS */
+static inline void tf_dummy_write_sec(unsigned long val, unsigned int reg)
+{
+}
+
+static inline void register_trusted_foundations(
+                                  struct trusted_foundations_platform_data *pd)
+{
+       /*
+        * If the system requires TF and we cannot provide it, continue booting
+        * but disable features that cannot be provided.
+        */
+       pr_err("No support for Trusted Foundations, continuing in degraded mode.\n");
+       pr_err("Secondary processors as well as CPU PM will be disabled.\n");
+#if IS_ENABLED(CONFIG_CACHE_L2X0)
+       pr_err("L2X0 cache will be kept disabled.\n");
+       outer_cache.write_sec = tf_dummy_write_sec;
+#endif
+#if IS_ENABLED(CONFIG_SMP)
+       setup_max_cpus = 0;
+#endif
+       cpu_idle_poll_ctrl(true);
+}
+
+static inline void of_register_trusted_foundations(void)
+{
+       /*
+        * If we find the target should enable TF but does not support it,
+        * fail as the system won't be able to do much anyway
+        */
+       if (of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations"))
+               register_trusted_foundations(NULL);
+}
+
+static inline bool trusted_foundations_registered(void)
+{
+       return false;
+}
+#endif /* CONFIG_TRUSTED_FOUNDATIONS */
+
+#endif
index 642dab10f65d7340d88eba039f28a44d23274d88..1262ea6a1f4b91b45a88312ad0de139ce57747a7 100644 (file)
 #define        ZYNQMP_PM_CAPABILITY_WAKEUP     0x4U
 #define        ZYNQMP_PM_CAPABILITY_POWER      0x8U
 
+/*
+ * Firmware FPGA Manager flags
+ * XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration
+ * XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration
+ */
+#define XILINX_ZYNQMP_PM_FPGA_FULL     0x0U
+#define XILINX_ZYNQMP_PM_FPGA_PARTIAL  BIT(0)
+
 enum pm_api_id {
        PM_GET_API_VERSION = 1,
        PM_REQUEST_NODE = 13,
@@ -56,6 +64,8 @@ enum pm_api_id {
        PM_RESET_ASSERT = 17,
        PM_RESET_GET_STATUS,
        PM_PM_INIT_FINALIZE = 21,
+       PM_FPGA_LOAD,
+       PM_FPGA_GET_STATUS,
        PM_GET_CHIPID = 24,
        PM_IOCTL = 34,
        PM_QUERY_DATA,
@@ -258,6 +268,8 @@ struct zynqmp_pm_query_data {
 struct zynqmp_eemi_ops {
        int (*get_api_version)(u32 *version);
        int (*get_chipid)(u32 *idcode, u32 *version);
+       int (*fpga_load)(const u64 address, const u32 size, const u32 flags);
+       int (*fpga_get_status)(u32 *value);
        int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out);
        int (*clock_enable)(u32 clock_id);
        int (*clock_disable)(u32 clock_id);
@@ -293,7 +305,7 @@ const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void);
 #else
 static inline struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
 {
-       return NULL;
+       return ERR_PTR(-ENODEV);
 }
 #endif
 
index 28c74e0a72310ea31792911a4c20c212ce0c1be8..f7680ef1abd2d3d88e41f705a65febe79bc7f1cb 100644 (file)
@@ -247,6 +247,11 @@ extern int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
 extern const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
                                       unsigned int max_size,
                                       struct delayed_call *done);
+static inline void fscrypt_set_ops(struct super_block *sb,
+                                  const struct fscrypt_operations *s_cop)
+{
+       sb->s_cop = s_cop;
+}
 #else  /* !CONFIG_FS_ENCRYPTION */
 
 static inline bool fscrypt_has_encryption_key(const struct inode *inode)
@@ -471,6 +476,12 @@ static inline const char *fscrypt_get_symlink(struct inode *inode,
 {
        return ERR_PTR(-EOPNOTSUPP);
 }
+
+static inline void fscrypt_set_ops(struct super_block *sb,
+                                  const struct fscrypt_operations *s_cop)
+{
+}
+
 #endif /* !CONFIG_FS_ENCRYPTION */
 
 /**
index 0c0ef3078a220a0f0ff6993162360a97a8b47eb7..94972e8eb6d1e018f5005e43fdd8d71ac76d59e7 100644 (file)
@@ -151,39 +151,6 @@ static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt)
        __fsnotify_vfsmount_delete(mnt);
 }
 
-/*
- * fsnotify_nameremove - a filename was removed from a directory
- *
- * This is mostly called under parent vfs inode lock so name and
- * dentry->d_parent should be stable. However there are some corner cases where
- * inode lock is not held. So to be on the safe side and be reselient to future
- * callers and out of tree users of d_delete(), we do not assume that d_parent
- * and d_name are stable and we use dget_parent() and
- * take_dentry_name_snapshot() to grab stable references.
- */
-static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
-{
-       struct dentry *parent;
-       struct name_snapshot name;
-       __u32 mask = FS_DELETE;
-
-       /* d_delete() of pseudo inode? (e.g. __ns_get_path() playing tricks) */
-       if (IS_ROOT(dentry))
-               return;
-
-       if (isdir)
-               mask |= FS_ISDIR;
-
-       parent = dget_parent(dentry);
-       take_dentry_name_snapshot(&name, dentry);
-
-       fsnotify(d_inode(parent), mask, d_inode(dentry), FSNOTIFY_EVENT_INODE,
-                &name.name, 0);
-
-       release_dentry_name_snapshot(&name);
-       dput(parent);
-}
-
 /*
  * fsnotify_inoderemove - an inode is going away
  */
index c28f6ed1f59b82302b0a733090fecfb42bc1436c..a9f9dcc1e5151353a9664fa99fb9eb7b1c3ed46d 100644 (file)
@@ -355,6 +355,7 @@ extern int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u
 extern void __fsnotify_inode_delete(struct inode *inode);
 extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
 extern void fsnotify_sb_delete(struct super_block *sb);
+extern void fsnotify_nameremove(struct dentry *dentry, int isdir);
 extern u32 fsnotify_get_cookie(void);
 
 static inline int fsnotify_inode_watches_children(struct inode *inode)
@@ -524,6 +525,9 @@ static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
 static inline void fsnotify_sb_delete(struct super_block *sb)
 {}
 
+static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
+{}
+
 static inline void fsnotify_update_flags(struct dentry *dentry)
 {}
 
index 20899919ead8ade88ee64346ccb1c362018ebf20..25e2995d4a4c1f3f89bbb1e8f5fe9595126a4514 100644 (file)
@@ -741,6 +741,8 @@ struct ftrace_graph_ret {
 typedef void (*trace_func_graph_ret_t)(struct ftrace_graph_ret *); /* return */
 typedef int (*trace_func_graph_ent_t)(struct ftrace_graph_ent *); /* entry */
 
+extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace);
+
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
 struct fgraph_ops {
index fdab7de7490dff2ae693c710214023489e6f394f..fb07b503dc453ddfe16c5f0f959d46be01ad55ba 100644 (file)
@@ -585,12 +585,12 @@ static inline bool pm_suspended_storage(void)
 }
 #endif /* CONFIG_PM_SLEEP */
 
-#if (defined(CONFIG_MEMORY_ISOLATION) && defined(CONFIG_COMPACTION)) || defined(CONFIG_CMA)
+#ifdef CONFIG_CONTIG_ALLOC
 /* The below functions must be run on a range from a single zone. */
 extern int alloc_contig_range(unsigned long start, unsigned long end,
                              unsigned migratetype, gfp_t gfp_mask);
-extern void free_contig_range(unsigned long pfn, unsigned nr_pages);
 #endif
+void free_contig_range(unsigned long pfn, unsigned int nr_pages);
 
 #ifdef CONFIG_CMA
 /* CMA stuff */
index 951be1715c128a012b963d7e202407370b13ca6d..a1d273c96016ad2764d04467b007c2667f763749 100644 (file)
@@ -227,9 +227,10 @@ struct gpio_irq_chip {
  * @reg_dat: data (in) register for generic GPIO
  * @reg_set: output set register (out=high) for generic GPIO
  * @reg_clr: output clear register (out=low) for generic GPIO
- * @reg_dir: direction setting register for generic GPIO
- * @bgpio_dir_inverted: indicates that the direction register is inverted
- *     (gpiolib private state variable)
+ * @reg_dir_out: direction out setting register for generic GPIO
+ * @reg_dir_in: direction in setting register for generic GPIO
+ * @bgpio_dir_unreadable: indicates that the direction register(s) cannot
+ *     be read and we need to rely on out internal state tracking.
  * @bgpio_bits: number of register bits used for a generic GPIO i.e.
  *     <register width> * 8
  * @bgpio_lock: used to lock chip->bgpio_data. Also, this is needed to keep
@@ -237,7 +238,8 @@ struct gpio_irq_chip {
  * @bgpio_data:        shadowed data register for generic GPIO to clear/set bits
  *     safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
- *     direction safely.
+ *     direction safely. A "1" in this word means the line is set as
+ *     output.
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
@@ -298,8 +300,9 @@ struct gpio_chip {
        void __iomem *reg_dat;
        void __iomem *reg_set;
        void __iomem *reg_clr;
-       void __iomem *reg_dir;
-       bool bgpio_dir_inverted;
+       void __iomem *reg_dir_out;
+       void __iomem *reg_dir_in;
+       bool bgpio_dir_unreadable;
        int bgpio_bits;
        spinlock_t bgpio_lock;
        unsigned long bgpio_data;
index 69673be10213d94a839ac6c6d97bdc1e27e1aa57..35f299d1f6a794d0898f276836a345c88a7c14a5 100644 (file)
@@ -6,14 +6,16 @@
 #include <linux/list.h>
 
 enum gpio_lookup_flags {
-       GPIO_ACTIVE_HIGH = (0 << 0),
-       GPIO_ACTIVE_LOW = (1 << 0),
-       GPIO_OPEN_DRAIN = (1 << 1),
-       GPIO_OPEN_SOURCE = (1 << 2),
-       GPIO_PERSISTENT = (0 << 3),
-       GPIO_TRANSITORY = (1 << 3),
-       GPIO_PULL_UP = (1 << 4),
-       GPIO_PULL_DOWN = (1 << 5),
+       GPIO_ACTIVE_HIGH                = (0 << 0),
+       GPIO_ACTIVE_LOW                 = (1 << 0),
+       GPIO_OPEN_DRAIN                 = (1 << 1),
+       GPIO_OPEN_SOURCE                = (1 << 2),
+       GPIO_PERSISTENT                 = (0 << 3),
+       GPIO_TRANSITORY                 = (1 << 3),
+       GPIO_PULL_UP                    = (1 << 4),
+       GPIO_PULL_DOWN                  = (1 << 5),
+
+       GPIO_LOOKUP_FLAGS_DEFAULT       = GPIO_ACTIVE_HIGH | GPIO_PERSISTENT,
 };
 
 /**
@@ -22,7 +24,7 @@ enum gpio_lookup_flags {
  * @chip_hwnum: hardware number (i.e. relative to the chip) of the GPIO
  * @con_id: name of the GPIO from the device's point of view
  * @idx: index of the GPIO in case several GPIOs share the same name
- * @flags: mask of GPIO_* values
+ * @flags: bitmask of gpio_lookup_flags GPIO_* values
  *
  * gpiod_lookup is a lookup table for associating GPIOs to specific devices and
  * functions using platform data.
@@ -32,7 +34,7 @@ struct gpiod_lookup {
        u16 chip_hwnum;
        const char *con_id;
        unsigned int idx;
-       enum gpio_lookup_flags flags;
+       unsigned long flags;
 };
 
 struct gpiod_lookup_table {
@@ -46,7 +48,7 @@ struct gpiod_lookup_table {
  * @chip_label: name of the chip the GPIO belongs to
  * @chip_hwnum: hardware number (i.e. relative to the chip) of the GPIO
  * @line_name: consumer name for the hogged line
- * @lflags: mask of GPIO lookup flags
+ * @lflags: bitmask of gpio_lookup_flags GPIO_* values
  * @dflags: GPIO flags used to specify the direction and value
  */
 struct gpiod_hog {
@@ -54,7 +56,7 @@ struct gpiod_hog {
        const char *chip_label;
        u16 chip_hwnum;
        const char *line_name;
-       enum gpio_lookup_flags lflags;
+       unsigned long lflags;
        int dflags;
 };
 
index ad50b7b4f141ce7eeb22c46c3d2ef61c672919a8..51ec27a846681647afee1a714c5d2cd2e75ef3fb 100644 (file)
 #include <linux/migrate.h>
 #include <linux/memremap.h>
 #include <linux/completion.h>
+#include <linux/mmu_notifier.h>
 
-struct hmm;
+
+/*
+ * struct hmm - HMM per mm struct
+ *
+ * @mm: mm struct this HMM struct is bound to
+ * @lock: lock protecting ranges list
+ * @ranges: list of range being snapshotted
+ * @mirrors: list of mirrors for this mm
+ * @mmu_notifier: mmu notifier to track updates to CPU page table
+ * @mirrors_sem: read/write semaphore protecting the mirrors list
+ * @wq: wait queue for user waiting on a range invalidation
+ * @notifiers: count of active mmu notifiers
+ * @dead: is the mm dead ?
+ */
+struct hmm {
+       struct mm_struct        *mm;
+       struct kref             kref;
+       struct mutex            lock;
+       struct list_head        ranges;
+       struct list_head        mirrors;
+       struct mmu_notifier     mmu_notifier;
+       struct rw_semaphore     mirrors_sem;
+       wait_queue_head_t       wq;
+       long                    notifiers;
+       bool                    dead;
+};
 
 /*
  * hmm_pfn_flag_e - HMM flag enums
@@ -131,6 +157,7 @@ enum hmm_pfn_value_e {
 /*
  * struct hmm_range - track invalidation lock on virtual address range
  *
+ * @hmm: the core HMM structure this range is active against
  * @vma: the vm area struct for the range
  * @list: all range lock are on a list
  * @start: range virtual start address (inclusive)
@@ -138,10 +165,13 @@ enum hmm_pfn_value_e {
  * @pfns: array of pfns (big enough for the range)
  * @flags: pfn flags to match device driver page table
  * @values: pfn value for some special case (none, special, error, ...)
+ * @default_flags: default flags for the range (write, read, ... see hmm doc)
+ * @pfn_flags_mask: allows to mask pfn flags so that only default_flags matter
  * @pfn_shifts: pfn shift value (should be <= PAGE_SHIFT)
  * @valid: pfns array did not change since it has been fill by an HMM function
  */
 struct hmm_range {
+       struct hmm              *hmm;
        struct vm_area_struct   *vma;
        struct list_head        list;
        unsigned long           start;
@@ -149,41 +179,96 @@ struct hmm_range {
        uint64_t                *pfns;
        const uint64_t          *flags;
        const uint64_t          *values;
+       uint64_t                default_flags;
+       uint64_t                pfn_flags_mask;
+       uint8_t                 page_shift;
        uint8_t                 pfn_shift;
        bool                    valid;
 };
 
 /*
- * hmm_pfn_to_page() - return struct page pointed to by a valid HMM pfn
- * @range: range use to decode HMM pfn value
- * @pfn: HMM pfn value to get corresponding struct page from
- * Returns: struct page pointer if pfn is a valid HMM pfn, NULL otherwise
+ * hmm_range_page_shift() - return the page shift for the range
+ * @range: range being queried
+ * Returns: page shift (page size = 1 << page shift) for the range
+ */
+static inline unsigned hmm_range_page_shift(const struct hmm_range *range)
+{
+       return range->page_shift;
+}
+
+/*
+ * hmm_range_page_size() - return the page size for the range
+ * @range: range being queried
+ * Returns: page size for the range in bytes
+ */
+static inline unsigned long hmm_range_page_size(const struct hmm_range *range)
+{
+       return 1UL << hmm_range_page_shift(range);
+}
+
+/*
+ * hmm_range_wait_until_valid() - wait for range to be valid
+ * @range: range affected by invalidation to wait on
+ * @timeout: time out for wait in ms (ie abort wait after that period of time)
+ * Returns: true if the range is valid, false otherwise.
+ */
+static inline bool hmm_range_wait_until_valid(struct hmm_range *range,
+                                             unsigned long timeout)
+{
+       /* Check if mm is dead ? */
+       if (range->hmm == NULL || range->hmm->dead || range->hmm->mm == NULL) {
+               range->valid = false;
+               return false;
+       }
+       if (range->valid)
+               return true;
+       wait_event_timeout(range->hmm->wq, range->valid || range->hmm->dead,
+                          msecs_to_jiffies(timeout));
+       /* Return current valid status just in case we get lucky */
+       return range->valid;
+}
+
+/*
+ * hmm_range_valid() - test if a range is valid or not
+ * @range: range
+ * Returns: true if the range is valid, false otherwise.
+ */
+static inline bool hmm_range_valid(struct hmm_range *range)
+{
+       return range->valid;
+}
+
+/*
+ * hmm_device_entry_to_page() - return struct page pointed to by a device entry
+ * @range: range use to decode device entry value
+ * @entry: device entry value to get corresponding struct page from
+ * Returns: struct page pointer if entry is a valid, NULL otherwise
  *
- * If the HMM pfn is valid (ie valid flag set) then return the struct page
- * matching the pfn value stored in the HMM pfn. Otherwise return NULL.
+ * If the device entry is valid (ie valid flag set) then return the struct page
+ * matching the entry value. Otherwise return NULL.
  */
-static inline struct page *hmm_pfn_to_page(const struct hmm_range *range,
-                                          uint64_t pfn)
+static inline struct page *hmm_device_entry_to_page(const struct hmm_range *range,
+                                                   uint64_t entry)
 {
-       if (pfn == range->values[HMM_PFN_NONE])
+       if (entry == range->values[HMM_PFN_NONE])
                return NULL;
-       if (pfn == range->values[HMM_PFN_ERROR])
+       if (entry == range->values[HMM_PFN_ERROR])
                return NULL;
-       if (pfn == range->values[HMM_PFN_SPECIAL])
+       if (entry == range->values[HMM_PFN_SPECIAL])
                return NULL;
-       if (!(pfn & range->flags[HMM_PFN_VALID]))
+       if (!(entry & range->flags[HMM_PFN_VALID]))
                return NULL;
-       return pfn_to_page(pfn >> range->pfn_shift);
+       return pfn_to_page(entry >> range->pfn_shift);
 }
 
 /*
- * hmm_pfn_to_pfn() - return pfn value store in a HMM pfn
- * @range: range use to decode HMM pfn value
- * @pfn: HMM pfn value to extract pfn from
- * Returns: pfn value if HMM pfn is valid, -1UL otherwise
+ * hmm_device_entry_to_pfn() - return pfn value store in a device entry
+ * @range: range use to decode device entry value
+ * @entry: device entry to extract pfn from
+ * Returns: pfn value if device entry is valid, -1UL otherwise
  */
-static inline unsigned long hmm_pfn_to_pfn(const struct hmm_range *range,
-                                          uint64_t pfn)
+static inline unsigned long
+hmm_device_entry_to_pfn(const struct hmm_range *range, uint64_t pfn)
 {
        if (pfn == range->values[HMM_PFN_NONE])
                return -1UL;
@@ -197,31 +282,66 @@ static inline unsigned long hmm_pfn_to_pfn(const struct hmm_range *range,
 }
 
 /*
- * hmm_pfn_from_page() - create a valid HMM pfn value from struct page
+ * hmm_device_entry_from_page() - create a valid device entry for a page
  * @range: range use to encode HMM pfn value
- * @page: struct page pointer for which to create the HMM pfn
- * Returns: valid HMM pfn for the page
+ * @page: page for which to create the device entry
+ * Returns: valid device entry for the page
  */
-static inline uint64_t hmm_pfn_from_page(const struct hmm_range *range,
-                                        struct page *page)
+static inline uint64_t hmm_device_entry_from_page(const struct hmm_range *range,
+                                                 struct page *page)
 {
        return (page_to_pfn(page) << range->pfn_shift) |
                range->flags[HMM_PFN_VALID];
 }
 
 /*
- * hmm_pfn_from_pfn() - create a valid HMM pfn value from pfn
+ * hmm_device_entry_from_pfn() - create a valid device entry value from pfn
  * @range: range use to encode HMM pfn value
- * @pfn: pfn value for which to create the HMM pfn
- * Returns: valid HMM pfn for the pfn
+ * @pfn: pfn value for which to create the device entry
+ * Returns: valid device entry for the pfn
  */
-static inline uint64_t hmm_pfn_from_pfn(const struct hmm_range *range,
-                                       unsigned long pfn)
+static inline uint64_t hmm_device_entry_from_pfn(const struct hmm_range *range,
+                                                unsigned long pfn)
 {
        return (pfn << range->pfn_shift) |
                range->flags[HMM_PFN_VALID];
 }
 
+/*
+ * Old API:
+ * hmm_pfn_to_page()
+ * hmm_pfn_to_pfn()
+ * hmm_pfn_from_page()
+ * hmm_pfn_from_pfn()
+ *
+ * This are the OLD API please use new API, it is here to avoid cross-tree
+ * merge painfullness ie we convert things to new API in stages.
+ */
+static inline struct page *hmm_pfn_to_page(const struct hmm_range *range,
+                                          uint64_t pfn)
+{
+       return hmm_device_entry_to_page(range, pfn);
+}
+
+static inline unsigned long hmm_pfn_to_pfn(const struct hmm_range *range,
+                                          uint64_t pfn)
+{
+       return hmm_device_entry_to_pfn(range, pfn);
+}
+
+static inline uint64_t hmm_pfn_from_page(const struct hmm_range *range,
+                                        struct page *page)
+{
+       return hmm_device_entry_from_page(range, page);
+}
+
+static inline uint64_t hmm_pfn_from_pfn(const struct hmm_range *range,
+                                       unsigned long pfn)
+{
+       return hmm_device_entry_from_pfn(range, pfn);
+}
+
+
 
 #if IS_ENABLED(CONFIG_HMM_MIRROR)
 /*
@@ -353,43 +473,113 @@ struct hmm_mirror {
 int hmm_mirror_register(struct hmm_mirror *mirror, struct mm_struct *mm);
 void hmm_mirror_unregister(struct hmm_mirror *mirror);
 
-
 /*
- * To snapshot the CPU page table, call hmm_vma_get_pfns(), then take a device
- * driver lock that serializes device page table updates, then call
- * hmm_vma_range_done(), to check if the snapshot is still valid. The same
- * device driver page table update lock must also be used in the
- * hmm_mirror_ops.sync_cpu_device_pagetables() callback, so that CPU page
- * table invalidation serializes on it.
- *
- * YOU MUST CALL hmm_vma_range_done() ONCE AND ONLY ONCE EACH TIME YOU CALL
- * hmm_vma_get_pfns() WITHOUT ERROR !
- *
- * IF YOU DO NOT FOLLOW THE ABOVE RULE THE SNAPSHOT CONTENT MIGHT BE INVALID !
+ * hmm_mirror_mm_is_alive() - test if mm is still alive
+ * @mirror: the HMM mm mirror for which we want to lock the mmap_sem
+ * Returns: false if the mm is dead, true otherwise
+ *
+ * This is an optimization it will not accurately always return -EINVAL if the
+ * mm is dead ie there can be false negative (process is being kill but HMM is
+ * not yet inform of that). It is only intented to be use to optimize out case
+ * where driver is about to do something time consuming and it would be better
+ * to skip it if the mm is dead.
  */
-int hmm_vma_get_pfns(struct hmm_range *range);
-bool hmm_vma_range_done(struct hmm_range *range);
+static inline bool hmm_mirror_mm_is_alive(struct hmm_mirror *mirror)
+{
+       struct mm_struct *mm;
+
+       if (!mirror || !mirror->hmm)
+               return false;
+       mm = READ_ONCE(mirror->hmm->mm);
+       if (mirror->hmm->dead || !mm)
+               return false;
+
+       return true;
+}
 
 
 /*
- * Fault memory on behalf of device driver. Unlike handle_mm_fault(), this will
- * not migrate any device memory back to system memory. The HMM pfn array will
- * be updated with the fault result and current snapshot of the CPU page table
- * for the range.
- *
- * The mmap_sem must be taken in read mode before entering and it might be
- * dropped by the function if the block argument is false. In that case, the
- * function returns -EAGAIN.
- *
- * Return value does not reflect if the fault was successful for every single
- * address or not. Therefore, the caller must to inspect the HMM pfn array to
- * determine fault status for each address.
- *
- * Trying to fault inside an invalid vma will result in -EINVAL.
+ * Please see Documentation/vm/hmm.rst for how to use the range API.
+ */
+int hmm_range_register(struct hmm_range *range,
+                      struct mm_struct *mm,
+                      unsigned long start,
+                      unsigned long end,
+                      unsigned page_shift);
+void hmm_range_unregister(struct hmm_range *range);
+long hmm_range_snapshot(struct hmm_range *range);
+long hmm_range_fault(struct hmm_range *range, bool block);
+long hmm_range_dma_map(struct hmm_range *range,
+                      struct device *device,
+                      dma_addr_t *daddrs,
+                      bool block);
+long hmm_range_dma_unmap(struct hmm_range *range,
+                        struct vm_area_struct *vma,
+                        struct device *device,
+                        dma_addr_t *daddrs,
+                        bool dirty);
+
+/*
+ * HMM_RANGE_DEFAULT_TIMEOUT - default timeout (ms) when waiting for a range
  *
- * See the function description in mm/hmm.c for further documentation.
+ * When waiting for mmu notifiers we need some kind of time out otherwise we
+ * could potentialy wait for ever, 1000ms ie 1s sounds like a long time to
+ * wait already.
  */
-int hmm_vma_fault(struct hmm_range *range, bool block);
+#define HMM_RANGE_DEFAULT_TIMEOUT 1000
+
+/* This is a temporary helper to avoid merge conflict between trees. */
+static inline bool hmm_vma_range_done(struct hmm_range *range)
+{
+       bool ret = hmm_range_valid(range);
+
+       hmm_range_unregister(range);
+       return ret;
+}
+
+/* This is a temporary helper to avoid merge conflict between trees. */
+static inline int hmm_vma_fault(struct hmm_range *range, bool block)
+{
+       long ret;
+
+       /*
+        * With the old API the driver must set each individual entries with
+        * the requested flags (valid, write, ...). So here we set the mask to
+        * keep intact the entries provided by the driver and zero out the
+        * default_flags.
+        */
+       range->default_flags = 0;
+       range->pfn_flags_mask = -1UL;
+
+       ret = hmm_range_register(range, range->vma->vm_mm,
+                                range->start, range->end,
+                                PAGE_SHIFT);
+       if (ret)
+               return (int)ret;
+
+       if (!hmm_range_wait_until_valid(range, HMM_RANGE_DEFAULT_TIMEOUT)) {
+               /*
+                * The mmap_sem was taken by driver we release it here and
+                * returns -EAGAIN which correspond to mmap_sem have been
+                * drop in the old API.
+                */
+               up_read(&range->vma->vm_mm->mmap_sem);
+               return -EAGAIN;
+       }
+
+       ret = hmm_range_fault(range, block);
+       if (ret <= 0) {
+               if (ret == -EBUSY || !ret) {
+                       /* Same as above  drop mmap_sem to match old API. */
+                       up_read(&range->vma->vm_mm->mmap_sem);
+                       ret = -EBUSY;
+               } else if (ret == -EAGAIN)
+                       ret = -EBUSY;
+               hmm_range_unregister(range);
+               return ret;
+       }
+       return 0;
+}
 
 /* Below are for HMM internal use only! Not to be used by device driver! */
 void hmm_mm_destroy(struct mm_struct *mm);
index 381e872bfde04c86aa68ba6c15f18bcc09e4b0b5..7cd5c150c21d9ebed9aeba2c0306a7d88b4233a7 100644 (file)
@@ -47,10 +47,8 @@ extern bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,
 extern int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
                        unsigned long addr, pgprot_t newprot,
                        int prot_numa);
-vm_fault_t vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
-                       pmd_t *pmd, pfn_t pfn, bool write);
-vm_fault_t vmf_insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr,
-                       pud_t *pud, pfn_t pfn, bool write);
+vm_fault_t vmf_insert_pfn_pmd(struct vm_fault *vmf, pfn_t pfn, bool write);
+vm_fault_t vmf_insert_pfn_pud(struct vm_fault *vmf, pfn_t pfn, bool write);
 enum transparent_hugepage_flag {
        TRANSPARENT_HUGEPAGE_FLAG,
        TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG,
index 11943b60f2084cb5e69c6dd5553f2adf0ea4f8ca..edf476c8cfb9c0ddc11da72d091bc0077091745e 100644 (file)
@@ -123,9 +123,7 @@ void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason);
 void free_huge_page(struct page *page);
 void hugetlb_fix_reserve_counts(struct inode *inode);
 extern struct mutex *hugetlb_fault_mutex_table;
-u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
-                               struct vm_area_struct *vma,
-                               struct address_space *mapping,
+u32 hugetlb_fault_mutex_hash(struct hstate *h, struct address_space *mapping,
                                pgoff_t idx, unsigned long address);
 
 pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud);
index 9887f4f8e2a898bce65cc76477eab86aadafa296..b2d34831ed7cd153e7a5bf63f42528c7677454bc 100644 (file)
@@ -290,6 +290,20 @@ int iio_read_max_channel_raw(struct iio_channel *chan, int *val);
 int iio_read_avail_channel_raw(struct iio_channel *chan,
                               const int **vals, int *length);
 
+/**
+ * iio_read_avail_channel_attribute() - read available channel attribute values
+ * @chan:              The channel being queried.
+ * @vals:              Available values read back.
+ * @type:              Type of values read back.
+ * @length:            Number of entries in vals.
+ * @attribute:         info attribute to be read back.
+ *
+ * Returns an error code, IIO_AVAIL_RANGE or IIO_AVAIL_LIST.
+ */
+int iio_read_avail_channel_attribute(struct iio_channel *chan,
+                                    const int **vals, int *type, int *length,
+                                    enum iio_chan_info_enum attribute);
+
 /**
  * iio_get_channel_type() - get the type of a channel
  * @channel:           The channel being queried.
index fa364de9db18ee8ff6845c908f7ddcb93707be2c..6925a18a5ca343b45649c505ad543c4a9b193014 100644 (file)
@@ -489,9 +489,11 @@ struct dmar_domain {
                                        /* Domain ids per IOMMU. Use u16 since
                                         * domain ids are 16 bit wide according
                                         * to VT-d spec, section 9.3 */
+       unsigned int    auxd_refcnt;    /* Refcount of auxiliary attaching */
 
        bool has_iotlb_device;
        struct list_head devices;       /* all devices' list */
+       struct list_head auxd;          /* link to device's auxiliary list */
        struct iova_domain iovad;       /* iova's that belong to this domain */
 
        struct dma_pte  *pgd;           /* virtual address */
@@ -510,6 +512,11 @@ struct dmar_domain {
                                           2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
        u64             max_addr;       /* maximum mapped address */
 
+       int             default_pasid;  /*
+                                        * The default pasid used for non-SVM
+                                        * traffic on mediated devices.
+                                        */
+
        struct iommu_domain domain;     /* generic domain data structure for
                                           iommu core */
 };
@@ -559,6 +566,9 @@ 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 */
+       struct list_head auxiliary_domains; /* auxiliary domains
+                                            * attached to this device
+                                            */
        u8 bus;                 /* PCI bus number */
        u8 devfn;               /* PCI devfn number */
        u16 pfsid;              /* SRIOV physical function source ID */
@@ -568,6 +578,7 @@ struct device_domain_info {
        u8 pri_enabled:1;
        u8 ats_supported:1;
        u8 ats_enabled:1;
+       u8 auxd_enabled:1;      /* Multiple domains per device */
        u8 ats_qdep;
        struct device *dev; /* it's NULL for PCIe-to-PCI bridge */
        struct intel_iommu *iommu; /* IOMMU used by this device */
@@ -650,6 +661,7 @@ 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);
 
 #ifdef CONFIG_INTEL_IOMMU_SVM
 int intel_svm_init(struct intel_iommu *iommu);
@@ -679,7 +691,6 @@ struct intel_svm {
        struct list_head list;
 };
 
-extern int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sdev);
 extern struct intel_iommu *intel_svm_device_to_iommu(struct device *dev);
 #endif
 
index ffbbc7e39ceeba3ed827cc475b78683de27dc31a..a815cf6f6f47a8611b70b886d15da0f003ac5a01 100644 (file)
@@ -48,6 +48,7 @@ struct bus_type;
 struct device;
 struct iommu_domain;
 struct notifier_block;
+struct iommu_sva;
 
 /* iommu fault flags */
 #define IOMMU_FAULT_READ       0x0
@@ -55,6 +56,8 @@ struct notifier_block;
 
 typedef int (*iommu_fault_handler_t)(struct iommu_domain *,
                        struct device *, unsigned long, int, void *);
+typedef int (*iommu_mm_exit_handler_t)(struct device *dev, struct iommu_sva *,
+                                      void *);
 
 struct iommu_domain_geometry {
        dma_addr_t aperture_start; /* First address that can be mapped    */
@@ -156,6 +159,33 @@ struct iommu_resv_region {
        enum iommu_resv_type    type;
 };
 
+/* Per device IOMMU features */
+enum iommu_dev_features {
+       IOMMU_DEV_FEAT_AUX,     /* Aux-domain feature */
+       IOMMU_DEV_FEAT_SVA,     /* Shared Virtual Addresses */
+};
+
+#define IOMMU_PASID_INVALID    (-1U)
+
+/**
+ * struct iommu_sva_ops - device driver callbacks for an SVA context
+ *
+ * @mm_exit: called when the mm is about to be torn down by exit_mmap. After
+ *           @mm_exit returns, the device must not issue any more transaction
+ *           with the PASID given as argument.
+ *
+ *           The @mm_exit handler is allowed to sleep. Be careful about the
+ *           locks taken in @mm_exit, because they might lead to deadlocks if
+ *           they are also held when dropping references to the mm. Consider the
+ *           following call chain:
+ *           mutex_lock(A); mmput(mm) -> exit_mm() -> @mm_exit() -> mutex_lock(A)
+ *           Using mmput_async() prevents this scenario.
+ *
+ */
+struct iommu_sva_ops {
+       iommu_mm_exit_handler_t mm_exit;
+};
+
 #ifdef CONFIG_IOMMU_API
 
 /**
@@ -186,6 +216,14 @@ struct iommu_resv_region {
  * @of_xlate: add OF master IDs to iommu grouping
  * @is_attach_deferred: Check if domain attach should be deferred from iommu
  *                      driver init to device driver init (default no)
+ * @dev_has/enable/disable_feat: per device entries to check/enable/disable
+ *                               iommu specific features.
+ * @dev_feat_enabled: check enabled feature
+ * @aux_attach/detach_dev: aux-domain specific attach/detach entries.
+ * @aux_get_pasid: get the pasid given an aux-domain
+ * @sva_bind: Bind process address space to device
+ * @sva_unbind: Unbind process address space from device
+ * @sva_get_pasid: Get PASID associated to a SVA handle
  * @pgsize_bitmap: bitmap of all possible supported page sizes
  */
 struct iommu_ops {
@@ -230,6 +268,22 @@ struct iommu_ops {
        int (*of_xlate)(struct device *dev, struct of_phandle_args *args);
        bool (*is_attach_deferred)(struct iommu_domain *domain, struct device *dev);
 
+       /* Per device IOMMU features */
+       bool (*dev_has_feat)(struct device *dev, enum iommu_dev_features f);
+       bool (*dev_feat_enabled)(struct device *dev, enum iommu_dev_features f);
+       int (*dev_enable_feat)(struct device *dev, enum iommu_dev_features f);
+       int (*dev_disable_feat)(struct device *dev, enum iommu_dev_features f);
+
+       /* Aux-domain specific attach/detach entries */
+       int (*aux_attach_dev)(struct iommu_domain *domain, struct device *dev);
+       void (*aux_detach_dev)(struct iommu_domain *domain, struct device *dev);
+       int (*aux_get_pasid)(struct iommu_domain *domain, struct device *dev);
+
+       struct iommu_sva *(*sva_bind)(struct device *dev, struct mm_struct *mm,
+                                     void *drvdata);
+       void (*sva_unbind)(struct iommu_sva *handle);
+       int (*sva_get_pasid)(struct iommu_sva *handle);
+
        unsigned long pgsize_bitmap;
 };
 
@@ -392,10 +446,22 @@ struct iommu_fwspec {
        const struct iommu_ops  *ops;
        struct fwnode_handle    *iommu_fwnode;
        void                    *iommu_priv;
+       u32                     flags;
        unsigned int            num_ids;
        u32                     ids[1];
 };
 
+/* ATS is supported */
+#define IOMMU_FWSPEC_PCI_RC_ATS                        (1 << 0)
+
+/**
+ * struct iommu_sva - handle to a device-mm bond
+ */
+struct iommu_sva {
+       struct device                   *dev;
+       const struct iommu_sva_ops      *ops;
+};
+
 int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
                      const struct iommu_ops *ops);
 void iommu_fwspec_free(struct device *dev);
@@ -416,6 +482,22 @@ static inline void dev_iommu_fwspec_set(struct device *dev,
 int iommu_probe_device(struct device *dev);
 void iommu_release_device(struct device *dev);
 
+bool iommu_dev_has_feature(struct device *dev, enum iommu_dev_features f);
+int iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features f);
+int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features f);
+bool iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features f);
+int iommu_aux_attach_device(struct iommu_domain *domain, struct device *dev);
+void iommu_aux_detach_device(struct iommu_domain *domain, struct device *dev);
+int iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev);
+
+struct iommu_sva *iommu_sva_bind_device(struct device *dev,
+                                       struct mm_struct *mm,
+                                       void *drvdata);
+void iommu_sva_unbind_device(struct iommu_sva *handle);
+int iommu_sva_set_ops(struct iommu_sva *handle,
+                     const struct iommu_sva_ops *ops);
+int iommu_sva_get_pasid(struct iommu_sva *handle);
+
 #else /* CONFIG_IOMMU_API */
 
 struct iommu_ops {};
@@ -700,6 +782,68 @@ const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode)
        return NULL;
 }
 
+static inline bool
+iommu_dev_has_feature(struct device *dev, enum iommu_dev_features feat)
+{
+       return false;
+}
+
+static inline bool
+iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features feat)
+{
+       return false;
+}
+
+static inline int
+iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features feat)
+{
+       return -ENODEV;
+}
+
+static inline int
+iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat)
+{
+       return -ENODEV;
+}
+
+static inline int
+iommu_aux_attach_device(struct iommu_domain *domain, struct device *dev)
+{
+       return -ENODEV;
+}
+
+static inline void
+iommu_aux_detach_device(struct iommu_domain *domain, struct device *dev)
+{
+}
+
+static inline int
+iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev)
+{
+       return -ENODEV;
+}
+
+static inline struct iommu_sva *
+iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
+{
+       return NULL;
+}
+
+static inline void iommu_sva_unbind_device(struct iommu_sva *handle)
+{
+}
+
+static inline int iommu_sva_set_ops(struct iommu_sva *handle,
+                                   const struct iommu_sva_ops *ops)
+{
+       return -EINVAL;
+}
+
+static inline int iommu_sva_get_pasid(struct iommu_sva *handle)
+{
+       return IOMMU_PASID_INVALID;
+}
+
 #endif /* CONFIG_IOMMU_API */
 
 #ifdef CONFIG_IOMMU_DEBUGFS
index 0b93bf96693ef6f3ea8b6a30315a24fe548443c6..28a5128405f82dd04e03caff3188d90f31eed71c 100644 (file)
@@ -76,6 +76,14 @@ struct iova_domain {
        unsigned long   start_pfn;      /* Lower limit for this domain */
        unsigned long   dma_32bit_pfn;
        unsigned long   max32_alloc_size; /* Size of last failed allocation */
+       struct iova_fq __percpu *fq;    /* Flush Queue */
+
+       atomic64_t      fq_flush_start_cnt;     /* Number of TLB flushes that
+                                                  have been started */
+
+       atomic64_t      fq_flush_finish_cnt;    /* Number of TLB flushes that
+                                                  have been finished */
+
        struct iova     anchor;         /* rbtree lookup anchor */
        struct iova_rcache rcaches[IOVA_RANGE_CACHE_MAX_SIZE];  /* IOVA range caches */
 
@@ -85,14 +93,6 @@ struct iova_domain {
        iova_entry_dtor entry_dtor;     /* IOMMU driver specific destructor for
                                           iova entry */
 
-       struct iova_fq __percpu *fq;    /* Flush Queue */
-
-       atomic64_t      fq_flush_start_cnt;     /* Number of TLB flushes that
-                                                  have been started */
-
-       atomic64_t      fq_flush_finish_cnt;    /* Number of TLB flushes that
-                                                  have been finished */
-
        struct timer_list fq_timer;             /* Timer to regularily empty the
                                                   flush-queues */
        atomic_t fq_timer_on;                   /* 1 when timer is active, 0
index 6ab8c1bada3fccb11119f93130b1989ddb090ad3..c309f43bde45e086df82c7740aed8ddc3671bced 100644 (file)
@@ -19,6 +19,7 @@ struct ipc_ids {
        struct rw_semaphore rwsem;
        struct idr ipcs_idr;
        int max_idx;
+       int last_idx;   /* For wrap around detection */
 #ifdef CONFIG_CHECKPOINT_RESTORE
        int next_id;
 #endif
diff --git a/include/linux/irqchip/irq-ixp4xx.h b/include/linux/irqchip/irq-ixp4xx.h
new file mode 100644 (file)
index 0000000..9395917
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __IRQ_IXP4XX_H
+#define __IRQ_IXP4XX_H
+
+#include <linux/ioport.h>
+struct irq_domain;
+
+void ixp4xx_irq_init(resource_size_t irqbase,
+                    bool is_356);
+struct irq_domain *ixp4xx_get_irq_domain(void);
+
+#endif /* __IRQ_IXP4XX_H */
index a3b59d143afb5d1700dd62072e7f0c92350ee72b..74b1ee9027f595240f35cd6ff83bb4df8021bc62 100644 (file)
@@ -484,6 +484,7 @@ extern int __kernel_text_address(unsigned long addr);
 extern int kernel_text_address(unsigned long addr);
 extern int func_ptr_is_kernel_text(void *ptr);
 
+u64 int_pow(u64 base, unsigned int exp);
 unsigned long int_sqrt(unsigned long);
 
 #if BITS_PER_LONG < 64
index 2c89e60bc7525515d1ff099e7009acb09c575754..0f9da966934e28e40d1315638a26d9a3a4ab597f 100644 (file)
@@ -4,7 +4,6 @@
 /* Simple interface for creating and stopping kernel threads without mess. */
 #include <linux/err.h>
 #include <linux/sched.h>
-#include <linux/cgroup.h>
 
 __printf(4, 5)
 struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
@@ -198,6 +197,8 @@ bool kthread_cancel_delayed_work_sync(struct kthread_delayed_work *work);
 
 void kthread_destroy_worker(struct kthread_worker *worker);
 
+struct cgroup_subsys_state;
+
 #ifdef CONFIG_BLK_CGROUP
 void kthread_associate_blkcg(struct cgroup_subsys_state *css);
 struct cgroup_subsys_state *kthread_blkcg(void);
index 640a03642766bb4ae02c86e3606318c80adaf81d..79fa4426509c4e68b8c519b5196328abbe2370b9 100644 (file)
@@ -227,6 +227,32 @@ enum {
        READING_SHADOW_PAGE_TABLES,
 };
 
+#define KVM_UNMAPPED_PAGE      ((void *) 0x500 + POISON_POINTER_DELTA)
+
+struct kvm_host_map {
+       /*
+        * Only valid if the 'pfn' is managed by the host kernel (i.e. There is
+        * a 'struct page' for it. When using mem= kernel parameter some memory
+        * can be used as guest memory but they are not managed by host
+        * kernel).
+        * If 'pfn' is not managed by the host kernel, this field is
+        * initialized to KVM_UNMAPPED_PAGE.
+        */
+       struct page *page;
+       void *hva;
+       kvm_pfn_t pfn;
+       kvm_pfn_t gfn;
+};
+
+/*
+ * Used to check if the mapping is valid or not. Never use 'kvm_host_map'
+ * directly to check for that.
+ */
+static inline bool kvm_vcpu_mapped(struct kvm_host_map *map)
+{
+       return !!map->hva;
+}
+
 /*
  * Sometimes a large or cross-page mmio needs to be broken up into separate
  * exits for userspace servicing.
@@ -733,7 +759,9 @@ struct kvm_memslots *kvm_vcpu_memslots(struct kvm_vcpu *vcpu);
 struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn);
 kvm_pfn_t kvm_vcpu_gfn_to_pfn_atomic(struct kvm_vcpu *vcpu, gfn_t gfn);
 kvm_pfn_t kvm_vcpu_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
+int kvm_vcpu_map(struct kvm_vcpu *vcpu, gpa_t gpa, struct kvm_host_map *map);
 struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn);
+void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map, bool dirty);
 unsigned long kvm_vcpu_gfn_to_hva(struct kvm_vcpu *vcpu, gfn_t gfn);
 unsigned long kvm_vcpu_gfn_to_hva_prot(struct kvm_vcpu *vcpu, gfn_t gfn, bool *writable);
 int kvm_vcpu_read_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, void *data, int offset,
@@ -1242,11 +1270,21 @@ struct kvm_device_ops {
         */
        void (*destroy)(struct kvm_device *dev);
 
+       /*
+        * Release is an alternative method to free the device. It is
+        * called when the device file descriptor is closed. Once
+        * release is called, the destroy method will not be called
+        * anymore as the device is removed from the device list of
+        * the VM. kvm->lock is held.
+        */
+       void (*release)(struct kvm_device *dev);
+
        int (*set_attr)(struct kvm_device *dev, struct kvm_device_attr *attr);
        int (*get_attr)(struct kvm_device *dev, struct kvm_device_attr *attr);
        int (*has_attr)(struct kvm_device *dev, struct kvm_device_attr *attr);
        long (*ioctl)(struct kvm_device *dev, unsigned int ioctl,
                      unsigned long arg);
+       int (*mmap)(struct kvm_device *dev, struct vm_area_struct *vma);
 };
 
 void kvm_device_get(struct kvm_device *dev);
@@ -1307,6 +1345,16 @@ static inline bool vcpu_valid_wakeup(struct kvm_vcpu *vcpu)
 }
 #endif /* CONFIG_HAVE_KVM_INVALID_WAKEUPS */
 
+#ifdef CONFIG_HAVE_KVM_NO_POLL
+/* Callback that tells if we must not poll */
+bool kvm_arch_no_poll(struct kvm_vcpu *vcpu);
+#else
+static inline bool kvm_arch_no_poll(struct kvm_vcpu *vcpu)
+{
+       return false;
+}
+#endif /* CONFIG_HAVE_KVM_NO_POLL */
+
 #ifdef CONFIG_HAVE_KVM_VCPU_ASYNC_IOCTL
 long kvm_arch_vcpu_async_ioctl(struct file *filp,
                               unsigned int ioctl, unsigned long arg);
index 7c560e0dc8f4d6793ba00553bea63d2cb1de2a87..9022f0c2e2e41ea40265c564fe25a2a6f9fa831a 100644 (file)
@@ -36,7 +36,7 @@ account_scheduler_latency(struct task_struct *task, int usecs, int inter)
                __account_scheduler_latency(task, usecs, inter);
 }
 
-void clear_all_latency_tracing(struct task_struct *p);
+void clear_tsk_latency_tracing(struct task_struct *p);
 
 extern int sysctl_latencytop(struct ctl_table *table, int write,
                        void __user *buffer, size_t *lenp, loff_t *ppos);
@@ -48,7 +48,7 @@ account_scheduler_latency(struct task_struct *task, int usecs, int inter)
 {
 }
 
-static inline void clear_all_latency_tracing(struct task_struct *p)
+static inline void clear_tsk_latency_tracing(struct task_struct *p)
 {
 }
 
index 5d865a5d5cdca503bfbcddcfa55c9cef082f1b36..4d0d5655c7b24bc8af36cd0dfc476e3cad9221d5 100644 (file)
@@ -358,6 +358,7 @@ struct nvm_geo {
        u16     csecs;          /* sector size */
        u16     sos;            /* out-of-band area size */
        bool    ext;            /* metadata in extended data buffer */
+       u32     mdts;           /* Max data transfer size*/
 
        /* device write constrains */
        u32     ws_min;         /* minimum write size */
@@ -427,6 +428,7 @@ struct nvm_dev {
        char name[DISK_NAME_LEN];
        void *private_data;
 
+       struct kref ref;
        void *rmap;
 
        struct mutex mlock;
index 58aa3adf94e63585631876b9a880c454fbd905df..e951228db4b2c64f68a05f73bd6e058652699730 100644 (file)
@@ -150,6 +150,23 @@ static inline void list_replace_init(struct list_head *old,
        INIT_LIST_HEAD(old);
 }
 
+/**
+ * list_swap - replace entry1 with entry2 and re-add entry1 at entry2's position
+ * @entry1: the location to place entry2
+ * @entry2: the location to place entry1
+ */
+static inline void list_swap(struct list_head *entry1,
+                            struct list_head *entry2)
+{
+       struct list_head *pos = entry2->prev;
+
+       list_del(entry2);
+       list_replace(entry1, entry2);
+       if (pos == entry1)
+               pos = entry2;
+       list_add(entry1, pos);
+}
+
 /**
  * list_del_init - deletes entry from list and reinitialize it.
  * @entry: the element to delete from the list.
@@ -270,6 +287,24 @@ static inline void list_rotate_left(struct list_head *head)
        }
 }
 
+/**
+ * list_rotate_to_front() - Rotate list to specific item.
+ * @list: The desired new front of the list.
+ * @head: The head of the list.
+ *
+ * Rotates list so that @list becomes the new front of the list.
+ */
+static inline void list_rotate_to_front(struct list_head *list,
+                                       struct list_head *head)
+{
+       /*
+        * Deletes the list head from the list denoted by @head and
+        * places it as the tail of @list, this effectively rotates the
+        * list so that @list is at the front.
+        */
+       list_move_tail(head, list);
+}
+
 /**
  * list_is_singular - tests whether a list has just one entry.
  * @head: the list to test.
@@ -754,7 +789,7 @@ static inline void hlist_add_behind(struct hlist_node *n,
                                    struct hlist_node *prev)
 {
        n->next = prev->next;
-       WRITE_ONCE(prev->next, n);
+       prev->next = n;
        n->pprev = &prev->next;
 
        if (n->next)
index 3fc2cc57ba1bc6d5badfd24ef67982683457507e..ae1b541446c906158cb057538b62241161e4b361 100644 (file)
@@ -86,6 +86,32 @@ static inline void hlist_bl_add_head(struct hlist_bl_node *n,
        hlist_bl_set_first(h, n);
 }
 
+static inline void hlist_bl_add_before(struct hlist_bl_node *n,
+                                      struct hlist_bl_node *next)
+{
+       struct hlist_bl_node **pprev = next->pprev;
+
+       n->pprev = pprev;
+       n->next = next;
+       next->pprev = &n->next;
+
+       /* pprev may be `first`, so be careful not to lose the lock bit */
+       WRITE_ONCE(*pprev,
+                  (struct hlist_bl_node *)
+                       ((uintptr_t)n | ((uintptr_t)*pprev & LIST_BL_LOCKMASK)));
+}
+
+static inline void hlist_bl_add_behind(struct hlist_bl_node *n,
+                                      struct hlist_bl_node *prev)
+{
+       n->next = prev->next;
+       n->pprev = &prev->next;
+       prev->next = n;
+
+       if (n->next)
+               n->next->pprev = &n->next;
+}
+
 static inline void __hlist_bl_del(struct hlist_bl_node *n)
 {
        struct hlist_bl_node *next = n->next;
index ba79956e848d5d86ea9194f64c59bf0c60c4b65a..20f178c24e9d13db3ddb4d628f1085831410b30b 100644 (file)
@@ -6,6 +6,7 @@
 
 struct list_head;
 
+__attribute__((nonnull(2,3)))
 void list_sort(void *priv, struct list_head *head,
               int (*cmp)(void *priv, struct list_head *a,
                          struct list_head *b));
index 8c0cf1059443afe0f48690b41895f2ae746b0fe1..0520c0cd73f42ef33c67c97fbad3ca277be67f48 100644 (file)
@@ -76,7 +76,7 @@ struct nlmclnt_operations {
 };
 
 extern int     nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl, void *data);
-extern int     lockd_up(struct net *net);
+extern int     lockd_up(struct net *net, const struct cred *cred);
 extern void    lockd_down(struct net *net);
 
 #endif /* LINUX_LOCKD_BIND_H */
index d7aee90e5da5adf16bdcd26fea9f4f130aced6dc..89a52fd5756e482d1cc216afb4fbe700483b675a 100644 (file)
 
 struct mdev_device;
 
+/*
+ * Called by the parent device driver to set the device which represents
+ * this mdev in iommu protection scope. By default, the iommu device is
+ * NULL, that indicates using vendor defined isolation.
+ *
+ * @dev: the mediated device that iommu will isolate.
+ * @iommu_device: a pci device which represents the iommu for @dev.
+ *
+ * Return 0 for success, otherwise negative error value.
+ */
+int mdev_set_iommu_device(struct device *dev, struct device *iommu_device);
+
+struct device *mdev_get_iommu_device(struct device *dev);
+
 /**
  * struct mdev_parent_ops - Structure to be registered for each parent device to
  * register the device to mdev module.
@@ -118,21 +132,20 @@ struct mdev_driver {
 
 #define to_mdev_driver(drv)    container_of(drv, struct mdev_driver, driver)
 
-extern void *mdev_get_drvdata(struct mdev_device *mdev);
-extern void mdev_set_drvdata(struct mdev_device *mdev, void *data);
-extern const guid_t *mdev_uuid(struct mdev_device *mdev);
+void *mdev_get_drvdata(struct mdev_device *mdev);
+void mdev_set_drvdata(struct mdev_device *mdev, void *data);
+const guid_t *mdev_uuid(struct mdev_device *mdev);
 
 extern struct bus_type mdev_bus_type;
 
-extern int  mdev_register_device(struct device *dev,
-                                const struct mdev_parent_ops *ops);
-extern void mdev_unregister_device(struct device *dev);
+int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops);
+void mdev_unregister_device(struct device *dev);
 
-extern int  mdev_register_driver(struct mdev_driver *drv, struct module *owner);
-extern void mdev_unregister_driver(struct mdev_driver *drv);
+int mdev_register_driver(struct mdev_driver *drv, struct module *owner);
+void mdev_unregister_driver(struct mdev_driver *drv);
 
-extern struct device *mdev_parent_dev(struct mdev_device *mdev);
-extern struct device *mdev_dev(struct mdev_device *mdev);
-extern struct mdev_device *mdev_from_dev(struct device *dev);
+struct device *mdev_parent_dev(struct mdev_device *mdev);
+struct device *mdev_dev(struct mdev_device *mdev);
+struct mdev_device *mdev_from_dev(struct device *dev);
 
 #endif /* MDEV_H */
index 294d5d80e1500998dd8a52752fee5e288b761204..676d3900e1bd5f0a3001105c944bd5da0097bba0 100644 (file)
@@ -96,13 +96,14 @@ struct memblock {
 extern struct memblock memblock;
 extern int memblock_debug;
 
-#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
+#ifndef CONFIG_ARCH_KEEP_MEMBLOCK
 #define __init_memblock __meminit
 #define __initdata_memblock __meminitdata
 void memblock_discard(void);
 #else
 #define __init_memblock
 #define __initdata_memblock
+static inline void memblock_discard(void) {}
 #endif
 
 #define memblock_dbg(fmt, ...) \
@@ -240,6 +241,47 @@ void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn,
             i >= 0; __next_mem_pfn_range(&i, nid, p_start, p_end, p_nid))
 #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
 
+#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
+void __next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone,
+                                 unsigned long *out_spfn,
+                                 unsigned long *out_epfn);
+/**
+ * for_each_free_mem_range_in_zone - iterate through zone specific free
+ * memblock areas
+ * @i: u64 used as loop variable
+ * @zone: zone in which all of the memory blocks reside
+ * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL
+ * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL
+ *
+ * Walks over free (memory && !reserved) areas of memblock in a specific
+ * zone. Available once memblock and an empty zone is initialized. The main
+ * assumption is that the zone start, end, and pgdat have been associated.
+ * This way we can use the zone to determine NUMA node, and if a given part
+ * of the memblock is valid for the zone.
+ */
+#define for_each_free_mem_pfn_range_in_zone(i, zone, p_start, p_end)   \
+       for (i = 0,                                                     \
+            __next_mem_pfn_range_in_zone(&i, zone, p_start, p_end);    \
+            i != U64_MAX;                                      \
+            __next_mem_pfn_range_in_zone(&i, zone, p_start, p_end))
+
+/**
+ * for_each_free_mem_range_in_zone_from - iterate through zone specific
+ * free memblock areas from a given point
+ * @i: u64 used as loop variable
+ * @zone: zone in which all of the memory blocks reside
+ * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL
+ * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL
+ *
+ * Walks over free (memory && !reserved) areas of memblock in a specific
+ * zone, continuing from current position. Available as soon as memblock is
+ * initialized.
+ */
+#define for_each_free_mem_pfn_range_in_zone_from(i, zone, p_start, p_end) \
+       for (; i != U64_MAX;                                      \
+            __next_mem_pfn_range_in_zone(&i, zone, p_start, p_end))
+#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
+
 /**
  * for_each_free_mem_range - iterate through free memblock areas
  * @i: u64 used as loop variable
index dbb6118370c1e3c6df88b7da5695aea57dcd08ad..bc74d6a4407c9a5eeb23f31410e4d01590a62ab0 100644 (file)
@@ -94,8 +94,8 @@ enum mem_cgroup_events_target {
        MEM_CGROUP_NTARGETS,
 };
 
-struct mem_cgroup_stat_cpu {
-       long count[MEMCG_NR_STAT];
+struct memcg_vmstats_percpu {
+       long stat[MEMCG_NR_STAT];
        unsigned long events[NR_VM_EVENT_ITEMS];
        unsigned long nr_page_events;
        unsigned long targets[MEM_CGROUP_NTARGETS];
@@ -128,6 +128,7 @@ struct mem_cgroup_per_node {
 
        struct lruvec_stat __percpu *lruvec_stat_cpu;
        atomic_long_t           lruvec_stat[NR_VM_NODE_STAT_ITEMS];
+       atomic_long_t           lruvec_stat_local[NR_VM_NODE_STAT_ITEMS];
 
        unsigned long           lru_zone_size[MAX_NR_ZONES][NR_LRU_LISTS];
 
@@ -274,13 +275,17 @@ struct mem_cgroup {
        struct task_struct      *move_lock_task;
 
        /* memory.stat */
-       struct mem_cgroup_stat_cpu __percpu *stat_cpu;
+       struct memcg_vmstats_percpu __percpu *vmstats_percpu;
 
        MEMCG_PADDING(_pad2_);
 
-       atomic_long_t           stat[MEMCG_NR_STAT];
-       atomic_long_t           events[NR_VM_EVENT_ITEMS];
-       atomic_long_t memory_events[MEMCG_NR_MEMORY_EVENTS];
+       atomic_long_t           vmstats[MEMCG_NR_STAT];
+       atomic_long_t           vmstats_local[MEMCG_NR_STAT];
+
+       atomic_long_t           vmevents[NR_VM_EVENT_ITEMS];
+       atomic_long_t           vmevents_local[NR_VM_EVENT_ITEMS];
+
+       atomic_long_t           memory_events[MEMCG_NR_MEMORY_EVENTS];
 
        unsigned long           socket_pressure;
 
@@ -501,22 +506,6 @@ int mem_cgroup_select_victim_node(struct mem_cgroup *memcg);
 void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru,
                int zid, int nr_pages);
 
-unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
-                                          int nid, unsigned int lru_mask);
-
-static inline
-unsigned long mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru)
-{
-       struct mem_cgroup_per_node *mz;
-       unsigned long nr_pages = 0;
-       int zid;
-
-       mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
-       for (zid = 0; zid < MAX_NR_ZONES; zid++)
-               nr_pages += mz->lru_zone_size[zid][lru];
-       return nr_pages;
-}
-
 static inline
 unsigned long mem_cgroup_get_zone_lru_size(struct lruvec *lruvec,
                enum lru_list lru, int zone_idx)
@@ -570,10 +559,9 @@ void unlock_page_memcg(struct page *page);
  * idx can be of type enum memcg_stat_item or node_stat_item.
  * Keep in sync with memcg_exact_page_state().
  */
-static inline unsigned long memcg_page_state(struct mem_cgroup *memcg,
-                                            int idx)
+static inline unsigned long memcg_page_state(struct mem_cgroup *memcg, int idx)
 {
-       long x = atomic_long_read(&memcg->stat[idx]);
+       long x = atomic_long_read(&memcg->vmstats[idx]);
 #ifdef CONFIG_SMP
        if (x < 0)
                x = 0;
@@ -581,23 +569,23 @@ static inline unsigned long memcg_page_state(struct mem_cgroup *memcg,
        return x;
 }
 
-/* idx can be of type enum memcg_stat_item or node_stat_item */
-static inline void __mod_memcg_state(struct mem_cgroup *memcg,
-                                    int idx, int val)
+/*
+ * idx can be of type enum memcg_stat_item or node_stat_item.
+ * Keep in sync with memcg_exact_page_state().
+ */
+static inline unsigned long memcg_page_state_local(struct mem_cgroup *memcg,
+                                                  int idx)
 {
-       long x;
-
-       if (mem_cgroup_disabled())
-               return;
-
-       x = val + __this_cpu_read(memcg->stat_cpu->count[idx]);
-       if (unlikely(abs(x) > MEMCG_CHARGE_BATCH)) {
-               atomic_long_add(x, &memcg->stat[idx]);
+       long x = atomic_long_read(&memcg->vmstats_local[idx]);
+#ifdef CONFIG_SMP
+       if (x < 0)
                x = 0;
-       }
-       __this_cpu_write(memcg->stat_cpu->count[idx], x);
+#endif
+       return x;
 }
 
+void __mod_memcg_state(struct mem_cgroup *memcg, int idx, int val);
+
 /* idx can be of type enum memcg_stat_item or node_stat_item */
 static inline void mod_memcg_state(struct mem_cgroup *memcg,
                                   int idx, int val)
@@ -658,32 +646,27 @@ static inline unsigned long lruvec_page_state(struct lruvec *lruvec,
        return x;
 }
 
-static inline void __mod_lruvec_state(struct lruvec *lruvec,
-                                     enum node_stat_item idx, int val)
+static inline unsigned long lruvec_page_state_local(struct lruvec *lruvec,
+                                                   enum node_stat_item idx)
 {
        struct mem_cgroup_per_node *pn;
        long x;
 
-       /* Update node */
-       __mod_node_page_state(lruvec_pgdat(lruvec), idx, val);
-
        if (mem_cgroup_disabled())
-               return;
+               return node_page_state(lruvec_pgdat(lruvec), idx);
 
        pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
-
-       /* Update memcg */
-       __mod_memcg_state(pn->memcg, idx, val);
-
-       /* Update lruvec */
-       x = val + __this_cpu_read(pn->lruvec_stat_cpu->count[idx]);
-       if (unlikely(abs(x) > MEMCG_CHARGE_BATCH)) {
-               atomic_long_add(x, &pn->lruvec_stat[idx]);
+       x = atomic_long_read(&pn->lruvec_stat_local[idx]);
+#ifdef CONFIG_SMP
+       if (x < 0)
                x = 0;
-       }
-       __this_cpu_write(pn->lruvec_stat_cpu->count[idx], x);
+#endif
+       return x;
 }
 
+void __mod_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
+                       int val);
+
 static inline void mod_lruvec_state(struct lruvec *lruvec,
                                    enum node_stat_item idx, int val)
 {
@@ -724,22 +707,8 @@ unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
                                                gfp_t gfp_mask,
                                                unsigned long *total_scanned);
 
-static inline void __count_memcg_events(struct mem_cgroup *memcg,
-                                       enum vm_event_item idx,
-                                       unsigned long count)
-{
-       unsigned long x;
-
-       if (mem_cgroup_disabled())
-               return;
-
-       x = count + __this_cpu_read(memcg->stat_cpu->events[idx]);
-       if (unlikely(x > MEMCG_CHARGE_BATCH)) {
-               atomic_long_add(x, &memcg->events[idx]);
-               x = 0;
-       }
-       __this_cpu_write(memcg->stat_cpu->events[idx], x);
-}
+void __count_memcg_events(struct mem_cgroup *memcg, enum vm_event_item idx,
+                         unsigned long count);
 
 static inline void count_memcg_events(struct mem_cgroup *memcg,
                                      enum vm_event_item idx,
@@ -960,11 +929,6 @@ static inline bool mem_cgroup_online(struct mem_cgroup *memcg)
        return true;
 }
 
-static inline unsigned long
-mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru)
-{
-       return 0;
-}
 static inline
 unsigned long mem_cgroup_get_zone_lru_size(struct lruvec *lruvec,
                enum lru_list lru, int zone_idx)
@@ -972,13 +936,6 @@ unsigned long mem_cgroup_get_zone_lru_size(struct lruvec *lruvec,
        return 0;
 }
 
-static inline unsigned long
-mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
-                            int nid, unsigned int lru_mask)
-{
-       return 0;
-}
-
 static inline unsigned long mem_cgroup_get_max(struct mem_cgroup *memcg)
 {
        return 0;
@@ -1039,8 +996,13 @@ static inline void mem_cgroup_print_oom_group(struct mem_cgroup *memcg)
 {
 }
 
-static inline unsigned long memcg_page_state(struct mem_cgroup *memcg,
-                                            int idx)
+static inline unsigned long memcg_page_state(struct mem_cgroup *memcg, int idx)
+{
+       return 0;
+}
+
+static inline unsigned long memcg_page_state_local(struct mem_cgroup *memcg,
+                                                  int idx)
 {
        return 0;
 }
@@ -1075,6 +1037,12 @@ static inline unsigned long lruvec_page_state(struct lruvec *lruvec,
        return node_page_state(lruvec_pgdat(lruvec), idx);
 }
 
+static inline unsigned long lruvec_page_state_local(struct lruvec *lruvec,
+                                                   enum node_stat_item idx)
+{
+       return node_page_state(lruvec_pgdat(lruvec), idx);
+}
+
 static inline void __mod_lruvec_state(struct lruvec *lruvec,
                                      enum node_stat_item idx, int val)
 {
@@ -1117,6 +1085,12 @@ static inline void count_memcg_events(struct mem_cgroup *memcg,
 {
 }
 
+static inline void __count_memcg_events(struct mem_cgroup *memcg,
+                                       enum vm_event_item idx,
+                                       unsigned long count)
+{
+}
+
 static inline void count_memcg_page_event(struct page *page,
                                          int idx)
 {
index a6ddefc60517899167b55b53b0007ba3e3b9ed80..e1dc1bb2b787756d833266697161edfb69ceb7cb 100644 (file)
@@ -113,7 +113,7 @@ extern int register_memory_isolate_notifier(struct notifier_block *nb);
 extern void unregister_memory_isolate_notifier(struct notifier_block *nb);
 int hotplug_memory_register(int nid, struct mem_section *section);
 #ifdef CONFIG_MEMORY_HOTREMOVE
-extern int unregister_memory_section(struct mem_section *);
+extern void unregister_memory_section(struct mem_section *);
 #endif
 extern int memory_dev_init(void);
 extern int memory_notify(unsigned long val, void *v);
index 8ade08c50d26bd3a0d3dc2ef2b391a8be046ab83..ae892eef8b825fb95a94b8ff37a7aa31c203d006 100644 (file)
@@ -53,6 +53,16 @@ enum {
        MMOP_ONLINE_MOVABLE,
 };
 
+/*
+ * Restrictions for the memory hotplug:
+ * flags:  MHP_ flags
+ * altmap: alternative allocator for memmap array
+ */
+struct mhp_restrictions {
+       unsigned long flags;
+       struct vmem_altmap *altmap;
+};
+
 /*
  * Zone resizing functions
  *
@@ -87,7 +97,8 @@ extern int add_one_highpage(struct page *page, int pfn, int bad_ppro);
 extern int online_pages(unsigned long, unsigned long, int);
 extern int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn,
        unsigned long *valid_start, unsigned long *valid_end);
-extern void __offline_isolated_pages(unsigned long, unsigned long);
+extern unsigned long __offline_isolated_pages(unsigned long start_pfn,
+                                               unsigned long end_pfn);
 
 typedef void (*online_page_callback_t)(struct page *page, unsigned int order);
 
@@ -100,6 +111,8 @@ extern void __online_page_free(struct page *page);
 
 extern int try_online_node(int nid);
 
+extern int arch_add_memory(int nid, u64 start, u64 size,
+                       struct mhp_restrictions *restrictions);
 extern u64 max_mem_size;
 
 extern bool memhp_auto_online;
@@ -111,26 +124,33 @@ static inline bool movable_node_is_enabled(void)
 }
 
 #ifdef CONFIG_MEMORY_HOTREMOVE
-extern int arch_remove_memory(int nid, u64 start, u64 size,
-                               struct vmem_altmap *altmap);
-extern int __remove_pages(struct zone *zone, unsigned long start_pfn,
-       unsigned long nr_pages, struct vmem_altmap *altmap);
+extern void arch_remove_memory(int nid, u64 start, u64 size,
+                              struct vmem_altmap *altmap);
+extern void __remove_pages(struct zone *zone, unsigned long start_pfn,
+                          unsigned long nr_pages, struct vmem_altmap *altmap);
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
+/*
+ * Do we want sysfs memblock files created. This will allow userspace to online
+ * and offline memory explicitly. Lack of this bit means that the caller has to
+ * call move_pfn_range_to_zone to finish the initialization.
+ */
+
+#define MHP_MEMBLOCK_API               (1<<0)
+
 /* reasonably generic interface to expand the physical pages */
 extern int __add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
-               struct vmem_altmap *altmap, bool want_memblock);
+                      struct mhp_restrictions *restrictions);
 
 #ifndef CONFIG_ARCH_HAS_ADD_PAGES
 static inline int add_pages(int nid, unsigned long start_pfn,
-               unsigned long nr_pages, struct vmem_altmap *altmap,
-               bool want_memblock)
+               unsigned long nr_pages, struct mhp_restrictions *restrictions)
 {
-       return __add_pages(nid, start_pfn, nr_pages, altmap, want_memblock);
+       return __add_pages(nid, start_pfn, nr_pages, restrictions);
 }
 #else /* ARCH_HAS_ADD_PAGES */
 int add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
-               struct vmem_altmap *altmap, bool want_memblock);
+             struct mhp_restrictions *restrictions);
 #endif /* ARCH_HAS_ADD_PAGES */
 
 #ifdef CONFIG_NUMA
@@ -331,8 +351,6 @@ extern int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
 extern int __add_memory(int nid, u64 start, u64 size);
 extern int add_memory(int nid, u64 start, u64 size);
 extern int add_memory_resource(int nid, struct resource *resource);
-extern int arch_add_memory(int nid, u64 start, u64 size,
-               struct vmem_altmap *altmap, bool want_memblock);
 extern void move_pfn_range_to_zone(struct zone *zone, unsigned long start_pfn,
                unsigned long nr_pages, struct vmem_altmap *altmap);
 extern bool is_memblock_offlined(struct memory_block *mem);
diff --git a/include/linux/mfd/altera-sysmgr.h b/include/linux/mfd/altera-sysmgr.h
new file mode 100644 (file)
index 0000000..b1ef11a
--- /dev/null
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018-2019 Intel Corporation
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2012 Linaro Ltd.
+ */
+
+#ifndef __LINUX_MFD_ALTERA_SYSMGR_H__
+#define __LINUX_MFD_ALTERA_SYSMGR_H__
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/firmware/intel/stratix10-smc.h>
+
+struct device_node;
+
+#ifdef CONFIG_MFD_ALTERA_SYSMGR
+struct regmap *altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np,
+                                                   const char *property);
+#else
+static inline struct regmap *
+altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np,
+                                    const char *property)
+{
+       return ERR_PTR(-ENOTSUPP);
+}
+#endif
+
+#endif /* __LINUX_MFD_ALTERA_SYSMGR_H__ */
index 8f2a8918bfa33c21b26a1489bf61484454fde2ae..cfa78bb4990f7547470e9ebcfd0183ad13295e77 100644 (file)
 #include <linux/mutex.h>
 
 #define CROS_EC_DEV_NAME "cros_ec"
+#define CROS_EC_DEV_FP_NAME "cros_fp"
 #define CROS_EC_DEV_PD_NAME "cros_pd"
+#define CROS_EC_DEV_TP_NAME "cros_tp"
+#define CROS_EC_DEV_ISH_NAME "cros_ish"
 
 /*
  * The EC is unresponsive for a time after a reboot command.  Add a
@@ -120,6 +123,7 @@ struct cros_ec_command {
  * @pkt_xfer: Send packet to EC and get response.
  * @lock: One transaction at a time.
  * @mkbp_event_supported: True if this EC supports the MKBP event protocol.
+ * @host_sleep_v1: True if this EC supports the sleep v1 command.
  * @event_notifier: Interrupt event notifier for transport devices.
  * @event_data: Raw payload transferred with the MKBP event.
  * @event_size: Size in bytes of the event data.
@@ -153,6 +157,7 @@ struct cros_ec_device {
                        struct cros_ec_command *msg);
        struct mutex lock;
        bool mkbp_event_supported;
+       bool host_sleep_v1;
        struct blocking_notifier_head event_notifier;
 
        struct ec_response_get_next_event_v1 event_data;
index fc91082d4c357bad552d8eb2578d2da3f16ecef5..dcec96f0187924948e322c539589abd25fa02038 100644 (file)
@@ -840,7 +840,7 @@ enum ec_feature_code {
         * (Common Smart Battery System Interface Specification)
         */
        EC_FEATURE_SMART_BATTERY = 18,
-       /* EC can dectect when the host hangs. */
+       /* EC can detect when the host hangs. */
        EC_FEATURE_HANG_DETECT = 19,
        /* Report power information, for pit only */
        EC_FEATURE_PMU = 20,
@@ -852,10 +852,42 @@ enum ec_feature_code {
        EC_FEATURE_USB_MUX = 23,
        /* Motion Sensor code has an internal software FIFO */
        EC_FEATURE_MOTION_SENSE_FIFO = 24,
+       /* Support temporary secure vstore */
+       EC_FEATURE_VSTORE = 25,
+       /* EC decides on USB-C SS mux state, muxes configured by host */
+       EC_FEATURE_USBC_SS_MUX_VIRTUAL = 26,
        /* EC has RTC feature that can be controlled by host commands */
        EC_FEATURE_RTC = 27,
+       /* The MCU exposes a Fingerprint sensor */
+       EC_FEATURE_FINGERPRINT = 28,
+       /* The MCU exposes a Touchpad */
+       EC_FEATURE_TOUCHPAD = 29,
+       /* The MCU has RWSIG task enabled */
+       EC_FEATURE_RWSIG = 30,
+       /* EC has device events support */
+       EC_FEATURE_DEVICE_EVENT = 31,
+       /* EC supports the unified wake masks for LPC/eSPI systems */
+       EC_FEATURE_UNIFIED_WAKE_MASKS = 32,
+       /* EC supports 64-bit host events */
+       EC_FEATURE_HOST_EVENT64 = 33,
+       /* EC runs code in RAM (not in place, a.k.a. XIP) */
+       EC_FEATURE_EXEC_IN_RAM = 34,
        /* EC supports CEC commands */
        EC_FEATURE_CEC = 35,
+       /* EC supports tight sensor timestamping. */
+       EC_FEATURE_MOTION_SENSE_TIGHT_TIMESTAMPS = 36,
+       /*
+        * EC supports tablet mode detection aligned to Chrome and allows
+        * setting of threshold by host command using
+        * MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE.
+        */
+       EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS = 37,
+       /* EC supports audio codec. */
+       EC_FEATURE_AUDIO_CODEC = 38,
+       /* EC Supports SCP. */
+       EC_FEATURE_SCP = 39,
+       /* The MCU is an Integrated Sensor Hub */
+       EC_FEATURE_ISH = 40,
 };
 
 #define EC_FEATURE_MASK_0(event_code) (1UL << (event_code % 32))
@@ -2729,6 +2761,63 @@ struct ec_params_host_sleep_event {
        uint8_t sleep_event;
 } __packed;
 
+/*
+ * Use a default timeout value (CONFIG_SLEEP_TIMEOUT_MS) for detecting sleep
+ * transition failures
+ */
+#define EC_HOST_SLEEP_TIMEOUT_DEFAULT 0
+
+/* Disable timeout detection for this sleep transition */
+#define EC_HOST_SLEEP_TIMEOUT_INFINITE 0xFFFF
+
+struct ec_params_host_sleep_event_v1 {
+       /* The type of sleep being entered or exited. */
+       uint8_t sleep_event;
+
+       /* Padding */
+       uint8_t reserved;
+       union {
+               /* Parameters that apply for suspend messages. */
+               struct {
+                       /*
+                        * The timeout in milliseconds between when this message
+                        * is received and when the EC will declare sleep
+                        * transition failure if the sleep signal is not
+                        * asserted.
+                        */
+                       uint16_t sleep_timeout_ms;
+               } suspend_params;
+
+               /* No parameters for non-suspend messages. */
+       };
+} __packed;
+
+/* A timeout occurred when this bit is set */
+#define EC_HOST_RESUME_SLEEP_TIMEOUT 0x80000000
+
+/*
+ * The mask defining which bits correspond to the number of sleep transitions,
+ * as well as the maximum number of suspend line transitions that will be
+ * reported back to the host.
+ */
+#define EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK 0x7FFFFFFF
+
+struct ec_response_host_sleep_event_v1 {
+       union {
+               /* Response fields that apply for resume messages. */
+               struct {
+                       /*
+                        * The number of sleep power signal transitions that
+                        * occurred since the suspend message. The high bit
+                        * indicates a timeout occurred.
+                        */
+                       uint32_t sleep_transitions;
+               } resume_response;
+
+               /* No response fields for non-resume messages. */
+       };
+} __packed;
+
 /*****************************************************************************/
 /* Smart battery pass-through */
 
index 71b09154e2db023140c16b8ec80bfd3fe4582626..5cd06ab26352ea8c572f05cabc2c111ae1258321 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Definitions for DA9063 MFD driver
  *
@@ -5,12 +6,6 @@
  *
  * Author: Michal Hajduk, Dialog Semiconductor
  * Author: Krystian Garbaciak, Dialog Semiconductor
- *
- *  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.
- *
  */
 
 #ifndef __MFD_DA9063_CORE_H__
index 5d42859cb441102148c34c76d93b1ac9629cafff..ba706b0e28c2d13cc5a6b5c2d17245389f5c084d 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Registers definition for DA9063 modules
  *
@@ -5,12 +6,6 @@
  *
  * Author: Michal Hajduk, Dialog Semiconductor
  * Author: Krystian Garbaciak, Dialog Semiconductor
- *
- *  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.
- *
  */
 
 #ifndef _DA9063_REG_H
 
 /* DA9063 Configuration registers */
 /* OTP */
-#define        DA9063_REG_OPT_COUNT            0x101
-#define        DA9063_REG_OPT_ADDR             0x102
-#define        DA9063_REG_OPT_DATA             0x103
+#define        DA9063_REG_OTP_CONT             0x101
+#define        DA9063_REG_OTP_ADDR             0x102
+#define        DA9063_REG_OTP_DATA             0x103
 
 /* Customer Trim and Configuration */
 #define        DA9063_REG_T_OFFSET             0x104
index ad2a9a852aead143a69e7ada265e5b7832f3727f..82407fe85ca26144514a12327bcd695f0404ddd5 100644 (file)
 #define MAX77620_FPS_PERIOD_MIN_US             40
 #define MAX20024_FPS_PERIOD_MIN_US             20
 
-#define MAX77620_FPS_PERIOD_MAX_US             2560
-#define MAX20024_FPS_PERIOD_MAX_US             5120
+#define MAX20024_FPS_PERIOD_MAX_US             2560
+#define MAX77620_FPS_PERIOD_MAX_US             5120
 
 #define MAX77620_REG_FPS_GPIO1                 0x54
 #define MAX77620_REG_FPS_GPIO2                 0x55
@@ -324,6 +324,7 @@ enum max77620_fps_src {
 enum max77620_chip_id {
        MAX77620,
        MAX20024,
+       MAX77663,
 };
 
 struct max77620_chip {
diff --git a/include/linux/mfd/max77650.h b/include/linux/mfd/max77650.h
new file mode 100644 (file)
index 0000000..c809e21
--- /dev/null
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 BayLibre SAS
+ * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+ *
+ * Common definitions for MAXIM 77650/77651 charger/power-supply.
+ */
+
+#ifndef MAX77650_H
+#define MAX77650_H
+
+#include <linux/bits.h>
+
+#define MAX77650_REG_INT_GLBL          0x00
+#define MAX77650_REG_INT_CHG           0x01
+#define MAX77650_REG_STAT_CHG_A                0x02
+#define MAX77650_REG_STAT_CHG_B                0x03
+#define MAX77650_REG_ERCFLAG           0x04
+#define MAX77650_REG_STAT_GLBL         0x05
+#define MAX77650_REG_INTM_GLBL         0x06
+#define MAX77650_REG_INTM_CHG          0x07
+#define MAX77650_REG_CNFG_GLBL         0x10
+#define MAX77650_REG_CID               0x11
+#define MAX77650_REG_CNFG_GPIO         0x12
+#define MAX77650_REG_CNFG_CHG_A                0x18
+#define MAX77650_REG_CNFG_CHG_B                0x19
+#define MAX77650_REG_CNFG_CHG_C                0x1a
+#define MAX77650_REG_CNFG_CHG_D                0x1b
+#define MAX77650_REG_CNFG_CHG_E                0x1c
+#define MAX77650_REG_CNFG_CHG_F                0x1d
+#define MAX77650_REG_CNFG_CHG_G                0x1e
+#define MAX77650_REG_CNFG_CHG_H                0x1f
+#define MAX77650_REG_CNFG_CHG_I                0x20
+#define MAX77650_REG_CNFG_SBB_TOP      0x28
+#define MAX77650_REG_CNFG_SBB0_A       0x29
+#define MAX77650_REG_CNFG_SBB0_B       0x2a
+#define MAX77650_REG_CNFG_SBB1_A       0x2b
+#define MAX77650_REG_CNFG_SBB1_B       0x2c
+#define MAX77650_REG_CNFG_SBB2_A       0x2d
+#define MAX77650_REG_CNFG_SBB2_B       0x2e
+#define MAX77650_REG_CNFG_LDO_A                0x38
+#define MAX77650_REG_CNFG_LDO_B                0x39
+#define MAX77650_REG_CNFG_LED0_A       0x40
+#define MAX77650_REG_CNFG_LED1_A       0x41
+#define MAX77650_REG_CNFG_LED2_A       0x42
+#define MAX77650_REG_CNFG_LED0_B       0x43
+#define MAX77650_REG_CNFG_LED1_B       0x44
+#define MAX77650_REG_CNFG_LED2_B       0x45
+#define MAX77650_REG_CNFG_LED_TOP      0x46
+
+#define MAX77650_CID_MASK              GENMASK(3, 0)
+#define MAX77650_CID_BITS(_reg)                (_reg & MAX77650_CID_MASK)
+
+#define MAX77650_CID_77650A            0x03
+#define MAX77650_CID_77650C            0x0a
+#define MAX77650_CID_77651A            0x06
+#define MAX77650_CID_77651B            0x08
+
+#endif /* MAX77650_H */
diff --git a/include/linux/mfd/stmfx.h b/include/linux/mfd/stmfx.h
new file mode 100644 (file)
index 0000000..d890595
--- /dev/null
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 STMicroelectronics
+ * Author(s): Amelie Delaunay <amelie.delaunay@st.com>.
+ */
+
+#ifndef MFD_STMFX_H
+#define MFX_STMFX_H
+
+#include <linux/regmap.h>
+
+/* General */
+#define STMFX_REG_CHIP_ID              0x00 /* R */
+#define STMFX_REG_FW_VERSION_MSB       0x01 /* R */
+#define STMFX_REG_FW_VERSION_LSB       0x02 /* R */
+#define STMFX_REG_SYS_CTRL             0x40 /* RW */
+/* IRQ output management */
+#define STMFX_REG_IRQ_OUT_PIN          0x41 /* RW */
+#define STMFX_REG_IRQ_SRC_EN           0x42 /* RW */
+#define STMFX_REG_IRQ_PENDING          0x08 /* R */
+#define STMFX_REG_IRQ_ACK              0x44 /* RW */
+/* GPIO management */
+#define STMFX_REG_IRQ_GPI_PENDING1     0x0C /* R */
+#define STMFX_REG_IRQ_GPI_PENDING2     0x0D /* R */
+#define STMFX_REG_IRQ_GPI_PENDING3     0x0E /* R */
+#define STMFX_REG_GPIO_STATE1          0x10 /* R */
+#define STMFX_REG_GPIO_STATE2          0x11 /* R */
+#define STMFX_REG_GPIO_STATE3          0x12 /* R */
+#define STMFX_REG_IRQ_GPI_SRC1         0x48 /* RW */
+#define STMFX_REG_IRQ_GPI_SRC2         0x49 /* RW */
+#define STMFX_REG_IRQ_GPI_SRC3         0x4A /* RW */
+#define STMFX_REG_IRQ_GPI_EVT1         0x4C /* RW */
+#define STMFX_REG_IRQ_GPI_EVT2         0x4D /* RW */
+#define STMFX_REG_IRQ_GPI_EVT3         0x4E /* RW */
+#define STMFX_REG_IRQ_GPI_TYPE1                0x50 /* RW */
+#define STMFX_REG_IRQ_GPI_TYPE2                0x51 /* RW */
+#define STMFX_REG_IRQ_GPI_TYPE3                0x52 /* RW */
+#define STMFX_REG_IRQ_GPI_ACK1         0x54 /* RW */
+#define STMFX_REG_IRQ_GPI_ACK2         0x55 /* RW */
+#define STMFX_REG_IRQ_GPI_ACK3         0x56 /* RW */
+#define STMFX_REG_GPIO_DIR1            0x60 /* RW */
+#define STMFX_REG_GPIO_DIR2            0x61 /* RW */
+#define STMFX_REG_GPIO_DIR3            0x62 /* RW */
+#define STMFX_REG_GPIO_TYPE1           0x64 /* RW */
+#define STMFX_REG_GPIO_TYPE2           0x65 /* RW */
+#define STMFX_REG_GPIO_TYPE3           0x66 /* RW */
+#define STMFX_REG_GPIO_PUPD1           0x68 /* RW */
+#define STMFX_REG_GPIO_PUPD2           0x69 /* RW */
+#define STMFX_REG_GPIO_PUPD3           0x6A /* RW */
+#define STMFX_REG_GPO_SET1             0x6C /* RW */
+#define STMFX_REG_GPO_SET2             0x6D /* RW */
+#define STMFX_REG_GPO_SET3             0x6E /* RW */
+#define STMFX_REG_GPO_CLR1             0x70 /* RW */
+#define STMFX_REG_GPO_CLR2             0x71 /* RW */
+#define STMFX_REG_GPO_CLR3             0x72 /* RW */
+
+#define STMFX_REG_MAX                  0xB0
+
+/* MFX boot time is around 10ms, so after reset, we have to wait this delay */
+#define STMFX_BOOT_TIME_MS 10
+
+/* STMFX_REG_CHIP_ID bitfields */
+#define STMFX_REG_CHIP_ID_MASK         GENMASK(7, 0)
+
+/* STMFX_REG_SYS_CTRL bitfields */
+#define STMFX_REG_SYS_CTRL_GPIO_EN     BIT(0)
+#define STMFX_REG_SYS_CTRL_TS_EN       BIT(1)
+#define STMFX_REG_SYS_CTRL_IDD_EN      BIT(2)
+#define STMFX_REG_SYS_CTRL_ALTGPIO_EN  BIT(3)
+#define STMFX_REG_SYS_CTRL_SWRST       BIT(7)
+
+/* STMFX_REG_IRQ_OUT_PIN bitfields */
+#define STMFX_REG_IRQ_OUT_PIN_TYPE     BIT(0) /* 0-OD 1-PP */
+#define STMFX_REG_IRQ_OUT_PIN_POL      BIT(1) /* 0-active LOW 1-active HIGH */
+
+/* STMFX_REG_IRQ_(SRC_EN/PENDING/ACK) bit shift */
+enum stmfx_irqs {
+       STMFX_REG_IRQ_SRC_EN_GPIO = 0,
+       STMFX_REG_IRQ_SRC_EN_IDD,
+       STMFX_REG_IRQ_SRC_EN_ERROR,
+       STMFX_REG_IRQ_SRC_EN_TS_DET,
+       STMFX_REG_IRQ_SRC_EN_TS_NE,
+       STMFX_REG_IRQ_SRC_EN_TS_TH,
+       STMFX_REG_IRQ_SRC_EN_TS_FULL,
+       STMFX_REG_IRQ_SRC_EN_TS_OVF,
+       STMFX_REG_IRQ_SRC_MAX,
+};
+
+enum stmfx_functions {
+       STMFX_FUNC_GPIO         = BIT(0), /* GPIO[15:0] */
+       STMFX_FUNC_ALTGPIO_LOW  = BIT(1), /* aGPIO[3:0] */
+       STMFX_FUNC_ALTGPIO_HIGH = BIT(2), /* aGPIO[7:4] */
+       STMFX_FUNC_TS           = BIT(3),
+       STMFX_FUNC_IDD          = BIT(4),
+};
+
+/**
+ * struct stmfx_ddata - STMFX MFD structure
+ * @device:            device reference used for logs
+ * @map:               register map
+ * @vdd:               STMFX power supply
+ * @irq_domain:                IRQ domain
+ * @lock:              IRQ bus lock
+ * @irq_src:           cache of IRQ_SRC_EN register for bus_lock
+ * @bkp_sysctrl:       backup of SYS_CTRL register for suspend/resume
+ * @bkp_irqoutpin:     backup of IRQ_OUT_PIN register for suspend/resume
+ */
+struct stmfx {
+       struct device *dev;
+       struct regmap *map;
+       struct regulator *vdd;
+       struct irq_domain *irq_domain;
+       struct mutex lock; /* IRQ bus lock */
+       u8 irq_src;
+#ifdef CONFIG_PM
+       u8 bkp_sysctrl;
+       u8 bkp_irqoutpin;
+#endif
+};
+
+int stmfx_function_enable(struct stmfx *stmfx, u32 func);
+int stmfx_function_disable(struct stmfx *stmfx, u32 func);
+#endif
index 8293c3e2a82a385ff95054a9f259d87dc78b0eb6..f61cd127a85274b0874257e1003db1d52742ad60 100644 (file)
@@ -1,12 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  *  Copyright (C) 2014 Atmel Corporation.
  *
  * Memory Controllers (MATRIX, EBI) - System peripherals registers.
- *
- * 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.
  */
 
 #ifndef _LINUX_MFD_SYSCON_ATMEL_MATRIX_H
index afd9b8f1e36351773736a0ee71a8e7686861d76b..99c56205c410907eb84ed3e9fd31d4472c97be0f 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Copyright (C) 2005 Ivan Kokshaysky
  * Copyright (C) SAN People
@@ -5,11 +6,6 @@
  * Memory Controllers (MC, EBI, SMC, SDRAMC, BFC) - System peripherals
  * registers.
  * Based on AT91RM9200 datasheet revision E.
- *
- * 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.
  */
 
 #ifndef _LINUX_MFD_SYSCON_ATMEL_MC_H_
index 7a367f34b66ae6995e84d54b3b13a1b28cb22788..e9e24f4c457898f5ba3b9b2be512293ed32deae9 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Atmel SMC (Static Memory Controller) register offsets and bit definitions.
  *
@@ -5,10 +6,6 @@
  * Copyright (C) 2014 Free Electrons
  *
  * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef _LINUX_MFD_SYSCON_ATMEL_SMC_H_
index 8acf1ec1fa3273aa079f0e3d7fe6440df663b02f..5b6013d0c440ac509d9901fafe3ea1ea6b6e87df 100644 (file)
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Copyright (C) 2005 Ivan Kokshaysky
  * Copyright (C) SAN People
  *
  * System Timer (ST) - System peripherals registers.
  * Based on AT91RM9200 datasheet revision E.
- *
- * 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.
  */
 
 #ifndef _LINUX_MFD_SYSCON_ATMEL_ST_H
index c1b25f5e386d55e12545d1d958dc119cba7eb2dc..f232c8130d00e47bd9907edb31a866beafae04c4 100644 (file)
 #define IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK             (0x3 << 17)
 #define IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_EXT              (0x3 << 13)
 
+#define IMX6SX_GPR2_MQS_OVERSAMPLE_MASK                        (0x1 << 26)
+#define IMX6SX_GPR2_MQS_OVERSAMPLE_SHIFT               (26)
+#define IMX6SX_GPR2_MQS_EN_MASK                                (0x1 << 25)
+#define IMX6SX_GPR2_MQS_EN_SHIFT                       (25)
+#define IMX6SX_GPR2_MQS_SW_RST_MASK                    (0x1 << 24)
+#define IMX6SX_GPR2_MQS_SW_RST_SHIFT                   (24)
+#define IMX6SX_GPR2_MQS_CLK_DIV_MASK                   (0xFF << 16)
+#define IMX6SX_GPR2_MQS_CLK_DIV_SHIFT                  (16)
+
 #define IMX6SX_GPR4_FEC_ENET1_STOP_REQ                 (0x1 << 3)
 #define IMX6SX_GPR4_FEC_ENET2_STOP_REQ                 (0x1 << 4)
 
index 82612741b29e27000592c7816c214320eb556cdc..5e74305e2e577be66331046e5ae1a4010b1f5568 100644 (file)
@@ -7344,7 +7344,7 @@ struct mlx5_ifc_create_eq_out_bits {
 
 struct mlx5_ifc_create_eq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_at_10[0x10];
+       u8         uid[0x10];
 
        u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
index 083d7b4863edaba800d7d11d4fbf779acf4f11e4..0e8834ac32b76c74c965abec1a84b54a55e9e8f5 100644 (file)
@@ -124,10 +124,45 @@ extern int mmap_rnd_compat_bits __read_mostly;
 
 /*
  * On some architectures it is expensive to call memset() for small sizes.
- * Those architectures should provide their own implementation of "struct page"
- * zeroing by defining this macro in <asm/pgtable.h>.
+ * If an architecture decides to implement their own version of
+ * mm_zero_struct_page they should wrap the defines below in a #ifndef and
+ * define their own version of this macro in <asm/pgtable.h>
  */
-#ifndef mm_zero_struct_page
+#if BITS_PER_LONG == 64
+/* This function must be updated when the size of struct page grows above 80
+ * or reduces below 56. The idea that compiler optimizes out switch()
+ * statement, and only leaves move/store instructions. Also the compiler can
+ * combine write statments if they are both assignments and can be reordered,
+ * this can result in several of the writes here being dropped.
+ */
+#define        mm_zero_struct_page(pp) __mm_zero_struct_page(pp)
+static inline void __mm_zero_struct_page(struct page *page)
+{
+       unsigned long *_pp = (void *)page;
+
+        /* Check that struct page is either 56, 64, 72, or 80 bytes */
+       BUILD_BUG_ON(sizeof(struct page) & 7);
+       BUILD_BUG_ON(sizeof(struct page) < 56);
+       BUILD_BUG_ON(sizeof(struct page) > 80);
+
+       switch (sizeof(struct page)) {
+       case 80:
+               _pp[9] = 0;     /* fallthrough */
+       case 72:
+               _pp[8] = 0;     /* fallthrough */
+       case 64:
+               _pp[7] = 0;     /* fallthrough */
+       case 56:
+               _pp[6] = 0;
+               _pp[5] = 0;
+               _pp[4] = 0;
+               _pp[3] = 0;
+               _pp[2] = 0;
+               _pp[1] = 0;
+               _pp[0] = 0;
+       }
+}
+#else
 #define mm_zero_struct_page(pp)  ((void)memset((pp), 0, sizeof(struct page)))
 #endif
 
@@ -501,9 +536,6 @@ static inline void vma_set_anonymous(struct vm_area_struct *vma)
 struct mmu_gather;
 struct inode;
 
-#define page_private(page)             ((page)->private)
-#define set_page_private(page, v)      ((page)->private = (v))
-
 #if !defined(__HAVE_ARCH_PTE_DEVMAP) || !defined(CONFIG_TRANSPARENT_HUGEPAGE)
 static inline int pmd_devmap(pmd_t pmd)
 {
@@ -1007,6 +1039,30 @@ static inline void put_page(struct page *page)
                __put_page(page);
 }
 
+/**
+ * put_user_page() - release a gup-pinned page
+ * @page:            pointer to page to be released
+ *
+ * Pages that were pinned via get_user_pages*() must be released via
+ * either put_user_page(), or one of the put_user_pages*() routines
+ * below. This is so that eventually, pages that are pinned via
+ * get_user_pages*() can be separately tracked and uniquely handled. In
+ * particular, interactions with RDMA and filesystems need special
+ * handling.
+ *
+ * put_user_page() and put_page() are not interchangeable, despite this early
+ * implementation that makes them look the same. put_user_page() calls must
+ * be perfectly matched up with get_user_page() calls.
+ */
+static inline void put_user_page(struct page *page)
+{
+       put_page(page);
+}
+
+void put_user_pages_dirty(struct page **pages, unsigned long npages);
+void put_user_pages_dirty_lock(struct page **pages, unsigned long npages);
+void put_user_pages(struct page **pages, unsigned long npages);
+
 #if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
 #define SECTION_IN_PAGE_FLAGS
 #endif
@@ -1505,21 +1561,8 @@ long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
 long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
                    struct page **pages, unsigned int gup_flags);
 
-#if defined(CONFIG_FS_DAX) || defined(CONFIG_CMA)
-long get_user_pages_longterm(unsigned long start, unsigned long nr_pages,
-                           unsigned int gup_flags, struct page **pages,
-                           struct vm_area_struct **vmas);
-#else
-static inline long get_user_pages_longterm(unsigned long start,
-               unsigned long nr_pages, unsigned int gup_flags,
-               struct page **pages, struct vm_area_struct **vmas)
-{
-       return get_user_pages(start, nr_pages, gup_flags, pages, vmas);
-}
-#endif /* CONFIG_FS_DAX */
-
-int get_user_pages_fast(unsigned long start, int nr_pages, int write,
-                       struct page **pages);
+int get_user_pages_fast(unsigned long start, int nr_pages,
+                       unsigned int gup_flags, struct page **pages);
 
 /* Container for pinned pfns / pages */
 struct frame_vector {
@@ -2533,6 +2576,10 @@ struct vm_area_struct *find_extend_vma(struct mm_struct *, unsigned long addr);
 int remap_pfn_range(struct vm_area_struct *, unsigned long addr,
                        unsigned long pfn, unsigned long size, pgprot_t);
 int vm_insert_page(struct vm_area_struct *, unsigned long addr, struct page *);
+int vm_map_pages(struct vm_area_struct *vma, struct page **pages,
+                               unsigned long num);
+int vm_map_pages_zero(struct vm_area_struct *vma, struct page **pages,
+                               unsigned long num);
 vm_fault_t vmf_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
                        unsigned long pfn);
 vm_fault_t vmf_insert_pfn_prot(struct vm_area_struct *vma, unsigned long addr,
@@ -2583,6 +2630,34 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
 #define FOLL_REMOTE    0x2000  /* we are working on non-current tsk/mm */
 #define FOLL_COW       0x4000  /* internal GUP flag */
 #define FOLL_ANON      0x8000  /* don't do file mappings */
+#define FOLL_LONGTERM  0x10000 /* mapping lifetime is indefinite: see below */
+
+/*
+ * NOTE on FOLL_LONGTERM:
+ *
+ * FOLL_LONGTERM indicates that the page will be held for an indefinite time
+ * period _often_ under userspace control.  This is contrasted with
+ * iov_iter_get_pages() where usages which are transient.
+ *
+ * FIXME: For pages which are part of a filesystem, mappings are subject to the
+ * lifetime enforced by the filesystem and we need guarantees that longterm
+ * users like RDMA and V4L2 only establish mappings which coordinate usage with
+ * the filesystem.  Ideas for this coordination include revoking the longterm
+ * pin, delaying writeback, bounce buffer page writeback, etc.  As FS DAX was
+ * added after the problem with filesystems was found FS DAX VMAs are
+ * specifically failed.  Filesystem pages are still subject to bugs and use of
+ * FOLL_LONGTERM should be avoided on those pages.
+ *
+ * FIXME: Also NOTE that FOLL_LONGTERM is not supported in every GUP call.
+ * Currently only get_user_pages() and get_user_pages_fast() support this flag
+ * and calls to get_user_pages_[un]locked are specifically not allowed.  This
+ * is due to an incompatibility with the FS DAX check and
+ * FAULT_FLAG_ALLOW_RETRY
+ *
+ * In the CMA case: longterm pins in a CMA region would unnecessarily fragment
+ * that region.  And so CMA attempts to migrate the page before pinning when
+ * FOLL_LONGTERM is specified.
+ */
 
 static inline int vm_fault_to_errno(vm_fault_t vm_fault, int foll_flags)
 {
index 04ec454d44cefd0dbd2ffb1b82842b220a14d2cf..6f2fef7b0784e0eae3cfb9220d289535e331ec45 100644 (file)
@@ -29,7 +29,7 @@ static __always_inline void __update_lru_size(struct lruvec *lruvec,
 {
        struct pglist_data *pgdat = lruvec_pgdat(lruvec);
 
-       __mod_node_page_state(pgdat, NR_LRU_BASE + lru, nr_pages);
+       __mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages);
        __mod_zone_page_state(&pgdat->node_zones[zid],
                                NR_ZONE_LRU_BASE + lru, nr_pages);
 }
index 4ef4bbe78a1da163fee585597b57ff215c819be6..8ec38b11b361e5e3d56d3725893093db8e6ae309 100644 (file)
@@ -103,7 +103,7 @@ struct page {
                };
                struct {        /* slab, slob and slub */
                        union {
-                               struct list_head slab_list;     /* uses lru */
+                               struct list_head slab_list;
                                struct {        /* Partial pages */
                                        struct page *next;
 #ifdef CONFIG_64BIT
@@ -220,6 +220,9 @@ struct page {
 #define PAGE_FRAG_CACHE_MAX_SIZE       __ALIGN_MASK(32768, ~PAGE_MASK)
 #define PAGE_FRAG_CACHE_MAX_ORDER      get_order(PAGE_FRAG_CACHE_MAX_SIZE)
 
+#define page_private(page)             ((page)->private)
+#define set_page_private(page, v)      ((page)->private = (v))
+
 struct page_frag_cache {
        void * va;
 #if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
index 4050ec1c3b45efcd7ede562256f5df50819cd792..b6c004bd9f6ad977ffdcb60ffc662a2916f94766 100644 (file)
 struct mmu_notifier;
 struct mmu_notifier_ops;
 
+/**
+ * enum mmu_notifier_event - reason for the mmu notifier callback
+ * @MMU_NOTIFY_UNMAP: either munmap() that unmap the range or a mremap() that
+ * move the range
+ *
+ * @MMU_NOTIFY_CLEAR: clear page table entry (many reasons for this like
+ * madvise() or replacing a page by another one, ...).
+ *
+ * @MMU_NOTIFY_PROTECTION_VMA: update is due to protection change for the range
+ * ie using the vma access permission (vm_page_prot) to update the whole range
+ * is enough no need to inspect changes to the CPU page table (mprotect()
+ * syscall)
+ *
+ * @MMU_NOTIFY_PROTECTION_PAGE: update is due to change in read/write flag for
+ * pages in the range so to mirror those changes the user must inspect the CPU
+ * page table (from the end callback).
+ *
+ * @MMU_NOTIFY_SOFT_DIRTY: soft dirty accounting (still same page and same
+ * access flags). User should soft dirty the page in the end callback to make
+ * sure that anyone relying on soft dirtyness catch pages that might be written
+ * through non CPU mappings.
+ */
+enum mmu_notifier_event {
+       MMU_NOTIFY_UNMAP = 0,
+       MMU_NOTIFY_CLEAR,
+       MMU_NOTIFY_PROTECTION_VMA,
+       MMU_NOTIFY_PROTECTION_PAGE,
+       MMU_NOTIFY_SOFT_DIRTY,
+};
+
 #ifdef CONFIG_MMU_NOTIFIER
 
 /*
@@ -25,11 +55,15 @@ struct mmu_notifier_mm {
        spinlock_t lock;
 };
 
+#define MMU_NOTIFIER_RANGE_BLOCKABLE (1 << 0)
+
 struct mmu_notifier_range {
+       struct vm_area_struct *vma;
        struct mm_struct *mm;
        unsigned long start;
        unsigned long end;
-       bool blockable;
+       unsigned flags;
+       enum mmu_notifier_event event;
 };
 
 struct mmu_notifier_ops {
@@ -225,6 +259,14 @@ extern void __mmu_notifier_invalidate_range_end(struct mmu_notifier_range *r,
                                  bool only_end);
 extern void __mmu_notifier_invalidate_range(struct mm_struct *mm,
                                  unsigned long start, unsigned long end);
+extern bool
+mmu_notifier_range_update_to_read_only(const struct mmu_notifier_range *range);
+
+static inline bool
+mmu_notifier_range_blockable(const struct mmu_notifier_range *range)
+{
+       return (range->flags & MMU_NOTIFIER_RANGE_BLOCKABLE);
+}
 
 static inline void mmu_notifier_release(struct mm_struct *mm)
 {
@@ -269,7 +311,7 @@ static inline void
 mmu_notifier_invalidate_range_start(struct mmu_notifier_range *range)
 {
        if (mm_has_notifiers(range->mm)) {
-               range->blockable = true;
+               range->flags |= MMU_NOTIFIER_RANGE_BLOCKABLE;
                __mmu_notifier_invalidate_range_start(range);
        }
 }
@@ -278,7 +320,7 @@ static inline int
 mmu_notifier_invalidate_range_start_nonblock(struct mmu_notifier_range *range)
 {
        if (mm_has_notifiers(range->mm)) {
-               range->blockable = false;
+               range->flags &= ~MMU_NOTIFIER_RANGE_BLOCKABLE;
                return __mmu_notifier_invalidate_range_start(range);
        }
        return 0;
@@ -318,13 +360,19 @@ static inline void mmu_notifier_mm_destroy(struct mm_struct *mm)
 
 
 static inline void mmu_notifier_range_init(struct mmu_notifier_range *range,
+                                          enum mmu_notifier_event event,
+                                          unsigned flags,
+                                          struct vm_area_struct *vma,
                                           struct mm_struct *mm,
                                           unsigned long start,
                                           unsigned long end)
 {
+       range->vma = vma;
+       range->event = event;
        range->mm = mm;
        range->start = start;
        range->end = end;
+       range->flags = flags;
 }
 
 #define ptep_clear_flush_young_notify(__vma, __address, __ptep)                \
@@ -452,9 +500,14 @@ static inline void _mmu_notifier_range_init(struct mmu_notifier_range *range,
        range->end = end;
 }
 
-#define mmu_notifier_range_init(range, mm, start, end) \
+#define mmu_notifier_range_init(range,event,flags,vma,mm,start,end)  \
        _mmu_notifier_range_init(range, start, end)
 
+static inline bool
+mmu_notifier_range_blockable(const struct mmu_notifier_range *range)
+{
+       return true;
+}
 
 static inline int mm_has_notifiers(struct mm_struct *mm)
 {
@@ -517,6 +570,8 @@ static inline void mmu_notifier_mm_destroy(struct mm_struct *mm)
 {
 }
 
+#define mmu_notifier_range_update_to_read_only(r) false
+
 #define ptep_clear_flush_young_notify ptep_clear_flush_young
 #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
 #define ptep_clear_young_notify ptep_test_and_clear_young
index fba7741533bec2535ef9552ed9bf07e25ff984f8..70394cabaf4e0fe6efc3c18701796bb04c71168b 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/pageblock-flags.h>
 #include <linux/page-flags-layout.h>
 #include <linux/atomic.h>
+#include <linux/mm_types.h>
+#include <linux/page-flags.h>
 #include <asm/page.h>
 
 /* Free memory management - zoned buddy allocator.  */
@@ -98,6 +100,62 @@ struct free_area {
        unsigned long           nr_free;
 };
 
+/* Used for pages not on another list */
+static inline void add_to_free_area(struct page *page, struct free_area *area,
+                            int migratetype)
+{
+       list_add(&page->lru, &area->free_list[migratetype]);
+       area->nr_free++;
+}
+
+/* Used for pages not on another list */
+static inline void add_to_free_area_tail(struct page *page, struct free_area *area,
+                                 int migratetype)
+{
+       list_add_tail(&page->lru, &area->free_list[migratetype]);
+       area->nr_free++;
+}
+
+#ifdef CONFIG_SHUFFLE_PAGE_ALLOCATOR
+/* Used to preserve page allocation order entropy */
+void add_to_free_area_random(struct page *page, struct free_area *area,
+               int migratetype);
+#else
+static inline void add_to_free_area_random(struct page *page,
+               struct free_area *area, int migratetype)
+{
+       add_to_free_area(page, area, migratetype);
+}
+#endif
+
+/* Used for pages which are on another list */
+static inline void move_to_free_area(struct page *page, struct free_area *area,
+                            int migratetype)
+{
+       list_move(&page->lru, &area->free_list[migratetype]);
+}
+
+static inline struct page *get_page_from_free_area(struct free_area *area,
+                                           int migratetype)
+{
+       return list_first_entry_or_null(&area->free_list[migratetype],
+                                       struct page, lru);
+}
+
+static inline void del_page_from_free_area(struct page *page,
+               struct free_area *area)
+{
+       list_del(&page->lru);
+       __ClearPageBuddy(page);
+       set_page_private(page, 0);
+       area->nr_free--;
+}
+
+static inline bool free_area_empty(struct free_area *area, int migratetype)
+{
+       return list_empty(&area->free_list[migratetype]);
+}
+
 struct pglist_data;
 
 /*
@@ -247,11 +305,6 @@ struct lruvec {
 #endif
 };
 
-/* Mask used at gathering information at once (see memcontrol.c) */
-#define LRU_ALL_FILE (BIT(LRU_INACTIVE_FILE) | BIT(LRU_ACTIVE_FILE))
-#define LRU_ALL_ANON (BIT(LRU_INACTIVE_ANON) | BIT(LRU_ACTIVE_ANON))
-#define LRU_ALL             ((1 << NR_LRU_LISTS) - 1)
-
 /* Isolate unmapped file */
 #define ISOLATE_UNMAPPED       ((__force isolate_mode_t)0x2)
 /* Isolate for asynchronous migration */
@@ -1276,6 +1329,7 @@ void sparse_init(void);
 #else
 #define sparse_init()  do {} while (0)
 #define sparse_index_init(_sec, _nid)  do {} while (0)
+#define pfn_present pfn_valid
 #endif /* CONFIG_SPARSEMEM */
 
 /*
index 8f75277d4cef2003236eb2072bf13ad26e3e2c97..188998d3dca94162aedd5cbfdf18708fa016c1e4 100644 (file)
@@ -332,6 +332,7 @@ struct mod_kallsyms {
        Elf_Sym *symtab;
        unsigned int num_symtab;
        char *strtab;
+       char *typetab;
 };
 
 #ifdef CONFIG_LIVEPATCH
@@ -717,6 +718,17 @@ static inline bool within_module_core(unsigned long addr,
        return false;
 }
 
+static inline bool within_module_init(unsigned long addr,
+                                     const struct module *mod)
+{
+       return false;
+}
+
+static inline bool within_module(unsigned long addr, const struct module *mod)
+{
+       return false;
+}
+
 /* Get/put a kernel symbol (calls should be symmetric) */
 #define symbol_get(x) ({ extern typeof(x) x __attribute__((weak)); &(x); })
 #define symbol_put(x) do { } while (0)
index 7e9b81c3b50d923f9a4c41d24215e3f0683ad425..052f04fcf95323046206f40e87da2081dd182a49 100644 (file)
@@ -148,24 +148,6 @@ u32 __pci_msi_desc_mask_irq(struct msi_desc *desc, u32 mask, u32 flag);
 void pci_msi_mask_irq(struct irq_data *data);
 void pci_msi_unmask_irq(struct irq_data *data);
 
-/* Conversion helpers. Should be removed after merging */
-static inline void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
-{
-       __pci_write_msi_msg(entry, msg);
-}
-static inline void write_msi_msg(int irq, struct msi_msg *msg)
-{
-       pci_write_msi_msg(irq, msg);
-}
-static inline void mask_msi_irq(struct irq_data *data)
-{
-       pci_msi_mask_irq(data);
-}
-static inline void unmask_msi_irq(struct irq_data *data)
-{
-       pci_msi_unmask_irq(data);
-}
-
 /*
  * The arch hooks to setup up msi irqs. Those functions are
  * implemented as weak symbols so that they /can/ be overriden by
index 3102bd754d1882809ce7b74fc6ba7e09bfa7d0c9..010bc5544c54b2da3217ce6fedcb8aecb60d1363 100644 (file)
@@ -93,10 +93,7 @@ struct nand_bbt_descr {
 #define NAND_BBT_WRITE         0x00002000
 /* Read and write back block contents when writing bbt */
 #define NAND_BBT_SAVECONTENT   0x00004000
-/* Search good / bad pattern on the first and the second page */
-#define NAND_BBT_SCAN2NDPAGE   0x00008000
-/* Search good / bad pattern on the last page of the eraseblock */
-#define NAND_BBT_SCANLASTPAGE  0x00010000
+
 /*
  * Use a flash based bad block table. By default, OOB identifier is saved in
  * OOB area. This option is passed to the default bad block table function.
@@ -123,13 +120,6 @@ struct nand_bbt_descr {
 /* The maximum number of blocks to scan for a bbt */
 #define NAND_BBT_SCAN_MAXBLOCKS        4
 
-/*
- * Constants for oob configuration
- */
-#define NAND_SMALL_BADBLOCK_POS                5
-#define NAND_LARGE_BADBLOCK_POS                0
-#define ONENAND_BADBLOCK_POS           0
-
 /*
  * Bad block scanning errors
  */
@@ -140,7 +130,6 @@ struct nand_bbt_descr {
 /**
  * struct bbm_info - [GENERIC] Bad Block Table data structure
  * @bbt_erase_shift:   [INTERN] number of address bits in a bbt entry
- * @badblockpos:       [INTERN] position of the bad block marker in the oob area
  * @options:           options for this descriptor
  * @bbt:               [INTERN] bad block table pointer
  * @isbad_bbt:         function to determine if a block is bad
@@ -150,7 +139,6 @@ struct nand_bbt_descr {
  */
 struct bbm_info {
        int bbt_erase_shift;
-       int badblockpos;
        int options;
 
        uint8_t *bbt;
index 7f53ece2c039aeb849ca929b2b13cb29bd172292..cebc38b6d6f582aa723728ff37fb53a8c2ce73e1 100644 (file)
@@ -19,6 +19,7 @@
  * @oobsize: OOB area size
  * @pages_per_eraseblock: number of pages per eraseblock
  * @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number)
+ * @max_bad_eraseblocks_per_lun: maximum number of eraseblocks per LUN
  * @planes_per_lun: number of planes per LUN
  * @luns_per_target: number of LUN per target (target is a synonym for die)
  * @ntargets: total number of targets exposed by the NAND device
@@ -29,18 +30,20 @@ struct nand_memory_organization {
        unsigned int oobsize;
        unsigned int pages_per_eraseblock;
        unsigned int eraseblocks_per_lun;
+       unsigned int max_bad_eraseblocks_per_lun;
        unsigned int planes_per_lun;
        unsigned int luns_per_target;
        unsigned int ntargets;
 };
 
-#define NAND_MEMORG(bpc, ps, os, ppe, epl, ppl, lpt, nt)       \
+#define NAND_MEMORG(bpc, ps, os, ppe, epl, mbb, ppl, lpt, nt)  \
        {                                                       \
                .bits_per_cell = (bpc),                         \
                .pagesize = (ps),                               \
                .oobsize = (os),                                \
                .pages_per_eraseblock = (ppe),                  \
                .eraseblocks_per_lun = (epl),                   \
+               .max_bad_eraseblocks_per_lun = (mbb),           \
                .planes_per_lun = (ppl),                        \
                .luns_per_target = (lpt),                       \
                .ntargets = (nt),                               \
@@ -268,6 +271,20 @@ nanddev_pages_per_eraseblock(const struct nand_device *nand)
        return nand->memorg.pages_per_eraseblock;
 }
 
+/**
+ * nanddev_pages_per_target() - Get the number of pages per target
+ * @nand: NAND device
+ *
+ * Return: the number of pages per target.
+ */
+static inline unsigned int
+nanddev_pages_per_target(const struct nand_device *nand)
+{
+       return nand->memorg.pages_per_eraseblock *
+              nand->memorg.eraseblocks_per_lun *
+              nand->memorg.luns_per_target;
+}
+
 /**
  * nanddev_per_page_oobsize() - Get NAND erase block size
  * @nand: NAND device
@@ -291,6 +308,18 @@ nanddev_eraseblocks_per_lun(const struct nand_device *nand)
        return nand->memorg.eraseblocks_per_lun;
 }
 
+/**
+ * nanddev_eraseblocks_per_target() - Get the number of eraseblocks per target
+ * @nand: NAND device
+ *
+ * Return: the number of eraseblocks per target.
+ */
+static inline unsigned int
+nanddev_eraseblocks_per_target(const struct nand_device *nand)
+{
+       return nand->memorg.eraseblocks_per_lun * nand->memorg.luns_per_target;
+}
+
 /**
  * nanddev_target_size() - Get the total size provided by a single target/die
  * @nand: NAND device
@@ -729,5 +758,6 @@ static inline bool nanddev_bbt_is_initialized(struct nand_device *nand)
 
 /* MTD -> NAND helper functions. */
 int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo);
+int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len);
 
 #endif /* __LINUX_MTD_NAND_H */
index b8106651f80799cfdb7236018d82c77328a2f8b2..a8a6909b594ee9e81863ba9b93f36a1210590115 100644 (file)
@@ -15,7 +15,7 @@ struct mtd_info;
 struct nand_chip;
 struct nand_bch_control;
 
-#if defined(CONFIG_MTD_NAND_ECC_BCH)
+#if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_BCH)
 
 static inline int mtd_nand_has_bch(void) { return 1; }
 
@@ -39,7 +39,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd);
  */
 void nand_bch_free(struct nand_bch_control *nbc);
 
-#else /* !CONFIG_MTD_NAND_ECC_BCH */
+#else /* !CONFIG_MTD_NAND_ECC_SW_BCH */
 
 static inline int mtd_nand_has_bch(void) { return 0; }
 
@@ -64,6 +64,6 @@ static inline struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
 
 static inline void nand_bch_free(struct nand_bch_control *nbc) {}
 
-#endif /* CONFIG_MTD_NAND_ECC_BCH */
+#endif /* CONFIG_MTD_NAND_ECC_SW_BCH */
 
 #endif /* __MTD_NAND_BCH_H__ */
index 0aaa98b219a461711306913674d5d582b40a617b..bfe9e10fae04b86c33913ec672a223501972ecdb 100644 (file)
@@ -94,6 +94,7 @@ struct onenand_chip {
        unsigned int            technology;
        unsigned int            density_mask;
        unsigned int            options;
+       unsigned int            badblockpos;
 
        unsigned int            erase_shift;
        unsigned int            page_shift;
@@ -188,6 +189,8 @@ struct onenand_chip {
 /* Check byte access in OneNAND */
 #define ONENAND_CHECK_BYTE_ACCESS(addr)                (addr & 0x1)
 
+#define ONENAND_BADBLOCK_POS           0
+
 /*
  * Options bits
  */
index b7445a44a814f67a62692e47886d74d76e3a3b07..dbfffa5bec7b4917c9883d433500d00d74f4b967 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mtd/flashchip.h>
 #include <linux/mtd/bbm.h>
 #include <linux/mtd/jedec.h>
+#include <linux/mtd/nand.h>
 #include <linux/mtd/onfi.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
@@ -168,6 +169,21 @@ enum nand_ecc_algo {
 /* Macros to identify the above */
 #define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ))
 
+/*
+ * There are different places where the manufacturer stores the factory bad
+ * block markers.
+ *
+ * Position within the block: Each of these pages needs to be checked for a
+ * bad block marking pattern.
+ */
+#define NAND_BBM_FIRSTPAGE             0x01000000
+#define NAND_BBM_SECONDPAGE            0x02000000
+#define NAND_BBM_LASTPAGE              0x04000000
+
+/* Position within the OOB data of the page */
+#define NAND_BBM_POS_SMALL             5
+#define NAND_BBM_POS_LARGE             0
+
 /* Non chip related options */
 /* This option skips the bbt scan during initialization. */
 #define NAND_SKIP_BBTSCAN      0x00010000
@@ -805,7 +821,7 @@ struct nand_op_parser_pattern {
 #define NAND_OP_PARSER_PATTERN(_exec, ...)                                                     \
        {                                                                                       \
                .exec = _exec,                                                                  \
-               .elems = (struct nand_op_parser_pattern_elem[]) { __VA_ARGS__ },                \
+               .elems = (const struct nand_op_parser_pattern_elem[]) { __VA_ARGS__ },          \
                .nelems = sizeof((struct nand_op_parser_pattern_elem[]) { __VA_ARGS__ }) /      \
                          sizeof(struct nand_op_parser_pattern_elem),                           \
        }
@@ -831,7 +847,7 @@ struct nand_op_parser {
 
 #define NAND_OP_PARSER(...)                                                                    \
        {                                                                                       \
-               .patterns = (struct nand_op_parser_pattern[]) { __VA_ARGS__ },                  \
+               .patterns = (const struct nand_op_parser_pattern[]) { __VA_ARGS__ },            \
                .npatterns = sizeof((struct nand_op_parser_pattern[]) { __VA_ARGS__ }) /        \
                             sizeof(struct nand_op_parser_pattern),                             \
        }
@@ -860,6 +876,7 @@ struct nand_operation {
 int nand_op_parser_exec_op(struct nand_chip *chip,
                           const struct nand_op_parser *parser,
                           const struct nand_operation *op, bool check_only);
+
 /**
  * struct nand_controller_ops - Controller operations
  *
@@ -962,7 +979,7 @@ struct nand_legacy {
 
 /**
  * struct nand_chip - NAND Private Flash Chip Data
- * @mtd:               MTD device registered to the MTD framework
+ * @base:              Inherit from the generic NAND device
  * @legacy:            All legacy fields/hooks. If you develop a new driver,
  *                     don't even try to use any of these fields/hooks, and if
  *                     you're modifying an existing driver that is using those
@@ -990,37 +1007,26 @@ struct nand_legacy {
  * @badblockbits:      [INTERN] minimum number of set bits in a good block's
  *                     bad block marker position; i.e., BBM == 11110111b is
  *                     not bad when badblockbits == 7
- * @bits_per_cell:     [INTERN] number of bits per cell. i.e., 1 means SLC.
- * @ecc_strength_ds:   [INTERN] ECC correctability from the datasheet.
- *                     Minimum amount of bit errors per @ecc_step_ds guaranteed
- *                     to be correctable. If unknown, set to zero.
- * @ecc_step_ds:       [INTERN] ECC step required by the @ecc_strength_ds,
- *                     also from the datasheet. It is the recommended ECC step
- *                     size, if known; if unknown, set to zero.
  * @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is
  *                           set to the actually used ONFI mode if the chip is
  *                           ONFI compliant or deduced from the datasheet if
  *                           the NAND chip is not ONFI compliant.
- * @numchips:          [INTERN] number of physical chips
- * @chipsize:          [INTERN] the size of one chip for multichip arrays
  * @pagemask:          [INTERN] page number mask = number of (pages / chip) - 1
  * @data_buf:          [INTERN] buffer for data, size is (page size + oobsize).
- * @pagebuf:           [INTERN] holds the pagenumber which is currently in
- *                     data_buf.
- * @pagebuf_bitflips:  [INTERN] holds the bitflip count for the page which is
- *                     currently in data_buf.
+ * @pagecache:         Structure containing page cache related fields
+ * @pagecache.bitflips:        Number of bitflips of the cached page
+ * @pagecache.page:    Page number currently in the cache. -1 means no page is
+ *                     currently cached
  * @subpagesize:       [INTERN] holds the subpagesize
  * @id:                        [INTERN] holds NAND ID
  * @parameters:                [INTERN] holds generic parameters under an easily
  *                     readable form.
- * @max_bb_per_die:    [INTERN] the max number of bad blocks each die of a
- *                     this nand device will encounter their life times.
- * @blocks_per_die:    [INTERN] The number of PEBs in a die
  * @data_interface:    [INTERN] NAND interface timing information
  * @cur_cs:            currently selected target. -1 means no target selected,
  *                     otherwise we should always have cur_cs >= 0 &&
- *                     cur_cs < numchips. NAND Controller drivers should not
- *                     modify this value, but they're allowed to read it.
+ *                     cur_cs < nanddev_ntargets(). NAND Controller drivers
+ *                     should not modify this value, but they're allowed to
+ *                     read it.
  * @read_retries:      [INTERN] the number of read retry modes supported
  * @lock:              lock protecting the suspended field. Also used to
  *                     serialize accesses to the NAND device.
@@ -1041,7 +1047,7 @@ struct nand_legacy {
  */
 
 struct nand_chip {
-       struct mtd_info mtd;
+       struct nand_device base;
 
        struct nand_legacy legacy;
 
@@ -1054,24 +1060,21 @@ struct nand_chip {
        int phys_erase_shift;
        int bbt_erase_shift;
        int chip_shift;
-       int numchips;
-       uint64_t chipsize;
        int pagemask;
        u8 *data_buf;
-       int pagebuf;
-       unsigned int pagebuf_bitflips;
+
+       struct {
+               unsigned int bitflips;
+               int page;
+       } pagecache;
+
        int subpagesize;
-       uint8_t bits_per_cell;
-       uint16_t ecc_strength_ds;
-       uint16_t ecc_step_ds;
        int onfi_timing_mode_default;
-       int badblockpos;
+       unsigned int badblockpos;
        int badblockbits;
 
        struct nand_id id;
        struct nand_parameters parameters;
-       u16 max_bb_per_die;
-       u32 blocks_per_die;
 
        struct nand_data_interface data_interface;
 
@@ -1105,25 +1108,14 @@ struct nand_chip {
 extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops;
 extern const struct mtd_ooblayout_ops nand_ooblayout_lp_ops;
 
-static inline void nand_set_flash_node(struct nand_chip *chip,
-                                      struct device_node *np)
-{
-       mtd_set_of_node(&chip->mtd, np);
-}
-
-static inline struct device_node *nand_get_flash_node(struct nand_chip *chip)
-{
-       return mtd_get_of_node(&chip->mtd);
-}
-
 static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd)
 {
-       return container_of(mtd, struct nand_chip, mtd);
+       return container_of(mtd, struct nand_chip, base.mtd);
 }
 
 static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip)
 {
-       return &chip->mtd;
+       return &chip->base.mtd;
 }
 
 static inline void *nand_get_controller_data(struct nand_chip *chip)
@@ -1147,6 +1139,17 @@ static inline void *nand_get_manufacturer_data(struct nand_chip *chip)
        return chip->manufacturer.priv;
 }
 
+static inline void nand_set_flash_node(struct nand_chip *chip,
+                                      struct device_node *np)
+{
+       mtd_set_of_node(nand_to_mtd(chip), np);
+}
+
+static inline struct device_node *nand_get_flash_node(struct nand_chip *chip)
+{
+       return mtd_get_of_node(nand_to_mtd(chip));
+}
+
 /*
  * A helper for defining older NAND chips where the second ID byte fully
  * defined the chip, including the geometry (chip size, eraseblock size, page
@@ -1180,9 +1183,9 @@ static inline void *nand_get_manufacturer_data(struct nand_chip *chip)
  * @name: a human-readable name of the NAND chip
  * @dev_id: the device ID (the second byte of the full chip ID array)
  * @mfr_id: manufecturer ID part of the full chip ID array (refers the same
- *          memory address as @id[0])
+ *          memory address as ``id[0]``)
  * @dev_id: device ID part of the full chip ID array (refers the same memory
- *          address as @id[1])
+ *          address as ``id[1]``)
  * @id: full device ID array
  * @pagesize: size of the NAND page in bytes; if 0, then the real page size (as
  *            well as the eraseblock size) is determined from the extended NAND
@@ -1235,9 +1238,9 @@ int nand_create_bbt(struct nand_chip *chip);
  */
 static inline bool nand_is_slc(struct nand_chip *chip)
 {
-       WARN(chip->bits_per_cell == 0,
+       WARN(nanddev_bits_per_cell(&chip->base) == 0,
             "chip->bits_per_cell is used uninitialized\n");
-       return chip->bits_per_cell == 1;
+       return nanddev_bits_per_cell(&chip->base) == 1;
 }
 
 /**
@@ -1348,4 +1351,25 @@ int nand_gpio_waitrdy(struct nand_chip *chip, struct gpio_desc *gpiod,
 void nand_select_target(struct nand_chip *chip, unsigned int cs);
 void nand_deselect_target(struct nand_chip *chip);
 
+/**
+ * nand_get_data_buf() - Get the internal page buffer
+ * @chip: NAND chip object
+ *
+ * Returns the pre-allocated page buffer after invalidating the cache. This
+ * function should be used by drivers that do not want to allocate their own
+ * bounce buffer and still need such a buffer for specific operations (most
+ * commonly when reading OOB data only).
+ *
+ * Be careful to never call this function in the write/write_oob path, because
+ * the core may have placed the data to be written out in this buffer.
+ *
+ * Return: pointer to the page cache buffer
+ */
+static inline void *nand_get_data_buf(struct nand_chip *chip)
+{
+       chip->pagecache.page = -1;
+
+       return chip->data_buf;
+}
+
 #endif /* __LINUX_MTD_RAWNAND_H */
index b92e2aa955b6f8f59fec6dfc802e15658b126b5c..507f7e289bd1596c746062a705455a9c4c5722e0 100644 (file)
@@ -302,6 +302,11 @@ struct spinand_info {
                __VA_ARGS__                                             \
        }
 
+struct spinand_dirmap {
+       struct spi_mem_dirmap_desc *wdesc;
+       struct spi_mem_dirmap_desc *rdesc;
+};
+
 /**
  * struct spinand_device - SPI NAND device instance
  * @base: NAND device instance
@@ -341,6 +346,8 @@ struct spinand_device {
                const struct spi_mem_op *update_cache;
        } op_templates;
 
+       struct spinand_dirmap *dirmaps;
+
        int (*select_target)(struct spinand_device *spinand,
                             unsigned int target);
        unsigned int cur_target;
index c40720cb59acc4190d40aafdfe23b42ef8159cf9..8028adacaff351179ee2de1ce4c50e42c4f9d994 100644 (file)
@@ -1246,9 +1246,9 @@ enum {
        NVME_SC_FW_NEEDS_SUBSYS_RESET   = 0x110,
        NVME_SC_FW_NEEDS_RESET          = 0x111,
        NVME_SC_FW_NEEDS_MAX_TIME       = 0x112,
-       NVME_SC_FW_ACIVATE_PROHIBITED   = 0x113,
+       NVME_SC_FW_ACTIVATE_PROHIBITED  = 0x113,
        NVME_SC_OVERLAPPING_RANGE       = 0x114,
-       NVME_SC_NS_INSUFFICENT_CAP      = 0x115,
+       NVME_SC_NS_INSUFFICIENT_CAP     = 0x115,
        NVME_SC_NS_ID_UNAVAILABLE       = 0x116,
        NVME_SC_NS_ALREADY_ATTACHED     = 0x118,
        NVME_SC_NS_IS_PRIVATE           = 0x119,
index 15eb85de92269e90d725c6da97f5615bd883dbff..659045046468fec25dfacbab285b95db5c3b028d 100644 (file)
@@ -284,11 +284,15 @@ static inline __must_check size_t array3_size(size_t a, size_t b, size_t c)
        return bytes;
 }
 
-static inline __must_check size_t __ab_c_size(size_t n, size_t size, size_t c)
+/*
+ * Compute a*b+c, returning SIZE_MAX on overflow. Internal helper for
+ * struct_size() below.
+ */
+static inline __must_check size_t __ab_c_size(size_t a, size_t b, size_t c)
 {
        size_t bytes;
 
-       if (check_mul_overflow(n, size, &bytes))
+       if (check_mul_overflow(a, b, &bytes))
                return SIZE_MAX;
        if (check_add_overflow(bytes, c, &bytes))
                return SIZE_MAX;
index bcf909d0de5f8e53f3fec18eb01c04fdd20ad5d8..9ec3544baee2d64f3005f864329b2c96100bbcd4 100644 (file)
@@ -333,6 +333,19 @@ static inline struct page *grab_cache_page_nowait(struct address_space *mapping,
                        mapping_gfp_mask(mapping));
 }
 
+static inline struct page *find_subpage(struct page *page, pgoff_t offset)
+{
+       unsigned long mask;
+
+       if (PageHuge(page))
+               return page;
+
+       VM_BUG_ON_PAGE(PageTail(page), page);
+
+       mask = (1UL << compound_order(page)) - 1;
+       return page + (offset & mask);
+}
+
 struct page *find_get_entry(struct address_space *mapping, pgoff_t offset);
 struct page *find_lock_entry(struct address_space *mapping, pgoff_t offset);
 unsigned find_get_entries(struct address_space *mapping, pgoff_t start,
@@ -360,9 +373,6 @@ static inline unsigned find_get_pages_tag(struct address_space *mapping,
        return find_get_pages_range_tag(mapping, index, (pgoff_t)-1, tag,
                                        nr_pages, pages);
 }
-unsigned find_get_entries_tag(struct address_space *mapping, pgoff_t start,
-                       xa_mark_t tag, unsigned int nr_entries,
-                       struct page **entries, pgoff_t *indices);
 
 struct page *grab_cache_page_write_begin(struct address_space *mapping,
                        pgoff_t index, unsigned flags);
@@ -527,15 +537,7 @@ static inline int wait_on_page_locked_killable(struct page *page)
 
 extern void put_and_wait_on_page_locked(struct page *page);
 
-/* 
- * Wait for a page to complete writeback
- */
-static inline void wait_on_page_writeback(struct page *page)
-{
-       if (PageWriteback(page))
-               wait_on_page_bit(page, PG_writeback);
-}
-
+void wait_on_page_writeback(struct page *page);
 extern void end_page_writeback(struct page *page);
 void wait_for_stable_page(struct page *page);
 
index 29efa09d686b2d8062b827f20b1f8b21d08ac20f..a73164c85e78b904bcbce317897c531a5130a6df 100644 (file)
@@ -56,6 +56,7 @@ extern struct pci_ecam_ops thunder_pem_ecam_ops; /* Cavium ThunderX 1.x & 2.x */
 extern struct pci_ecam_ops pci_thunder_ecam_ops; /* Cavium ThunderX 1.x */
 extern struct pci_ecam_ops xgene_v1_pcie_ecam_ops; /* APM X-Gene PCIe v1 */
 extern struct pci_ecam_ops xgene_v2_pcie_ecam_ops; /* APM X-Gene PCIe v2.x */
+extern struct pci_ecam_ops al_pcie_ops; /* Amazon Annapurna Labs PCIe */
 #endif
 
 #ifdef CONFIG_PCI_HOST_COMMON
index c3ffa3917f88e2f4f926e029d1c9e7e8f7ff2001..f641badc2c6157c3b1f670b4690b0514d9871352 100644 (file)
@@ -109,6 +109,7 @@ struct pci_epc {
  * @reserved_bar: bitmap to indicate reserved BAR unavailable to function driver
  * @bar_fixed_64bit: bitmap to indicate fixed 64bit BARs
  * @bar_fixed_size: Array specifying the size supported by each BAR
+ * @align: alignment size required for BAR buffer allocation
  */
 struct pci_epc_features {
        unsigned int    linkup_notifier : 1;
@@ -117,6 +118,7 @@ struct pci_epc_features {
        u8      reserved_bar;
        u8      bar_fixed_64bit;
        u64     bar_fixed_size[BAR_5 + 1];
+       size_t  align;
 };
 
 #define to_pci_epc(device) container_of((device), struct pci_epc, dev)
index ec02f58758c84636de6a15874898e5fe810c12fd..2d6f0755668245863fdf2d66f84799bfaf35a83a 100644 (file)
@@ -149,7 +149,8 @@ void pci_epf_destroy(struct pci_epf *epf);
 int __pci_epf_register_driver(struct pci_epf_driver *driver,
                              struct module *owner);
 void pci_epf_unregister_driver(struct pci_epf_driver *driver);
-void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar);
+void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
+                         size_t align);
 void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar);
 int pci_epf_bind(struct pci_epf *epf);
 void pci_epf_unbind(struct pci_epf *epf);
index 77448215ef5b7373ef6de3f7ff075e422f9302f2..4a5a84d7bdd43edad868dc8247b8995ca478dec9 100644 (file)
@@ -348,6 +348,8 @@ struct pci_dev {
        unsigned int    hotplug_user_indicators:1; /* SlotCtl indicators
                                                      controlled exclusively by
                                                      user sysfs */
+       unsigned int    clear_retrain_link:1;   /* Need to clear Retrain Link
+                                                  bit manually */
        unsigned int    d3_delay;       /* D3->D0 transition time in ms */
        unsigned int    d3cold_delay;   /* D3cold->D0 transition time in ms */
 
@@ -490,6 +492,7 @@ struct pci_host_bridge {
        void            *sysdata;
        int             busnr;
        struct list_head windows;       /* resource_entry */
+       struct list_head dma_ranges;    /* dma ranges resource list */
        u8 (*swizzle_irq)(struct pci_dev *, u8 *); /* Platform IRQ swizzler */
        int (*map_irq)(const struct pci_dev *, u8, u8);
        void (*release_fn)(struct pci_host_bridge *);
@@ -596,6 +599,11 @@ struct pci_bus {
 
 #define to_pci_bus(n)  container_of(n, struct pci_bus, dev)
 
+static inline u16 pci_dev_id(struct pci_dev *dev)
+{
+       return PCI_DEVID(dev->bus->number, dev->devfn);
+}
+
 /*
  * Returns true if the PCI bus is root (behind host-PCI bridge),
  * false otherwise
@@ -1233,7 +1241,6 @@ int __must_check pci_request_regions(struct pci_dev *, const char *);
 int __must_check pci_request_regions_exclusive(struct pci_dev *, const char *);
 void pci_release_regions(struct pci_dev *);
 int __must_check pci_request_region(struct pci_dev *, int, const char *);
-int __must_check pci_request_region_exclusive(struct pci_dev *, int, const char *);
 void pci_release_region(struct pci_dev *, int);
 int pci_request_selected_regions(struct pci_dev *, int, const char *);
 int pci_request_selected_regions_exclusive(struct pci_dev *, int, const char *);
@@ -1521,21 +1528,6 @@ static inline void pcie_ecrc_get_policy(char *str) { }
 
 bool pci_ats_disabled(void);
 
-#ifdef CONFIG_PCI_ATS
-/* Address Translation Service */
-void pci_ats_init(struct pci_dev *dev);
-int pci_enable_ats(struct pci_dev *dev, int ps);
-void pci_disable_ats(struct pci_dev *dev);
-int pci_ats_queue_depth(struct pci_dev *dev);
-int pci_ats_page_aligned(struct pci_dev *dev);
-#else
-static inline void pci_ats_init(struct pci_dev *d) { }
-static inline int pci_enable_ats(struct pci_dev *d, int ps) { return -ENODEV; }
-static inline void pci_disable_ats(struct pci_dev *d) { }
-static inline int pci_ats_queue_depth(struct pci_dev *d) { return -ENODEV; }
-static inline int pci_ats_page_aligned(struct pci_dev *dev) { return 0; }
-#endif
-
 #ifdef CONFIG_PCIE_PTM
 int pci_enable_ptm(struct pci_dev *dev, u8 *granularity);
 #else
@@ -1728,8 +1720,24 @@ static inline int pci_irqd_intx_xlate(struct irq_domain *d,
 static inline const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
                                                         struct pci_dev *dev)
 { return NULL; }
+static inline bool pci_ats_disabled(void) { return true; }
 #endif /* CONFIG_PCI */
 
+#ifdef CONFIG_PCI_ATS
+/* Address Translation Service */
+void pci_ats_init(struct pci_dev *dev);
+int pci_enable_ats(struct pci_dev *dev, int ps);
+void pci_disable_ats(struct pci_dev *dev);
+int pci_ats_queue_depth(struct pci_dev *dev);
+int pci_ats_page_aligned(struct pci_dev *dev);
+#else
+static inline void pci_ats_init(struct pci_dev *d) { }
+static inline int pci_enable_ats(struct pci_dev *d, int ps) { return -ENODEV; }
+static inline void pci_disable_ats(struct pci_dev *d) { }
+static inline int pci_ats_queue_depth(struct pci_dev *d) { return -ENODEV; }
+static inline int pci_ats_page_aligned(struct pci_dev *dev) { return 0; }
+#endif
+
 /* Include architecture-dependent settings and functions */
 
 #include <asm/pci.h>
@@ -2363,4 +2371,7 @@ void pci_uevent_ers(struct pci_dev *pdev, enum  pci_ers_result err_type);
 #define pci_info(pdev, fmt, arg...)    dev_info(&(pdev)->dev, fmt, ##arg)
 #define pci_dbg(pdev, fmt, arg...)     dev_dbg(&(pdev)->dev, fmt, ##arg)
 
+#define pci_notice_ratelimited(pdev, fmt, arg...) \
+       dev_notice_ratelimited(&(pdev)->dev, fmt, ##arg)
+
 #endif /* LINUX_PCI_H */
index 7acc9f91e72b69a965f88da983ce9c6100ff5bdf..f694eb2ca97815982165c0f6ba1d3757cb0a550e 100644 (file)
@@ -124,26 +124,72 @@ struct hpp_type2 {
        u32 sec_unc_err_mask_or;
 };
 
-struct hotplug_params {
-       struct hpp_type0 *t0;           /* Type0: NULL if not available */
-       struct hpp_type1 *t1;           /* Type1: NULL if not available */
-       struct hpp_type2 *t2;           /* Type2: NULL if not available */
-       struct hpp_type0 type0_data;
-       struct hpp_type1 type1_data;
-       struct hpp_type2 type2_data;
+/*
+ * _HPX PCI Express Setting Record (Type 3)
+ */
+struct hpx_type3 {
+       u16 device_type;
+       u16 function_type;
+       u16 config_space_location;
+       u16 pci_exp_cap_id;
+       u16 pci_exp_cap_ver;
+       u16 pci_exp_vendor_id;
+       u16 dvsec_id;
+       u16 dvsec_rev;
+       u16 match_offset;
+       u32 match_mask_and;
+       u32 match_value;
+       u16 reg_offset;
+       u32 reg_mask_and;
+       u32 reg_mask_or;
+};
+
+struct hotplug_program_ops {
+       void (*program_type0)(struct pci_dev *dev, struct hpp_type0 *hpp);
+       void (*program_type1)(struct pci_dev *dev, struct hpp_type1 *hpp);
+       void (*program_type2)(struct pci_dev *dev, struct hpp_type2 *hpp);
+       void (*program_type3)(struct pci_dev *dev, struct hpx_type3 *hpp);
+};
+
+enum hpx_type3_dev_type {
+       HPX_TYPE_ENDPOINT       = BIT(0),
+       HPX_TYPE_LEG_END        = BIT(1),
+       HPX_TYPE_RC_END         = BIT(2),
+       HPX_TYPE_RC_EC          = BIT(3),
+       HPX_TYPE_ROOT_PORT      = BIT(4),
+       HPX_TYPE_UPSTREAM       = BIT(5),
+       HPX_TYPE_DOWNSTREAM     = BIT(6),
+       HPX_TYPE_PCI_BRIDGE     = BIT(7),
+       HPX_TYPE_PCIE_BRIDGE    = BIT(8),
+};
+
+enum hpx_type3_fn_type {
+       HPX_FN_NORMAL           = BIT(0),
+       HPX_FN_SRIOV_PHYS       = BIT(1),
+       HPX_FN_SRIOV_VIRT       = BIT(2),
+};
+
+enum hpx_type3_cfg_loc {
+       HPX_CFG_PCICFG          = 0,
+       HPX_CFG_PCIE_CAP        = 1,
+       HPX_CFG_PCIE_CAP_EXT    = 2,
+       HPX_CFG_VEND_CAP        = 3,
+       HPX_CFG_DVSEC           = 4,
+       HPX_CFG_MAX,
 };
 
 #ifdef CONFIG_ACPI
 #include <linux/acpi.h>
-int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp);
+int pci_acpi_program_hp_params(struct pci_dev *dev,
+                              const struct hotplug_program_ops *hp_ops);
 bool pciehp_is_native(struct pci_dev *bridge);
 int acpi_get_hp_hw_control_from_firmware(struct pci_dev *bridge);
 bool shpchp_is_native(struct pci_dev *bridge);
 int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle);
 int acpi_pci_detect_ejectable(acpi_handle handle);
 #else
-static inline int pci_get_hp_params(struct pci_dev *dev,
-                                   struct hotplug_params *hpp)
+static inline int pci_acpi_program_hp_params(struct pci_dev *dev,
+                                   const struct hotplug_program_ops *hp_ops)
 {
        return -ENODEV;
 }
index 70b7123f38c7c9044bb262a2cecc96ab415b1f4d..9909dc0e273adb1e7bf8eac0eae95862e9b35210 100644 (file)
 #define PCPU_MIN_ALLOC_SHIFT           2
 #define PCPU_MIN_ALLOC_SIZE            (1 << PCPU_MIN_ALLOC_SHIFT)
 
-/* number of bits per page, used to trigger a scan if blocks are > PAGE_SIZE */
-#define PCPU_BITS_PER_PAGE             (PAGE_SIZE >> PCPU_MIN_ALLOC_SHIFT)
-
 /*
- * This determines the size of each metadata block.  There are several subtle
- * constraints around this constant.  The reserved region must be a multiple of
- * PCPU_BITMAP_BLOCK_SIZE.  Additionally, PCPU_BITMAP_BLOCK_SIZE must be a
- * multiple of PAGE_SIZE or PAGE_SIZE must be a multiple of
- * PCPU_BITMAP_BLOCK_SIZE to align with the populated page map. The unit_size
- * also has to be a multiple of PCPU_BITMAP_BLOCK_SIZE to ensure full blocks.
+ * The PCPU_BITMAP_BLOCK_SIZE must be the same size as PAGE_SIZE as the
+ * updating of hints is used to manage the nr_empty_pop_pages in both
+ * the chunk and globally.
  */
 #define PCPU_BITMAP_BLOCK_SIZE         PAGE_SIZE
 #define PCPU_BITMAP_BLOCK_BITS         (PCPU_BITMAP_BLOCK_SIZE >>      \
index 15a82ff0aefe8be73ffe262cd76d7c7ce3ff7a00..0ab99c7b652d41b15b7de0ddf185d01d412fcfd1 100644 (file)
@@ -30,6 +30,7 @@ struct perf_guest_info_callbacks {
        int                             (*is_in_guest)(void);
        int                             (*is_user_mode)(void);
        unsigned long                   (*get_guest_ip)(void);
+       void                            (*handle_intel_pt_intr)(void);
 };
 
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
index b8686c00f15ff9fca42df0c8e3552a1031b52e83..fef4b081b73632c357459f7532259f3c46c2fd3a 100644 (file)
@@ -60,6 +60,6 @@ static inline int elm_config(struct device *dev, enum bch_ecc bch_type,
 {
        return -ENOSYS;
 }
-#endif /* CONFIG_MTD_NAND_ECC_BCH */
+#endif /* CONFIG_MTD_NAND_OMAP_BCH */
 
 #endif /* __ELM_H */
diff --git a/include/linux/platform_data/eth-ep93xx.h b/include/linux/platform_data/eth-ep93xx.h
new file mode 100644 (file)
index 0000000..8eef637
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_PLATFORM_DATA_ETH_EP93XX
+#define _LINUX_PLATFORM_DATA_ETH_EP93XX
+
+struct ep93xx_eth_data {
+       unsigned char   dev_addr[6];
+       unsigned char   phy_id;
+};
+
+#endif
index 6d07eebb3f75907efa50bf5fadd92dd568da8ec6..7c36370c062eac4ab9b1db2e7280160afe5b9d85 100644 (file)
@@ -200,8 +200,6 @@ struct omap_gpio_platform_data {
        bool is_mpuio;          /* whether the bank is of type MPUIO */
        u32 non_wakeup_gpios;
 
-       u32 quirks;             /* Version specific quirks mask */
-
        struct omap_gpio_reg_offs *regs;
 
        /* Return context loss count due to PM states changing */
index 0e36818e368056f849920788207986c8b32ef36e..3054fced850922208a5c4948e5ac9c5f473d98be 100644 (file)
@@ -9,8 +9,7 @@ struct matrix_keymap_data;
 #define EP93XX_KEYPAD_DIAG_MODE                (1<<1)  /* diagnostic mode */
 #define EP93XX_KEYPAD_BACK_DRIVE       (1<<2)  /* back driving mode */
 #define EP93XX_KEYPAD_TEST_MODE                (1<<3)  /* scan only column 0 */
-#define EP93XX_KEYPAD_KDIV             (1<<4)  /* 1/4 clock or 1/16 clock */
-#define EP93XX_KEYPAD_AUTOREPEAT       (1<<5)  /* enable key autorepeat */
+#define EP93XX_KEYPAD_AUTOREPEAT       (1<<4)  /* enable key autorepeat */
 
 /**
  * struct ep93xx_keypad_platform_data - platform specific device structure
@@ -24,6 +23,7 @@ struct ep93xx_keypad_platform_data {
        unsigned int    debounce;
        unsigned int    prescale;
        unsigned int    flags;
+       unsigned int    clk_rate;
 };
 
 #define EP93XX_MATRIX_ROWS             (8)
index 7538e38e270b17ae2f551134e4a6bae5a27a62ec..762e68956f311ed9e71882f5ad015015904ed6e8 100644 (file)
@@ -38,9 +38,11 @@ enum lm3630a_ledb_ctrl {
 
 #define LM3630A_MAX_BRIGHTNESS 255
 /*
+ *@leda_label    : optional led a label.
  *@leda_init_brt : led a init brightness. 4~255
  *@leda_max_brt  : led a max brightness.  4~255
  *@leda_ctrl     : led a disable, enable linear, enable exponential
+ *@ledb_label    : optional led b label.
  *@ledb_init_brt : led b init brightness. 4~255
  *@ledb_max_brt  : led b max brightness.  4~255
  *@ledb_ctrl     : led b disable, enable linear, enable exponential
@@ -50,10 +52,12 @@ enum lm3630a_ledb_ctrl {
 struct lm3630a_platform_data {
 
        /* led a config.  */
+       const char *leda_label;
        int leda_init_brt;
        int leda_max_brt;
        enum lm3630a_leda_ctrl leda_ctrl;
        /* led b config. */
+       const char *ledb_label;
        int ledb_init_brt;
        int ledb_max_brt;
        enum lm3630a_ledb_ctrl ledb_ctrl;
index fbf5ed73c7cca47c9afa3ff66134af8b6ec6429d..dd5971937a643c0703563a6ba4fa353237b6696c 100644 (file)
@@ -51,6 +51,11 @@ struct am33xx_pm_platform_data {
                               unsigned long args);
        struct  am33xx_pm_sram_addr *(*get_sram_addrs)(void);
        void __iomem *(*get_rtc_base_addr)(void);
+       void (*save_context)(void);
+       void (*restore_context)(void);
+       void (*prepare_rtc_suspend)(void);
+       void (*prepare_rtc_resume)(void);
+       int (*check_off_mode_enable)(void);
 };
 
 struct am33xx_pm_sram_data {
index 1ea3aab972b42c315bf41a6775739c393a441d94..9256c03059684ee544aa107e29a182c8ef5c5a4a 100644 (file)
@@ -46,8 +46,13 @@ struct sysc_regbits {
        s8 emufree_shift;
 };
 
-#define SYSC_QUIRK_LEGACY_IDLE         BIT(8)
-#define SYSC_QUIRK_RESET_STATUS                BIT(7)
+#define SYSC_QUIRK_SWSUP_MSTANDBY      BIT(13)
+#define SYSC_QUIRK_SWSUP_SIDLE_ACT     BIT(12)
+#define SYSC_QUIRK_SWSUP_SIDLE         BIT(11)
+#define SYSC_QUIRK_EXT_OPT_CLOCK       BIT(10)
+#define SYSC_QUIRK_LEGACY_IDLE         BIT(9)
+#define SYSC_QUIRK_RESET_STATUS                BIT(8)
+#define SYSC_QUIRK_NO_IDLE             BIT(7)
 #define SYSC_QUIRK_NO_IDLE_ON_INIT     BIT(6)
 #define SYSC_QUIRK_NO_RESET_ON_INIT    BIT(5)
 #define SYSC_QUIRK_OPT_CLKS_NEEDED     BIT(4)
diff --git a/include/linux/platform_data/timer-ixp4xx.h b/include/linux/platform_data/timer-ixp4xx.h
new file mode 100644 (file)
index 0000000..ee92ae7
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __TIMER_IXP4XX_H
+#define __TIMER_IXP4XX_H
+
+#include <linux/ioport.h>
+
+void __init ixp4xx_timer_setup(resource_size_t timerbase,
+                              int timer_irq,
+                              unsigned int timer_freq);
+
+#endif
index 446473a46b88d3d623bf235a7f0508610b2d085c..1ff224793c99f9778f803b3fed1d1e4eed70227e 100644 (file)
 /* Message flags for using the mailbox() interface */
 #define WILCO_EC_FLAG_NO_RESPONSE      BIT(0) /* EC does not respond */
 #define WILCO_EC_FLAG_EXTENDED_DATA    BIT(1) /* EC returns 256 data bytes */
-#define WILCO_EC_FLAG_RAW_REQUEST      BIT(2) /* Do not trim request data */
-#define WILCO_EC_FLAG_RAW_RESPONSE     BIT(3) /* Do not trim response data */
-#define WILCO_EC_FLAG_RAW              (WILCO_EC_FLAG_RAW_REQUEST | \
-                                        WILCO_EC_FLAG_RAW_RESPONSE)
 
 /* Normal commands have a maximum 32 bytes of data */
 #define EC_MAILBOX_DATA_SIZE           32
@@ -56,10 +52,7 @@ struct wilco_ec_device {
  * @mailbox_id: Mailbox identifier, specifies the command set.
  * @mailbox_version: Mailbox interface version %EC_MAILBOX_VERSION
  * @reserved: Set to zero.
- * @data_size: Length of request, data + last 2 bytes of the header.
- * @command: Mailbox command code, unique for each mailbox_id set.
- * @reserved_raw: Set to zero for most commands, but is used by
- *                some command types and for raw commands.
+ * @data_size: Length of following data.
  */
 struct wilco_ec_request {
        u8 struct_version;
@@ -68,8 +61,6 @@ struct wilco_ec_request {
        u8 mailbox_version;
        u8 reserved;
        u16 data_size;
-       u8 command;
-       u8 reserved_raw;
 } __packed;
 
 /**
@@ -79,8 +70,6 @@ struct wilco_ec_request {
  * @result: Result code from the EC.  Non-zero indicates an error.
  * @data_size: Length of the response data buffer.
  * @reserved: Set to zero.
- * @mbox0: EC returned data at offset 0 is unused (always 0) so this byte
- *         is treated as part of the header instead of the data.
  * @data: Response data buffer.  Max size is %EC_MAILBOX_DATA_SIZE_EXTENDED.
  */
 struct wilco_ec_response {
@@ -89,7 +78,6 @@ struct wilco_ec_response {
        u16 result;
        u16 data_size;
        u8 reserved[2];
-       u8 mbox0;
        u8 data[0];
 } __packed;
 
@@ -111,21 +99,15 @@ enum wilco_ec_msg_type {
  * struct wilco_ec_message - Request and response message.
  * @type: Mailbox message type.
  * @flags: Message flags, e.g. %WILCO_EC_FLAG_NO_RESPONSE.
- * @command: Mailbox command code.
- * @result: Result code from the EC.  Non-zero indicates an error.
  * @request_size: Number of bytes to send to the EC.
  * @request_data: Buffer containing the request data.
- * @response_size: Number of bytes expected from the EC.
- *                 This is 32 by default and 256 if the flag
- *                 is set for %WILCO_EC_FLAG_EXTENDED_DATA
+ * @response_size: Number of bytes to read from EC.
  * @response_data: Buffer containing the response data, should be
  *                 response_size bytes and allocated by caller.
  */
 struct wilco_ec_message {
        enum wilco_ec_msg_type type;
        u8 flags;
-       u8 command;
-       u8 result;
        size_t request_size;
        void *request_data;
        size_t response_size;
index 53dfc25419603e666d1d6da8fad9a0ef419b36e7..bfba245636a715cb25b6d154979f403e319a6a5d 100644 (file)
@@ -67,6 +67,7 @@
 /* Input */
 #define ASUS_WMI_DEVID_TOUCHPAD                0x00100011
 #define ASUS_WMI_DEVID_TOUCHPAD_LED    0x00100012
+#define ASUS_WMI_DEVID_FNLOCK          0x00100023
 
 /* Fan, Thermal */
 #define ASUS_WMI_DEVID_THERMAL_CTRL    0x00110011
diff --git a/include/linux/platform_data/xtalk-bridge.h b/include/linux/platform_data/xtalk-bridge.h
new file mode 100644 (file)
index 0000000..51e5001
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SGI PCI Xtalk Bridge
+ */
+
+#ifndef PLATFORM_DATA_XTALK_BRIDGE_H
+#define PLATFORM_DATA_XTALK_BRIDGE_H
+
+#include <asm/sn/types.h>
+
+struct xtalk_bridge_platform_data {
+       struct resource mem;
+       struct resource io;
+       unsigned long bridge_addr;
+       unsigned long intr_addr;
+       unsigned long mem_offset;
+       unsigned long io_offset;
+       nasid_t nasid;
+       int     masterwid;
+};
+
+#endif /* PLATFORM_DATA_XTALK_BRIDGE_H */
index 97883604a3c5f7516ae2aa67574c5ce7ffda4cb8..9365df5a823fa5d90990c5aea37448e0fd467802 100644 (file)
@@ -231,7 +231,7 @@ static inline int plist_node_empty(const struct plist_node *node)
  * @type:      the type of the struct this is embedded in
  * @member:    the name of the list_head within the struct
  */
-#ifdef CONFIG_DEBUG_PI_LIST
+#ifdef CONFIG_DEBUG_PLIST
 # define plist_first_entry(head, type, member) \
 ({ \
        WARN_ON(plist_head_empty(head)); \
@@ -248,7 +248,7 @@ static inline int plist_node_empty(const struct plist_node *node)
  * @type:      the type of the struct this is embedded in
  * @member:    the name of the list_head within the struct
  */
-#ifdef CONFIG_DEBUG_PI_LIST
+#ifdef CONFIG_DEBUG_PLIST
 # define plist_last_entry(head, type, member)  \
 ({ \
        WARN_ON(plist_head_empty(head)); \
index 0e8e356bed6a406725dbc55e5d0dae72e419105c..b21f35f0ee2eafbfae04fa7c193f5be543d75825 100644 (file)
  *                             driver must then comply with the so called,
  *                             last-man-standing algorithm, for the CPUs in the
  *                             PM domain.
+ *
+ * GENPD_FLAG_RPM_ALWAYS_ON:   Instructs genpd to always keep the PM domain
+ *                             powered on except for system suspend.
  */
 #define GENPD_FLAG_PM_CLK       (1U << 0)
 #define GENPD_FLAG_IRQ_SAFE     (1U << 1)
 #define GENPD_FLAG_ALWAYS_ON    (1U << 2)
 #define GENPD_FLAG_ACTIVE_WAKEUP (1U << 3)
 #define GENPD_FLAG_CPU_DOMAIN   (1U << 4)
+#define GENPD_FLAG_RPM_ALWAYS_ON (1U << 5)
 
 enum gpd_status {
        GPD_STATE_ACTIVE = 0,   /* PM domain is active */
index 7e0fdcf905d2e77b355c94a7381446927452723c..1cdc32b1f1b0836e6dccf2ecf446b9aeab0a950b 100644 (file)
 extern struct ctl_table epoll_table[]; /* for sysctl */
 /* ~832 bytes of stack space used max in sys_select/sys_poll before allocating
    additional memory. */
+#ifdef __clang__
+#define MAX_STACK_ALLOC 768
+#else
 #define MAX_STACK_ALLOC 832
+#endif
 #define FRONTEND_STACK_ALLOC   256
 #define SELECT_STACK_ALLOC     FRONTEND_STACK_ALLOC
 #define POLL_STACK_ALLOC       FRONTEND_STACK_ALLOC
index 2f9c201a54d1b6865640ed297fd61168ae9b7e10..d9c0c094f8a0d8af95f70dfaa2e2588f2ea4e1a9 100644 (file)
@@ -40,11 +40,15 @@ enum {
        POWER_SUPPLY_STATUS_FULL,
 };
 
+/* What algorithm is the charger using? */
 enum {
        POWER_SUPPLY_CHARGE_TYPE_UNKNOWN = 0,
        POWER_SUPPLY_CHARGE_TYPE_NONE,
-       POWER_SUPPLY_CHARGE_TYPE_TRICKLE,
-       POWER_SUPPLY_CHARGE_TYPE_FAST,
+       POWER_SUPPLY_CHARGE_TYPE_TRICKLE,       /* slow speed */
+       POWER_SUPPLY_CHARGE_TYPE_FAST,          /* fast speed */
+       POWER_SUPPLY_CHARGE_TYPE_STANDARD,      /* normal speed */
+       POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE,      /* dynamically adjusted speed */
+       POWER_SUPPLY_CHARGE_TYPE_CUSTOM,        /* use CHARGE_CONTROL_* props */
 };
 
 enum {
@@ -57,6 +61,7 @@ enum {
        POWER_SUPPLY_HEALTH_COLD,
        POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE,
        POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE,
+       POWER_SUPPLY_HEALTH_OVERCURRENT,
 };
 
 enum {
@@ -121,6 +126,8 @@ enum power_supply_property {
        POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
        POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
        POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
+       POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD, /* in percents! */
+       POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, /* in percents! */
        POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
        POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
        POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
index 56f35dd3d01d382820c18283500f4a6f725c854f..44171e6b7197af574dcd3d93398d4431cf00133c 100644 (file)
 #define _PPS_GPIO_H
 
 struct pps_gpio_platform_data {
+       struct gpio_desc *gpio_pin;
+       struct gpio_desc *echo_pin;
        bool assert_falling_edge;
        bool capture_clear;
-       unsigned int gpio_pin;
-       const char *gpio_label;
+       unsigned int echo_active_ms;
 };
 
 #endif /* _PPS_GPIO_H */
index 84ea4d094af33368711071f4fcff34c1532eccd5..cefd374c47b1f88ebcd21e203da4311c27676da6 100644 (file)
@@ -82,6 +82,8 @@ static inline void console_verbose(void)
 extern char devkmsg_log_str[];
 struct ctl_table;
 
+extern int suppress_printk;
+
 struct va_format {
        const char *fmt;
        va_list *va;
index 7006008d5b72fbb4bde94a98fde89202bfd706a0..7b3de73212199cfb6e46092600c9af3dc7749865 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/jump_label.h>
 #include <linux/psi_types.h>
 #include <linux/sched.h>
+#include <linux/poll.h>
 
 struct seq_file;
 struct css_set;
@@ -11,6 +12,7 @@ struct css_set;
 #ifdef CONFIG_PSI
 
 extern struct static_key_false psi_disabled;
+extern struct psi_group psi_system;
 
 void psi_init(void);
 
@@ -26,6 +28,13 @@ int psi_show(struct seq_file *s, struct psi_group *group, enum psi_res res);
 int psi_cgroup_alloc(struct cgroup *cgrp);
 void psi_cgroup_free(struct cgroup *cgrp);
 void cgroup_move_task(struct task_struct *p, struct css_set *to);
+
+struct psi_trigger *psi_trigger_create(struct psi_group *group,
+                       char *buf, size_t nbytes, enum psi_res res);
+void psi_trigger_replace(void **trigger_ptr, struct psi_trigger *t);
+
+__poll_t psi_trigger_poll(void **trigger_ptr, struct file *file,
+                       poll_table *wait);
 #endif
 
 #else /* CONFIG_PSI */
index 2cf422db5d18d5b87f17ef5952bf9510ad6cbbad..07aaf9b822416a49ae41c57835ced3ca4515439c 100644 (file)
@@ -1,8 +1,11 @@
 #ifndef _LINUX_PSI_TYPES_H
 #define _LINUX_PSI_TYPES_H
 
+#include <linux/kthread.h>
 #include <linux/seqlock.h>
 #include <linux/types.h>
+#include <linux/kref.h>
+#include <linux/wait.h>
 
 #ifdef CONFIG_PSI
 
@@ -11,7 +14,7 @@ enum psi_task_count {
        NR_IOWAIT,
        NR_MEMSTALL,
        NR_RUNNING,
-       NR_PSI_TASK_COUNTS,
+       NR_PSI_TASK_COUNTS = 3,
 };
 
 /* Task state bitmasks */
@@ -24,7 +27,7 @@ enum psi_res {
        PSI_IO,
        PSI_MEM,
        PSI_CPU,
-       NR_PSI_RESOURCES,
+       NR_PSI_RESOURCES = 3,
 };
 
 /*
@@ -41,7 +44,13 @@ enum psi_states {
        PSI_CPU_SOME,
        /* Only per-CPU, to weigh the CPU in the global average: */
        PSI_NONIDLE,
-       NR_PSI_STATES,
+       NR_PSI_STATES = 6,
+};
+
+enum psi_aggregators {
+       PSI_AVGS = 0,
+       PSI_POLL,
+       NR_PSI_AGGREGATORS,
 };
 
 struct psi_group_cpu {
@@ -53,6 +62,9 @@ struct psi_group_cpu {
        /* States of the tasks belonging to this group */
        unsigned int tasks[NR_PSI_TASK_COUNTS];
 
+       /* Aggregate pressure state derived from the tasks */
+       u32 state_mask;
+
        /* Period time sampling buckets for each state of interest (ns) */
        u32 times[NR_PSI_STATES];
 
@@ -62,25 +74,94 @@ struct psi_group_cpu {
        /* 2nd cacheline updated by the aggregator */
 
        /* Delta detection against the sampling buckets */
-       u32 times_prev[NR_PSI_STATES] ____cacheline_aligned_in_smp;
+       u32 times_prev[NR_PSI_AGGREGATORS][NR_PSI_STATES]
+                       ____cacheline_aligned_in_smp;
+};
+
+/* PSI growth tracking window */
+struct psi_window {
+       /* Window size in ns */
+       u64 size;
+
+       /* Start time of the current window in ns */
+       u64 start_time;
+
+       /* Value at the start of the window */
+       u64 start_value;
+
+       /* Value growth in the previous window */
+       u64 prev_growth;
+};
+
+struct psi_trigger {
+       /* PSI state being monitored by the trigger */
+       enum psi_states state;
+
+       /* User-spacified threshold in ns */
+       u64 threshold;
+
+       /* List node inside triggers list */
+       struct list_head node;
+
+       /* Backpointer needed during trigger destruction */
+       struct psi_group *group;
+
+       /* Wait queue for polling */
+       wait_queue_head_t event_wait;
+
+       /* Pending event flag */
+       int event;
+
+       /* Tracking window */
+       struct psi_window win;
+
+       /*
+        * Time last event was generated. Used for rate-limiting
+        * events to one per window
+        */
+       u64 last_event_time;
+
+       /* Refcounting to prevent premature destruction */
+       struct kref refcount;
 };
 
 struct psi_group {
-       /* Protects data updated during an aggregation */
-       struct mutex stat_lock;
+       /* Protects data used by the aggregator */
+       struct mutex avgs_lock;
 
        /* Per-cpu task state & time tracking */
        struct psi_group_cpu __percpu *pcpu;
 
-       /* Periodic aggregation state */
-       u64 total_prev[NR_PSI_STATES - 1];
-       u64 last_update;
-       u64 next_update;
-       struct delayed_work clock_work;
+       /* Running pressure averages */
+       u64 avg_total[NR_PSI_STATES - 1];
+       u64 avg_last_update;
+       u64 avg_next_update;
+
+       /* Aggregator work control */
+       struct delayed_work avgs_work;
 
        /* Total stall times and sampled pressure averages */
-       u64 total[NR_PSI_STATES - 1];
+       u64 total[NR_PSI_AGGREGATORS][NR_PSI_STATES - 1];
        unsigned long avg[NR_PSI_STATES - 1][3];
+
+       /* Monitor work control */
+       atomic_t poll_scheduled;
+       struct kthread_worker __rcu *poll_kworker;
+       struct kthread_delayed_work poll_work;
+
+       /* Protects data used by the monitor */
+       struct mutex trigger_lock;
+
+       /* Configured polling triggers */
+       struct list_head triggers;
+       u32 nr_triggers[NR_PSI_STATES - 1];
+       u32 poll_states;
+       u64 poll_min_period;
+
+       /* Total stall times at the start of monitor activation */
+       u64 polling_total[NR_PSI_STATES - 1];
+       u64 polling_next_update;
+       u64 polling_until;
 };
 
 #else /* CONFIG_PSI */
index b628abfffacc26a253214352b7de7b1580e4dfe6..eaa5c6e3fc9fc4465a277767b043612015090421 100644 (file)
@@ -596,7 +596,6 @@ static inline void pwm_remove_table(struct pwm_lookup *table, size_t num)
 #ifdef CONFIG_PWM_SYSFS
 void pwmchip_sysfs_export(struct pwm_chip *chip);
 void pwmchip_sysfs_unexport(struct pwm_chip *chip);
-void pwmchip_sysfs_unexport_children(struct pwm_chip *chip);
 #else
 static inline void pwmchip_sysfs_export(struct pwm_chip *chip)
 {
@@ -605,10 +604,6 @@ static inline void pwmchip_sysfs_export(struct pwm_chip *chip)
 static inline void pwmchip_sysfs_unexport(struct pwm_chip *chip)
 {
 }
-
-static inline void pwmchip_sysfs_unexport_children(struct pwm_chip *chip)
-{
-}
 #endif /* CONFIG_PWM_SYSFS */
 
 #endif /* __LINUX_PWM_H */
index 3bcd67fd554851bbf7f928989d5f78817d547efc..dd464943f717a476964000348e87103b2063b6bb 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  */
index 13aeaf5a4bd4e30275da374ef384091dad9d4484..1f7dced2bba66b8afe6f0824ee8dba615f0fb8cc 100644 (file)
@@ -20,7 +20,7 @@ struct random_ready_callback {
 
 extern void add_device_randomness(const void *, unsigned int);
 
-#if defined(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) && !defined(__CHECKER__)
+#if defined(LATENT_ENTROPY_PLUGIN) && !defined(__CHECKER__)
 static inline void add_latent_entropy(void)
 {
        add_device_randomness((const void *)&latent_entropy,
index e63799a6e89515d0893606530b07e101f39c52fb..3734cd8f38a896d55af2ff3a3f3518707444c4fe 100644 (file)
@@ -14,6 +14,7 @@ struct device;
 #define SYS_POWER_OFF  0x0003  /* Notify of system power off */
 
 enum reboot_mode {
+       REBOOT_UNDEFINED = -1,
        REBOOT_COLD = 0,
        REBOOT_WARM,
        REBOOT_HARD,
@@ -21,6 +22,7 @@ enum reboot_mode {
        REBOOT_GPIO,
 };
 extern enum reboot_mode reboot_mode;
+extern enum reboot_mode panic_reboot_mode;
 
 enum reboot_type {
        BOOT_TRIPLE     = 't',
index 95d555c2130a0b97581a932e1a8fd62f62f4d2f3..e7793fc0fa932ee3e41d49756e75bf829a743452 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _LINUX_RESET_H_
 #define _LINUX_RESET_H_
 
+#include <linux/err.h>
+#include <linux/errno.h>
 #include <linux/types.h>
 
 struct device;
diff --git a/include/linux/rtc/rtc-omap.h b/include/linux/rtc/rtc-omap.h
new file mode 100644 (file)
index 0000000..9f03a32
--- /dev/null
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LINUX_RTCOMAP_H_
+#define _LINUX_RTCOMAP_H_
+
+int omap_rtc_power_off_program(struct device *dev);
+#endif /* _LINUX_RTCOMAP_H_ */
index a2cd15855bad87f3b10540e5c045c6a36db051af..11837410690f01d72712287068953bd8729d464a 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/latencytop.h>
 #include <linux/sched/prio.h>
 #include <linux/signal_types.h>
-#include <linux/psi_types.h>
 #include <linux/mm_types_task.h>
 #include <linux/task_io_accounting.h>
 #include <linux/rseq.h>
index e412c092c1e821edd18f0c9dc0ed734ced5d6234..38a0f0785323759dcf9c0dcdc8b0a897600c61e4 100644 (file)
@@ -271,17 +271,18 @@ static inline int signal_group_exit(const struct signal_struct *sig)
 extern void flush_signals(struct task_struct *);
 extern void ignore_signals(struct task_struct *);
 extern void flush_signal_handlers(struct task_struct *, int force_default);
-extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, kernel_siginfo_t *info);
+extern int dequeue_signal(struct task_struct *task,
+                         sigset_t *mask, kernel_siginfo_t *info);
 
 static inline int kernel_dequeue_signal(void)
 {
-       struct task_struct *tsk = current;
+       struct task_struct *task = current;
        kernel_siginfo_t __info;
        int ret;
 
-       spin_lock_irq(&tsk->sighand->siglock);
-       ret = dequeue_signal(tsk, &tsk->blocked, &__info);
-       spin_unlock_irq(&tsk->sighand->siglock);
+       spin_lock_irq(&task->sighand->siglock);
+       ret = dequeue_signal(task, &task->blocked, &__info);
+       spin_unlock_irq(&task->sighand->siglock);
 
        return ret;
 }
@@ -419,18 +420,18 @@ static inline void set_restore_sigmask(void)
        WARN_ON(!test_thread_flag(TIF_SIGPENDING));
 }
 
-static inline void clear_tsk_restore_sigmask(struct task_struct *tsk)
+static inline void clear_tsk_restore_sigmask(struct task_struct *task)
 {
-       clear_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK);
+       clear_tsk_thread_flag(task, TIF_RESTORE_SIGMASK);
 }
 
 static inline void clear_restore_sigmask(void)
 {
        clear_thread_flag(TIF_RESTORE_SIGMASK);
 }
-static inline bool test_tsk_restore_sigmask(struct task_struct *tsk)
+static inline bool test_tsk_restore_sigmask(struct task_struct *task)
 {
-       return test_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK);
+       return test_tsk_thread_flag(task, TIF_RESTORE_SIGMASK);
 }
 static inline bool test_restore_sigmask(void)
 {
@@ -449,9 +450,9 @@ static inline void set_restore_sigmask(void)
        current->restore_sigmask = true;
        WARN_ON(!test_thread_flag(TIF_SIGPENDING));
 }
-static inline void clear_tsk_restore_sigmask(struct task_struct *tsk)
+static inline void clear_tsk_restore_sigmask(struct task_struct *task)
 {
-       tsk->restore_sigmask = false;
+       task->restore_sigmask = false;
 }
 static inline void clear_restore_sigmask(void)
 {
@@ -461,9 +462,9 @@ static inline bool test_restore_sigmask(void)
 {
        return current->restore_sigmask;
 }
-static inline bool test_tsk_restore_sigmask(struct task_struct *tsk)
+static inline bool test_tsk_restore_sigmask(struct task_struct *task)
 {
-       return tsk->restore_sigmask;
+       return task->restore_sigmask;
 }
 static inline bool test_and_clear_restore_sigmask(void)
 {
@@ -617,9 +618,9 @@ static inline struct pid *task_session(struct task_struct *task)
        return task->signal->pids[PIDTYPE_SID];
 }
 
-static inline int get_nr_threads(struct task_struct *tsk)
+static inline int get_nr_threads(struct task_struct *task)
 {
-       return tsk->signal->nr_threads;
+       return task->signal->nr_threads;
 }
 
 static inline bool thread_group_leader(struct task_struct *p)
@@ -658,35 +659,35 @@ static inline int thread_group_empty(struct task_struct *p)
 #define delay_group_leader(p) \
                (thread_group_leader(p) && !thread_group_empty(p))
 
-extern struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
+extern struct sighand_struct *__lock_task_sighand(struct task_struct *task,
                                                        unsigned long *flags);
 
-static inline struct sighand_struct *lock_task_sighand(struct task_struct *tsk,
+static inline struct sighand_struct *lock_task_sighand(struct task_struct *task,
                                                       unsigned long *flags)
 {
        struct sighand_struct *ret;
 
-       ret = __lock_task_sighand(tsk, flags);
-       (void)__cond_lock(&tsk->sighand->siglock, ret);
+       ret = __lock_task_sighand(task, flags);
+       (void)__cond_lock(&task->sighand->siglock, ret);
        return ret;
 }
 
-static inline void unlock_task_sighand(struct task_struct *tsk,
+static inline void unlock_task_sighand(struct task_struct *task,
                                                unsigned long *flags)
 {
-       spin_unlock_irqrestore(&tsk->sighand->siglock, *flags);
+       spin_unlock_irqrestore(&task->sighand->siglock, *flags);
 }
 
-static inline unsigned long task_rlimit(const struct task_struct *tsk,
+static inline unsigned long task_rlimit(const struct task_struct *task,
                unsigned int limit)
 {
-       return READ_ONCE(tsk->signal->rlim[limit].rlim_cur);
+       return READ_ONCE(task->signal->rlim[limit].rlim_cur);
 }
 
-static inline unsigned long task_rlimit_max(const struct task_struct *tsk,
+static inline unsigned long task_rlimit_max(const struct task_struct *task,
                unsigned int limit)
 {
-       return READ_ONCE(tsk->signal->rlim[limit].rlim_max);
+       return READ_ONCE(task->signal->rlim[limit].rlim_max);
 }
 
 static inline unsigned long rlimit(unsigned int limit)
index 9a5eafb7145bb1733fa8ffeaf26ff15445ee013c..abc7de77b9881a0a3ab81c50f103f0b1b782fc68 100644 (file)
@@ -61,9 +61,6 @@ struct kmem_cache {
        atomic_t allocmiss;
        atomic_t freehit;
        atomic_t freemiss;
-#ifdef CONFIG_DEBUG_SLAB_LEAK
-       atomic_t store_user_clean;
-#endif
 
        /*
         * If debugging is enabled, then the allocator can add additional
diff --git a/include/linux/soc/cirrus/ep93xx.h b/include/linux/soc/cirrus/ep93xx.h
new file mode 100644 (file)
index 0000000..56fbe2d
--- /dev/null
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SOC_EP93XX_H
+#define _SOC_EP93XX_H
+
+struct platform_device;
+
+#define EP93XX_CHIP_REV_D0     3
+#define EP93XX_CHIP_REV_D1     4
+#define EP93XX_CHIP_REV_E0     5
+#define EP93XX_CHIP_REV_E1     6
+#define EP93XX_CHIP_REV_E2     7
+
+#ifdef CONFIG_ARCH_EP93XX
+int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);
+void ep93xx_pwm_release_gpio(struct platform_device *pdev);
+int ep93xx_ide_acquire_gpio(struct platform_device *pdev);
+void ep93xx_ide_release_gpio(struct platform_device *pdev);
+int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
+void ep93xx_keypad_release_gpio(struct platform_device *pdev);
+int ep93xx_i2s_acquire(void);
+void ep93xx_i2s_release(void);
+unsigned int ep93xx_chip_revision(void);
+
+#else
+static inline int ep93xx_pwm_acquire_gpio(struct platform_device *pdev) { return 0; }
+static inline void ep93xx_pwm_release_gpio(struct platform_device *pdev) {}
+static inline int ep93xx_ide_acquire_gpio(struct platform_device *pdev) { return 0; }
+static inline void ep93xx_ide_release_gpio(struct platform_device *pdev) {}
+static inline int ep93xx_keypad_acquire_gpio(struct platform_device *pdev) { return 0; }
+static inline void ep93xx_keypad_release_gpio(struct platform_device *pdev) {}
+static inline int ep93xx_i2s_acquire(void) { return 0; }
+static inline void ep93xx_i2s_release(void) {}
+static inline unsigned int ep93xx_chip_revision(void) { return 0; }
+
+#endif
+
+#endif
diff --git a/include/linux/soc/ixp4xx/npe.h b/include/linux/soc/ixp4xx/npe.h
new file mode 100644 (file)
index 0000000..2a91f46
--- /dev/null
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __IXP4XX_NPE_H
+#define __IXP4XX_NPE_H
+
+#include <linux/kernel.h>
+
+extern const char *npe_names[];
+
+struct npe_regs {
+       u32 exec_addr, exec_data, exec_status_cmd, exec_count;
+       u32 action_points[4];
+       u32 watchpoint_fifo, watch_count;
+       u32 profile_count;
+       u32 messaging_status, messaging_control;
+       u32 mailbox_status, /*messaging_*/ in_out_fifo;
+};
+
+struct npe {
+       struct npe_regs __iomem *regs;
+       int id;
+       int valid;
+};
+
+
+static inline const char *npe_name(struct npe *npe)
+{
+       return npe_names[npe->id];
+}
+
+int npe_running(struct npe *npe);
+int npe_send_message(struct npe *npe, const void *msg, const char *what);
+int npe_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_load_firmware(struct npe *npe, const char *name, struct device *dev);
+struct npe *npe_request(unsigned id);
+void npe_release(struct npe *npe);
+
+#endif /* __IXP4XX_NPE_H */
diff --git a/include/linux/soc/ixp4xx/qmgr.h b/include/linux/soc/ixp4xx/qmgr.h
new file mode 100644 (file)
index 0000000..bed8ee9
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef IXP4XX_QMGR_H
+#define IXP4XX_QMGR_H
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+
+#define DEBUG_QMGR     0
+
+#define HALF_QUEUES    32
+#define QUEUES         64
+#define MAX_QUEUE_LENGTH 4     /* in dwords */
+
+#define QUEUE_STAT1_EMPTY              1 /* queue status bits */
+#define QUEUE_STAT1_NEARLY_EMPTY       2
+#define QUEUE_STAT1_NEARLY_FULL                4
+#define QUEUE_STAT1_FULL               8
+#define QUEUE_STAT2_UNDERFLOW          1
+#define QUEUE_STAT2_OVERFLOW           2
+
+#define QUEUE_WATERMARK_0_ENTRIES      0
+#define QUEUE_WATERMARK_1_ENTRY                1
+#define QUEUE_WATERMARK_2_ENTRIES      2
+#define QUEUE_WATERMARK_4_ENTRIES      3
+#define QUEUE_WATERMARK_8_ENTRIES      4
+#define QUEUE_WATERMARK_16_ENTRIES     5
+#define QUEUE_WATERMARK_32_ENTRIES     6
+#define QUEUE_WATERMARK_64_ENTRIES     7
+
+/* queue interrupt request conditions */
+#define QUEUE_IRQ_SRC_EMPTY            0
+#define QUEUE_IRQ_SRC_NEARLY_EMPTY     1
+#define QUEUE_IRQ_SRC_NEARLY_FULL      2
+#define QUEUE_IRQ_SRC_FULL             3
+#define QUEUE_IRQ_SRC_NOT_EMPTY                4
+#define QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY 5
+#define QUEUE_IRQ_SRC_NOT_NEARLY_FULL  6
+#define QUEUE_IRQ_SRC_NOT_FULL         7
+
+struct qmgr_regs {
+       u32 acc[QUEUES][MAX_QUEUE_LENGTH]; /* 0x000 - 0x3FF */
+       u32 stat1[4];           /* 0x400 - 0x40F */
+       u32 stat2[2];           /* 0x410 - 0x417 */
+       u32 statne_h;           /* 0x418 - queue nearly empty */
+       u32 statf_h;            /* 0x41C - queue full */
+       u32 irqsrc[4];          /* 0x420 - 0x42F IRC source */
+       u32 irqen[2];           /* 0x430 - 0x437 IRQ enabled */
+       u32 irqstat[2];         /* 0x438 - 0x43F - IRQ access only */
+       u32 reserved[1776];
+       u32 sram[2048];         /* 0x2000 - 0x3FFF - config and buffer */
+};
+
+void qmgr_put_entry(unsigned int queue, u32 val);
+u32 qmgr_get_entry(unsigned int queue);
+int qmgr_stat_empty(unsigned int queue);
+int qmgr_stat_below_low_watermark(unsigned int queue);
+int qmgr_stat_full(unsigned int queue);
+int qmgr_stat_overflow(unsigned int queue);
+void qmgr_release_queue(unsigned int queue);
+void qmgr_set_irq(unsigned int queue, int src,
+                 void (*handler)(void *pdev), void *pdev);
+void qmgr_enable_irq(unsigned int queue);
+void qmgr_disable_irq(unsigned int queue);
+
+/* request_ and release_queue() must be called from non-IRQ context */
+
+#if DEBUG_QMGR
+extern char qmgr_queue_descs[QUEUES][32];
+
+int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+                      unsigned int nearly_empty_watermark,
+                      unsigned int nearly_full_watermark,
+                      const char *desc_format, const char* name);
+#else
+int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+                        unsigned int nearly_empty_watermark,
+                        unsigned int nearly_full_watermark);
+#define qmgr_request_queue(queue, len, nearly_empty_watermark,         \
+                          nearly_full_watermark, desc_format, name)    \
+       __qmgr_request_queue(queue, len, nearly_empty_watermark,        \
+                            nearly_full_watermark)
+#endif
+
+#endif
index e52385340b3b874c3d047b01873791b2bfbd5397..1afe38eb33f7eab286c88f99ad969c5382952c3b 100644 (file)
@@ -271,6 +271,7 @@ struct svc_rqst {
 #define        RQ_VICTIM       (5)                     /* about to be shut down */
 #define        RQ_BUSY         (6)                     /* request is busy */
 #define        RQ_DATA         (7)                     /* request has data */
+#define RQ_AUTHERR     (8)                     /* Request status is auth error */
        unsigned long           rq_flags;       /* flags field */
        ktime_t                 rq_qtime;       /* enqueue time */
 
@@ -382,6 +383,16 @@ struct svc_deferred_req {
        __be32                  args[0];
 };
 
+struct svc_process_info {
+       union {
+               int  (*dispatch)(struct svc_rqst *, __be32 *);
+               struct {
+                       unsigned int lovers;
+                       unsigned int hivers;
+               } mismatch;
+       };
+};
+
 /*
  * List of RPC programs on the same transport endpoint
  */
@@ -396,6 +407,14 @@ struct svc_program {
        char *                  pg_class;       /* class name: services sharing authentication */
        struct svc_stat *       pg_stats;       /* rpc statistics */
        int                     (*pg_authenticate)(struct svc_rqst *);
+       __be32                  (*pg_init_request)(struct svc_rqst *,
+                                                  const struct svc_program *,
+                                                  struct svc_process_info *);
+       int                     (*pg_rpcbind_set)(struct net *net,
+                                                 const struct svc_program *,
+                                                 u32 version, int family,
+                                                 unsigned short proto,
+                                                 unsigned short port);
 };
 
 /*
@@ -504,6 +523,20 @@ unsigned int          svc_fill_write_vector(struct svc_rqst *rqstp,
 char             *svc_fill_symlink_pathname(struct svc_rqst *rqstp,
                                             struct kvec *first, void *p,
                                             size_t total);
+__be32            svc_return_autherr(struct svc_rqst *rqstp, __be32 auth_err);
+__be32            svc_generic_init_request(struct svc_rqst *rqstp,
+                                           const struct svc_program *progp,
+                                           struct svc_process_info *procinfo);
+int               svc_generic_rpcbind_set(struct net *net,
+                                          const struct svc_program *progp,
+                                          u32 version, int family,
+                                          unsigned short proto,
+                                          unsigned short port);
+int               svc_rpcbind_set_version(struct net *net,
+                                          const struct svc_program *progp,
+                                          u32 version, int family,
+                                          unsigned short proto,
+                                          unsigned short port);
 
 #define        RPC_MAX_ADDRBUFLEN      (63U)
 
index b3f9577e17d6d669ca892bc206229a1e88771354..ea6f46be9cb74384c402ca20f957fb73cedb22ad 100644 (file)
@@ -86,6 +86,7 @@ struct svc_xprt {
        struct list_head        xpt_users;      /* callbacks on free */
 
        struct net              *xpt_net;
+       const struct cred       *xpt_cred;
        struct rpc_xprt         *xpt_bc_xprt;   /* NFSv4.1 backchannel */
        struct rpc_xprt_switch  *xpt_bc_xps;    /* NFSv4.1 backchannel */
 };
@@ -119,7 +120,8 @@ void        svc_unreg_xprt_class(struct svc_xprt_class *);
 void   svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *,
                      struct svc_serv *);
 int    svc_create_xprt(struct svc_serv *, const char *, struct net *,
-                       const int, const unsigned short, int);
+                       const int, const unsigned short, int,
+                       const struct cred *);
 void   svc_xprt_do_enqueue(struct svc_xprt *xprt);
 void   svc_xprt_enqueue(struct svc_xprt *xprt);
 void   svc_xprt_put(struct svc_xprt *xprt);
index 119718a922f2c3bb7f42f50cfb61f1cf1b552971..771baadaee9d6a74121011942a5be45f31f332a4 100644 (file)
@@ -59,7 +59,8 @@ void          svc_drop(struct svc_rqst *);
 void           svc_sock_update_bufs(struct svc_serv *serv);
 bool           svc_alien_sock(struct net *net, int fd);
 int            svc_addsock(struct svc_serv *serv, const int fd,
-                                       char *name_return, const size_t len);
+                                       char *name_return, const size_t len,
+                                       const struct cred *cred);
 void           svc_init_xprt_sock(void);
 void           svc_cleanup_xprt_sock(void);
 struct svc_xprt *svc_sock_create(struct svc_serv *serv, int prot);
index 52a079b3a9a6d0d1fb889343c3d75a605a6c8f80..0cfc34ac37fb94e3a7621570521d4490915b6c02 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/cdev.h>
 
 #define SWITCHTEC_MRPC_PAYLOAD_SIZE 1024
-#define SWITCHTEC_MAX_PFF_CSR 48
+#define SWITCHTEC_MAX_PFF_CSR 255
 
 #define SWITCHTEC_EVENT_OCCURRED BIT(0)
 #define SWITCHTEC_EVENT_CLEAR    BIT(0)
index 5f4705f46c2f9ab8aae927304443807de8e27f4d..15a4ca5d709995b55c81d08615ce7f8f68c223e7 100644 (file)
@@ -442,11 +442,16 @@ void thermal_zone_device_update(struct thermal_zone_device *,
                                enum thermal_notify_event);
 void thermal_zone_set_trips(struct thermal_zone_device *);
 
-struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
-               const struct thermal_cooling_device_ops *);
+struct thermal_cooling_device *thermal_cooling_device_register(const char *,
+               void *, const struct thermal_cooling_device_ops *);
 struct thermal_cooling_device *
-thermal_of_cooling_device_register(struct device_node *np, char *, void *,
+thermal_of_cooling_device_register(struct device_node *np, const char *, void *,
                                   const struct thermal_cooling_device_ops *);
+struct thermal_cooling_device *
+devm_thermal_of_cooling_device_register(struct device *dev,
+                               struct device_node *np,
+                               char *type, void *devdata,
+                               const struct thermal_cooling_device_ops *ops);
 void thermal_cooling_device_unregister(struct thermal_cooling_device *);
 struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name);
 int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
@@ -503,6 +508,14 @@ static inline struct thermal_cooling_device *
 thermal_of_cooling_device_register(struct device_node *np,
        char *type, void *devdata, const struct thermal_cooling_device_ops *ops)
 { return ERR_PTR(-ENODEV); }
+static inline struct thermal_cooling_device *
+devm_thermal_of_cooling_device_register(struct device *dev,
+                               struct device_node *np,
+                               char *type, void *devdata,
+                               const struct thermal_cooling_device_ops *ops)
+{
+       return ERR_PTR(-ENODEV);
+}
 static inline void thermal_cooling_device_unregister(
        struct thermal_cooling_device *cdev)
 { }
index 53604b087f2c0b24993ea357b42103a8e07a4971..2fc854155c2786e621c8a28ea754657f705fa2ab 100644 (file)
@@ -55,6 +55,7 @@ struct ti_emif_pm_data {
 struct ti_emif_pm_functions {
        u32 save_context;
        u32 restore_context;
+       u32 run_hw_leveling;
        u32 enter_sr;
        u32 exit_sr;
        u32 abort_sr;
@@ -126,6 +127,8 @@ static inline void ti_emif_asm_offsets(void)
               offsetof(struct ti_emif_pm_functions, save_context));
        DEFINE(EMIF_PM_RESTORE_CONTEXT_OFFSET,
               offsetof(struct ti_emif_pm_functions, restore_context));
+       DEFINE(EMIF_PM_RUN_HW_LEVELING,
+              offsetof(struct ti_emif_pm_functions, run_hw_leveling));
        DEFINE(EMIF_PM_ENTER_SR_OFFSET,
               offsetof(struct ti_emif_pm_functions, enter_sr));
        DEFINE(EMIF_PM_EXIT_SR_OFFSET,
index 9c3186578ce06d2b872e6e93ad1da0e27cf36152..86b019aa28398fdf40748b30aeedd4cc8c6faa21 100644 (file)
@@ -548,4 +548,19 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
 
 #define TRACE_EVENT_PERF_PERM(event, expr...)
 
+#define DECLARE_EVENT_NOP(name, proto, args)                           \
+       static inline void trace_##name(proto)                          \
+       { }                                                             \
+       static inline bool trace_##name##_enabled(void)                 \
+       {                                                               \
+               return false;                                           \
+       }
+
+#define TRACE_EVENT_NOP(name, proto, args, struct, assign, print)      \
+       DECLARE_EVENT_NOP(name, PARAMS(proto), PARAMS(args))
+
+#define DECLARE_EVENT_CLASS_NOP(name, proto, args, tstruct, assign, print)
+#define DEFINE_EVENT_NOP(template, name, proto, args)                  \
+       DECLARE_EVENT_NOP(name, PARAMS(proto), PARAMS(args))
+
 #endif /* ifdef TRACE_EVENT (see note above) */
index 37c9eba75c983a7b2488f1a18c2c0f1d520a5425..ac9d71e24b81ac91ab38abdea32c364a2884cedb 100644 (file)
@@ -28,6 +28,8 @@
 #define UFFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK)
 #define UFFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS)
 
+extern int sysctl_unprivileged_userfaultfd;
+
 extern vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason);
 
 extern ssize_t mcopy_atomic(struct mm_struct *dst_mm, unsigned long dst_start,
index 673fe3ef360788642edf1f4c448f3618a556373f..15f906e4a748f7495c36ef1ee189bd1c883c9e39 100644 (file)
@@ -90,23 +90,6 @@ dma_addr_t virtqueue_get_desc_addr(struct virtqueue *vq);
 dma_addr_t virtqueue_get_avail_addr(struct virtqueue *vq);
 dma_addr_t virtqueue_get_used_addr(struct virtqueue *vq);
 
-/*
- * Legacy accessors -- in almost all cases, these are the wrong functions
- * to use.
- */
-static inline void *virtqueue_get_desc(struct virtqueue *vq)
-{
-       return virtqueue_get_vring(vq)->desc;
-}
-static inline void *virtqueue_get_avail(struct virtqueue *vq)
-{
-       return virtqueue_get_vring(vq)->avail;
-}
-static inline void *virtqueue_get_used(struct virtqueue *vq)
-{
-       return virtqueue_get_vring(vq)->used;
-}
-
 /**
  * virtio_device - representation of a device using virtio
  * @index: unique position on the virtio bus
index 2db8d60981fe51c08b841ab50f46f2c7e640c080..bdeda4b079fe8987699fe620f3b1f51d2b875f2d 100644 (file)
@@ -26,7 +26,7 @@ struct reclaim_stat {
        unsigned nr_congested;
        unsigned nr_writeback;
        unsigned nr_immediate;
-       unsigned nr_activate;
+       unsigned nr_activate[2];
        unsigned nr_ref_keep;
        unsigned nr_unmap_fail;
 };
index 2b0072fa5e92d2eb4ef6d779eb95be3f4d7e9ae3..7dec36aecbd9fe239ba1b94f81c729e6665d6bd4 100644 (file)
@@ -305,6 +305,19 @@ do {                                                                       \
        __ret;                                                          \
 })
 
+#define __wait_var_event_interruptible(var, condition)                 \
+       ___wait_var_event(var, condition, TASK_INTERRUPTIBLE, 0, 0,     \
+                         schedule())
+
+#define wait_var_event_interruptible(var, condition)                   \
+({                                                                     \
+       int __ret = 0;                                                  \
+       might_sleep();                                                  \
+       if (!(condition))                                               \
+               __ret = __wait_var_event_interruptible(var, condition); \
+       __ret;                                                          \
+})
+
 /**
  * clear_and_wake_up_bit - clear a bit and wake up anyone waiting on that bit
  *
index 5c31a768249201d48459e6f603d9a00df5e8cf14..f76d2f25a82474f1ab80eb7dd7004b94f288900d 100644 (file)
@@ -92,7 +92,7 @@ struct vpbe_config {
        struct encoder_config_info *ext_encoders;
        /* amplifier information goes here */
        struct amp_config_info *amp;
-       int num_outputs;
+       unsigned int num_outputs;
        /* Order is venc outputs followed by LCD and then external encoders */
        struct vpbe_output *outputs;
 };
index 78c856cba4f538c078fada09ef3238c2bc220069..93358bfc0e1b997c1c58d536dd02ff452c26cb0b 100644 (file)
@@ -45,6 +45,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *,
                                           gfp_t,
                                           rxrpc_notify_rx_t,
                                           bool,
+                                          bool,
                                           unsigned int);
 int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *,
                           struct msghdr *, size_t,
@@ -68,5 +69,7 @@ u32 rxrpc_kernel_get_epoch(struct socket *, struct rxrpc_call *);
 bool rxrpc_kernel_get_reply_time(struct socket *, struct rxrpc_call *,
                                 ktime_t *);
 bool rxrpc_kernel_call_is_complete(struct rxrpc_call *);
+void rxrpc_kernel_set_max_life(struct socket *, struct rxrpc_call *,
+                              unsigned long);
 
 #endif /* _NET_RXRPC_H */
index 6aaaadd6a413c9bf1d8600325d171fb69006d3be..6852948177129bd5719e63acdae3d42a7b6b429a 100644 (file)
@@ -99,24 +99,9 @@ struct __dsa_skb_cb {
 
 #define DSA_SKB_CB(skb) ((struct dsa_skb_cb *)((skb)->cb))
 
-#define DSA_SKB_CB_COPY(nskb, skb)             \
-       { *__DSA_SKB_CB(nskb) = *__DSA_SKB_CB(skb); }
-
-#define DSA_SKB_CB_ZERO(skb)                   \
-       { *__DSA_SKB_CB(skb) = (struct __dsa_skb_cb) {0}; }
-
 #define DSA_SKB_CB_PRIV(skb)                   \
        ((void *)(skb)->cb + offsetof(struct __dsa_skb_cb, priv))
 
-#define DSA_SKB_CB_CLONE(_clone, _skb)         \
-       {                                       \
-               struct sk_buff *clone = _clone; \
-               struct sk_buff *skb = _skb;     \
-                                               \
-               DSA_SKB_CB_COPY(clone, skb);    \
-               DSA_SKB_CB(skb)->clone = clone; \
-       }
-
 struct dsa_switch_tree {
        struct list_head        list;
 
index 482337af06b8d5a1c226b4b18bce2956b37768d1..532fd784e86cbd96798f0d7f8301cdc9fc6305cd 100644 (file)
 #define _LINUX_MFD_SYSCON_ATMEL_SFR_H
 
 #define AT91_SFR_DDRCFG                0x04    /* DDR Configuration Register */
+#define AT91_SFR_CCFG_EBICSA   0x04    /* EBI Chip Select Register */
 /* 0x08 ~ 0x0c: Reserved */
 #define AT91_SFR_OHCIICR       0x10    /* OHCI INT Configuration Register */
 #define AT91_SFR_OHCIISR       0x14    /* OHCI INT Status Register */
 #define AT91_SFR_UTMICKTRIM    0x30    /* UTMI Clock Trimming Register */
+#define AT91_SFR_UTMISWAP      0x3c    /* UTMI DP/DM Pin Swapping Register */
+#define AT91_SFR_LS            0x7c    /* Light Sleep Register */
 #define AT91_SFR_I2SCLKSEL     0x90    /* I2SC Register */
+#define AT91_SFR_WPMR          0xe4    /* Write Protection Mode Register */
 
 /* Field definitions */
-#define AT91_OHCIICR_SUSPEND_A BIT(8)
-#define AT91_OHCIICR_SUSPEND_B BIT(9)
-#define AT91_OHCIICR_SUSPEND_C BIT(10)
+#define AT91_SFR_CCFG_EBI_CSA(cs, val)         ((val) << (cs))
+#define AT91_SFR_CCFG_EBI_DBPUC                        BIT(8)
+#define AT91_SFR_CCFG_EBI_DBPDC                        BIT(9)
+#define AT91_SFR_CCFG_EBI_DRIVE                        BIT(17)
+#define AT91_SFR_CCFG_NFD0_ON_D16              BIT(24)
+#define AT91_SFR_CCFG_DDR_MP_EN                        BIT(25)
 
-#define AT91_OHCIICR_USB_SUSPEND       (AT91_OHCIICR_SUSPEND_A | \
-                                        AT91_OHCIICR_SUSPEND_B | \
-                                        AT91_OHCIICR_SUSPEND_C)
+#define AT91_SFR_OHCIICR_RES(x)                        BIT(x)
+#define AT91_SFR_OHCIICR_ARIE                  BIT(4)
+#define AT91_SFR_OHCIICR_APPSTART              BIT(5)
+#define AT91_SFR_OHCIICR_USB_SUSP(x)           BIT(8 + (x))
+#define AT91_SFR_OHCIICR_UDPPUDIS              BIT(23)
+#define AT91_OHCIICR_USB_SUSPEND               GENMASK(10, 8)
 
-#define AT91_UTMICKTRIM_FREQ   GENMASK(1, 0)
+#define AT91_SFR_OHCIISR_RIS(x)                        BIT(x)
+
+#define AT91_UTMICKTRIM_FREQ                   GENMASK(1, 0)
+
+#define AT91_SFR_UTMISWAP_PORT(x)              BIT(x)
+
+#define AT91_SFR_LS_VALUE(x)                   BIT(x)
+#define AT91_SFR_LS_MEM_POWER_GATING_ULP1_EN   BIT(16)
+
+#define AT91_SFR_WPMR_WPEN                     BIT(0)
+#define AT91_SFR_WPMR_WPKEY_MASK               GENMASK(31, 8)
 
 #endif /* _LINUX_MFD_SYSCON_ATMEL_SFR_H */
index 896c3f45503b3b81ae86b9ea334bfb2d2a845b24..e8346784cf3f8d1afdf23d3c2e0f7e99ca909538 100644 (file)
@@ -81,6 +81,7 @@ struct hdac_device {
        atomic_t in_pm;         /* suspend/resume being performed */
 
        /* sysfs */
+       struct mutex widget_lock;
        struct hdac_widget_tree *widgets;
 
        /* regmap */
index cb30c5532144883c7f534a5d7340bb294b49b998..bd75f97867b99a64ba0706a516cb06f0e4cc5a42 100644 (file)
                assign, print, reg, unreg)                      \
        DEFINE_TRACE_FN(name, reg, unreg)
 
+#undef TRACE_EVENT_NOP
+#define TRACE_EVENT_NOP(name, proto, args, struct, assign, print)
+
+#undef DEFINE_EVENT_NOP
+#define DEFINE_EVENT_NOP(template, name, proto, args)
+
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, name, proto, args) \
        DEFINE_TRACE(name)
 #undef TRACE_EVENT_FN
 #undef TRACE_EVENT_FN_COND
 #undef TRACE_EVENT_CONDITION
+#undef TRACE_EVENT_NOP
+#undef DEFINE_EVENT_NOP
 #undef DECLARE_EVENT_CLASS
 #undef DEFINE_EVENT
 #undef DEFINE_EVENT_FN
index 6074eff3d766d6bde63975a69df795e23b65bd79..e5bf6ee4e8145ac585d56c99810a5f97b5db58af 100644 (file)
@@ -64,6 +64,7 @@ DEFINE_EVENT(mm_compaction_isolate_template, mm_compaction_isolate_freepages,
        TP_ARGS(start_pfn, end_pfn, nr_scanned, nr_taken)
 );
 
+#ifdef CONFIG_COMPACTION
 TRACE_EVENT(mm_compaction_migratepages,
 
        TP_PROTO(unsigned long nr_all,
@@ -132,7 +133,6 @@ TRACE_EVENT(mm_compaction_begin,
                __entry->sync ? "sync" : "async")
 );
 
-#ifdef CONFIG_COMPACTION
 TRACE_EVENT(mm_compaction_end,
        TP_PROTO(unsigned long zone_start, unsigned long migrate_pfn,
                unsigned long free_pfn, unsigned long zone_end, bool sync,
@@ -166,7 +166,6 @@ TRACE_EVENT(mm_compaction_end,
                __entry->sync ? "sync" : "async",
                __print_symbolic(__entry->status, COMPACTION_STATUS))
 );
-#endif
 
 TRACE_EVENT(mm_compaction_try_to_compact_pages,
 
@@ -189,13 +188,12 @@ TRACE_EVENT(mm_compaction_try_to_compact_pages,
                __entry->prio = prio;
        ),
 
-       TP_printk("order=%d gfp_mask=0x%x priority=%d",
+       TP_printk("order=%d gfp_mask=%s priority=%d",
                __entry->order,
-               __entry->gfp_mask,
+               show_gfp_flags(__entry->gfp_mask),
                __entry->prio)
 );
 
-#ifdef CONFIG_COMPACTION
 DECLARE_EVENT_CLASS(mm_compaction_suitable_template,
 
        TP_PROTO(struct zone *zone,
@@ -296,7 +294,6 @@ DEFINE_EVENT(mm_compaction_defer_template, mm_compaction_defer_reset,
 
        TP_ARGS(zone, order)
 );
-#endif
 
 TRACE_EVENT(mm_compaction_kcompactd_sleep,
 
@@ -352,6 +349,7 @@ DEFINE_EVENT(kcompactd_wake_template, mm_compaction_kcompactd_wake,
 
        TP_ARGS(nid, order, classzone_idx)
 );
+#endif
 
 #endif /* _TRACE_COMPACTION_H */
 
index a3916b4dd57ed2dc227ec78437524460616e8ae0..53b96f12300c18cdfe7dac1d3535322d0ae0d622 100644 (file)
@@ -533,6 +533,37 @@ TRACE_EVENT(f2fs_truncate_partial_nodes,
                __entry->err)
 );
 
+TRACE_EVENT(f2fs_file_write_iter,
+
+       TP_PROTO(struct inode *inode, unsigned long offset,
+               unsigned long length, int ret),
+
+       TP_ARGS(inode, offset, length, ret),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(unsigned long, offset)
+               __field(unsigned long, length)
+               __field(int,    ret)
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->ino    = inode->i_ino;
+               __entry->offset = offset;
+               __entry->length = length;
+               __entry->ret    = ret;
+       ),
+
+       TP_printk("dev = (%d,%d), ino = %lu, "
+               "offset = %lu, length = %lu, written(err) = %d",
+               show_dev_ino(__entry),
+               __entry->offset,
+               __entry->length,
+               __entry->ret)
+);
+
 TRACE_EVENT(f2fs_map_blocks,
        TP_PROTO(struct inode *inode, struct f2fs_map_blocks *map, int ret),
 
@@ -1253,6 +1284,32 @@ DEFINE_EVENT(f2fs__page, f2fs_commit_inmem_page,
        TP_ARGS(page, type)
 );
 
+TRACE_EVENT(f2fs_filemap_fault,
+
+       TP_PROTO(struct inode *inode, pgoff_t index, unsigned long ret),
+
+       TP_ARGS(inode, index, ret),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(pgoff_t, index)
+               __field(unsigned long, ret)
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->ino    = inode->i_ino;
+               __entry->index  = index;
+               __entry->ret    = ret;
+       ),
+
+       TP_printk("dev = (%d,%d), ino = %lu, index = %lu, ret = %lx",
+               show_dev_ino(__entry),
+               (unsigned long)__entry->index,
+               __entry->ret)
+);
+
 TRACE_EVENT(f2fs_writepages,
 
        TP_PROTO(struct inode *inode, struct writeback_control *wbc, int type),
index 5c189a22c48973a86502710a45886271fe631c21..3aa9fd86d7486383015e7ba5eea91b28c470089b 100644 (file)
@@ -2,10 +2,6 @@
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM gpio
 
-#ifndef CONFIG_TRACING_EVENTS_GPIO
-#define NOTRACE
-#endif
-
 #if !defined(_TRACE_GPIO_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_GPIO_H
 
index 80339fd14c1caf106ba042ab50b8d9c17d00749e..02a3f78f7cd8ed9791a4dd80106f441414c9c855 100644 (file)
@@ -7,6 +7,12 @@
 
 #include <linux/tracepoint.h>
 
+#ifdef CONFIG_RCU_TRACE
+#define TRACE_EVENT_RCU TRACE_EVENT
+#else
+#define TRACE_EVENT_RCU TRACE_EVENT_NOP
+#endif
+
 /*
  * Tracepoint for start/end markers used for utilization calculations.
  * By convention, the string is of the following forms:
@@ -35,8 +41,6 @@ TRACE_EVENT(rcu_utilization,
        TP_printk("%s", __entry->s)
 );
 
-#ifdef CONFIG_RCU_TRACE
-
 #if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU)
 
 /*
@@ -62,7 +66,7 @@ TRACE_EVENT(rcu_utilization,
  *     "end": End a grace period.
  *     "cpuend": CPU first notices a grace-period end.
  */
-TRACE_EVENT(rcu_grace_period,
+TRACE_EVENT_RCU(rcu_grace_period,
 
        TP_PROTO(const char *rcuname, unsigned long gp_seq, const char *gpevent),
 
@@ -101,7 +105,7 @@ TRACE_EVENT(rcu_grace_period,
  * "Cleanup": Clean up rcu_node structure after previous GP.
  * "CleanupMore": Clean up, and another GP is needed.
  */
-TRACE_EVENT(rcu_future_grace_period,
+TRACE_EVENT_RCU(rcu_future_grace_period,
 
        TP_PROTO(const char *rcuname, unsigned long gp_seq,
                 unsigned long gp_seq_req, u8 level, int grplo, int grphi,
@@ -141,7 +145,7 @@ TRACE_EVENT(rcu_future_grace_period,
  * rcu_node structure, and the mask of CPUs that will be waited for.
  * All but the type of RCU are extracted from the rcu_node structure.
  */
-TRACE_EVENT(rcu_grace_period_init,
+TRACE_EVENT_RCU(rcu_grace_period_init,
 
        TP_PROTO(const char *rcuname, unsigned long gp_seq, u8 level,
                 int grplo, int grphi, unsigned long qsmask),
@@ -186,7 +190,7 @@ TRACE_EVENT(rcu_grace_period_init,
  *     "endwake": Woke piggybackers up.
  *     "done": Someone else did the expedited grace period for us.
  */
-TRACE_EVENT(rcu_exp_grace_period,
+TRACE_EVENT_RCU(rcu_exp_grace_period,
 
        TP_PROTO(const char *rcuname, unsigned long gpseq, const char *gpevent),
 
@@ -218,7 +222,7 @@ TRACE_EVENT(rcu_exp_grace_period,
  *     "nxtlvl": Advance to next level of rcu_node funnel
  *     "wait": Wait for someone else to do expedited GP
  */
-TRACE_EVENT(rcu_exp_funnel_lock,
+TRACE_EVENT_RCU(rcu_exp_funnel_lock,
 
        TP_PROTO(const char *rcuname, u8 level, int grplo, int grphi,
                 const char *gpevent),
@@ -269,7 +273,7 @@ TRACE_EVENT(rcu_exp_funnel_lock,
  *     "WaitQueue": Enqueue partially done, timed wait for it to complete.
  *     "WokeQueue": Partial enqueue now complete.
  */
-TRACE_EVENT(rcu_nocb_wake,
+TRACE_EVENT_RCU(rcu_nocb_wake,
 
        TP_PROTO(const char *rcuname, int cpu, const char *reason),
 
@@ -297,7 +301,7 @@ TRACE_EVENT(rcu_nocb_wake,
  * include SRCU), the grace-period number that the task is blocking
  * (the current or the next), and the task's PID.
  */
-TRACE_EVENT(rcu_preempt_task,
+TRACE_EVENT_RCU(rcu_preempt_task,
 
        TP_PROTO(const char *rcuname, int pid, unsigned long gp_seq),
 
@@ -324,7 +328,7 @@ TRACE_EVENT(rcu_preempt_task,
  * read-side critical section exiting that critical section.  Track the
  * type of RCU (which one day might include SRCU) and the task's PID.
  */
-TRACE_EVENT(rcu_unlock_preempted_task,
+TRACE_EVENT_RCU(rcu_unlock_preempted_task,
 
        TP_PROTO(const char *rcuname, unsigned long gp_seq, int pid),
 
@@ -353,7 +357,7 @@ TRACE_EVENT(rcu_unlock_preempted_task,
  * whether there are any blocked tasks blocking the current grace period.
  * All but the type of RCU are extracted from the rcu_node structure.
  */
-TRACE_EVENT(rcu_quiescent_state_report,
+TRACE_EVENT_RCU(rcu_quiescent_state_report,
 
        TP_PROTO(const char *rcuname, unsigned long gp_seq,
                 unsigned long mask, unsigned long qsmask,
@@ -396,7 +400,7 @@ TRACE_EVENT(rcu_quiescent_state_report,
  * state, which can be "dti" for dyntick-idle mode or "kick" when kicking
  * a CPU that has been in dyntick-idle mode for too long.
  */
-TRACE_EVENT(rcu_fqs,
+TRACE_EVENT_RCU(rcu_fqs,
 
        TP_PROTO(const char *rcuname, unsigned long gp_seq, int cpu, const char *qsevent),
 
@@ -436,7 +440,7 @@ TRACE_EVENT(rcu_fqs,
  * events use two separate counters, and that the "++=" and "--=" events
  * for irq/NMI will change the counter by two, otherwise by one.
  */
-TRACE_EVENT(rcu_dyntick,
+TRACE_EVENT_RCU(rcu_dyntick,
 
        TP_PROTO(const char *polarity, long oldnesting, long newnesting, atomic_t dynticks),
 
@@ -468,7 +472,7 @@ TRACE_EVENT(rcu_dyntick,
  * number of lazy callbacks queued, and the fourth element is the
  * total number of callbacks queued.
  */
-TRACE_EVENT(rcu_callback,
+TRACE_EVENT_RCU(rcu_callback,
 
        TP_PROTO(const char *rcuname, struct rcu_head *rhp, long qlen_lazy,
                 long qlen),
@@ -504,7 +508,7 @@ TRACE_EVENT(rcu_callback,
  * the fourth argument is the number of lazy callbacks queued, and the
  * fifth argument is the total number of callbacks queued.
  */
-TRACE_EVENT(rcu_kfree_callback,
+TRACE_EVENT_RCU(rcu_kfree_callback,
 
        TP_PROTO(const char *rcuname, struct rcu_head *rhp, unsigned long offset,
                 long qlen_lazy, long qlen),
@@ -539,7 +543,7 @@ TRACE_EVENT(rcu_kfree_callback,
  * the total number of callbacks queued, and the fourth argument is
  * the current RCU-callback batch limit.
  */
-TRACE_EVENT(rcu_batch_start,
+TRACE_EVENT_RCU(rcu_batch_start,
 
        TP_PROTO(const char *rcuname, long qlen_lazy, long qlen, long blimit),
 
@@ -569,7 +573,7 @@ TRACE_EVENT(rcu_batch_start,
  * The first argument is the type of RCU, and the second argument is
  * a pointer to the RCU callback itself.
  */
-TRACE_EVENT(rcu_invoke_callback,
+TRACE_EVENT_RCU(rcu_invoke_callback,
 
        TP_PROTO(const char *rcuname, struct rcu_head *rhp),
 
@@ -598,7 +602,7 @@ TRACE_EVENT(rcu_invoke_callback,
  * is the offset of the callback within the enclosing RCU-protected
  * data structure.
  */
-TRACE_EVENT(rcu_invoke_kfree_callback,
+TRACE_EVENT_RCU(rcu_invoke_kfree_callback,
 
        TP_PROTO(const char *rcuname, struct rcu_head *rhp, unsigned long offset),
 
@@ -631,7 +635,7 @@ TRACE_EVENT(rcu_invoke_kfree_callback,
  * and the sixth argument (risk) is the return value from
  * rcu_is_callbacks_kthread().
  */
-TRACE_EVENT(rcu_batch_end,
+TRACE_EVENT_RCU(rcu_batch_end,
 
        TP_PROTO(const char *rcuname, int callbacks_invoked,
                 char cb, char nr, char iit, char risk),
@@ -673,7 +677,7 @@ TRACE_EVENT(rcu_batch_end,
  * callback address can be NULL.
  */
 #define RCUTORTURENAME_LEN 8
-TRACE_EVENT(rcu_torture_read,
+TRACE_EVENT_RCU(rcu_torture_read,
 
        TP_PROTO(const char *rcutorturename, struct rcu_head *rhp,
                 unsigned long secs, unsigned long c_old, unsigned long c),
@@ -721,7 +725,7 @@ TRACE_EVENT(rcu_torture_read,
  * The "cpu" argument is the CPU or -1 if meaningless, the "cnt" argument
  * is the count of remaining callbacks, and "done" is the piggybacking count.
  */
-TRACE_EVENT(rcu_barrier,
+TRACE_EVENT_RCU(rcu_barrier,
 
        TP_PROTO(const char *rcuname, const char *s, int cpu, int cnt, unsigned long done),
 
@@ -748,41 +752,6 @@ TRACE_EVENT(rcu_barrier,
                  __entry->done)
 );
 
-#else /* #ifdef CONFIG_RCU_TRACE */
-
-#define trace_rcu_grace_period(rcuname, gp_seq, gpevent) do { } while (0)
-#define trace_rcu_future_grace_period(rcuname, gp_seq, gp_seq_req, \
-                                     level, grplo, grphi, event) \
-                                     do { } while (0)
-#define trace_rcu_grace_period_init(rcuname, gp_seq, level, grplo, grphi, \
-                                   qsmask) do { } while (0)
-#define trace_rcu_exp_grace_period(rcuname, gqseq, gpevent) \
-       do { } while (0)
-#define trace_rcu_exp_funnel_lock(rcuname, level, grplo, grphi, gpevent) \
-       do { } while (0)
-#define trace_rcu_nocb_wake(rcuname, cpu, reason) do { } while (0)
-#define trace_rcu_preempt_task(rcuname, pid, gp_seq) do { } while (0)
-#define trace_rcu_unlock_preempted_task(rcuname, gp_seq, pid) do { } while (0)
-#define trace_rcu_quiescent_state_report(rcuname, gp_seq, mask, qsmask, level, \
-                                        grplo, grphi, gp_tasks) do { } \
-       while (0)
-#define trace_rcu_fqs(rcuname, gp_seq, cpu, qsevent) do { } while (0)
-#define trace_rcu_dyntick(polarity, oldnesting, newnesting, dyntick) do { } while (0)
-#define trace_rcu_callback(rcuname, rhp, qlen_lazy, qlen) do { } while (0)
-#define trace_rcu_kfree_callback(rcuname, rhp, offset, qlen_lazy, qlen) \
-       do { } while (0)
-#define trace_rcu_batch_start(rcuname, qlen_lazy, qlen, blimit) \
-       do { } while (0)
-#define trace_rcu_invoke_callback(rcuname, rhp) do { } while (0)
-#define trace_rcu_invoke_kfree_callback(rcuname, rhp, offset) do { } while (0)
-#define trace_rcu_batch_end(rcuname, callbacks_invoked, cb, nr, iit, risk) \
-       do { } while (0)
-#define trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \
-       do { } while (0)
-#define trace_rcu_barrier(name, s, cpu, cnt, done) do { } while (0)
-
-#endif /* #else #ifdef CONFIG_RCU_TRACE */
-
 #endif /* _TRACE_RCU_H */
 
 /* This part must be outside protection */
index 9a4bdfadab0770d62a3b46510441cf00b5397f16..c8c7c7efb4875d81823ca6d562f35ba22ec314a7 100644 (file)
@@ -241,7 +241,6 @@ DECLARE_EVENT_CLASS(sched_process_template,
 DEFINE_EVENT(sched_process_template, sched_process_free,
             TP_PROTO(struct task_struct *p),
             TP_ARGS(p));
-            
 
 /*
  * Tracepoint for a task exiting:
@@ -336,11 +335,20 @@ TRACE_EVENT(sched_process_exec,
                  __entry->pid, __entry->old_pid)
 );
 
+
+#ifdef CONFIG_SCHEDSTATS
+#define DEFINE_EVENT_SCHEDSTAT DEFINE_EVENT
+#define DECLARE_EVENT_CLASS_SCHEDSTAT DECLARE_EVENT_CLASS
+#else
+#define DEFINE_EVENT_SCHEDSTAT DEFINE_EVENT_NOP
+#define DECLARE_EVENT_CLASS_SCHEDSTAT DECLARE_EVENT_CLASS_NOP
+#endif
+
 /*
  * XXX the below sched_stat tracepoints only apply to SCHED_OTHER/BATCH/IDLE
  *     adding sched_stat support to SCHED_FIFO/RR would be welcome.
  */
-DECLARE_EVENT_CLASS(sched_stat_template,
+DECLARE_EVENT_CLASS_SCHEDSTAT(sched_stat_template,
 
        TP_PROTO(struct task_struct *tsk, u64 delay),
 
@@ -363,12 +371,11 @@ DECLARE_EVENT_CLASS(sched_stat_template,
                        (unsigned long long)__entry->delay)
 );
 
-
 /*
  * Tracepoint for accounting wait time (time the task is runnable
  * but not actually running due to scheduler contention).
  */
-DEFINE_EVENT(sched_stat_template, sched_stat_wait,
+DEFINE_EVENT_SCHEDSTAT(sched_stat_template, sched_stat_wait,
             TP_PROTO(struct task_struct *tsk, u64 delay),
             TP_ARGS(tsk, delay));
 
@@ -376,7 +383,7 @@ DEFINE_EVENT(sched_stat_template, sched_stat_wait,
  * Tracepoint for accounting sleep time (time the task is not runnable,
  * including iowait, see below).
  */
-DEFINE_EVENT(sched_stat_template, sched_stat_sleep,
+DEFINE_EVENT_SCHEDSTAT(sched_stat_template, sched_stat_sleep,
             TP_PROTO(struct task_struct *tsk, u64 delay),
             TP_ARGS(tsk, delay));
 
@@ -384,14 +391,14 @@ DEFINE_EVENT(sched_stat_template, sched_stat_sleep,
  * Tracepoint for accounting iowait time (time the task is not runnable
  * due to waiting on IO to complete).
  */
-DEFINE_EVENT(sched_stat_template, sched_stat_iowait,
+DEFINE_EVENT_SCHEDSTAT(sched_stat_template, sched_stat_iowait,
             TP_PROTO(struct task_struct *tsk, u64 delay),
             TP_ARGS(tsk, delay));
 
 /*
  * Tracepoint for accounting blocked time (time the task is in uninterruptible).
  */
-DEFINE_EVENT(sched_stat_template, sched_stat_blocked,
+DEFINE_EVENT_SCHEDSTAT(sched_stat_template, sched_stat_blocked,
             TP_PROTO(struct task_struct *tsk, u64 delay),
             TP_ARGS(tsk, delay));
 
index 252327dbfa51b3870ae3b21407ac2aba04ba9804..a5ab2973e8dc3bed647a2f099cf0580cd9e5e157 100644 (file)
                {RECLAIM_WB_ASYNC,      "RECLAIM_WB_ASYNC"}     \
                ) : "RECLAIM_WB_NONE"
 
-#define trace_reclaim_flags(page) ( \
-       (page_is_file_cache(page) ? RECLAIM_WB_FILE : RECLAIM_WB_ANON) | \
+#define trace_reclaim_flags(file) ( \
+       (file ? RECLAIM_WB_FILE : RECLAIM_WB_ANON) | \
        (RECLAIM_WB_ASYNC) \
        )
 
-#define trace_shrink_flags(file) \
-       ( \
-               (file ? RECLAIM_WB_FILE : RECLAIM_WB_ANON) | \
-               (RECLAIM_WB_ASYNC) \
-       )
-
 TRACE_EVENT(mm_vmscan_kswapd_sleep,
 
        TP_PROTO(int nid),
@@ -73,7 +67,9 @@ TRACE_EVENT(mm_vmscan_kswapd_wake,
                __entry->order  = order;
        ),
 
-       TP_printk("nid=%d zid=%d order=%d", __entry->nid, __entry->zid, __entry->order)
+       TP_printk("nid=%d order=%d",
+               __entry->nid,
+               __entry->order)
 );
 
 TRACE_EVENT(mm_vmscan_wakeup_kswapd,
@@ -96,60 +92,53 @@ TRACE_EVENT(mm_vmscan_wakeup_kswapd,
                __entry->gfp_flags      = gfp_flags;
        ),
 
-       TP_printk("nid=%d zid=%d order=%d gfp_flags=%s",
+       TP_printk("nid=%d order=%d gfp_flags=%s",
                __entry->nid,
-               __entry->zid,
                __entry->order,
                show_gfp_flags(__entry->gfp_flags))
 );
 
 DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_begin_template,
 
-       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx),
+       TP_PROTO(int order, gfp_t gfp_flags),
 
-       TP_ARGS(order, may_writepage, gfp_flags, classzone_idx),
+       TP_ARGS(order, gfp_flags),
 
        TP_STRUCT__entry(
                __field(        int,    order           )
-               __field(        int,    may_writepage   )
                __field(        gfp_t,  gfp_flags       )
-               __field(        int,    classzone_idx   )
        ),
 
        TP_fast_assign(
                __entry->order          = order;
-               __entry->may_writepage  = may_writepage;
                __entry->gfp_flags      = gfp_flags;
-               __entry->classzone_idx  = classzone_idx;
        ),
 
-       TP_printk("order=%d may_writepage=%d gfp_flags=%s classzone_idx=%d",
+       TP_printk("order=%d gfp_flags=%s",
                __entry->order,
-               __entry->may_writepage,
-               show_gfp_flags(__entry->gfp_flags),
-               __entry->classzone_idx)
+               show_gfp_flags(__entry->gfp_flags))
 );
 
 DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_direct_reclaim_begin,
 
-       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx),
+       TP_PROTO(int order, gfp_t gfp_flags),
 
-       TP_ARGS(order, may_writepage, gfp_flags, classzone_idx)
+       TP_ARGS(order, gfp_flags)
 );
 
 #ifdef CONFIG_MEMCG
 DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_reclaim_begin,
 
-       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx),
+       TP_PROTO(int order, gfp_t gfp_flags),
 
-       TP_ARGS(order, may_writepage, gfp_flags, classzone_idx)
+       TP_ARGS(order, gfp_flags)
 );
 
 DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_softlimit_reclaim_begin,
 
-       TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx),
+       TP_PROTO(int order, gfp_t gfp_flags),
 
-       TP_ARGS(order, may_writepage, gfp_flags, classzone_idx)
+       TP_ARGS(order, gfp_flags)
 );
 #endif /* CONFIG_MEMCG */
 
@@ -333,7 +322,8 @@ TRACE_EVENT(mm_vmscan_writepage,
 
        TP_fast_assign(
                __entry->pfn = page_to_pfn(page);
-               __entry->reclaim_flags = trace_reclaim_flags(page);
+               __entry->reclaim_flags = trace_reclaim_flags(
+                                               page_is_file_cache(page));
        ),
 
        TP_printk("page=%p pfn=%lu flags=%s",
@@ -358,7 +348,8 @@ TRACE_EVENT(mm_vmscan_lru_shrink_inactive,
                __field(unsigned long, nr_writeback)
                __field(unsigned long, nr_congested)
                __field(unsigned long, nr_immediate)
-               __field(unsigned long, nr_activate)
+               __field(unsigned int, nr_activate0)
+               __field(unsigned int, nr_activate1)
                __field(unsigned long, nr_ref_keep)
                __field(unsigned long, nr_unmap_fail)
                __field(int, priority)
@@ -373,20 +364,22 @@ TRACE_EVENT(mm_vmscan_lru_shrink_inactive,
                __entry->nr_writeback = stat->nr_writeback;
                __entry->nr_congested = stat->nr_congested;
                __entry->nr_immediate = stat->nr_immediate;
-               __entry->nr_activate = stat->nr_activate;
+               __entry->nr_activate0 = stat->nr_activate[0];
+               __entry->nr_activate1 = stat->nr_activate[1];
                __entry->nr_ref_keep = stat->nr_ref_keep;
                __entry->nr_unmap_fail = stat->nr_unmap_fail;
                __entry->priority = priority;
-               __entry->reclaim_flags = trace_shrink_flags(file);
+               __entry->reclaim_flags = trace_reclaim_flags(file);
        ),
 
-       TP_printk("nid=%d nr_scanned=%ld nr_reclaimed=%ld nr_dirty=%ld nr_writeback=%ld nr_congested=%ld nr_immediate=%ld nr_activate=%ld nr_ref_keep=%ld nr_unmap_fail=%ld priority=%d flags=%s",
+       TP_printk("nid=%d nr_scanned=%ld nr_reclaimed=%ld nr_dirty=%ld nr_writeback=%ld nr_congested=%ld nr_immediate=%ld nr_activate_anon=%d nr_activate_file=%d nr_ref_keep=%ld nr_unmap_fail=%ld priority=%d flags=%s",
                __entry->nid,
                __entry->nr_scanned, __entry->nr_reclaimed,
                __entry->nr_dirty, __entry->nr_writeback,
                __entry->nr_congested, __entry->nr_immediate,
-               __entry->nr_activate, __entry->nr_ref_keep,
-               __entry->nr_unmap_fail, __entry->priority,
+               __entry->nr_activate0, __entry->nr_activate1,
+               __entry->nr_ref_keep, __entry->nr_unmap_fail,
+               __entry->priority,
                show_reclaim_flags(__entry->reclaim_flags))
 );
 
@@ -415,7 +408,7 @@ TRACE_EVENT(mm_vmscan_lru_shrink_active,
                __entry->nr_deactivated = nr_deactivated;
                __entry->nr_referenced = nr_referenced;
                __entry->priority = priority;
-               __entry->reclaim_flags = trace_shrink_flags(file);
+               __entry->reclaim_flags = trace_reclaim_flags(file);
        ),
 
        TP_printk("nid=%d nr_taken=%ld nr_active=%ld nr_deactivated=%ld nr_referenced=%ld priority=%d flags=%s",
@@ -454,7 +447,8 @@ TRACE_EVENT(mm_vmscan_inactive_list_is_low,
                __entry->total_active = total_active;
                __entry->active = active;
                __entry->ratio = ratio;
-               __entry->reclaim_flags = trace_shrink_flags(file) & RECLAIM_WB_LRU;
+               __entry->reclaim_flags = trace_reclaim_flags(file) &
+                                        RECLAIM_WB_LRU;
        ),
 
        TP_printk("nid=%d reclaim_idx=%d total_inactive=%ld inactive=%ld total_active=%ld active=%ld ratio=%ld flags=%s",
@@ -465,6 +459,38 @@ TRACE_EVENT(mm_vmscan_inactive_list_is_low,
                __entry->ratio,
                show_reclaim_flags(__entry->reclaim_flags))
 );
+
+TRACE_EVENT(mm_vmscan_node_reclaim_begin,
+
+       TP_PROTO(int nid, int order, gfp_t gfp_flags),
+
+       TP_ARGS(nid, order, gfp_flags),
+
+       TP_STRUCT__entry(
+               __field(int, nid)
+               __field(int, order)
+               __field(gfp_t, gfp_flags)
+       ),
+
+       TP_fast_assign(
+               __entry->nid = nid;
+               __entry->order = order;
+               __entry->gfp_flags = gfp_flags;
+       ),
+
+       TP_printk("nid=%d order=%d gfp_flags=%s",
+               __entry->nid,
+               __entry->order,
+               show_gfp_flags(__entry->gfp_flags))
+);
+
+DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_node_reclaim_end,
+
+       TP_PROTO(unsigned long nr_reclaimed),
+
+       TP_ARGS(nr_reclaimed)
+);
+
 #endif /* _TRACE_VMSCAN_H */
 
 /* This part must be outside protection */
index 32db72c7c055fa2f566f70d89cce51402f213b28..aa7f3aeac74087e9e77966dfb905e748f30a889a 100644 (file)
@@ -53,7 +53,7 @@ WB_WORK_REASON
 
 struct wb_writeback_work;
 
-TRACE_EVENT(writeback_dirty_page,
+DECLARE_EVENT_CLASS(writeback_page_template,
 
        TP_PROTO(struct page *page, struct address_space *mapping),
 
@@ -79,6 +79,20 @@ TRACE_EVENT(writeback_dirty_page,
        )
 );
 
+DEFINE_EVENT(writeback_page_template, writeback_dirty_page,
+
+       TP_PROTO(struct page *page, struct address_space *mapping),
+
+       TP_ARGS(page, mapping)
+);
+
+DEFINE_EVENT(writeback_page_template, wait_on_page_writeback,
+
+       TP_PROTO(struct page *page, struct address_space *mapping),
+
+       TP_ARGS(page, mapping)
+);
+
 DECLARE_EVENT_CLASS(writeback_dirty_inode_template,
 
        TP_PROTO(struct inode *inode, int flags),
index dee7292e1df6b162a12d0e55e9ccdf875fad428d..a87904daf1034449980afb86b952a538f84b9da9 100644 (file)
@@ -832,9 +832,21 @@ __SYSCALL(__NR_io_uring_setup, sys_io_uring_setup)
 __SYSCALL(__NR_io_uring_enter, sys_io_uring_enter)
 #define __NR_io_uring_register 427
 __SYSCALL(__NR_io_uring_register, sys_io_uring_register)
+#define __NR_open_tree 428
+__SYSCALL(__NR_open_tree, sys_open_tree)
+#define __NR_move_mount 429
+__SYSCALL(__NR_move_mount, sys_move_mount)
+#define __NR_fsopen 430
+__SYSCALL(__NR_fsopen, sys_fsopen)
+#define __NR_fsconfig 431
+__SYSCALL(__NR_fsconfig, sys_fsconfig)
+#define __NR_fsmount 432
+__SYSCALL(__NR_fsmount, sys_fsmount)
+#define __NR_fspick 433
+__SYSCALL(__NR_fspick, sys_fspick)
 
 #undef __NR_syscalls
-#define __NR_syscalls 428
+#define __NR_syscalls 434
 
 /*
  * 32 bit systems traditionally used different
index 72336bac7573368e7bce974626b68569c46eaabb..63e0cf66f01a9698ff6bc41ac5492809bb83d834 100644 (file)
@@ -629,7 +629,7 @@ union bpf_attr {
  *             **BPF_F_INVALIDATE_HASH** (set *skb*\ **->hash**, *skb*\
  *             **->swhash** and *skb*\ **->l4hash** to 0).
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -654,7 +654,7 @@ union bpf_attr {
  *             flexibility and can handle sizes larger than 2 or 4 for the
  *             checksum to update.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -686,7 +686,7 @@ union bpf_attr {
  *             flexibility and can handle sizes larger than 2 or 4 for the
  *             checksum to update.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -741,7 +741,7 @@ union bpf_attr {
  *             efficient, but it is handled through an action code where the
  *             redirection happens only after the eBPF program has returned.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -806,7 +806,7 @@ union bpf_attr {
  *             **ETH_P_8021Q** and **ETH_P_8021AD**, it is considered to
  *             be **ETH_P_8021Q**.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -818,7 +818,7 @@ union bpf_attr {
  *     Description
  *             Pop a VLAN header from the packet associated to *skb*.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1168,7 +1168,7 @@ union bpf_attr {
  *             All values for *flags* are reserved for future usage, and must
  *             be left at zero.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1281,7 +1281,7 @@ union bpf_attr {
  *             implicitly linearizes, unclones and drops offloads from the
  *             *skb*.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1317,7 +1317,7 @@ union bpf_attr {
  *             **bpf_skb_pull_data()** to effectively unclone the *skb* from
  *             the very beginning in case it is indeed cloned.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1369,7 +1369,7 @@ union bpf_attr {
  *             All values for *flags* are reserved for future usage, and must
  *             be left at zero.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1384,7 +1384,7 @@ union bpf_attr {
  *             can be used to prepare the packet for pushing or popping
  *             headers.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1518,20 +1518,20 @@ union bpf_attr {
  *             * **BPF_F_ADJ_ROOM_FIXED_GSO**: Do not adjust gso_size.
  *               Adjusting mss in this way is not allowed for datagrams.
  *
- *             * **BPF_F_ADJ_ROOM_ENCAP_L3_IPV4 **:
- *             * **BPF_F_ADJ_ROOM_ENCAP_L3_IPV6 **:
+ *             * **BPF_F_ADJ_ROOM_ENCAP_L3_IPV4**,
+ *               **BPF_F_ADJ_ROOM_ENCAP_L3_IPV6**:
  *               Any new space is reserved to hold a tunnel header.
  *               Configure skb offsets and other fields accordingly.
  *
- *             * **BPF_F_ADJ_ROOM_ENCAP_L4_GRE **:
- *             * **BPF_F_ADJ_ROOM_ENCAP_L4_UDP **:
+ *             * **BPF_F_ADJ_ROOM_ENCAP_L4_GRE**,
+ *               **BPF_F_ADJ_ROOM_ENCAP_L4_UDP**:
  *               Use with ENCAP_L3 flags to further specify the tunnel type.
  *
- *             * **BPF_F_ADJ_ROOM_ENCAP_L2(len) **:
+ *             * **BPF_F_ADJ_ROOM_ENCAP_L2**\ (*len*):
  *               Use with ENCAP_L3/L4 flags to further specify the tunnel
- *               type; **len** is the length of the inner MAC header.
+ *               type; *len* is the length of the inner MAC header.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1610,7 +1610,7 @@ union bpf_attr {
  *             more flexibility as the user is free to store whatever meta
  *             data they need.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1852,7 +1852,7 @@ union bpf_attr {
  *             copied if necessary (i.e. if data was not linear and if start
  *             and end pointers do not point to the same chunk).
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1886,7 +1886,7 @@ union bpf_attr {
  *             only possible to shrink the packet as of this writing,
  *             therefore *delta* must be a negative integer.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -2061,18 +2061,18 @@ union bpf_attr {
  *             **BPF_LWT_ENCAP_IP**
  *                     IP encapsulation (GRE/GUE/IPIP/etc). The outer header
  *                     must be IPv4 or IPv6, followed by zero or more
- *                     additional headers, up to LWT_BPF_MAX_HEADROOM total
- *                     bytes in all prepended headers. Please note that
- *                     if skb_is_gso(skb) is true, no more than two headers
- *                     can be prepended, and the inner header, if present,
- *                     should be either GRE or UDP/GUE.
- *
- *             BPF_LWT_ENCAP_SEG6*** types can be called by bpf programs of
- *             type BPF_PROG_TYPE_LWT_IN; BPF_LWT_ENCAP_IP type can be called
- *             by bpf programs of types BPF_PROG_TYPE_LWT_IN and
- *             BPF_PROG_TYPE_LWT_XMIT.
- *
- *             A call to this helper is susceptible to change the underlaying
+ *                     additional headers, up to **LWT_BPF_MAX_HEADROOM**
+ *                     total bytes in all prepended headers. Please note that
+ *                     if **skb_is_gso**\ (*skb*) is true, no more than two
+ *                     headers can be prepended, and the inner header, if
+ *                     present, should be either GRE or UDP/GUE.
+ *
+ *             **BPF_LWT_ENCAP_SEG6**\ \* types can be called by BPF programs
+ *             of type **BPF_PROG_TYPE_LWT_IN**; **BPF_LWT_ENCAP_IP** type can
+ *             be called by bpf programs of types **BPF_PROG_TYPE_LWT_IN** and
+ *             **BPF_PROG_TYPE_LWT_XMIT**.
+ *
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -2087,7 +2087,7 @@ union bpf_attr {
  *             inside the outermost IPv6 Segment Routing Header can be
  *             modified through this helper.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -2103,7 +2103,7 @@ union bpf_attr {
  *             after the segments are accepted. *delta* can be as well
  *             positive (growing) as negative (shrinking).
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -2126,13 +2126,13 @@ union bpf_attr {
  *                     Type of *param*: **int**.
  *             **SEG6_LOCAL_ACTION_END_B6**
  *                     End.B6 action: Endpoint bound to an SRv6 policy.
- *                     Type of param: **struct ipv6_sr_hdr**.
+ *                     Type of *param*: **struct ipv6_sr_hdr**.
  *             **SEG6_LOCAL_ACTION_END_B6_ENCAP**
  *                     End.B6.Encap action: Endpoint bound to an SRv6
  *                     encapsulation policy.
- *                     Type of param: **struct ipv6_sr_hdr**.
+ *                     Type of *param*: **struct ipv6_sr_hdr**.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -2285,7 +2285,8 @@ union bpf_attr {
  *     Return
  *             Pointer to **struct bpf_sock**, or **NULL** in case of failure.
  *             For sockets with reuseport option, the **struct bpf_sock**
- *             result is from **reuse->socks**\ [] using the hash of the tuple.
+ *             result is from *reuse*\ **->socks**\ [] using the hash of the
+ *             tuple.
  *
  * struct bpf_sock *bpf_sk_lookup_udp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u64 netns, u64 flags)
  *     Description
@@ -2321,7 +2322,8 @@ union bpf_attr {
  *     Return
  *             Pointer to **struct bpf_sock**, or **NULL** in case of failure.
  *             For sockets with reuseport option, the **struct bpf_sock**
- *             result is from **reuse->socks**\ [] using the hash of the tuple.
+ *             result is from *reuse*\ **->socks**\ [] using the hash of the
+ *             tuple.
  *
  * int bpf_sk_release(struct bpf_sock *sock)
  *     Description
@@ -2490,31 +2492,34 @@ union bpf_attr {
  *             network namespace *netns*. The return value must be checked,
  *             and if non-**NULL**, released via **bpf_sk_release**\ ().
  *
- *             This function is identical to bpf_sk_lookup_tcp, except that it
- *             also returns timewait or request sockets. Use bpf_sk_fullsock
- *             or bpf_tcp_socket to access the full structure.
+ *             This function is identical to **bpf_sk_lookup_tcp**\ (), except
+ *             that it also returns timewait or request sockets. Use
+ *             **bpf_sk_fullsock**\ () or **bpf_tcp_sock**\ () to access the
+ *             full structure.
  *
  *             This helper is available only if the kernel was compiled with
  *             **CONFIG_NET** configuration option.
  *     Return
  *             Pointer to **struct bpf_sock**, or **NULL** in case of failure.
  *             For sockets with reuseport option, the **struct bpf_sock**
- *             result is from **reuse->socks**\ [] using the hash of the tuple.
+ *             result is from *reuse*\ **->socks**\ [] using the hash of the
+ *             tuple.
  *
  * int bpf_tcp_check_syncookie(struct bpf_sock *sk, void *iph, u32 iph_len, struct tcphdr *th, u32 th_len)
  *     Description
- *             Check whether iph and th contain a valid SYN cookie ACK for
- *             the listening socket in sk.
+ *             Check whether *iph* and *th* contain a valid SYN cookie ACK for
+ *             the listening socket in *sk*.
  *
- *             iph points to the start of the IPv4 or IPv6 header, while
- *             iph_len contains sizeof(struct iphdr) or sizeof(struct ip6hdr).
+ *             *iph* points to the start of the IPv4 or IPv6 header, while
+ *             *iph_len* contains **sizeof**\ (**struct iphdr**) or
+ *             **sizeof**\ (**struct ip6hdr**).
  *
- *             th points to the start of the TCP header, while th_len contains
- *             sizeof(struct tcphdr).
+ *             *th* points to the start of the TCP header, while *th_len*
+ *             contains **sizeof**\ (**struct tcphdr**).
  *
  *     Return
- *             0 if iph and th are a valid SYN cookie ACK, or a negative error
- *             otherwise.
+ *             0 if *iph* and *th* are a valid SYN cookie ACK, or a negative
+ *             error otherwise.
  *
  * int bpf_sysctl_get_name(struct bpf_sysctl *ctx, char *buf, size_t buf_len, u64 flags)
  *     Description
@@ -2592,17 +2597,17 @@ union bpf_attr {
  *             and save the result in *res*.
  *
  *             The string may begin with an arbitrary amount of white space
- *             (as determined by isspace(3)) followed by a single optional '-'
- *             sign.
+ *             (as determined by **isspace**\ (3)) followed by a single
+ *             optional '**-**' sign.
  *
  *             Five least significant bits of *flags* encode base, other bits
  *             are currently unused.
  *
  *             Base must be either 8, 10, 16 or 0 to detect it automatically
- *             similar to user space strtol(3).
+ *             similar to user space **strtol**\ (3).
  *     Return
  *             Number of characters consumed on success. Must be positive but
- *             no more than buf_len.
+ *             no more than *buf_len*.
  *
  *             **-EINVAL** if no valid digits were found or unsupported base
  *             was provided.
@@ -2616,16 +2621,16 @@ union bpf_attr {
  *             given base and save the result in *res*.
  *
  *             The string may begin with an arbitrary amount of white space
- *             (as determined by isspace(3)).
+ *             (as determined by **isspace**\ (3)).
  *
  *             Five least significant bits of *flags* encode base, other bits
  *             are currently unused.
  *
  *             Base must be either 8, 10, 16 or 0 to detect it automatically
- *             similar to user space strtoul(3).
+ *             similar to user space **strtoul**\ (3).
  *     Return
  *             Number of characters consumed on success. Must be positive but
- *             no more than buf_len.
+ *             no more than *buf_len*.
  *
  *             **-EINVAL** if no valid digits were found or unsupported base
  *             was provided.
@@ -2634,26 +2639,26 @@ union bpf_attr {
  *
  * void *bpf_sk_storage_get(struct bpf_map *map, struct bpf_sock *sk, void *value, u64 flags)
  *     Description
- *             Get a bpf-local-storage from a sk.
+ *             Get a bpf-local-storage from a *sk*.
  *
  *             Logically, it could be thought of getting the value from
  *             a *map* with *sk* as the **key**.  From this
  *             perspective,  the usage is not much different from
- *             **bpf_map_lookup_elem(map, &sk)** except this
- *             helper enforces the key must be a **bpf_fullsock()**
- *             and the map must be a BPF_MAP_TYPE_SK_STORAGE also.
+ *             **bpf_map_lookup_elem**\ (*map*, **&**\ *sk*) except this
+ *             helper enforces the key must be a full socket and the map must
+ *             be a **BPF_MAP_TYPE_SK_STORAGE** also.
  *
  *             Underneath, the value is stored locally at *sk* instead of
- *             the map.  The *map* is used as the bpf-local-storage **type**.
- *             The bpf-local-storage **type** (i.e. the *map*) is searched
- *             against all bpf-local-storages residing at sk.
+ *             the *map*.  The *map* is used as the bpf-local-storage
+ *             "type". The bpf-local-storage "type" (i.e. the *map*) is
+ *             searched against all bpf-local-storages residing at *sk*.
  *
- *             An optional *flags* (BPF_SK_STORAGE_GET_F_CREATE) can be
+ *             An optional *flags* (**BPF_SK_STORAGE_GET_F_CREATE**) can be
  *             used such that a new bpf-local-storage will be
  *             created if one does not exist.  *value* can be used
- *             together with BPF_SK_STORAGE_GET_F_CREATE to specify
+ *             together with **BPF_SK_STORAGE_GET_F_CREATE** to specify
  *             the initial value of a bpf-local-storage.  If *value* is
- *             NULL, the new bpf-local-storage will be zero initialized.
+ *             **NULL**, the new bpf-local-storage will be zero initialized.
  *     Return
  *             A bpf-local-storage pointer is returned on success.
  *
@@ -2662,7 +2667,7 @@ union bpf_attr {
  *
  * int bpf_sk_storage_delete(struct bpf_map *map, struct bpf_sock *sk)
  *     Description
- *             Delete a bpf-local-storage from a sk.
+ *             Delete a bpf-local-storage from a *sk*.
  *     Return
  *             0 on success.
  *
index 121e82ce296b5a4d9e85757e94e3d9521897cb56..59c71fa8c553a394d516502538c188aa01502e2c 100644 (file)
@@ -320,6 +320,9 @@ struct fscrypt_key {
 #define SYNC_FILE_RANGE_WAIT_BEFORE    1
 #define SYNC_FILE_RANGE_WRITE          2
 #define SYNC_FILE_RANGE_WAIT_AFTER     4
+#define SYNC_FILE_RANGE_WRITE_AND_WAIT (SYNC_FILE_RANGE_WRITE | \
+                                        SYNC_FILE_RANGE_WAIT_BEFORE | \
+                                        SYNC_FILE_RANGE_WAIT_AFTER)
 
 /*
  * Flags for preadv2/pwritev2:
index 2ac598614a8fc7a8db337168c32bf1a4c376519c..19fb55e3c73e3bafae7084177cc6e5575404314b 100644 (file)
@@ -44,6 +44,7 @@
  *  - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in
  *  - add blksize field to fuse_attr
  *  - add file flags field to fuse_read_in and fuse_write_in
+ *  - Add ATIME_NOW and MTIME_NOW flags to fuse_setattr_in
  *
  * 7.10
  *  - add nonseekable open flag
@@ -54,7 +55,7 @@
  *  - add POLL message and NOTIFY_POLL notification
  *
  * 7.12
- *  - add umask flag to input argument of open, mknod and mkdir
+ *  - add umask flag to input argument of create, mknod and mkdir
  *  - add notification messages for invalidation of inodes and
  *    directory entries
  *
  *
  *  7.29
  *  - add FUSE_NO_OPENDIR_SUPPORT flag
+ *
+ *  7.30
+ *  - add FUSE_EXPLICIT_INVAL_DATA
+ *  - add FUSE_IOCTL_COMPAT_X32
  */
 
 #ifndef _LINUX_FUSE_H
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 29
+#define FUSE_KERNEL_MINOR_VERSION 30
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -229,11 +234,13 @@ struct fuse_file_lock {
  * FOPEN_KEEP_CACHE: don't invalidate the data cache on open
  * FOPEN_NONSEEKABLE: the file is not seekable
  * FOPEN_CACHE_DIR: allow caching this directory
+ * FOPEN_STREAM: the file is stream-like (no file position at all)
  */
 #define FOPEN_DIRECT_IO                (1 << 0)
 #define FOPEN_KEEP_CACHE       (1 << 1)
 #define FOPEN_NONSEEKABLE      (1 << 2)
 #define FOPEN_CACHE_DIR                (1 << 3)
+#define FOPEN_STREAM           (1 << 4)
 
 /**
  * INIT request/reply flags
@@ -263,6 +270,7 @@ struct fuse_file_lock {
  * FUSE_MAX_PAGES: init_out.max_pages contains the max number of req pages
  * FUSE_CACHE_SYMLINKS: cache READLINK responses
  * FUSE_NO_OPENDIR_SUPPORT: kernel supports zero-message opendir
+ * FUSE_EXPLICIT_INVAL_DATA: only invalidate cached pages on explicit request
  */
 #define FUSE_ASYNC_READ                (1 << 0)
 #define FUSE_POSIX_LOCKS       (1 << 1)
@@ -289,6 +297,7 @@ struct fuse_file_lock {
 #define FUSE_MAX_PAGES         (1 << 22)
 #define FUSE_CACHE_SYMLINKS    (1 << 23)
 #define FUSE_NO_OPENDIR_SUPPORT (1 << 24)
+#define FUSE_EXPLICIT_INVAL_DATA (1 << 25)
 
 /**
  * CUSE INIT request/reply flags
@@ -335,6 +344,7 @@ struct fuse_file_lock {
  * FUSE_IOCTL_RETRY: retry with new iovecs
  * FUSE_IOCTL_32BIT: 32bit ioctl
  * FUSE_IOCTL_DIR: is a directory
+ * FUSE_IOCTL_COMPAT_X32: x32 compat ioctl on 64bit machine (64bit time_t)
  *
  * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
  */
@@ -343,6 +353,7 @@ struct fuse_file_lock {
 #define FUSE_IOCTL_RETRY       (1 << 2)
 #define FUSE_IOCTL_32BIT       (1 << 3)
 #define FUSE_IOCTL_DIR         (1 << 4)
+#define FUSE_IOCTL_COMPAT_X32  (1 << 5)
 
 #define FUSE_IOCTL_MAX_IOV     256
 
@@ -353,6 +364,13 @@ struct fuse_file_lock {
  */
 #define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0)
 
+/**
+ * Fsync flags
+ *
+ * FUSE_FSYNC_FDATASYNC: Sync data only, not metadata
+ */
+#define FUSE_FSYNC_FDATASYNC   (1 << 0)
+
 enum fuse_opcode {
        FUSE_LOOKUP             = 1,
        FUSE_FORGET             = 2,  /* no reply */
index 64cee116928ebd92d97acec08c273e02c89958ab..85387c76c24f384ac31a934ca14f0e76faf1ba3a 100644 (file)
 #define KEY_SCREENSAVER                0x245   /* AL Screen Saver */
 #define KEY_VOICECOMMAND               0x246   /* Listening Voice Command */
 #define KEY_ASSISTANT          0x247   /* AL Context-aware desktop assistant */
+#define KEY_KBD_LAYOUT_NEXT    0x248   /* AC Next Keyboard Layout Select */
 
 #define KEY_BRIGHTNESS_MIN             0x250   /* Set Brightness to Minimum */
 #define KEY_BRIGHTNESS_MAX             0x251   /* Set Brightness to Maximum */
index 6d4ea4b6c92206ac5843c258f5c1f56987d79f0e..2fe12b40d5035a7b459720476e7ab7002b04c9d4 100644 (file)
@@ -986,8 +986,13 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_HYPERV_ENLIGHTENED_VMCS 163
 #define KVM_CAP_EXCEPTION_PAYLOAD 164
 #define KVM_CAP_ARM_VM_IPA_SIZE 165
-#define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT 166
+#define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT 166 /* Obsolete */
 #define KVM_CAP_HYPERV_CPUID 167
+#define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 168
+#define KVM_CAP_PPC_IRQ_XIVE 169
+#define KVM_CAP_ARM_SVE 170
+#define KVM_CAP_ARM_PTRAUTH_ADDRESS 171
+#define KVM_CAP_ARM_PTRAUTH_GENERIC 172
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1145,6 +1150,7 @@ struct kvm_dirty_tlb {
 #define KVM_REG_SIZE_U256      0x0050000000000000ULL
 #define KVM_REG_SIZE_U512      0x0060000000000000ULL
 #define KVM_REG_SIZE_U1024     0x0070000000000000ULL
+#define KVM_REG_SIZE_U2048     0x0080000000000000ULL
 
 struct kvm_reg_list {
        __u64 n; /* number of regs */
@@ -1211,6 +1217,8 @@ enum kvm_device_type {
 #define KVM_DEV_TYPE_ARM_VGIC_V3       KVM_DEV_TYPE_ARM_VGIC_V3
        KVM_DEV_TYPE_ARM_VGIC_ITS,
 #define KVM_DEV_TYPE_ARM_VGIC_ITS      KVM_DEV_TYPE_ARM_VGIC_ITS
+       KVM_DEV_TYPE_XIVE,
+#define KVM_DEV_TYPE_XIVE              KVM_DEV_TYPE_XIVE
        KVM_DEV_TYPE_MAX,
 };
 
@@ -1434,12 +1442,15 @@ struct kvm_enc_region {
 #define KVM_GET_NESTED_STATE         _IOWR(KVMIO, 0xbe, struct kvm_nested_state)
 #define KVM_SET_NESTED_STATE         _IOW(KVMIO,  0xbf, struct kvm_nested_state)
 
-/* Available with KVM_CAP_MANUAL_DIRTY_LOG_PROTECT */
+/* Available with KVM_CAP_MANUAL_DIRTY_LOG_PROTECT_2 */
 #define KVM_CLEAR_DIRTY_LOG          _IOWR(KVMIO, 0xc0, struct kvm_clear_dirty_log)
 
 /* Available with KVM_CAP_HYPERV_CPUID */
 #define KVM_GET_SUPPORTED_HV_CPUID _IOWR(KVMIO, 0xc1, struct kvm_cpuid2)
 
+/* Available with KVM_CAP_ARM_SVE */
+#define KVM_ARM_VCPU_FINALIZE    _IOW(KVMIO,  0xc2, int)
+
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
        /* Guest initialization commands */
index f0cf7b0f4f352719056e52db790df82e6512bd14..505393c6e959ff737fccbf2f8dd8e84750af1e12 100644 (file)
@@ -966,7 +966,6 @@ enum nft_socket_keys {
  * @NFT_CT_DST_IP: conntrack layer 3 protocol destination (IPv4 address)
  * @NFT_CT_SRC_IP6: conntrack layer 3 protocol source (IPv6 address)
  * @NFT_CT_DST_IP6: conntrack layer 3 protocol destination (IPv6 address)
- * @NFT_CT_TIMEOUT: connection tracking timeout policy assigned to conntrack
  * @NFT_CT_ID: conntrack id
  */
 enum nft_ct_keys {
@@ -993,7 +992,6 @@ enum nft_ct_keys {
        NFT_CT_DST_IP,
        NFT_CT_SRC_IP6,
        NFT_CT_DST_IP6,
-       NFT_CT_TIMEOUT,
        NFT_CT_ID,
        __NFT_CT_MAX
 };
@@ -1138,7 +1136,7 @@ enum nft_log_level {
        NFT_LOGLEVEL_AUDIT,
        __NFT_LOGLEVEL_MAX
 };
-#define NFT_LOGLEVEL_MAX       (__NFT_LOGLEVEL_MAX + 1)
+#define NFT_LOGLEVEL_MAX       (__NFT_LOGLEVEL_MAX - 1)
 
 /**
  * enum nft_queue_attributes - nf_tables queue expression netlink attributes
index f8f5cccad749262bc48d3c8dfafc35774db65485..b1e9de4f07d5d5caea4db005fd666135b127a8a1 100644 (file)
@@ -36,6 +36,7 @@ enum cld_command {
        Cld_Remove,             /* remove record of this cm_id */
        Cld_Check,              /* is this cm_id allowed? */
        Cld_GraceDone,          /* grace period is complete */
+       Cld_GraceStart,
 };
 
 /* representation of long-form NFSv4 client ID */
index 5c98133f2c9494c48ee368668daf2495d4aa3b4b..27164769d18495336fa5acae66b8de878dea3cc0 100644 (file)
@@ -1,7 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 /*
- *     pci_regs.h
- *
  *     PCI standard defines
  *     Copyright 1994, Drew Eckhardt
  *     Copyright 1997--1999 Martin Mares <mj@ucw.cz>
@@ -15,7 +13,7 @@
  *     PCI System Design Guide
  *
  *     For HyperTransport information, please consult the following manuals
- *     from http://www.hypertransport.org
+ *     from http://www.hypertransport.org :
  *
  *     The HyperTransport I/O Link Specification
  */
 #define  PCI_SID_ESR_FIC       0x20    /* First In Chassis Flag */
 #define PCI_SID_CHASSIS_NR     3       /* Chassis Number */
 
-/* Message Signalled Interrupts registers */
+/* Message Signalled Interrupt registers */
 
 #define PCI_MSI_FLAGS          2       /* Message Control */
 #define  PCI_MSI_FLAGS_ENABLE  0x0001  /* MSI feature enabled */
 #define PCI_MSI_MASK_64                16      /* Mask bits register for 64-bit devices */
 #define PCI_MSI_PENDING_64     20      /* Pending intrs for 64-bit devices */
 
-/* MSI-X registers */
+/* MSI-X registers (in MSI-X capability) */
 #define PCI_MSIX_FLAGS         2       /* Message Control */
 #define  PCI_MSIX_FLAGS_QSIZE  0x07FF  /* Table size */
 #define  PCI_MSIX_FLAGS_MASKALL        0x4000  /* Mask all vectors for this function */
 #define PCI_MSIX_FLAGS_BIRMASK PCI_MSIX_PBA_BIR /* deprecated */
 #define PCI_CAP_MSIX_SIZEOF    12      /* size of MSIX registers */
 
-/* MSI-X Table entry format */
+/* MSI-X Table entry format (in memory mapped by a BAR) */
 #define PCI_MSIX_ENTRY_SIZE            16
-#define  PCI_MSIX_ENTRY_LOWER_ADDR     0
-#define  PCI_MSIX_ENTRY_UPPER_ADDR     4
-#define  PCI_MSIX_ENTRY_DATA           8
-#define  PCI_MSIX_ENTRY_VECTOR_CTRL    12
-#define   PCI_MSIX_ENTRY_CTRL_MASKBIT  1
+#define PCI_MSIX_ENTRY_LOWER_ADDR      0  /* Message Address */
+#define PCI_MSIX_ENTRY_UPPER_ADDR      4  /* Message Upper Address */
+#define PCI_MSIX_ENTRY_DATA            8  /* Message Data */
+#define PCI_MSIX_ENTRY_VECTOR_CTRL     12 /* Vector Control */
+#define  PCI_MSIX_ENTRY_CTRL_MASKBIT   0x00000001
 
 /* CompactPCI Hotswap Register */
 
 #define PCI_EA_FIRST_ENT_BRIDGE        8       /* First EA Entry for Bridges */
 #define  PCI_EA_ES             0x00000007 /* Entry Size */
 #define  PCI_EA_BEI            0x000000f0 /* BAR Equivalent Indicator */
+
+/* EA fixed Secondary and Subordinate bus numbers for Bridge */
+#define PCI_EA_SEC_BUS_MASK    0xff
+#define PCI_EA_SUB_BUS_MASK    0xff00
+#define PCI_EA_SUB_BUS_SHIFT   8
+
 /* 0-5 map to BARs 0-5 respectively */
 #define   PCI_EA_BEI_BAR0              0
 #define   PCI_EA_BEI_BAR5              5
 /* PCI Express capability registers */
 
 #define PCI_EXP_FLAGS          2       /* Capabilities register */
-#define PCI_EXP_FLAGS_VERS     0x000f  /* Capability version */
-#define PCI_EXP_FLAGS_TYPE     0x00f0  /* Device/Port type */
-#define  PCI_EXP_TYPE_ENDPOINT 0x0     /* Express Endpoint */
-#define  PCI_EXP_TYPE_LEG_END  0x1     /* Legacy Endpoint */
-#define  PCI_EXP_TYPE_ROOT_PORT 0x4    /* Root Port */
-#define  PCI_EXP_TYPE_UPSTREAM 0x5     /* Upstream Port */
-#define  PCI_EXP_TYPE_DOWNSTREAM 0x6   /* Downstream Port */
-#define  PCI_EXP_TYPE_PCI_BRIDGE 0x7   /* PCIe to PCI/PCI-X Bridge */
-#define  PCI_EXP_TYPE_PCIE_BRIDGE 0x8  /* PCI/PCI-X to PCIe Bridge */
-#define  PCI_EXP_TYPE_RC_END   0x9     /* Root Complex Integrated Endpoint */
-#define  PCI_EXP_TYPE_RC_EC    0xa     /* Root Complex Event Collector */
-#define PCI_EXP_FLAGS_SLOT     0x0100  /* Slot implemented */
-#define PCI_EXP_FLAGS_IRQ      0x3e00  /* Interrupt message number */
+#define  PCI_EXP_FLAGS_VERS    0x000f  /* Capability version */
+#define  PCI_EXP_FLAGS_TYPE    0x00f0  /* Device/Port type */
+#define   PCI_EXP_TYPE_ENDPOINT           0x0  /* Express Endpoint */
+#define   PCI_EXP_TYPE_LEG_END    0x1  /* Legacy Endpoint */
+#define   PCI_EXP_TYPE_ROOT_PORT   0x4 /* Root Port */
+#define   PCI_EXP_TYPE_UPSTREAM           0x5  /* Upstream Port */
+#define   PCI_EXP_TYPE_DOWNSTREAM  0x6 /* Downstream Port */
+#define   PCI_EXP_TYPE_PCI_BRIDGE  0x7 /* PCIe to PCI/PCI-X Bridge */
+#define   PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIe Bridge */
+#define   PCI_EXP_TYPE_RC_END     0x9  /* Root Complex Integrated Endpoint */
+#define   PCI_EXP_TYPE_RC_EC      0xa  /* Root Complex Event Collector */
+#define  PCI_EXP_FLAGS_SLOT    0x0100  /* Slot implemented */
+#define  PCI_EXP_FLAGS_IRQ     0x3e00  /* Interrupt message number */
 #define PCI_EXP_DEVCAP         4       /* Device capabilities */
 #define  PCI_EXP_DEVCAP_PAYLOAD        0x00000007 /* Max_Payload_Size */
 #define  PCI_EXP_DEVCAP_PHANTOM        0x00000018 /* Phantom functions */
 #define PCI_EXP_RTCAP          30      /* Root Capabilities */
 #define  PCI_EXP_RTCAP_CRSVIS  0x0001  /* CRS Software Visibility capability */
 #define PCI_EXP_RTSTA          32      /* Root Status */
-#define PCI_EXP_RTSTA_PME      0x00010000 /* PME status */
-#define PCI_EXP_RTSTA_PENDING  0x00020000 /* PME pending */
+#define  PCI_EXP_RTSTA_PME     0x00010000 /* PME status */
+#define  PCI_EXP_RTSTA_PENDING 0x00020000 /* PME pending */
 /*
  * The Device Capabilities 2, Device Status 2, Device Control 2,
  * Link Capabilities 2, Link Status 2, Link Control 2,
 #define  PCI_EXP_DEVCAP2_OBFF_MASK     0x000c0000 /* OBFF support mechanism */
 #define  PCI_EXP_DEVCAP2_OBFF_MSG      0x00040000 /* New message signaling */
 #define  PCI_EXP_DEVCAP2_OBFF_WAKE     0x00080000 /* Re-use WAKE# for OBFF */
-#define PCI_EXP_DEVCAP2_EE_PREFIX      0x00200000 /* End-End TLP Prefix */
+#define  PCI_EXP_DEVCAP2_EE_PREFIX     0x00200000 /* End-End TLP Prefix */
 #define PCI_EXP_DEVCTL2                40      /* Device Control 2 */
 #define  PCI_EXP_DEVCTL2_COMP_TIMEOUT  0x000f  /* Completion Timeout Value */
 #define  PCI_EXP_DEVCTL2_COMP_TMOUT_DIS        0x0010  /* Completion Timeout Disable */
 #define  PCI_EXP_DEVCTL2_ARI           0x0020  /* Alternative Routing-ID */
-#define PCI_EXP_DEVCTL2_ATOMIC_REQ     0x0040  /* Set Atomic requests */
-#define PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK 0x0080 /* Block atomic egress */
+#define  PCI_EXP_DEVCTL2_ATOMIC_REQ    0x0040  /* Set Atomic requests */
+#define  PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK 0x0080 /* Block atomic egress */
 #define  PCI_EXP_DEVCTL2_IDO_REQ_EN    0x0100  /* Allow IDO for requests */
 #define  PCI_EXP_DEVCTL2_IDO_CMP_EN    0x0200  /* Allow IDO for completions */
 #define  PCI_EXP_DEVCTL2_LTR_EN                0x0400  /* Enable LTR mechanism */
 #define  PCI_EXP_LNKCAP2_SLS_16_0GB    0x00000010 /* Supported Speed 16GT/s */
 #define  PCI_EXP_LNKCAP2_CROSSLINK     0x00000100 /* Crosslink supported */
 #define PCI_EXP_LNKCTL2                48      /* Link Control 2 */
-#define PCI_EXP_LNKCTL2_TLS            0x000f
-#define PCI_EXP_LNKCTL2_TLS_2_5GT      0x0001 /* Supported Speed 2.5GT/s */
-#define PCI_EXP_LNKCTL2_TLS_5_0GT      0x0002 /* Supported Speed 5GT/s */
-#define PCI_EXP_LNKCTL2_TLS_8_0GT      0x0003 /* Supported Speed 8GT/s */
-#define PCI_EXP_LNKCTL2_TLS_16_0GT     0x0004 /* Supported Speed 16GT/s */
+#define  PCI_EXP_LNKCTL2_TLS           0x000f
+#define  PCI_EXP_LNKCTL2_TLS_2_5GT     0x0001 /* Supported Speed 2.5GT/s */
+#define  PCI_EXP_LNKCTL2_TLS_5_0GT     0x0002 /* Supported Speed 5GT/s */
+#define  PCI_EXP_LNKCTL2_TLS_8_0GT     0x0003 /* Supported Speed 8GT/s */
+#define  PCI_EXP_LNKCTL2_TLS_16_0GT    0x0004 /* Supported Speed 16GT/s */
 #define PCI_EXP_LNKSTA2                50      /* Link Status 2 */
 #define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 52      /* v2 endpoints with link end here */
 #define PCI_EXP_SLTCAP2                52      /* Slot Capabilities 2 */
 #define  PCI_ERR_CAP_ECRC_CHKE 0x00000100      /* ECRC Check Enable */
 #define PCI_ERR_HEADER_LOG     28      /* Header Log Register (16 bytes) */
 #define PCI_ERR_ROOT_COMMAND   44      /* Root Error Command */
-#define PCI_ERR_ROOT_CMD_COR_EN                0x00000001 /* Correctable Err Reporting Enable */
-#define PCI_ERR_ROOT_CMD_NONFATAL_EN   0x00000002 /* Non-Fatal Err Reporting Enable */
-#define PCI_ERR_ROOT_CMD_FATAL_EN      0x00000004 /* Fatal Err Reporting Enable */
+#define  PCI_ERR_ROOT_CMD_COR_EN       0x00000001 /* Correctable Err Reporting Enable */
+#define  PCI_ERR_ROOT_CMD_NONFATAL_EN  0x00000002 /* Non-Fatal Err Reporting Enable */
+#define  PCI_ERR_ROOT_CMD_FATAL_EN     0x00000004 /* Fatal Err Reporting Enable */
 #define PCI_ERR_ROOT_STATUS    48
-#define PCI_ERR_ROOT_COR_RCV           0x00000001 /* ERR_COR Received */
-#define PCI_ERR_ROOT_MULTI_COR_RCV     0x00000002 /* Multiple ERR_COR */
-#define PCI_ERR_ROOT_UNCOR_RCV         0x00000004 /* ERR_FATAL/NONFATAL */
-#define PCI_ERR_ROOT_MULTI_UNCOR_RCV   0x00000008 /* Multiple FATAL/NONFATAL */
-#define PCI_ERR_ROOT_FIRST_FATAL       0x00000010 /* First UNC is Fatal */
-#define PCI_ERR_ROOT_NONFATAL_RCV      0x00000020 /* Non-Fatal Received */
-#define PCI_ERR_ROOT_FATAL_RCV         0x00000040 /* Fatal Received */
-#define PCI_ERR_ROOT_AER_IRQ           0xf8000000 /* Advanced Error Interrupt Message Number */
+#define  PCI_ERR_ROOT_COR_RCV          0x00000001 /* ERR_COR Received */
+#define  PCI_ERR_ROOT_MULTI_COR_RCV    0x00000002 /* Multiple ERR_COR */
+#define  PCI_ERR_ROOT_UNCOR_RCV                0x00000004 /* ERR_FATAL/NONFATAL */
+#define  PCI_ERR_ROOT_MULTI_UNCOR_RCV  0x00000008 /* Multiple FATAL/NONFATAL */
+#define  PCI_ERR_ROOT_FIRST_FATAL      0x00000010 /* First UNC is Fatal */
+#define  PCI_ERR_ROOT_NONFATAL_RCV     0x00000020 /* Non-Fatal Received */
+#define  PCI_ERR_ROOT_FATAL_RCV                0x00000040 /* Fatal Received */
+#define  PCI_ERR_ROOT_AER_IRQ          0xf8000000 /* Advanced Error Interrupt Message Number */
 #define PCI_ERR_ROOT_ERR_SRC   52      /* Error Source Identification */
 
 /* Virtual Channel */
 
 /* Page Request Interface */
 #define PCI_PRI_CTRL           0x04    /* PRI control register */
-#define  PCI_PRI_CTRL_ENABLE   0x01    /* Enable */
-#define  PCI_PRI_CTRL_RESET    0x02    /* Reset */
+#define  PCI_PRI_CTRL_ENABLE   0x0001  /* Enable */
+#define  PCI_PRI_CTRL_RESET    0x0002  /* Reset */
 #define PCI_PRI_STATUS         0x06    /* PRI status register */
-#define  PCI_PRI_STATUS_RF     0x00  /* Response Failure */
-#define  PCI_PRI_STATUS_UPRGI  0x00  /* Unexpected PRG index */
-#define  PCI_PRI_STATUS_STOPPED        0x100   /* PRI Stopped */
+#define  PCI_PRI_STATUS_RF     0x0001  /* Response Failure */
+#define  PCI_PRI_STATUS_UPRGI  0x0002  /* Unexpected PRG index */
+#define  PCI_PRI_STATUS_STOPPED        0x0100  /* PRI Stopped */
 #define  PCI_PRI_STATUS_PASID  0x8000  /* PRG Response PASID Required */
 #define PCI_PRI_MAX_REQ                0x08    /* PRI max reqs supported */
 #define PCI_PRI_ALLOC_REQ      0x0c    /* PRI max reqs allowed */
 
 /* Single Root I/O Virtualization */
 #define PCI_SRIOV_CAP          0x04    /* SR-IOV Capabilities */
-#define  PCI_SRIOV_CAP_VFM     0x01    /* VF Migration Capable */
+#define  PCI_SRIOV_CAP_VFM     0x00000001  /* VF Migration Capable */
 #define  PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */
 #define PCI_SRIOV_CTRL         0x08    /* SR-IOV Control */
-#define  PCI_SRIOV_CTRL_VFE    0x01    /* VF Enable */
-#define  PCI_SRIOV_CTRL_VFM    0x02    /* VF Migration Enable */
-#define  PCI_SRIOV_CTRL_INTR   0x04    /* VF Migration Interrupt Enable */
-#define  PCI_SRIOV_CTRL_MSE    0x08    /* VF Memory Space Enable */
-#define  PCI_SRIOV_CTRL_ARI    0x10    /* ARI Capable Hierarchy */
+#define  PCI_SRIOV_CTRL_VFE    0x0001  /* VF Enable */
+#define  PCI_SRIOV_CTRL_VFM    0x0002  /* VF Migration Enable */
+#define  PCI_SRIOV_CTRL_INTR   0x0004  /* VF Migration Interrupt Enable */
+#define  PCI_SRIOV_CTRL_MSE    0x0008  /* VF Memory Space Enable */
+#define  PCI_SRIOV_CTRL_ARI    0x0010  /* ARI Capable Hierarchy */
 #define PCI_SRIOV_STATUS       0x0a    /* SR-IOV Status */
-#define  PCI_SRIOV_STATUS_VFM  0x01    /* VF Migration Status */
+#define  PCI_SRIOV_STATUS_VFM  0x0001  /* VF Migration Status */
 #define PCI_SRIOV_INITIAL_VF   0x0c    /* Initial VFs */
 #define PCI_SRIOV_TOTAL_VF     0x0e    /* Total VFs */
 #define PCI_SRIOV_NUM_VF       0x10    /* Number of VFs */
 
 /* Access Control Service */
 #define PCI_ACS_CAP            0x04    /* ACS Capability Register */
-#define  PCI_ACS_SV            0x01    /* Source Validation */
-#define  PCI_ACS_TB            0x02    /* Translation Blocking */
-#define  PCI_ACS_RR            0x04    /* P2P Request Redirect */
-#define  PCI_ACS_CR            0x08    /* P2P Completion Redirect */
-#define  PCI_ACS_UF            0x10    /* Upstream Forwarding */
-#define  PCI_ACS_EC            0x20    /* P2P Egress Control */
-#define  PCI_ACS_DT            0x40    /* Direct Translated P2P */
+#define  PCI_ACS_SV            0x0001  /* Source Validation */
+#define  PCI_ACS_TB            0x0002  /* Translation Blocking */
+#define  PCI_ACS_RR            0x0004  /* P2P Request Redirect */
+#define  PCI_ACS_CR            0x0008  /* P2P Completion Redirect */
+#define  PCI_ACS_UF            0x0010  /* Upstream Forwarding */
+#define  PCI_ACS_EC            0x0020  /* P2P Egress Control */
+#define  PCI_ACS_DT            0x0040  /* Direct Translated P2P */
 #define PCI_ACS_EGRESS_BITS    0x05    /* ACS Egress Control Vector Size */
 #define PCI_ACS_CTRL           0x06    /* ACS Control Register */
 #define PCI_ACS_EGRESS_CTL_V   0x08    /* ACS Egress Control Vector */
 #define  PCI_EXP_DPC_CAP_DL_ACTIVE     0x1000  /* ERR_COR signal on DL_Active supported */
 
 #define PCI_EXP_DPC_CTL                        6       /* DPC control */
-#define  PCI_EXP_DPC_CTL_EN_FATAL      0x0001  /* Enable trigger on ERR_FATAL message */
-#define  PCI_EXP_DPC_CTL_EN_NONFATAL   0x0002  /* Enable trigger on ERR_NONFATAL message */
-#define  PCI_EXP_DPC_CTL_INT_EN        0x0008  /* DPC Interrupt Enable */
+#define  PCI_EXP_DPC_CTL_EN_FATAL      0x0001  /* Enable trigger on ERR_FATAL message */
+#define  PCI_EXP_DPC_CTL_EN_NONFATAL   0x0002  /* Enable trigger on ERR_NONFATAL message */
+#define  PCI_EXP_DPC_CTL_INT_EN                0x0008  /* DPC Interrupt Enable */
 
 #define PCI_EXP_DPC_STATUS             8       /* DPC Status */
 #define  PCI_EXP_DPC_STATUS_TRIGGER        0x0001 /* Trigger Status */
index 4f4daf8db954330605a4788a4cd3bb161e194389..c912b5a678e4270010359cd13f9fba01744de906 100644 (file)
@@ -50,7 +50,7 @@ struct switchtec_ioctl_flash_part_info {
        __u32 active;
 };
 
-struct switchtec_ioctl_event_summary {
+struct switchtec_ioctl_event_summary_legacy {
        __u64 global;
        __u64 part_bitmap;
        __u32 local_part;
@@ -59,6 +59,15 @@ struct switchtec_ioctl_event_summary {
        __u32 pff[48];
 };
 
+struct switchtec_ioctl_event_summary {
+       __u64 global;
+       __u64 part_bitmap;
+       __u32 local_part;
+       __u32 padding;
+       __u32 part[48];
+       __u32 pff[255];
+};
+
 #define SWITCHTEC_IOCTL_EVENT_STACK_ERROR              0
 #define SWITCHTEC_IOCTL_EVENT_PPU_ERROR                        1
 #define SWITCHTEC_IOCTL_EVENT_ISP_ERROR                        2
@@ -127,6 +136,8 @@ struct switchtec_ioctl_pff_port {
        _IOWR('W', 0x41, struct switchtec_ioctl_flash_part_info)
 #define SWITCHTEC_IOCTL_EVENT_SUMMARY \
        _IOR('W', 0x42, struct switchtec_ioctl_event_summary)
+#define SWITCHTEC_IOCTL_EVENT_SUMMARY_LEGACY \
+       _IOR('W', 0x42, struct switchtec_ioctl_event_summary_legacy)
 #define SWITCHTEC_IOCTL_EVENT_CTL \
        _IOWR('W', 0x43, struct switchtec_ioctl_event_ctl)
 #define SWITCHTEC_IOCTL_PFF_TO_PORT \
index 42a8bdc40a14e6d984e570926074019007f8a7a8..41db51367efafb3d2abb5103e59ddc04b3d61e99 100644 (file)
@@ -250,7 +250,7 @@ enum rdma_nldev_command {
 
        RDMA_NLDEV_CMD_PORT_GET, /* can dump */
 
-       RDMA_NLDEV_CMD_SYS_GET, /* can dump */
+       RDMA_NLDEV_CMD_SYS_GET,
        RDMA_NLDEV_CMD_SYS_SET,
 
        /* 8 is free to use */
index 7d09e54ae54e0f2b1dab07d76cf0be4718f20369..58fb5732831a4325f31ba7e66ef15aeb4a026516 100644 (file)
@@ -48,6 +48,13 @@ struct dlfb_data {
        int base8;
        u32 pseudo_palette[256];
        int blank_mode; /*one of FB_BLANK_ */
+       struct mutex render_mutex;
+       int damage_x;
+       int damage_y;
+       int damage_x2;
+       int damage_y2;
+       spinlock_t damage_lock;
+       struct work_struct damage_work;
        struct fb_ops ops;
        /* blit-only rendering path metrics, exposed through sysfs */
        atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */
index 82b84e5ee30d5387c8ff0d6a03caf1bb054e651c..8b9ffe236e4fea14355d65b92bb7ffd9b3ffc40d 100644 (file)
@@ -1752,6 +1752,30 @@ config SLAB_FREELIST_HARDENED
          sacrifies to harden the kernel slab allocator against common
          freelist exploit methods.
 
+config SHUFFLE_PAGE_ALLOCATOR
+       bool "Page allocator randomization"
+       default SLAB_FREELIST_RANDOM && ACPI_NUMA
+       help
+         Randomization of the page allocator improves the average
+         utilization of a direct-mapped memory-side-cache. See section
+         5.2.27 Heterogeneous Memory Attribute Table (HMAT) in the ACPI
+         6.2a specification for an example of how a platform advertises
+         the presence of a memory-side-cache. There are also incidental
+         security benefits as it reduces the predictability of page
+         allocations to compliment SLAB_FREELIST_RANDOM, but the
+         default granularity of shuffling on the "MAX_ORDER - 1" i.e,
+         10th order of pages is selected based on cache utilization
+         benefits on x86.
+
+         While the randomization improves cache utilization it may
+         negatively impact workloads on platforms without a cache. For
+         this reason, by default, the randomization is enabled only
+         after runtime detection of a direct-mapped memory-side-cache.
+         Otherwise, the randomization may be force enabled with the
+         'page_alloc.shuffle' kernel command line parameter.
+
+         Say Y if unsure.
+
 config SLUB_CPU_PARTIAL
        default y
        depends on SLUB && SMP
index 4749e1115eef3c8d079ab81c13a6a743314e1ef2..435a428c2af1cc3cdd021b08c5976e7e7ba9e64e 100644 (file)
@@ -513,42 +513,55 @@ static int __init retain_initrd_param(char *str)
 }
 __setup("retain_initrd", retain_initrd_param);
 
+#ifdef CONFIG_ARCH_HAS_KEEPINITRD
+static int __init keepinitrd_setup(char *__unused)
+{
+       do_retain_initrd = 1;
+       return 1;
+}
+__setup("keepinitrd", keepinitrd_setup);
+#endif
+
 extern char __initramfs_start[];
 extern unsigned long __initramfs_size;
 #include <linux/initrd.h>
 #include <linux/kexec.h>
 
-static void __init free_initrd(void)
+void __weak free_initrd_mem(unsigned long start, unsigned long end)
 {
+       free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+                       "initrd");
+}
+
 #ifdef CONFIG_KEXEC_CORE
+static bool kexec_free_initrd(void)
+{
        unsigned long crashk_start = (unsigned long)__va(crashk_res.start);
        unsigned long crashk_end   = (unsigned long)__va(crashk_res.end);
-#endif
-       if (do_retain_initrd)
-               goto skip;
 
-#ifdef CONFIG_KEXEC_CORE
        /*
         * If the initrd region is overlapped with crashkernel reserved region,
         * free only memory that is not part of crashkernel region.
         */
-       if (initrd_start < crashk_end && initrd_end > crashk_start) {
-               /*
-                * Initialize initrd memory region since the kexec boot does
-                * not do.
-                */
-               memset((void *)initrd_start, 0, initrd_end - initrd_start);
-               if (initrd_start < crashk_start)
-                       free_initrd_mem(initrd_start, crashk_start);
-               if (initrd_end > crashk_end)
-                       free_initrd_mem(crashk_end, initrd_end);
-       } else
-#endif
-               free_initrd_mem(initrd_start, initrd_end);
-skip:
-       initrd_start = 0;
-       initrd_end = 0;
+       if (initrd_start >= crashk_end || initrd_end <= crashk_start)
+               return false;
+
+       /*
+        * Initialize initrd memory region since the kexec boot does not do.
+        */
+       memset((void *)initrd_start, 0, initrd_end - initrd_start);
+       if (initrd_start < crashk_start)
+               free_initrd_mem(initrd_start, crashk_start);
+       if (initrd_end > crashk_end)
+               free_initrd_mem(crashk_end, initrd_end);
+       return true;
+}
+#else
+static inline bool kexec_free_initrd(void)
+{
+       return false;
 }
+#endif /* CONFIG_KEXEC_CORE */
 
 #ifdef CONFIG_BLK_DEV_RAM
 #define BUF_SIZE 1024
@@ -597,7 +610,38 @@ static void __init clean_rootfs(void)
        ksys_close(fd);
        kfree(buf);
 }
-#endif
+#else
+static inline void clean_rootfs(void)
+{
+}
+#endif /* CONFIG_BLK_DEV_RAM */
+
+#ifdef CONFIG_BLK_DEV_RAM
+static void populate_initrd_image(char *err)
+{
+       ssize_t written;
+       int fd;
+
+       unpack_to_rootfs(__initramfs_start, __initramfs_size);
+
+       printk(KERN_INFO "rootfs image is not initramfs (%s); looks like an initrd\n",
+                       err);
+       fd = ksys_open("/initrd.image", O_WRONLY | O_CREAT, 0700);
+       if (fd < 0)
+               return;
+
+       written = xwrite(fd, (char *)initrd_start, initrd_end - initrd_start);
+       if (written != initrd_end - initrd_start)
+               pr_err("/initrd.image: incomplete write (%zd != %ld)\n",
+                      written, initrd_end - initrd_start);
+       ksys_close(fd);
+}
+#else
+static void populate_initrd_image(char *err)
+{
+       printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);
+}
+#endif /* CONFIG_BLK_DEV_RAM */
 
 static int __init populate_rootfs(void)
 {
@@ -605,46 +649,31 @@ static int __init populate_rootfs(void)
        char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
        if (err)
                panic("%s", err); /* Failed to decompress INTERNAL initramfs */
-       /* If available load the bootloader supplied initrd */
-       if (initrd_start && !IS_ENABLED(CONFIG_INITRAMFS_FORCE)) {
-#ifdef CONFIG_BLK_DEV_RAM
-               int fd;
+
+       if (!initrd_start || IS_ENABLED(CONFIG_INITRAMFS_FORCE))
+               goto done;
+
+       if (IS_ENABLED(CONFIG_BLK_DEV_RAM))
                printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n");
-               err = unpack_to_rootfs((char *)initrd_start,
-                       initrd_end - initrd_start);
-               if (!err) {
-                       free_initrd();
-                       goto done;
-               } else {
-                       clean_rootfs();
-                       unpack_to_rootfs(__initramfs_start, __initramfs_size);
-               }
-               printk(KERN_INFO "rootfs image is not initramfs (%s)"
-                               "; looks like an initrd\n", err);
-               fd = ksys_open("/initrd.image",
-                             O_WRONLY|O_CREAT, 0700);
-               if (fd >= 0) {
-                       ssize_t written = xwrite(fd, (char *)initrd_start,
-                                               initrd_end - initrd_start);
-
-                       if (written != initrd_end - initrd_start)
-                               pr_err("/initrd.image: incomplete write (%zd != %ld)\n",
-                                      written, initrd_end - initrd_start);
-
-                       ksys_close(fd);
-                       free_initrd();
-               }
-       done:
-               /* empty statement */;
-#else
+       else
                printk(KERN_INFO "Unpacking initramfs...\n");
-               err = unpack_to_rootfs((char *)initrd_start,
-                       initrd_end - initrd_start);
-               if (err)
-                       printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);
-               free_initrd();
-#endif
+
+       err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start);
+       if (err) {
+               clean_rootfs();
+               populate_initrd_image(err);
        }
+
+done:
+       /*
+        * If the initrd region is overlapped with crashkernel reserved region,
+        * free only memory that is not part of crashkernel region.
+        */
+       if (!do_retain_initrd && !kexec_free_initrd())
+               free_initrd_mem(initrd_start, initrd_end);
+       initrd_start = 0;
+       initrd_end = 0;
+
        flush_delayed_fput();
        return 0;
 }
index 33c87e91dc37aa778389244687bfea3cfb5d12ef..5a2c69b4d7b3ac040f45eb0b2922bfcd7d2ab832 100644 (file)
@@ -1074,6 +1074,11 @@ static inline void mark_readonly(void)
 }
 #endif
 
+void __weak free_initmem(void)
+{
+       free_initmem_default(POISON_FREE_INITMEM);
+}
+
 static int __ref kernel_init(void *unused)
 {
        int ret;
index 49f9bf4ffc7f1ae09bc04b833891fcc7d7a5a5a5..bfaae457810ca8c690f784bfd1fb0f62043c4fd8 100644 (file)
@@ -120,7 +120,9 @@ static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
 static int zero;
 static int one = 1;
 static int int_max = INT_MAX;
-static int ipc_mni = IPCMNI;
+int ipc_mni = IPCMNI;
+int ipc_mni_shift = IPCMNI_SHIFT;
+int ipc_min_cycle = RADIX_TREE_MAP_SIZE;
 
 static struct ctl_table ipc_kern_table[] = {
        {
@@ -246,3 +248,13 @@ static int __init ipc_sysctl_init(void)
 }
 
 device_initcall(ipc_sysctl_init);
+
+static int __init ipc_mni_extend(char *str)
+{
+       ipc_mni = IPCMNI_EXTEND;
+       ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
+       ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
+       pr_info("IPCMNI extended to %d.\n", ipc_mni);
+       return 0;
+}
+early_param("ipcmni_extend", ipc_mni_extend);
index ba44164ea1f91f53868bdee549bab04d54ddbb84..216cad1ff0d0c475c6f6755156abc57d89573e0c 100644 (file)
@@ -76,6 +76,7 @@ struct mqueue_inode_info {
        wait_queue_head_t wait_q;
 
        struct rb_root msg_tree;
+       struct rb_node *msg_tree_rightmost;
        struct posix_msg_tree_node *node_cache;
        struct mq_attr attr;
 
@@ -131,6 +132,7 @@ static int msg_insert(struct msg_msg *msg, struct mqueue_inode_info *info)
 {
        struct rb_node **p, *parent = NULL;
        struct posix_msg_tree_node *leaf;
+       bool rightmost = true;
 
        p = &info->msg_tree.rb_node;
        while (*p) {
@@ -139,9 +141,10 @@ static int msg_insert(struct msg_msg *msg, struct mqueue_inode_info *info)
 
                if (likely(leaf->priority == msg->m_type))
                        goto insert_msg;
-               else if (msg->m_type < leaf->priority)
+               else if (msg->m_type < leaf->priority) {
                        p = &(*p)->rb_left;
-               else
+                       rightmost = false;
+               } else
                        p = &(*p)->rb_right;
        }
        if (info->node_cache) {
@@ -154,6 +157,10 @@ static int msg_insert(struct msg_msg *msg, struct mqueue_inode_info *info)
                INIT_LIST_HEAD(&leaf->msg_list);
        }
        leaf->priority = msg->m_type;
+
+       if (rightmost)
+               info->msg_tree_rightmost = &leaf->rb_node;
+
        rb_link_node(&leaf->rb_node, parent, p);
        rb_insert_color(&leaf->rb_node, &info->msg_tree);
 insert_msg:
@@ -163,23 +170,35 @@ insert_msg:
        return 0;
 }
 
+static inline void msg_tree_erase(struct posix_msg_tree_node *leaf,
+                                 struct mqueue_inode_info *info)
+{
+       struct rb_node *node = &leaf->rb_node;
+
+       if (info->msg_tree_rightmost == node)
+               info->msg_tree_rightmost = rb_prev(node);
+
+       rb_erase(node, &info->msg_tree);
+       if (info->node_cache) {
+               kfree(leaf);
+       } else {
+               info->node_cache = leaf;
+       }
+}
+
 static inline struct msg_msg *msg_get(struct mqueue_inode_info *info)
 {
-       struct rb_node **p, *parent = NULL;
+       struct rb_node *parent = NULL;
        struct posix_msg_tree_node *leaf;
        struct msg_msg *msg;
 
 try_again:
-       p = &info->msg_tree.rb_node;
-       while (*p) {
-               parent = *p;
-               /*
-                * During insert, low priorities go to the left and high to the
-                * right.  On receive, we want the highest priorities first, so
-                * walk all the way to the right.
-                */
-               p = &(*p)->rb_right;
-       }
+       /*
+        * During insert, low priorities go to the left and high to the
+        * right.  On receive, we want the highest priorities first, so
+        * walk all the way to the right.
+        */
+       parent = info->msg_tree_rightmost;
        if (!parent) {
                if (info->attr.mq_curmsgs) {
                        pr_warn_once("Inconsistency in POSIX message queue, "
@@ -194,24 +213,14 @@ try_again:
                pr_warn_once("Inconsistency in POSIX message queue, "
                             "empty leaf node but we haven't implemented "
                             "lazy leaf delete!\n");
-               rb_erase(&leaf->rb_node, &info->msg_tree);
-               if (info->node_cache) {
-                       kfree(leaf);
-               } else {
-                       info->node_cache = leaf;
-               }
+               msg_tree_erase(leaf, info);
                goto try_again;
        } else {
                msg = list_first_entry(&leaf->msg_list,
                                       struct msg_msg, m_list);
                list_del(&msg->m_list);
                if (list_empty(&leaf->msg_list)) {
-                       rb_erase(&leaf->rb_node, &info->msg_tree);
-                       if (info->node_cache) {
-                               kfree(leaf);
-                       } else {
-                               info->node_cache = leaf;
-                       }
+                       msg_tree_erase(leaf, info);
                }
        }
        info->attr.mq_curmsgs--;
@@ -254,6 +263,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
                info->qsize = 0;
                info->user = NULL;      /* set when all is ok */
                info->msg_tree = RB_ROOT;
+               info->msg_tree_rightmost = NULL;
                info->node_cache = NULL;
                memset(&info->attr, 0, sizeof(info->attr));
                info->attr.mq_maxmsg = min(ipc_ns->mq_msg_max,
@@ -430,7 +440,8 @@ static void mqueue_evict_inode(struct inode *inode)
        struct user_struct *user;
        unsigned long mq_bytes, mq_treesize;
        struct ipc_namespace *ipc_ns;
-       struct msg_msg *msg;
+       struct msg_msg *msg, *nmsg;
+       LIST_HEAD(tmp_msg);
 
        clear_inode(inode);
 
@@ -441,10 +452,15 @@ static void mqueue_evict_inode(struct inode *inode)
        info = MQUEUE_I(inode);
        spin_lock(&info->lock);
        while ((msg = msg_get(info)) != NULL)
-               free_msg(msg);
+               list_add_tail(&msg->m_list, &tmp_msg);
        kfree(info->node_cache);
        spin_unlock(&info->lock);
 
+       list_for_each_entry_safe(msg, nmsg, &tmp_msg, m_list) {
+               list_del(&msg->m_list);
+               free_msg(msg);
+       }
+
        /* Total amount of bytes accounted for the mqueue */
        mq_treesize = info->attr.mq_maxmsg * sizeof(struct msg_msg) +
                min_t(unsigned int, info->attr.mq_maxmsg, MQ_PRIO_MAX) *
@@ -605,8 +621,6 @@ static void wq_add(struct mqueue_inode_info *info, int sr,
 {
        struct ext_wait_queue *walk;
 
-       ewp->task = current;
-
        list_for_each_entry(walk, &info->e_wait_q[sr].list, list) {
                if (walk->task->prio <= current->prio) {
                        list_add_tail(&ewp->list, &walk->list);
index 84598025a6ade1faaf412d3ae67e5c2bda32e294..e65593742e2be5965f45929d485b54e8707f6d0d 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/utsname.h>
 #include <linux/proc_ns.h>
 #include <linux/uaccess.h>
+#include <linux/sched.h>
 
 #include "util.h"
 
@@ -64,6 +65,9 @@ static struct msg_msg *alloc_msg(size_t len)
        pseg = &msg->next;
        while (len > 0) {
                struct msg_msgseg *seg;
+
+               cond_resched();
+
                alen = min(len, DATALEN_SEG);
                seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL_ACCOUNT);
                if (seg == NULL)
@@ -176,6 +180,8 @@ void free_msg(struct msg_msg *msg)
        kfree(msg);
        while (seg != NULL) {
                struct msg_msgseg *tmp = seg->next;
+
+               cond_resched();
                kfree(seg);
                seg = tmp;
        }
index 095274a871f89b9d37f825d9190355a8592a10b3..d126d156efc64e7d2d710197cf50377c12ad620d 100644 (file)
@@ -109,7 +109,7 @@ static const struct rhashtable_params ipc_kht_params = {
  * @ids: ipc identifier set
  *
  * Set up the sequence range to use for the ipc identifier range (limited
- * below IPCMNI) then initialise the keys hashtable and ids idr.
+ * below ipc_mni) then initialise the keys hashtable and ids idr.
  */
 void ipc_init_ids(struct ipc_ids *ids)
 {
@@ -119,6 +119,7 @@ void ipc_init_ids(struct ipc_ids *ids)
        rhashtable_init(&ids->key_ht, &ipc_kht_params);
        idr_init(&ids->ipcs_idr);
        ids->max_idx = -1;
+       ids->last_idx = -1;
 #ifdef CONFIG_CHECKPOINT_RESTORE
        ids->next_id = -1;
 #endif
@@ -192,6 +193,10 @@ static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
  *
  * The caller must own kern_ipc_perm.lock.of the new object.
  * On error, the function returns a (negative) error code.
+ *
+ * To conserve sequence number space, especially with extended ipc_mni,
+ * the sequence number is incremented only when the returned ID is less than
+ * the last one.
  */
 static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new)
 {
@@ -215,17 +220,42 @@ static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new)
         */
 
        if (next_id < 0) { /* !CHECKPOINT_RESTORE or next_id is unset */
-               new->seq = ids->seq++;
-               if (ids->seq > IPCID_SEQ_MAX)
-                       ids->seq = 0;
-               idx = idr_alloc(&ids->ipcs_idr, new, 0, 0, GFP_NOWAIT);
+               int max_idx;
+
+               max_idx = max(ids->in_use*3/2, ipc_min_cycle);
+               max_idx = min(max_idx, ipc_mni);
+
+               /* allocate the idx, with a NULL struct kern_ipc_perm */
+               idx = idr_alloc_cyclic(&ids->ipcs_idr, NULL, 0, max_idx,
+                                       GFP_NOWAIT);
+
+               if (idx >= 0) {
+                       /*
+                        * idx got allocated successfully.
+                        * Now calculate the sequence number and set the
+                        * pointer for real.
+                        */
+                       if (idx <= ids->last_idx) {
+                               ids->seq++;
+                               if (ids->seq >= ipcid_seq_max())
+                                       ids->seq = 0;
+                       }
+                       ids->last_idx = idx;
+
+                       new->seq = ids->seq;
+                       /* no need for smp_wmb(), this is done
+                        * inside idr_replace, as part of
+                        * rcu_assign_pointer
+                        */
+                       idr_replace(&ids->ipcs_idr, new, idx);
+               }
        } else {
                new->seq = ipcid_to_seqx(next_id);
                idx = idr_alloc(&ids->ipcs_idr, new, ipcid_to_idx(next_id),
                                0, GFP_NOWAIT);
        }
        if (idx >= 0)
-               new->id = SEQ_MULTIPLIER * new->seq + idx;
+               new->id = (new->seq << ipcmni_seq_shift()) + idx;
        return idx;
 }
 
@@ -253,8 +283,8 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit)
        /* 1) Initialize the refcount so that ipc_rcu_putref works */
        refcount_set(&new->refcount, 1);
 
-       if (limit > IPCMNI)
-               limit = IPCMNI;
+       if (limit > ipc_mni)
+               limit = ipc_mni;
 
        if (ids->in_use >= limit)
                return -ENOSPC;
@@ -737,7 +767,7 @@ static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
        if (total >= ids->in_use)
                return NULL;
 
-       for (; pos < IPCMNI; pos++) {
+       for (; pos < ipc_mni; pos++) {
                ipc = idr_find(&ids->ipcs_idr, pos);
                if (ipc != NULL) {
                        *new_pos = pos + 1;
index e272be622ae79b4e751202e3d781183975bd0794..0fcf8e719b7647fe7e59141c153b2485c95c4399 100644 (file)
 #include <linux/err.h>
 #include <linux/ipc_namespace.h>
 
-#define IPCMNI 32768  /* <= MAX_INT limit for ipc arrays (including sysctl changes) */
-#define SEQ_MULTIPLIER (IPCMNI)
+/*
+ * The IPC ID contains 2 separate numbers - index and sequence number.
+ * By default,
+ *   bits  0-14: index (32k, 15 bits)
+ *   bits 15-30: sequence number (64k, 16 bits)
+ *
+ * When IPCMNI extension mode is turned on, the composition changes:
+ *   bits  0-23: index (16M, 24 bits)
+ *   bits 24-30: sequence number (128, 7 bits)
+ */
+#define IPCMNI_SHIFT           15
+#define IPCMNI_EXTEND_SHIFT    24
+#define IPCMNI_EXTEND_MIN_CYCLE        (RADIX_TREE_MAP_SIZE * RADIX_TREE_MAP_SIZE)
+#define IPCMNI                 (1 << IPCMNI_SHIFT)
+#define IPCMNI_EXTEND          (1 << IPCMNI_EXTEND_SHIFT)
+
+#ifdef CONFIG_SYSVIPC_SYSCTL
+extern int ipc_mni;
+extern int ipc_mni_shift;
+extern int ipc_min_cycle;
+
+#define ipcmni_seq_shift()     ipc_mni_shift
+#define IPCMNI_IDX_MASK                ((1 << ipc_mni_shift) - 1)
+
+#else /* CONFIG_SYSVIPC_SYSCTL */
+
+#define ipc_mni                        IPCMNI
+#define ipc_min_cycle          ((int)RADIX_TREE_MAP_SIZE)
+#define ipcmni_seq_shift()     IPCMNI_SHIFT
+#define IPCMNI_IDX_MASK                ((1 << IPCMNI_SHIFT) - 1)
+#endif /* CONFIG_SYSVIPC_SYSCTL */
 
 void sem_init(void);
 void msg_init(void);
@@ -96,9 +125,9 @@ struct pid_namespace *ipc_seq_pid_ns(struct seq_file *);
 #define IPC_MSG_IDS    1
 #define IPC_SHM_IDS    2
 
-#define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER)
-#define ipcid_to_seqx(id) ((id) / SEQ_MULTIPLIER)
-#define IPCID_SEQ_MAX min_t(int, INT_MAX/SEQ_MULTIPLIER, USHRT_MAX)
+#define ipcid_to_idx(id)  ((id) & IPCMNI_IDX_MASK)
+#define ipcid_to_seqx(id) ((id) >> ipcmni_seq_shift())
+#define ipcid_seq_max()          (INT_MAX >> ipcmni_seq_shift())
 
 /* must be called with ids->rwsem acquired for writing */
 int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
@@ -123,8 +152,8 @@ static inline int ipc_get_maxidx(struct ipc_ids *ids)
        if (ids->in_use == 0)
                return -1;
 
-       if (ids->in_use == IPCMNI)
-               return IPCMNI - 1;
+       if (ids->in_use == ipc_mni)
+               return ipc_mni - 1;
 
        return ids->max_idx;
 }
@@ -216,10 +245,10 @@ void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
 
 static inline int sem_check_semmni(struct ipc_namespace *ns) {
        /*
-        * Check semmni range [0, IPCMNI]
+        * Check semmni range [0, ipc_mni]
         * semmni is the last element of sem_ctls[4] array
         */
-       return ((ns->sem_ctls[3] < 0) || (ns->sem_ctls[3] > IPCMNI))
+       return ((ns->sem_ctls[3] < 0) || (ns->sem_ctls[3] > ipc_mni))
                ? -ERANGE : 0;
 }
 
index 298437bb2c6a16806245af72328434fb247ae53f..33824f0385b3a3f5070e529d34f44b00c934e2a6 100644 (file)
@@ -127,7 +127,7 @@ $(obj)/config_data.gz: $(KCONFIG_CONFIG) FORCE
 $(obj)/kheaders.o: $(obj)/kheaders_data.tar.xz
 
 quiet_cmd_genikh = CHK     $(obj)/kheaders_data.tar.xz
-cmd_genikh = $(srctree)/kernel/gen_ikh_data.sh $@
+cmd_genikh = $(CONFIG_SHELL) $(srctree)/kernel/gen_ikh_data.sh $@
 $(obj)/kheaders_data.tar.xz: FORCE
        $(call cmd,genikh)
 
index 3ba56e73c90e87db4dde46ca4ed26b147537ec96..242a643af82fe6422ef902192fe7ff7971d32808 100644 (file)
@@ -338,7 +338,7 @@ int bpf_prog_calc_tag(struct bpf_prog *fp)
 }
 
 static int bpf_adj_delta_to_imm(struct bpf_insn *insn, u32 pos, s32 end_old,
-                               s32 end_new, u32 curr, const bool probe_pass)
+                               s32 end_new, s32 curr, const bool probe_pass)
 {
        const s64 imm_min = S32_MIN, imm_max = S32_MAX;
        s32 delta = end_new - end_old;
@@ -356,7 +356,7 @@ static int bpf_adj_delta_to_imm(struct bpf_insn *insn, u32 pos, s32 end_old,
 }
 
 static int bpf_adj_delta_to_off(struct bpf_insn *insn, u32 pos, s32 end_old,
-                               s32 end_new, u32 curr, const bool probe_pass)
+                               s32 end_new, s32 curr, const bool probe_pass)
 {
        const s32 off_min = S16_MIN, off_max = S16_MAX;
        s32 delta = end_new - end_old;
index 7b05e8938d5cc69192b768a78108223d8322010c..95f9354495ad833ae7c981e551a518a478897fd0 100644 (file)
@@ -7599,7 +7599,7 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
                                                                        insn->dst_reg,
                                                                        shift);
                                insn_buf[cnt++] = BPF_ALU64_IMM(BPF_AND, insn->dst_reg,
-                                                               (1 << size * 8) - 1);
+                                                               (1ULL << size * 8) - 1);
                        }
                }
 
index 327f37c9fdfaaf4ca9ea475129fa8b28cb75fe6a..217cec4e22c68c6053b0e8406b670affd64963dc 100644 (file)
@@ -3540,17 +3540,84 @@ static int cpu_stat_show(struct seq_file *seq, void *v)
 #ifdef CONFIG_PSI
 static int cgroup_io_pressure_show(struct seq_file *seq, void *v)
 {
-       return psi_show(seq, &seq_css(seq)->cgroup->psi, PSI_IO);
+       struct cgroup *cgroup = seq_css(seq)->cgroup;
+       struct psi_group *psi = cgroup->id == 1 ? &psi_system : &cgroup->psi;
+
+       return psi_show(seq, psi, PSI_IO);
 }
 static int cgroup_memory_pressure_show(struct seq_file *seq, void *v)
 {
-       return psi_show(seq, &seq_css(seq)->cgroup->psi, PSI_MEM);
+       struct cgroup *cgroup = seq_css(seq)->cgroup;
+       struct psi_group *psi = cgroup->id == 1 ? &psi_system : &cgroup->psi;
+
+       return psi_show(seq, psi, PSI_MEM);
 }
 static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v)
 {
-       return psi_show(seq, &seq_css(seq)->cgroup->psi, PSI_CPU);
+       struct cgroup *cgroup = seq_css(seq)->cgroup;
+       struct psi_group *psi = cgroup->id == 1 ? &psi_system : &cgroup->psi;
+
+       return psi_show(seq, psi, PSI_CPU);
 }
-#endif
+
+static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf,
+                                         size_t nbytes, enum psi_res res)
+{
+       struct psi_trigger *new;
+       struct cgroup *cgrp;
+
+       cgrp = cgroup_kn_lock_live(of->kn, false);
+       if (!cgrp)
+               return -ENODEV;
+
+       cgroup_get(cgrp);
+       cgroup_kn_unlock(of->kn);
+
+       new = psi_trigger_create(&cgrp->psi, buf, nbytes, res);
+       if (IS_ERR(new)) {
+               cgroup_put(cgrp);
+               return PTR_ERR(new);
+       }
+
+       psi_trigger_replace(&of->priv, new);
+
+       cgroup_put(cgrp);
+
+       return nbytes;
+}
+
+static ssize_t cgroup_io_pressure_write(struct kernfs_open_file *of,
+                                         char *buf, size_t nbytes,
+                                         loff_t off)
+{
+       return cgroup_pressure_write(of, buf, nbytes, PSI_IO);
+}
+
+static ssize_t cgroup_memory_pressure_write(struct kernfs_open_file *of,
+                                         char *buf, size_t nbytes,
+                                         loff_t off)
+{
+       return cgroup_pressure_write(of, buf, nbytes, PSI_MEM);
+}
+
+static ssize_t cgroup_cpu_pressure_write(struct kernfs_open_file *of,
+                                         char *buf, size_t nbytes,
+                                         loff_t off)
+{
+       return cgroup_pressure_write(of, buf, nbytes, PSI_CPU);
+}
+
+static __poll_t cgroup_pressure_poll(struct kernfs_open_file *of,
+                                         poll_table *pt)
+{
+       return psi_trigger_poll(&of->priv, of->file, pt);
+}
+
+static void cgroup_pressure_release(struct kernfs_open_file *of)
+{
+       psi_trigger_replace(&of->priv, NULL);
+}
+#endif /* CONFIG_PSI */
 
 static int cgroup_freeze_show(struct seq_file *seq, void *v)
 {
@@ -4743,20 +4810,26 @@ static struct cftype cgroup_base_files[] = {
 #ifdef CONFIG_PSI
        {
                .name = "io.pressure",
-               .flags = CFTYPE_NOT_ON_ROOT,
                .seq_show = cgroup_io_pressure_show,
+               .write = cgroup_io_pressure_write,
+               .poll = cgroup_pressure_poll,
+               .release = cgroup_pressure_release,
        },
        {
                .name = "memory.pressure",
-               .flags = CFTYPE_NOT_ON_ROOT,
                .seq_show = cgroup_memory_pressure_show,
+               .write = cgroup_memory_pressure_write,
+               .poll = cgroup_pressure_poll,
+               .release = cgroup_pressure_release,
        },
        {
                .name = "cpu.pressure",
-               .flags = CFTYPE_NOT_ON_ROOT,
                .seq_show = cgroup_cpu_pressure_show,
+               .write = cgroup_cpu_pressure_write,
+               .poll = cgroup_pressure_poll,
+               .release = cgroup_pressure_release,
        },
-#endif
+#endif /* CONFIG_PSI */
        { }     /* terminate */
 };
 
index d8a36c6ad7c91046ff71bd1833ded3c0f2d989a6..b5f7063c0db60dd192ca1f882e492ff16a7477f1 100644 (file)
@@ -346,8 +346,11 @@ get_compat_sigset(sigset_t *set, const compat_sigset_t __user *compat)
                return -EFAULT;
        switch (_NSIG_WORDS) {
        case 4: set->sig[3] = v.sig[6] | (((long)v.sig[7]) << 32 );
+               /* fall through */
        case 3: set->sig[2] = v.sig[4] | (((long)v.sig[5]) << 32 );
+               /* fall through */
        case 2: set->sig[1] = v.sig[2] | (((long)v.sig[3]) << 32 );
+               /* fall through */
        case 1: set->sig[0] = v.sig[0] | (((long)v.sig[1]) << 32 );
        }
 #else
index 7510dc687c0dc1a2cd195b6f387bd3dc7e4b7614..4b280fc7dd67589affc3ed6106b78d1bbcc85781 100644 (file)
@@ -1033,13 +1033,14 @@ int gdb_serial_stub(struct kgdb_state *ks)
                                return DBG_PASS_EVENT;
                        }
 #endif
+                       /* Fall through */
                case 'C': /* Exception passing */
                        tmp = gdb_cmd_exception_pass(ks);
                        if (tmp > 0)
                                goto default_handle;
                        if (tmp == 0)
                                break;
-                       /* Fall through on tmp < 0 */
+                       /* Fall through on tmp < 0 */
                case 'c': /* Continue packet */
                case 's': /* Single step packet */
                        if (kgdb_contthread && kgdb_contthread != current) {
@@ -1048,7 +1049,7 @@ int gdb_serial_stub(struct kgdb_state *ks)
                                break;
                        }
                        dbg_activate_sw_breakpoints();
-                       /* Fall through to default processing */
+                       /* Fall through to default processing */
                default:
 default_handle:
                        error = kgdb_arch_handle_exception(ks->ex_vector,
@@ -1094,10 +1095,10 @@ int gdbstub_state(struct kgdb_state *ks, char *cmd)
                return error;
        case 's':
        case 'c':
-               strcpy(remcom_in_buffer, cmd);
+               strscpy(remcom_in_buffer, cmd, sizeof(remcom_in_buffer));
                return 0;
        case '$':
-               strcpy(remcom_in_buffer, cmd);
+               strscpy(remcom_in_buffer, cmd, sizeof(remcom_in_buffer));
                gdbstub_use_prev_in_buf = strlen(remcom_in_buffer);
                gdbstub_prev_in_buf_pos = 0;
                return 0;
index d4fc58f4b88dee4a076a157a0766d090c7415b03..efac857c55119f1252d0a32e956ea47f7d670b04 100644 (file)
@@ -6,7 +6,6 @@
 # Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
 #
 
-CCVERSION      := $(shell $(CC) -v 2>&1 | sed -ne '$$p')
 obj-y := kdb_io.o kdb_main.o kdb_support.o kdb_bt.o gen-kdb_cmds.o kdb_bp.o kdb_debugger.o
 obj-$(CONFIG_KDB_KEYBOARD)    += kdb_keyboard.o
 
index 6a4b41484afe654572f3b4f37186046c4541c8e5..3a5184eb6977d430f9df84493340ceaafe2cefde 100644 (file)
@@ -446,7 +446,7 @@ poll_again:
 char *kdb_getstr(char *buffer, size_t bufsize, const char *prompt)
 {
        if (prompt && kdb_prompt_str != prompt)
-               strncpy(kdb_prompt_str, prompt, CMD_BUFLEN);
+               strscpy(kdb_prompt_str, prompt, CMD_BUFLEN);
        kdb_printf(kdb_prompt_str);
        kdb_nextline = 1;       /* Prompt and input resets line number */
        return kdb_read(buffer, bufsize);
index 82a3b32a7cfc975ea99dba2eae7bdd7e23d070e9..9ecfa37c7fbfc2ba52d79c62d8e1991b0d28538a 100644 (file)
@@ -2522,7 +2522,6 @@ static int kdb_summary(int argc, const char **argv)
        kdb_printf("machine    %s\n", init_uts_ns.name.machine);
        kdb_printf("nodename   %s\n", init_uts_ns.name.nodename);
        kdb_printf("domainname %s\n", init_uts_ns.name.domainname);
-       kdb_printf("ccversion  %s\n", __stringify(CCVERSION));
 
        now = __ktime_get_real_seconds();
        time64_to_tm(now, 0, &tm);
@@ -2584,7 +2583,7 @@ static int kdb_per_cpu(int argc, const char **argv)
                diag = kdbgetularg(argv[3], &whichcpu);
                if (diag)
                        return diag;
-               if (!cpu_online(whichcpu)) {
+               if (whichcpu >= nr_cpu_ids || !cpu_online(whichcpu)) {
                        kdb_printf("cpu %ld is not online\n", whichcpu);
                        return KDB_BADCPUNUM;
                }
index 50bf9b119bad04952c767451a4e29315b0234ab0..b8e6306e7e133d452dad4c5e46e4753439d4b448 100644 (file)
@@ -192,7 +192,7 @@ int kallsyms_symbol_complete(char *prefix_name, int max_len)
 
        while ((name = kdb_walk_kallsyms(&pos))) {
                if (strncmp(name, prefix_name, prefix_len) == 0) {
-                       strcpy(ks_namebuf, name);
+                       strscpy(ks_namebuf, name, sizeof(ks_namebuf));
                        /* Work out the longest name that matches the prefix */
                        if (++number == 1) {
                                prev_len = min_t(int, max_len-1,
index 4ca7364c956def56c751d8361ccaf26aa2b35087..78f61bfc6b7976128d623a7915c5a394620b0bbd 100644 (file)
@@ -161,7 +161,8 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
        struct mmu_notifier_range range;
        struct mem_cgroup *memcg;
 
-       mmu_notifier_range_init(&range, mm, addr, addr + PAGE_SIZE);
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, mm, addr,
+                               addr + PAGE_SIZE);
 
        VM_BUG_ON_PAGE(PageTransHuge(old_page), old_page);
 
index 2166c2d92ddc0c8a0af6e5a1dd833fe0243fd06a..8361a560cd1d10849469146d90894fb6c25064c4 100644 (file)
@@ -422,7 +422,7 @@ retry:
         * freed task structure.
         */
        if (atomic_read(&mm->mm_users) <= 1) {
-               mm->owner = NULL;
+               WRITE_ONCE(mm->owner, NULL);
                return;
        }
 
@@ -462,7 +462,7 @@ retry:
         * most likely racing with swapoff (try_to_unuse()) or /proc or
         * ptrace or page migration (get_task_mm()).  Mark owner as NULL.
         */
-       mm->owner = NULL;
+       WRITE_ONCE(mm->owner, NULL);
        return;
 
 assign_new_owner:
@@ -483,7 +483,7 @@ assign_new_owner:
                put_task_struct(c);
                goto retry;
        }
-       mm->owner = c;
+       WRITE_ONCE(mm->owner, c);
        task_unlock(c);
        put_task_struct(c);
 }
index 5359facf98675d7746e29f3883b07be4e242dca1..b4cba953040a0f46ef6c9139099f1f9bef3b005e 100644 (file)
@@ -955,6 +955,15 @@ static void mm_init_aio(struct mm_struct *mm)
 #endif
 }
 
+static __always_inline void mm_clear_owner(struct mm_struct *mm,
+                                          struct task_struct *p)
+{
+#ifdef CONFIG_MEMCG
+       if (mm->owner == p)
+               WRITE_ONCE(mm->owner, NULL);
+#endif
+}
+
 static void mm_init_owner(struct mm_struct *mm, struct task_struct *p)
 {
 #ifdef CONFIG_MEMCG
@@ -1343,6 +1352,7 @@ static struct mm_struct *dup_mm(struct task_struct *tsk,
 free_pt:
        /* don't put binfmt in mmput, we haven't got module yet */
        mm->binfmt = NULL;
+       mm_init_owner(mm, NULL);
        mmput(mm);
 
 fail_nomem:
@@ -1726,6 +1736,21 @@ static int pidfd_create(struct pid *pid)
        return fd;
 }
 
+static void __delayed_free_task(struct rcu_head *rhp)
+{
+       struct task_struct *tsk = container_of(rhp, struct task_struct, rcu);
+
+       free_task(tsk);
+}
+
+static __always_inline void delayed_free_task(struct task_struct *tsk)
+{
+       if (IS_ENABLED(CONFIG_MEMCG))
+               call_rcu(&tsk->rcu, __delayed_free_task);
+       else
+               free_task(tsk);
+}
+
 /*
  * This creates a new process as a copy of the old one,
  * but does not actually start it yet.
@@ -2068,7 +2093,7 @@ static __latent_entropy struct task_struct *copy_process(
 #ifdef TIF_SYSCALL_EMU
        clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
 #endif
-       clear_all_latency_tracing(p);
+       clear_tsk_latency_tracing(p);
 
        /* ok, now we should be set up.. */
        p->pid = pid_nr(pid);
@@ -2102,7 +2127,7 @@ static __latent_entropy struct task_struct *copy_process(
         */
        retval = cgroup_can_fork(p);
        if (retval)
-               goto bad_fork_put_pidfd;
+               goto bad_fork_cgroup_threadgroup_change_end;
 
        /*
         * From this point on we must avoid any synchronous user-space
@@ -2217,11 +2242,12 @@ bad_fork_cancel_cgroup:
        spin_unlock(&current->sighand->siglock);
        write_unlock_irq(&tasklist_lock);
        cgroup_cancel_fork(p);
+bad_fork_cgroup_threadgroup_change_end:
+       cgroup_threadgroup_change_end(current);
 bad_fork_put_pidfd:
        if (clone_flags & CLONE_PIDFD)
                ksys_close(pidfd);
 bad_fork_free_pid:
-       cgroup_threadgroup_change_end(current);
        if (pid != &init_struct_pid)
                free_pid(pid);
 bad_fork_cleanup_thread:
@@ -2232,8 +2258,10 @@ bad_fork_cleanup_io:
 bad_fork_cleanup_namespaces:
        exit_task_namespaces(p);
 bad_fork_cleanup_mm:
-       if (p->mm)
+       if (p->mm) {
+               mm_clear_owner(p->mm, p);
                mmput(p->mm);
+       }
 bad_fork_cleanup_signal:
        if (!(clone_flags & CLONE_THREAD))
                free_signal_struct(p->signal);
@@ -2264,7 +2292,7 @@ bad_fork_cleanup_count:
 bad_fork_free:
        p->state = TASK_DEAD;
        put_task_stack(p);
-       free_task(p);
+       delayed_free_task(p);
 fork_out:
        spin_lock_irq(&current->sighand->siglock);
        hlist_del_init(&delayed.node);
index 6262f1534ac94d05bdfcde04fcf6b2eea95c3eaa..2268b97d5439d883825c4133dcf1df703d5bae32 100644 (file)
@@ -543,7 +543,7 @@ again:
        if (unlikely(should_fail_futex(fshared)))
                return -EFAULT;
 
-       err = get_user_pages_fast(address, 1, 1, &page);
+       err = get_user_pages_fast(address, 1, FOLL_WRITE, &page);
        /*
         * If write access is not required (eg. FUTEX_WAIT), try
         * and get read-only access.
index 1e3823fa799b299b88f1eeb3f5818ed7a31e905e..f71c1adcff3132646bfd26167ff3e57802bf68a2 100644 (file)
@@ -53,6 +53,7 @@ config GCOV_PROFILE_ALL
 choice
        prompt "Specify GCOV format"
        depends on GCOV_KERNEL
+       depends on CC_IS_GCC
        ---help---
        The gcov format is usually determined by the GCC version, and the
        default is chosen according to your GCC version. However, there are
@@ -62,7 +63,7 @@ choice
 
 config GCOV_FORMAT_3_4
        bool "GCC 3.4 format"
-       depends on CC_IS_GCC && GCC_VERSION < 40700
+       depends on GCC_VERSION < 40700
        ---help---
        Select this option to use the format defined by GCC 3.4.
 
index ff06d64df3976807840dffd3a7629e64f5270de2..d66a74b0f10045db1a7f7450e5dd13fcf18c8da6 100644 (file)
@@ -2,5 +2,6 @@
 ccflags-y := -DSRCTREE='"$(srctree)"' -DOBJTREE='"$(objtree)"'
 
 obj-y := base.o fs.o
-obj-$(CONFIG_GCOV_FORMAT_3_4) += gcc_3_4.o
-obj-$(CONFIG_GCOV_FORMAT_4_7) += gcc_4_7.o
+obj-$(CONFIG_GCOV_FORMAT_3_4) += gcc_base.o gcc_3_4.o
+obj-$(CONFIG_GCOV_FORMAT_4_7) += gcc_base.o gcc_4_7.o
+obj-$(CONFIG_CC_IS_CLANG) += clang.o
index 9c7c8d5c18f2d5ebdf71f5a6ead7f205bd3b3609..0ffe9f1940807258e8bf3255613ea5077ca44410 100644 (file)
 #include <linux/sched.h>
 #include "gcov.h"
 
-static int gcov_events_enabled;
-static DEFINE_MUTEX(gcov_lock);
-
-/*
- * __gcov_init is called by gcc-generated constructor code for each object
- * file compiled with -fprofile-arcs.
- */
-void __gcov_init(struct gcov_info *info)
-{
-       static unsigned int gcov_version;
-
-       mutex_lock(&gcov_lock);
-       if (gcov_version == 0) {
-               gcov_version = gcov_info_version(info);
-               /*
-                * Printing gcc's version magic may prove useful for debugging
-                * incompatibility reports.
-                */
-               pr_info("version magic: 0x%x\n", gcov_version);
-       }
-       /*
-        * Add new profiling data structure to list and inform event
-        * listener.
-        */
-       gcov_info_link(info);
-       if (gcov_events_enabled)
-               gcov_event(GCOV_ADD, info);
-       mutex_unlock(&gcov_lock);
-}
-EXPORT_SYMBOL(__gcov_init);
-
-/*
- * These functions may be referenced by gcc-generated profiling code but serve
- * no function for kernel profiling.
- */
-void __gcov_flush(void)
-{
-       /* Unused. */
-}
-EXPORT_SYMBOL(__gcov_flush);
-
-void __gcov_merge_add(gcov_type *counters, unsigned int n_counters)
-{
-       /* Unused. */
-}
-EXPORT_SYMBOL(__gcov_merge_add);
-
-void __gcov_merge_single(gcov_type *counters, unsigned int n_counters)
-{
-       /* Unused. */
-}
-EXPORT_SYMBOL(__gcov_merge_single);
-
-void __gcov_merge_delta(gcov_type *counters, unsigned int n_counters)
-{
-       /* Unused. */
-}
-EXPORT_SYMBOL(__gcov_merge_delta);
-
-void __gcov_merge_ior(gcov_type *counters, unsigned int n_counters)
-{
-       /* Unused. */
-}
-EXPORT_SYMBOL(__gcov_merge_ior);
-
-void __gcov_merge_time_profile(gcov_type *counters, unsigned int n_counters)
-{
-       /* Unused. */
-}
-EXPORT_SYMBOL(__gcov_merge_time_profile);
-
-void __gcov_merge_icall_topn(gcov_type *counters, unsigned int n_counters)
-{
-       /* Unused. */
-}
-EXPORT_SYMBOL(__gcov_merge_icall_topn);
-
-void __gcov_exit(void)
-{
-       /* Unused. */
-}
-EXPORT_SYMBOL(__gcov_exit);
+int gcov_events_enabled;
+DEFINE_MUTEX(gcov_lock);
 
 /**
  * gcov_enable_events - enable event reporting through gcov_event()
@@ -144,7 +64,7 @@ static int gcov_module_notifier(struct notifier_block *nb, unsigned long event,
 
        /* Remove entries located in module from linked list. */
        while ((info = gcov_info_next(info))) {
-               if (within_module((unsigned long)info, mod)) {
+               if (gcov_info_within_module(info, mod)) {
                        gcov_info_unlink(prev, info);
                        if (gcov_events_enabled)
                                gcov_event(GCOV_REMOVE, info);
diff --git a/kernel/gcov/clang.c b/kernel/gcov/clang.c
new file mode 100644 (file)
index 0000000..c94b820
--- /dev/null
@@ -0,0 +1,581 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Google, Inc.
+ * modified from kernel/gcov/gcc_4_7.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ *
+ * LLVM uses profiling data that's deliberately similar to GCC, but has a
+ * very different way of exporting that data.  LLVM calls llvm_gcov_init() once
+ * per module, and provides a couple of callbacks that we can use to ask for
+ * more data.
+ *
+ * We care about the "writeout" callback, which in turn calls back into
+ * compiler-rt/this module to dump all the gathered coverage data to disk:
+ *
+ *    llvm_gcda_start_file()
+ *      llvm_gcda_emit_function()
+ *      llvm_gcda_emit_arcs()
+ *      llvm_gcda_emit_function()
+ *      llvm_gcda_emit_arcs()
+ *      [... repeats for each function ...]
+ *    llvm_gcda_summary_info()
+ *    llvm_gcda_end_file()
+ *
+ * This design is much more stateless and unstructured than gcc's, and is
+ * intended to run at process exit.  This forces us to keep some local state
+ * about which module we're dealing with at the moment.  On the other hand, it
+ * also means we don't depend as much on how LLVM represents profiling data
+ * internally.
+ *
+ * See LLVM's lib/Transforms/Instrumentation/GCOVProfiling.cpp for more
+ * details on how this works, particularly GCOVProfiler::emitProfileArcs(),
+ * GCOVProfiler::insertCounterWriteout(), and
+ * GCOVProfiler::insertFlush().
+ */
+
+#define pr_fmt(fmt)    "gcov: " fmt
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include "gcov.h"
+
+typedef void (*llvm_gcov_callback)(void);
+
+struct gcov_info {
+       struct list_head head;
+
+       const char *filename;
+       unsigned int version;
+       u32 checksum;
+
+       struct list_head functions;
+};
+
+struct gcov_fn_info {
+       struct list_head head;
+
+       u32 ident;
+       u32 checksum;
+       u8 use_extra_checksum;
+       u32 cfg_checksum;
+
+       u32 num_counters;
+       u64 *counters;
+       const char *function_name;
+};
+
+static struct gcov_info *current_info;
+
+static LIST_HEAD(clang_gcov_list);
+
+void llvm_gcov_init(llvm_gcov_callback writeout, llvm_gcov_callback flush)
+{
+       struct gcov_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
+
+       if (!info)
+               return;
+
+       INIT_LIST_HEAD(&info->head);
+       INIT_LIST_HEAD(&info->functions);
+
+       mutex_lock(&gcov_lock);
+
+       list_add_tail(&info->head, &clang_gcov_list);
+       current_info = info;
+       writeout();
+       current_info = NULL;
+       if (gcov_events_enabled)
+               gcov_event(GCOV_ADD, info);
+
+       mutex_unlock(&gcov_lock);
+}
+EXPORT_SYMBOL(llvm_gcov_init);
+
+void llvm_gcda_start_file(const char *orig_filename, const char version[4],
+               u32 checksum)
+{
+       current_info->filename = orig_filename;
+       memcpy(&current_info->version, version, sizeof(current_info->version));
+       current_info->checksum = checksum;
+}
+EXPORT_SYMBOL(llvm_gcda_start_file);
+
+void llvm_gcda_emit_function(u32 ident, const char *function_name,
+               u32 func_checksum, u8 use_extra_checksum, u32 cfg_checksum)
+{
+       struct gcov_fn_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
+
+       if (!info)
+               return;
+
+       INIT_LIST_HEAD(&info->head);
+       info->ident = ident;
+       info->checksum = func_checksum;
+       info->use_extra_checksum = use_extra_checksum;
+       info->cfg_checksum = cfg_checksum;
+       if (function_name)
+               info->function_name = kstrdup(function_name, GFP_KERNEL);
+
+       list_add_tail(&info->head, &current_info->functions);
+}
+EXPORT_SYMBOL(llvm_gcda_emit_function);
+
+void llvm_gcda_emit_arcs(u32 num_counters, u64 *counters)
+{
+       struct gcov_fn_info *info = list_last_entry(&current_info->functions,
+                       struct gcov_fn_info, head);
+
+       info->num_counters = num_counters;
+       info->counters = counters;
+}
+EXPORT_SYMBOL(llvm_gcda_emit_arcs);
+
+void llvm_gcda_summary_info(void)
+{
+}
+EXPORT_SYMBOL(llvm_gcda_summary_info);
+
+void llvm_gcda_end_file(void)
+{
+}
+EXPORT_SYMBOL(llvm_gcda_end_file);
+
+/**
+ * gcov_info_filename - return info filename
+ * @info: profiling data set
+ */
+const char *gcov_info_filename(struct gcov_info *info)
+{
+       return info->filename;
+}
+
+/**
+ * gcov_info_version - return info version
+ * @info: profiling data set
+ */
+unsigned int gcov_info_version(struct gcov_info *info)
+{
+       return info->version;
+}
+
+/**
+ * gcov_info_next - return next profiling data set
+ * @info: profiling data set
+ *
+ * Returns next gcov_info following @info or first gcov_info in the chain if
+ * @info is %NULL.
+ */
+struct gcov_info *gcov_info_next(struct gcov_info *info)
+{
+       if (!info)
+               return list_first_entry_or_null(&clang_gcov_list,
+                               struct gcov_info, head);
+       if (list_is_last(&info->head, &clang_gcov_list))
+               return NULL;
+       return list_next_entry(info, head);
+}
+
+/**
+ * gcov_info_link - link/add profiling data set to the list
+ * @info: profiling data set
+ */
+void gcov_info_link(struct gcov_info *info)
+{
+       list_add_tail(&info->head, &clang_gcov_list);
+}
+
+/**
+ * gcov_info_unlink - unlink/remove profiling data set from the list
+ * @prev: previous profiling data set
+ * @info: profiling data set
+ */
+void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info)
+{
+       /* Generic code unlinks while iterating. */
+       __list_del_entry(&info->head);
+}
+
+/**
+ * gcov_info_within_module - check if a profiling data set belongs to a module
+ * @info: profiling data set
+ * @mod: module
+ *
+ * Returns true if profiling data belongs module, false otherwise.
+ */
+bool gcov_info_within_module(struct gcov_info *info, struct module *mod)
+{
+       return within_module((unsigned long)info->filename, mod);
+}
+
+/* Symbolic links to be created for each profiling data file. */
+const struct gcov_link gcov_link[] = {
+       { OBJ_TREE, "gcno" },   /* Link to .gcno file in $(objtree). */
+       { 0, NULL},
+};
+
+/**
+ * gcov_info_reset - reset profiling data to zero
+ * @info: profiling data set
+ */
+void gcov_info_reset(struct gcov_info *info)
+{
+       struct gcov_fn_info *fn;
+
+       list_for_each_entry(fn, &info->functions, head)
+               memset(fn->counters, 0,
+                               sizeof(fn->counters[0]) * fn->num_counters);
+}
+
+/**
+ * gcov_info_is_compatible - check if profiling data can be added
+ * @info1: first profiling data set
+ * @info2: second profiling data set
+ *
+ * Returns non-zero if profiling data can be added, zero otherwise.
+ */
+int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2)
+{
+       struct gcov_fn_info *fn_ptr1 = list_first_entry_or_null(
+                       &info1->functions, struct gcov_fn_info, head);
+       struct gcov_fn_info *fn_ptr2 = list_first_entry_or_null(
+                       &info2->functions, struct gcov_fn_info, head);
+
+       if (info1->checksum != info2->checksum)
+               return false;
+       if (!fn_ptr1)
+               return fn_ptr1 == fn_ptr2;
+       while (!list_is_last(&fn_ptr1->head, &info1->functions) &&
+               !list_is_last(&fn_ptr2->head, &info2->functions)) {
+               if (fn_ptr1->checksum != fn_ptr2->checksum)
+                       return false;
+               if (fn_ptr1->use_extra_checksum != fn_ptr2->use_extra_checksum)
+                       return false;
+               if (fn_ptr1->use_extra_checksum &&
+                       fn_ptr1->cfg_checksum != fn_ptr2->cfg_checksum)
+                       return false;
+               fn_ptr1 = list_next_entry(fn_ptr1, head);
+               fn_ptr2 = list_next_entry(fn_ptr2, head);
+       }
+       return list_is_last(&fn_ptr1->head, &info1->functions) &&
+               list_is_last(&fn_ptr2->head, &info2->functions);
+}
+
+/**
+ * gcov_info_add - add up profiling data
+ * @dest: profiling data set to which data is added
+ * @source: profiling data set which is added
+ *
+ * Adds profiling counts of @source to @dest.
+ */
+void gcov_info_add(struct gcov_info *dst, struct gcov_info *src)
+{
+       struct gcov_fn_info *dfn_ptr;
+       struct gcov_fn_info *sfn_ptr = list_first_entry_or_null(&src->functions,
+                       struct gcov_fn_info, head);
+
+       list_for_each_entry(dfn_ptr, &dst->functions, head) {
+               u32 i;
+
+               for (i = 0; i < sfn_ptr->num_counters; i++)
+                       dfn_ptr->counters[i] += sfn_ptr->counters[i];
+       }
+}
+
+static struct gcov_fn_info *gcov_fn_info_dup(struct gcov_fn_info *fn)
+{
+       size_t cv_size; /* counter values size */
+       struct gcov_fn_info *fn_dup = kmemdup(fn, sizeof(*fn),
+                       GFP_KERNEL);
+       if (!fn_dup)
+               return NULL;
+       INIT_LIST_HEAD(&fn_dup->head);
+
+       fn_dup->function_name = kstrdup(fn->function_name, GFP_KERNEL);
+       if (!fn_dup->function_name)
+               goto err_name;
+
+       cv_size = fn->num_counters * sizeof(fn->counters[0]);
+       fn_dup->counters = vmalloc(cv_size);
+       if (!fn_dup->counters)
+               goto err_counters;
+       memcpy(fn_dup->counters, fn->counters, cv_size);
+
+       return fn_dup;
+
+err_counters:
+       kfree(fn_dup->function_name);
+err_name:
+       kfree(fn_dup);
+       return NULL;
+}
+
+/**
+ * gcov_info_dup - duplicate profiling data set
+ * @info: profiling data set to duplicate
+ *
+ * Return newly allocated duplicate on success, %NULL on error.
+ */
+struct gcov_info *gcov_info_dup(struct gcov_info *info)
+{
+       struct gcov_info *dup;
+       struct gcov_fn_info *fn;
+
+       dup = kmemdup(info, sizeof(*dup), GFP_KERNEL);
+       if (!dup)
+               return NULL;
+       INIT_LIST_HEAD(&dup->head);
+       INIT_LIST_HEAD(&dup->functions);
+       dup->filename = kstrdup(info->filename, GFP_KERNEL);
+       if (!dup->filename)
+               goto err;
+
+       list_for_each_entry(fn, &info->functions, head) {
+               struct gcov_fn_info *fn_dup = gcov_fn_info_dup(fn);
+
+               if (!fn_dup)
+                       goto err;
+               list_add_tail(&fn_dup->head, &dup->functions);
+       }
+
+       return dup;
+
+err:
+       gcov_info_free(dup);
+       return NULL;
+}
+
+/**
+ * gcov_info_free - release memory for profiling data set duplicate
+ * @info: profiling data set duplicate to free
+ */
+void gcov_info_free(struct gcov_info *info)
+{
+       struct gcov_fn_info *fn, *tmp;
+
+       list_for_each_entry_safe(fn, tmp, &info->functions, head) {
+               kfree(fn->function_name);
+               vfree(fn->counters);
+               list_del(&fn->head);
+               kfree(fn);
+       }
+       kfree(info->filename);
+       kfree(info);
+}
+
+#define ITER_STRIDE    PAGE_SIZE
+
+/**
+ * struct gcov_iterator - specifies current file position in logical records
+ * @info: associated profiling data
+ * @buffer: buffer containing file data
+ * @size: size of buffer
+ * @pos: current position in file
+ */
+struct gcov_iterator {
+       struct gcov_info *info;
+       void *buffer;
+       size_t size;
+       loff_t pos;
+};
+
+/**
+ * store_gcov_u32 - store 32 bit number in gcov format to buffer
+ * @buffer: target buffer or NULL
+ * @off: offset into the buffer
+ * @v: value to be stored
+ *
+ * Number format defined by gcc: numbers are recorded in the 32 bit
+ * unsigned binary form of the endianness of the machine generating the
+ * file. Returns the number of bytes stored. If @buffer is %NULL, doesn't
+ * store anything.
+ */
+static size_t store_gcov_u32(void *buffer, size_t off, u32 v)
+{
+       u32 *data;
+
+       if (buffer) {
+               data = buffer + off;
+               *data = v;
+       }
+
+       return sizeof(*data);
+}
+
+/**
+ * store_gcov_u64 - store 64 bit number in gcov format to buffer
+ * @buffer: target buffer or NULL
+ * @off: offset into the buffer
+ * @v: value to be stored
+ *
+ * Number format defined by gcc: numbers are recorded in the 32 bit
+ * unsigned binary form of the endianness of the machine generating the
+ * file. 64 bit numbers are stored as two 32 bit numbers, the low part
+ * first. Returns the number of bytes stored. If @buffer is %NULL, doesn't store
+ * anything.
+ */
+static size_t store_gcov_u64(void *buffer, size_t off, u64 v)
+{
+       u32 *data;
+
+       if (buffer) {
+               data = buffer + off;
+
+               data[0] = (v & 0xffffffffUL);
+               data[1] = (v >> 32);
+       }
+
+       return sizeof(*data) * 2;
+}
+
+/**
+ * convert_to_gcda - convert profiling data set to gcda file format
+ * @buffer: the buffer to store file data or %NULL if no data should be stored
+ * @info: profiling data set to be converted
+ *
+ * Returns the number of bytes that were/would have been stored into the buffer.
+ */
+static size_t convert_to_gcda(char *buffer, struct gcov_info *info)
+{
+       struct gcov_fn_info *fi_ptr;
+       size_t pos = 0;
+
+       /* File header. */
+       pos += store_gcov_u32(buffer, pos, GCOV_DATA_MAGIC);
+       pos += store_gcov_u32(buffer, pos, info->version);
+       pos += store_gcov_u32(buffer, pos, info->checksum);
+
+       list_for_each_entry(fi_ptr, &info->functions, head) {
+               u32 i;
+               u32 len = 2;
+
+               if (fi_ptr->use_extra_checksum)
+                       len++;
+
+               pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION);
+               pos += store_gcov_u32(buffer, pos, len);
+               pos += store_gcov_u32(buffer, pos, fi_ptr->ident);
+               pos += store_gcov_u32(buffer, pos, fi_ptr->checksum);
+               if (fi_ptr->use_extra_checksum)
+                       pos += store_gcov_u32(buffer, pos, fi_ptr->cfg_checksum);
+
+               pos += store_gcov_u32(buffer, pos, GCOV_TAG_COUNTER_BASE);
+               pos += store_gcov_u32(buffer, pos, fi_ptr->num_counters * 2);
+               for (i = 0; i < fi_ptr->num_counters; i++)
+                       pos += store_gcov_u64(buffer, pos, fi_ptr->counters[i]);
+       }
+
+       return pos;
+}
+
+/**
+ * gcov_iter_new - allocate and initialize profiling data iterator
+ * @info: profiling data set to be iterated
+ *
+ * Return file iterator on success, %NULL otherwise.
+ */
+struct gcov_iterator *gcov_iter_new(struct gcov_info *info)
+{
+       struct gcov_iterator *iter;
+
+       iter = kzalloc(sizeof(struct gcov_iterator), GFP_KERNEL);
+       if (!iter)
+               goto err_free;
+
+       iter->info = info;
+       /* Dry-run to get the actual buffer size. */
+       iter->size = convert_to_gcda(NULL, info);
+       iter->buffer = vmalloc(iter->size);
+       if (!iter->buffer)
+               goto err_free;
+
+       convert_to_gcda(iter->buffer, info);
+
+       return iter;
+
+err_free:
+       kfree(iter);
+       return NULL;
+}
+
+
+/**
+ * gcov_iter_get_info - return profiling data set for given file iterator
+ * @iter: file iterator
+ */
+void gcov_iter_free(struct gcov_iterator *iter)
+{
+       vfree(iter->buffer);
+       kfree(iter);
+}
+
+/**
+ * gcov_iter_get_info - return profiling data set for given file iterator
+ * @iter: file iterator
+ */
+struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter)
+{
+       return iter->info;
+}
+
+/**
+ * gcov_iter_start - reset file iterator to starting position
+ * @iter: file iterator
+ */
+void gcov_iter_start(struct gcov_iterator *iter)
+{
+       iter->pos = 0;
+}
+
+/**
+ * gcov_iter_next - advance file iterator to next logical record
+ * @iter: file iterator
+ *
+ * Return zero if new position is valid, non-zero if iterator has reached end.
+ */
+int gcov_iter_next(struct gcov_iterator *iter)
+{
+       if (iter->pos < iter->size)
+               iter->pos += ITER_STRIDE;
+
+       if (iter->pos >= iter->size)
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * gcov_iter_write - write data for current pos to seq_file
+ * @iter: file iterator
+ * @seq: seq_file handle
+ *
+ * Return zero on success, non-zero otherwise.
+ */
+int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
+{
+       size_t len;
+
+       if (iter->pos >= iter->size)
+               return -EINVAL;
+
+       len = ITER_STRIDE;
+       if (iter->pos + len > iter->size)
+               len = iter->size - iter->pos;
+
+       seq_write(seq, iter->buffer + iter->pos, len);
+
+       return 0;
+}
index 2dddecbdbe6ed708bef966f9e05997515cb51027..801ee4b0b969b516a5f17b111d5dba9784b7e92b 100644 (file)
@@ -137,6 +137,18 @@ void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info)
                gcov_info_head = info->next;
 }
 
+/**
+ * gcov_info_within_module - check if a profiling data set belongs to a module
+ * @info: profiling data set
+ * @mod: module
+ *
+ * Returns true if profiling data belongs module, false otherwise.
+ */
+bool gcov_info_within_module(struct gcov_info *info, struct module *mod)
+{
+       return within_module((unsigned long)info, mod);
+}
+
 /* Symbolic links to be created for each profiling data file. */
 const struct gcov_link gcov_link[] = {
        { OBJ_TREE, "gcno" },   /* Link to .gcno file in $(objtree). */
index ca5e5c0ef8536ccded9097e94ebab38d3a868547..ec37563674d62497d1d4d356ab9b547242469f63 100644 (file)
@@ -150,6 +150,18 @@ void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info)
                gcov_info_head = info->next;
 }
 
+/**
+ * gcov_info_within_module - check if a profiling data set belongs to a module
+ * @info: profiling data set
+ * @mod: module
+ *
+ * Returns true if profiling data belongs module, false otherwise.
+ */
+bool gcov_info_within_module(struct gcov_info *info, struct module *mod)
+{
+       return within_module((unsigned long)info, mod);
+}
+
 /* Symbolic links to be created for each profiling data file. */
 const struct gcov_link gcov_link[] = {
        { OBJ_TREE, "gcno" },   /* Link to .gcno file in $(objtree). */
diff --git a/kernel/gcov/gcc_base.c b/kernel/gcov/gcc_base.c
new file mode 100644 (file)
index 0000000..3cf736b
--- /dev/null
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include "gcov.h"
+
+/*
+ * __gcov_init is called by gcc-generated constructor code for each object
+ * file compiled with -fprofile-arcs.
+ */
+void __gcov_init(struct gcov_info *info)
+{
+       static unsigned int gcov_version;
+
+       mutex_lock(&gcov_lock);
+       if (gcov_version == 0) {
+               gcov_version = gcov_info_version(info);
+               /*
+                * Printing gcc's version magic may prove useful for debugging
+                * incompatibility reports.
+                */
+               pr_info("version magic: 0x%x\n", gcov_version);
+       }
+       /*
+        * Add new profiling data structure to list and inform event
+        * listener.
+        */
+       gcov_info_link(info);
+       if (gcov_events_enabled)
+               gcov_event(GCOV_ADD, info);
+       mutex_unlock(&gcov_lock);
+}
+EXPORT_SYMBOL(__gcov_init);
+
+/*
+ * These functions may be referenced by gcc-generated profiling code but serve
+ * no function for kernel profiling.
+ */
+void __gcov_flush(void)
+{
+       /* Unused. */
+}
+EXPORT_SYMBOL(__gcov_flush);
+
+void __gcov_merge_add(gcov_type *counters, unsigned int n_counters)
+{
+       /* Unused. */
+}
+EXPORT_SYMBOL(__gcov_merge_add);
+
+void __gcov_merge_single(gcov_type *counters, unsigned int n_counters)
+{
+       /* Unused. */
+}
+EXPORT_SYMBOL(__gcov_merge_single);
+
+void __gcov_merge_delta(gcov_type *counters, unsigned int n_counters)
+{
+       /* Unused. */
+}
+EXPORT_SYMBOL(__gcov_merge_delta);
+
+void __gcov_merge_ior(gcov_type *counters, unsigned int n_counters)
+{
+       /* Unused. */
+}
+EXPORT_SYMBOL(__gcov_merge_ior);
+
+void __gcov_merge_time_profile(gcov_type *counters, unsigned int n_counters)
+{
+       /* Unused. */
+}
+EXPORT_SYMBOL(__gcov_merge_time_profile);
+
+void __gcov_merge_icall_topn(gcov_type *counters, unsigned int n_counters)
+{
+       /* Unused. */
+}
+EXPORT_SYMBOL(__gcov_merge_icall_topn);
+
+void __gcov_exit(void)
+{
+       /* Unused. */
+}
+EXPORT_SYMBOL(__gcov_exit);
index de118ad4a024e172ef621e82801843f6ddc2d85d..6ab2c1808c9d5b534a4e1d18d62ee5e7ea34f519 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef GCOV_H
 #define GCOV_H GCOV_H
 
+#include <linux/module.h>
 #include <linux/types.h>
 
 /*
@@ -46,6 +47,7 @@ unsigned int gcov_info_version(struct gcov_info *info);
 struct gcov_info *gcov_info_next(struct gcov_info *info);
 void gcov_info_link(struct gcov_info *info);
 void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info);
+bool gcov_info_within_module(struct gcov_info *info, struct module *mod);
 
 /* Base interface. */
 enum gcov_action {
@@ -83,4 +85,7 @@ struct gcov_link {
 };
 extern const struct gcov_link gcov_link[];
 
+extern int gcov_events_enabled;
+extern struct mutex gcov_lock;
+
 #endif /* GCOV_H */
index f7fb8f6a688fd47b4af8833c067510571fbdcf2c..072b6ee55e3f19d16fac73a9cbe7457fd311a72c 100644 (file)
@@ -500,13 +500,7 @@ static int locate_mem_hole_callback(struct resource *res, void *arg)
        return locate_mem_hole_bottom_up(start, end, kbuf);
 }
 
-#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
-static int kexec_walk_memblock(struct kexec_buf *kbuf,
-                              int (*func)(struct resource *, void *))
-{
-       return 0;
-}
-#else
+#ifdef CONFIG_ARCH_KEEP_MEMBLOCK
 static int kexec_walk_memblock(struct kexec_buf *kbuf,
                               int (*func)(struct resource *, void *))
 {
@@ -550,6 +544,12 @@ static int kexec_walk_memblock(struct kexec_buf *kbuf,
 
        return ret;
 }
+#else
+static int kexec_walk_memblock(struct kexec_buf *kbuf,
+                              int (*func)(struct resource *, void *))
+{
+       return 0;
+}
 #endif
 
 /**
@@ -589,7 +589,7 @@ int kexec_locate_mem_hole(struct kexec_buf *kbuf)
        if (kbuf->mem != KEXEC_BUF_MEM_UNKNOWN)
                return 0;
 
-       if (IS_ENABLED(CONFIG_ARCH_DISCARD_MEMBLOCK))
+       if (!IS_ENABLED(CONFIG_ARCH_KEEP_MEMBLOCK))
                ret = kexec_walk_resources(kbuf, locate_mem_hole_callback);
        else
                ret = kexec_walk_memblock(kbuf, locate_mem_hole_callback);
index 5942eeafb9acfd577768c9e737c91547680449ae..be4e8795561a6afe550ebae2ddcf67af95f8416a 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kthread.h>
 #include <linux/completion.h>
 #include <linux/err.h>
+#include <linux/cgroup.h>
 #include <linux/cpuset.h>
 #include <linux/unistd.h>
 #include <linux/file.h>
index 99a5b5f46dc5d99080ef7b1320c7c59106f580c4..871734ea2f045a5ec7787c6d27d4951118c74df9 100644 (file)
@@ -67,13 +67,10 @@ static struct latency_record latency_record[MAXLR];
 
 int latencytop_enabled;
 
-void clear_all_latency_tracing(struct task_struct *p)
+void clear_tsk_latency_tracing(struct task_struct *p)
 {
        unsigned long flags;
 
-       if (!latencytop_enabled)
-               return;
-
        raw_spin_lock_irqsave(&latency_lock, flags);
        memset(&p->latency_record, 0, sizeof(p->latency_record));
        p->latency_record_count = 0;
@@ -96,9 +93,6 @@ account_global_scheduler_latency(struct task_struct *tsk,
        int firstnonnull = MAXLR + 1;
        int i;
 
-       if (!latencytop_enabled)
-               return;
-
        /* skip kernel threads for now */
        if (!tsk->mm)
                return;
index f6fbaff10e71194462a59841fc19a117d70708f3..91cd519756d3744597080d9d5c2ecb7b7c5e7aaf 100644 (file)
@@ -1208,14 +1208,6 @@ void klp_module_going(struct module *mod)
 
 static int __init klp_init(void)
 {
-       int ret;
-
-       ret = klp_check_compiler_support();
-       if (ret) {
-               pr_info("Your compiler is too old; turning off.\n");
-               return -EINVAL;
-       }
-
        klp_root_kobj = kobject_create_and_add("livepatch", kernel_kobj);
        if (!klp_root_kobj)
                return -ENOMEM;
index 6b3ee9948bf17a37f5be8a730064f3e5d7374774..0b1f779572402d4736783cbc890bfbf748416b38 100644 (file)
@@ -130,6 +130,7 @@ static void __rwsem_mark_wake(struct rw_semaphore *sem,
 {
        struct rwsem_waiter *waiter, *tmp;
        long oldcount, woken = 0, adjustment = 0;
+       struct list_head wlist;
 
        /*
         * Take a peek at the queue head waiter such that we can determine
@@ -188,18 +189,43 @@ static void __rwsem_mark_wake(struct rw_semaphore *sem,
         * of the queue. We know that woken will be at least 1 as we accounted
         * for above. Note we increment the 'active part' of the count by the
         * number of readers before waking any processes up.
+        *
+        * We have to do wakeup in 2 passes to prevent the possibility that
+        * the reader count may be decremented before it is incremented. It
+        * is because the to-be-woken waiter may not have slept yet. So it
+        * may see waiter->task got cleared, finish its critical section and
+        * do an unlock before the reader count increment.
+        *
+        * 1) Collect the read-waiters in a separate list, count them and
+        *    fully increment the reader count in rwsem.
+        * 2) For each waiters in the new list, clear waiter->task and
+        *    put them into wake_q to be woken up later.
         */
-       list_for_each_entry_safe(waiter, tmp, &sem->wait_list, list) {
-               struct task_struct *tsk;
-
+       list_for_each_entry(waiter, &sem->wait_list, list) {
                if (waiter->type == RWSEM_WAITING_FOR_WRITE)
                        break;
 
                woken++;
-               tsk = waiter->task;
+       }
+       list_cut_before(&wlist, &sem->wait_list, &waiter->list);
+
+       adjustment = woken * RWSEM_ACTIVE_READ_BIAS - adjustment;
+       lockevent_cond_inc(rwsem_wake_reader, woken);
+       if (list_empty(&sem->wait_list)) {
+               /* hit end of list above */
+               adjustment -= RWSEM_WAITING_BIAS;
+       }
+
+       if (adjustment)
+               atomic_long_add(adjustment, &sem->count);
+
+       /* 2nd pass */
+       list_for_each_entry_safe(waiter, tmp, &wlist, list) {
+               struct task_struct *tsk;
 
+               tsk = waiter->task;
                get_task_struct(tsk);
-               list_del(&waiter->list);
+
                /*
                 * Ensure calling get_task_struct() before setting the reader
                 * waiter to nil such that rwsem_down_read_failed() cannot
@@ -213,16 +239,6 @@ static void __rwsem_mark_wake(struct rw_semaphore *sem,
                 */
                wake_q_add_safe(wake_q, tsk);
        }
-
-       adjustment = woken * RWSEM_ACTIVE_READ_BIAS - adjustment;
-       lockevent_cond_inc(rwsem_wake_reader, woken);
-       if (list_empty(&sem->wait_list)) {
-               /* hit end of list above */
-               adjustment -= RWSEM_WAITING_BIAS;
-       }
-
-       if (adjustment)
-               atomic_long_add(adjustment, &sem->count);
 }
 
 /*
index a856cb5ff192aa5584f98c5138d8cabece672f3b..1490e63f69a955e3857e8b8e10bdaa62cc063a3d 100644 (file)
@@ -45,7 +45,6 @@ vm_fault_t device_private_entry_fault(struct vm_area_struct *vma,
         */
        return devmem->page_fault(vma, addr, page, flags, pmdp);
 }
-EXPORT_SYMBOL(device_private_entry_fault);
 #endif /* CONFIG_DEVICE_PRIVATE */
 
 static void pgmap_array_delete(struct resource *res)
@@ -148,6 +147,12 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
                        &pgmap->altmap : NULL;
        struct resource *res = &pgmap->res;
        struct dev_pagemap *conflict_pgmap;
+       struct mhp_restrictions restrictions = {
+               /*
+                * We do not want any optional features only our own memmap
+               */
+               .altmap = altmap,
+       };
        pgprot_t pgprot = PAGE_KERNEL;
        int error, nid, is_ram;
 
@@ -214,7 +219,7 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
         */
        if (pgmap->type == MEMORY_DEVICE_PRIVATE) {
                error = add_pages(nid, align_start >> PAGE_SHIFT,
-                               align_size >> PAGE_SHIFT, NULL, false);
+                               align_size >> PAGE_SHIFT, &restrictions);
        } else {
                error = kasan_add_zero_shadow(__va(align_start), align_size);
                if (error) {
@@ -222,8 +227,8 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
                        goto err_kasan;
                }
 
-               error = arch_add_memory(nid, align_start, align_size, altmap,
-                               false);
+               error = arch_add_memory(nid, align_start, align_size,
+                                       &restrictions);
        }
 
        if (!error) {
index 79c9be2dbbe987a95e53be8c64d9e540db7bec4b..d354341f8cc0c3e2cb00a89790523b43c32ddc7c 100644 (file)
@@ -20,7 +20,7 @@ struct load_info {
        unsigned long len;
        Elf_Shdr *sechdrs;
        char *secstrings, *strtab;
-       unsigned long symoffs, stroffs;
+       unsigned long symoffs, stroffs, init_typeoffs, core_typeoffs;
        struct _ddebug *debug;
        unsigned int num_debug;
        bool sig_ok;
index a9e1e7f2c224927a7fa997bb73b4fbb79933cbb6..6e6712b3aaf51226f07cc9f9e32d8df9605d396a 100644 (file)
@@ -2642,6 +2642,8 @@ static void layout_symtab(struct module *mod, struct load_info *info)
        info->symoffs = ALIGN(mod->core_layout.size, symsect->sh_addralign ?: 1);
        info->stroffs = mod->core_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
        mod->core_layout.size += strtab_size;
+       info->core_typeoffs = mod->core_layout.size;
+       mod->core_layout.size += ndst * sizeof(char);
        mod->core_layout.size = debug_align(mod->core_layout.size);
 
        /* Put string table section at end of init part of module. */
@@ -2655,6 +2657,8 @@ static void layout_symtab(struct module *mod, struct load_info *info)
                                      __alignof__(struct mod_kallsyms));
        info->mod_kallsyms_init_off = mod->init_layout.size;
        mod->init_layout.size += sizeof(struct mod_kallsyms);
+       info->init_typeoffs = mod->init_layout.size;
+       mod->init_layout.size += nsrc * sizeof(char);
        mod->init_layout.size = debug_align(mod->init_layout.size);
 }
 
@@ -2678,20 +2682,23 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
        mod->kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
        /* Make sure we get permanent strtab: don't use info->strtab. */
        mod->kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
+       mod->kallsyms->typetab = mod->init_layout.base + info->init_typeoffs;
 
-       /* Set types up while we still have access to sections. */
-       for (i = 0; i < mod->kallsyms->num_symtab; i++)
-               mod->kallsyms->symtab[i].st_size
-                       = elf_type(&mod->kallsyms->symtab[i], info);
-
-       /* Now populate the cut down core kallsyms for after init. */
+       /*
+        * Now populate the cut down core kallsyms for after init
+        * and set types up while we still have access to sections.
+        */
        mod->core_kallsyms.symtab = dst = mod->core_layout.base + info->symoffs;
        mod->core_kallsyms.strtab = s = mod->core_layout.base + info->stroffs;
+       mod->core_kallsyms.typetab = mod->core_layout.base + info->core_typeoffs;
        src = mod->kallsyms->symtab;
        for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) {
+               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)) {
+                       mod->core_kallsyms.typetab[ndst] =
+                           mod->kallsyms->typetab[i];
                        dst[ndst] = src[i];
                        dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
                        s += strlcpy(s, &mod->kallsyms->strtab[src[i].st_name],
@@ -4091,7 +4098,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
                        const Elf_Sym *sym = &kallsyms->symtab[symnum];
 
                        *value = kallsyms_symbol_value(sym);
-                       *type = sym->st_size;
+                       *type = kallsyms->typetab[symnum];
                        strlcpy(name, kallsyms_symbol_name(kallsyms, symnum), KSYM_NAME_LEN);
                        strlcpy(module_name, mod->name, MODULE_NAME_LEN);
                        *exported = is_exported(name, *value, mod);
index 6196af8a82230024ba98647c7fe946bf842bd102..bfc95b3e42355d41edc036e46e661ee1db0f2708 100644 (file)
@@ -22,6 +22,7 @@ static int notifier_chain_register(struct notifier_block **nl,
                struct notifier_block *n)
 {
        while ((*nl) != NULL) {
+               WARN_ONCE(((*nl) == n), "double register detected");
                if (n->priority > (*nl)->priority)
                        break;
                nl = &((*nl)->next);
index c1fcaad337b743d00d7a1abe27cb94506b04338e..8779d64bace0b1db43672924f637f078225da8e3 100644 (file)
@@ -306,6 +306,8 @@ void panic(const char *fmt, ...)
                 * shutting down.  But if there is a chance of
                 * rebooting the system it will be rebooted.
                 */
+               if (panic_reboot_mode != REBOOT_UNDEFINED)
+                       reboot_mode = panic_reboot_mode;
                emergency_restart();
        }
 #ifdef __sparc__
@@ -321,6 +323,9 @@ void panic(const char *fmt, ...)
        disabled_wait();
 #endif
        pr_emerg("---[ end Kernel panic - not syncing: %s ]---\n", buf);
+
+       /* Do not scroll important messages printed above */
+       suppress_printk = 1;
        local_irq_enable();
        for (i = 0; ; i += PANIC_TIMER_STEP) {
                touch_softlockup_watchdog();
index 20881598bdfaccc2e0ad736e1e2f8228ca3299bf..89548d35eefb747bb446a297fac633598db73a4b 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/init.h>
 #include <linux/rculist.h>
 #include <linux/memblock.h>
-#include <linux/hash.h>
 #include <linux/pid_namespace.h>
 #include <linux/init_task.h>
 #include <linux/syscalls.h>
index 02ca827b8fac7f110535ba5d6aca8f1c87306def..17102fd4c1366a831b0e0b74d2a2768f3cb89db6 100644 (file)
@@ -86,6 +86,12 @@ static DEFINE_SEMAPHORE(console_sem);
 struct console *console_drivers;
 EXPORT_SYMBOL_GPL(console_drivers);
 
+/*
+ * System may need to suppress printk message under certain
+ * circumstances, like after kernel panic happens.
+ */
+int __read_mostly suppress_printk;
+
 #ifdef CONFIG_LOCKDEP
 static struct lockdep_map console_lock_dep_map = {
        .name = "console_lock"
@@ -1943,6 +1949,10 @@ asmlinkage int vprintk_emit(int facility, int level,
        unsigned long flags;
        u64 curr_log_seq;
 
+       /* Suppress unimportant messages after panic happens */
+       if (unlikely(suppress_printk))
+               return 0;
+
        if (level == LOGLEVEL_SCHED) {
                level = LOGLEVEL_DEFAULT;
                in_sched = true;
index 4b58c907b4b7f416c76c8f6ac718c406d978570d..390aab20115e8133e45d97e73b163ccb59121fe3 100644 (file)
 #define __LINUX_RCU_H
 
 #include <trace/events/rcu.h>
-#ifdef CONFIG_RCU_TRACE
-#define RCU_TRACE(stmt) stmt
-#else /* #ifdef CONFIG_RCU_TRACE */
-#define RCU_TRACE(stmt)
-#endif /* #else #ifdef CONFIG_RCU_TRACE */
 
 /* Offset to allow distinguishing irq vs. task-based idle entry/exit. */
 #define DYNTICK_IRQ_NONIDLE    ((LONG_MAX / 2) + 1)
@@ -216,12 +211,12 @@ static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head)
 
        rcu_lock_acquire(&rcu_callback_map);
        if (__is_kfree_rcu_offset(offset)) {
-               RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset);)
+               trace_rcu_invoke_kfree_callback(rn, head, offset);
                kfree((void *)head - offset);
                rcu_lock_release(&rcu_callback_map);
                return true;
        } else {
-               RCU_TRACE(trace_rcu_invoke_callback(rn, head);)
+               trace_rcu_invoke_callback(rn, head);
                f = head->func;
                WRITE_ONCE(head->func, (rcu_callback_t)0L);
                f(head);
index b4d88a594785076ef4ace2924455f0d2d2d21a8c..980ca3ca643fbf09c35b4e1b7810d196be511f23 100644 (file)
@@ -1969,14 +1969,14 @@ rcu_check_quiescent_state(struct rcu_data *rdp)
  */
 int rcutree_dying_cpu(unsigned int cpu)
 {
-       RCU_TRACE(bool blkd;)
-       RCU_TRACE(struct rcu_data *rdp = this_cpu_ptr(&rcu_data);)
-       RCU_TRACE(struct rcu_node *rnp = rdp->mynode;)
+       bool blkd;
+       struct rcu_data *rdp = this_cpu_ptr(&rcu_data);
+       struct rcu_node *rnp = rdp->mynode;
 
        if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
                return 0;
 
-       RCU_TRACE(blkd = !!(rnp->qsmask & rdp->grpmask);)
+       blkd = !!(rnp->qsmask & rdp->grpmask);
        trace_rcu_grace_period(rcu_state.name, rnp->gp_seq,
                               blkd ? TPS("cpuofl") : TPS("cpuofl-bgp"));
        return 0;
index e1b79b6a273550516a57d3f7db10c236fcdf0305..b9e79e8c722654e84cc90407f3dfc8322d4ffe23 100644 (file)
@@ -31,6 +31,7 @@ EXPORT_SYMBOL(cad_pid);
 #define DEFAULT_REBOOT_MODE
 #endif
 enum reboot_mode reboot_mode DEFAULT_REBOOT_MODE;
+enum reboot_mode panic_reboot_mode = REBOOT_UNDEFINED;
 
 /*
  * This variable is used privately to keep track of whether or not
@@ -519,6 +520,8 @@ EXPORT_SYMBOL_GPL(orderly_reboot);
 static int __init reboot_setup(char *str)
 {
        for (;;) {
+               enum reboot_mode *mode;
+
                /*
                 * Having anything passed on the command line via
                 * reboot= will cause us to disable DMI checking
@@ -526,17 +529,24 @@ static int __init reboot_setup(char *str)
                 */
                reboot_default = 0;
 
+               if (!strncmp(str, "panic_", 6)) {
+                       mode = &panic_reboot_mode;
+                       str += 6;
+               } else {
+                       mode = &reboot_mode;
+               }
+
                switch (*str) {
                case 'w':
-                       reboot_mode = REBOOT_WARM;
+                       *mode = REBOOT_WARM;
                        break;
 
                case 'c':
-                       reboot_mode = REBOOT_COLD;
+                       *mode = REBOOT_COLD;
                        break;
 
                case 'h':
-                       reboot_mode = REBOOT_HARD;
+                       *mode = REBOOT_HARD;
                        break;
 
                case 's':
@@ -553,11 +563,11 @@ static int __init reboot_setup(char *str)
                                if (rc)
                                        return rc;
                        } else
-                               reboot_mode = REBOOT_SOFT;
+                               *mode = REBOOT_SOFT;
                        break;
                }
                case 'g':
-                       reboot_mode = REBOOT_GPIO;
+                       *mode = REBOOT_GPIO;
                        break;
 
                case 'b':
index 0e97ca9306efc164ada86b6c6bd73506bfdb706e..7acc632c3b82bebceeff2cfdc06eb652096f912b 100644 (file)
@@ -4,6 +4,9 @@
  * Copyright (c) 2018 Facebook, Inc.
  * Author: Johannes Weiner <hannes@cmpxchg.org>
  *
+ * Polling support by Suren Baghdasaryan <surenb@google.com>
+ * Copyright (c) 2018 Google, Inc.
+ *
  * When CPU, memory and IO are contended, tasks experience delays that
  * reduce throughput and introduce latencies into the workload. Memory
  * and IO contention, in addition, can cause a full loss of forward
 #include <linux/seq_file.h>
 #include <linux/proc_fs.h>
 #include <linux/seqlock.h>
+#include <linux/uaccess.h>
 #include <linux/cgroup.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/ctype.h>
+#include <linux/file.h>
+#include <linux/poll.h>
 #include <linux/psi.h>
 #include "sched.h"
 
@@ -140,9 +147,9 @@ static int psi_bug __read_mostly;
 DEFINE_STATIC_KEY_FALSE(psi_disabled);
 
 #ifdef CONFIG_PSI_DEFAULT_DISABLED
-bool psi_enable;
+static bool psi_enable;
 #else
-bool psi_enable = true;
+static bool psi_enable = true;
 #endif
 static int __init setup_psi(char *str)
 {
@@ -156,16 +163,21 @@ __setup("psi=", setup_psi);
 #define EXP_60s                1981            /* 1/exp(2s/60s) */
 #define EXP_300s       2034            /* 1/exp(2s/300s) */
 
+/* PSI trigger definitions */
+#define WINDOW_MIN_US 500000   /* Min window size is 500ms */
+#define WINDOW_MAX_US 10000000 /* Max window size is 10s */
+#define UPDATES_PER_WINDOW 10  /* 10 updates per window */
+
 /* Sampling frequency in nanoseconds */
 static u64 psi_period __read_mostly;
 
 /* System-level pressure and stall tracking */
 static DEFINE_PER_CPU(struct psi_group_cpu, system_group_pcpu);
-static struct psi_group psi_system = {
+struct psi_group psi_system = {
        .pcpu = &system_group_pcpu,
 };
 
-static void psi_update_work(struct work_struct *work);
+static void psi_avgs_work(struct work_struct *work);
 
 static void group_init(struct psi_group *group)
 {
@@ -173,9 +185,20 @@ static void group_init(struct psi_group *group)
 
        for_each_possible_cpu(cpu)
                seqcount_init(&per_cpu_ptr(group->pcpu, cpu)->seq);
-       group->next_update = sched_clock() + psi_period;
-       INIT_DELAYED_WORK(&group->clock_work, psi_update_work);
-       mutex_init(&group->stat_lock);
+       group->avg_next_update = sched_clock() + psi_period;
+       INIT_DELAYED_WORK(&group->avgs_work, psi_avgs_work);
+       mutex_init(&group->avgs_lock);
+       /* Init trigger-related members */
+       atomic_set(&group->poll_scheduled, 0);
+       mutex_init(&group->trigger_lock);
+       INIT_LIST_HEAD(&group->triggers);
+       memset(group->nr_triggers, 0, sizeof(group->nr_triggers));
+       group->poll_states = 0;
+       group->poll_min_period = U32_MAX;
+       memset(group->polling_total, 0, sizeof(group->polling_total));
+       group->polling_next_update = ULLONG_MAX;
+       group->polling_until = 0;
+       rcu_assign_pointer(group->poll_kworker, NULL);
 }
 
 void __init psi_init(void)
@@ -210,20 +233,24 @@ static bool test_state(unsigned int *tasks, enum psi_states state)
        }
 }
 
-static void get_recent_times(struct psi_group *group, int cpu, u32 *times)
+static void get_recent_times(struct psi_group *group, int cpu,
+                            enum psi_aggregators aggregator, u32 *times,
+                            u32 *pchanged_states)
 {
        struct psi_group_cpu *groupc = per_cpu_ptr(group->pcpu, cpu);
-       unsigned int tasks[NR_PSI_TASK_COUNTS];
        u64 now, state_start;
+       enum psi_states s;
        unsigned int seq;
-       int s;
+       u32 state_mask;
+
+       *pchanged_states = 0;
 
        /* Snapshot a coherent view of the CPU state */
        do {
                seq = read_seqcount_begin(&groupc->seq);
                now = cpu_clock(cpu);
                memcpy(times, groupc->times, sizeof(groupc->times));
-               memcpy(tasks, groupc->tasks, sizeof(groupc->tasks));
+               state_mask = groupc->state_mask;
                state_start = groupc->state_start;
        } while (read_seqcount_retry(&groupc->seq, seq));
 
@@ -239,13 +266,15 @@ static void get_recent_times(struct psi_group *group, int cpu, u32 *times)
                 * (u32) and our reported pressure close to what's
                 * actually happening.
                 */
-               if (test_state(tasks, s))
+               if (state_mask & (1 << s))
                        times[s] += now - state_start;
 
-               delta = times[s] - groupc->times_prev[s];
-               groupc->times_prev[s] = times[s];
+               delta = times[s] - groupc->times_prev[aggregator][s];
+               groupc->times_prev[aggregator][s] = times[s];
 
                times[s] = delta;
+               if (delta)
+                       *pchanged_states |= (1 << s);
        }
 }
 
@@ -269,17 +298,16 @@ static void calc_avgs(unsigned long avg[3], int missed_periods,
        avg[2] = calc_load(avg[2], EXP_300s, pct);
 }
 
-static bool update_stats(struct psi_group *group)
+static void collect_percpu_times(struct psi_group *group,
+                                enum psi_aggregators aggregator,
+                                u32 *pchanged_states)
 {
        u64 deltas[NR_PSI_STATES - 1] = { 0, };
-       unsigned long missed_periods = 0;
        unsigned long nonidle_total = 0;
-       u64 now, expires, period;
+       u32 changed_states = 0;
        int cpu;
        int s;
 
-       mutex_lock(&group->stat_lock);
-
        /*
         * Collect the per-cpu time buckets and average them into a
         * single time sample that is normalized to wallclock time.
@@ -291,8 +319,11 @@ static bool update_stats(struct psi_group *group)
        for_each_possible_cpu(cpu) {
                u32 times[NR_PSI_STATES];
                u32 nonidle;
+               u32 cpu_changed_states;
 
-               get_recent_times(group, cpu, times);
+               get_recent_times(group, cpu, aggregator, times,
+                               &cpu_changed_states);
+               changed_states |= cpu_changed_states;
 
                nonidle = nsecs_to_jiffies(times[PSI_NONIDLE]);
                nonidle_total += nonidle;
@@ -315,13 +346,22 @@ static bool update_stats(struct psi_group *group)
 
        /* total= */
        for (s = 0; s < NR_PSI_STATES - 1; s++)
-               group->total[s] += div_u64(deltas[s], max(nonidle_total, 1UL));
+               group->total[aggregator][s] +=
+                               div_u64(deltas[s], max(nonidle_total, 1UL));
+
+       if (pchanged_states)
+               *pchanged_states = changed_states;
+}
+
+static u64 update_averages(struct psi_group *group, u64 now)
+{
+       unsigned long missed_periods = 0;
+       u64 expires, period;
+       u64 avg_next_update;
+       int s;
 
        /* avgX= */
-       now = sched_clock();
-       expires = group->next_update;
-       if (now < expires)
-               goto out;
+       expires = group->avg_next_update;
        if (now - expires >= psi_period)
                missed_periods = div_u64(now - expires, psi_period);
 
@@ -332,14 +372,14 @@ static bool update_stats(struct psi_group *group)
         * But the deltas we sample out of the per-cpu buckets above
         * are based on the actual time elapsing between clock ticks.
         */
-       group->next_update = expires + ((1 + missed_periods) * psi_period);
-       period = now - (group->last_update + (missed_periods * psi_period));
-       group->last_update = now;
+       avg_next_update = expires + ((1 + missed_periods) * psi_period);
+       period = now - (group->avg_last_update + (missed_periods * psi_period));
+       group->avg_last_update = now;
 
        for (s = 0; s < NR_PSI_STATES - 1; s++) {
                u32 sample;
 
-               sample = group->total[s] - group->total_prev[s];
+               sample = group->total[PSI_AVGS][s] - group->avg_total[s];
                /*
                 * Due to the lockless sampling of the time buckets,
                 * recorded time deltas can slip into the next period,
@@ -359,23 +399,30 @@ static bool update_stats(struct psi_group *group)
                 */
                if (sample > period)
                        sample = period;
-               group->total_prev[s] += sample;
+               group->avg_total[s] += sample;
                calc_avgs(group->avg[s], missed_periods, sample, period);
        }
-out:
-       mutex_unlock(&group->stat_lock);
-       return nonidle_total;
+
+       return avg_next_update;
 }
 
-static void psi_update_work(struct work_struct *work)
+static void psi_avgs_work(struct work_struct *work)
 {
        struct delayed_work *dwork;
        struct psi_group *group;
+       u32 changed_states;
        bool nonidle;
+       u64 now;
 
        dwork = to_delayed_work(work);
-       group = container_of(dwork, struct psi_group, clock_work);
+       group = container_of(dwork, struct psi_group, avgs_work);
+
+       mutex_lock(&group->avgs_lock);
 
+       now = sched_clock();
+
+       collect_percpu_times(group, PSI_AVGS, &changed_states);
+       nonidle = changed_states & (1 << PSI_NONIDLE);
        /*
         * If there is task activity, periodically fold the per-cpu
         * times and feed samples into the running averages. If things
@@ -383,18 +430,196 @@ static void psi_update_work(struct work_struct *work)
         * Once restarted, we'll catch up the running averages in one
         * go - see calc_avgs() and missed_periods.
         */
-
-       nonidle = update_stats(group);
+       if (now >= group->avg_next_update)
+               group->avg_next_update = update_averages(group, now);
 
        if (nonidle) {
-               unsigned long delay = 0;
-               u64 now;
+               schedule_delayed_work(dwork, nsecs_to_jiffies(
+                               group->avg_next_update - now) + 1);
+       }
+
+       mutex_unlock(&group->avgs_lock);
+}
+
+/* Trigger tracking window manupulations */
+static void window_reset(struct psi_window *win, u64 now, u64 value,
+                        u64 prev_growth)
+{
+       win->start_time = now;
+       win->start_value = value;
+       win->prev_growth = prev_growth;
+}
+
+/*
+ * PSI growth tracking window update and growth calculation routine.
+ *
+ * This approximates a sliding tracking window by interpolating
+ * partially elapsed windows using historical growth data from the
+ * previous intervals. This minimizes memory requirements (by not storing
+ * all the intermediate values in the previous window) and simplifies
+ * the calculations. It works well because PSI signal changes only in
+ * positive direction and over relatively small window sizes the growth
+ * is close to linear.
+ */
+static u64 window_update(struct psi_window *win, u64 now, u64 value)
+{
+       u64 elapsed;
+       u64 growth;
+
+       elapsed = now - win->start_time;
+       growth = value - win->start_value;
+       /*
+        * After each tracking window passes win->start_value and
+        * win->start_time get reset and win->prev_growth stores
+        * the average per-window growth of the previous window.
+        * win->prev_growth is then used to interpolate additional
+        * growth from the previous window assuming it was linear.
+        */
+       if (elapsed > win->size)
+               window_reset(win, now, value, growth);
+       else {
+               u32 remaining;
+
+               remaining = win->size - elapsed;
+               growth += div_u64(win->prev_growth * remaining, win->size);
+       }
+
+       return growth;
+}
+
+static void init_triggers(struct psi_group *group, u64 now)
+{
+       struct psi_trigger *t;
+
+       list_for_each_entry(t, &group->triggers, node)
+               window_reset(&t->win, now,
+                               group->total[PSI_POLL][t->state], 0);
+       memcpy(group->polling_total, group->total[PSI_POLL],
+                  sizeof(group->polling_total));
+       group->polling_next_update = now + group->poll_min_period;
+}
+
+static u64 update_triggers(struct psi_group *group, u64 now)
+{
+       struct psi_trigger *t;
+       bool new_stall = false;
+       u64 *total = group->total[PSI_POLL];
+
+       /*
+        * On subsequent updates, calculate growth deltas and let
+        * watchers know when their specified thresholds are exceeded.
+        */
+       list_for_each_entry(t, &group->triggers, node) {
+               u64 growth;
+
+               /* Check for stall activity */
+               if (group->polling_total[t->state] == total[t->state])
+                       continue;
+
+               /*
+                * Multiple triggers might be looking at the same state,
+                * remember to update group->polling_total[] once we've
+                * been through all of them. Also remember to extend the
+                * polling time if we see new stall activity.
+                */
+               new_stall = true;
+
+               /* Calculate growth since last update */
+               growth = window_update(&t->win, now, total[t->state]);
+               if (growth < t->threshold)
+                       continue;
+
+               /* Limit event signaling to once per window */
+               if (now < t->last_event_time + t->win.size)
+                       continue;
+
+               /* Generate an event */
+               if (cmpxchg(&t->event, 0, 1) == 0)
+                       wake_up_interruptible(&t->event_wait);
+               t->last_event_time = now;
+       }
+
+       if (new_stall)
+               memcpy(group->polling_total, total,
+                               sizeof(group->polling_total));
+
+       return now + group->poll_min_period;
+}
+
+/*
+ * Schedule polling if it's not already scheduled. It's safe to call even from
+ * hotpath because even though kthread_queue_delayed_work takes worker->lock
+ * spinlock that spinlock is never contended due to poll_scheduled atomic
+ * preventing such competition.
+ */
+static void psi_schedule_poll_work(struct psi_group *group, unsigned long delay)
+{
+       struct kthread_worker *kworker;
+
+       /* Do not reschedule if already scheduled */
+       if (atomic_cmpxchg(&group->poll_scheduled, 0, 1) != 0)
+               return;
+
+       rcu_read_lock();
 
-               now = sched_clock();
-               if (group->next_update > now)
-                       delay = nsecs_to_jiffies(group->next_update - now) + 1;
-               schedule_delayed_work(dwork, delay);
+       kworker = rcu_dereference(group->poll_kworker);
+       /*
+        * kworker might be NULL in case psi_trigger_destroy races with
+        * psi_task_change (hotpath) which can't use locks
+        */
+       if (likely(kworker))
+               kthread_queue_delayed_work(kworker, &group->poll_work, delay);
+       else
+               atomic_set(&group->poll_scheduled, 0);
+
+       rcu_read_unlock();
+}
+
+static void psi_poll_work(struct kthread_work *work)
+{
+       struct kthread_delayed_work *dwork;
+       struct psi_group *group;
+       u32 changed_states;
+       u64 now;
+
+       dwork = container_of(work, struct kthread_delayed_work, work);
+       group = container_of(dwork, struct psi_group, poll_work);
+
+       atomic_set(&group->poll_scheduled, 0);
+
+       mutex_lock(&group->trigger_lock);
+
+       now = sched_clock();
+
+       collect_percpu_times(group, PSI_POLL, &changed_states);
+
+       if (changed_states & group->poll_states) {
+               /* Initialize trigger windows when entering polling mode */
+               if (now > group->polling_until)
+                       init_triggers(group, now);
+
+               /*
+                * Keep the monitor active for at least the duration of the
+                * minimum tracking window as long as monitor states are
+                * changing.
+                */
+               group->polling_until = now +
+                       group->poll_min_period * UPDATES_PER_WINDOW;
+       }
+
+       if (now > group->polling_until) {
+               group->polling_next_update = ULLONG_MAX;
+               goto out;
        }
+
+       if (now >= group->polling_next_update)
+               group->polling_next_update = update_triggers(group, now);
+
+       psi_schedule_poll_work(group,
+               nsecs_to_jiffies(group->polling_next_update - now) + 1);
+
+out:
+       mutex_unlock(&group->trigger_lock);
 }
 
 static void record_times(struct psi_group_cpu *groupc, int cpu,
@@ -407,15 +632,15 @@ static void record_times(struct psi_group_cpu *groupc, int cpu,
        delta = now - groupc->state_start;
        groupc->state_start = now;
 
-       if (test_state(groupc->tasks, PSI_IO_SOME)) {
+       if (groupc->state_mask & (1 << PSI_IO_SOME)) {
                groupc->times[PSI_IO_SOME] += delta;
-               if (test_state(groupc->tasks, PSI_IO_FULL))
+               if (groupc->state_mask & (1 << PSI_IO_FULL))
                        groupc->times[PSI_IO_FULL] += delta;
        }
 
-       if (test_state(groupc->tasks, PSI_MEM_SOME)) {
+       if (groupc->state_mask & (1 << PSI_MEM_SOME)) {
                groupc->times[PSI_MEM_SOME] += delta;
-               if (test_state(groupc->tasks, PSI_MEM_FULL))
+               if (groupc->state_mask & (1 << PSI_MEM_FULL))
                        groupc->times[PSI_MEM_FULL] += delta;
                else if (memstall_tick) {
                        u32 sample;
@@ -436,18 +661,20 @@ static void record_times(struct psi_group_cpu *groupc, int cpu,
                }
        }
 
-       if (test_state(groupc->tasks, PSI_CPU_SOME))
+       if (groupc->state_mask & (1 << PSI_CPU_SOME))
                groupc->times[PSI_CPU_SOME] += delta;
 
-       if (test_state(groupc->tasks, PSI_NONIDLE))
+       if (groupc->state_mask & (1 << PSI_NONIDLE))
                groupc->times[PSI_NONIDLE] += delta;
 }
 
-static void psi_group_change(struct psi_group *group, int cpu,
-                            unsigned int clear, unsigned int set)
+static u32 psi_group_change(struct psi_group *group, int cpu,
+                           unsigned int clear, unsigned int set)
 {
        struct psi_group_cpu *groupc;
        unsigned int t, m;
+       enum psi_states s;
+       u32 state_mask = 0;
 
        groupc = per_cpu_ptr(group->pcpu, cpu);
 
@@ -480,7 +707,16 @@ static void psi_group_change(struct psi_group *group, int cpu,
                if (set & (1 << t))
                        groupc->tasks[t]++;
 
+       /* Calculate state mask representing active states */
+       for (s = 0; s < NR_PSI_STATES; s++) {
+               if (test_state(groupc->tasks, s))
+                       state_mask |= (1 << s);
+       }
+       groupc->state_mask = state_mask;
+
        write_seqcount_end(&groupc->seq);
+
+       return state_mask;
 }
 
 static struct psi_group *iterate_groups(struct task_struct *task, void **iter)
@@ -537,13 +773,17 @@ void psi_task_change(struct task_struct *task, int clear, int set)
         */
        if (unlikely((clear & TSK_RUNNING) &&
                     (task->flags & PF_WQ_WORKER) &&
-                    wq_worker_last_func(task) == psi_update_work))
+                    wq_worker_last_func(task) == psi_avgs_work))
                wake_clock = false;
 
        while ((group = iterate_groups(task, &iter))) {
-               psi_group_change(group, cpu, clear, set);
-               if (wake_clock && !delayed_work_pending(&group->clock_work))
-                       schedule_delayed_work(&group->clock_work, PSI_FREQ);
+               u32 state_mask = psi_group_change(group, cpu, clear, set);
+
+               if (state_mask & group->poll_states)
+                       psi_schedule_poll_work(group, 1);
+
+               if (wake_clock && !delayed_work_pending(&group->avgs_work))
+                       schedule_delayed_work(&group->avgs_work, PSI_FREQ);
        }
 }
 
@@ -640,8 +880,10 @@ void psi_cgroup_free(struct cgroup *cgroup)
        if (static_branch_likely(&psi_disabled))
                return;
 
-       cancel_delayed_work_sync(&cgroup->psi.clock_work);
+       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");
 }
 
 /**
@@ -697,11 +939,18 @@ void cgroup_move_task(struct task_struct *task, struct css_set *to)
 int psi_show(struct seq_file *m, struct psi_group *group, enum psi_res res)
 {
        int full;
+       u64 now;
 
        if (static_branch_likely(&psi_disabled))
                return -EOPNOTSUPP;
 
-       update_stats(group);
+       /* Update averages before reporting them */
+       mutex_lock(&group->avgs_lock);
+       now = sched_clock();
+       collect_percpu_times(group, PSI_AVGS, NULL);
+       if (now >= group->avg_next_update)
+               group->avg_next_update = update_averages(group, now);
+       mutex_unlock(&group->avgs_lock);
 
        for (full = 0; full < 2 - (res == PSI_CPU); full++) {
                unsigned long avg[3];
@@ -710,7 +959,8 @@ int psi_show(struct seq_file *m, struct psi_group *group, enum psi_res res)
 
                for (w = 0; w < 3; w++)
                        avg[w] = group->avg[res * 2 + full][w];
-               total = div_u64(group->total[res * 2 + full], NSEC_PER_USEC);
+               total = div_u64(group->total[PSI_AVGS][res * 2 + full],
+                               NSEC_PER_USEC);
 
                seq_printf(m, "%s avg10=%lu.%02lu avg60=%lu.%02lu avg300=%lu.%02lu total=%llu\n",
                           full ? "full" : "some",
@@ -753,25 +1003,270 @@ static int psi_cpu_open(struct inode *inode, struct file *file)
        return single_open(file, psi_cpu_show, NULL);
 }
 
+struct psi_trigger *psi_trigger_create(struct psi_group *group,
+                       char *buf, size_t nbytes, enum psi_res res)
+{
+       struct psi_trigger *t;
+       enum psi_states state;
+       u32 threshold_us;
+       u32 window_us;
+
+       if (static_branch_likely(&psi_disabled))
+               return ERR_PTR(-EOPNOTSUPP);
+
+       if (sscanf(buf, "some %u %u", &threshold_us, &window_us) == 2)
+               state = PSI_IO_SOME + res * 2;
+       else if (sscanf(buf, "full %u %u", &threshold_us, &window_us) == 2)
+               state = PSI_IO_FULL + res * 2;
+       else
+               return ERR_PTR(-EINVAL);
+
+       if (state >= PSI_NONIDLE)
+               return ERR_PTR(-EINVAL);
+
+       if (window_us < WINDOW_MIN_US ||
+               window_us > WINDOW_MAX_US)
+               return ERR_PTR(-EINVAL);
+
+       /* Check threshold */
+       if (threshold_us == 0 || threshold_us > window_us)
+               return ERR_PTR(-EINVAL);
+
+       t = kmalloc(sizeof(*t), GFP_KERNEL);
+       if (!t)
+               return ERR_PTR(-ENOMEM);
+
+       t->group = group;
+       t->state = state;
+       t->threshold = threshold_us * NSEC_PER_USEC;
+       t->win.size = window_us * NSEC_PER_USEC;
+       window_reset(&t->win, 0, 0, 0);
+
+       t->event = 0;
+       t->last_event_time = 0;
+       init_waitqueue_head(&t->event_wait);
+       kref_init(&t->refcount);
+
+       mutex_lock(&group->trigger_lock);
+
+       if (!rcu_access_pointer(group->poll_kworker)) {
+               struct sched_param param = {
+                       .sched_priority = MAX_RT_PRIO - 1,
+               };
+               struct kthread_worker *kworker;
+
+               kworker = kthread_create_worker(0, "psimon");
+               if (IS_ERR(kworker)) {
+                       kfree(t);
+                       mutex_unlock(&group->trigger_lock);
+                       return ERR_CAST(kworker);
+               }
+               sched_setscheduler(kworker->task, SCHED_FIFO, &param);
+               kthread_init_delayed_work(&group->poll_work,
+                               psi_poll_work);
+               rcu_assign_pointer(group->poll_kworker, kworker);
+       }
+
+       list_add(&t->node, &group->triggers);
+       group->poll_min_period = min(group->poll_min_period,
+               div_u64(t->win.size, UPDATES_PER_WINDOW));
+       group->nr_triggers[t->state]++;
+       group->poll_states |= (1 << t->state);
+
+       mutex_unlock(&group->trigger_lock);
+
+       return t;
+}
+
+static void psi_trigger_destroy(struct kref *ref)
+{
+       struct psi_trigger *t = container_of(ref, struct psi_trigger, refcount);
+       struct psi_group *group = t->group;
+       struct kthread_worker *kworker_to_destroy = NULL;
+
+       if (static_branch_likely(&psi_disabled))
+               return;
+
+       /*
+        * Wakeup waiters to stop polling. Can happen if cgroup is deleted
+        * from under a polling process.
+        */
+       wake_up_interruptible(&t->event_wait);
+
+       mutex_lock(&group->trigger_lock);
+
+       if (!list_empty(&t->node)) {
+               struct psi_trigger *tmp;
+               u64 period = ULLONG_MAX;
+
+               list_del(&t->node);
+               group->nr_triggers[t->state]--;
+               if (!group->nr_triggers[t->state])
+                       group->poll_states &= ~(1 << t->state);
+               /* reset min update period for the remaining triggers */
+               list_for_each_entry(tmp, &group->triggers, node)
+                       period = min(period, div_u64(tmp->win.size,
+                                       UPDATES_PER_WINDOW));
+               group->poll_min_period = period;
+               /* Destroy poll_kworker when the last trigger is destroyed */
+               if (group->poll_states == 0) {
+                       group->polling_until = 0;
+                       kworker_to_destroy = rcu_dereference_protected(
+                                       group->poll_kworker,
+                                       lockdep_is_held(&group->trigger_lock));
+                       rcu_assign_pointer(group->poll_kworker, NULL);
+               }
+       }
+
+       mutex_unlock(&group->trigger_lock);
+
+       /*
+        * Wait for both *trigger_ptr from psi_trigger_replace and
+        * poll_kworker RCUs to complete their read-side critical sections
+        * before destroying the trigger and optionally the poll_kworker
+        */
+       synchronize_rcu();
+       /*
+        * Destroy the kworker after releasing trigger_lock to prevent a
+        * deadlock while waiting for psi_poll_work to acquire trigger_lock
+        */
+       if (kworker_to_destroy) {
+               kthread_cancel_delayed_work_sync(&group->poll_work);
+               kthread_destroy_worker(kworker_to_destroy);
+       }
+       kfree(t);
+}
+
+void psi_trigger_replace(void **trigger_ptr, struct psi_trigger *new)
+{
+       struct psi_trigger *old = *trigger_ptr;
+
+       if (static_branch_likely(&psi_disabled))
+               return;
+
+       rcu_assign_pointer(*trigger_ptr, new);
+       if (old)
+               kref_put(&old->refcount, psi_trigger_destroy);
+}
+
+__poll_t psi_trigger_poll(void **trigger_ptr,
+                               struct file *file, poll_table *wait)
+{
+       __poll_t ret = DEFAULT_POLLMASK;
+       struct psi_trigger *t;
+
+       if (static_branch_likely(&psi_disabled))
+               return DEFAULT_POLLMASK | EPOLLERR | EPOLLPRI;
+
+       rcu_read_lock();
+
+       t = rcu_dereference(*(void __rcu __force **)trigger_ptr);
+       if (!t) {
+               rcu_read_unlock();
+               return DEFAULT_POLLMASK | EPOLLERR | EPOLLPRI;
+       }
+       kref_get(&t->refcount);
+
+       rcu_read_unlock();
+
+       poll_wait(file, &t->event_wait, wait);
+
+       if (cmpxchg(&t->event, 1, 0) == 1)
+               ret |= EPOLLPRI;
+
+       kref_put(&t->refcount, psi_trigger_destroy);
+
+       return ret;
+}
+
+static ssize_t psi_write(struct file *file, const char __user *user_buf,
+                        size_t nbytes, enum psi_res res)
+{
+       char buf[32];
+       size_t buf_size;
+       struct seq_file *seq;
+       struct psi_trigger *new;
+
+       if (static_branch_likely(&psi_disabled))
+               return -EOPNOTSUPP;
+
+       buf_size = min(nbytes, (sizeof(buf) - 1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       buf[buf_size - 1] = '\0';
+
+       new = psi_trigger_create(&psi_system, buf, nbytes, res);
+       if (IS_ERR(new))
+               return PTR_ERR(new);
+
+       seq = file->private_data;
+       /* Take seq->lock to protect seq->private from concurrent writes */
+       mutex_lock(&seq->lock);
+       psi_trigger_replace(&seq->private, new);
+       mutex_unlock(&seq->lock);
+
+       return nbytes;
+}
+
+static ssize_t psi_io_write(struct file *file, const char __user *user_buf,
+                           size_t nbytes, loff_t *ppos)
+{
+       return psi_write(file, user_buf, nbytes, PSI_IO);
+}
+
+static ssize_t psi_memory_write(struct file *file, const char __user *user_buf,
+                               size_t nbytes, loff_t *ppos)
+{
+       return psi_write(file, user_buf, nbytes, PSI_MEM);
+}
+
+static ssize_t psi_cpu_write(struct file *file, const char __user *user_buf,
+                            size_t nbytes, loff_t *ppos)
+{
+       return psi_write(file, user_buf, nbytes, PSI_CPU);
+}
+
+static __poll_t psi_fop_poll(struct file *file, poll_table *wait)
+{
+       struct seq_file *seq = file->private_data;
+
+       return psi_trigger_poll(&seq->private, file, wait);
+}
+
+static int psi_fop_release(struct inode *inode, struct file *file)
+{
+       struct seq_file *seq = file->private_data;
+
+       psi_trigger_replace(&seq->private, NULL);
+       return single_release(inode, file);
+}
+
 static const struct file_operations psi_io_fops = {
        .open           = psi_io_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = single_release,
+       .write          = psi_io_write,
+       .poll           = psi_fop_poll,
+       .release        = psi_fop_release,
 };
 
 static const struct file_operations psi_memory_fops = {
        .open           = psi_memory_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = single_release,
+       .write          = psi_memory_write,
+       .poll           = psi_fop_poll,
+       .release        = psi_fop_release,
 };
 
 static const struct file_operations psi_cpu_fops = {
        .open           = psi_cpu_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = single_release,
+       .write          = psi_cpu_write,
+       .poll           = psi_fop_poll,
+       .release        = psi_fop_release,
 };
 
 static int __init psi_proc_init(void)
index 62f9aea4a15a0f6295145626ee5597970785d7d3..a1eb44dc9ff523d16401a00f9b65117b96bfee01 100644 (file)
@@ -840,6 +840,7 @@ static int check_kill_permission(int sig, struct kernel_siginfo *info,
                         */
                        if (!sid || sid == task_session(current))
                                break;
+                       /* fall through */
                default:
                        return -EPERM;
                }
@@ -2112,6 +2113,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t
                preempt_enable_no_resched();
                cgroup_enter_frozen();
                freezable_schedule();
+               cgroup_leave_frozen(true);
        } else {
                /*
                 * By the time we got the lock, our tracer went away.
index 12df0e5434b845abe7c5a6d98beb7627503af792..bdbfe8d37418fd5f20ff429d15258f331cb7bf68 100644 (file)
@@ -1924,7 +1924,7 @@ static int validate_prctl_map(struct prctl_mm_map *prctl_map)
        ((unsigned long)prctl_map->__m1 __op                            \
         (unsigned long)prctl_map->__m2) ? 0 : -EINVAL
        error  = __prctl_check_order(start_code, <, end_code);
-       error |= __prctl_check_order(start_data, <, end_data);
+       error |= __prctl_check_order(start_data,<=, end_data);
        error |= __prctl_check_order(start_brk, <=, brk);
        error |= __prctl_check_order(arg_start, <=, arg_end);
        error |= __prctl_check_order(env_start, <=, env_end);
index 599510a3355e1336609c4237e1a566905c7a117d..943c89178e3d3eb04accf784b38f18813d35abbc 100644 (file)
@@ -66,6 +66,7 @@
 #include <linux/kexec.h>
 #include <linux/bpf.h>
 #include <linux/mount.h>
+#include <linux/userfaultfd_k.h>
 
 #include "../lib/kstrtox.h"
 
@@ -1719,6 +1720,17 @@ static struct ctl_table vm_table[] = {
                .extra1         = (void *)&mmap_rnd_compat_bits_min,
                .extra2         = (void *)&mmap_rnd_compat_bits_max,
        },
+#endif
+#ifdef CONFIG_USERFAULTFD
+       {
+               .procname       = "unprivileged_userfaultfd",
+               .data           = &sysctl_unprivileged_userfaultfd,
+               .maxlen         = sizeof(sysctl_unprivileged_userfaultfd),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &one,
+       },
 #endif
        { }
 };
@@ -2874,8 +2886,10 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
                        if (neg)
                                continue;
                        val = convmul * val / convdiv;
-                       if ((min && val < *min) || (max && val > *max))
-                               continue;
+                       if ((min && val < *min) || (max && val > *max)) {
+                               err = -EINVAL;
+                               break;
+                       }
                        *i = val;
                } else {
                        val = convdiv * (*i) / convmul;
@@ -3158,17 +3172,19 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
 
        if (write) {
                char *kbuf, *p;
+               size_t skipped = 0;
 
-               if (left > PAGE_SIZE - 1)
+               if (left > PAGE_SIZE - 1) {
                        left = PAGE_SIZE - 1;
+                       /* How much of the buffer we'll skip this pass */
+                       skipped = *lenp - left;
+               }
 
                p = kbuf = memdup_user_nul(buffer, left);
                if (IS_ERR(kbuf))
                        return PTR_ERR(kbuf);
 
-               tmp_bitmap = kcalloc(BITS_TO_LONGS(bitmap_len),
-                                    sizeof(unsigned long),
-                                    GFP_KERNEL);
+               tmp_bitmap = bitmap_zalloc(bitmap_len, GFP_KERNEL);
                if (!tmp_bitmap) {
                        kfree(kbuf);
                        return -ENOMEM;
@@ -3177,9 +3193,22 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
                while (!err && left) {
                        unsigned long val_a, val_b;
                        bool neg;
+                       size_t saved_left;
 
+                       /* In case we stop parsing mid-number, we can reset */
+                       saved_left = left;
                        err = proc_get_long(&p, &left, &val_a, &neg, tr_a,
                                             sizeof(tr_a), &c);
+                       /*
+                        * If we consumed the entirety of a truncated buffer or
+                        * only one char is left (may be a "-"), then stop here,
+                        * reset, & come back for more.
+                        */
+                       if ((left <= 1) && skipped) {
+                               left = saved_left;
+                               break;
+                       }
+
                        if (err)
                                break;
                        if (val_a >= bitmap_len || neg) {
@@ -3197,6 +3226,15 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
                                err = proc_get_long(&p, &left, &val_b,
                                                     &neg, tr_b, sizeof(tr_b),
                                                     &c);
+                               /*
+                                * If we consumed all of a truncated buffer or
+                                * then stop here, reset, & come back for more.
+                                */
+                               if (!left && skipped) {
+                                       left = saved_left;
+                                       break;
+                               }
+
                                if (err)
                                        break;
                                if (val_b >= bitmap_len || neg ||
@@ -3215,6 +3253,7 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
                        proc_skip_char(&p, &left, '\n');
                }
                kfree(kbuf);
+               left += skipped;
        } else {
                unsigned long bit_a, bit_b = 0;
 
@@ -3259,7 +3298,7 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
                *ppos += *lenp;
        }
 
-       kfree(tmp_bitmap);
+       bitmap_free(tmp_bitmap);
        return err;
 }
 
index ac5555e257334b7a33bab652e37fc43dfb0f9bac..8de4f789dc1b59cd45383a225487e5510580a023 100644 (file)
@@ -691,7 +691,7 @@ static inline void process_adjtimex_modes(const struct __kernel_timex *txc,
                time_constant = max(time_constant, 0l);
        }
 
-       if (txc->modes & ADJ_TAI && txc->constant > 0)
+       if (txc->modes & ADJ_TAI && txc->constant >= 0)
                *time_tai = txc->constant;
 
        if (txc->modes & ADJ_OFFSET)
index 8bd1d6d001d7bca02b13975b1dd16d09825619bc..5d965cef6c77941264e5c5e1a4dc2d8c32e3dd33 100644 (file)
@@ -774,13 +774,6 @@ config TRACE_EVAL_MAP_FILE
 
        If unsure, say N
 
-config TRACING_EVENTS_GPIO
-       bool "Trace gpio events"
-       depends on GPIOLIB
-       default y
-       help
-         Enable tracing events for gpio subsystem
-
 config GCOV_PROFILE_FTRACE
        bool "Enable GCOV profiling on ftrace subsystem"
        depends on GCOV_KERNEL
index b920358dd8f7f8cfcd226ba046e786901699c53a..a12aff849c0437021b46d3351e16274824cbbc87 100644 (file)
 #define INIT_OPS_HASH(opsname) \
        .func_hash              = &opsname.local_hash,                  \
        .local_hash.regex_lock  = __MUTEX_INITIALIZER(opsname.local_hash.regex_lock),
-#define ASSIGN_OPS_HASH(opsname, val) \
-       .func_hash              = val, \
-       .local_hash.regex_lock  = __MUTEX_INITIALIZER(opsname.local_hash.regex_lock),
 #else
 #define INIT_OPS_HASH(opsname)
-#define ASSIGN_OPS_HASH(opsname, val)
 #endif
 
 enum {
@@ -3880,7 +3876,7 @@ static int ftrace_hash_move_and_update_ops(struct ftrace_ops *ops,
 static bool module_exists(const char *module)
 {
        /* All modules have the symbol __this_module */
-       const char this_mod[] = "__this_module";
+       static const char this_mod[] = "__this_module";
        char modname[MAX_PARAM_PREFIX_LEN + sizeof(this_mod) + 2];
        unsigned long val;
        int n;
@@ -6265,6 +6261,9 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
        preempt_disable_notrace();
 
        do_for_each_ftrace_op(op, ftrace_ops_list) {
+               /* Stub functions don't need to be called nor tested */
+               if (op->flags & FTRACE_OPS_FL_STUB)
+                       continue;
                /*
                 * Check the following for each ops before calling their func:
                 *  if RCU flag is set, then rcu_is_watching() must be true
index 4ee8d8aa3d0fdcfe6dac6ea91c4ee96cc9330835..05b0b3139ebcc1a9fd3bc659b52a8dfb9ca42844 100644 (file)
@@ -4979,7 +4979,7 @@ static __init int rb_write_something(struct rb_test_data *data, bool nested)
        cnt = data->cnt + (nested ? 27 : 0);
 
        /* Multiply cnt by ~e, to make some unique increment */
-       size = (data->cnt * 68 / 25) % (sizeof(rb_string) - 1);
+       size = (cnt * 68 / 25) % (sizeof(rb_string) - 1);
 
        len = size + sizeof(struct rb_item);
 
index ffba6789c0e2442044ee24a5176982d86d7ac625..0564f6db05617ae0dcebbd82c6bd7af33ec62e44 100644 (file)
@@ -362,7 +362,7 @@ static void ring_buffer_producer(void)
                        hit--; /* make it non zero */
                }
 
-               /* Caculate the average time in nanosecs */
+               /* Calculate the average time in nanosecs */
                avg = NSEC_PER_MSEC / (hit + missed);
                trace_printk("%ld ns per entry\n", avg);
        }
index ec439999f38748090616406f77b93afc6f39b07a..2c92b3d9ea3077df8cd5d272cc48335e66a64681 100644 (file)
@@ -1727,6 +1727,10 @@ static __init int init_trace_selftests(void)
        pr_info("Running postponed tracer tests:\n");
 
        list_for_each_entry_safe(p, n, &postponed_selftests, list) {
+               /* This loop can take minutes when sanitizers are enabled, so
+                * lets make sure we allow RCU processing.
+                */
+               cond_resched();
                ret = run_tracer_selftest(p->type);
                /* If the test fails, then warn and remove from available_tracers */
                if (ret < 0) {
@@ -3045,6 +3049,7 @@ void trace_printk_init_buffers(void)
        if (global_trace.trace_buffer.buffer)
                tracing_start_cmdline_record();
 }
+EXPORT_SYMBOL_GPL(trace_printk_init_buffers);
 
 void trace_printk_start_comm(void)
 {
@@ -3205,6 +3210,7 @@ int trace_array_printk(struct trace_array *tr,
        va_end(ap);
        return ret;
 }
+EXPORT_SYMBOL_GPL(trace_array_printk);
 
 __printf(3, 4)
 int trace_array_printk_buf(struct ring_buffer *buffer,
@@ -3482,34 +3488,69 @@ static void s_stop(struct seq_file *m, void *p)
        trace_event_read_unlock();
 }
 
+static void
+get_total_entries_cpu(struct trace_buffer *buf, unsigned long *total,
+                     unsigned long *entries, int cpu)
+{
+       unsigned long count;
+
+       count = ring_buffer_entries_cpu(buf->buffer, cpu);
+       /*
+        * If this buffer has skipped entries, then we hold all
+        * entries for the trace and we need to ignore the
+        * ones before the time stamp.
+        */
+       if (per_cpu_ptr(buf->data, cpu)->skipped_entries) {
+               count -= per_cpu_ptr(buf->data, cpu)->skipped_entries;
+               /* total is the same as the entries */
+               *total = count;
+       } else
+               *total = count +
+                       ring_buffer_overrun_cpu(buf->buffer, cpu);
+       *entries = count;
+}
+
 static void
 get_total_entries(struct trace_buffer *buf,
                  unsigned long *total, unsigned long *entries)
 {
-       unsigned long count;
+       unsigned long t, e;
        int cpu;
 
        *total = 0;
        *entries = 0;
 
        for_each_tracing_cpu(cpu) {
-               count = ring_buffer_entries_cpu(buf->buffer, cpu);
-               /*
-                * If this buffer has skipped entries, then we hold all
-                * entries for the trace and we need to ignore the
-                * ones before the time stamp.
-                */
-               if (per_cpu_ptr(buf->data, cpu)->skipped_entries) {
-                       count -= per_cpu_ptr(buf->data, cpu)->skipped_entries;
-                       /* total is the same as the entries */
-                       *total += count;
-               } else
-                       *total += count +
-                               ring_buffer_overrun_cpu(buf->buffer, cpu);
-               *entries += count;
+               get_total_entries_cpu(buf, &t, &e, cpu);
+               *total += t;
+               *entries += e;
        }
 }
 
+unsigned long trace_total_entries_cpu(struct trace_array *tr, int cpu)
+{
+       unsigned long total, entries;
+
+       if (!tr)
+               tr = &global_trace;
+
+       get_total_entries_cpu(&tr->trace_buffer, &total, &entries, cpu);
+
+       return entries;
+}
+
+unsigned long trace_total_entries(struct trace_array *tr)
+{
+       unsigned long total, entries;
+
+       if (!tr)
+               tr = &global_trace;
+
+       get_total_entries(&tr->trace_buffer, &total, &entries);
+
+       return entries;
+}
+
 static void print_lat_help_header(struct seq_file *m)
 {
        seq_puts(m, "#                  _------=> CPU#            \n"
@@ -3548,25 +3589,18 @@ static void print_func_help_header_irq(struct trace_buffer *buf, struct seq_file
                                       unsigned int flags)
 {
        bool tgid = flags & TRACE_ITER_RECORD_TGID;
-       const char tgid_space[] = "          ";
-       const char space[] = "  ";
+       const char *space = "          ";
+       int prec = tgid ? 10 : 2;
 
        print_event_info(buf, m);
 
-       seq_printf(m, "#                          %s  _-----=> irqs-off\n",
-                  tgid ? tgid_space : space);
-       seq_printf(m, "#                          %s / _----=> need-resched\n",
-                  tgid ? tgid_space : space);
-       seq_printf(m, "#                          %s| / _---=> hardirq/softirq\n",
-                  tgid ? tgid_space : space);
-       seq_printf(m, "#                          %s|| / _--=> preempt-depth\n",
-                  tgid ? tgid_space : space);
-       seq_printf(m, "#                          %s||| /     delay\n",
-                  tgid ? tgid_space : space);
-       seq_printf(m, "#           TASK-PID %sCPU#  ||||    TIMESTAMP  FUNCTION\n",
-                  tgid ? "   TGID   " : space);
-       seq_printf(m, "#              | |   %s  |   ||||       |         |\n",
-                  tgid ? "     |    " : space);
+       seq_printf(m, "#                          %.*s  _-----=> irqs-off\n", prec, space);
+       seq_printf(m, "#                          %.*s / _----=> need-resched\n", prec, space);
+       seq_printf(m, "#                          %.*s| / _---=> hardirq/softirq\n", prec, space);
+       seq_printf(m, "#                          %.*s|| / _--=> preempt-depth\n", prec, space);
+       seq_printf(m, "#                          %.*s||| /     delay\n", prec, space);
+       seq_printf(m, "#           TASK-PID %.*sCPU#  ||||    TIMESTAMP  FUNCTION\n", prec, "   TGID   ");
+       seq_printf(m, "#              | |   %.*s  |   ||||       |         |\n", prec, "     |    ");
 }
 
 void
@@ -4692,6 +4726,7 @@ static const char readme_msg[] =
        "  trace_pipe\t\t- A consuming read to see the contents of the buffer\n"
        "  current_tracer\t- function and latency tracers\n"
        "  available_tracers\t- list of configured tracers for current_tracer\n"
+       "  error_log\t- error log for failed commands (that support it)\n"
        "  buffer_size_kb\t- view and modify size of per cpu buffer\n"
        "  buffer_total_size_kb  - view total size of all cpu buffers\n\n"
        "  trace_clock\t\t-change the clock used to order events\n"
@@ -4712,7 +4747,7 @@ static const char readme_msg[] =
        "  instances\t\t- Make sub-buffers with: mkdir instances/foo\n"
        "\t\t\t  Remove sub-buffer with rmdir\n"
        "  trace_options\t\t- Set format or modify how tracing happens\n"
-       "\t\t\t  Disable an option by adding a suffix 'no' to the\n"
+       "\t\t\t  Disable an option by prefixing 'no' to the\n"
        "\t\t\t  option name\n"
        "  saved_cmdlines_size\t- echo command number in here to store comm-pid list\n"
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -6296,13 +6331,13 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
        struct ring_buffer *buffer;
        struct print_entry *entry;
        unsigned long irq_flags;
-       const char faulted[] = "<faulted>";
        ssize_t written;
        int size;
        int len;
 
 /* Used in tracing_mark_raw_write() as well */
-#define FAULTED_SIZE (sizeof(faulted) - 1) /* '\0' is already accounted for */
+#define FAULTED_STR "<faulted>"
+#define FAULTED_SIZE (sizeof(FAULTED_STR) - 1) /* '\0' is already accounted for */
 
        if (tracing_disabled)
                return -EINVAL;
@@ -6334,7 +6369,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
 
        len = __copy_from_user_inatomic(&entry->buf, ubuf, cnt);
        if (len) {
-               memcpy(&entry->buf, faulted, FAULTED_SIZE);
+               memcpy(&entry->buf, FAULTED_STR, FAULTED_SIZE);
                cnt = FAULTED_SIZE;
                written = -EFAULT;
        } else
@@ -6375,7 +6410,6 @@ tracing_mark_raw_write(struct file *filp, const char __user *ubuf,
        struct ring_buffer_event *event;
        struct ring_buffer *buffer;
        struct raw_data_entry *entry;
-       const char faulted[] = "<faulted>";
        unsigned long irq_flags;
        ssize_t written;
        int size;
@@ -6415,7 +6449,7 @@ tracing_mark_raw_write(struct file *filp, const char __user *ubuf,
        len = __copy_from_user_inatomic(&entry->id, ubuf, cnt);
        if (len) {
                entry->id = -1;
-               memcpy(&entry->buf, faulted, FAULTED_SIZE);
+               memcpy(&entry->buf, FAULTED_STR, FAULTED_SIZE);
                written = -EFAULT;
        } else
                written = cnt;
@@ -6868,6 +6902,238 @@ static const struct file_operations snapshot_raw_fops = {
 
 #endif /* CONFIG_TRACER_SNAPSHOT */
 
+#define TRACING_LOG_ERRS_MAX   8
+#define TRACING_LOG_LOC_MAX    128
+
+#define CMD_PREFIX "  Command: "
+
+struct err_info {
+       const char      **errs; /* ptr to loc-specific array of err strings */
+       u8              type;   /* index into errs -> specific err string */
+       u8              pos;    /* MAX_FILTER_STR_VAL = 256 */
+       u64             ts;
+};
+
+struct tracing_log_err {
+       struct list_head        list;
+       struct err_info         info;
+       char                    loc[TRACING_LOG_LOC_MAX]; /* err location */
+       char                    cmd[MAX_FILTER_STR_VAL]; /* what caused err */
+};
+
+static DEFINE_MUTEX(tracing_err_log_lock);
+
+struct tracing_log_err *get_tracing_log_err(struct trace_array *tr)
+{
+       struct tracing_log_err *err;
+
+       if (tr->n_err_log_entries < TRACING_LOG_ERRS_MAX) {
+               err = kzalloc(sizeof(*err), GFP_KERNEL);
+               if (!err)
+                       err = ERR_PTR(-ENOMEM);
+               tr->n_err_log_entries++;
+
+               return err;
+       }
+
+       err = list_first_entry(&tr->err_log, struct tracing_log_err, list);
+       list_del(&err->list);
+
+       return err;
+}
+
+/**
+ * err_pos - find the position of a string within a command for error careting
+ * @cmd: The tracing command that caused the error
+ * @str: The string to position the caret at within @cmd
+ *
+ * Finds the position of the first occurence of @str within @cmd.  The
+ * return value can be passed to tracing_log_err() for caret placement
+ * within @cmd.
+ *
+ * Returns the index within @cmd of the first occurence of @str or 0
+ * if @str was not found.
+ */
+unsigned int err_pos(char *cmd, const char *str)
+{
+       char *found;
+
+       if (WARN_ON(!strlen(cmd)))
+               return 0;
+
+       found = strstr(cmd, str);
+       if (found)
+               return found - cmd;
+
+       return 0;
+}
+
+/**
+ * tracing_log_err - write an error to the tracing error log
+ * @tr: The associated trace array for the error (NULL for top level array)
+ * @loc: A string describing where the error occurred
+ * @cmd: The tracing command that caused the error
+ * @errs: The array of loc-specific static error strings
+ * @type: The index into errs[], which produces the specific static err string
+ * @pos: The position the caret should be placed in the cmd
+ *
+ * Writes an error into tracing/error_log of the form:
+ *
+ * <loc>: error: <text>
+ *   Command: <cmd>
+ *              ^
+ *
+ * tracing/error_log is a small log file containing the last
+ * TRACING_LOG_ERRS_MAX errors (8).  Memory for errors isn't allocated
+ * unless there has been a tracing error, and the error log can be
+ * cleared and have its memory freed by writing the empty string in
+ * truncation mode to it i.e. echo > tracing/error_log.
+ *
+ * NOTE: the @errs array along with the @type param are used to
+ * produce a static error string - this string is not copied and saved
+ * when the error is logged - only a pointer to it is saved.  See
+ * existing callers for examples of how static strings are typically
+ * defined for use with tracing_log_err().
+ */
+void tracing_log_err(struct trace_array *tr,
+                    const char *loc, const char *cmd,
+                    const char **errs, u8 type, u8 pos)
+{
+       struct tracing_log_err *err;
+
+       if (!tr)
+               tr = &global_trace;
+
+       mutex_lock(&tracing_err_log_lock);
+       err = get_tracing_log_err(tr);
+       if (PTR_ERR(err) == -ENOMEM) {
+               mutex_unlock(&tracing_err_log_lock);
+               return;
+       }
+
+       snprintf(err->loc, TRACING_LOG_LOC_MAX, "%s: error: ", loc);
+       snprintf(err->cmd, MAX_FILTER_STR_VAL,"\n" CMD_PREFIX "%s\n", cmd);
+
+       err->info.errs = errs;
+       err->info.type = type;
+       err->info.pos = pos;
+       err->info.ts = local_clock();
+
+       list_add_tail(&err->list, &tr->err_log);
+       mutex_unlock(&tracing_err_log_lock);
+}
+
+static void clear_tracing_err_log(struct trace_array *tr)
+{
+       struct tracing_log_err *err, *next;
+
+       mutex_lock(&tracing_err_log_lock);
+       list_for_each_entry_safe(err, next, &tr->err_log, list) {
+               list_del(&err->list);
+               kfree(err);
+       }
+
+       tr->n_err_log_entries = 0;
+       mutex_unlock(&tracing_err_log_lock);
+}
+
+static void *tracing_err_log_seq_start(struct seq_file *m, loff_t *pos)
+{
+       struct trace_array *tr = m->private;
+
+       mutex_lock(&tracing_err_log_lock);
+
+       return seq_list_start(&tr->err_log, *pos);
+}
+
+static void *tracing_err_log_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       struct trace_array *tr = m->private;
+
+       return seq_list_next(v, &tr->err_log, pos);
+}
+
+static void tracing_err_log_seq_stop(struct seq_file *m, void *v)
+{
+       mutex_unlock(&tracing_err_log_lock);
+}
+
+static void tracing_err_log_show_pos(struct seq_file *m, u8 pos)
+{
+       u8 i;
+
+       for (i = 0; i < sizeof(CMD_PREFIX) - 1; i++)
+               seq_putc(m, ' ');
+       for (i = 0; i < pos; i++)
+               seq_putc(m, ' ');
+       seq_puts(m, "^\n");
+}
+
+static int tracing_err_log_seq_show(struct seq_file *m, void *v)
+{
+       struct tracing_log_err *err = v;
+
+       if (err) {
+               const char *err_text = err->info.errs[err->info.type];
+               u64 sec = err->info.ts;
+               u32 nsec;
+
+               nsec = do_div(sec, NSEC_PER_SEC);
+               seq_printf(m, "[%5llu.%06u] %s%s", sec, nsec / 1000,
+                          err->loc, err_text);
+               seq_printf(m, "%s", err->cmd);
+               tracing_err_log_show_pos(m, err->info.pos);
+       }
+
+       return 0;
+}
+
+static const struct seq_operations tracing_err_log_seq_ops = {
+       .start  = tracing_err_log_seq_start,
+       .next   = tracing_err_log_seq_next,
+       .stop   = tracing_err_log_seq_stop,
+       .show   = tracing_err_log_seq_show
+};
+
+static int tracing_err_log_open(struct inode *inode, struct file *file)
+{
+       struct trace_array *tr = inode->i_private;
+       int ret = 0;
+
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
+
+       /* If this file was opened for write, then erase contents */
+       if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC))
+               clear_tracing_err_log(tr);
+
+       if (file->f_mode & FMODE_READ) {
+               ret = seq_open(file, &tracing_err_log_seq_ops);
+               if (!ret) {
+                       struct seq_file *m = file->private_data;
+                       m->private = tr;
+               } else {
+                       trace_array_put(tr);
+               }
+       }
+       return ret;
+}
+
+static ssize_t tracing_err_log_write(struct file *file,
+                                    const char __user *buffer,
+                                    size_t count, loff_t *ppos)
+{
+       return count;
+}
+
+static const struct file_operations tracing_err_log_fops = {
+       .open           = tracing_err_log_open,
+       .write          = tracing_err_log_write,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = tracing_release_generic_tr,
+};
+
 static int tracing_buffers_open(struct inode *inode, struct file *filp)
 {
        struct trace_array *tr = inode->i_private;
@@ -8033,7 +8299,7 @@ static void update_tracer_options(struct trace_array *tr)
        mutex_unlock(&trace_types_lock);
 }
 
-static int instance_mkdir(const char *name)
+struct trace_array *trace_array_create(const char *name)
 {
        struct trace_array *tr;
        int ret;
@@ -8072,6 +8338,7 @@ static int instance_mkdir(const char *name)
        INIT_LIST_HEAD(&tr->systems);
        INIT_LIST_HEAD(&tr->events);
        INIT_LIST_HEAD(&tr->hist_vars);
+       INIT_LIST_HEAD(&tr->err_log);
 
        if (allocate_trace_buffers(tr, trace_buf_size) < 0)
                goto out_free_tr;
@@ -8097,7 +8364,7 @@ static int instance_mkdir(const char *name)
        mutex_unlock(&trace_types_lock);
        mutex_unlock(&event_mutex);
 
-       return 0;
+       return tr;
 
  out_free_tr:
        free_trace_buffers(tr);
@@ -8109,33 +8376,21 @@ static int instance_mkdir(const char *name)
        mutex_unlock(&trace_types_lock);
        mutex_unlock(&event_mutex);
 
-       return ret;
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(trace_array_create);
 
+static int instance_mkdir(const char *name)
+{
+       return PTR_ERR_OR_ZERO(trace_array_create(name));
 }
 
-static int instance_rmdir(const char *name)
+static int __remove_instance(struct trace_array *tr)
 {
-       struct trace_array *tr;
-       int found = 0;
-       int ret;
        int i;
 
-       mutex_lock(&event_mutex);
-       mutex_lock(&trace_types_lock);
-
-       ret = -ENODEV;
-       list_for_each_entry(tr, &ftrace_trace_arrays, list) {
-               if (tr->name && strcmp(tr->name, name) == 0) {
-                       found = 1;
-                       break;
-               }
-       }
-       if (!found)
-               goto out_unlock;
-
-       ret = -EBUSY;
        if (tr->ref || (tr->current_trace && tr->current_trace->ref))
-               goto out_unlock;
+               return -EBUSY;
 
        list_del(&tr->list);
 
@@ -8161,10 +8416,46 @@ static int instance_rmdir(const char *name)
        free_cpumask_var(tr->tracing_cpumask);
        kfree(tr->name);
        kfree(tr);
+       tr = NULL;
 
-       ret = 0;
+       return 0;
+}
+
+int trace_array_destroy(struct trace_array *tr)
+{
+       int ret;
+
+       if (!tr)
+               return -EINVAL;
+
+       mutex_lock(&event_mutex);
+       mutex_lock(&trace_types_lock);
+
+       ret = __remove_instance(tr);
+
+       mutex_unlock(&trace_types_lock);
+       mutex_unlock(&event_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(trace_array_destroy);
+
+static int instance_rmdir(const char *name)
+{
+       struct trace_array *tr;
+       int ret;
+
+       mutex_lock(&event_mutex);
+       mutex_lock(&trace_types_lock);
+
+       ret = -ENODEV;
+       list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+               if (tr->name && strcmp(tr->name, name) == 0) {
+                       ret = __remove_instance(tr);
+                       break;
+               }
+       }
 
- out_unlock:
        mutex_unlock(&trace_types_lock);
        mutex_unlock(&event_mutex);
 
@@ -8254,6 +8545,9 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
                          tr, &snapshot_fops);
 #endif
 
+       trace_create_file("error_log", 0644, d_tracer,
+                         tr, &tracing_err_log_fops);
+
        for_each_tracing_cpu(cpu)
                tracing_init_tracefs_percpu(tr, cpu);
 
@@ -8839,6 +9133,7 @@ __init static int tracer_alloc_buffers(void)
        INIT_LIST_HEAD(&global_trace.systems);
        INIT_LIST_HEAD(&global_trace.events);
        INIT_LIST_HEAD(&global_trace.hist_vars);
+       INIT_LIST_HEAD(&global_trace.err_log);
        list_add(&global_trace.list, &ftrace_trace_arrays);
 
        apply_trace_boot_options();
index 639047b259d79b34c83ee47894cbc7ec9f40b608..1974ce818ddb921ce7a4723f3a97b7cbdf684937 100644 (file)
@@ -293,11 +293,13 @@ struct trace_array {
        int                     nr_topts;
        bool                    clear_trace;
        int                     buffer_percent;
+       unsigned int            n_err_log_entries;
        struct tracer           *current_trace;
        unsigned int            trace_flags;
        unsigned char           trace_flags_index[TRACE_FLAGS_MAX_SIZE];
        unsigned int            flags;
        raw_spinlock_t          start_lock;
+       struct list_head        err_log;
        struct dentry           *dir;
        struct dentry           *options;
        struct dentry           *percpu_dir;
@@ -719,6 +721,9 @@ void trace_init_global_iter(struct trace_iterator *iter);
 
 void tracing_iter_reset(struct trace_iterator *iter, int cpu);
 
+unsigned long trace_total_entries_cpu(struct trace_array *tr, int cpu);
+unsigned long trace_total_entries(struct trace_array *tr);
+
 void trace_function(struct trace_array *tr,
                    unsigned long ip,
                    unsigned long parent_ip,
@@ -1545,7 +1550,8 @@ extern int apply_subsystem_event_filter(struct trace_subsystem_dir *dir,
 extern void print_subsystem_event_filter(struct event_subsystem *system,
                                         struct trace_seq *s);
 extern int filter_assign_type(const char *type);
-extern int create_event_filter(struct trace_event_call *call,
+extern int create_event_filter(struct trace_array *tr,
+                              struct trace_event_call *call,
                               char *filter_str, bool set_str,
                               struct event_filter **filterp);
 extern void free_event_filter(struct event_filter *filter);
@@ -1876,6 +1882,11 @@ extern ssize_t trace_parse_run_command(struct file *file,
                const char __user *buffer, size_t count, loff_t *ppos,
                int (*createfn)(int, char**));
 
+extern unsigned int err_pos(char *cmd, const char *str);
+extern void tracing_log_err(struct trace_array *tr,
+                           const char *loc, const char *cmd,
+                           const char **errs, u8 type, u8 pos);
+
 /*
  * Normal trace_printk() and friends allocates special buffers
  * to do the manipulation, as well as saves the print formats
index 5b3b0c3c8a47e581483818e270af391fd0ef1d57..0ce3db67f5569dda5550ce06f98a9cb0e62a96e5 100644 (file)
@@ -832,6 +832,7 @@ static int ftrace_set_clr_event(struct trace_array *tr, char *buf, int set)
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(ftrace_set_clr_event);
 
 /**
  * trace_set_clr_event - enable or disable an event
@@ -1318,9 +1319,6 @@ event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
        char buf[32];
        int len;
 
-       if (*ppos)
-               return 0;
-
        if (unlikely(!id))
                return -ENODEV;
 
index 05a66493a1640ff9f5ae0b72c409231d367104ec..d3e59312ef405072e941464d5f66a8ef79433750 100644 (file)
@@ -66,7 +66,8 @@ static const char * ops[] = { OPS };
        C(INVALID_FILTER,       "Meaningless filter expression"),       \
        C(IP_FIELD_ONLY,        "Only 'ip' field is supported for function trace"), \
        C(INVALID_VALUE,        "Invalid value (did you forget quotes)?"), \
-       C(NO_FILTER,            "No filter found"),
+       C(ERRNO,                "Error"),                               \
+       C(NO_FILTER,            "No filter found")
 
 #undef C
 #define C(a, b)                FILT_ERR_##a
@@ -76,7 +77,7 @@ enum { ERRORS };
 #undef C
 #define C(a, b)                b
 
-static char *err_text[] = { ERRORS };
+static const char *err_text[] = { ERRORS };
 
 /* Called after a '!' character but "!=" and "!~" are not "not"s */
 static bool is_not(const char *str)
@@ -919,7 +920,8 @@ static void remove_filter_string(struct event_filter *filter)
        filter->filter_string = NULL;
 }
 
-static void append_filter_err(struct filter_parse_error *pe,
+static void append_filter_err(struct trace_array *tr,
+                             struct filter_parse_error *pe,
                              struct event_filter *filter)
 {
        struct trace_seq *s;
@@ -947,8 +949,14 @@ static void append_filter_err(struct filter_parse_error *pe,
        if (pe->lasterr > 0) {
                trace_seq_printf(s, "\n%*s", pos, "^");
                trace_seq_printf(s, "\nparse_error: %s\n", err_text[pe->lasterr]);
+               tracing_log_err(tr, "event filter parse error",
+                               filter->filter_string, err_text,
+                               pe->lasterr, pe->lasterr_pos);
        } else {
                trace_seq_printf(s, "\nError: (%d)\n", pe->lasterr);
+               tracing_log_err(tr, "event filter parse error",
+                               filter->filter_string, err_text,
+                               FILT_ERR_ERRNO, 0);
        }
        trace_seq_putc(s, 0);
        buf = kmemdup_nul(s->buffer, s->seq.len, GFP_KERNEL);
@@ -1214,30 +1222,30 @@ static int parse_pred(const char *str, void *data,
                 * (perf doesn't use it) and grab everything.
                 */
                if (strcmp(field->name, "ip") != 0) {
-                        parse_error(pe, FILT_ERR_IP_FIELD_ONLY, pos + i);
-                        goto err_free;
-                }
-                pred->fn = filter_pred_none;
-
-                /*
-                 * Quotes are not required, but if they exist then we need
-                 * to read them till we hit a matching one.
-                 */
-                if (str[i] == '\'' || str[i] == '"')
-                        q = str[i];
-                else
-                        q = 0;
-
-                for (i++; str[i]; i++) {
-                        if (q && str[i] == q)
-                                break;
-                        if (!q && (str[i] == ')' || str[i] == '&' ||
-                                   str[i] == '|'))
-                                break;
-                }
-                /* Skip quotes */
-                if (q)
-                        s++;
+                       parse_error(pe, FILT_ERR_IP_FIELD_ONLY, pos + i);
+                       goto err_free;
+               }
+               pred->fn = filter_pred_none;
+
+               /*
+                * Quotes are not required, but if they exist then we need
+                * to read them till we hit a matching one.
+                */
+               if (str[i] == '\'' || str[i] == '"')
+                       q = str[i];
+               else
+                       q = 0;
+
+               for (i++; str[i]; i++) {
+                       if (q && str[i] == q)
+                               break;
+                       if (!q && (str[i] == ')' || str[i] == '&' ||
+                                  str[i] == '|'))
+                               break;
+               }
+               /* Skip quotes */
+               if (q)
+                       s++;
                len = i - s;
                if (len >= MAX_FILTER_STR_VAL) {
                        parse_error(pe, FILT_ERR_OPERAND_TOO_LONG, pos + i);
@@ -1600,7 +1608,7 @@ static int process_system_preds(struct trace_subsystem_dir *dir,
                if (err) {
                        filter_disable(file);
                        parse_error(pe, FILT_ERR_BAD_SUBSYS_FILTER, 0);
-                       append_filter_err(pe, filter);
+                       append_filter_err(tr, pe, filter);
                } else
                        event_set_filtered_flag(file);
 
@@ -1712,7 +1720,8 @@ static void create_filter_finish(struct filter_parse_error *pe)
  * information if @set_str is %true and the caller is responsible for
  * freeing it.
  */
-static int create_filter(struct trace_event_call *call,
+static int create_filter(struct trace_array *tr,
+                        struct trace_event_call *call,
                         char *filter_string, bool set_str,
                         struct event_filter **filterp)
 {
@@ -1729,17 +1738,18 @@ static int create_filter(struct trace_event_call *call,
 
        err = process_preds(call, filter_string, *filterp, pe);
        if (err && set_str)
-               append_filter_err(pe, *filterp);
+               append_filter_err(tr, pe, *filterp);
        create_filter_finish(pe);
 
        return err;
 }
 
-int create_event_filter(struct trace_event_call *call,
+int create_event_filter(struct trace_array *tr,
+                       struct trace_event_call *call,
                        char *filter_str, bool set_str,
                        struct event_filter **filterp)
 {
-       return create_filter(call, filter_str, set_str, filterp);
+       return create_filter(tr, call, filter_str, set_str, filterp);
 }
 
 /**
@@ -1766,7 +1776,7 @@ static int create_system_filter(struct trace_subsystem_dir *dir,
                        kfree((*filterp)->filter_string);
                        (*filterp)->filter_string = NULL;
                } else {
-                       append_filter_err(pe, *filterp);
+                       append_filter_err(tr, pe, *filterp);
                }
        }
        create_filter_finish(pe);
@@ -1797,7 +1807,7 @@ int apply_event_filter(struct trace_event_file *file, char *filter_string)
                return 0;
        }
 
-       err = create_filter(call, filter_string, true, &filter);
+       err = create_filter(file->tr, call, filter_string, true, &filter);
 
        /*
         * Always swap the call filter with the new filter
@@ -2053,7 +2063,7 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
        if (event->filter)
                goto out_unlock;
 
-       err = create_filter(call, filter_str, false, &filter);
+       err = create_filter(NULL, call, filter_str, false, &filter);
        if (err)
                goto free_filter;
 
@@ -2202,8 +2212,8 @@ static __init int ftrace_test_event_filter(void)
                struct test_filter_data_t *d = &test_filter_data[i];
                int err;
 
-               err = create_filter(&event_ftrace_test_filter, d->filter,
-                                   false, &filter);
+               err = create_filter(NULL, &event_ftrace_test_filter,
+                                   d->filter, false, &filter);
                if (err) {
                        printk(KERN_INFO
                               "Failed to get filter for '%s', err %d\n",
index a1d20421f4b033e037c6497ca00c22c2a1904d4a..7fca3457c7059dd15b71d84f801d01b12fcdff35 100644 (file)
 
 #define STR_VAR_LEN_MAX                32 /* must be multiple of sizeof(u64) */
 
+#define ERRORS                                                         \
+       C(NONE,                 "No error"),                            \
+       C(DUPLICATE_VAR,        "Variable already defined"),            \
+       C(VAR_NOT_UNIQUE,       "Variable name not unique, need to use fully qualified name (subsys.event.var) for variable"), \
+       C(TOO_MANY_VARS,        "Too many variables defined"),          \
+       C(MALFORMED_ASSIGNMENT, "Malformed assignment"),                \
+       C(NAMED_MISMATCH,       "Named hist trigger doesn't match existing named trigger (includes variables)"), \
+       C(TRIGGER_EEXIST,       "Hist trigger already exists"),         \
+       C(TRIGGER_ENOENT_CLEAR, "Can't clear or continue a nonexistent hist trigger"), \
+       C(SET_CLOCK_FAIL,       "Couldn't set trace_clock"),            \
+       C(BAD_FIELD_MODIFIER,   "Invalid field modifier"),              \
+       C(TOO_MANY_SUBEXPR,     "Too many subexpressions (3 max)"),     \
+       C(TIMESTAMP_MISMATCH,   "Timestamp units in expression don't match"), \
+       C(TOO_MANY_FIELD_VARS,  "Too many field variables defined"),    \
+       C(EVENT_FILE_NOT_FOUND, "Event file not found"),                \
+       C(HIST_NOT_FOUND,       "Matching event histogram not found"),  \
+       C(HIST_CREATE_FAIL,     "Couldn't create histogram for field"), \
+       C(SYNTH_VAR_NOT_FOUND,  "Couldn't find synthetic variable"),    \
+       C(SYNTH_EVENT_NOT_FOUND,"Couldn't find synthetic event"),       \
+       C(SYNTH_TYPE_MISMATCH,  "Param type doesn't match synthetic event field type"), \
+       C(SYNTH_COUNT_MISMATCH, "Param count doesn't match synthetic event field count"), \
+       C(FIELD_VAR_PARSE_FAIL, "Couldn't parse field variable"),       \
+       C(VAR_CREATE_FIND_FAIL, "Couldn't create or find variable"),    \
+       C(ONX_NOT_VAR,          "For onmax(x) or onchange(x), x must be a variable"), \
+       C(ONX_VAR_NOT_FOUND,    "Couldn't find onmax or onchange variable"), \
+       C(ONX_VAR_CREATE_FAIL,  "Couldn't create onmax or onchange variable"), \
+       C(FIELD_VAR_CREATE_FAIL,"Couldn't create field variable"),      \
+       C(TOO_MANY_PARAMS,      "Too many action params"),              \
+       C(PARAM_NOT_FOUND,      "Couldn't find param"),                 \
+       C(INVALID_PARAM,        "Invalid action param"),                \
+       C(ACTION_NOT_FOUND,     "No action found"),                     \
+       C(NO_SAVE_PARAMS,       "No params found for save()"),          \
+       C(TOO_MANY_SAVE_ACTIONS,"Can't have more than one save() action per hist"), \
+       C(ACTION_MISMATCH,      "Handler doesn't support action"),      \
+       C(NO_CLOSING_PAREN,     "No closing paren found"),              \
+       C(SUBSYS_NOT_FOUND,     "Missing subsystem"),                   \
+       C(INVALID_SUBSYS_EVENT, "Invalid subsystem or event name"),     \
+       C(INVALID_REF_KEY,      "Using variable references as keys not supported"), \
+       C(VAR_NOT_FOUND,        "Couldn't find variable"),              \
+       C(FIELD_NOT_FOUND,      "Couldn't find field"),
+
+#undef C
+#define C(a, b)                HIST_ERR_##a
+
+enum { ERRORS };
+
+#undef C
+#define C(a, b)                b
+
+static const char *err_text[] = { ERRORS };
+
 struct hist_field;
 
 typedef u64 (*hist_field_fn_t) (struct hist_field *field,
@@ -535,62 +586,49 @@ static struct track_data *track_data_alloc(unsigned int key_len,
        return data;
 }
 
-static char last_hist_cmd[MAX_FILTER_STR_VAL];
-static char hist_err_str[MAX_FILTER_STR_VAL];
+static char last_cmd[MAX_FILTER_STR_VAL];
+static char last_cmd_loc[MAX_FILTER_STR_VAL];
 
-static void last_cmd_set(char *str)
+static int errpos(char *str)
 {
-       if (!str)
-               return;
-
-       strncpy(last_hist_cmd, str, MAX_FILTER_STR_VAL - 1);
+       return err_pos(last_cmd, str);
 }
 
-static void hist_err(char *str, char *var)
+static void last_cmd_set(struct trace_event_file *file, char *str)
 {
-       int maxlen = MAX_FILTER_STR_VAL - 1;
+       const char *system = NULL, *name = NULL;
+       struct trace_event_call *call;
 
        if (!str)
                return;
 
-       if (strlen(hist_err_str))
-               return;
+       strncpy(last_cmd, str, MAX_FILTER_STR_VAL - 1);
 
-       if (!var)
-               var = "";
+       if (file) {
+               call = file->event_call;
 
-       if (strlen(hist_err_str) + strlen(str) + strlen(var) > maxlen)
-               return;
+               system = call->class->system;
+               if (system) {
+                       name = trace_event_name(call);
+                       if (!name)
+                               system = NULL;
+               }
+       }
 
-       strcat(hist_err_str, str);
-       strcat(hist_err_str, var);
+       if (system)
+               snprintf(last_cmd_loc, MAX_FILTER_STR_VAL, "hist:%s:%s", system, name);
 }
 
-static void hist_err_event(char *str, char *system, char *event, char *var)
+static void hist_err(struct trace_array *tr, u8 err_type, u8 err_pos)
 {
-       char err[MAX_FILTER_STR_VAL];
-
-       if (system && var)
-               snprintf(err, MAX_FILTER_STR_VAL, "%s.%s.%s", system, event, var);
-       else if (system)
-               snprintf(err, MAX_FILTER_STR_VAL, "%s.%s", system, event);
-       else
-               strscpy(err, var, MAX_FILTER_STR_VAL);
-
-       hist_err(str, err);
+       tracing_log_err(tr, last_cmd_loc, last_cmd, err_text,
+                       err_type, err_pos);
 }
 
 static void hist_err_clear(void)
 {
-       hist_err_str[0] = '\0';
-}
-
-static bool have_hist_err(void)
-{
-       if (strlen(hist_err_str))
-               return true;
-
-       return false;
+       last_cmd[0] = '\0';
+       last_cmd_loc[0] = '\0';
 }
 
 struct synth_trace_event {
@@ -1719,7 +1757,7 @@ static struct trace_event_file *find_var_file(struct trace_array *tr,
 
                if (find_var_field(var_hist_data, var_name)) {
                        if (found) {
-                               hist_err_event("Variable name not unique, need to use fully qualified name (subsys.event.var) for variable: ", system, event_name, var_name);
+                               hist_err(tr, HIST_ERR_VAR_NOT_UNIQUE, errpos(var_name));
                                return NULL;
                        }
 
@@ -1770,7 +1808,8 @@ find_match_var(struct hist_trigger_data *hist_data, char *var_name)
                        hist_field = find_file_var(file, var_name);
                        if (hist_field) {
                                if (found) {
-                                       hist_err_event("Variable name not unique, need to use fully qualified name (subsys.event.var) for variable: ", system, event_name, var_name);
+                                       hist_err(tr, HIST_ERR_VAR_NOT_UNIQUE,
+                                                errpos(var_name));
                                        return ERR_PTR(-EINVAL);
                                }
 
@@ -2002,11 +2041,11 @@ static int parse_action(char *str, struct hist_trigger_attrs *attrs)
                attrs->n_actions++;
                ret = 0;
        }
-
        return ret;
 }
 
-static int parse_assignment(char *str, struct hist_trigger_attrs *attrs)
+static int parse_assignment(struct trace_array *tr,
+                           char *str, struct hist_trigger_attrs *attrs)
 {
        int ret = 0;
 
@@ -2062,7 +2101,7 @@ static int parse_assignment(char *str, struct hist_trigger_attrs *attrs)
                char *assignment;
 
                if (attrs->n_assignments == TRACING_MAP_VARS_MAX) {
-                       hist_err("Too many variables defined: ", str);
+                       hist_err(tr, HIST_ERR_TOO_MANY_VARS, errpos(str));
                        ret = -EINVAL;
                        goto out;
                }
@@ -2079,7 +2118,8 @@ static int parse_assignment(char *str, struct hist_trigger_attrs *attrs)
        return ret;
 }
 
-static struct hist_trigger_attrs *parse_hist_trigger_attrs(char *trigger_str)
+static struct hist_trigger_attrs *
+parse_hist_trigger_attrs(struct trace_array *tr, char *trigger_str)
 {
        struct hist_trigger_attrs *attrs;
        int ret = 0;
@@ -2092,7 +2132,7 @@ static struct hist_trigger_attrs *parse_hist_trigger_attrs(char *trigger_str)
                char *str = strsep(&trigger_str, ":");
 
                if (strchr(str, '=')) {
-                       ret = parse_assignment(str, attrs);
+                       ret = parse_assignment(tr, str, attrs);
                        if (ret)
                                goto free;
                } else if (strcmp(str, "pause") == 0)
@@ -2648,6 +2688,7 @@ static struct hist_field *parse_var_ref(struct hist_trigger_data *hist_data,
                                        char *var_name)
 {
        struct hist_field *var_field = NULL, *ref_field = NULL;
+       struct trace_array *tr = hist_data->event_file->tr;
 
        if (!is_var_ref(var_name))
                return NULL;
@@ -2660,8 +2701,7 @@ static struct hist_field *parse_var_ref(struct hist_trigger_data *hist_data,
                                           system, event_name);
 
        if (!ref_field)
-               hist_err_event("Couldn't find variable: $",
-                              system, event_name, var_name);
+               hist_err(tr, HIST_ERR_VAR_NOT_FOUND, errpos(var_name));
 
        return ref_field;
 }
@@ -2672,6 +2712,7 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
 {
        struct ftrace_event_field *field = NULL;
        char *field_name, *modifier, *str;
+       struct trace_array *tr = file->tr;
 
        modifier = str = kstrdup(field_str, GFP_KERNEL);
        if (!modifier)
@@ -2695,7 +2736,7 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
                else if (strcmp(modifier, "usecs") == 0)
                        *flags |= HIST_FIELD_FL_TIMESTAMP_USECS;
                else {
-                       hist_err("Invalid field modifier: ", modifier);
+                       hist_err(tr, HIST_ERR_BAD_FIELD_MODIFIER, errpos(modifier));
                        field = ERR_PTR(-EINVAL);
                        goto out;
                }
@@ -2711,7 +2752,7 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
        else {
                field = trace_find_event_field(file->event_call, field_name);
                if (!field || !field->size) {
-                       hist_err("Couldn't find field: ", field_name);
+                       hist_err(tr, HIST_ERR_FIELD_NOT_FOUND, errpos(field_name));
                        field = ERR_PTR(-EINVAL);
                        goto out;
                }
@@ -2773,7 +2814,8 @@ static struct hist_field *parse_atom(struct hist_trigger_data *hist_data,
 
        s = local_field_var_ref(hist_data, ref_system, ref_event, ref_var);
        if (!s) {
-               hist_field = parse_var_ref(hist_data, ref_system, ref_event, ref_var);
+               hist_field = parse_var_ref(hist_data, ref_system,
+                                          ref_event, ref_var);
                if (hist_field) {
                        if (var_name) {
                                hist_field = create_alias(hist_data, hist_field, var_name);
@@ -2822,7 +2864,7 @@ static struct hist_field *parse_unary(struct hist_trigger_data *hist_data,
        /* we support only -(xxx) i.e. explicit parens required */
 
        if (level > 3) {
-               hist_err("Too many subexpressions (3 max): ", str);
+               hist_err(file->tr, HIST_ERR_TOO_MANY_SUBEXPR, errpos(str));
                ret = -EINVAL;
                goto free;
        }
@@ -2877,7 +2919,8 @@ static struct hist_field *parse_unary(struct hist_trigger_data *hist_data,
        return ERR_PTR(ret);
 }
 
-static int check_expr_operands(struct hist_field *operand1,
+static int check_expr_operands(struct trace_array *tr,
+                              struct hist_field *operand1,
                               struct hist_field *operand2)
 {
        unsigned long operand1_flags = operand1->flags;
@@ -2905,7 +2948,7 @@ static int check_expr_operands(struct hist_field *operand1,
 
        if ((operand1_flags & HIST_FIELD_FL_TIMESTAMP_USECS) !=
            (operand2_flags & HIST_FIELD_FL_TIMESTAMP_USECS)) {
-               hist_err("Timestamp units in expression don't match", NULL);
+               hist_err(tr, HIST_ERR_TIMESTAMP_MISMATCH, 0);
                return -EINVAL;
        }
 
@@ -2923,7 +2966,7 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
        char *sep, *operand1_str;
 
        if (level > 3) {
-               hist_err("Too many subexpressions (3 max): ", str);
+               hist_err(file->tr, HIST_ERR_TOO_MANY_SUBEXPR, errpos(str));
                return ERR_PTR(-EINVAL);
        }
 
@@ -2968,7 +3011,7 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
                goto free;
        }
 
-       ret = check_expr_operands(operand1, operand2);
+       ret = check_expr_operands(file->tr, operand1, operand2);
        if (ret)
                goto free;
 
@@ -3161,16 +3204,14 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,
        int ret;
 
        if (target_hist_data->n_field_var_hists >= SYNTH_FIELDS_MAX) {
-               hist_err_event("trace action: Too many field variables defined: ",
-                              subsys_name, event_name, field_name);
+               hist_err(tr, HIST_ERR_TOO_MANY_FIELD_VARS, errpos(field_name));
                return ERR_PTR(-EINVAL);
        }
 
        file = event_file(tr, subsys_name, event_name);
 
        if (IS_ERR(file)) {
-               hist_err_event("trace action: Event file not found: ",
-                              subsys_name, event_name, field_name);
+               hist_err(tr, HIST_ERR_EVENT_FILE_NOT_FOUND, errpos(field_name));
                ret = PTR_ERR(file);
                return ERR_PTR(ret);
        }
@@ -3183,8 +3224,7 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,
         */
        hist_data = find_compatible_hist(target_hist_data, file);
        if (!hist_data) {
-               hist_err_event("trace action: Matching event histogram not found: ",
-                              subsys_name, event_name, field_name);
+               hist_err(tr, HIST_ERR_HIST_NOT_FOUND, errpos(field_name));
                return ERR_PTR(-EINVAL);
        }
 
@@ -3245,8 +3285,7 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,
                kfree(cmd);
                kfree(var_hist->cmd);
                kfree(var_hist);
-               hist_err_event("trace action: Couldn't create histogram for field: ",
-                              subsys_name, event_name, field_name);
+               hist_err(tr, HIST_ERR_HIST_CREATE_FAIL, errpos(field_name));
                return ERR_PTR(ret);
        }
 
@@ -3258,8 +3297,7 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,
        if (IS_ERR_OR_NULL(event_var)) {
                kfree(var_hist->cmd);
                kfree(var_hist);
-               hist_err_event("trace action: Couldn't find synthetic variable: ",
-                              subsys_name, event_name, field_name);
+               hist_err(tr, HIST_ERR_SYNTH_VAR_NOT_FOUND, errpos(field_name));
                return ERR_PTR(-EINVAL);
        }
 
@@ -3392,25 +3430,26 @@ static struct field_var *create_field_var(struct hist_trigger_data *hist_data,
 {
        struct hist_field *val = NULL, *var = NULL;
        unsigned long flags = HIST_FIELD_FL_VAR;
+       struct trace_array *tr = file->tr;
        struct field_var *field_var;
        int ret = 0;
 
        if (hist_data->n_field_vars >= SYNTH_FIELDS_MAX) {
-               hist_err("Too many field variables defined: ", field_name);
+               hist_err(tr, HIST_ERR_TOO_MANY_FIELD_VARS, errpos(field_name));
                ret = -EINVAL;
                goto err;
        }
 
        val = parse_atom(hist_data, file, field_name, &flags, NULL);
        if (IS_ERR(val)) {
-               hist_err("Couldn't parse field variable: ", field_name);
+               hist_err(tr, HIST_ERR_FIELD_VAR_PARSE_FAIL, errpos(field_name));
                ret = PTR_ERR(val);
                goto err;
        }
 
        var = create_var(hist_data, file, field_name, val->size, val->type);
        if (IS_ERR(var)) {
-               hist_err("Couldn't create or find variable: ", field_name);
+               hist_err(tr, HIST_ERR_VAR_CREATE_FIND_FAIL, errpos(field_name));
                kfree(val);
                ret = PTR_ERR(var);
                goto err;
@@ -3737,19 +3776,20 @@ static int track_data_create(struct hist_trigger_data *hist_data,
 {
        struct hist_field *var_field, *ref_field, *track_var = NULL;
        struct trace_event_file *file = hist_data->event_file;
+       struct trace_array *tr = file->tr;
        char *track_data_var_str;
        int ret = 0;
 
        track_data_var_str = data->track_data.var_str;
        if (track_data_var_str[0] != '$') {
-               hist_err("For onmax(x) or onchange(x), x must be a variable: ", track_data_var_str);
+               hist_err(tr, HIST_ERR_ONX_NOT_VAR, errpos(track_data_var_str));
                return -EINVAL;
        }
        track_data_var_str++;
 
        var_field = find_target_event_var(hist_data, NULL, NULL, track_data_var_str);
        if (!var_field) {
-               hist_err("Couldn't find onmax or onchange variable: ", track_data_var_str);
+               hist_err(tr, HIST_ERR_ONX_VAR_NOT_FOUND, errpos(track_data_var_str));
                return -EINVAL;
        }
 
@@ -3762,7 +3802,7 @@ static int track_data_create(struct hist_trigger_data *hist_data,
        if (data->handler == HANDLER_ONMAX)
                track_var = create_var(hist_data, file, "__max", sizeof(u64), "u64");
        if (IS_ERR(track_var)) {
-               hist_err("Couldn't create onmax variable: ", "__max");
+               hist_err(tr, HIST_ERR_ONX_VAR_CREATE_FAIL, 0);
                ret = PTR_ERR(track_var);
                goto out;
        }
@@ -3770,7 +3810,7 @@ static int track_data_create(struct hist_trigger_data *hist_data,
        if (data->handler == HANDLER_ONCHANGE)
                track_var = create_var(hist_data, file, "__change", sizeof(u64), "u64");
        if (IS_ERR(track_var)) {
-               hist_err("Couldn't create onchange variable: ", "__change");
+               hist_err(tr, HIST_ERR_ONX_VAR_CREATE_FAIL, 0);
                ret = PTR_ERR(track_var);
                goto out;
        }
@@ -3781,7 +3821,8 @@ static int track_data_create(struct hist_trigger_data *hist_data,
        return ret;
 }
 
-static int parse_action_params(char *params, struct action_data *data)
+static int parse_action_params(struct trace_array *tr, char *params,
+                              struct action_data *data)
 {
        char *param, *saved_param;
        bool first_param = true;
@@ -3789,20 +3830,20 @@ static int parse_action_params(char *params, struct action_data *data)
 
        while (params) {
                if (data->n_params >= SYNTH_FIELDS_MAX) {
-                       hist_err("Too many action params", "");
+                       hist_err(tr, HIST_ERR_TOO_MANY_PARAMS, 0);
                        goto out;
                }
 
                param = strsep(&params, ",");
                if (!param) {
-                       hist_err("No action param found", "");
+                       hist_err(tr, HIST_ERR_PARAM_NOT_FOUND, 0);
                        ret = -EINVAL;
                        goto out;
                }
 
                param = strstrip(param);
                if (strlen(param) < 2) {
-                       hist_err("Invalid action param: ", param);
+                       hist_err(tr, HIST_ERR_INVALID_PARAM, errpos(param));
                        ret = -EINVAL;
                        goto out;
                }
@@ -3826,7 +3867,7 @@ static int parse_action_params(char *params, struct action_data *data)
        return ret;
 }
 
-static int action_parse(char *str, struct action_data *data,
+static int action_parse(struct trace_array *tr, char *str, struct action_data *data,
                        enum handler_id handler)
 {
        char *action_name;
@@ -3834,14 +3875,14 @@ static int action_parse(char *str, struct action_data *data,
 
        strsep(&str, ".");
        if (!str) {
-               hist_err("action parsing: No action found", "");
+               hist_err(tr, HIST_ERR_ACTION_NOT_FOUND, 0);
                ret = -EINVAL;
                goto out;
        }
 
        action_name = strsep(&str, "(");
        if (!action_name || !str) {
-               hist_err("action parsing: No action found", "");
+               hist_err(tr, HIST_ERR_ACTION_NOT_FOUND, 0);
                ret = -EINVAL;
                goto out;
        }
@@ -3850,12 +3891,12 @@ static int action_parse(char *str, struct action_data *data,
                char *params = strsep(&str, ")");
 
                if (!params) {
-                       hist_err("action parsing: No params found for %s", "save");
+                       hist_err(tr, HIST_ERR_NO_SAVE_PARAMS, 0);
                        ret = -EINVAL;
                        goto out;
                }
 
-               ret = parse_action_params(params, data);
+               ret = parse_action_params(tr, params, data);
                if (ret)
                        goto out;
 
@@ -3864,7 +3905,7 @@ static int action_parse(char *str, struct action_data *data,
                else if (handler == HANDLER_ONCHANGE)
                        data->track_data.check_val = check_track_val_changed;
                else {
-                       hist_err("action parsing: Handler doesn't support action: ", action_name);
+                       hist_err(tr, HIST_ERR_ACTION_MISMATCH, errpos(action_name));
                        ret = -EINVAL;
                        goto out;
                }
@@ -3876,7 +3917,7 @@ static int action_parse(char *str, struct action_data *data,
                char *params = strsep(&str, ")");
 
                if (!str) {
-                       hist_err("action parsing: No closing paren found: %s", params);
+                       hist_err(tr, HIST_ERR_NO_CLOSING_PAREN, errpos(params));
                        ret = -EINVAL;
                        goto out;
                }
@@ -3886,7 +3927,7 @@ static int action_parse(char *str, struct action_data *data,
                else if (handler == HANDLER_ONCHANGE)
                        data->track_data.check_val = check_track_val_changed;
                else {
-                       hist_err("action parsing: Handler doesn't support action: ", action_name);
+                       hist_err(tr, HIST_ERR_ACTION_MISMATCH, errpos(action_name));
                        ret = -EINVAL;
                        goto out;
                }
@@ -3901,7 +3942,7 @@ static int action_parse(char *str, struct action_data *data,
                        data->use_trace_keyword = true;
 
                if (params) {
-                       ret = parse_action_params(params, data);
+                       ret = parse_action_params(tr, params, data);
                        if (ret)
                                goto out;
                }
@@ -3954,7 +3995,7 @@ static struct action_data *track_data_parse(struct hist_trigger_data *hist_data,
                goto free;
        }
 
-       ret = action_parse(str, data, handler);
+       ret = action_parse(hist_data->event_file->tr, str, data, handler);
        if (ret)
                goto free;
  out:
@@ -4024,6 +4065,7 @@ trace_action_find_var(struct hist_trigger_data *hist_data,
                      struct action_data *data,
                      char *system, char *event, char *var)
 {
+       struct trace_array *tr = hist_data->event_file->tr;
        struct hist_field *hist_field;
 
        var++; /* skip '$' */
@@ -4039,7 +4081,7 @@ trace_action_find_var(struct hist_trigger_data *hist_data,
        }
 
        if (!hist_field)
-               hist_err_event("trace action: Couldn't find param: $", system, event, var);
+               hist_err(tr, HIST_ERR_PARAM_NOT_FOUND, errpos(var));
 
        return hist_field;
 }
@@ -4097,6 +4139,7 @@ trace_action_create_field_var(struct hist_trigger_data *hist_data,
 static int trace_action_create(struct hist_trigger_data *hist_data,
                               struct action_data *data)
 {
+       struct trace_array *tr = hist_data->event_file->tr;
        char *event_name, *param, *system = NULL;
        struct hist_field *hist_field, *var_ref;
        unsigned int i, var_ref_idx;
@@ -4114,7 +4157,7 @@ static int trace_action_create(struct hist_trigger_data *hist_data,
 
        event = find_synth_event(synth_event_name);
        if (!event) {
-               hist_err("trace action: Couldn't find synthetic event: ", synth_event_name);
+               hist_err(tr, HIST_ERR_SYNTH_EVENT_NOT_FOUND, errpos(synth_event_name));
                return -EINVAL;
        }
 
@@ -4175,15 +4218,14 @@ static int trace_action_create(struct hist_trigger_data *hist_data,
                        continue;
                }
 
-               hist_err_event("trace action: Param type doesn't match synthetic event field type: ",
-                              system, event_name, param);
+               hist_err(tr, HIST_ERR_SYNTH_TYPE_MISMATCH, errpos(param));
                kfree(p);
                ret = -EINVAL;
                goto err;
        }
 
        if (field_pos != event->n_fields) {
-               hist_err("trace action: Param count doesn't match synthetic event field count: ", event->name);
+               hist_err(tr, HIST_ERR_SYNTH_COUNT_MISMATCH, errpos(event->name));
                ret = -EINVAL;
                goto err;
        }
@@ -4202,6 +4244,7 @@ static int action_create(struct hist_trigger_data *hist_data,
                         struct action_data *data)
 {
        struct trace_event_file *file = hist_data->event_file;
+       struct trace_array *tr = file->tr;
        struct track_data *track_data;
        struct field_var *field_var;
        unsigned int i;
@@ -4229,7 +4272,7 @@ static int action_create(struct hist_trigger_data *hist_data,
        if (data->action == ACTION_SAVE) {
                if (hist_data->n_save_vars) {
                        ret = -EEXIST;
-                       hist_err("save action: Can't have more than one save() action per hist", "");
+                       hist_err(tr, HIST_ERR_TOO_MANY_SAVE_ACTIONS, 0);
                        goto out;
                }
 
@@ -4242,7 +4285,8 @@ static int action_create(struct hist_trigger_data *hist_data,
 
                        field_var = create_target_field_var(hist_data, NULL, NULL, param);
                        if (IS_ERR(field_var)) {
-                               hist_err("save action: Couldn't create field variable: ", param);
+                               hist_err(tr, HIST_ERR_FIELD_VAR_CREATE_FAIL,
+                                        errpos(param));
                                ret = PTR_ERR(field_var);
                                kfree(param);
                                goto out;
@@ -4276,19 +4320,18 @@ static struct action_data *onmatch_parse(struct trace_array *tr, char *str)
 
        match_event = strsep(&str, ")");
        if (!match_event || !str) {
-               hist_err("onmatch: Missing closing paren: ", match_event);
+               hist_err(tr, HIST_ERR_NO_CLOSING_PAREN, errpos(match_event));
                goto free;
        }
 
        match_event_system = strsep(&match_event, ".");
        if (!match_event) {
-               hist_err("onmatch: Missing subsystem for match event: ", match_event_system);
+               hist_err(tr, HIST_ERR_SUBSYS_NOT_FOUND, errpos(match_event_system));
                goto free;
        }
 
        if (IS_ERR(event_file(tr, match_event_system, match_event))) {
-               hist_err_event("onmatch: Invalid subsystem or event name: ",
-                              match_event_system, match_event, NULL);
+               hist_err(tr, HIST_ERR_INVALID_SUBSYS_EVENT, errpos(match_event));
                goto free;
        }
 
@@ -4304,7 +4347,7 @@ static struct action_data *onmatch_parse(struct trace_array *tr, char *str)
                goto free;
        }
 
-       ret = action_parse(str, data, HANDLER_ONMATCH);
+       ret = action_parse(tr, str, data, HANDLER_ONMATCH);
        if (ret)
                goto free;
  out:
@@ -4373,13 +4416,14 @@ static int create_var_field(struct hist_trigger_data *hist_data,
                            struct trace_event_file *file,
                            char *var_name, char *expr_str)
 {
+       struct trace_array *tr = hist_data->event_file->tr;
        unsigned long flags = 0;
 
        if (WARN_ON(val_idx >= TRACING_MAP_VALS_MAX + TRACING_MAP_VARS_MAX))
                return -EINVAL;
 
        if (find_var(hist_data, file, var_name) && !hist_data->remove) {
-               hist_err("Variable already defined: ", var_name);
+               hist_err(tr, HIST_ERR_DUPLICATE_VAR, errpos(var_name));
                return -EINVAL;
        }
 
@@ -4436,8 +4480,8 @@ static int create_key_field(struct hist_trigger_data *hist_data,
                            struct trace_event_file *file,
                            char *field_str)
 {
+       struct trace_array *tr = hist_data->event_file->tr;
        struct hist_field *hist_field = NULL;
-
        unsigned long flags = 0;
        unsigned int key_size;
        int ret = 0;
@@ -4460,7 +4504,7 @@ static int create_key_field(struct hist_trigger_data *hist_data,
                }
 
                if (hist_field->flags & HIST_FIELD_FL_VAR_REF) {
-                       hist_err("Using variable references as keys not supported: ", field_str);
+                       hist_err(tr, HIST_ERR_INVALID_REF_KEY, errpos(field_str));
                        destroy_hist_field(hist_field, 0);
                        ret = -EINVAL;
                        goto out;
@@ -4561,6 +4605,7 @@ static void free_var_defs(struct hist_trigger_data *hist_data)
 
 static int parse_var_defs(struct hist_trigger_data *hist_data)
 {
+       struct trace_array *tr = hist_data->event_file->tr;
        char *s, *str, *var_name, *field_str;
        unsigned int i, j, n_vars = 0;
        int ret = 0;
@@ -4574,13 +4619,14 @@ static int parse_var_defs(struct hist_trigger_data *hist_data)
 
                        var_name = strsep(&field_str, "=");
                        if (!var_name || !field_str) {
-                               hist_err("Malformed assignment: ", var_name);
+                               hist_err(tr, HIST_ERR_MALFORMED_ASSIGNMENT,
+                                        errpos(var_name));
                                ret = -EINVAL;
                                goto free;
                        }
 
                        if (n_vars == TRACING_MAP_VARS_MAX) {
-                               hist_err("Too many variables defined: ", var_name);
+                               hist_err(tr, HIST_ERR_TOO_MANY_VARS, errpos(var_name));
                                ret = -EINVAL;
                                goto free;
                        }
@@ -5431,11 +5477,6 @@ static int hist_show(struct seq_file *m, void *v)
                        hist_trigger_show(m, data, n++);
        }
 
-       if (have_hist_err()) {
-               seq_printf(m, "\nERROR: %s\n", hist_err_str);
-               seq_printf(m, "  Last command: %s\n", last_hist_cmd);
-       }
-
  out_unlock:
        mutex_unlock(&event_mutex);
 
@@ -5800,6 +5841,7 @@ static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
 {
        struct hist_trigger_data *hist_data = data->private_data;
        struct event_trigger_data *test, *named_data = NULL;
+       struct trace_array *tr = file->tr;
        int ret = 0;
 
        if (hist_data->attrs->name) {
@@ -5807,7 +5849,7 @@ static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
                if (named_data) {
                        if (!hist_trigger_match(data, named_data, named_data,
                                                true)) {
-                               hist_err("Named hist trigger doesn't match existing named trigger (includes variables): ", hist_data->attrs->name);
+                               hist_err(tr, HIST_ERR_NAMED_MISMATCH, errpos(hist_data->attrs->name));
                                ret = -EINVAL;
                                goto out;
                        }
@@ -5828,7 +5870,7 @@ static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
                        else if (hist_data->attrs->clear)
                                hist_clear(test);
                        else {
-                               hist_err("Hist trigger already exists", NULL);
+                               hist_err(tr, HIST_ERR_TRIGGER_EEXIST, 0);
                                ret = -EEXIST;
                        }
                        goto out;
@@ -5836,7 +5878,7 @@ static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
        }
  new:
        if (hist_data->attrs->cont || hist_data->attrs->clear) {
-               hist_err("Can't clear or continue a nonexistent hist trigger", NULL);
+               hist_err(tr, HIST_ERR_TRIGGER_ENOENT_CLEAR, 0);
                ret = -ENOENT;
                goto out;
        }
@@ -5861,7 +5903,7 @@ static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
 
                ret = tracing_set_clock(file->tr, hist_data->attrs->clock);
                if (ret) {
-                       hist_err("Couldn't set trace_clock: ", clock);
+                       hist_err(tr, HIST_ERR_SET_CLOCK_FAIL, errpos(clock));
                        goto out;
                }
 
@@ -6037,8 +6079,8 @@ static int event_hist_trigger_func(struct event_command *cmd_ops,
        lockdep_assert_held(&event_mutex);
 
        if (glob && strlen(glob)) {
-               last_cmd_set(param);
                hist_err_clear();
+               last_cmd_set(file, param);
        }
 
        if (!param)
@@ -6079,7 +6121,7 @@ static int event_hist_trigger_func(struct event_command *cmd_ops,
                trigger = strstrip(trigger);
        }
 
-       attrs = parse_hist_trigger_attrs(trigger);
+       attrs = parse_hist_trigger_attrs(file->tr, trigger);
        if (IS_ERR(attrs))
                return PTR_ERR(attrs);
 
index cd12ecb66eb9236e3ca741517ea55105d744ab6e..2a2912cb4533fef2ba7170c7f8ddbf25676bc40d 100644 (file)
@@ -731,7 +731,8 @@ int set_trigger_filter(char *filter_str,
                goto out;
 
        /* The filter is for the 'trigger' event, not the triggered event */
-       ret = create_event_filter(file->event_call, filter_str, false, &filter);
+       ret = create_event_filter(file->tr, file->event_call,
+                                 filter_str, false, &filter);
        /*
         * If create_event_filter() fails, filter still needs to be freed.
         * Which the calling code will do with data->filter.
index 810d78a8d14c76b02efa3dff91b63e52e4c66feb..6c1ae6b752d1997310dbc487808be4a01c749b40 100644 (file)
 #include "trace.h"
 #include "trace_output.h"
 
-static void ftrace_dump_buf(int skip_lines, long cpu_file)
+static struct trace_iterator iter;
+static struct ring_buffer_iter *buffer_iter[CONFIG_NR_CPUS];
+
+static void ftrace_dump_buf(int skip_entries, long cpu_file)
 {
-       /* use static because iter can be a bit big for the stack */
-       static struct trace_iterator iter;
-       static struct ring_buffer_iter *buffer_iter[CONFIG_NR_CPUS];
        struct trace_array *tr;
        unsigned int old_userobj;
        int cnt = 0, cpu;
 
-       trace_init_global_iter(&iter);
-       iter.buffer_iter = buffer_iter;
        tr = iter.tr;
 
-       for_each_tracing_cpu(cpu) {
-               atomic_inc(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
-       }
-
        old_userobj = tr->trace_flags;
 
        /* don't look at user memory in panic mode */
        tr->trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
 
        kdb_printf("Dumping ftrace buffer:\n");
+       if (skip_entries)
+               kdb_printf("(skipping %d entries)\n", skip_entries);
 
        /* reset all but tr, trace, and overruns */
        memset(&iter.seq, 0,
@@ -70,11 +66,11 @@ static void ftrace_dump_buf(int skip_lines, long cpu_file)
                        kdb_printf("---------------------------------\n");
                cnt++;
 
-               if (!skip_lines) {
+               if (!skip_entries) {
                        print_trace_line(&iter);
                        trace_printk_seq(&iter.seq);
                } else {
-                       skip_lines--;
+                       skip_entries--;
                }
 
                if (KDB_FLAG(CMD_INTERRUPT))
@@ -89,10 +85,6 @@ static void ftrace_dump_buf(int skip_lines, long cpu_file)
 out:
        tr->trace_flags = old_userobj;
 
-       for_each_tracing_cpu(cpu) {
-               atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
-       }
-
        for_each_tracing_cpu(cpu) {
                if (iter.buffer_iter[cpu]) {
                        ring_buffer_read_finish(iter.buffer_iter[cpu]);
@@ -106,17 +98,19 @@ out:
  */
 static int kdb_ftdump(int argc, const char **argv)
 {
-       int skip_lines = 0;
+       int skip_entries = 0;
        long cpu_file;
        char *cp;
+       int cnt;
+       int cpu;
 
        if (argc > 2)
                return KDB_ARGCOUNT;
 
        if (argc) {
-               skip_lines = simple_strtol(argv[1], &cp, 0);
+               skip_entries = simple_strtol(argv[1], &cp, 0);
                if (*cp)
-                       skip_lines = 0;
+                       skip_entries = 0;
        }
 
        if (argc == 2) {
@@ -129,7 +123,29 @@ static int kdb_ftdump(int argc, const char **argv)
        }
 
        kdb_trap_printk++;
-       ftrace_dump_buf(skip_lines, cpu_file);
+
+       trace_init_global_iter(&iter);
+       iter.buffer_iter = buffer_iter;
+
+       for_each_tracing_cpu(cpu) {
+               atomic_inc(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
+       }
+
+       /* A negative skip_entries means skip all but the last entries */
+       if (skip_entries < 0) {
+               if (cpu_file == RING_BUFFER_ALL_CPUS)
+                       cnt = trace_total_entries(NULL);
+               else
+                       cnt = trace_total_entries_cpu(NULL, cpu_file);
+               skip_entries = max(cnt + skip_entries, 0);
+       }
+
+       ftrace_dump_buf(skip_entries, cpu_file);
+
+       for_each_tracing_cpu(cpu) {
+               atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
+       }
+
        kdb_trap_printk--;
 
        return 0;
@@ -137,8 +153,9 @@ static int kdb_ftdump(int argc, const char **argv)
 
 static __init int kdb_ftrace_register(void)
 {
-       kdb_register_flags("ftdump", kdb_ftdump, "[skip_#lines] [cpu]",
-                           "Dump ftrace log", 0, KDB_ENABLE_ALWAYS_SAFE);
+       kdb_register_flags("ftdump", kdb_ftdump, "[skip_#entries] [cpu]",
+                           "Dump ftrace log; -skip dumps last #entries", 0,
+                           KDB_ENABLE_ALWAYS_SAFE);
        return 0;
 }
 
index 5d5129b05df782bff2bd5d04764324863d3c6f10..7d736248a070b2f633349856345e2013d4a3cd34 100644 (file)
@@ -441,13 +441,8 @@ static int __register_trace_kprobe(struct trace_kprobe *tk)
        else
                ret = register_kprobe(&tk->rp.kp);
 
-       if (ret == 0) {
+       if (ret == 0)
                tk->tp.flags |= TP_FLAG_REGISTERED;
-       } else if (ret == -EILSEQ) {
-               pr_warn("Probing address(0x%p) is not an instruction boundary.\n",
-                       tk->rp.kp.addr);
-               ret = -EINVAL;
-       }
        return ret;
 }
 
@@ -591,7 +586,7 @@ static int trace_kprobe_create(int argc, const char *argv[])
         * Type of args:
         *  FETCHARG:TYPE : use TYPE instead of unsigned long.
         */
-       struct trace_kprobe *tk;
+       struct trace_kprobe *tk = NULL;
        int i, len, ret = 0;
        bool is_return = false;
        char *symbol = NULL, *tmp = NULL;
@@ -615,44 +610,50 @@ static int trace_kprobe_create(int argc, const char *argv[])
        if (argc < 2)
                return -ECANCELED;
 
+       trace_probe_log_init("trace_kprobe", argc, argv);
+
        event = strchr(&argv[0][1], ':');
        if (event)
                event++;
 
        if (isdigit(argv[0][1])) {
                if (!is_return) {
-                       pr_info("Maxactive is not for kprobe");
-                       return -EINVAL;
+                       trace_probe_log_err(1, MAXACT_NO_KPROBE);
+                       goto parse_error;
                }
                if (event)
                        len = event - &argv[0][1] - 1;
                else
                        len = strlen(&argv[0][1]);
-               if (len > MAX_EVENT_NAME_LEN - 1)
-                       return -E2BIG;
+               if (len > MAX_EVENT_NAME_LEN - 1) {
+                       trace_probe_log_err(1, BAD_MAXACT);
+                       goto parse_error;
+               }
                memcpy(buf, &argv[0][1], len);
                buf[len] = '\0';
                ret = kstrtouint(buf, 0, &maxactive);
                if (ret || !maxactive) {
-                       pr_info("Invalid maxactive number\n");
-                       return ret;
+                       trace_probe_log_err(1, BAD_MAXACT);
+                       goto parse_error;
                }
                /* kretprobes instances are iterated over via a list. The
                 * maximum should stay reasonable.
                 */
                if (maxactive > KRETPROBE_MAXACTIVE_MAX) {
-                       pr_info("Maxactive is too big (%d > %d).\n",
-                               maxactive, KRETPROBE_MAXACTIVE_MAX);
-                       return -E2BIG;
+                       trace_probe_log_err(1, MAXACT_TOO_BIG);
+                       goto parse_error;
                }
        }
 
        /* try to parse an address. if that fails, try to read the
         * input as a symbol. */
        if (kstrtoul(argv[1], 0, (unsigned long *)&addr)) {
+               trace_probe_log_set_index(1);
                /* Check whether uprobe event specified */
-               if (strchr(argv[1], '/') && strchr(argv[1], ':'))
-                       return -ECANCELED;
+               if (strchr(argv[1], '/') && strchr(argv[1], ':')) {
+                       ret = -ECANCELED;
+                       goto error;
+               }
                /* a symbol specified */
                symbol = kstrdup(argv[1], GFP_KERNEL);
                if (!symbol)
@@ -660,23 +661,23 @@ static int trace_kprobe_create(int argc, const char *argv[])
                /* TODO: support .init module functions */
                ret = traceprobe_split_symbol_offset(symbol, &offset);
                if (ret || offset < 0 || offset > UINT_MAX) {
-                       pr_info("Failed to parse either an address or a symbol.\n");
-                       goto out;
+                       trace_probe_log_err(0, BAD_PROBE_ADDR);
+                       goto parse_error;
                }
                if (kprobe_on_func_entry(NULL, symbol, offset))
                        flags |= TPARG_FL_FENTRY;
                if (offset && is_return && !(flags & TPARG_FL_FENTRY)) {
-                       pr_info("Given offset is not valid for return probe.\n");
-                       ret = -EINVAL;
-                       goto out;
+                       trace_probe_log_err(0, BAD_RETPROBE);
+                       goto parse_error;
                }
        }
-       argc -= 2; argv += 2;
 
+       trace_probe_log_set_index(0);
        if (event) {
-               ret = traceprobe_parse_event_name(&event, &group, buf);
+               ret = traceprobe_parse_event_name(&event, &group, buf,
+                                                 event - argv[0]);
                if (ret)
-                       goto out;
+                       goto parse_error;
        } else {
                /* Make a new event name */
                if (symbol)
@@ -691,13 +692,14 @@ static int trace_kprobe_create(int argc, const char *argv[])
 
        /* setup a probe */
        tk = alloc_trace_kprobe(group, event, addr, symbol, offset, maxactive,
-                              argc, is_return);
+                              argc - 2, is_return);
        if (IS_ERR(tk)) {
                ret = PTR_ERR(tk);
-               /* This must return -ENOMEM otherwise there is a bug */
+               /* This must return -ENOMEM, else there is a bug */
                WARN_ON_ONCE(ret != -ENOMEM);
-               goto out;
+               goto out;       /* We know tk is not allocated */
        }
+       argc -= 2; argv += 2;
 
        /* parse arguments */
        for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
@@ -707,19 +709,32 @@ static int trace_kprobe_create(int argc, const char *argv[])
                        goto error;
                }
 
+               trace_probe_log_set_index(i + 2);
                ret = traceprobe_parse_probe_arg(&tk->tp, i, tmp, flags);
                kfree(tmp);
                if (ret)
-                       goto error;
+                       goto error;     /* This can be -ENOMEM */
        }
 
        ret = register_trace_kprobe(tk);
-       if (ret)
+       if (ret) {
+               trace_probe_log_set_index(1);
+               if (ret == -EILSEQ)
+                       trace_probe_log_err(0, BAD_INSN_BNDRY);
+               else if (ret == -ENOENT)
+                       trace_probe_log_err(0, BAD_PROBE_ADDR);
+               else if (ret != -ENOMEM)
+                       trace_probe_log_err(0, FAIL_REG_PROBE);
                goto error;
+       }
+
 out:
+       trace_probe_log_clear();
        kfree(symbol);
        return ret;
 
+parse_error:
+       ret = -EINVAL;
 error:
        free_trace_kprobe(tk);
        goto out;
index 8f8411e7835fdc0e138924c8ab5c35683894774e..a347faced9595092464744b9729c80145ea8e0c8 100644 (file)
 
 #include "trace_probe.h"
 
+#undef C
+#define C(a, b)                b
+
+static const char *trace_probe_err_text[] = { ERRORS };
+
 static const char *reserved_field_names[] = {
        "common_type",
        "common_flags",
@@ -133,6 +138,60 @@ fail:
        return NULL;
 }
 
+static struct trace_probe_log trace_probe_log;
+
+void trace_probe_log_init(const char *subsystem, int argc, const char **argv)
+{
+       trace_probe_log.subsystem = subsystem;
+       trace_probe_log.argc = argc;
+       trace_probe_log.argv = argv;
+       trace_probe_log.index = 0;
+}
+
+void trace_probe_log_clear(void)
+{
+       memset(&trace_probe_log, 0, sizeof(trace_probe_log));
+}
+
+void trace_probe_log_set_index(int index)
+{
+       trace_probe_log.index = index;
+}
+
+void __trace_probe_log_err(int offset, int err_type)
+{
+       char *command, *p;
+       int i, len = 0, pos = 0;
+
+       if (!trace_probe_log.argv)
+               return;
+
+       /* Recalcurate the length and allocate buffer */
+       for (i = 0; i < trace_probe_log.argc; i++) {
+               if (i == trace_probe_log.index)
+                       pos = len;
+               len += strlen(trace_probe_log.argv[i]) + 1;
+       }
+       command = kzalloc(len, GFP_KERNEL);
+       if (!command)
+               return;
+
+       /* And make a command string from argv array */
+       p = command;
+       for (i = 0; i < trace_probe_log.argc; i++) {
+               len = strlen(trace_probe_log.argv[i]);
+               strcpy(p, trace_probe_log.argv[i]);
+               p[len] = ' ';
+               p += len + 1;
+       }
+       *(p - 1) = '\0';
+
+       tracing_log_err(NULL, trace_probe_log.subsystem, command,
+                       trace_probe_err_text, err_type, pos + offset);
+
+       kfree(command);
+}
+
 /* Split symbol and offset. */
 int traceprobe_split_symbol_offset(char *symbol, long *offset)
 {
@@ -156,7 +215,7 @@ int traceprobe_split_symbol_offset(char *symbol, long *offset)
 
 /* @buf must has MAX_EVENT_NAME_LEN size */
 int traceprobe_parse_event_name(const char **pevent, const char **pgroup,
-                               char *buf)
+                               char *buf, int offset)
 {
        const char *slash, *event = *pevent;
        int len;
@@ -164,32 +223,33 @@ int traceprobe_parse_event_name(const char **pevent, const char **pgroup,
        slash = strchr(event, '/');
        if (slash) {
                if (slash == event) {
-                       pr_info("Group name is not specified\n");
+                       trace_probe_log_err(offset, NO_GROUP_NAME);
                        return -EINVAL;
                }
                if (slash - event + 1 > MAX_EVENT_NAME_LEN) {
-                       pr_info("Group name is too long\n");
-                       return -E2BIG;
+                       trace_probe_log_err(offset, GROUP_TOO_LONG);
+                       return -EINVAL;
                }
                strlcpy(buf, event, slash - event + 1);
                if (!is_good_name(buf)) {
-                       pr_info("Group name must follow the same rules as C identifiers\n");
+                       trace_probe_log_err(offset, BAD_GROUP_NAME);
                        return -EINVAL;
                }
                *pgroup = buf;
                *pevent = slash + 1;
+               offset += slash - event + 1;
                event = *pevent;
        }
        len = strlen(event);
        if (len == 0) {
-               pr_info("Event name is not specified\n");
+               trace_probe_log_err(offset, NO_EVENT_NAME);
                return -EINVAL;
        } else if (len > MAX_EVENT_NAME_LEN) {
-               pr_info("Event name is too long\n");
-               return -E2BIG;
+               trace_probe_log_err(offset, EVENT_TOO_LONG);
+               return -EINVAL;
        }
        if (!is_good_name(event)) {
-               pr_info("Event name must follow the same rules as C identifiers\n");
+               trace_probe_log_err(offset, BAD_EVENT_NAME);
                return -EINVAL;
        }
        return 0;
@@ -198,56 +258,67 @@ int traceprobe_parse_event_name(const char **pevent, const char **pgroup,
 #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
 
 static int parse_probe_vars(char *arg, const struct fetch_type *t,
-                           struct fetch_insn *code, unsigned int flags)
+                       struct fetch_insn *code, unsigned int flags, int offs)
 {
        unsigned long param;
        int ret = 0;
        int len;
 
        if (strcmp(arg, "retval") == 0) {
-               if (flags & TPARG_FL_RETURN)
+               if (flags & TPARG_FL_RETURN) {
                        code->op = FETCH_OP_RETVAL;
-               else
+               } else {
+                       trace_probe_log_err(offs, RETVAL_ON_PROBE);
                        ret = -EINVAL;
+               }
        } else if ((len = str_has_prefix(arg, "stack"))) {
                if (arg[len] == '\0') {
                        code->op = FETCH_OP_STACKP;
                } else if (isdigit(arg[len])) {
                        ret = kstrtoul(arg + len, 10, &param);
-                       if (ret || ((flags & TPARG_FL_KERNEL) &&
-                                   param > PARAM_MAX_STACK))
+                       if (ret) {
+                               goto inval_var;
+                       } else if ((flags & TPARG_FL_KERNEL) &&
+                                   param > PARAM_MAX_STACK) {
+                               trace_probe_log_err(offs, BAD_STACK_NUM);
                                ret = -EINVAL;
-                       else {
+                       else {
                                code->op = FETCH_OP_STACK;
                                code->param = (unsigned int)param;
                        }
                } else
-                       ret = -EINVAL;
+                       goto inval_var;
        } else if (strcmp(arg, "comm") == 0) {
                code->op = FETCH_OP_COMM;
 #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
        } else if (((flags & TPARG_FL_MASK) ==
                    (TPARG_FL_KERNEL | TPARG_FL_FENTRY)) &&
                   (len = str_has_prefix(arg, "arg"))) {
-               if (!isdigit(arg[len]))
-                       return -EINVAL;
                ret = kstrtoul(arg + len, 10, &param);
-               if (ret || !param || param > PARAM_MAX_STACK)
+               if (ret) {
+                       goto inval_var;
+               } else if (!param || param > PARAM_MAX_STACK) {
+                       trace_probe_log_err(offs, BAD_ARG_NUM);
                        return -EINVAL;
+               }
                code->op = FETCH_OP_ARG;
                code->param = (unsigned int)param - 1;
 #endif
        } else
-               ret = -EINVAL;
+               goto inval_var;
 
        return ret;
+
+inval_var:
+       trace_probe_log_err(offs, BAD_VAR);
+       return -EINVAL;
 }
 
 /* Recursive argument parser */
 static int
 parse_probe_arg(char *arg, const struct fetch_type *type,
                struct fetch_insn **pcode, struct fetch_insn *end,
-               unsigned int flags)
+               unsigned int flags, int offs)
 {
        struct fetch_insn *code = *pcode;
        unsigned long param;
@@ -257,7 +328,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 
        switch (arg[0]) {
        case '$':
-               ret = parse_probe_vars(arg + 1, type, code, flags);
+               ret = parse_probe_vars(arg + 1, type, code, flags, offs);
                break;
 
        case '%':       /* named register */
@@ -266,47 +337,57 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
                        code->op = FETCH_OP_REG;
                        code->param = (unsigned int)ret;
                        ret = 0;
-               }
+               } else
+                       trace_probe_log_err(offs, BAD_REG_NAME);
                break;
 
        case '@':       /* memory, file-offset or symbol */
                if (isdigit(arg[1])) {
                        ret = kstrtoul(arg + 1, 0, &param);
-                       if (ret)
+                       if (ret) {
+                               trace_probe_log_err(offs, BAD_MEM_ADDR);
                                break;
+                       }
                        /* load address */
                        code->op = FETCH_OP_IMM;
                        code->immediate = param;
                } else if (arg[1] == '+') {
                        /* kprobes don't support file offsets */
-                       if (flags & TPARG_FL_KERNEL)
+                       if (flags & TPARG_FL_KERNEL) {
+                               trace_probe_log_err(offs, FILE_ON_KPROBE);
                                return -EINVAL;
-
+                       }
                        ret = kstrtol(arg + 2, 0, &offset);
-                       if (ret)
+                       if (ret) {
+                               trace_probe_log_err(offs, BAD_FILE_OFFS);
                                break;
+                       }
 
                        code->op = FETCH_OP_FOFFS;
                        code->immediate = (unsigned long)offset;  // imm64?
                } else {
                        /* uprobes don't support symbols */
-                       if (!(flags & TPARG_FL_KERNEL))
+                       if (!(flags & TPARG_FL_KERNEL)) {
+                               trace_probe_log_err(offs, SYM_ON_UPROBE);
                                return -EINVAL;
-
+                       }
                        /* Preserve symbol for updating */
                        code->op = FETCH_NOP_SYMBOL;
                        code->data = kstrdup(arg + 1, GFP_KERNEL);
                        if (!code->data)
                                return -ENOMEM;
-                       if (++code == end)
-                               return -E2BIG;
-
+                       if (++code == end) {
+                               trace_probe_log_err(offs, TOO_MANY_OPS);
+                               return -EINVAL;
+                       }
                        code->op = FETCH_OP_IMM;
                        code->immediate = 0;
                }
                /* These are fetching from memory */
-               if (++code == end)
-                       return -E2BIG;
+               if (++code == end) {
+                       trace_probe_log_err(offs, TOO_MANY_OPS);
+                       return -EINVAL;
+               }
                *pcode = code;
                code->op = FETCH_OP_DEREF;
                code->offset = offset;
@@ -317,28 +398,38 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
                /* fall through */
        case '-':
                tmp = strchr(arg, '(');
-               if (!tmp)
+               if (!tmp) {
+                       trace_probe_log_err(offs, DEREF_NEED_BRACE);
                        return -EINVAL;
-
+               }
                *tmp = '\0';
                ret = kstrtol(arg, 0, &offset);
-               if (ret)
+               if (ret) {
+                       trace_probe_log_err(offs, BAD_DEREF_OFFS);
                        break;
-
+               }
+               offs += (tmp + 1 - arg) + (arg[0] != '-' ? 1 : 0);
                arg = tmp + 1;
                tmp = strrchr(arg, ')');
-
-               if (tmp) {
+               if (!tmp) {
+                       trace_probe_log_err(offs + strlen(arg),
+                                           DEREF_OPEN_BRACE);
+                       return -EINVAL;
+               } else {
                        const struct fetch_type *t2 = find_fetch_type(NULL);
 
                        *tmp = '\0';
-                       ret = parse_probe_arg(arg, t2, &code, end, flags);
+                       ret = parse_probe_arg(arg, t2, &code, end, flags, offs);
                        if (ret)
                                break;
-                       if (code->op == FETCH_OP_COMM)
+                       if (code->op == FETCH_OP_COMM) {
+                               trace_probe_log_err(offs, COMM_CANT_DEREF);
                                return -EINVAL;
-                       if (++code == end)
-                               return -E2BIG;
+                       }
+                       if (++code == end) {
+                               trace_probe_log_err(offs, TOO_MANY_OPS);
+                               return -EINVAL;
+                       }
                        *pcode = code;
 
                        code->op = FETCH_OP_DEREF;
@@ -348,6 +439,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
        }
        if (!ret && code->op == FETCH_OP_NOP) {
                /* Parsed, but do not find fetch method */
+               trace_probe_log_err(offs, BAD_FETCH_ARG);
                ret = -EINVAL;
        }
        return ret;
@@ -379,7 +471,7 @@ static int __parse_bitfield_probe_arg(const char *bf,
                return -EINVAL;
        code++;
        if (code->op != FETCH_OP_NOP)
-               return -E2BIG;
+               return -EINVAL;
        *pcode = code;
 
        code->op = FETCH_OP_MOD_BF;
@@ -392,44 +484,66 @@ static int __parse_bitfield_probe_arg(const char *bf,
 
 /* String length checking wrapper */
 static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
-               struct probe_arg *parg, unsigned int flags)
+               struct probe_arg *parg, unsigned int flags, int offset)
 {
        struct fetch_insn *code, *scode, *tmp = NULL;
-       char *t, *t2;
+       char *t, *t2, *t3;
        int ret, len;
 
-       if (strlen(arg) > MAX_ARGSTR_LEN) {
-               pr_info("Argument is too long.: %s\n",  arg);
-               return -ENOSPC;
+       len = strlen(arg);
+       if (len > MAX_ARGSTR_LEN) {
+               trace_probe_log_err(offset, ARG_TOO_LONG);
+               return -EINVAL;
+       } else if (len == 0) {
+               trace_probe_log_err(offset, NO_ARG_BODY);
+               return -EINVAL;
        }
+
        parg->comm = kstrdup(arg, GFP_KERNEL);
-       if (!parg->comm) {
-               pr_info("Failed to allocate memory for command '%s'.\n", arg);
+       if (!parg->comm)
                return -ENOMEM;
-       }
+
        t = strchr(arg, ':');
        if (t) {
                *t = '\0';
                t2 = strchr(++t, '[');
                if (t2) {
-                       *t2 = '\0';
-                       parg->count = simple_strtoul(t2 + 1, &t2, 0);
-                       if (strcmp(t2, "]") || parg->count == 0)
+                       *t2++ = '\0';
+                       t3 = strchr(t2, ']');
+                       if (!t3) {
+                               offset += t2 + strlen(t2) - arg;
+                               trace_probe_log_err(offset,
+                                                   ARRAY_NO_CLOSE);
+                               return -EINVAL;
+                       } else if (t3[1] != '\0') {
+                               trace_probe_log_err(offset + t3 + 1 - arg,
+                                                   BAD_ARRAY_SUFFIX);
                                return -EINVAL;
-                       if (parg->count > MAX_ARRAY_LEN)
-                               return -E2BIG;
+                       }
+                       *t3 = '\0';
+                       if (kstrtouint(t2, 0, &parg->count) || !parg->count) {
+                               trace_probe_log_err(offset + t2 - arg,
+                                                   BAD_ARRAY_NUM);
+                               return -EINVAL;
+                       }
+                       if (parg->count > MAX_ARRAY_LEN) {
+                               trace_probe_log_err(offset + t2 - arg,
+                                                   ARRAY_TOO_BIG);
+                               return -EINVAL;
+                       }
                }
        }
-       /*
-        * The default type of $comm should be "string", and it can't be
-        * dereferenced.
-        */
-       if (!t && strcmp(arg, "$comm") == 0)
+
+       /* Since $comm can not be dereferred, we can find $comm by strcmp */
+       if (strcmp(arg, "$comm") == 0) {
+               /* The type of $comm must be "string", and not an array. */
+               if (parg->count || (t && strcmp(t, "string")))
+                       return -EINVAL;
                parg->type = find_fetch_type("string");
-       else
+       else
                parg->type = find_fetch_type(t);
        if (!parg->type) {
-               pr_info("Unsupported type: %s\n", t);
+               trace_probe_log_err(offset + (t ? (t - arg) : 0), BAD_TYPE);
                return -EINVAL;
        }
        parg->offset = *size;
@@ -444,13 +558,13 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
                         parg->count);
        }
 
-       code = tmp = kzalloc(sizeof(*code) * FETCH_INSN_MAX, GFP_KERNEL);
+       code = tmp = kcalloc(FETCH_INSN_MAX, sizeof(*code), GFP_KERNEL);
        if (!code)
                return -ENOMEM;
        code[FETCH_INSN_MAX - 1].op = FETCH_OP_END;
 
        ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1],
-                             flags);
+                             flags, offset);
        if (ret)
                goto fail;
 
@@ -458,7 +572,8 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
        if (!strcmp(parg->type->name, "string")) {
                if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_IMM &&
                    code->op != FETCH_OP_COMM) {
-                       pr_info("string only accepts memory or address.\n");
+                       trace_probe_log_err(offset + (t ? (t - arg) : 0),
+                                           BAD_STRING);
                        ret = -EINVAL;
                        goto fail;
                }
@@ -470,7 +585,8 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
                         */
                        code++;
                        if (code->op != FETCH_OP_NOP) {
-                               ret = -E2BIG;
+                               trace_probe_log_err(offset, TOO_MANY_OPS);
+                               ret = -EINVAL;
                                goto fail;
                        }
                }
@@ -483,7 +599,8 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
        } else {
                code++;
                if (code->op != FETCH_OP_NOP) {
-                       ret = -E2BIG;
+                       trace_probe_log_err(offset, TOO_MANY_OPS);
+                       ret = -EINVAL;
                        goto fail;
                }
                code->op = FETCH_OP_ST_RAW;
@@ -493,20 +610,24 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
        /* Modify operation */
        if (t != NULL) {
                ret = __parse_bitfield_probe_arg(t, parg->type, &code);
-               if (ret)
+               if (ret) {
+                       trace_probe_log_err(offset + t - arg, BAD_BITFIELD);
                        goto fail;
+               }
        }
        /* Loop(Array) operation */
        if (parg->count) {
                if (scode->op != FETCH_OP_ST_MEM &&
                    scode->op != FETCH_OP_ST_STRING) {
-                       pr_info("array only accepts memory or address\n");
+                       trace_probe_log_err(offset + (t ? (t - arg) : 0),
+                                           BAD_STRING);
                        ret = -EINVAL;
                        goto fail;
                }
                code++;
                if (code->op != FETCH_OP_NOP) {
-                       ret = -E2BIG;
+                       trace_probe_log_err(offset, TOO_MANY_OPS);
+                       ret = -EINVAL;
                        goto fail;
                }
                code->op = FETCH_OP_LP_ARRAY;
@@ -516,7 +637,7 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
        code->op = FETCH_OP_END;
 
        /* Shrink down the code buffer */
-       parg->code = kzalloc(sizeof(*code) * (code - tmp + 1), GFP_KERNEL);
+       parg->code = kcalloc(code - tmp + 1, sizeof(*code), GFP_KERNEL);
        if (!parg->code)
                ret = -ENOMEM;
        else
@@ -555,15 +676,19 @@ int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, char *arg,
 {
        struct probe_arg *parg = &tp->args[i];
        char *body;
-       int ret;
 
        /* Increment count for freeing args in error case */
        tp->nr_args++;
 
        body = strchr(arg, '=');
        if (body) {
-               if (body - arg > MAX_ARG_NAME_LEN || body == arg)
+               if (body - arg > MAX_ARG_NAME_LEN) {
+                       trace_probe_log_err(0, ARG_NAME_TOO_LONG);
+                       return -EINVAL;
+               } else if (body == arg) {
+                       trace_probe_log_err(0, NO_ARG_NAME);
                        return -EINVAL;
+               }
                parg->name = kmemdup_nul(arg, body - arg, GFP_KERNEL);
                body++;
        } else {
@@ -575,22 +700,16 @@ int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, char *arg,
                return -ENOMEM;
 
        if (!is_good_name(parg->name)) {
-               pr_info("Invalid argument[%d] name: %s\n",
-                       i, parg->name);
+               trace_probe_log_err(0, BAD_ARG_NAME);
                return -EINVAL;
        }
-
        if (traceprobe_conflict_field_name(parg->name, tp->args, i)) {
-               pr_info("Argument[%d]: '%s' conflicts with another field.\n",
-                       i, parg->name);
+               trace_probe_log_err(0, USED_ARG_NAME);
                return -EINVAL;
        }
-
        /* Parse fetch argument */
-       ret = traceprobe_parse_probe_arg_body(body, &tp->size, parg, flags);
-       if (ret)
-               pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
-       return ret;
+       return traceprobe_parse_probe_arg_body(body, &tp->size, parg, flags,
+                                              body - arg);
 }
 
 void traceprobe_free_probe_arg(struct probe_arg *arg)
index 2177c206de151c1b4e17b491020d0d9cd0af57a8..f9a8c632188bcf8a3d849cdf94f2d9a11a081eb6 100644 (file)
@@ -124,6 +124,7 @@ struct fetch_insn {
 
 /* fetch + deref*N + store + mod + end <= 16, this allows N=12, enough */
 #define FETCH_INSN_MAX 16
+#define FETCH_TOKEN_COMM       (-ECOMM)
 
 /* Fetch type information table */
 struct fetch_type {
@@ -280,8 +281,8 @@ extern int traceprobe_update_arg(struct probe_arg *arg);
 extern void traceprobe_free_probe_arg(struct probe_arg *arg);
 
 extern int traceprobe_split_symbol_offset(char *symbol, long *offset);
-extern int traceprobe_parse_event_name(const char **pevent,
-                                      const char **pgroup, char *buf);
+int traceprobe_parse_event_name(const char **pevent, const char **pgroup,
+                               char *buf, int offset);
 
 extern int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return);
 
@@ -298,3 +299,76 @@ extern void destroy_local_trace_uprobe(struct trace_event_call *event_call);
 #endif
 extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
                                        size_t offset, struct trace_probe *tp);
+
+#undef ERRORS
+#define ERRORS \
+       C(FILE_NOT_FOUND,       "Failed to find the given file"),       \
+       C(NO_REGULAR_FILE,      "Not a regular file"),                  \
+       C(BAD_REFCNT,           "Invalid reference counter offset"),    \
+       C(REFCNT_OPEN_BRACE,    "Reference counter brace is not closed"), \
+       C(BAD_REFCNT_SUFFIX,    "Reference counter has wrong suffix"),  \
+       C(BAD_UPROBE_OFFS,      "Invalid uprobe offset"),               \
+       C(MAXACT_NO_KPROBE,     "Maxactive is not for kprobe"),         \
+       C(BAD_MAXACT,           "Invalid maxactive number"),            \
+       C(MAXACT_TOO_BIG,       "Maxactive is too big"),                \
+       C(BAD_PROBE_ADDR,       "Invalid probed address or symbol"),    \
+       C(BAD_RETPROBE,         "Retprobe address must be an function entry"), \
+       C(NO_GROUP_NAME,        "Group name is not specified"),         \
+       C(GROUP_TOO_LONG,       "Group name is too long"),              \
+       C(BAD_GROUP_NAME,       "Group name must follow the same rules as C identifiers"), \
+       C(NO_EVENT_NAME,        "Event name is not specified"),         \
+       C(EVENT_TOO_LONG,       "Event name is too long"),              \
+       C(BAD_EVENT_NAME,       "Event name must follow the same rules as C identifiers"), \
+       C(RETVAL_ON_PROBE,      "$retval is not available on probe"),   \
+       C(BAD_STACK_NUM,        "Invalid stack number"),                \
+       C(BAD_ARG_NUM,          "Invalid argument number"),             \
+       C(BAD_VAR,              "Invalid $-valiable specified"),        \
+       C(BAD_REG_NAME,         "Invalid register name"),               \
+       C(BAD_MEM_ADDR,         "Invalid memory address"),              \
+       C(FILE_ON_KPROBE,       "File offset is not available with kprobe"), \
+       C(BAD_FILE_OFFS,        "Invalid file offset value"),           \
+       C(SYM_ON_UPROBE,        "Symbol is not available with uprobe"), \
+       C(TOO_MANY_OPS,         "Dereference is too much nested"),      \
+       C(DEREF_NEED_BRACE,     "Dereference needs a brace"),           \
+       C(BAD_DEREF_OFFS,       "Invalid dereference offset"),          \
+       C(DEREF_OPEN_BRACE,     "Dereference brace is not closed"),     \
+       C(COMM_CANT_DEREF,      "$comm can not be dereferenced"),       \
+       C(BAD_FETCH_ARG,        "Invalid fetch argument"),              \
+       C(ARRAY_NO_CLOSE,       "Array is not closed"),                 \
+       C(BAD_ARRAY_SUFFIX,     "Array has wrong suffix"),              \
+       C(BAD_ARRAY_NUM,        "Invalid array size"),                  \
+       C(ARRAY_TOO_BIG,        "Array number is too big"),             \
+       C(BAD_TYPE,             "Unknown type is specified"),           \
+       C(BAD_STRING,           "String accepts only memory argument"), \
+       C(BAD_BITFIELD,         "Invalid bitfield"),                    \
+       C(ARG_NAME_TOO_LONG,    "Argument name is too long"),           \
+       C(NO_ARG_NAME,          "Argument name is not specified"),      \
+       C(BAD_ARG_NAME,         "Argument name must follow the same rules as C identifiers"), \
+       C(USED_ARG_NAME,        "This argument name is already used"),  \
+       C(ARG_TOO_LONG,         "Argument expression is too long"),     \
+       C(NO_ARG_BODY,          "No argument expression"),              \
+       C(BAD_INSN_BNDRY,       "Probe point is not an instruction boundary"),\
+       C(FAIL_REG_PROBE,       "Failed to register probe event"),
+
+#undef C
+#define C(a, b)                TP_ERR_##a
+
+/* Define TP_ERR_ */
+enum { ERRORS };
+
+/* Error text is defined in trace_probe.c */
+
+struct trace_probe_log {
+       const char      *subsystem;
+       const char      **argv;
+       int             argc;
+       int             index;
+};
+
+void trace_probe_log_init(const char *subsystem, int argc, const char **argv);
+void trace_probe_log_set_index(int index);
+void trace_probe_log_clear(void);
+void __trace_probe_log_err(int offset, int err);
+
+#define trace_probe_log_err(offs, err) \
+       __trace_probe_log_err(offs, TP_ERR_##err)
index 4737bb8c07a3851c30fa565d48e3b4dae5da2e8b..c30c61f12dddff4b1e791751c2029a34bd182b93 100644 (file)
@@ -88,7 +88,7 @@ stage3:
        /* 3rd stage: store value to buffer */
        if (unlikely(!dest)) {
                if (code->op == FETCH_OP_ST_STRING) {
-                       ret += fetch_store_strlen(val + code->offset);
+                       ret = fetch_store_strlen(val + code->offset);
                        code++;
                        goto array;
                } else
index 9d402e7fc949cb7b8dfee9975f17be8508446810..69ee8ef12cee372f4f44fca053d2cc5b67182d0a 100644 (file)
@@ -792,7 +792,10 @@ trace_selftest_startup_function_graph(struct tracer *trace,
        /* check the trace buffer */
        ret = trace_test_buffer(&tr->trace_buffer, &count);
 
-       trace->reset(tr);
+       /* Need to also simulate the tr->reset to remove this fgraph_ops */
+       tracing_stop_cmdline_record();
+       unregister_ftrace_graph(&fgraph_ops);
+
        tracing_start();
 
        if (!ret && !count) {
index be78d99ee6bc2b092c789d59070895b1da9aef8b..eb7e06b54741beec641f536a645597698a5df986 100644 (file)
@@ -156,7 +156,10 @@ fetch_store_string(unsigned long addr, void *dest, void *base)
        if (unlikely(!maxlen))
                return -ENOMEM;
 
-       ret = strncpy_from_user(dst, src, maxlen);
+       if (addr == FETCH_TOKEN_COMM)
+               ret = strlcpy(dst, current->comm, maxlen);
+       else
+               ret = strncpy_from_user(dst, src, maxlen);
        if (ret >= 0) {
                if (ret == maxlen)
                        dst[ret - 1] = '\0';
@@ -180,7 +183,10 @@ fetch_store_strlen(unsigned long addr)
        int len;
        void __user *vaddr = (void __force __user *) addr;
 
-       len = strnlen_user(vaddr, MAX_STRING_SIZE);
+       if (addr == FETCH_TOKEN_COMM)
+               len = strlen(current->comm) + 1;
+       else
+               len = strnlen_user(vaddr, MAX_STRING_SIZE);
 
        return (len > MAX_STRING_SIZE) ? 0 : len;
 }
@@ -220,6 +226,9 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
        case FETCH_OP_IMM:
                val = code->immediate;
                break;
+       case FETCH_OP_COMM:
+               val = FETCH_TOKEN_COMM;
+               break;
        case FETCH_OP_FOFFS:
                val = translate_user_vaddr(code->immediate);
                break;
@@ -457,13 +466,19 @@ static int trace_uprobe_create(int argc, const char **argv)
                return -ECANCELED;
        }
 
+       trace_probe_log_init("trace_uprobe", argc, argv);
+       trace_probe_log_set_index(1);   /* filename is the 2nd argument */
+
        *arg++ = '\0';
        ret = kern_path(filename, LOOKUP_FOLLOW, &path);
        if (ret) {
+               trace_probe_log_err(0, FILE_NOT_FOUND);
                kfree(filename);
+               trace_probe_log_clear();
                return ret;
        }
        if (!d_is_reg(path.dentry)) {
+               trace_probe_log_err(0, NO_REGULAR_FILE);
                ret = -EINVAL;
                goto fail_address_parse;
        }
@@ -472,9 +487,16 @@ static int trace_uprobe_create(int argc, const char **argv)
        rctr = strchr(arg, '(');
        if (rctr) {
                rctr_end = strchr(rctr, ')');
-               if (rctr > rctr_end || *(rctr_end + 1) != 0) {
+               if (!rctr_end) {
+                       ret = -EINVAL;
+                       rctr_end = rctr + strlen(rctr);
+                       trace_probe_log_err(rctr_end - filename,
+                                           REFCNT_OPEN_BRACE);
+                       goto fail_address_parse;
+               } else if (rctr_end[1] != '\0') {
                        ret = -EINVAL;
-                       pr_info("Invalid reference counter offset.\n");
+                       trace_probe_log_err(rctr_end + 1 - filename,
+                                           BAD_REFCNT_SUFFIX);
                        goto fail_address_parse;
                }
 
@@ -482,22 +504,23 @@ static int trace_uprobe_create(int argc, const char **argv)
                *rctr_end = '\0';
                ret = kstrtoul(rctr, 0, &ref_ctr_offset);
                if (ret) {
-                       pr_info("Invalid reference counter offset.\n");
+                       trace_probe_log_err(rctr - filename, BAD_REFCNT);
                        goto fail_address_parse;
                }
        }
 
        /* Parse uprobe offset. */
        ret = kstrtoul(arg, 0, &offset);
-       if (ret)
+       if (ret) {
+               trace_probe_log_err(arg - filename, BAD_UPROBE_OFFS);
                goto fail_address_parse;
-
-       argc -= 2;
-       argv += 2;
+       }
 
        /* setup a probe */
+       trace_probe_log_set_index(0);
        if (event) {
-               ret = traceprobe_parse_event_name(&event, &group, buf);
+               ret = traceprobe_parse_event_name(&event, &group, buf,
+                                                 event - argv[0]);
                if (ret)
                        goto fail_address_parse;
        } else {
@@ -519,6 +542,9 @@ static int trace_uprobe_create(int argc, const char **argv)
                kfree(tail);
        }
 
+       argc -= 2;
+       argv += 2;
+
        tu = alloc_trace_uprobe(group, event, argc, is_return);
        if (IS_ERR(tu)) {
                ret = PTR_ERR(tu);
@@ -539,6 +565,7 @@ static int trace_uprobe_create(int argc, const char **argv)
                        goto error;
                }
 
+               trace_probe_log_set_index(i + 2);
                ret = traceprobe_parse_probe_arg(&tu->tp, i, tmp,
                                        is_return ? TPARG_FL_RETURN : 0);
                kfree(tmp);
@@ -547,20 +574,20 @@ static int trace_uprobe_create(int argc, const char **argv)
        }
 
        ret = register_trace_uprobe(tu);
-       if (ret)
-               goto error;
-       return 0;
+       if (!ret)
+               goto out;
 
 error:
        free_trace_uprobe(tu);
+out:
+       trace_probe_log_clear();
        return ret;
 
 fail_address_parse:
+       trace_probe_log_clear();
        path_put(&path);
        kfree(filename);
 
-       pr_info("Failed to parse address or file.\n");
-
        return ret;
 }
 
index 0df9b1640b2af5d4ade21a376172fdfd6d097694..88b834f0eebc50cb2fedb0b6b5347620743e1d56 100644 (file)
@@ -185,7 +185,7 @@ struct user_struct *alloc_uid(kuid_t uid)
        if (!up) {
                new = kmem_cache_zalloc(uid_cachep, GFP_KERNEL);
                if (!new)
-                       goto out_unlock;
+                       return NULL;
 
                new->uid = uid;
                refcount_set(&new->__count, 1);
@@ -199,8 +199,6 @@ struct user_struct *alloc_uid(kuid_t uid)
                spin_lock_irq(&uidhash_lock);
                up = uid_hash_find(uid, hashent);
                if (up) {
-                       key_put(new->uid_keyring);
-                       key_put(new->session_keyring);
                        kmem_cache_free(uid_cachep, new);
                } else {
                        uid_hash_insert(new, hashent);
@@ -210,9 +208,6 @@ struct user_struct *alloc_uid(kuid_t uid)
        }
 
        return up;
-
-out_unlock:
-       return NULL;
 }
 
 static int __init uid_cache_init(void)
index f323b85ad11cb311426806148c300d918697564d..8d9239a4156c65288c12ef5a5626446335315b94 100644 (file)
@@ -46,9 +46,6 @@ config HAVE_ARCH_BITREVERSE
          This option enables the use of hardware bit-reversal instructions on
          architectures which support such operations.
 
-config RATIONAL
-       bool
-
 config GENERIC_STRNCPY_FROM_USER
        bool
 
@@ -61,6 +58,8 @@ config GENERIC_NET_UTILS
 config GENERIC_FIND_FIRST_BIT
        bool
 
+source "lib/math/Kconfig"
+
 config NO_GENERIC_PCI_IOPORT_MAP
        bool
 
@@ -531,12 +530,6 @@ config LRU_CACHE
 config CLZ_TAB
        bool
 
-config CORDIC
-       tristate "CORDIC algorithm"
-       help
-         This option provides an implementation of the CORDIC algorithm;
-         calculations are in fixed point. Module will be called cordic.
-
 config DDR
        bool "JEDEC DDR data"
        help
@@ -608,6 +601,10 @@ config ARCH_NO_SG_CHAIN
 config ARCH_HAS_PMEM_API
        bool
 
+# use memcpy to implement user copies for nommu architectures
+config UACCESS_MEMCPY
+       bool
+
 config ARCH_HAS_UACCESS_FLUSHCACHE
        bool
 
@@ -628,9 +625,6 @@ config SBITMAP
 config PARMAN
        tristate "parman" if COMPILE_TEST
 
-config PRIME_NUMBERS
-       tristate
-
 config STRING_SELFTEST
        tristate "Test string functions"
 
index d695ec1477f39e86f7c6c74bf7f1021a6776879c..eae43952902ebfb487817b081f52685a47154464 100644 (file)
@@ -318,6 +318,20 @@ config HEADERS_CHECK
          exported to $(INSTALL_HDR_PATH) (usually 'usr/include' in
          your build tree), to make sure they're suitable.
 
+config OPTIMIZE_INLINING
+       bool "Allow compiler to uninline functions marked 'inline'"
+       help
+         This option determines if the kernel forces gcc to inline the functions
+         developers have marked 'inline'. Doing so takes away freedom from gcc to
+         do what it thinks is best, which is desirable for the gcc 3.x series of
+         compilers. The gcc 4.x series have a rewritten inlining algorithm and
+         enabling this option will generate a smaller kernel there. Hopefully
+         this algorithm is so good that allowing gcc 4.x and above to make the
+         decision will become the default in the future. Until then this option
+         is there to test gcc for this.
+
+         If unsure, say N.
+
 config DEBUG_SECTION_MISMATCH
        bool "Enable full Section mismatch analysis"
        help
@@ -446,6 +460,15 @@ config DEBUG_KERNEL
          Say Y here if you are developing drivers or trying to debug and
          identify kernel problems.
 
+config DEBUG_MISC
+       bool "Miscellaneous debug code"
+       default DEBUG_KERNEL
+       depends on DEBUG_KERNEL
+       help
+         Say Y here if you need to enable miscellaneous debug code that should
+         be under a more specific debug option but isn't.
+
+
 menu "Memory Debugging"
 
 source "mm/Kconfig.debug"
@@ -519,10 +542,6 @@ config DEBUG_SLAB
          allocation as well as poisoning memory on free to catch use of freed
          memory. This can make kmalloc/kfree-intensive workloads much slower.
 
-config DEBUG_SLAB_LEAK
-       bool "Memory leak debugging"
-       depends on DEBUG_SLAB
-
 config SLUB_DEBUG_ON
        bool "SLUB debugging on by default"
        depends on SLUB && SLUB_DEBUG
@@ -1358,7 +1377,7 @@ config DEBUG_LIST
 
          If unsure, say N.
 
-config DEBUG_PI_LIST
+config DEBUG_PLIST
        bool "Debug priority linked list manipulation"
        depends on DEBUG_KERNEL
        help
index 83d7df2661ffa1bcf8bd1f0db2711a4533a0b720..fb7697031a797f0f4c73a5e4e7a611a231c93947 100644 (file)
@@ -30,7 +30,7 @@ endif
 
 lib-y := ctype.o string.o vsprintf.o cmdline.o \
         rbtree.o radix-tree.o timerqueue.o xarray.o \
-        idr.o int_sqrt.o extable.o \
+        idr.o extable.o \
         sha1.o chacha.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 \
@@ -44,11 +44,11 @@ lib-$(CONFIG_SMP) += cpumask.o
 lib-y  += kobject.o klist.o
 obj-y  += lockref.o
 
-obj-y += bcd.o div64.o sort.o parser.o debug_locks.o random32.o \
+obj-y += bcd.o sort.o parser.o debug_locks.o random32.o \
         bust_spinlocks.o kasprintf.o bitmap.o scatterlist.o \
-        gcd.o lcm.o list_sort.o uuid.o iov_iter.o clz_ctz.o \
+        list_sort.o uuid.o iov_iter.o clz_ctz.o \
         bsearch.o find_bit.o llist.o memweight.o kfifo.o \
-        percpu-refcount.o rhashtable.o reciprocal_div.o \
+        percpu-refcount.o rhashtable.o \
         once.o refcount.o usercopy.o errseq.o bucket_locks.o \
         generic-radix-tree.o
 obj-$(CONFIG_STRING_SELFTEST) += test_string.o
@@ -102,6 +102,8 @@ endif
 obj-$(CONFIG_DEBUG_INFO_REDUCED) += debug_info.o
 CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any)
 
+obj-y += math/
+
 obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
 obj-$(CONFIG_GENERIC_PCI_IOMAP) += pci_iomap.o
 obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
@@ -121,7 +123,6 @@ obj-$(CONFIG_DEBUG_OBJECTS) += debugobjects.o
 
 obj-$(CONFIG_BITREVERSE) += bitrev.o
 obj-$(CONFIG_PACKING)  += packing.o
-obj-$(CONFIG_RATIONAL) += rational.o
 obj-$(CONFIG_CRC_CCITT)        += crc-ccitt.o
 obj-$(CONFIG_CRC16)    += crc16.o
 obj-$(CONFIG_CRC_T10DIF)+= crc-t10dif.o
@@ -195,8 +196,6 @@ obj-$(CONFIG_ATOMIC64_SELFTEST) += atomic64_test.o
 
 obj-$(CONFIG_CPU_RMAP) += cpu_rmap.o
 
-obj-$(CONFIG_CORDIC) += cordic.o
-
 obj-$(CONFIG_DQL) += dynamic_queue_limits.o
 
 obj-$(CONFIG_GLOB) += glob.o
@@ -238,8 +237,6 @@ obj-$(CONFIG_ASN1) += asn1_decoder.o
 
 obj-$(CONFIG_FONT_SUPPORT) += fonts/
 
-obj-$(CONFIG_PRIME_NUMBERS) += prime_numbers.o
-
 hostprogs-y    := gen_crc32table
 hostprogs-y    += gen_crc64table
 clean-files    := crc32table.h
index 98872e9025dabd336fbb01dc5970376adc88c4e8..f235434df87bc7ce1e3cfc3e4f77971aa160667d 100644 (file)
@@ -20,6 +20,8 @@
 
 #include <asm/page.h>
 
+#include "kstrtox.h"
+
 /**
  * DOC: bitmap introduction
  *
@@ -477,12 +479,128 @@ int bitmap_print_to_pagebuf(bool list, char *buf, const unsigned long *maskp,
 }
 EXPORT_SYMBOL(bitmap_print_to_pagebuf);
 
+/*
+ * Region 9-38:4/10 describes the following bitmap structure:
+ * 0      9  12    18                  38
+ * .........****......****......****......
+ *         ^  ^     ^                   ^
+ *      start  off   group_len        end
+ */
+struct region {
+       unsigned int start;
+       unsigned int off;
+       unsigned int group_len;
+       unsigned int end;
+};
+
+static int bitmap_set_region(const struct region *r,
+                               unsigned long *bitmap, int nbits)
+{
+       unsigned int start;
+
+       if (r->end >= nbits)
+               return -ERANGE;
+
+       for (start = r->start; start <= r->end; start += r->group_len)
+               bitmap_set(bitmap, start, min(r->end - start + 1, r->off));
+
+       return 0;
+}
+
+static int bitmap_check_region(const struct region *r)
+{
+       if (r->start > r->end || r->group_len == 0 || r->off > r->group_len)
+               return -EINVAL;
+
+       return 0;
+}
+
+static const char *bitmap_getnum(const char *str, unsigned int *num)
+{
+       unsigned long long n;
+       unsigned int len;
+
+       len = _parse_integer(str, 10, &n);
+       if (!len)
+               return ERR_PTR(-EINVAL);
+       if (len & KSTRTOX_OVERFLOW || n != (unsigned int)n)
+               return ERR_PTR(-EOVERFLOW);
+
+       *num = n;
+       return str + len;
+}
+
+static inline bool end_of_str(char c)
+{
+       return c == '\0' || c == '\n';
+}
+
+static inline bool __end_of_region(char c)
+{
+       return isspace(c) || c == ',';
+}
+
+static inline bool end_of_region(char c)
+{
+       return __end_of_region(c) || end_of_str(c);
+}
+
+/*
+ * The format allows commas and whitespases at the beginning
+ * of the region.
+ */
+static const char *bitmap_find_region(const char *str)
+{
+       while (__end_of_region(*str))
+               str++;
+
+       return end_of_str(*str) ? NULL : str;
+}
+
+static const char *bitmap_parse_region(const char *str, struct region *r)
+{
+       str = bitmap_getnum(str, &r->start);
+       if (IS_ERR(str))
+               return str;
+
+       if (end_of_region(*str))
+               goto no_end;
+
+       if (*str != '-')
+               return ERR_PTR(-EINVAL);
+
+       str = bitmap_getnum(str + 1, &r->end);
+       if (IS_ERR(str))
+               return str;
+
+       if (end_of_region(*str))
+               goto no_pattern;
+
+       if (*str != ':')
+               return ERR_PTR(-EINVAL);
+
+       str = bitmap_getnum(str + 1, &r->off);
+       if (IS_ERR(str))
+               return str;
+
+       if (*str != '/')
+               return ERR_PTR(-EINVAL);
+
+       return bitmap_getnum(str + 1, &r->group_len);
+
+no_end:
+       r->end = r->start;
+no_pattern:
+       r->off = r->end + 1;
+       r->group_len = r->end + 1;
+
+       return end_of_str(*str) ? NULL : str;
+}
+
 /**
- * __bitmap_parselist - convert list format ASCII string to bitmap
- * @buf: read nul-terminated user string from this buffer
- * @buflen: buffer size in bytes.  If string is smaller than this
- *    then it must be terminated with a \0.
- * @is_user: location of buffer, 0 indicates kernel space
+ * bitmap_parselist - convert list format ASCII string to bitmap
+ * @buf: read user string from this buffer; must be terminated
+ *    with a \0 or \n.
  * @maskp: write resulting mask here
  * @nmaskbits: number of bits in mask to be written
  *
@@ -498,127 +616,38 @@ EXPORT_SYMBOL(bitmap_print_to_pagebuf);
  *
  * Returns: 0 on success, -errno on invalid input strings. Error values:
  *
- *   - ``-EINVAL``: second number in range smaller than first
+ *   - ``-EINVAL``: wrong region format
  *   - ``-EINVAL``: invalid character in string
  *   - ``-ERANGE``: bit number specified too large for mask
+ *   - ``-EOVERFLOW``: integer overflow in the input parameters
  */
-static int __bitmap_parselist(const char *buf, unsigned int buflen,
-               int is_user, unsigned long *maskp,
-               int nmaskbits)
+int bitmap_parselist(const char *buf, unsigned long *maskp, int nmaskbits)
 {
-       unsigned int a, b, old_a, old_b;
-       unsigned int group_size, used_size, off;
-       int c, old_c, totaldigits, ndigits;
-       const char __user __force *ubuf = (const char __user __force *)buf;
-       int at_start, in_range, in_partial_range;
+       struct region r;
+       long ret;
 
-       totaldigits = c = 0;
-       old_a = old_b = 0;
-       group_size = used_size = 0;
        bitmap_zero(maskp, nmaskbits);
-       do {
-               at_start = 1;
-               in_range = 0;
-               in_partial_range = 0;
-               a = b = 0;
-               ndigits = totaldigits;
-
-               /* Get the next cpu# or a range of cpu#'s */
-               while (buflen) {
-                       old_c = c;
-                       if (is_user) {
-                               if (__get_user(c, ubuf++))
-                                       return -EFAULT;
-                       } else
-                               c = *buf++;
-                       buflen--;
-                       if (isspace(c))
-                               continue;
-
-                       /* A '\0' or a ',' signal the end of a cpu# or range */
-                       if (c == '\0' || c == ',')
-                               break;
-                       /*
-                       * whitespaces between digits are not allowed,
-                       * but it's ok if whitespaces are on head or tail.
-                       * when old_c is whilespace,
-                       * if totaldigits == ndigits, whitespace is on head.
-                       * if whitespace is on tail, it should not run here.
-                       * as c was ',' or '\0',
-                       * the last code line has broken the current loop.
-                       */
-                       if ((totaldigits != ndigits) && isspace(old_c))
-                               return -EINVAL;
 
-                       if (c == '/') {
-                               used_size = a;
-                               at_start = 1;
-                               in_range = 0;
-                               a = b = 0;
-                               continue;
-                       }
+       while (buf) {
+               buf = bitmap_find_region(buf);
+               if (buf == NULL)
+                       return 0;
 
-                       if (c == ':') {
-                               old_a = a;
-                               old_b = b;
-                               at_start = 1;
-                               in_range = 0;
-                               in_partial_range = 1;
-                               a = b = 0;
-                               continue;
-                       }
+               buf = bitmap_parse_region(buf, &r);
+               if (IS_ERR(buf))
+                       return PTR_ERR(buf);
 
-                       if (c == '-') {
-                               if (at_start || in_range)
-                                       return -EINVAL;
-                               b = 0;
-                               in_range = 1;
-                               at_start = 1;
-                               continue;
-                       }
+               ret = bitmap_check_region(&r);
+               if (ret)
+                       return ret;
 
-                       if (!isdigit(c))
-                               return -EINVAL;
+               ret = bitmap_set_region(&r, maskp, nmaskbits);
+               if (ret)
+                       return ret;
+       }
 
-                       b = b * 10 + (c - '0');
-                       if (!in_range)
-                               a = b;
-                       at_start = 0;
-                       totaldigits++;
-               }
-               if (ndigits == totaldigits)
-                       continue;
-               if (in_partial_range) {
-                       group_size = a;
-                       a = old_a;
-                       b = old_b;
-                       old_a = old_b = 0;
-               } else {
-                       used_size = group_size = b - a + 1;
-               }
-               /* if no digit is after '-', it's wrong*/
-               if (at_start && in_range)
-                       return -EINVAL;
-               if (!(a <= b) || group_size == 0 || !(used_size <= group_size))
-                       return -EINVAL;
-               if (b >= nmaskbits)
-                       return -ERANGE;
-               while (a <= b) {
-                       off = min(b - a + 1, used_size);
-                       bitmap_set(maskp, a, off);
-                       a += group_size;
-               }
-       } while (buflen && c == ',');
        return 0;
 }
-
-int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits)
-{
-       char *nl  = strchrnul(bp, '\n');
-       int len = nl - bp;
-
-       return __bitmap_parselist(bp, len, 0, maskp, nmaskbits);
-}
 EXPORT_SYMBOL(bitmap_parselist);
 
 
@@ -632,23 +661,27 @@ EXPORT_SYMBOL(bitmap_parselist);
  * @nmaskbits: size of bitmap, in bits.
  *
  * Wrapper for bitmap_parselist(), providing it with user buffer.
- *
- * We cannot have this as an inline function in bitmap.h because it needs
- * linux/uaccess.h to get the access_ok() declaration and this causes
- * cyclic dependencies.
  */
 int bitmap_parselist_user(const char __user *ubuf,
                        unsigned int ulen, unsigned long *maskp,
                        int nmaskbits)
 {
-       if (!access_ok(ubuf, ulen))
-               return -EFAULT;
-       return __bitmap_parselist((const char __force *)ubuf,
-                                       ulen, 1, maskp, nmaskbits);
+       char *buf;
+       int ret;
+
+       buf = memdup_user_nul(ubuf, ulen);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       ret = bitmap_parselist(buf, maskp, nmaskbits);
+
+       kfree(buf);
+       return ret;
 }
 EXPORT_SYMBOL(bitmap_parselist_user);
 
 
+#ifdef CONFIG_NUMA
 /**
  * bitmap_pos_to_ord - find ordinal of set bit at given position in bitmap
  *     @buf: pointer to a bitmap
@@ -757,7 +790,6 @@ void bitmap_remap(unsigned long *dst, const unsigned long *src,
                        set_bit(bitmap_ord_to_pos(new, n % w, nbits), dst);
        }
 }
-EXPORT_SYMBOL(bitmap_remap);
 
 /**
  * bitmap_bitremap - Apply map defined by a pair of bitmaps to a single bit
@@ -795,7 +827,6 @@ int bitmap_bitremap(int oldbit, const unsigned long *old,
        else
                return bitmap_ord_to_pos(new, n % w, bits);
 }
-EXPORT_SYMBOL(bitmap_bitremap);
 
 /**
  * bitmap_onto - translate one bitmap relative to another
@@ -930,7 +961,6 @@ void bitmap_onto(unsigned long *dst, const unsigned long *orig,
                m++;
        }
 }
-EXPORT_SYMBOL(bitmap_onto);
 
 /**
  * bitmap_fold - fold larger bitmap into smaller, modulo specified size
@@ -955,7 +985,7 @@ void bitmap_fold(unsigned long *dst, const unsigned long *orig,
        for_each_set_bit(oldbit, orig, nbits)
                set_bit(oldbit % sz, dst);
 }
-EXPORT_SYMBOL(bitmap_fold);
+#endif /* CONFIG_NUMA */
 
 /*
  * Common code for bitmap_*_region() routines.
diff --git a/lib/cordic.c b/lib/cordic.c
deleted file mode 100644 (file)
index 8ef27c1..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2011 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#include <linux/module.h>
-#include <linux/cordic.h>
-
-static const s32 arctan_table[] = {
-       2949120,
-       1740967,
-       919879,
-       466945,
-       234379,
-       117304,
-       58666,
-       29335,
-       14668,
-       7334,
-       3667,
-       1833,
-       917,
-       458,
-       229,
-       115,
-       57,
-       29
-};
-
-/*
- * cordic_calc_iq() - calculates the i/q coordinate for given angle
- *
- * theta: angle in degrees for which i/q coordinate is to be calculated
- * coord: function output parameter holding the i/q coordinate
- */
-struct cordic_iq cordic_calc_iq(s32 theta)
-{
-       struct cordic_iq coord;
-       s32 angle, valtmp;
-       unsigned iter;
-       int signx = 1;
-       int signtheta;
-
-       coord.i = CORDIC_ANGLE_GEN;
-       coord.q = 0;
-       angle = 0;
-
-       theta = CORDIC_FIXED(theta);
-       signtheta = (theta < 0) ? -1 : 1;
-       theta = ((theta + CORDIC_FIXED(180) * signtheta) % CORDIC_FIXED(360)) -
-               CORDIC_FIXED(180) * signtheta;
-
-       if (CORDIC_FLOAT(theta) > 90) {
-               theta -= CORDIC_FIXED(180);
-               signx = -1;
-       } else if (CORDIC_FLOAT(theta) < -90) {
-               theta += CORDIC_FIXED(180);
-               signx = -1;
-       }
-
-       for (iter = 0; iter < CORDIC_NUM_ITER; iter++) {
-               if (theta > angle) {
-                       valtmp = coord.i - (coord.q >> iter);
-                       coord.q += (coord.i >> iter);
-                       angle += arctan_table[iter];
-               } else {
-                       valtmp = coord.i + (coord.q >> iter);
-                       coord.q -= (coord.i >> iter);
-                       angle -= arctan_table[iter];
-               }
-               coord.i = valtmp;
-       }
-
-       coord.i *= signx;
-       coord.q *= signx;
-       return coord;
-}
-EXPORT_SYMBOL(cordic_calc_iq);
-
-MODULE_DESCRIPTION("CORDIC algorithm");
-MODULE_AUTHOR("Broadcom Corporation");
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/lib/div64.c b/lib/div64.c
deleted file mode 100644 (file)
index ee146bb..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
- *
- * Based on former do_div() implementation from asm-parisc/div64.h:
- *     Copyright (C) 1999 Hewlett-Packard Co
- *     Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- *
- *
- * Generic C version of 64bit/32bit division and modulo, with
- * 64bit result and 32bit remainder.
- *
- * The fast case for (n>>32 == 0) is handled inline by do_div(). 
- *
- * Code generated for this function might be very inefficient
- * for some CPUs. __div64_32() can be overridden by linking arch-specific
- * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S
- * or by defining a preprocessor macro in arch/include/asm/div64.h.
- */
-
-#include <linux/export.h>
-#include <linux/kernel.h>
-#include <linux/math64.h>
-
-/* Not needed on 64bit architectures */
-#if BITS_PER_LONG == 32
-
-#ifndef __div64_32
-uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
-{
-       uint64_t rem = *n;
-       uint64_t b = base;
-       uint64_t res, d = 1;
-       uint32_t high = rem >> 32;
-
-       /* Reduce the thing a bit first */
-       res = 0;
-       if (high >= base) {
-               high /= base;
-               res = (uint64_t) high << 32;
-               rem -= (uint64_t) (high*base) << 32;
-       }
-
-       while ((int64_t)b > 0 && b < rem) {
-               b = b+b;
-               d = d+d;
-       }
-
-       do {
-               if (rem >= b) {
-                       rem -= b;
-                       res += d;
-               }
-               b >>= 1;
-               d >>= 1;
-       } while (d);
-
-       *n = res;
-       return rem;
-}
-EXPORT_SYMBOL(__div64_32);
-#endif
-
-/**
- * div_s64_rem - signed 64bit divide with 64bit divisor and remainder
- * @dividend:  64bit dividend
- * @divisor:   64bit divisor
- * @remainder:  64bit remainder
- */
-#ifndef div_s64_rem
-s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
-{
-       u64 quotient;
-
-       if (dividend < 0) {
-               quotient = div_u64_rem(-dividend, abs(divisor), (u32 *)remainder);
-               *remainder = -*remainder;
-               if (divisor > 0)
-                       quotient = -quotient;
-       } else {
-               quotient = div_u64_rem(dividend, abs(divisor), (u32 *)remainder);
-               if (divisor < 0)
-                       quotient = -quotient;
-       }
-       return quotient;
-}
-EXPORT_SYMBOL(div_s64_rem);
-#endif
-
-/**
- * div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder
- * @dividend:  64bit dividend
- * @divisor:   64bit divisor
- * @remainder:  64bit remainder
- *
- * This implementation is a comparable to algorithm used by div64_u64.
- * But this operation, which includes math for calculating the remainder,
- * is kept distinct to avoid slowing down the div64_u64 operation on 32bit
- * systems.
- */
-#ifndef div64_u64_rem
-u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
-{
-       u32 high = divisor >> 32;
-       u64 quot;
-
-       if (high == 0) {
-               u32 rem32;
-               quot = div_u64_rem(dividend, divisor, &rem32);
-               *remainder = rem32;
-       } else {
-               int n = fls(high);
-               quot = div_u64(dividend >> n, divisor >> n);
-
-               if (quot != 0)
-                       quot--;
-
-               *remainder = dividend - quot * divisor;
-               if (*remainder >= divisor) {
-                       quot++;
-                       *remainder -= divisor;
-               }
-       }
-
-       return quot;
-}
-EXPORT_SYMBOL(div64_u64_rem);
-#endif
-
-/**
- * div64_u64 - unsigned 64bit divide with 64bit divisor
- * @dividend:  64bit dividend
- * @divisor:   64bit divisor
- *
- * This implementation is a modified version of the algorithm proposed
- * by the book 'Hacker's Delight'.  The original source and full proof
- * can be found here and is available for use without restriction.
- *
- * 'http://www.hackersdelight.org/hdcodetxt/divDouble.c.txt'
- */
-#ifndef div64_u64
-u64 div64_u64(u64 dividend, u64 divisor)
-{
-       u32 high = divisor >> 32;
-       u64 quot;
-
-       if (high == 0) {
-               quot = div_u64(dividend, divisor);
-       } else {
-               int n = fls(high);
-               quot = div_u64(dividend >> n, divisor >> n);
-
-               if (quot != 0)
-                       quot--;
-               if ((dividend - quot * divisor) >= divisor)
-                       quot++;
-       }
-
-       return quot;
-}
-EXPORT_SYMBOL(div64_u64);
-#endif
-
-/**
- * div64_s64 - signed 64bit divide with 64bit divisor
- * @dividend:  64bit dividend
- * @divisor:   64bit divisor
- */
-#ifndef div64_s64
-s64 div64_s64(s64 dividend, s64 divisor)
-{
-       s64 quot, t;
-
-       quot = div64_u64(abs(dividend), abs(divisor));
-       t = (dividend ^ divisor) >> 63;
-
-       return (quot ^ t) - t;
-}
-EXPORT_SYMBOL(div64_s64);
-#endif
-
-#endif /* BITS_PER_LONG == 32 */
-
-/*
- * Iterative div/mod for use when dividend is not expected to be much
- * bigger than divisor.
- */
-u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)
-{
-       return __iter_div_u64_rem(dividend, divisor, remainder);
-}
-EXPORT_SYMBOL(iter_div_u64_rem);
diff --git a/lib/gcd.c b/lib/gcd.c
deleted file mode 100644 (file)
index 7948ab2..0000000
--- a/lib/gcd.c
+++ /dev/null
@@ -1,84 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/gcd.h>
-#include <linux/export.h>
-
-/*
- * This implements the binary GCD algorithm. (Often attributed to Stein,
- * but as Knuth has noted, appears in a first-century Chinese math text.)
- *
- * This is faster than the division-based algorithm even on x86, which
- * has decent hardware division.
- */
-
-#if !defined(CONFIG_CPU_NO_EFFICIENT_FFS)
-
-/* If __ffs is available, the even/odd algorithm benchmarks slower. */
-
-/**
- * gcd - calculate and return the greatest common divisor of 2 unsigned longs
- * @a: first value
- * @b: second value
- */
-unsigned long gcd(unsigned long a, unsigned long b)
-{
-       unsigned long r = a | b;
-
-       if (!a || !b)
-               return r;
-
-       b >>= __ffs(b);
-       if (b == 1)
-               return r & -r;
-
-       for (;;) {
-               a >>= __ffs(a);
-               if (a == 1)
-                       return r & -r;
-               if (a == b)
-                       return a << __ffs(r);
-
-               if (a < b)
-                       swap(a, b);
-               a -= b;
-       }
-}
-
-#else
-
-/* If normalization is done by loops, the even/odd algorithm is a win. */
-unsigned long gcd(unsigned long a, unsigned long b)
-{
-       unsigned long r = a | b;
-
-       if (!a || !b)
-               return r;
-
-       /* Isolate lsbit of r */
-       r &= -r;
-
-       while (!(b & r))
-               b >>= 1;
-       if (b == r)
-               return r;
-
-       for (;;) {
-               while (!(a & r))
-                       a >>= 1;
-               if (a == r)
-                       return r;
-               if (a == b)
-                       return a;
-
-               if (a < b)
-                       swap(a, b);
-               a -= b;
-               a >>= 1;
-               if (a & r)
-                       a += b;
-               a >>= 1;
-       }
-}
-
-#endif
-
-EXPORT_SYMBOL_GPL(gcd);
index 7660d88fd4960c8571d16f035d4d92b76fd17f2c..c94586b6255187906cfde38fda8b84f33c9fc21f 100644 (file)
@@ -10,7 +10,6 @@
  * The Hamming Weight of a number is the total number of bits set in it.
  */
 
-#ifndef __HAVE_ARCH_SW_HWEIGHT
 unsigned int __sw_hweight32(unsigned int w)
 {
 #ifdef CONFIG_ARCH_HAS_FAST_MULTIPLIER
@@ -27,7 +26,6 @@ unsigned int __sw_hweight32(unsigned int w)
 #endif
 }
 EXPORT_SYMBOL(__sw_hweight32);
-#endif
 
 unsigned int __sw_hweight16(unsigned int w)
 {
@@ -46,7 +44,6 @@ unsigned int __sw_hweight8(unsigned int w)
 }
 EXPORT_SYMBOL(__sw_hweight8);
 
-#ifndef __HAVE_ARCH_SW_HWEIGHT
 unsigned long __sw_hweight64(__u64 w)
 {
 #if BITS_PER_LONG == 32
@@ -69,4 +66,3 @@ unsigned long __sw_hweight64(__u64 w)
 #endif
 }
 EXPORT_SYMBOL(__sw_hweight64);
-#endif
diff --git a/lib/int_sqrt.c b/lib/int_sqrt.c
deleted file mode 100644 (file)
index 30e0f97..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2013 Davidlohr Bueso <davidlohr.bueso@hp.com>
- *
- *  Based on the shift-and-subtract algorithm for computing integer
- *  square root from Guy L. Steele.
- */
-
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/bitops.h>
-
-/**
- * int_sqrt - computes the integer square root
- * @x: integer of which to calculate the sqrt
- *
- * Computes: floor(sqrt(x))
- */
-unsigned long int_sqrt(unsigned long x)
-{
-       unsigned long b, m, y = 0;
-
-       if (x <= 1)
-               return x;
-
-       m = 1UL << (__fls(x) & ~1UL);
-       while (m != 0) {
-               b = y + m;
-               y >>= 1;
-
-               if (x >= b) {
-                       x -= b;
-                       y += m;
-               }
-               m >>= 2;
-       }
-
-       return y;
-}
-EXPORT_SYMBOL(int_sqrt);
-
-#if BITS_PER_LONG < 64
-/**
- * int_sqrt64 - strongly typed int_sqrt function when minimum 64 bit input
- * is expected.
- * @x: 64bit integer of which to calculate the sqrt
- */
-u32 int_sqrt64(u64 x)
-{
-       u64 b, m, y = 0;
-
-       if (x <= ULONG_MAX)
-               return int_sqrt((unsigned long) x);
-
-       m = 1ULL << ((fls64(x) - 1) & ~1ULL);
-       while (m != 0) {
-               b = y + m;
-               y >>= 1;
-
-               if (x >= b) {
-                       x -= b;
-                       y += m;
-               }
-               m >>= 2;
-       }
-
-       return y;
-}
-EXPORT_SYMBOL(int_sqrt64);
-#endif
index b396d328a7643b7c1984b8e87df9da88c45e7470..f74fa832f3aa99b8364dc5ba22e4af5eba64368c 100644 (file)
@@ -1293,7 +1293,9 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
                        len = maxpages * PAGE_SIZE;
                addr &= ~(PAGE_SIZE - 1);
                n = DIV_ROUND_UP(len, PAGE_SIZE);
-               res = get_user_pages_fast(addr, n, iov_iter_rw(i) != WRITE, pages);
+               res = get_user_pages_fast(addr, n,
+                               iov_iter_rw(i) != WRITE ?  FOLL_WRITE : 0,
+                               pages);
                if (unlikely(res < 0))
                        return res;
                return (res == n ? len : res * PAGE_SIZE) - *start;
@@ -1374,7 +1376,8 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
                p = get_pages_array(n);
                if (!p)
                        return -ENOMEM;
-               res = get_user_pages_fast(addr, n, iov_iter_rw(i) != WRITE, p);
+               res = get_user_pages_fast(addr, n,
+                               iov_iter_rw(i) != WRITE ?  FOLL_WRITE : 0, p);
                if (unlikely(res < 0)) {
                        kvfree(p);
                        return res;
diff --git a/lib/lcm.c b/lib/lcm.c
deleted file mode 100644 (file)
index 03d7fcb..0000000
--- a/lib/lcm.c
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <linux/compiler.h>
-#include <linux/gcd.h>
-#include <linux/export.h>
-#include <linux/lcm.h>
-
-/* Lowest common multiple */
-unsigned long lcm(unsigned long a, unsigned long b)
-{
-       if (a && b)
-               return (a / gcd(a, b)) * b;
-       else
-               return 0;
-}
-EXPORT_SYMBOL_GPL(lcm);
-
-unsigned long lcm_not_zero(unsigned long a, unsigned long b)
-{
-       unsigned long l = lcm(a, b);
-
-       if (l)
-               return l;
-
-       return (b ? : a);
-}
-EXPORT_SYMBOL_GPL(lcm_not_zero);
index 85759928215b41f7be4ae56089eaaa7007f79659..06e900c5587b20246f566064729835bb3267cec0 100644 (file)
@@ -7,33 +7,41 @@
 #include <linux/list_sort.h>
 #include <linux/list.h>
 
-#define MAX_LIST_LENGTH_BITS 20
+typedef int __attribute__((nonnull(2,3))) (*cmp_func)(void *,
+               struct list_head const *, struct list_head const *);
 
 /*
  * Returns a list organized in an intermediate format suited
  * to chaining of merge() calls: null-terminated, no reserved or
  * sentinel head node, "prev" links not maintained.
  */
-static struct list_head *merge(void *priv,
-                               int (*cmp)(void *priv, struct list_head *a,
-                                       struct list_head *b),
+__attribute__((nonnull(2,3,4)))
+static struct list_head *merge(void *priv, cmp_func cmp,
                                struct list_head *a, struct list_head *b)
 {
-       struct list_head head, *tail = &head;
+       struct list_head *head, **tail = &head;
 
-       while (a && b) {
+       for (;;) {
                /* if equal, take 'a' -- important for sort stability */
-               if ((*cmp)(priv, a, b) <= 0) {
-                       tail->next = a;
+               if (cmp(priv, a, b) <= 0) {
+                       *tail = a;
+                       tail = &a->next;
                        a = a->next;
+                       if (!a) {
+                               *tail = b;
+                               break;
+                       }
                } else {
-                       tail->next = b;
+                       *tail = b;
+                       tail = &b->next;
                        b = b->next;
+                       if (!b) {
+                               *tail = a;
+                               break;
+                       }
                }
-               tail = tail->next;
        }
-       tail->next = a?:b;
-       return head.next;
+       return head;
 }
 
 /*
@@ -43,44 +51,52 @@ static struct list_head *merge(void *priv,
  * prev-link restoration pass, or maintaining the prev links
  * throughout.
  */
-static void merge_and_restore_back_links(void *priv,
-                               int (*cmp)(void *priv, struct list_head *a,
-                                       struct list_head *b),
-                               struct list_head *head,
-                               struct list_head *a, struct list_head *b)
+__attribute__((nonnull(2,3,4,5)))
+static void merge_final(void *priv, cmp_func cmp, struct list_head *head,
+                       struct list_head *a, struct list_head *b)
 {
        struct list_head *tail = head;
        u8 count = 0;
 
-       while (a && b) {
+       for (;;) {
                /* if equal, take 'a' -- important for sort stability */
-               if ((*cmp)(priv, a, b) <= 0) {
+               if (cmp(priv, a, b) <= 0) {
                        tail->next = a;
                        a->prev = tail;
+                       tail = a;
                        a = a->next;
+                       if (!a)
+                               break;
                } else {
                        tail->next = b;
                        b->prev = tail;
+                       tail = b;
                        b = b->next;
+                       if (!b) {
+                               b = a;
+                               break;
+                       }
                }
-               tail = tail->next;
        }
-       tail->next = a ? : b;
 
+       /* Finish linking remainder of list b on to tail */
+       tail->next = b;
        do {
                /*
-                * In worst cases this loop may run many iterations.
+                * If the merge is highly unbalanced (e.g. the input is
+                * already sorted), this loop may run many iterations.
                 * Continue callbacks to the client even though no
                 * element comparison is needed, so the client's cmp()
                 * routine can invoke cond_resched() periodically.
                 */
-               if (unlikely(!(++count)))
-                       (*cmp)(priv, tail->next, tail->next);
-
-               tail->next->prev = tail;
-               tail = tail->next;
-       } while (tail->next);
-
+               if (unlikely(!++count))
+                       cmp(priv, b, b);
+               b->prev = tail;
+               tail = b;
+               b = b->next;
+       } while (b);
+
+       /* And the final links to make a circular doubly-linked list */
        tail->next = head;
        head->prev = tail;
 }
@@ -91,55 +107,149 @@ static void merge_and_restore_back_links(void *priv,
  * @head: the list to sort
  * @cmp: the elements comparison function
  *
- * This function implements "merge sort", which has O(nlog(n))
- * complexity.
+ * The comparison funtion @cmp must return > 0 if @a should sort after
+ * @b ("@a > @b" if you want an ascending sort), and <= 0 if @a should
+ * sort before @b *or* their original order should be preserved.  It is
+ * always called with the element that came first in the input in @a,
+ * and list_sort is a stable sort, so it is not necessary to distinguish
+ * the @a < @b and @a == @b cases.
+ *
+ * This is compatible with two styles of @cmp function:
+ * - The traditional style which returns <0 / =0 / >0, or
+ * - Returning a boolean 0/1.
+ * The latter offers a chance to save a few cycles in the comparison
+ * (which is used by e.g. plug_ctx_cmp() in block/blk-mq.c).
+ *
+ * A good way to write a multi-word comparison is
+ *     if (a->high != b->high)
+ *             return a->high > b->high;
+ *     if (a->middle != b->middle)
+ *             return a->middle > b->middle;
+ *     return a->low > b->low;
+ *
+ *
+ * This mergesort is as eager as possible while always performing at least
+ * 2:1 balanced merges.  Given two pending sublists of size 2^k, they are
+ * merged to a size-2^(k+1) list as soon as we have 2^k following elements.
+ *
+ * Thus, it will avoid cache thrashing as long as 3*2^k elements can
+ * fit into the cache.  Not quite as good as a fully-eager bottom-up
+ * mergesort, but it does use 0.2*n fewer comparisons, so is faster in
+ * the common case that everything fits into L1.
+ *
+ *
+ * The merging is controlled by "count", the number of elements in the
+ * pending lists.  This is beautiully simple code, but rather subtle.
  *
- * The comparison function @cmp must return a negative value if @a
- * should sort before @b, and a positive value if @a should sort after
- * @b. If @a and @b are equivalent, and their original relative
- * ordering is to be preserved, @cmp must return 0.
+ * Each time we increment "count", we set one bit (bit k) and clear
+ * bits k-1 .. 0.  Each time this happens (except the very first time
+ * for each bit, when count increments to 2^k), we merge two lists of
+ * size 2^k into one list of size 2^(k+1).
+ *
+ * This merge happens exactly when the count reaches an odd multiple of
+ * 2^k, which is when we have 2^k elements pending in smaller lists,
+ * so it's safe to merge away two lists of size 2^k.
+ *
+ * After this happens twice, we have created two lists of size 2^(k+1),
+ * which will be merged into a list of size 2^(k+2) before we create
+ * a third list of size 2^(k+1), so there are never more than two pending.
+ *
+ * The number of pending lists of size 2^k is determined by the
+ * state of bit k of "count" plus two extra pieces of information:
+ * - The state of bit k-1 (when k == 0, consider bit -1 always set), and
+ * - Whether the higher-order bits are zero or non-zero (i.e.
+ *   is count >= 2^(k+1)).
+ * There are six states we distinguish.  "x" represents some arbitrary
+ * bits, and "y" represents some arbitrary non-zero bits:
+ * 0:  00x: 0 pending of size 2^k;           x pending of sizes < 2^k
+ * 1:  01x: 0 pending of size 2^k; 2^(k-1) + x pending of sizes < 2^k
+ * 2: x10x: 0 pending of size 2^k; 2^k     + x pending of sizes < 2^k
+ * 3: x11x: 1 pending of size 2^k; 2^(k-1) + x pending of sizes < 2^k
+ * 4: y00x: 1 pending of size 2^k; 2^k     + x pending of sizes < 2^k
+ * 5: y01x: 2 pending of size 2^k; 2^(k-1) + x pending of sizes < 2^k
+ * (merge and loop back to state 2)
+ *
+ * We gain lists of size 2^k in the 2->3 and 4->5 transitions (because
+ * bit k-1 is set while the more significant bits are non-zero) and
+ * merge them away in the 5->2 transition.  Note in particular that just
+ * before the 5->2 transition, all lower-order bits are 11 (state 3),
+ * so there is one list of each smaller size.
+ *
+ * When we reach the end of the input, we merge all the pending
+ * lists, from smallest to largest.  If you work through cases 2 to
+ * 5 above, you can see that the number of elements we merge with a list
+ * of size 2^k varies from 2^(k-1) (cases 3 and 5 when x == 0) to
+ * 2^(k+1) - 1 (second merge of case 5 when x == 2^(k-1) - 1).
  */
+__attribute__((nonnull(2,3)))
 void list_sort(void *priv, struct list_head *head,
                int (*cmp)(void *priv, struct list_head *a,
                        struct list_head *b))
 {
-       struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists
-                                               -- last slot is a sentinel */
-       int lev;  /* index into part[] */
-       int max_lev = 0;
-       struct list_head *list;
+       struct list_head *list = head->next, *pending = NULL;
+       size_t count = 0;       /* Count of pending */
 
-       if (list_empty(head))
+       if (list == head->prev) /* Zero or one elements */
                return;
 
-       memset(part, 0, sizeof(part));
-
+       /* Convert to a null-terminated singly-linked list. */
        head->prev->next = NULL;
-       list = head->next;
-
-       while (list) {
-               struct list_head *cur = list;
-               list = list->next;
-               cur->next = NULL;
 
-               for (lev = 0; part[lev]; lev++) {
-                       cur = merge(priv, cmp, part[lev], cur);
-                       part[lev] = NULL;
-               }
-               if (lev > max_lev) {
-                       if (unlikely(lev >= ARRAY_SIZE(part)-1)) {
-                               printk_once(KERN_DEBUG "list too long for efficiency\n");
-                               lev--;
-                       }
-                       max_lev = lev;
+       /*
+        * Data structure invariants:
+        * - All lists are singly linked and null-terminated; prev
+        *   pointers are not maintained.
+        * - pending is a prev-linked "list of lists" of sorted
+        *   sublists awaiting further merging.
+        * - Each of the sorted sublists is power-of-two in size.
+        * - Sublists are sorted by size and age, smallest & newest at front.
+        * - There are zero to two sublists of each size.
+        * - A pair of pending sublists are merged as soon as the number
+        *   of following pending elements equals their size (i.e.
+        *   each time count reaches an odd multiple of that size).
+        *   That ensures each later final merge will be at worst 2:1.
+        * - Each round consists of:
+        *   - Merging the two sublists selected by the highest bit
+        *     which flips when count is incremented, and
+        *   - Adding an element from the input as a size-1 sublist.
+        */
+       do {
+               size_t bits;
+               struct list_head **tail = &pending;
+
+               /* Find the least-significant clear bit in count */
+               for (bits = count; bits & 1; bits >>= 1)
+                       tail = &(*tail)->prev;
+               /* Do the indicated merge */
+               if (likely(bits)) {
+                       struct list_head *a = *tail, *b = a->prev;
+
+                       a = merge(priv, (cmp_func)cmp, b, a);
+                       /* Install the merged result in place of the inputs */
+                       a->prev = b->prev;
+                       *tail = a;
                }
-               part[lev] = cur;
-       }
 
-       for (lev = 0; lev < max_lev; lev++)
-               if (part[lev])
-                       list = merge(priv, cmp, part[lev], list);
-
-       merge_and_restore_back_links(priv, cmp, head, part[max_lev], list);
+               /* Move one element from input list to pending */
+               list->prev = pending;
+               pending = list;
+               list = list->next;
+               pending->next = NULL;
+               count++;
+       } while (list);
+
+       /* End of input; merge together all the pending lists. */
+       list = pending;
+       pending = pending->prev;
+       for (;;) {
+               struct list_head *next = pending->prev;
+
+               if (!next)
+                       break;
+               list = merge(priv, (cmp_func)cmp, pending, list);
+               pending = next;
+       }
+       /* The final merge, rebuilding prev links */
+       merge_final(priv, (cmp_func)cmp, head, pending, list);
 }
 EXPORT_SYMBOL(list_sort);
diff --git a/lib/math/Kconfig b/lib/math/Kconfig
new file mode 100644 (file)
index 0000000..73bdf37
--- /dev/null
@@ -0,0 +1,11 @@
+config CORDIC
+       tristate "CORDIC algorithm"
+       help
+         This option provides an implementation of the CORDIC algorithm;
+         calculations are in fixed point. Module will be called cordic.
+
+config PRIME_NUMBERS
+       tristate
+
+config RATIONAL
+       bool
diff --git a/lib/math/Makefile b/lib/math/Makefile
new file mode 100644 (file)
index 0000000..583bbfe
--- /dev/null
@@ -0,0 +1,5 @@
+obj-y += div64.o gcd.o lcm.o int_pow.o int_sqrt.o reciprocal_div.o
+
+obj-$(CONFIG_CORDIC)           += cordic.o
+obj-$(CONFIG_PRIME_NUMBERS)    += prime_numbers.o
+obj-$(CONFIG_RATIONAL)         += rational.o
diff --git a/lib/math/cordic.c b/lib/math/cordic.c
new file mode 100644 (file)
index 0000000..8ef27c1
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/module.h>
+#include <linux/cordic.h>
+
+static const s32 arctan_table[] = {
+       2949120,
+       1740967,
+       919879,
+       466945,
+       234379,
+       117304,
+       58666,
+       29335,
+       14668,
+       7334,
+       3667,
+       1833,
+       917,
+       458,
+       229,
+       115,
+       57,
+       29
+};
+
+/*
+ * cordic_calc_iq() - calculates the i/q coordinate for given angle
+ *
+ * theta: angle in degrees for which i/q coordinate is to be calculated
+ * coord: function output parameter holding the i/q coordinate
+ */
+struct cordic_iq cordic_calc_iq(s32 theta)
+{
+       struct cordic_iq coord;
+       s32 angle, valtmp;
+       unsigned iter;
+       int signx = 1;
+       int signtheta;
+
+       coord.i = CORDIC_ANGLE_GEN;
+       coord.q = 0;
+       angle = 0;
+
+       theta = CORDIC_FIXED(theta);
+       signtheta = (theta < 0) ? -1 : 1;
+       theta = ((theta + CORDIC_FIXED(180) * signtheta) % CORDIC_FIXED(360)) -
+               CORDIC_FIXED(180) * signtheta;
+
+       if (CORDIC_FLOAT(theta) > 90) {
+               theta -= CORDIC_FIXED(180);
+               signx = -1;
+       } else if (CORDIC_FLOAT(theta) < -90) {
+               theta += CORDIC_FIXED(180);
+               signx = -1;
+       }
+
+       for (iter = 0; iter < CORDIC_NUM_ITER; iter++) {
+               if (theta > angle) {
+                       valtmp = coord.i - (coord.q >> iter);
+                       coord.q += (coord.i >> iter);
+                       angle += arctan_table[iter];
+               } else {
+                       valtmp = coord.i + (coord.q >> iter);
+                       coord.q -= (coord.i >> iter);
+                       angle -= arctan_table[iter];
+               }
+               coord.i = valtmp;
+       }
+
+       coord.i *= signx;
+       coord.q *= signx;
+       return coord;
+}
+EXPORT_SYMBOL(cordic_calc_iq);
+
+MODULE_DESCRIPTION("CORDIC algorithm");
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/lib/math/div64.c b/lib/math/div64.c
new file mode 100644 (file)
index 0000000..368ca7f
--- /dev/null
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
+ *
+ * Based on former do_div() implementation from asm-parisc/div64.h:
+ *     Copyright (C) 1999 Hewlett-Packard Co
+ *     Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ *
+ * Generic C version of 64bit/32bit division and modulo, with
+ * 64bit result and 32bit remainder.
+ *
+ * The fast case for (n>>32 == 0) is handled inline by do_div().
+ *
+ * Code generated for this function might be very inefficient
+ * for some CPUs. __div64_32() can be overridden by linking arch-specific
+ * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S
+ * or by defining a preprocessor macro in arch/include/asm/div64.h.
+ */
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+
+/* Not needed on 64bit architectures */
+#if BITS_PER_LONG == 32
+
+#ifndef __div64_32
+uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
+{
+       uint64_t rem = *n;
+       uint64_t b = base;
+       uint64_t res, d = 1;
+       uint32_t high = rem >> 32;
+
+       /* Reduce the thing a bit first */
+       res = 0;
+       if (high >= base) {
+               high /= base;
+               res = (uint64_t) high << 32;
+               rem -= (uint64_t) (high*base) << 32;
+       }
+
+       while ((int64_t)b > 0 && b < rem) {
+               b = b+b;
+               d = d+d;
+       }
+
+       do {
+               if (rem >= b) {
+                       rem -= b;
+                       res += d;
+               }
+               b >>= 1;
+               d >>= 1;
+       } while (d);
+
+       *n = res;
+       return rem;
+}
+EXPORT_SYMBOL(__div64_32);
+#endif
+
+/**
+ * div_s64_rem - signed 64bit divide with 64bit divisor and remainder
+ * @dividend:  64bit dividend
+ * @divisor:   64bit divisor
+ * @remainder:  64bit remainder
+ */
+#ifndef div_s64_rem
+s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
+{
+       u64 quotient;
+
+       if (dividend < 0) {
+               quotient = div_u64_rem(-dividend, abs(divisor), (u32 *)remainder);
+               *remainder = -*remainder;
+               if (divisor > 0)
+                       quotient = -quotient;
+       } else {
+               quotient = div_u64_rem(dividend, abs(divisor), (u32 *)remainder);
+               if (divisor < 0)
+                       quotient = -quotient;
+       }
+       return quotient;
+}
+EXPORT_SYMBOL(div_s64_rem);
+#endif
+
+/**
+ * div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder
+ * @dividend:  64bit dividend
+ * @divisor:   64bit divisor
+ * @remainder:  64bit remainder
+ *
+ * This implementation is a comparable to algorithm used by div64_u64.
+ * But this operation, which includes math for calculating the remainder,
+ * is kept distinct to avoid slowing down the div64_u64 operation on 32bit
+ * systems.
+ */
+#ifndef div64_u64_rem
+u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
+{
+       u32 high = divisor >> 32;
+       u64 quot;
+
+       if (high == 0) {
+               u32 rem32;
+               quot = div_u64_rem(dividend, divisor, &rem32);
+               *remainder = rem32;
+       } else {
+               int n = fls(high);
+               quot = div_u64(dividend >> n, divisor >> n);
+
+               if (quot != 0)
+                       quot--;
+
+               *remainder = dividend - quot * divisor;
+               if (*remainder >= divisor) {
+                       quot++;
+                       *remainder -= divisor;
+               }
+       }
+
+       return quot;
+}
+EXPORT_SYMBOL(div64_u64_rem);
+#endif
+
+/**
+ * div64_u64 - unsigned 64bit divide with 64bit divisor
+ * @dividend:  64bit dividend
+ * @divisor:   64bit divisor
+ *
+ * This implementation is a modified version of the algorithm proposed
+ * by the book 'Hacker's Delight'.  The original source and full proof
+ * can be found here and is available for use without restriction.
+ *
+ * 'http://www.hackersdelight.org/hdcodetxt/divDouble.c.txt'
+ */
+#ifndef div64_u64
+u64 div64_u64(u64 dividend, u64 divisor)
+{
+       u32 high = divisor >> 32;
+       u64 quot;
+
+       if (high == 0) {
+               quot = div_u64(dividend, divisor);
+       } else {
+               int n = fls(high);
+               quot = div_u64(dividend >> n, divisor >> n);
+
+               if (quot != 0)
+                       quot--;
+               if ((dividend - quot * divisor) >= divisor)
+                       quot++;
+       }
+
+       return quot;
+}
+EXPORT_SYMBOL(div64_u64);
+#endif
+
+/**
+ * div64_s64 - signed 64bit divide with 64bit divisor
+ * @dividend:  64bit dividend
+ * @divisor:   64bit divisor
+ */
+#ifndef div64_s64
+s64 div64_s64(s64 dividend, s64 divisor)
+{
+       s64 quot, t;
+
+       quot = div64_u64(abs(dividend), abs(divisor));
+       t = (dividend ^ divisor) >> 63;
+
+       return (quot ^ t) - t;
+}
+EXPORT_SYMBOL(div64_s64);
+#endif
+
+#endif /* BITS_PER_LONG == 32 */
+
+/*
+ * Iterative div/mod for use when dividend is not expected to be much
+ * bigger than divisor.
+ */
+u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)
+{
+       return __iter_div_u64_rem(dividend, divisor, remainder);
+}
+EXPORT_SYMBOL(iter_div_u64_rem);
diff --git a/lib/math/gcd.c b/lib/math/gcd.c
new file mode 100644 (file)
index 0000000..7948ab2
--- /dev/null
@@ -0,0 +1,84 @@
+#include <linux/kernel.h>
+#include <linux/gcd.h>
+#include <linux/export.h>
+
+/*
+ * This implements the binary GCD algorithm. (Often attributed to Stein,
+ * but as Knuth has noted, appears in a first-century Chinese math text.)
+ *
+ * This is faster than the division-based algorithm even on x86, which
+ * has decent hardware division.
+ */
+
+#if !defined(CONFIG_CPU_NO_EFFICIENT_FFS)
+
+/* If __ffs is available, the even/odd algorithm benchmarks slower. */
+
+/**
+ * gcd - calculate and return the greatest common divisor of 2 unsigned longs
+ * @a: first value
+ * @b: second value
+ */
+unsigned long gcd(unsigned long a, unsigned long b)
+{
+       unsigned long r = a | b;
+
+       if (!a || !b)
+               return r;
+
+       b >>= __ffs(b);
+       if (b == 1)
+               return r & -r;
+
+       for (;;) {
+               a >>= __ffs(a);
+               if (a == 1)
+                       return r & -r;
+               if (a == b)
+                       return a << __ffs(r);
+
+               if (a < b)
+                       swap(a, b);
+               a -= b;
+       }
+}
+
+#else
+
+/* If normalization is done by loops, the even/odd algorithm is a win. */
+unsigned long gcd(unsigned long a, unsigned long b)
+{
+       unsigned long r = a | b;
+
+       if (!a || !b)
+               return r;
+
+       /* Isolate lsbit of r */
+       r &= -r;
+
+       while (!(b & r))
+               b >>= 1;
+       if (b == r)
+               return r;
+
+       for (;;) {
+               while (!(a & r))
+                       a >>= 1;
+               if (a == r)
+                       return r;
+               if (a == b)
+                       return a;
+
+               if (a < b)
+                       swap(a, b);
+               a -= b;
+               a >>= 1;
+               if (a & r)
+                       a += b;
+               a >>= 1;
+       }
+}
+
+#endif
+
+EXPORT_SYMBOL_GPL(gcd);
diff --git a/lib/math/int_pow.c b/lib/math/int_pow.c
new file mode 100644 (file)
index 0000000..622fc1a
--- /dev/null
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * An integer based power function
+ *
+ * Derived from drivers/video/backlight/pwm_bl.c
+ */
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+/**
+ * int_pow - computes the exponentiation of the given base and exponent
+ * @base: base which will be raised to the given power
+ * @exp: power to be raised to
+ *
+ * Computes: pow(base, exp), i.e. @base raised to the @exp power
+ */
+u64 int_pow(u64 base, unsigned int exp)
+{
+       u64 result = 1;
+
+       while (exp) {
+               if (exp & 1)
+                       result *= base;
+               exp >>= 1;
+               base *= base;
+       }
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(int_pow);
diff --git a/lib/math/int_sqrt.c b/lib/math/int_sqrt.c
new file mode 100644 (file)
index 0000000..30e0f97
--- /dev/null
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2013 Davidlohr Bueso <davidlohr.bueso@hp.com>
+ *
+ *  Based on the shift-and-subtract algorithm for computing integer
+ *  square root from Guy L. Steele.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/bitops.h>
+
+/**
+ * int_sqrt - computes the integer square root
+ * @x: integer of which to calculate the sqrt
+ *
+ * Computes: floor(sqrt(x))
+ */
+unsigned long int_sqrt(unsigned long x)
+{
+       unsigned long b, m, y = 0;
+
+       if (x <= 1)
+               return x;
+
+       m = 1UL << (__fls(x) & ~1UL);
+       while (m != 0) {
+               b = y + m;
+               y >>= 1;
+
+               if (x >= b) {
+                       x -= b;
+                       y += m;
+               }
+               m >>= 2;
+       }
+
+       return y;
+}
+EXPORT_SYMBOL(int_sqrt);
+
+#if BITS_PER_LONG < 64
+/**
+ * int_sqrt64 - strongly typed int_sqrt function when minimum 64 bit input
+ * is expected.
+ * @x: 64bit integer of which to calculate the sqrt
+ */
+u32 int_sqrt64(u64 x)
+{
+       u64 b, m, y = 0;
+
+       if (x <= ULONG_MAX)
+               return int_sqrt((unsigned long) x);
+
+       m = 1ULL << ((fls64(x) - 1) & ~1ULL);
+       while (m != 0) {
+               b = y + m;
+               y >>= 1;
+
+               if (x >= b) {
+                       x -= b;
+                       y += m;
+               }
+               m >>= 2;
+       }
+
+       return y;
+}
+EXPORT_SYMBOL(int_sqrt64);
+#endif
diff --git a/lib/math/lcm.c b/lib/math/lcm.c
new file mode 100644 (file)
index 0000000..03d7fcb
--- /dev/null
@@ -0,0 +1,25 @@
+#include <linux/compiler.h>
+#include <linux/gcd.h>
+#include <linux/export.h>
+#include <linux/lcm.h>
+
+/* Lowest common multiple */
+unsigned long lcm(unsigned long a, unsigned long b)
+{
+       if (a && b)
+               return (a / gcd(a, b)) * b;
+       else
+               return 0;
+}
+EXPORT_SYMBOL_GPL(lcm);
+
+unsigned long lcm_not_zero(unsigned long a, unsigned long b)
+{
+       unsigned long l = lcm(a, b);
+
+       if (l)
+               return l;
+
+       return (b ? : a);
+}
+EXPORT_SYMBOL_GPL(lcm_not_zero);
diff --git a/lib/math/prime_numbers.c b/lib/math/prime_numbers.c
new file mode 100644 (file)
index 0000000..550eec4
--- /dev/null
@@ -0,0 +1,315 @@
+#define pr_fmt(fmt) "prime numbers: " fmt "\n"
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/prime_numbers.h>
+#include <linux/slab.h>
+
+#define bitmap_size(nbits) (BITS_TO_LONGS(nbits) * sizeof(unsigned long))
+
+struct primes {
+       struct rcu_head rcu;
+       unsigned long last, sz;
+       unsigned long primes[];
+};
+
+#if BITS_PER_LONG == 64
+static const struct primes small_primes = {
+       .last = 61,
+       .sz = 64,
+       .primes = {
+               BIT(2) |
+               BIT(3) |
+               BIT(5) |
+               BIT(7) |
+               BIT(11) |
+               BIT(13) |
+               BIT(17) |
+               BIT(19) |
+               BIT(23) |
+               BIT(29) |
+               BIT(31) |
+               BIT(37) |
+               BIT(41) |
+               BIT(43) |
+               BIT(47) |
+               BIT(53) |
+               BIT(59) |
+               BIT(61)
+       }
+};
+#elif BITS_PER_LONG == 32
+static const struct primes small_primes = {
+       .last = 31,
+       .sz = 32,
+       .primes = {
+               BIT(2) |
+               BIT(3) |
+               BIT(5) |
+               BIT(7) |
+               BIT(11) |
+               BIT(13) |
+               BIT(17) |
+               BIT(19) |
+               BIT(23) |
+               BIT(29) |
+               BIT(31)
+       }
+};
+#else
+#error "unhandled BITS_PER_LONG"
+#endif
+
+static DEFINE_MUTEX(lock);
+static const struct primes __rcu *primes = RCU_INITIALIZER(&small_primes);
+
+static unsigned long selftest_max;
+
+static bool slow_is_prime_number(unsigned long x)
+{
+       unsigned long y = int_sqrt(x);
+
+       while (y > 1) {
+               if ((x % y) == 0)
+                       break;
+               y--;
+       }
+
+       return y == 1;
+}
+
+static unsigned long slow_next_prime_number(unsigned long x)
+{
+       while (x < ULONG_MAX && !slow_is_prime_number(++x))
+               ;
+
+       return x;
+}
+
+static unsigned long clear_multiples(unsigned long x,
+                                    unsigned long *p,
+                                    unsigned long start,
+                                    unsigned long end)
+{
+       unsigned long m;
+
+       m = 2 * x;
+       if (m < start)
+               m = roundup(start, x);
+
+       while (m < end) {
+               __clear_bit(m, p);
+               m += x;
+       }
+
+       return x;
+}
+
+static bool expand_to_next_prime(unsigned long x)
+{
+       const struct primes *p;
+       struct primes *new;
+       unsigned long sz, y;
+
+       /* Betrand's Postulate (or Chebyshev's theorem) states that if n > 3,
+        * there is always at least one prime p between n and 2n - 2.
+        * Equivalently, if n > 1, then there is always at least one prime p
+        * such that n < p < 2n.
+        *
+        * http://mathworld.wolfram.com/BertrandsPostulate.html
+        * https://en.wikipedia.org/wiki/Bertrand's_postulate
+        */
+       sz = 2 * x;
+       if (sz < x)
+               return false;
+
+       sz = round_up(sz, BITS_PER_LONG);
+       new = kmalloc(sizeof(*new) + bitmap_size(sz),
+                     GFP_KERNEL | __GFP_NOWARN);
+       if (!new)
+               return false;
+
+       mutex_lock(&lock);
+       p = rcu_dereference_protected(primes, lockdep_is_held(&lock));
+       if (x < p->last) {
+               kfree(new);
+               goto unlock;
+       }
+
+       /* Where memory permits, track the primes using the
+        * Sieve of Eratosthenes. The sieve is to remove all multiples of known
+        * primes from the set, what remains in the set is therefore prime.
+        */
+       bitmap_fill(new->primes, sz);
+       bitmap_copy(new->primes, p->primes, p->sz);
+       for (y = 2UL; y < sz; y = find_next_bit(new->primes, sz, y + 1))
+               new->last = clear_multiples(y, new->primes, p->sz, sz);
+       new->sz = sz;
+
+       BUG_ON(new->last <= x);
+
+       rcu_assign_pointer(primes, new);
+       if (p != &small_primes)
+               kfree_rcu((struct primes *)p, rcu);
+
+unlock:
+       mutex_unlock(&lock);
+       return true;
+}
+
+static void free_primes(void)
+{
+       const struct primes *p;
+
+       mutex_lock(&lock);
+       p = rcu_dereference_protected(primes, lockdep_is_held(&lock));
+       if (p != &small_primes) {
+               rcu_assign_pointer(primes, &small_primes);
+               kfree_rcu((struct primes *)p, rcu);
+       }
+       mutex_unlock(&lock);
+}
+
+/**
+ * next_prime_number - return the next prime number
+ * @x: the starting point for searching to test
+ *
+ * A prime number is an integer greater than 1 that is only divisible by
+ * itself and 1.  The set of prime numbers is computed using the Sieve of
+ * Eratoshenes (on finding a prime, all multiples of that prime are removed
+ * from the set) enabling a fast lookup of the next prime number larger than
+ * @x. If the sieve fails (memory limitation), the search falls back to using
+ * slow trial-divison, up to the value of ULONG_MAX (which is reported as the
+ * final prime as a sentinel).
+ *
+ * Returns: the next prime number larger than @x
+ */
+unsigned long next_prime_number(unsigned long x)
+{
+       const struct primes *p;
+
+       rcu_read_lock();
+       p = rcu_dereference(primes);
+       while (x >= p->last) {
+               rcu_read_unlock();
+
+               if (!expand_to_next_prime(x))
+                       return slow_next_prime_number(x);
+
+               rcu_read_lock();
+               p = rcu_dereference(primes);
+       }
+       x = find_next_bit(p->primes, p->last, x + 1);
+       rcu_read_unlock();
+
+       return x;
+}
+EXPORT_SYMBOL(next_prime_number);
+
+/**
+ * is_prime_number - test whether the given number is prime
+ * @x: the number to test
+ *
+ * A prime number is an integer greater than 1 that is only divisible by
+ * itself and 1. Internally a cache of prime numbers is kept (to speed up
+ * searching for sequential primes, see next_prime_number()), but if the number
+ * falls outside of that cache, its primality is tested using trial-divison.
+ *
+ * Returns: true if @x is prime, false for composite numbers.
+ */
+bool is_prime_number(unsigned long x)
+{
+       const struct primes *p;
+       bool result;
+
+       rcu_read_lock();
+       p = rcu_dereference(primes);
+       while (x >= p->sz) {
+               rcu_read_unlock();
+
+               if (!expand_to_next_prime(x))
+                       return slow_is_prime_number(x);
+
+               rcu_read_lock();
+               p = rcu_dereference(primes);
+       }
+       result = test_bit(x, p->primes);
+       rcu_read_unlock();
+
+       return result;
+}
+EXPORT_SYMBOL(is_prime_number);
+
+static void dump_primes(void)
+{
+       const struct primes *p;
+       char *buf;
+
+       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+       rcu_read_lock();
+       p = rcu_dereference(primes);
+
+       if (buf)
+               bitmap_print_to_pagebuf(true, buf, p->primes, p->sz);
+       pr_info("primes.{last=%lu, .sz=%lu, .primes[]=...x%lx} = %s",
+               p->last, p->sz, p->primes[BITS_TO_LONGS(p->sz) - 1], buf);
+
+       rcu_read_unlock();
+
+       kfree(buf);
+}
+
+static int selftest(unsigned long max)
+{
+       unsigned long x, last;
+
+       if (!max)
+               return 0;
+
+       for (last = 0, x = 2; x < max; x++) {
+               bool slow = slow_is_prime_number(x);
+               bool fast = is_prime_number(x);
+
+               if (slow != fast) {
+                       pr_err("inconsistent result for is-prime(%lu): slow=%s, fast=%s!",
+                              x, slow ? "yes" : "no", fast ? "yes" : "no");
+                       goto err;
+               }
+
+               if (!slow)
+                       continue;
+
+               if (next_prime_number(last) != x) {
+                       pr_err("incorrect result for next-prime(%lu): expected %lu, got %lu",
+                              last, x, next_prime_number(last));
+                       goto err;
+               }
+               last = x;
+       }
+
+       pr_info("selftest(%lu) passed, last prime was %lu", x, last);
+       return 0;
+
+err:
+       dump_primes();
+       return -EINVAL;
+}
+
+static int __init primes_init(void)
+{
+       return selftest(selftest_max);
+}
+
+static void __exit primes_exit(void)
+{
+       free_primes();
+}
+
+module_init(primes_init);
+module_exit(primes_exit);
+
+module_param_named(selftest, selftest_max, ulong, 0400);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL");
diff --git a/lib/math/rational.c b/lib/math/rational.c
new file mode 100644 (file)
index 0000000..ba74436
--- /dev/null
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rational fractions
+ *
+ * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <oskar@scara.com>
+ *
+ * helper functions when coping with rational numbers
+ */
+
+#include <linux/rational.h>
+#include <linux/compiler.h>
+#include <linux/export.h>
+
+/*
+ * calculate best rational approximation for a given fraction
+ * taking into account restricted register size, e.g. to find
+ * appropriate values for a pll with 5 bit denominator and
+ * 8 bit numerator register fields, trying to set up with a
+ * frequency ratio of 3.1415, one would say:
+ *
+ * rational_best_approximation(31415, 10000,
+ *             (1 << 8) - 1, (1 << 5) - 1, &n, &d);
+ *
+ * you may look at given_numerator as a fixed point number,
+ * with the fractional part size described in given_denominator.
+ *
+ * for theoretical background, see:
+ * http://en.wikipedia.org/wiki/Continued_fraction
+ */
+
+void rational_best_approximation(
+       unsigned long given_numerator, unsigned long given_denominator,
+       unsigned long max_numerator, unsigned long max_denominator,
+       unsigned long *best_numerator, unsigned long *best_denominator)
+{
+       unsigned long n, d, n0, d0, n1, d1;
+       n = given_numerator;
+       d = given_denominator;
+       n0 = d1 = 0;
+       n1 = d0 = 1;
+       for (;;) {
+               unsigned long t, a;
+               if ((n1 > max_numerator) || (d1 > max_denominator)) {
+                       n1 = n0;
+                       d1 = d0;
+                       break;
+               }
+               if (d == 0)
+                       break;
+               t = d;
+               a = n / d;
+               d = n % d;
+               n = t;
+               t = n0 + a * n1;
+               n0 = n1;
+               n1 = t;
+               t = d0 + a * d1;
+               d0 = d1;
+               d1 = t;
+       }
+       *best_numerator = n1;
+       *best_denominator = d1;
+}
+
+EXPORT_SYMBOL(rational_best_approximation);
diff --git a/lib/math/reciprocal_div.c b/lib/math/reciprocal_div.c
new file mode 100644 (file)
index 0000000..bf04325
--- /dev/null
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <asm/div64.h>
+#include <linux/reciprocal_div.h>
+#include <linux/export.h>
+
+/*
+ * For a description of the algorithm please have a look at
+ * include/linux/reciprocal_div.h
+ */
+
+struct reciprocal_value reciprocal_value(u32 d)
+{
+       struct reciprocal_value R;
+       u64 m;
+       int l;
+
+       l = fls(d - 1);
+       m = ((1ULL << 32) * ((1ULL << l) - d));
+       do_div(m, d);
+       ++m;
+       R.m = (u32)m;
+       R.sh1 = min(l, 1);
+       R.sh2 = max(l - 1, 0);
+
+       return R;
+}
+EXPORT_SYMBOL(reciprocal_value);
+
+struct reciprocal_value_adv reciprocal_value_adv(u32 d, u8 prec)
+{
+       struct reciprocal_value_adv R;
+       u32 l, post_shift;
+       u64 mhigh, mlow;
+
+       /* ceil(log2(d)) */
+       l = fls(d - 1);
+       /* NOTE: mlow/mhigh could overflow u64 when l == 32. This case needs to
+        * be handled before calling "reciprocal_value_adv", please see the
+        * comment at include/linux/reciprocal_div.h.
+        */
+       WARN(l == 32,
+            "ceil(log2(0x%08x)) == 32, %s doesn't support such divisor",
+            d, __func__);
+       post_shift = l;
+       mlow = 1ULL << (32 + l);
+       do_div(mlow, d);
+       mhigh = (1ULL << (32 + l)) + (1ULL << (32 + l - prec));
+       do_div(mhigh, d);
+
+       for (; post_shift > 0; post_shift--) {
+               u64 lo = mlow >> 1, hi = mhigh >> 1;
+
+               if (lo >= hi)
+                       break;
+
+               mlow = lo;
+               mhigh = hi;
+       }
+
+       R.m = (u32)mhigh;
+       R.sh = post_shift;
+       R.exp = l;
+       R.is_wide_m = mhigh > U32_MAX;
+
+       return R;
+}
+EXPORT_SYMBOL(reciprocal_value_adv);
index 199408f91057d527dcaafc2f054be51892819da5..d3bd8827186fe5446ec744f5e2dd8a21c59e2692 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/bug.h>
 #include <linux/plist.h>
 
-#ifdef CONFIG_DEBUG_PI_LIST
+#ifdef CONFIG_DEBUG_PLIST
 
 static struct plist_head test_head;
 
@@ -173,7 +173,7 @@ void plist_requeue(struct plist_node *node, struct plist_head *head)
        plist_check_head(head);
 }
 
-#ifdef CONFIG_DEBUG_PI_LIST
+#ifdef CONFIG_DEBUG_PLIST
 #include <linux/sched.h>
 #include <linux/sched/clock.h>
 #include <linux/module.h>
diff --git a/lib/prime_numbers.c b/lib/prime_numbers.c
deleted file mode 100644 (file)
index 550eec4..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-#define pr_fmt(fmt) "prime numbers: " fmt "\n"
-
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/prime_numbers.h>
-#include <linux/slab.h>
-
-#define bitmap_size(nbits) (BITS_TO_LONGS(nbits) * sizeof(unsigned long))
-
-struct primes {
-       struct rcu_head rcu;
-       unsigned long last, sz;
-       unsigned long primes[];
-};
-
-#if BITS_PER_LONG == 64
-static const struct primes small_primes = {
-       .last = 61,
-       .sz = 64,
-       .primes = {
-               BIT(2) |
-               BIT(3) |
-               BIT(5) |
-               BIT(7) |
-               BIT(11) |
-               BIT(13) |
-               BIT(17) |
-               BIT(19) |
-               BIT(23) |
-               BIT(29) |
-               BIT(31) |
-               BIT(37) |
-               BIT(41) |
-               BIT(43) |
-               BIT(47) |
-               BIT(53) |
-               BIT(59) |
-               BIT(61)
-       }
-};
-#elif BITS_PER_LONG == 32
-static const struct primes small_primes = {
-       .last = 31,
-       .sz = 32,
-       .primes = {
-               BIT(2) |
-               BIT(3) |
-               BIT(5) |
-               BIT(7) |
-               BIT(11) |
-               BIT(13) |
-               BIT(17) |
-               BIT(19) |
-               BIT(23) |
-               BIT(29) |
-               BIT(31)
-       }
-};
-#else
-#error "unhandled BITS_PER_LONG"
-#endif
-
-static DEFINE_MUTEX(lock);
-static const struct primes __rcu *primes = RCU_INITIALIZER(&small_primes);
-
-static unsigned long selftest_max;
-
-static bool slow_is_prime_number(unsigned long x)
-{
-       unsigned long y = int_sqrt(x);
-
-       while (y > 1) {
-               if ((x % y) == 0)
-                       break;
-               y--;
-       }
-
-       return y == 1;
-}
-
-static unsigned long slow_next_prime_number(unsigned long x)
-{
-       while (x < ULONG_MAX && !slow_is_prime_number(++x))
-               ;
-
-       return x;
-}
-
-static unsigned long clear_multiples(unsigned long x,
-                                    unsigned long *p,
-                                    unsigned long start,
-                                    unsigned long end)
-{
-       unsigned long m;
-
-       m = 2 * x;
-       if (m < start)
-               m = roundup(start, x);
-
-       while (m < end) {
-               __clear_bit(m, p);
-               m += x;
-       }
-
-       return x;
-}
-
-static bool expand_to_next_prime(unsigned long x)
-{
-       const struct primes *p;
-       struct primes *new;
-       unsigned long sz, y;
-
-       /* Betrand's Postulate (or Chebyshev's theorem) states that if n > 3,
-        * there is always at least one prime p between n and 2n - 2.
-        * Equivalently, if n > 1, then there is always at least one prime p
-        * such that n < p < 2n.
-        *
-        * http://mathworld.wolfram.com/BertrandsPostulate.html
-        * https://en.wikipedia.org/wiki/Bertrand's_postulate
-        */
-       sz = 2 * x;
-       if (sz < x)
-               return false;
-
-       sz = round_up(sz, BITS_PER_LONG);
-       new = kmalloc(sizeof(*new) + bitmap_size(sz),
-                     GFP_KERNEL | __GFP_NOWARN);
-       if (!new)
-               return false;
-
-       mutex_lock(&lock);
-       p = rcu_dereference_protected(primes, lockdep_is_held(&lock));
-       if (x < p->last) {
-               kfree(new);
-               goto unlock;
-       }
-
-       /* Where memory permits, track the primes using the
-        * Sieve of Eratosthenes. The sieve is to remove all multiples of known
-        * primes from the set, what remains in the set is therefore prime.
-        */
-       bitmap_fill(new->primes, sz);
-       bitmap_copy(new->primes, p->primes, p->sz);
-       for (y = 2UL; y < sz; y = find_next_bit(new->primes, sz, y + 1))
-               new->last = clear_multiples(y, new->primes, p->sz, sz);
-       new->sz = sz;
-
-       BUG_ON(new->last <= x);
-
-       rcu_assign_pointer(primes, new);
-       if (p != &small_primes)
-               kfree_rcu((struct primes *)p, rcu);
-
-unlock:
-       mutex_unlock(&lock);
-       return true;
-}
-
-static void free_primes(void)
-{
-       const struct primes *p;
-
-       mutex_lock(&lock);
-       p = rcu_dereference_protected(primes, lockdep_is_held(&lock));
-       if (p != &small_primes) {
-               rcu_assign_pointer(primes, &small_primes);
-               kfree_rcu((struct primes *)p, rcu);
-       }
-       mutex_unlock(&lock);
-}
-
-/**
- * next_prime_number - return the next prime number
- * @x: the starting point for searching to test
- *
- * A prime number is an integer greater than 1 that is only divisible by
- * itself and 1.  The set of prime numbers is computed using the Sieve of
- * Eratoshenes (on finding a prime, all multiples of that prime are removed
- * from the set) enabling a fast lookup of the next prime number larger than
- * @x. If the sieve fails (memory limitation), the search falls back to using
- * slow trial-divison, up to the value of ULONG_MAX (which is reported as the
- * final prime as a sentinel).
- *
- * Returns: the next prime number larger than @x
- */
-unsigned long next_prime_number(unsigned long x)
-{
-       const struct primes *p;
-
-       rcu_read_lock();
-       p = rcu_dereference(primes);
-       while (x >= p->last) {
-               rcu_read_unlock();
-
-               if (!expand_to_next_prime(x))
-                       return slow_next_prime_number(x);
-
-               rcu_read_lock();
-               p = rcu_dereference(primes);
-       }
-       x = find_next_bit(p->primes, p->last, x + 1);
-       rcu_read_unlock();
-
-       return x;
-}
-EXPORT_SYMBOL(next_prime_number);
-
-/**
- * is_prime_number - test whether the given number is prime
- * @x: the number to test
- *
- * A prime number is an integer greater than 1 that is only divisible by
- * itself and 1. Internally a cache of prime numbers is kept (to speed up
- * searching for sequential primes, see next_prime_number()), but if the number
- * falls outside of that cache, its primality is tested using trial-divison.
- *
- * Returns: true if @x is prime, false for composite numbers.
- */
-bool is_prime_number(unsigned long x)
-{
-       const struct primes *p;
-       bool result;
-
-       rcu_read_lock();
-       p = rcu_dereference(primes);
-       while (x >= p->sz) {
-               rcu_read_unlock();
-
-               if (!expand_to_next_prime(x))
-                       return slow_is_prime_number(x);
-
-               rcu_read_lock();
-               p = rcu_dereference(primes);
-       }
-       result = test_bit(x, p->primes);
-       rcu_read_unlock();
-
-       return result;
-}
-EXPORT_SYMBOL(is_prime_number);
-
-static void dump_primes(void)
-{
-       const struct primes *p;
-       char *buf;
-
-       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-
-       rcu_read_lock();
-       p = rcu_dereference(primes);
-
-       if (buf)
-               bitmap_print_to_pagebuf(true, buf, p->primes, p->sz);
-       pr_info("primes.{last=%lu, .sz=%lu, .primes[]=...x%lx} = %s",
-               p->last, p->sz, p->primes[BITS_TO_LONGS(p->sz) - 1], buf);
-
-       rcu_read_unlock();
-
-       kfree(buf);
-}
-
-static int selftest(unsigned long max)
-{
-       unsigned long x, last;
-
-       if (!max)
-               return 0;
-
-       for (last = 0, x = 2; x < max; x++) {
-               bool slow = slow_is_prime_number(x);
-               bool fast = is_prime_number(x);
-
-               if (slow != fast) {
-                       pr_err("inconsistent result for is-prime(%lu): slow=%s, fast=%s!",
-                              x, slow ? "yes" : "no", fast ? "yes" : "no");
-                       goto err;
-               }
-
-               if (!slow)
-                       continue;
-
-               if (next_prime_number(last) != x) {
-                       pr_err("incorrect result for next-prime(%lu): expected %lu, got %lu",
-                              last, x, next_prime_number(last));
-                       goto err;
-               }
-               last = x;
-       }
-
-       pr_info("selftest(%lu) passed, last prime was %lu", x, last);
-       return 0;
-
-err:
-       dump_primes();
-       return -EINVAL;
-}
-
-static int __init primes_init(void)
-{
-       return selftest(selftest_max);
-}
-
-static void __exit primes_exit(void)
-{
-       free_primes();
-}
-
-module_init(primes_init);
-module_exit(primes_exit);
-
-module_param_named(selftest, selftest_max, ulong, 0400);
-
-MODULE_AUTHOR("Intel Corporation");
-MODULE_LICENSE("GPL");
diff --git a/lib/rational.c b/lib/rational.c
deleted file mode 100644 (file)
index ba74436..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * rational fractions
- *
- * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <oskar@scara.com>
- *
- * helper functions when coping with rational numbers
- */
-
-#include <linux/rational.h>
-#include <linux/compiler.h>
-#include <linux/export.h>
-
-/*
- * calculate best rational approximation for a given fraction
- * taking into account restricted register size, e.g. to find
- * appropriate values for a pll with 5 bit denominator and
- * 8 bit numerator register fields, trying to set up with a
- * frequency ratio of 3.1415, one would say:
- *
- * rational_best_approximation(31415, 10000,
- *             (1 << 8) - 1, (1 << 5) - 1, &n, &d);
- *
- * you may look at given_numerator as a fixed point number,
- * with the fractional part size described in given_denominator.
- *
- * for theoretical background, see:
- * http://en.wikipedia.org/wiki/Continued_fraction
- */
-
-void rational_best_approximation(
-       unsigned long given_numerator, unsigned long given_denominator,
-       unsigned long max_numerator, unsigned long max_denominator,
-       unsigned long *best_numerator, unsigned long *best_denominator)
-{
-       unsigned long n, d, n0, d0, n1, d1;
-       n = given_numerator;
-       d = given_denominator;
-       n0 = d1 = 0;
-       n1 = d0 = 1;
-       for (;;) {
-               unsigned long t, a;
-               if ((n1 > max_numerator) || (d1 > max_denominator)) {
-                       n1 = n0;
-                       d1 = d0;
-                       break;
-               }
-               if (d == 0)
-                       break;
-               t = d;
-               a = n / d;
-               d = n % d;
-               n = t;
-               t = n0 + a * n1;
-               n0 = n1;
-               n1 = t;
-               t = d0 + a * d1;
-               d0 = d1;
-               d1 = t;
-       }
-       *best_numerator = n1;
-       *best_denominator = d1;
-}
-
-EXPORT_SYMBOL(rational_best_approximation);
diff --git a/lib/reciprocal_div.c b/lib/reciprocal_div.c
deleted file mode 100644 (file)
index bf04325..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/bug.h>
-#include <linux/kernel.h>
-#include <asm/div64.h>
-#include <linux/reciprocal_div.h>
-#include <linux/export.h>
-
-/*
- * For a description of the algorithm please have a look at
- * include/linux/reciprocal_div.h
- */
-
-struct reciprocal_value reciprocal_value(u32 d)
-{
-       struct reciprocal_value R;
-       u64 m;
-       int l;
-
-       l = fls(d - 1);
-       m = ((1ULL << 32) * ((1ULL << l) - d));
-       do_div(m, d);
-       ++m;
-       R.m = (u32)m;
-       R.sh1 = min(l, 1);
-       R.sh2 = max(l - 1, 0);
-
-       return R;
-}
-EXPORT_SYMBOL(reciprocal_value);
-
-struct reciprocal_value_adv reciprocal_value_adv(u32 d, u8 prec)
-{
-       struct reciprocal_value_adv R;
-       u32 l, post_shift;
-       u64 mhigh, mlow;
-
-       /* ceil(log2(d)) */
-       l = fls(d - 1);
-       /* NOTE: mlow/mhigh could overflow u64 when l == 32. This case needs to
-        * be handled before calling "reciprocal_value_adv", please see the
-        * comment at include/linux/reciprocal_div.h.
-        */
-       WARN(l == 32,
-            "ceil(log2(0x%08x)) == 32, %s doesn't support such divisor",
-            d, __func__);
-       post_shift = l;
-       mlow = 1ULL << (32 + l);
-       do_div(mlow, d);
-       mhigh = (1ULL << (32 + l)) + (1ULL << (32 + l - prec));
-       do_div(mhigh, d);
-
-       for (; post_shift > 0; post_shift--) {
-               u64 lo = mlow >> 1, hi = mhigh >> 1;
-
-               if (lo >= hi)
-                       break;
-
-               mlow = lo;
-               mhigh = hi;
-       }
-
-       R.m = (u32)mhigh;
-       R.sh = post_shift;
-       R.exp = l;
-       R.is_wide_m = mhigh > U32_MAX;
-
-       return R;
-}
-EXPORT_SYMBOL(reciprocal_value_adv);
index d6b7a202b0b648ea4b45bd1b979b2562dddbb8f1..50855ea8c2622b29bc77ade1555bff15b953b7a7 100644 (file)
@@ -1,8 +1,13 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * A fast, small, non-recursive O(nlog n) sort for the Linux kernel
+ * A fast, small, non-recursive O(n log n) sort for the Linux kernel
  *
- * Jan 23 2005  Matt Mackall <mpm@selenic.com>
+ * This performs n*log2(n) + 0.37*n + o(n) comparisons on average,
+ * and 1.5*n*log2(n) + O(n) in the (very contrived) worst case.
+ *
+ * Glibc qsort() manages n*log2(n) - 1.26*n for random inputs (1.63*n
+ * better) at the expense of stack usage and much larger code to avoid
+ * quicksort's O(n^2) worst case.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/export.h>
 #include <linux/sort.h>
 
-static int alignment_ok(const void *base, int align)
+/**
+ * is_aligned - is this pointer & size okay for word-wide copying?
+ * @base: pointer to data
+ * @size: size of each element
+ * @align: required alignment (typically 4 or 8)
+ *
+ * Returns true if elements can be copied using word loads and stores.
+ * The size must be a multiple of the alignment, and the base address must
+ * be if we do not have CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS.
+ *
+ * For some reason, gcc doesn't know to optimize "if (a & mask || b & mask)"
+ * to "if ((a | b) & mask)", so we do that by hand.
+ */
+__attribute_const__ __always_inline
+static bool is_aligned(const void *base, size_t size, unsigned char align)
 {
-       return IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ||
-               ((unsigned long)base & (align - 1)) == 0;
+       unsigned char lsbits = (unsigned char)size;
+
+       (void)base;
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+       lsbits |= (unsigned char)(uintptr_t)base;
+#endif
+       return (lsbits & (align - 1)) == 0;
 }
 
-static void u32_swap(void *a, void *b, int size)
+/**
+ * swap_words_32 - swap two elements in 32-bit chunks
+ * @a, @b: pointers to the elements
+ * @size: element size (must be a multiple of 4)
+ *
+ * Exchange the two objects in memory.  This exploits base+index addressing,
+ * which basically all CPUs have, to minimize loop overhead computations.
+ *
+ * For some reason, on x86 gcc 7.3.0 adds a redundant test of n at the
+ * bottom of the loop, even though the zero flag is stil valid from the
+ * subtract (since the intervening mov instructions don't alter the flags).
+ * Gcc 8.1.0 doesn't have that problem.
+ */
+static void swap_words_32(void *a, void *b, size_t n)
 {
-       u32 t = *(u32 *)a;
-       *(u32 *)a = *(u32 *)b;
-       *(u32 *)b = t;
+       do {
+               u32 t = *(u32 *)(a + (n -= 4));
+               *(u32 *)(a + n) = *(u32 *)(b + n);
+               *(u32 *)(b + n) = t;
+       } while (n);
 }
 
-static void u64_swap(void *a, void *b, int size)
+/**
+ * swap_words_64 - swap two elements in 64-bit chunks
+ * @a, @b: pointers to the elements
+ * @size: element size (must be a multiple of 8)
+ *
+ * Exchange the two objects in memory.  This exploits base+index
+ * addressing, which basically all CPUs have, to minimize loop overhead
+ * computations.
+ *
+ * We'd like to use 64-bit loads if possible.  If they're not, emulating
+ * one requires base+index+4 addressing which x86 has but most other
+ * processors do not.  If CONFIG_64BIT, we definitely have 64-bit loads,
+ * but it's possible to have 64-bit loads without 64-bit pointers (e.g.
+ * x32 ABI).  Are there any cases the kernel needs to worry about?
+ */
+static void swap_words_64(void *a, void *b, size_t n)
 {
-       u64 t = *(u64 *)a;
-       *(u64 *)a = *(u64 *)b;
-       *(u64 *)b = t;
+       do {
+#ifdef CONFIG_64BIT
+               u64 t = *(u64 *)(a + (n -= 8));
+               *(u64 *)(a + n) = *(u64 *)(b + n);
+               *(u64 *)(b + n) = t;
+#else
+               /* Use two 32-bit transfers to avoid base+index+4 addressing */
+               u32 t = *(u32 *)(a + (n -= 4));
+               *(u32 *)(a + n) = *(u32 *)(b + n);
+               *(u32 *)(b + n) = t;
+
+               t = *(u32 *)(a + (n -= 4));
+               *(u32 *)(a + n) = *(u32 *)(b + n);
+               *(u32 *)(b + n) = t;
+#endif
+       } while (n);
 }
 
-static void generic_swap(void *a, void *b, int size)
+/**
+ * swap_bytes - swap two elements a byte at a time
+ * @a, @b: pointers to the elements
+ * @size: element size
+ *
+ * This is the fallback if alignment doesn't allow using larger chunks.
+ */
+static void swap_bytes(void *a, void *b, size_t n)
 {
-       char t;
-
        do {
-               t = *(char *)a;
-               *(char *)a++ = *(char *)b;
-               *(char *)b++ = t;
-       } while (--size > 0);
+               char t = ((char *)a)[--n];
+               ((char *)a)[n] = ((char *)b)[n];
+               ((char *)b)[n] = t;
+       } while (n);
+}
+
+typedef void (*swap_func_t)(void *a, void *b, int size);
+
+/*
+ * The values are arbitrary as long as they can't be confused with
+ * a pointer, but small integers make for the smallest compare
+ * instructions.
+ */
+#define SWAP_WORDS_64 (swap_func_t)0
+#define SWAP_WORDS_32 (swap_func_t)1
+#define SWAP_BYTES    (swap_func_t)2
+
+/*
+ * The function pointer is last to make tail calls most efficient if the
+ * compiler decides not to inline this function.
+ */
+static void do_swap(void *a, void *b, size_t size, swap_func_t swap_func)
+{
+       if (swap_func == SWAP_WORDS_64)
+               swap_words_64(a, b, size);
+       else if (swap_func == SWAP_WORDS_32)
+               swap_words_32(a, b, size);
+       else if (swap_func == SWAP_BYTES)
+               swap_bytes(a, b, size);
+       else
+               swap_func(a, b, (int)size);
+}
+
+/**
+ * parent - given the offset of the child, find the offset of the parent.
+ * @i: the offset of the heap element whose parent is sought.  Non-zero.
+ * @lsbit: a precomputed 1-bit mask, equal to "size & -size"
+ * @size: size of each element
+ *
+ * In terms of array indexes, the parent of element j = @i/@size is simply
+ * (j-1)/2.  But when working in byte offsets, we can't use implicit
+ * truncation of integer divides.
+ *
+ * Fortunately, we only need one bit of the quotient, not the full divide.
+ * @size has a least significant bit.  That bit will be clear if @i is
+ * an even multiple of @size, and set if it's an odd multiple.
+ *
+ * Logically, we're doing "if (i & lsbit) i -= size;", but since the
+ * branch is unpredictable, it's done with a bit of clever branch-free
+ * code instead.
+ */
+__attribute_const__ __always_inline
+static size_t parent(size_t i, unsigned int lsbit, size_t size)
+{
+       i -= size;
+       i -= size & -(i & lsbit);
+       return i / 2;
 }
 
 /**
@@ -50,57 +175,78 @@ static void generic_swap(void *a, void *b, int size)
  * @cmp_func: pointer to comparison function
  * @swap_func: pointer to swap function or NULL
  *
- * This function does a heapsort on the given array. You may provide a
- * swap_func function optimized to your element type.
+ * This function does a heapsort on the given array.  You may provide
+ * a swap_func function if you need to do something more than a memory
+ * copy (e.g. fix up pointers or auxiliary data), but the built-in swap
+ * avoids a slow retpoline and so is significantly faster.
  *
  * Sorting time is O(n log n) both on average and worst-case. While
- * qsort is about 20% faster on average, it suffers from exploitable
+ * quicksort is slightly faster on average, it suffers from exploitable
  * O(n*n) worst-case behavior and extra memory requirements that make
  * it less suitable for kernel use.
  */
-
 void sort(void *base, size_t num, size_t size,
          int (*cmp_func)(const void *, const void *),
          void (*swap_func)(void *, void *, int size))
 {
        /* pre-scale counters for performance */
-       int i = (num/2 - 1) * size, n = num * size, c, r;
+       size_t n = num * size, a = (num/2) * size;
+       const unsigned int lsbit = size & -size;  /* Used to find parent */
+
+       if (!a)         /* num < 2 || size == 0 */
+               return;
 
        if (!swap_func) {
-               if (size == 4 && alignment_ok(base, 4))
-                       swap_func = u32_swap;
-               else if (size == 8 && alignment_ok(base, 8))
-                       swap_func = u64_swap;
+               if (is_aligned(base, size, 8))
+                       swap_func = SWAP_WORDS_64;
+               else if (is_aligned(base, size, 4))
+                       swap_func = SWAP_WORDS_32;
                else
-                       swap_func = generic_swap;
+                       swap_func = SWAP_BYTES;
        }
 
-       /* heapify */
-       for ( ; i >= 0; i -= size) {
-               for (r = i; r * 2 + size < n; r  = c) {
-                       c = r * 2 + size;
-                       if (c < n - size &&
-                                       cmp_func(base + c, base + c + size) < 0)
-                               c += size;
-                       if (cmp_func(base + r, base + c) >= 0)
-                               break;
-                       swap_func(base + r, base + c, size);
-               }
-       }
+       /*
+        * Loop invariants:
+        * 1. elements [a,n) satisfy the heap property (compare greater than
+        *    all of their children),
+        * 2. elements [n,num*size) are sorted, and
+        * 3. a <= b <= c <= d <= n (whenever they are valid).
+        */
+       for (;;) {
+               size_t b, c, d;
+
+               if (a)                  /* Building heap: sift down --a */
+                       a -= size;
+               else if (n -= size)     /* Sorting: Extract root to --n */
+                       do_swap(base, base + n, size, swap_func);
+               else                    /* Sort complete */
+                       break;
 
-       /* sort */
-       for (i = n - size; i > 0; i -= size) {
-               swap_func(base, base + i, size);
-               for (r = 0; r * 2 + size < i; r = c) {
-                       c = r * 2 + size;
-                       if (c < i - size &&
-                                       cmp_func(base + c, base + c + size) < 0)
-                               c += size;
-                       if (cmp_func(base + r, base + c) >= 0)
-                               break;
-                       swap_func(base + r, base + c, size);
+               /*
+                * Sift element at "a" down into heap.  This is the
+                * "bottom-up" variant, which significantly reduces
+                * calls to cmp_func(): we find the sift-down path all
+                * the way to the leaves (one compare per level), then
+                * backtrack to find where to insert the target element.
+                *
+                * Because elements tend to sift down close to the leaves,
+                * this uses fewer compares than doing two per level
+                * on the way down.  (A bit more than half as many on
+                * average, 3/4 worst-case.)
+                */
+               for (b = a; c = 2*b + size, (d = c + size) < n;)
+                       b = cmp_func(base + c, base + d) >= 0 ? c : d;
+               if (d == n)     /* Special case last leaf with no sibling */
+                       b = c;
+
+               /* Now backtrack from "b" to the correct location for "a" */
+               while (b != a && cmp_func(base + a, base + b) >= 0)
+                       b = parent(b, lsbit, size);
+               c = b;                  /* Where "a" belongs */
+               while (b != a) {        /* Shift it into place */
+                       b = parent(b, lsbit, size);
+                       do_swap(base + b, base + c, size, swap_func);
                }
        }
 }
-
 EXPORT_SYMBOL(sort);
index 792d90608052b02bdd2645e5534c14737b523b06..d3a501f2a81ac7c42402bf3830dc56a77781595d 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/printk.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/uaccess.h>
 
 #include "../tools/testing/selftests/kselftest_module.h"
 
@@ -226,7 +227,8 @@ static const unsigned long exp[] __initconst = {
        BITMAP_FROM_U64(0xffffffff),
        BITMAP_FROM_U64(0xfffffffe),
        BITMAP_FROM_U64(0x3333333311111111ULL),
-       BITMAP_FROM_U64(0xffffffff77777777ULL)
+       BITMAP_FROM_U64(0xffffffff77777777ULL),
+       BITMAP_FROM_U64(0),
 };
 
 static const unsigned long exp2[] __initconst = {
@@ -249,55 +251,93 @@ static const struct test_bitmap_parselist parselist_tests[] __initconst = {
        {0, "1-31:4/4",                 &exp[9 * step], 32, 0},
        {0, "0-31:1/4,32-63:2/4",       &exp[10 * step], 64, 0},
        {0, "0-31:3/4,32-63:4/4",       &exp[11 * step], 64, 0},
+       {0, "  ,,  0-31:3/4  ,, 32-63:4/4  ,,  ",       &exp[11 * step], 64, 0},
 
        {0, "0-31:1/4,32-63:2/4,64-95:3/4,96-127:4/4",  exp2, 128, 0},
 
        {0, "0-2047:128/256", NULL, 2048, PARSE_TIME},
 
+       {0, "",                         &exp[12 * step], 8, 0},
+       {0, "\n",                       &exp[12 * step], 8, 0},
+       {0, ",,  ,,  , ,  ,",           &exp[12 * step], 8, 0},
+       {0, " ,  ,,  , ,   ",           &exp[12 * step], 8, 0},
+       {0, " ,  ,,  , ,   \n",         &exp[12 * step], 8, 0},
+
        {-EINVAL, "-1", NULL, 8, 0},
        {-EINVAL, "-0", NULL, 8, 0},
        {-EINVAL, "10-1", NULL, 8, 0},
        {-EINVAL, "0-31:", NULL, 8, 0},
        {-EINVAL, "0-31:0", NULL, 8, 0},
+       {-EINVAL, "0-31:0/", NULL, 8, 0},
        {-EINVAL, "0-31:0/0", NULL, 8, 0},
        {-EINVAL, "0-31:1/0", NULL, 8, 0},
        {-EINVAL, "0-31:10/1", NULL, 8, 0},
+       {-EOVERFLOW, "0-98765432123456789:10/1", NULL, 8, 0},
+
+       {-EINVAL, "a-31", NULL, 8, 0},
+       {-EINVAL, "0-a1", NULL, 8, 0},
+       {-EINVAL, "a-31:10/1", NULL, 8, 0},
+       {-EINVAL, "0-31:a/1", NULL, 8, 0},
+       {-EINVAL, "0-\n", NULL, 8, 0},
 };
 
-static void __init test_bitmap_parselist(void)
+static void __init __test_bitmap_parselist(int is_user)
 {
        int i;
        int err;
-       cycles_t cycles;
+       ktime_t time;
        DECLARE_BITMAP(bmap, 2048);
+       char *mode = is_user ? "_user"  : "";
 
        for (i = 0; i < ARRAY_SIZE(parselist_tests); i++) {
 #define ptest parselist_tests[i]
 
-               cycles = get_cycles();
-               err = bitmap_parselist(ptest.in, bmap, ptest.nbits);
-               cycles = get_cycles() - cycles;
+               if (is_user) {
+                       mm_segment_t orig_fs = get_fs();
+                       size_t len = strlen(ptest.in);
+
+                       set_fs(KERNEL_DS);
+                       time = ktime_get();
+                       err = bitmap_parselist_user(ptest.in, len,
+                                                   bmap, ptest.nbits);
+                       time = ktime_get() - time;
+                       set_fs(orig_fs);
+               } else {
+                       time = ktime_get();
+                       err = bitmap_parselist(ptest.in, bmap, ptest.nbits);
+                       time = ktime_get() - time;
+               }
 
                if (err != ptest.errno) {
-                       pr_err("test %d: input is %s, errno is %d, expected %d\n",
-                                       i, ptest.in, err, ptest.errno);
+                       pr_err("parselist%s: %d: input is %s, errno is %d, expected %d\n",
+                                       mode, i, ptest.in, err, ptest.errno);
                        continue;
                }
 
                if (!err && ptest.expected
                         && !__bitmap_equal(bmap, ptest.expected, ptest.nbits)) {
-                       pr_err("test %d: input is %s, result is 0x%lx, expected 0x%lx\n",
-                                       i, ptest.in, bmap[0], *ptest.expected);
+                       pr_err("parselist%s: %d: input is %s, result is 0x%lx, expected 0x%lx\n",
+                                       mode, i, ptest.in, bmap[0],
+                                       *ptest.expected);
                        continue;
                }
 
                if (ptest.flags & PARSE_TIME)
-                       pr_err("test %d: input is '%s' OK, Time: %llu\n",
-                                       i, ptest.in,
-                                       (unsigned long long)cycles);
+                       pr_err("parselist%s: %d: input is '%s' OK, Time: %llu\n",
+                                       mode, i, ptest.in, time);
        }
 }
 
+static void __init test_bitmap_parselist(void)
+{
+       __test_bitmap_parselist(0);
+}
+
+static void __init test_bitmap_parselist_user(void)
+{
+       __test_bitmap_parselist(1);
+}
+
 #define EXP_BYTES      (sizeof(exp) * 8)
 
 static void __init test_bitmap_arr32(void)
@@ -370,6 +410,7 @@ static void __init selftest(void)
        test_copy();
        test_bitmap_arr32();
        test_bitmap_parselist();
+       test_bitmap_parselist_user();
        test_mem_optimisations();
 }
 
index 3dd801c1c85b3ce179b44968cb9fe33f5ee45c30..566dad3f419601165bc32e71f2f2a580afbc3c8c 100644 (file)
@@ -47,6 +47,9 @@ struct test_sysctl_data {
        unsigned int uint_0001;
 
        char string_0001[65];
+
+#define SYSCTL_TEST_BITMAP_SIZE        65536
+       unsigned long *bitmap_0001;
 };
 
 static struct test_sysctl_data test_data = {
@@ -102,6 +105,13 @@ static struct ctl_table test_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dostring,
        },
+       {
+               .procname       = "bitmap_0001",
+               .data           = &test_data.bitmap_0001,
+               .maxlen         = SYSCTL_TEST_BITMAP_SIZE,
+               .mode           = 0644,
+               .proc_handler   = proc_do_large_bitmap,
+       },
        { }
 };
 
@@ -129,15 +139,21 @@ static struct ctl_table_header *test_sysctl_header;
 
 static int __init test_sysctl_init(void)
 {
+       test_data.bitmap_0001 = kzalloc(SYSCTL_TEST_BITMAP_SIZE/8, GFP_KERNEL);
+       if (!test_data.bitmap_0001)
+               return -ENOMEM;
        test_sysctl_header = register_sysctl_table(test_sysctl_root_table);
-       if (!test_sysctl_header)
+       if (!test_sysctl_header) {
+               kfree(test_data.bitmap_0001);
                return -ENOMEM;
+       }
        return 0;
 }
 late_initcall(test_sysctl_init);
 
 static void __exit test_sysctl_exit(void)
 {
+       kfree(test_data.bitmap_0001);
        if (test_sysctl_header)
                unregister_sysctl_table(test_sysctl_header);
 }
index f832b095afba011293b6a3da18a2170b55501325..8bbefcaddfe843f65dae4fcd7ac77867fc53eb18 100644 (file)
@@ -384,12 +384,11 @@ static int test_func(void *private)
 {
        struct test_driver *t = private;
        int random_array[ARRAY_SIZE(test_case_array)];
-       int index, i, j, ret;
+       int index, i, j;
        ktime_t kt;
        u64 delta;
 
-       ret = set_cpus_allowed_ptr(current, cpumask_of(t->cpu));
-       if (ret < 0)
+       if (set_cpus_allowed_ptr(current, cpumask_of(t->cpu)) < 0)
                pr_err("Failed to set affinity to %d CPU\n", t->cpu);
 
        for (i = 0; i < ARRAY_SIZE(test_case_array); i++)
@@ -415,8 +414,7 @@ static int test_func(void *private)
 
                kt = ktime_get();
                for (j = 0; j < test_repeat_count; j++) {
-                       ret = test_case_array[index].test_func();
-                       if (!ret)
+                       if (!test_case_array[index].test_func())
                                per_cpu_test_data[t->cpu][index].test_passed++;
                        else
                                per_cpu_test_data[t->cpu][index].test_failed++;
index 7b0a6140bfad917bff73d4bbfdf125e5de63a6be..2f003cfe340ec55d0a8e96309b02fd6326b1af1e 100644 (file)
@@ -628,19 +628,16 @@ static char *error_string(char *buf, char *end, const char *s,
 }
 
 /*
- * This is not a fool-proof test. 99% of the time that this will fault is
- * due to a bad pointer, not one that crosses into bad memory. Just test
- * the address to make sure it doesn't fault due to a poorly added printk
- * during debugging.
+ * Do not call any complex external code here. Nested printk()/vsprintf()
+ * might cause infinite loops. Failures might break printk() and would
+ * be hard to debug.
  */
 static const char *check_pointer_msg(const void *ptr)
 {
-       char byte;
-
        if (!ptr)
                return "(null)";
 
-       if (probe_kernel_address(ptr, byte))
+       if ((unsigned long)ptr < PAGE_SIZE || IS_ERR_VALUE(ptr))
                return "(efault)";
 
        return NULL;
index 25c71eb8a7dbd9170f29cdbca9d273d02afb1cf3..ee8d1f311858833c56ffd96b6f61f0d5d1b9740b 100644 (file)
@@ -11,23 +11,24 @@ choice
        default DISCONTIGMEM_MANUAL if ARCH_DISCONTIGMEM_DEFAULT
        default SPARSEMEM_MANUAL if ARCH_SPARSEMEM_DEFAULT
        default FLATMEM_MANUAL
+       help
+         This option allows you to change some of the ways that
+         Linux manages its memory internally. Most users will
+         only have one option here selected by the architecture
+         configuration. This is normal.
 
 config FLATMEM_MANUAL
        bool "Flat Memory"
        depends on !(ARCH_DISCONTIGMEM_ENABLE || ARCH_SPARSEMEM_ENABLE) || ARCH_FLATMEM_ENABLE
        help
-         This option allows you to change some of the ways that
-         Linux manages its memory internally.  Most users will
-         only have one option here: FLATMEM.  This is normal
-         and a correct option.
-
-         Some users of more advanced features like NUMA and
-         memory hotplug may have different options here.
-         DISCONTIGMEM is a more mature, better tested system,
-         but is incompatible with memory hotplug and may suffer
-         decreased performance over SPARSEMEM.  If unsure between
-         "Sparse Memory" and "Discontiguous Memory", choose
-         "Discontiguous Memory".
+         This option is best suited for non-NUMA systems with
+         flat address space. The FLATMEM is the most efficient
+         system in terms of performance and resource consumption
+         and it is the best option for smaller systems.
+
+         For systems that have holes in their physical address
+         spaces and for features like NUMA and memory hotplug,
+         choose "Sparse Memory"
 
          If unsure, choose this option (Flat Memory) over any other.
 
@@ -38,29 +39,26 @@ config DISCONTIGMEM_MANUAL
          This option provides enhanced support for discontiguous
          memory systems, over FLATMEM.  These systems have holes
          in their physical address spaces, and this option provides
-         more efficient handling of these holes.  However, the vast
-         majority of hardware has quite flat address spaces, and
-         can have degraded performance from the extra overhead that
-         this option imposes.
+         more efficient handling of these holes.
 
-         Many NUMA configurations will have this as the only option.
+         Although "Discontiguous Memory" is still used by several
+         architectures, it is considered deprecated in favor of
+         "Sparse Memory".
 
-         If unsure, choose "Flat Memory" over this option.
+         If unsure, choose "Sparse Memory" over this option.
 
 config SPARSEMEM_MANUAL
        bool "Sparse Memory"
        depends on ARCH_SPARSEMEM_ENABLE
        help
          This will be the only option for some systems, including
-         memory hotplug systems.  This is normal.
+         memory hot-plug systems.  This is normal.
 
-         For many other systems, this will be an alternative to
-         "Discontiguous Memory".  This option provides some potential
-         performance benefits, along with decreased code complexity,
-         but it is newer, and more experimental.
+         This option provides efficient support for systems with
+         holes is their physical address space and allows memory
+         hot-plug and hot-remove.
 
-         If unsure, choose "Discontiguous Memory" or "Flat Memory"
-         over this option.
+         If unsure, choose "Flat Memory" over this option.
 
 endchoice
 
@@ -136,7 +134,7 @@ config HAVE_MEMBLOCK_PHYS_MAP
 config HAVE_GENERIC_GUP
        bool
 
-config ARCH_DISCARD_MEMBLOCK
+config ARCH_KEEP_MEMBLOCK
        bool
 
 config MEMORY_ISOLATION
@@ -161,7 +159,6 @@ config MEMORY_HOTPLUG_SPARSE
 
 config MEMORY_HOTPLUG_DEFAULT_ONLINE
         bool "Online the newly added memory blocks by default"
-        default n
         depends on MEMORY_HOTPLUG
         help
          This option sets the default policy setting for memory hotplug
@@ -258,6 +255,9 @@ config ARCH_ENABLE_HUGEPAGE_MIGRATION
 config ARCH_ENABLE_THP_MIGRATION
        bool
 
+config CONTIG_ALLOC
+       def_bool (MEMORY_ISOLATION && COMPACTION) || CMA
+
 config PHYS_ADDR_T_64BIT
        def_bool 64BIT
 
@@ -436,7 +436,6 @@ config NEED_PER_CPU_KM
 
 config CLEANCACHE
        bool "Enable cleancache driver to cache clean pages if tmem is present"
-       default n
        help
          Cleancache can be thought of as a page-granularity victim cache
          for clean pages that the kernel's pageframe replacement algorithm
@@ -460,7 +459,6 @@ config CLEANCACHE
 config FRONTSWAP
        bool "Enable frontswap to cache swap pages if tmem is present"
        depends on SWAP
-       default n
        help
          Frontswap is so named because it can be thought of as the opposite
          of a "backing" store for a swap device.  The data is stored into
@@ -532,7 +530,6 @@ config ZSWAP
        depends on FRONTSWAP && CRYPTO=y
        select CRYPTO_LZO
        select ZPOOL
-       default n
        help
          A lightweight compressed cache for swap pages.  It takes
          pages that are in the process of being swapped out and attempts to
@@ -549,14 +546,12 @@ config ZSWAP
 
 config ZPOOL
        tristate "Common API for compressed memory storage"
-       default n
        help
          Compressed memory storage API.  This allows using either zbud or
          zsmalloc.
 
 config ZBUD
        tristate "Low (Up to 2x) density storage for compressed pages"
-       default n
        help
          A special purpose allocator for storing compressed pages.
          It is designed to store up to two compressed pages per physical
@@ -567,7 +562,6 @@ config ZBUD
 config Z3FOLD
        tristate "Up to 3x density storage for compressed pages"
        depends on ZPOOL
-       default n
        help
          A special purpose allocator for storing compressed pages.
          It is designed to store up to three compressed pages per physical
@@ -577,7 +571,6 @@ config Z3FOLD
 config ZSMALLOC
        tristate "Memory allocator for compressed pages"
        depends on MMU
-       default n
        help
          zsmalloc is a slab-based memory allocator designed to store
          compressed RAM pages.  zsmalloc uses virtual memory mapping
@@ -628,7 +621,6 @@ config MAX_STACK_SIZE_MB
 
 config DEFERRED_STRUCT_PAGE_INIT
        bool "Defer initialisation of struct pages to kthreads"
-       default n
        depends on SPARSEMEM
        depends on !NEED_PER_CPU_KM
        depends on 64BIT
@@ -676,6 +668,22 @@ config ZONE_DEVICE
 
          If FS_DAX is enabled, then say Y.
 
+config ARCH_HAS_HMM_MIRROR
+       bool
+       default y
+       depends on (X86_64 || PPC64)
+       depends on MMU && 64BIT
+
+config ARCH_HAS_HMM_DEVICE
+       bool
+       default y
+       depends on (X86_64 || PPC64)
+       depends on MEMORY_HOTPLUG
+       depends on MEMORY_HOTREMOVE
+       depends on SPARSEMEM_VMEMMAP
+       depends on ARCH_HAS_ZONE_DEVICE
+       select XARRAY_MULTI
+
 config ARCH_HAS_HMM
        bool
        default y
@@ -694,12 +702,12 @@ config DEV_PAGEMAP_OPS
 
 config HMM
        bool
+       select MMU_NOTIFIER
        select MIGRATE_VMA_HELPER
 
 config HMM_MIRROR
        bool "HMM mirror CPU page table into a device page table"
        depends on ARCH_HAS_HMM
-       select MMU_NOTIFIER
        select HMM
        help
          Select HMM_MIRROR if you want to mirror range of the CPU page table of a
@@ -740,7 +748,6 @@ config ARCH_HAS_PKEYS
 
 config PERCPU_STATS
        bool "Collect percpu memory statistics"
-       default n
        help
          This feature collects and exposes statistics via debugfs. The
          information includes global and per chunk statistics, which can
@@ -748,7 +755,6 @@ config PERCPU_STATS
 
 config GUP_BENCHMARK
        bool "Enable infrastructure for get_user_pages_fast() benchmarking"
-       default n
        help
          Provides /sys/kernel/debug/gup_benchmark that helps with testing
          performance of get_user_pages_fast().
index e3df921208c0d81edd6d9a981ffc010bc4eea072..e980ceb775a44a59b8d285ef28df5fb61f69b8e6 100644 (file)
@@ -33,7 +33,6 @@ config DEBUG_PAGEALLOC
 
 config DEBUG_PAGEALLOC_ENABLE_DEFAULT
        bool "Enable debug page memory allocations by default?"
-       default n
        depends on DEBUG_PAGEALLOC
        ---help---
          Enable debug page memory allocations by default? This value
index d210cc9d6f800711a08523d364ecfa42431cdf39..ac5e5ba78874661445a3cd8854f7c15844904914 100644 (file)
@@ -33,7 +33,7 @@ mmu-$(CONFIG_MMU)     += process_vm_access.o
 endif
 
 obj-y                  := filemap.o mempool.o oom_kill.o fadvise.o \
-                          maccess.o page_alloc.o page-writeback.o \
+                          maccess.o page-writeback.o \
                           readahead.o swap.o truncate.o vmscan.o shmem.o \
                           util.o mmzone.o vmstat.o backing-dev.o \
                           mm_init.o mmu_context.o percpu.o slab_common.o \
@@ -41,6 +41,11 @@ obj-y                        := filemap.o mempool.o oom_kill.o fadvise.o \
                           interval_tree.o list_lru.o workingset.o \
                           debug.o $(mmu-y)
 
+# Give 'page_alloc' its own module-parameter namespace
+page-alloc-y := page_alloc.o
+page-alloc-$(CONFIG_SHUFFLE_PAGE_ALLOCATOR) += shuffle.o
+
+obj-y += page-alloc.o
 obj-y += init-mm.o
 obj-y += memblock.o
 
index bb2d333ffcb3128db361fbe6053818e5db677170..5e36d7418031cad51bad0864dae3412f7bc8b783 100644 (file)
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -106,8 +106,10 @@ static int __init cma_activate_area(struct cma *cma)
 
        cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
 
-       if (!cma->bitmap)
+       if (!cma->bitmap) {
+               cma->count = 0;
                return -ENOMEM;
+       }
 
        WARN_ON_ONCE(!pfn_valid(pfn));
        zone = page_zone(pfn_to_page(pfn));
@@ -367,23 +369,26 @@ err:
 #ifdef CONFIG_CMA_DEBUG
 static void cma_debug_show_areas(struct cma *cma)
 {
-       unsigned long next_zero_bit, next_set_bit;
+       unsigned long next_zero_bit, next_set_bit, nr_zero;
        unsigned long start = 0;
-       unsigned int nr_zero, nr_total = 0;
+       unsigned long nr_part, nr_total = 0;
+       unsigned long nbits = cma_bitmap_maxno(cma);
 
        mutex_lock(&cma->lock);
        pr_info("number of available pages: ");
        for (;;) {
-               next_zero_bit = find_next_zero_bit(cma->bitmap, cma->count, start);
-               if (next_zero_bit >= cma->count)
+               next_zero_bit = find_next_zero_bit(cma->bitmap, nbits, start);
+               if (next_zero_bit >= nbits)
                        break;
-               next_set_bit = find_next_bit(cma->bitmap, cma->count, next_zero_bit);
+               next_set_bit = find_next_bit(cma->bitmap, nbits, next_zero_bit);
                nr_zero = next_set_bit - next_zero_bit;
-               pr_cont("%s%u@%lu", nr_total ? "+" : "", nr_zero, next_zero_bit);
-               nr_total += nr_zero;
+               nr_part = nr_zero << cma->order_per_bit;
+               pr_cont("%s%lu@%lu", nr_total ? "+" : "", nr_part,
+                       next_zero_bit);
+               nr_total += nr_part;
                start = next_zero_bit + nr_zero;
        }
-       pr_cont("=> %u free of %lu total pages\n", nr_total, cma->count);
+       pr_cont("=> %lu free of %lu total pages\n", nr_total, cma->count);
        mutex_unlock(&cma->lock);
 }
 #else
index 8d7b2fd5222599a4045608e0b9b499eb91deb51f..a7dd9e8e10d5da4c914e9eebff27e42b3b0e9652 100644 (file)
@@ -56,7 +56,7 @@ static int cma_maxchunk_get(void *data, u64 *val)
        mutex_lock(&cma->lock);
        for (;;) {
                start = find_next_zero_bit(cma->bitmap, bitmap_maxno, end);
-               if (start >= cma->count)
+               if (start >= bitmap_maxno)
                        break;
                end = find_next_bit(cma->bitmap, bitmap_maxno, start);
                maxchunk = max(end - start, maxchunk);
index 3319e0872d014628a6e505fc80d9daeb8d8a2b47..cbac7277978ace1beb6a71a44ccfec09c6c386c2 100644 (file)
@@ -1164,7 +1164,9 @@ static bool suitable_migration_target(struct compact_control *cc,
 static inline unsigned int
 freelist_scan_limit(struct compact_control *cc)
 {
-       return (COMPACT_CLUSTER_MAX >> cc->fast_search_fail) + 1;
+       unsigned short shift = BITS_PER_LONG - 1;
+
+       return (COMPACT_CLUSTER_MAX >> min(shift, cc->fast_search_fail)) + 1;
 }
 
 /*
@@ -1886,13 +1888,13 @@ static enum compact_result __compact_finished(struct compact_control *cc)
                bool can_steal;
 
                /* Job done if page is free of the right migratetype */
-               if (!list_empty(&area->free_list[migratetype]))
+               if (!free_area_empty(area, migratetype))
                        return COMPACT_SUCCESS;
 
 #ifdef CONFIG_CMA
                /* MIGRATE_MOVABLE can fallback on MIGRATE_CMA */
                if (migratetype == MIGRATE_MOVABLE &&
-                       !list_empty(&area->free_list[MIGRATE_CMA]))
+                       !free_area_empty(area, MIGRATE_CMA))
                        return COMPACT_SUCCESS;
 #endif
                /*
index eee9c221280c07c22eec9c33845ec2edf003faf1..8345bb6e47699d52fe1c19976b46312fecd25c1f 100644 (file)
@@ -67,7 +67,7 @@ void __dump_page(struct page *page, const char *reason)
         */
        mapcount = PageSlab(page) ? 0 : page_mapcount(page);
 
-       pr_warn("page:%px count:%d mapcount:%d mapping:%px index:%#lx",
+       pr_warn("page:%px refcount:%d mapcount:%d mapping:%px index:%#lx",
                  page, page_ref_count(page), mapcount,
                  page->mapping, page_to_pgoff(page));
        if (PageCompound(page))
index d78f577baef2a17d1d525673d4e6519f4e950fbc..c5af80c43d367305fc86ed7f4719e0e28a5ed146 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/pagemap.h>
 #include <linux/file.h>
 #include <linux/uio.h>
+#include <linux/error-injection.h>
 #include <linux/hash.h>
 #include <linux/writeback.h>
 #include <linux/backing-dev.h>
@@ -279,11 +280,11 @@ EXPORT_SYMBOL(delete_from_page_cache);
  * @pvec: pagevec with pages to delete
  *
  * The function walks over mapping->i_pages and removes pages passed in @pvec
- * from the mapping. The function expects @pvec to be sorted by page index.
+ * from the mapping. The function expects @pvec to be sorted by page index
+ * and is optimised for it to be dense.
  * It tolerates holes in @pvec (mapping entries at those indices are not
  * modified). The function expects only THP head pages to be present in the
- * @pvec and takes care to delete all corresponding tail pages from the
- * mapping as well.
+ * @pvec.
  *
  * The function expects the i_pages lock to be held.
  */
@@ -292,40 +293,44 @@ static void page_cache_delete_batch(struct address_space *mapping,
 {
        XA_STATE(xas, &mapping->i_pages, pvec->pages[0]->index);
        int total_pages = 0;
-       int i = 0, tail_pages = 0;
+       int i = 0;
        struct page *page;
 
        mapping_set_update(&xas, mapping);
        xas_for_each(&xas, page, ULONG_MAX) {
-               if (i >= pagevec_count(pvec) && !tail_pages)
+               if (i >= pagevec_count(pvec))
                        break;
+
+               /* A swap/dax/shadow entry got inserted? Skip it. */
                if (xa_is_value(page))
                        continue;
-               if (!tail_pages) {
-                       /*
-                        * Some page got inserted in our range? Skip it. We
-                        * have our pages locked so they are protected from
-                        * being removed.
-                        */
-                       if (page != pvec->pages[i]) {
-                               VM_BUG_ON_PAGE(page->index >
-                                               pvec->pages[i]->index, page);
-                               continue;
-                       }
-                       WARN_ON_ONCE(!PageLocked(page));
-                       if (PageTransHuge(page) && !PageHuge(page))
-                               tail_pages = HPAGE_PMD_NR - 1;
+               /*
+                * A page got inserted in our range? Skip it. We have our
+                * pages locked so they are protected from being removed.
+                * If we see a page whose index is higher than ours, it
+                * means our page has been removed, which shouldn't be
+                * possible because we're holding the PageLock.
+                */
+               if (page != pvec->pages[i]) {
+                       VM_BUG_ON_PAGE(page->index > pvec->pages[i]->index,
+                                       page);
+                       continue;
+               }
+
+               WARN_ON_ONCE(!PageLocked(page));
+
+               if (page->index == xas.xa_index)
                        page->mapping = NULL;
-                       /*
-                        * Leave page->index set: truncation lookup relies
-                        * upon it
-                        */
+               /* Leave page->index set: truncation lookup relies on it */
+
+               /*
+                * Move to the next page in the vector if this is a regular
+                * page or the index is of the last sub-page of this compound
+                * page.
+                */
+               if (page->index + (1UL << compound_order(page)) - 1 ==
+                               xas.xa_index)
                        i++;
-               } else {
-                       VM_BUG_ON_PAGE(page->index + HPAGE_PMD_NR - tail_pages
-                                       != pvec->pages[i]->index, page);
-                       tail_pages--;
-               }
                xas_store(&xas, NULL);
                total_pages++;
        }
@@ -878,6 +883,7 @@ error:
        put_page(page);
        return xas_error(&xas);
 }
+ALLOW_ERROR_INJECTION(__add_to_page_cache_locked, ERRNO);
 
 /**
  * add_to_page_cache_locked - add a locked page to the pagecache
@@ -1440,7 +1446,7 @@ pgoff_t page_cache_next_miss(struct address_space *mapping,
 EXPORT_SYMBOL(page_cache_next_miss);
 
 /**
- * page_cache_prev_miss() - Find the next gap in the page cache.
+ * page_cache_prev_miss() - Find the previous gap in the page cache.
  * @mapping: Mapping.
  * @index: Index.
  * @max_scan: Maximum range to search.
@@ -1491,7 +1497,7 @@ EXPORT_SYMBOL(page_cache_prev_miss);
 struct page *find_get_entry(struct address_space *mapping, pgoff_t offset)
 {
        XA_STATE(xas, &mapping->i_pages, offset);
-       struct page *head, *page;
+       struct page *page;
 
        rcu_read_lock();
 repeat:
@@ -1506,25 +1512,19 @@ repeat:
        if (!page || xa_is_value(page))
                goto out;
 
-       head = compound_head(page);
-       if (!page_cache_get_speculative(head))
+       if (!page_cache_get_speculative(page))
                goto repeat;
 
-       /* The page was split under us? */
-       if (compound_head(page) != head) {
-               put_page(head);
-               goto repeat;
-       }
-
        /*
-        * Has the page moved?
+        * Has the page moved or been split?
         * This is part of the lockless pagecache protocol. See
         * include/linux/pagemap.h for details.
         */
        if (unlikely(page != xas_reload(&xas))) {
-               put_page(head);
+               put_page(page);
                goto repeat;
        }
+       page = find_subpage(page, offset);
 out:
        rcu_read_unlock();
 
@@ -1706,7 +1706,6 @@ unsigned find_get_entries(struct address_space *mapping,
 
        rcu_read_lock();
        xas_for_each(&xas, page, ULONG_MAX) {
-               struct page *head;
                if (xas_retry(&xas, page))
                        continue;
                /*
@@ -1717,17 +1716,13 @@ unsigned find_get_entries(struct address_space *mapping,
                if (xa_is_value(page))
                        goto export;
 
-               head = compound_head(page);
-               if (!page_cache_get_speculative(head))
+               if (!page_cache_get_speculative(page))
                        goto retry;
 
-               /* The page was split under us? */
-               if (compound_head(page) != head)
-                       goto put_page;
-
-               /* Has the page moved? */
+               /* Has the page moved or been split? */
                if (unlikely(page != xas_reload(&xas)))
                        goto put_page;
+               page = find_subpage(page, xas.xa_index);
 
 export:
                indices[ret] = xas.xa_index;
@@ -1736,7 +1731,7 @@ export:
                        break;
                continue;
 put_page:
-               put_page(head);
+               put_page(page);
 retry:
                xas_reset(&xas);
        }
@@ -1778,33 +1773,27 @@ unsigned find_get_pages_range(struct address_space *mapping, pgoff_t *start,
 
        rcu_read_lock();
        xas_for_each(&xas, page, end) {
-               struct page *head;
                if (xas_retry(&xas, page))
                        continue;
                /* Skip over shadow, swap and DAX entries */
                if (xa_is_value(page))
                        continue;
 
-               head = compound_head(page);
-               if (!page_cache_get_speculative(head))
+               if (!page_cache_get_speculative(page))
                        goto retry;
 
-               /* The page was split under us? */
-               if (compound_head(page) != head)
-                       goto put_page;
-
-               /* Has the page moved? */
+               /* Has the page moved or been split? */
                if (unlikely(page != xas_reload(&xas)))
                        goto put_page;
 
-               pages[ret] = page;
+               pages[ret] = find_subpage(page, xas.xa_index);
                if (++ret == nr_pages) {
                        *start = xas.xa_index + 1;
                        goto out;
                }
                continue;
 put_page:
-               put_page(head);
+               put_page(page);
 retry:
                xas_reset(&xas);
        }
@@ -1849,7 +1838,6 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
 
        rcu_read_lock();
        for (page = xas_load(&xas); page; page = xas_next(&xas)) {
-               struct page *head;
                if (xas_retry(&xas, page))
                        continue;
                /*
@@ -1859,24 +1847,19 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
                if (xa_is_value(page))
                        break;
 
-               head = compound_head(page);
-               if (!page_cache_get_speculative(head))
+               if (!page_cache_get_speculative(page))
                        goto retry;
 
-               /* The page was split under us? */
-               if (compound_head(page) != head)
-                       goto put_page;
-
-               /* Has the page moved? */
+               /* Has the page moved or been split? */
                if (unlikely(page != xas_reload(&xas)))
                        goto put_page;
 
-               pages[ret] = page;
+               pages[ret] = find_subpage(page, xas.xa_index);
                if (++ret == nr_pages)
                        break;
                continue;
 put_page:
-               put_page(head);
+               put_page(page);
 retry:
                xas_reset(&xas);
        }
@@ -1912,7 +1895,6 @@ unsigned find_get_pages_range_tag(struct address_space *mapping, pgoff_t *index,
 
        rcu_read_lock();
        xas_for_each_marked(&xas, page, end, tag) {
-               struct page *head;
                if (xas_retry(&xas, page))
                        continue;
                /*
@@ -1923,26 +1905,21 @@ unsigned find_get_pages_range_tag(struct address_space *mapping, pgoff_t *index,
                if (xa_is_value(page))
                        continue;
 
-               head = compound_head(page);
-               if (!page_cache_get_speculative(head))
+               if (!page_cache_get_speculative(page))
                        goto retry;
 
-               /* The page was split under us? */
-               if (compound_head(page) != head)
-                       goto put_page;
-
-               /* Has the page moved? */
+               /* Has the page moved or been split? */
                if (unlikely(page != xas_reload(&xas)))
                        goto put_page;
 
-               pages[ret] = page;
+               pages[ret] = find_subpage(page, xas.xa_index);
                if (++ret == nr_pages) {
                        *index = xas.xa_index + 1;
                        goto out;
                }
                continue;
 put_page:
-               put_page(head);
+               put_page(page);
 retry:
                xas_reset(&xas);
        }
@@ -1964,72 +1941,6 @@ out:
 }
 EXPORT_SYMBOL(find_get_pages_range_tag);
 
-/**
- * find_get_entries_tag - find and return entries that match @tag
- * @mapping:   the address_space to search
- * @start:     the starting page cache index
- * @tag:       the tag index
- * @nr_entries:        the maximum number of entries
- * @entries:   where the resulting entries are placed
- * @indices:   the cache indices corresponding to the entries in @entries
- *
- * Like find_get_entries, except we only return entries which are tagged with
- * @tag.
- *
- * Return: the number of entries which were found.
- */
-unsigned find_get_entries_tag(struct address_space *mapping, pgoff_t start,
-                       xa_mark_t tag, unsigned int nr_entries,
-                       struct page **entries, pgoff_t *indices)
-{
-       XA_STATE(xas, &mapping->i_pages, start);
-       struct page *page;
-       unsigned int ret = 0;
-
-       if (!nr_entries)
-               return 0;
-
-       rcu_read_lock();
-       xas_for_each_marked(&xas, page, ULONG_MAX, tag) {
-               struct page *head;
-               if (xas_retry(&xas, page))
-                       continue;
-               /*
-                * A shadow entry of a recently evicted page, a swap
-                * entry from shmem/tmpfs or a DAX entry.  Return it
-                * without attempting to raise page count.
-                */
-               if (xa_is_value(page))
-                       goto export;
-
-               head = compound_head(page);
-               if (!page_cache_get_speculative(head))
-                       goto retry;
-
-               /* The page was split under us? */
-               if (compound_head(page) != head)
-                       goto put_page;
-
-               /* Has the page moved? */
-               if (unlikely(page != xas_reload(&xas)))
-                       goto put_page;
-
-export:
-               indices[ret] = xas.xa_index;
-               entries[ret] = page;
-               if (++ret == nr_entries)
-                       break;
-               continue;
-put_page:
-               put_page(head);
-retry:
-               xas_reset(&xas);
-       }
-       rcu_read_unlock();
-       return ret;
-}
-EXPORT_SYMBOL(find_get_entries_tag);
-
 /*
  * CD/DVDs are error prone. When a medium error occurs, the driver may fail
  * a _large_ part of the i/o request. Imagine the worst scenario:
@@ -2691,7 +2602,7 @@ void filemap_map_pages(struct vm_fault *vmf,
        pgoff_t last_pgoff = start_pgoff;
        unsigned long max_idx;
        XA_STATE(xas, &mapping->i_pages, start_pgoff);
-       struct page *head, *page;
+       struct page *page;
 
        rcu_read_lock();
        xas_for_each(&xas, page, end_pgoff) {
@@ -2700,24 +2611,19 @@ void filemap_map_pages(struct vm_fault *vmf,
                if (xa_is_value(page))
                        goto next;
 
-               head = compound_head(page);
-
                /*
                 * Check for a locked page first, as a speculative
                 * reference may adversely influence page migration.
                 */
-               if (PageLocked(head))
+               if (PageLocked(page))
                        goto next;
-               if (!page_cache_get_speculative(head))
+               if (!page_cache_get_speculative(page))
                        goto next;
 
-               /* The page was split under us? */
-               if (compound_head(page) != head)
-                       goto skip;
-
-               /* Has the page moved? */
+               /* Has the page moved or been split? */
                if (unlikely(page != xas_reload(&xas)))
                        goto skip;
+               page = find_subpage(page, xas.xa_index);
 
                if (!PageUptodate(page) ||
                                PageReadahead(page) ||
index 91819b8ad9cc511ca15a3d84ff81131cd4e2d0da..2c08248d4fa279bece3a748d22a30a250d5e8bbe 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -28,6 +28,111 @@ struct follow_page_context {
        unsigned int page_mask;
 };
 
+typedef int (*set_dirty_func_t)(struct page *page);
+
+static void __put_user_pages_dirty(struct page **pages,
+                                  unsigned long npages,
+                                  set_dirty_func_t sdf)
+{
+       unsigned long index;
+
+       for (index = 0; index < npages; index++) {
+               struct page *page = compound_head(pages[index]);
+
+               /*
+                * Checking PageDirty at this point may race with
+                * clear_page_dirty_for_io(), but that's OK. Two key cases:
+                *
+                * 1) This code sees the page as already dirty, so it skips
+                * the call to sdf(). That could happen because
+                * clear_page_dirty_for_io() called page_mkclean(),
+                * followed by set_page_dirty(). However, now the page is
+                * going to get written back, which meets the original
+                * intention of setting it dirty, so all is well:
+                * clear_page_dirty_for_io() goes on to call
+                * TestClearPageDirty(), and write the page back.
+                *
+                * 2) This code sees the page as clean, so it calls sdf().
+                * The page stays dirty, despite being written back, so it
+                * gets written back again in the next writeback cycle.
+                * This is harmless.
+                */
+               if (!PageDirty(page))
+                       sdf(page);
+
+               put_user_page(page);
+       }
+}
+
+/**
+ * put_user_pages_dirty() - release and dirty an array of gup-pinned pages
+ * @pages:  array of pages to be marked dirty and released.
+ * @npages: number of pages in the @pages array.
+ *
+ * "gup-pinned page" refers to a page that has had one of the get_user_pages()
+ * variants called on that page.
+ *
+ * For each page in the @pages array, make that page (or its head page, if a
+ * compound page) dirty, if it was previously listed as clean. Then, release
+ * the page using put_user_page().
+ *
+ * Please see the put_user_page() documentation for details.
+ *
+ * set_page_dirty(), which does not lock the page, is used here.
+ * Therefore, it is the caller's responsibility to ensure that this is
+ * safe. If not, then put_user_pages_dirty_lock() should be called instead.
+ *
+ */
+void put_user_pages_dirty(struct page **pages, unsigned long npages)
+{
+       __put_user_pages_dirty(pages, npages, set_page_dirty);
+}
+EXPORT_SYMBOL(put_user_pages_dirty);
+
+/**
+ * put_user_pages_dirty_lock() - release and dirty an array of gup-pinned pages
+ * @pages:  array of pages to be marked dirty and released.
+ * @npages: number of pages in the @pages array.
+ *
+ * For each page in the @pages array, make that page (or its head page, if a
+ * compound page) dirty, if it was previously listed as clean. Then, release
+ * the page using put_user_page().
+ *
+ * Please see the put_user_page() documentation for details.
+ *
+ * This is just like put_user_pages_dirty(), except that it invokes
+ * set_page_dirty_lock(), instead of set_page_dirty().
+ *
+ */
+void put_user_pages_dirty_lock(struct page **pages, unsigned long npages)
+{
+       __put_user_pages_dirty(pages, npages, set_page_dirty_lock);
+}
+EXPORT_SYMBOL(put_user_pages_dirty_lock);
+
+/**
+ * put_user_pages() - release an array of gup-pinned pages.
+ * @pages:  array of pages to be marked dirty and released.
+ * @npages: number of pages in the @pages array.
+ *
+ * For each page in the @pages array, release the page using put_user_page().
+ *
+ * Please see the put_user_page() documentation for details.
+ */
+void put_user_pages(struct page **pages, unsigned long npages)
+{
+       unsigned long index;
+
+       /*
+        * TODO: this can be optimized for huge pages: if a series of pages is
+        * physically contiguous and part of the same compound page, then a
+        * single operation to the head page should suffice.
+        */
+       for (index = 0; index < npages; index++)
+               put_user_page(pages[index]);
+}
+EXPORT_SYMBOL(put_user_pages);
+
 static struct page *no_page_table(struct vm_area_struct *vma,
                unsigned int flags)
 {
@@ -1018,6 +1123,15 @@ long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
                           unsigned int gup_flags, struct page **pages,
                           int *locked)
 {
+       /*
+        * FIXME: Current FOLL_LONGTERM behavior is incompatible with
+        * FAULT_FLAG_ALLOW_RETRY because of the FS DAX check requirement on
+        * vmas.  As there are no users of this flag in this call we simply
+        * disallow this option for now.
+        */
+       if (WARN_ON_ONCE(gup_flags & FOLL_LONGTERM))
+               return -EINVAL;
+
        return __get_user_pages_locked(current, current->mm, start, nr_pages,
                                       pages, NULL, locked,
                                       gup_flags | FOLL_TOUCH);
@@ -1046,6 +1160,15 @@ long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
        int locked = 1;
        long ret;
 
+       /*
+        * FIXME: Current FOLL_LONGTERM behavior is incompatible with
+        * FAULT_FLAG_ALLOW_RETRY because of the FS DAX check requirement on
+        * vmas.  As there are no users of this flag in this call we simply
+        * disallow this option for now.
+        */
+       if (WARN_ON_ONCE(gup_flags & FOLL_LONGTERM))
+               return -EINVAL;
+
        down_read(&mm->mmap_sem);
        ret = __get_user_pages_locked(current, mm, start, nr_pages, pages, NULL,
                                      &locked, gup_flags | FOLL_TOUCH);
@@ -1116,32 +1239,22 @@ long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
                unsigned int gup_flags, struct page **pages,
                struct vm_area_struct **vmas, int *locked)
 {
+       /*
+        * FIXME: Current FOLL_LONGTERM behavior is incompatible with
+        * FAULT_FLAG_ALLOW_RETRY because of the FS DAX check requirement on
+        * vmas.  As there are no users of this flag in this call we simply
+        * disallow this option for now.
+        */
+       if (WARN_ON_ONCE(gup_flags & FOLL_LONGTERM))
+               return -EINVAL;
+
        return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas,
                                       locked,
                                       gup_flags | FOLL_TOUCH | FOLL_REMOTE);
 }
 EXPORT_SYMBOL(get_user_pages_remote);
 
-/*
- * This is the same as get_user_pages_remote(), just with a
- * less-flexible calling convention where we assume that the task
- * and mm being operated on are the current task's and don't allow
- * passing of a locked parameter.  We also obviously don't pass
- * FOLL_REMOTE in here.
- */
-long get_user_pages(unsigned long start, unsigned long nr_pages,
-               unsigned int gup_flags, struct page **pages,
-               struct vm_area_struct **vmas)
-{
-       return __get_user_pages_locked(current, current->mm, start, nr_pages,
-                                      pages, vmas, NULL,
-                                      gup_flags | FOLL_TOUCH);
-}
-EXPORT_SYMBOL(get_user_pages);
-
 #if defined(CONFIG_FS_DAX) || defined (CONFIG_CMA)
-
-#ifdef CONFIG_FS_DAX
 static bool check_dax_vmas(struct vm_area_struct **vmas, long nr_pages)
 {
        long i;
@@ -1160,12 +1273,6 @@ static bool check_dax_vmas(struct vm_area_struct **vmas, long nr_pages)
        }
        return false;
 }
-#else
-static inline bool check_dax_vmas(struct vm_area_struct **vmas, long nr_pages)
-{
-       return false;
-}
-#endif
 
 #ifdef CONFIG_CMA
 static struct page *new_non_cma_page(struct page *page, unsigned long private)
@@ -1219,10 +1326,13 @@ static struct page *new_non_cma_page(struct page *page, unsigned long private)
        return __alloc_pages_node(nid, gfp_mask, 0);
 }
 
-static long check_and_migrate_cma_pages(unsigned long start, long nr_pages,
-                                       unsigned int gup_flags,
+static long check_and_migrate_cma_pages(struct task_struct *tsk,
+                                       struct mm_struct *mm,
+                                       unsigned long start,
+                                       unsigned long nr_pages,
                                        struct page **pages,
-                                       struct vm_area_struct **vmas)
+                                       struct vm_area_struct **vmas,
+                                       unsigned int gup_flags)
 {
        long i;
        bool drain_allow = true;
@@ -1278,10 +1388,14 @@ check_again:
                                putback_movable_pages(&cma_page_list);
                }
                /*
-                * We did migrate all the pages, Try to get the page references again
-                * migrating any new CMA pages which we failed to isolate earlier.
+                * We did migrate all the pages, Try to get the page references
+                * again migrating any new CMA pages which we failed to isolate
+                * earlier.
                 */
-               nr_pages = get_user_pages(start, nr_pages, gup_flags, pages, vmas);
+               nr_pages = __get_user_pages_locked(tsk, mm, start, nr_pages,
+                                                  pages, vmas, NULL,
+                                                  gup_flags);
+
                if ((nr_pages > 0) && migrate_allow) {
                        drain_allow = true;
                        goto check_again;
@@ -1291,66 +1405,101 @@ check_again:
        return nr_pages;
 }
 #else
-static inline long check_and_migrate_cma_pages(unsigned long start, long nr_pages,
-                                              unsigned int gup_flags,
-                                              struct page **pages,
-                                              struct vm_area_struct **vmas)
+static long check_and_migrate_cma_pages(struct task_struct *tsk,
+                                       struct mm_struct *mm,
+                                       unsigned long start,
+                                       unsigned long nr_pages,
+                                       struct page **pages,
+                                       struct vm_area_struct **vmas,
+                                       unsigned int gup_flags)
 {
        return nr_pages;
 }
 #endif
 
 /*
- * This is the same as get_user_pages() in that it assumes we are
- * operating on the current task's mm, but it goes further to validate
- * that the vmas associated with the address range are suitable for
- * longterm elevated page reference counts. For example, filesystem-dax
- * mappings are subject to the lifetime enforced by the filesystem and
- * we need guarantees that longterm users like RDMA and V4L2 only
- * establish mappings that have a kernel enforced revocation mechanism.
- *
- * "longterm" == userspace controlled elevated page count lifetime.
- * Contrast this to iov_iter_get_pages() usages which are transient.
+ * __gup_longterm_locked() is a wrapper for __get_user_pages_locked which
+ * allows us to process the FOLL_LONGTERM flag.
  */
-long get_user_pages_longterm(unsigned long start, unsigned long nr_pages,
-                            unsigned int gup_flags, struct page **pages,
-                            struct vm_area_struct **vmas_arg)
+static long __gup_longterm_locked(struct task_struct *tsk,
+                                 struct mm_struct *mm,
+                                 unsigned long start,
+                                 unsigned long nr_pages,
+                                 struct page **pages,
+                                 struct vm_area_struct **vmas,
+                                 unsigned int gup_flags)
 {
-       struct vm_area_struct **vmas = vmas_arg;
-       unsigned long flags;
+       struct vm_area_struct **vmas_tmp = vmas;
+       unsigned long flags = 0;
        long rc, i;
 
-       if (!pages)
-               return -EINVAL;
-
-       if (!vmas) {
-               vmas = kcalloc(nr_pages, sizeof(struct vm_area_struct *),
-                              GFP_KERNEL);
-               if (!vmas)
-                       return -ENOMEM;
+       if (gup_flags & FOLL_LONGTERM) {
+               if (!pages)
+                       return -EINVAL;
+
+               if (!vmas_tmp) {
+                       vmas_tmp = kcalloc(nr_pages,
+                                          sizeof(struct vm_area_struct *),
+                                          GFP_KERNEL);
+                       if (!vmas_tmp)
+                               return -ENOMEM;
+               }
+               flags = memalloc_nocma_save();
        }
 
-       flags = memalloc_nocma_save();
-       rc = get_user_pages(start, nr_pages, gup_flags, pages, vmas);
-       memalloc_nocma_restore(flags);
-       if (rc < 0)
-               goto out;
+       rc = __get_user_pages_locked(tsk, mm, start, nr_pages, pages,
+                                    vmas_tmp, NULL, gup_flags);
 
-       if (check_dax_vmas(vmas, rc)) {
-               for (i = 0; i < rc; i++)
-                       put_page(pages[i]);
-               rc = -EOPNOTSUPP;
-               goto out;
+       if (gup_flags & FOLL_LONGTERM) {
+               memalloc_nocma_restore(flags);
+               if (rc < 0)
+                       goto out;
+
+               if (check_dax_vmas(vmas_tmp, rc)) {
+                       for (i = 0; i < rc; i++)
+                               put_page(pages[i]);
+                       rc = -EOPNOTSUPP;
+                       goto out;
+               }
+
+               rc = check_and_migrate_cma_pages(tsk, mm, start, rc, pages,
+                                                vmas_tmp, gup_flags);
        }
 
-       rc = check_and_migrate_cma_pages(start, rc, gup_flags, pages, vmas);
 out:
-       if (vmas != vmas_arg)
-               kfree(vmas);
+       if (vmas_tmp != vmas)
+               kfree(vmas_tmp);
        return rc;
 }
-EXPORT_SYMBOL(get_user_pages_longterm);
-#endif /* CONFIG_FS_DAX */
+#else /* !CONFIG_FS_DAX && !CONFIG_CMA */
+static __always_inline long __gup_longterm_locked(struct task_struct *tsk,
+                                                 struct mm_struct *mm,
+                                                 unsigned long start,
+                                                 unsigned long nr_pages,
+                                                 struct page **pages,
+                                                 struct vm_area_struct **vmas,
+                                                 unsigned int flags)
+{
+       return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas,
+                                      NULL, flags);
+}
+#endif /* CONFIG_FS_DAX || CONFIG_CMA */
+
+/*
+ * This is the same as get_user_pages_remote(), just with a
+ * less-flexible calling convention where we assume that the task
+ * and mm being operated on are the current task's and don't allow
+ * passing of a locked parameter.  We also obviously don't pass
+ * FOLL_REMOTE in here.
+ */
+long get_user_pages(unsigned long start, unsigned long nr_pages,
+               unsigned int gup_flags, struct page **pages,
+               struct vm_area_struct **vmas)
+{
+       return __gup_longterm_locked(current, current->mm, start, nr_pages,
+                                    pages, vmas, gup_flags | FOLL_TOUCH);
+}
+EXPORT_SYMBOL(get_user_pages);
 
 /**
  * populate_vma_page_range() -  populate a range of pages in the vma.
@@ -1571,7 +1720,7 @@ static inline struct page *try_get_compound_head(struct page *page, int refs)
 
 #ifdef CONFIG_ARCH_HAS_PTE_SPECIAL
 static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
-                        int write, struct page **pages, int *nr)
+                        unsigned int flags, struct page **pages, int *nr)
 {
        struct dev_pagemap *pgmap = NULL;
        int nr_start = *nr, ret = 0;
@@ -1589,10 +1738,13 @@ static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
                if (pte_protnone(pte))
                        goto pte_unmap;
 
-               if (!pte_access_permitted(pte, write))
+               if (!pte_access_permitted(pte, flags & FOLL_WRITE))
                        goto pte_unmap;
 
                if (pte_devmap(pte)) {
+                       if (unlikely(flags & FOLL_LONGTERM))
+                               goto pte_unmap;
+
                        pgmap = get_dev_pagemap(pte_pfn(pte), pgmap);
                        if (unlikely(!pgmap)) {
                                undo_dev_pagemap(nr, nr_start, pages);
@@ -1641,7 +1793,7 @@ pte_unmap:
  * useful to have gup_huge_pmd even if we can't operate on ptes.
  */
 static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
-                        int write, struct page **pages, int *nr)
+                        unsigned int flags, struct page **pages, int *nr)
 {
        return 0;
 }
@@ -1724,16 +1876,19 @@ static int __gup_device_huge_pud(pud_t pud, pud_t *pudp, unsigned long addr,
 #endif
 
 static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr,
-               unsigned long end, int write, struct page **pages, int *nr)
+               unsigned long end, unsigned int flags, struct page **pages, int *nr)
 {
        struct page *head, *page;
        int refs;
 
-       if (!pmd_access_permitted(orig, write))
+       if (!pmd_access_permitted(orig, flags & FOLL_WRITE))
                return 0;
 
-       if (pmd_devmap(orig))
+       if (pmd_devmap(orig)) {
+               if (unlikely(flags & FOLL_LONGTERM))
+                       return 0;
                return __gup_device_huge_pmd(orig, pmdp, addr, end, pages, nr);
+       }
 
        refs = 0;
        page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
@@ -1762,16 +1917,19 @@ static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr,
 }
 
 static int gup_huge_pud(pud_t orig, pud_t *pudp, unsigned long addr,
-               unsigned long end, int write, struct page **pages, int *nr)
+               unsigned long end, unsigned int flags, struct page **pages, int *nr)
 {
        struct page *head, *page;
        int refs;
 
-       if (!pud_access_permitted(orig, write))
+       if (!pud_access_permitted(orig, flags & FOLL_WRITE))
                return 0;
 
-       if (pud_devmap(orig))
+       if (pud_devmap(orig)) {
+               if (unlikely(flags & FOLL_LONGTERM))
+                       return 0;
                return __gup_device_huge_pud(orig, pudp, addr, end, pages, nr);
+       }
 
        refs = 0;
        page = pud_page(orig) + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
@@ -1800,13 +1958,13 @@ static int gup_huge_pud(pud_t orig, pud_t *pudp, unsigned long addr,
 }
 
 static int gup_huge_pgd(pgd_t orig, pgd_t *pgdp, unsigned long addr,
-                       unsigned long end, int write,
+                       unsigned long end, unsigned int flags,
                        struct page **pages, int *nr)
 {
        int refs;
        struct page *head, *page;
 
-       if (!pgd_access_permitted(orig, write))
+       if (!pgd_access_permitted(orig, flags & FOLL_WRITE))
                return 0;
 
        BUILD_BUG_ON(pgd_devmap(orig));
@@ -1837,7 +1995,7 @@ static int gup_huge_pgd(pgd_t orig, pgd_t *pgdp, unsigned long addr,
 }
 
 static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
-               int write, struct page **pages, int *nr)
+               unsigned int flags, struct page **pages, int *nr)
 {
        unsigned long next;
        pmd_t *pmdp;
@@ -1860,7 +2018,7 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
                        if (pmd_protnone(pmd))
                                return 0;
 
-                       if (!gup_huge_pmd(pmd, pmdp, addr, next, write,
+                       if (!gup_huge_pmd(pmd, pmdp, addr, next, flags,
                                pages, nr))
                                return 0;
 
@@ -1870,9 +2028,9 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
                         * pmd format and THP pmd format
                         */
                        if (!gup_huge_pd(__hugepd(pmd_val(pmd)), addr,
-                                        PMD_SHIFT, next, write, pages, nr))
+                                        PMD_SHIFT, next, flags, pages, nr))
                                return 0;
-               } else if (!gup_pte_range(pmd, addr, next, write, pages, nr))
+               } else if (!gup_pte_range(pmd, addr, next, flags, pages, nr))
                        return 0;
        } while (pmdp++, addr = next, addr != end);
 
@@ -1880,7 +2038,7 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
 }
 
 static int gup_pud_range(p4d_t p4d, unsigned long addr, unsigned long end,
-                        int write, struct page **pages, int *nr)
+                        unsigned int flags, struct page **pages, int *nr)
 {
        unsigned long next;
        pud_t *pudp;
@@ -1893,14 +2051,14 @@ static int gup_pud_range(p4d_t p4d, unsigned long addr, unsigned long end,
                if (pud_none(pud))
                        return 0;
                if (unlikely(pud_huge(pud))) {
-                       if (!gup_huge_pud(pud, pudp, addr, next, write,
+                       if (!gup_huge_pud(pud, pudp, addr, next, flags,
                                          pages, nr))
                                return 0;
                } else if (unlikely(is_hugepd(__hugepd(pud_val(pud))))) {
                        if (!gup_huge_pd(__hugepd(pud_val(pud)), addr,
-                                        PUD_SHIFT, next, write, pages, nr))
+                                        PUD_SHIFT, next, flags, pages, nr))
                                return 0;
-               } else if (!gup_pmd_range(pud, addr, next, write, pages, nr))
+               } else if (!gup_pmd_range(pud, addr, next, flags, pages, nr))
                        return 0;
        } while (pudp++, addr = next, addr != end);
 
@@ -1908,7 +2066,7 @@ static int gup_pud_range(p4d_t p4d, unsigned long addr, unsigned long end,
 }
 
 static int gup_p4d_range(pgd_t pgd, unsigned long addr, unsigned long end,
-                        int write, struct page **pages, int *nr)
+                        unsigned int flags, struct page **pages, int *nr)
 {
        unsigned long next;
        p4d_t *p4dp;
@@ -1923,9 +2081,9 @@ static int gup_p4d_range(pgd_t pgd, unsigned long addr, unsigned long end,
                BUILD_BUG_ON(p4d_huge(p4d));
                if (unlikely(is_hugepd(__hugepd(p4d_val(p4d))))) {
                        if (!gup_huge_pd(__hugepd(p4d_val(p4d)), addr,
-                                        P4D_SHIFT, next, write, pages, nr))
+                                        P4D_SHIFT, next, flags, pages, nr))
                                return 0;
-               } else if (!gup_pud_range(p4d, addr, next, write, pages, nr))
+               } else if (!gup_pud_range(p4d, addr, next, flags, pages, nr))
                        return 0;
        } while (p4dp++, addr = next, addr != end);
 
@@ -1933,7 +2091,7 @@ static int gup_p4d_range(pgd_t pgd, unsigned long addr, unsigned long end,
 }
 
 static void gup_pgd_range(unsigned long addr, unsigned long end,
-               int write, struct page **pages, int *nr)
+               unsigned int flags, struct page **pages, int *nr)
 {
        unsigned long next;
        pgd_t *pgdp;
@@ -1946,14 +2104,14 @@ static void gup_pgd_range(unsigned long addr, unsigned long end,
                if (pgd_none(pgd))
                        return;
                if (unlikely(pgd_huge(pgd))) {
-                       if (!gup_huge_pgd(pgd, pgdp, addr, next, write,
+                       if (!gup_huge_pgd(pgd, pgdp, addr, next, flags,
                                          pages, nr))
                                return;
                } else if (unlikely(is_hugepd(__hugepd(pgd_val(pgd))))) {
                        if (!gup_huge_pd(__hugepd(pgd_val(pgd)), addr,
-                                        PGDIR_SHIFT, next, write, pages, nr))
+                                        PGDIR_SHIFT, next, flags, pages, nr))
                                return;
-               } else if (!gup_p4d_range(pgd, addr, next, write, pages, nr))
+               } else if (!gup_p4d_range(pgd, addr, next, flags, pages, nr))
                        return;
        } while (pgdp++, addr = next, addr != end);
 }
@@ -2007,18 +2165,41 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
 
        if (gup_fast_permitted(start, nr_pages)) {
                local_irq_save(flags);
-               gup_pgd_range(start, end, write, pages, &nr);
+               gup_pgd_range(start, end, write ? FOLL_WRITE : 0, pages, &nr);
                local_irq_restore(flags);
        }
 
        return nr;
 }
 
+static int __gup_longterm_unlocked(unsigned long start, int nr_pages,
+                                  unsigned int gup_flags, struct page **pages)
+{
+       int ret;
+
+       /*
+        * FIXME: FOLL_LONGTERM does not work with
+        * get_user_pages_unlocked() (see comments in that function)
+        */
+       if (gup_flags & FOLL_LONGTERM) {
+               down_read(&current->mm->mmap_sem);
+               ret = __gup_longterm_locked(current, current->mm,
+                                           start, nr_pages,
+                                           pages, NULL, gup_flags);
+               up_read(&current->mm->mmap_sem);
+       } else {
+               ret = get_user_pages_unlocked(start, nr_pages,
+                                             pages, gup_flags);
+       }
+
+       return ret;
+}
+
 /**
  * get_user_pages_fast() - pin user pages in memory
  * @start:     starting user address
  * @nr_pages:  number of pages from start to pin
- * @write:     whether pages will be written to
+ * @gup_flags: flags modifying pin behaviour
  * @pages:     array that receives pointers to the pages pinned.
  *             Should be at least nr_pages long.
  *
@@ -2030,8 +2211,8 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
  * requested. If nr_pages is 0 or negative, returns 0. If no pages
  * were pinned, returns -errno.
  */
-int get_user_pages_fast(unsigned long start, int nr_pages, int write,
-                       struct page **pages)
+int get_user_pages_fast(unsigned long start, int nr_pages,
+                       unsigned int gup_flags, struct page **pages)
 {
        unsigned long addr, len, end;
        int nr = 0, ret = 0;
@@ -2049,7 +2230,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
 
        if (gup_fast_permitted(start, nr_pages)) {
                local_irq_disable();
-               gup_pgd_range(addr, end, write, pages, &nr);
+               gup_pgd_range(addr, end, gup_flags, pages, &nr);
                local_irq_enable();
                ret = nr;
        }
@@ -2059,8 +2240,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                start += nr << PAGE_SHIFT;
                pages += nr;
 
-               ret = get_user_pages_unlocked(start, nr_pages - nr, pages,
-                               write ? FOLL_WRITE : 0);
+               ret = __gup_longterm_unlocked(start, nr_pages - nr,
+                                             gup_flags, pages);
 
                /* Have to be a bit careful with return values */
                if (nr > 0) {
index 6c0279e70cc479221adaf69142993c3e54557235..7dd602d7f8db7be0f698021b01d8fc9810d25e5b 100644 (file)
@@ -54,8 +54,9 @@ static int __gup_benchmark_ioctl(unsigned int cmd,
                                                 pages + i);
                        break;
                case GUP_LONGTERM_BENCHMARK:
-                       nr = get_user_pages_longterm(addr, nr, gup->flags & 1,
-                                                    pages + i, NULL);
+                       nr = get_user_pages(addr, nr,
+                                           (gup->flags & 1) | FOLL_LONGTERM,
+                                           pages + i, NULL);
                        break;
                case GUP_BENCHMARK:
                        nr = get_user_pages(addr, nr, gup->flags & 1, pages + i,
index fe1cd87e49acc94641eaf7178dc07e5c4306e408..0db8491090b888f708a7b52a7dba780d5b335b8c 100644 (file)
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -30,6 +30,7 @@
 #include <linux/hugetlb.h>
 #include <linux/memremap.h>
 #include <linux/jump_label.h>
+#include <linux/dma-mapping.h>
 #include <linux/mmu_notifier.h>
 #include <linux/memory_hotplug.h>
 
 #if IS_ENABLED(CONFIG_HMM_MIRROR)
 static const struct mmu_notifier_ops hmm_mmu_notifier_ops;
 
-/*
- * struct hmm - HMM per mm struct
- *
- * @mm: mm struct this HMM struct is bound to
- * @lock: lock protecting ranges list
- * @ranges: list of range being snapshotted
- * @mirrors: list of mirrors for this mm
- * @mmu_notifier: mmu notifier to track updates to CPU page table
- * @mirrors_sem: read/write semaphore protecting the mirrors list
- */
-struct hmm {
-       struct mm_struct        *mm;
-       spinlock_t              lock;
-       struct list_head        ranges;
-       struct list_head        mirrors;
-       struct mmu_notifier     mmu_notifier;
-       struct rw_semaphore     mirrors_sem;
-};
+static inline struct hmm *mm_get_hmm(struct mm_struct *mm)
+{
+       struct hmm *hmm = READ_ONCE(mm->hmm);
 
-/*
- * hmm_register - register HMM against an mm (HMM internal)
+       if (hmm && kref_get_unless_zero(&hmm->kref))
+               return hmm;
+
+       return NULL;
+}
+
+/**
+ * hmm_get_or_create - register HMM against an mm (HMM internal)
  *
  * @mm: mm struct to attach to
+ * Returns: returns an HMM object, either by referencing the existing
+ *          (per-process) object, or by creating a new one.
  *
- * This is not intended to be used directly by device drivers. It allocates an
- * HMM struct if mm does not have one, and initializes it.
+ * This is not intended to be used directly by device drivers. If mm already
+ * has an HMM struct then it get a reference on it and returns it. Otherwise
+ * it allocates an HMM struct, initializes it, associate it with the mm and
+ * returns it.
  */
-static struct hmm *hmm_register(struct mm_struct *mm)
+static struct hmm *hmm_get_or_create(struct mm_struct *mm)
 {
-       struct hmm *hmm = READ_ONCE(mm->hmm);
+       struct hmm *hmm = mm_get_hmm(mm);
        bool cleanup = false;
 
-       /*
-        * The hmm struct can only be freed once the mm_struct goes away,
-        * hence we should always have pre-allocated an new hmm struct
-        * above.
-        */
        if (hmm)
                return hmm;
 
        hmm = kmalloc(sizeof(*hmm), GFP_KERNEL);
        if (!hmm)
                return NULL;
+       init_waitqueue_head(&hmm->wq);
        INIT_LIST_HEAD(&hmm->mirrors);
        init_rwsem(&hmm->mirrors_sem);
        hmm->mmu_notifier.ops = NULL;
        INIT_LIST_HEAD(&hmm->ranges);
-       spin_lock_init(&hmm->lock);
+       mutex_init(&hmm->lock);
+       kref_init(&hmm->kref);
+       hmm->notifiers = 0;
+       hmm->dead = false;
        hmm->mm = mm;
 
        spin_lock(&mm->page_table_lock);
@@ -106,7 +101,7 @@ static struct hmm *hmm_register(struct mm_struct *mm)
        if (__mmu_notifier_register(&hmm->mmu_notifier, mm))
                goto error_mm;
 
-       return mm->hmm;
+       return hmm;
 
 error_mm:
        spin_lock(&mm->page_table_lock);
@@ -118,54 +113,60 @@ error:
        return NULL;
 }
 
-void hmm_mm_destroy(struct mm_struct *mm)
+static void hmm_free(struct kref *kref)
 {
-       kfree(mm->hmm);
-}
+       struct hmm *hmm = container_of(kref, struct hmm, kref);
+       struct mm_struct *mm = hmm->mm;
 
-static int hmm_invalidate_range(struct hmm *hmm, bool device,
-                               const struct hmm_update *update)
-{
-       struct hmm_mirror *mirror;
-       struct hmm_range *range;
-
-       spin_lock(&hmm->lock);
-       list_for_each_entry(range, &hmm->ranges, list) {
-               unsigned long addr, idx, npages;
+       mmu_notifier_unregister_no_release(&hmm->mmu_notifier, mm);
 
-               if (update->end < range->start || update->start >= range->end)
-                       continue;
+       spin_lock(&mm->page_table_lock);
+       if (mm->hmm == hmm)
+               mm->hmm = NULL;
+       spin_unlock(&mm->page_table_lock);
 
-               range->valid = false;
-               addr = max(update->start, range->start);
-               idx = (addr - range->start) >> PAGE_SHIFT;
-               npages = (min(range->end, update->end) - addr) >> PAGE_SHIFT;
-               memset(&range->pfns[idx], 0, sizeof(*range->pfns) * npages);
-       }
-       spin_unlock(&hmm->lock);
+       kfree(hmm);
+}
 
-       if (!device)
-               return 0;
+static inline void hmm_put(struct hmm *hmm)
+{
+       kref_put(&hmm->kref, hmm_free);
+}
 
-       down_read(&hmm->mirrors_sem);
-       list_for_each_entry(mirror, &hmm->mirrors, list) {
-               int ret;
+void hmm_mm_destroy(struct mm_struct *mm)
+{
+       struct hmm *hmm;
 
-               ret = mirror->ops->sync_cpu_device_pagetables(mirror, update);
-               if (!update->blockable && ret == -EAGAIN) {
-                       up_read(&hmm->mirrors_sem);
-                       return -EAGAIN;
-               }
+       spin_lock(&mm->page_table_lock);
+       hmm = mm_get_hmm(mm);
+       mm->hmm = NULL;
+       if (hmm) {
+               hmm->mm = NULL;
+               hmm->dead = true;
+               spin_unlock(&mm->page_table_lock);
+               hmm_put(hmm);
+               return;
        }
-       up_read(&hmm->mirrors_sem);
 
-       return 0;
+       spin_unlock(&mm->page_table_lock);
 }
 
 static void hmm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 {
+       struct hmm *hmm = mm_get_hmm(mm);
        struct hmm_mirror *mirror;
-       struct hmm *hmm = mm->hmm;
+       struct hmm_range *range;
+
+       /* Report this HMM as dying. */
+       hmm->dead = true;
+
+       /* Wake-up everyone waiting on any range. */
+       mutex_lock(&hmm->lock);
+       list_for_each_entry(range, &hmm->ranges, list) {
+               range->valid = false;
+       }
+       wake_up_all(&hmm->wq);
+       mutex_unlock(&hmm->lock);
 
        down_write(&hmm->mirrors_sem);
        mirror = list_first_entry_or_null(&hmm->mirrors, struct hmm_mirror,
@@ -186,36 +187,86 @@ static void hmm_release(struct mmu_notifier *mn, struct mm_struct *mm)
                                                  struct hmm_mirror, list);
        }
        up_write(&hmm->mirrors_sem);
+
+       hmm_put(hmm);
 }
 
 static int hmm_invalidate_range_start(struct mmu_notifier *mn,
-                       const struct mmu_notifier_range *range)
+                       const struct mmu_notifier_range *nrange)
 {
+       struct hmm *hmm = mm_get_hmm(nrange->mm);
+       struct hmm_mirror *mirror;
        struct hmm_update update;
-       struct hmm *hmm = range->mm->hmm;
+       struct hmm_range *range;
+       int ret = 0;
 
        VM_BUG_ON(!hmm);
 
-       update.start = range->start;
-       update.end = range->end;
+       update.start = nrange->start;
+       update.end = nrange->end;
        update.event = HMM_UPDATE_INVALIDATE;
-       update.blockable = range->blockable;
-       return hmm_invalidate_range(hmm, true, &update);
+       update.blockable = mmu_notifier_range_blockable(nrange);
+
+       if (mmu_notifier_range_blockable(nrange))
+               mutex_lock(&hmm->lock);
+       else if (!mutex_trylock(&hmm->lock)) {
+               ret = -EAGAIN;
+               goto out;
+       }
+       hmm->notifiers++;
+       list_for_each_entry(range, &hmm->ranges, list) {
+               if (update.end < range->start || update.start >= range->end)
+                       continue;
+
+               range->valid = false;
+       }
+       mutex_unlock(&hmm->lock);
+
+       if (mmu_notifier_range_blockable(nrange))
+               down_read(&hmm->mirrors_sem);
+       else if (!down_read_trylock(&hmm->mirrors_sem)) {
+               ret = -EAGAIN;
+               goto out;
+       }
+       list_for_each_entry(mirror, &hmm->mirrors, list) {
+               int ret;
+
+               ret = mirror->ops->sync_cpu_device_pagetables(mirror, &update);
+               if (!update.blockable && ret == -EAGAIN) {
+                       up_read(&hmm->mirrors_sem);
+                       ret = -EAGAIN;
+                       goto out;
+               }
+       }
+       up_read(&hmm->mirrors_sem);
+
+out:
+       hmm_put(hmm);
+       return ret;
 }
 
 static void hmm_invalidate_range_end(struct mmu_notifier *mn,
-                       const struct mmu_notifier_range *range)
+                       const struct mmu_notifier_range *nrange)
 {
-       struct hmm_update update;
-       struct hmm *hmm = range->mm->hmm;
+       struct hmm *hmm = mm_get_hmm(nrange->mm);
 
        VM_BUG_ON(!hmm);
 
-       update.start = range->start;
-       update.end = range->end;
-       update.event = HMM_UPDATE_INVALIDATE;
-       update.blockable = true;
-       hmm_invalidate_range(hmm, false, &update);
+       mutex_lock(&hmm->lock);
+       hmm->notifiers--;
+       if (!hmm->notifiers) {
+               struct hmm_range *range;
+
+               list_for_each_entry(range, &hmm->ranges, list) {
+                       if (range->valid)
+                               continue;
+                       range->valid = true;
+               }
+               wake_up_all(&hmm->wq);
+       }
+       mutex_unlock(&hmm->lock);
+
+       hmm_put(hmm);
 }
 
 static const struct mmu_notifier_ops hmm_mmu_notifier_ops = {
@@ -241,24 +292,13 @@ int hmm_mirror_register(struct hmm_mirror *mirror, struct mm_struct *mm)
        if (!mm || !mirror || !mirror->ops)
                return -EINVAL;
 
-again:
-       mirror->hmm = hmm_register(mm);
+       mirror->hmm = hmm_get_or_create(mm);
        if (!mirror->hmm)
                return -ENOMEM;
 
        down_write(&mirror->hmm->mirrors_sem);
-       if (mirror->hmm->mm == NULL) {
-               /*
-                * A racing hmm_mirror_unregister() is about to destroy the hmm
-                * struct. Try again to allocate a new one.
-                */
-               up_write(&mirror->hmm->mirrors_sem);
-               mirror->hmm = NULL;
-               goto again;
-       } else {
-               list_add(&mirror->list, &mirror->hmm->mirrors);
-               up_write(&mirror->hmm->mirrors_sem);
-       }
+       list_add(&mirror->list, &mirror->hmm->mirrors);
+       up_write(&mirror->hmm->mirrors_sem);
 
        return 0;
 }
@@ -273,38 +313,24 @@ EXPORT_SYMBOL(hmm_mirror_register);
  */
 void hmm_mirror_unregister(struct hmm_mirror *mirror)
 {
-       bool should_unregister = false;
-       struct mm_struct *mm;
-       struct hmm *hmm;
+       struct hmm *hmm = READ_ONCE(mirror->hmm);
 
-       if (mirror->hmm == NULL)
+       if (hmm == NULL)
                return;
 
-       hmm = mirror->hmm;
        down_write(&hmm->mirrors_sem);
        list_del_init(&mirror->list);
-       should_unregister = list_empty(&hmm->mirrors);
+       /* To protect us against double unregister ... */
        mirror->hmm = NULL;
-       mm = hmm->mm;
-       hmm->mm = NULL;
        up_write(&hmm->mirrors_sem);
 
-       if (!should_unregister || mm == NULL)
-               return;
-
-       mmu_notifier_unregister_no_release(&hmm->mmu_notifier, mm);
-
-       spin_lock(&mm->page_table_lock);
-       if (mm->hmm == hmm)
-               mm->hmm = NULL;
-       spin_unlock(&mm->page_table_lock);
-
-       kfree(hmm);
+       hmm_put(hmm);
 }
 EXPORT_SYMBOL(hmm_mirror_unregister);
 
 struct hmm_vma_walk {
        struct hmm_range        *range;
+       struct dev_pagemap      *pgmap;
        unsigned long           last;
        bool                    fault;
        bool                    block;
@@ -323,13 +349,13 @@ static int hmm_vma_do_fault(struct mm_walk *walk, unsigned long addr,
        flags |= write_fault ? FAULT_FLAG_WRITE : 0;
        ret = handle_mm_fault(vma, addr, flags);
        if (ret & VM_FAULT_RETRY)
-               return -EBUSY;
+               return -EAGAIN;
        if (ret & VM_FAULT_ERROR) {
                *pfn = range->values[HMM_PFN_ERROR];
                return -EFAULT;
        }
 
-       return -EAGAIN;
+       return -EBUSY;
 }
 
 static int hmm_pfns_bad(unsigned long addr,
@@ -355,7 +381,7 @@ static int hmm_pfns_bad(unsigned long addr,
  * @fault: should we fault or not ?
  * @write_fault: write fault ?
  * @walk: mm_walk structure
- * Returns: 0 on success, -EAGAIN after page fault, or page fault error
+ * Returns: 0 on success, -EBUSY after page fault, or page fault error
  *
  * This function will be called whenever pmd_none() or pte_none() returns true,
  * or whenever there is no page directory covering the virtual address range.
@@ -367,23 +393,25 @@ static int hmm_vma_walk_hole_(unsigned long addr, unsigned long end,
        struct hmm_vma_walk *hmm_vma_walk = walk->private;
        struct hmm_range *range = hmm_vma_walk->range;
        uint64_t *pfns = range->pfns;
-       unsigned long i;
+       unsigned long i, page_size;
 
        hmm_vma_walk->last = addr;
-       i = (addr - range->start) >> PAGE_SHIFT;
-       for (; addr < end; addr += PAGE_SIZE, i++) {
+       page_size = hmm_range_page_size(range);
+       i = (addr - range->start) >> range->page_shift;
+
+       for (; addr < end; addr += page_size, i++) {
                pfns[i] = range->values[HMM_PFN_NONE];
                if (fault || write_fault) {
                        int ret;
 
                        ret = hmm_vma_do_fault(walk, addr, write_fault,
                                               &pfns[i]);
-                       if (ret != -EAGAIN)
+                       if (ret != -EBUSY)
                                return ret;
                }
        }
 
-       return (fault || write_fault) ? -EAGAIN : 0;
+       return (fault || write_fault) ? -EBUSY : 0;
 }
 
 static inline void hmm_pte_need_fault(const struct hmm_vma_walk *hmm_vma_walk,
@@ -392,10 +420,21 @@ static inline void hmm_pte_need_fault(const struct hmm_vma_walk *hmm_vma_walk,
 {
        struct hmm_range *range = hmm_vma_walk->range;
 
-       *fault = *write_fault = false;
        if (!hmm_vma_walk->fault)
                return;
 
+       /*
+        * So we not only consider the individual per page request we also
+        * consider the default flags requested for the range. The API can
+        * be use in 2 fashions. The first one where the HMM user coalesce
+        * multiple page fault into one request and set flags per pfns for
+        * of those faults. The second one where the HMM user want to pre-
+        * fault a range with specific flags. For the latter one it is a
+        * waste to have the user pre-fill the pfn arrays with a default
+        * flags value.
+        */
+       pfns = (pfns & range->pfn_flags_mask) | range->default_flags;
+
        /* We aren't ask to do anything ... */
        if (!(pfns & range->flags[HMM_PFN_VALID]))
                return;
@@ -431,10 +470,11 @@ static void hmm_range_need_fault(const struct hmm_vma_walk *hmm_vma_walk,
                return;
        }
 
+       *fault = *write_fault = false;
        for (i = 0; i < npages; ++i) {
                hmm_pte_need_fault(hmm_vma_walk, pfns[i], cpu_flags,
                                   fault, write_fault);
-               if ((*fault) || (*write_fault))
+               if ((*write_fault))
                        return;
        }
 }
@@ -465,12 +505,22 @@ static inline uint64_t pmd_to_hmm_pfn_flags(struct hmm_range *range, pmd_t pmd)
                                range->flags[HMM_PFN_VALID];
 }
 
+static inline uint64_t pud_to_hmm_pfn_flags(struct hmm_range *range, pud_t pud)
+{
+       if (!pud_present(pud))
+               return 0;
+       return pud_write(pud) ? range->flags[HMM_PFN_VALID] |
+                               range->flags[HMM_PFN_WRITE] :
+                               range->flags[HMM_PFN_VALID];
+}
+
 static int hmm_vma_handle_pmd(struct mm_walk *walk,
                              unsigned long addr,
                              unsigned long end,
                              uint64_t *pfns,
                              pmd_t pmd)
 {
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
        struct hmm_vma_walk *hmm_vma_walk = walk->private;
        struct hmm_range *range = hmm_vma_walk->range;
        unsigned long pfn, npages, i;
@@ -486,10 +536,25 @@ static int hmm_vma_handle_pmd(struct mm_walk *walk,
                return hmm_vma_walk_hole_(addr, end, fault, write_fault, walk);
 
        pfn = pmd_pfn(pmd) + pte_index(addr);
-       for (i = 0; addr < end; addr += PAGE_SIZE, i++, pfn++)
-               pfns[i] = hmm_pfn_from_pfn(range, pfn) | cpu_flags;
+       for (i = 0; addr < end; addr += PAGE_SIZE, i++, pfn++) {
+               if (pmd_devmap(pmd)) {
+                       hmm_vma_walk->pgmap = get_dev_pagemap(pfn,
+                                             hmm_vma_walk->pgmap);
+                       if (unlikely(!hmm_vma_walk->pgmap))
+                               return -EBUSY;
+               }
+               pfns[i] = hmm_device_entry_from_pfn(range, pfn) | cpu_flags;
+       }
+       if (hmm_vma_walk->pgmap) {
+               put_dev_pagemap(hmm_vma_walk->pgmap);
+               hmm_vma_walk->pgmap = NULL;
+       }
        hmm_vma_walk->last = end;
        return 0;
+#else
+       /* If THP is not enabled then we should never reach that code ! */
+       return -EINVAL;
+#endif
 }
 
 static inline uint64_t pte_to_hmm_pfn_flags(struct hmm_range *range, pte_t pte)
@@ -514,11 +579,11 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
        uint64_t orig_pfn = *pfn;
 
        *pfn = range->values[HMM_PFN_NONE];
-       cpu_flags = pte_to_hmm_pfn_flags(range, pte);
-       hmm_pte_need_fault(hmm_vma_walk, orig_pfn, cpu_flags,
-                          &fault, &write_fault);
+       fault = write_fault = false;
 
        if (pte_none(pte)) {
+               hmm_pte_need_fault(hmm_vma_walk, orig_pfn, 0,
+                                  &fault, &write_fault);
                if (fault || write_fault)
                        goto fault;
                return 0;
@@ -546,7 +611,8 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
                                           &fault, &write_fault);
                        if (fault || write_fault)
                                goto fault;
-                       *pfn = hmm_pfn_from_pfn(range, swp_offset(entry));
+                       *pfn = hmm_device_entry_from_pfn(range,
+                                           swp_offset(entry));
                        *pfn |= cpu_flags;
                        return 0;
                }
@@ -557,7 +623,7 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
                                hmm_vma_walk->last = addr;
                                migration_entry_wait(vma->vm_mm,
                                                     pmdp, addr);
-                               return -EAGAIN;
+                               return -EBUSY;
                        }
                        return 0;
                }
@@ -565,15 +631,33 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
                /* Report error for everything else */
                *pfn = range->values[HMM_PFN_ERROR];
                return -EFAULT;
+       } else {
+               cpu_flags = pte_to_hmm_pfn_flags(range, pte);
+               hmm_pte_need_fault(hmm_vma_walk, orig_pfn, cpu_flags,
+                                  &fault, &write_fault);
        }
 
        if (fault || write_fault)
                goto fault;
 
-       *pfn = hmm_pfn_from_pfn(range, pte_pfn(pte)) | cpu_flags;
+       if (pte_devmap(pte)) {
+               hmm_vma_walk->pgmap = get_dev_pagemap(pte_pfn(pte),
+                                             hmm_vma_walk->pgmap);
+               if (unlikely(!hmm_vma_walk->pgmap))
+                       return -EBUSY;
+       } else if (IS_ENABLED(CONFIG_ARCH_HAS_PTE_SPECIAL) && pte_special(pte)) {
+               *pfn = range->values[HMM_PFN_SPECIAL];
+               return -EFAULT;
+       }
+
+       *pfn = hmm_device_entry_from_pfn(range, pte_pfn(pte)) | cpu_flags;
        return 0;
 
 fault:
+       if (hmm_vma_walk->pgmap) {
+               put_dev_pagemap(hmm_vma_walk->pgmap);
+               hmm_vma_walk->pgmap = NULL;
+       }
        pte_unmap(ptep);
        /* Fault any virtual address we were asked to fault */
        return hmm_vma_walk_hole_(addr, end, fault, write_fault, walk);
@@ -615,7 +699,7 @@ again:
                if (fault || write_fault) {
                        hmm_vma_walk->last = addr;
                        pmd_migration_entry_wait(vma->vm_mm, pmdp);
-                       return -EAGAIN;
+                       return -EBUSY;
                }
                return 0;
        } else if (!pmd_present(pmd))
@@ -661,12 +745,158 @@ again:
                        return r;
                }
        }
+       if (hmm_vma_walk->pgmap) {
+               /*
+                * We do put_dev_pagemap() here and not in hmm_vma_handle_pte()
+                * so that we can leverage get_dev_pagemap() optimization which
+                * will not re-take a reference on a pgmap if we already have
+                * one.
+                */
+               put_dev_pagemap(hmm_vma_walk->pgmap);
+               hmm_vma_walk->pgmap = NULL;
+       }
        pte_unmap(ptep - 1);
 
        hmm_vma_walk->last = addr;
        return 0;
 }
 
+static int hmm_vma_walk_pud(pud_t *pudp,
+                           unsigned long start,
+                           unsigned long end,
+                           struct mm_walk *walk)
+{
+       struct hmm_vma_walk *hmm_vma_walk = walk->private;
+       struct hmm_range *range = hmm_vma_walk->range;
+       unsigned long addr = start, next;
+       pmd_t *pmdp;
+       pud_t pud;
+       int ret;
+
+again:
+       pud = READ_ONCE(*pudp);
+       if (pud_none(pud))
+               return hmm_vma_walk_hole(start, end, walk);
+
+       if (pud_huge(pud) && pud_devmap(pud)) {
+               unsigned long i, npages, pfn;
+               uint64_t *pfns, cpu_flags;
+               bool fault, write_fault;
+
+               if (!pud_present(pud))
+                       return hmm_vma_walk_hole(start, end, walk);
+
+               i = (addr - range->start) >> PAGE_SHIFT;
+               npages = (end - addr) >> PAGE_SHIFT;
+               pfns = &range->pfns[i];
+
+               cpu_flags = pud_to_hmm_pfn_flags(range, pud);
+               hmm_range_need_fault(hmm_vma_walk, pfns, npages,
+                                    cpu_flags, &fault, &write_fault);
+               if (fault || write_fault)
+                       return hmm_vma_walk_hole_(addr, end, fault,
+                                               write_fault, walk);
+
+#ifdef CONFIG_HUGETLB_PAGE
+               pfn = pud_pfn(pud) + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
+               for (i = 0; i < npages; ++i, ++pfn) {
+                       hmm_vma_walk->pgmap = get_dev_pagemap(pfn,
+                                             hmm_vma_walk->pgmap);
+                       if (unlikely(!hmm_vma_walk->pgmap))
+                               return -EBUSY;
+                       pfns[i] = hmm_device_entry_from_pfn(range, pfn) |
+                                 cpu_flags;
+               }
+               if (hmm_vma_walk->pgmap) {
+                       put_dev_pagemap(hmm_vma_walk->pgmap);
+                       hmm_vma_walk->pgmap = NULL;
+               }
+               hmm_vma_walk->last = end;
+               return 0;
+#else
+               return -EINVAL;
+#endif
+       }
+
+       split_huge_pud(walk->vma, pudp, addr);
+       if (pud_none(*pudp))
+               goto again;
+
+       pmdp = pmd_offset(pudp, addr);
+       do {
+               next = pmd_addr_end(addr, end);
+               ret = hmm_vma_walk_pmd(pmdp, addr, next, walk);
+               if (ret)
+                       return ret;
+       } while (pmdp++, addr = next, addr != end);
+
+       return 0;
+}
+
+static int hmm_vma_walk_hugetlb_entry(pte_t *pte, unsigned long hmask,
+                                     unsigned long start, unsigned long end,
+                                     struct mm_walk *walk)
+{
+#ifdef CONFIG_HUGETLB_PAGE
+       unsigned long addr = start, i, pfn, mask, size, pfn_inc;
+       struct hmm_vma_walk *hmm_vma_walk = walk->private;
+       struct hmm_range *range = hmm_vma_walk->range;
+       struct vm_area_struct *vma = walk->vma;
+       struct hstate *h = hstate_vma(vma);
+       uint64_t orig_pfn, cpu_flags;
+       bool fault, write_fault;
+       spinlock_t *ptl;
+       pte_t entry;
+       int ret = 0;
+
+       size = 1UL << huge_page_shift(h);
+       mask = size - 1;
+       if (range->page_shift != PAGE_SHIFT) {
+               /* Make sure we are looking at full page. */
+               if (start & mask)
+                       return -EINVAL;
+               if (end < (start + size))
+                       return -EINVAL;
+               pfn_inc = size >> PAGE_SHIFT;
+       } else {
+               pfn_inc = 1;
+               size = PAGE_SIZE;
+       }
+
+
+       ptl = huge_pte_lock(hstate_vma(walk->vma), walk->mm, pte);
+       entry = huge_ptep_get(pte);
+
+       i = (start - range->start) >> range->page_shift;
+       orig_pfn = range->pfns[i];
+       range->pfns[i] = range->values[HMM_PFN_NONE];
+       cpu_flags = pte_to_hmm_pfn_flags(range, entry);
+       fault = write_fault = false;
+       hmm_pte_need_fault(hmm_vma_walk, orig_pfn, cpu_flags,
+                          &fault, &write_fault);
+       if (fault || write_fault) {
+               ret = -ENOENT;
+               goto unlock;
+       }
+
+       pfn = pte_pfn(entry) + ((start & mask) >> range->page_shift);
+       for (; addr < end; addr += size, i++, pfn += pfn_inc)
+               range->pfns[i] = hmm_device_entry_from_pfn(range, pfn) |
+                                cpu_flags;
+       hmm_vma_walk->last = end;
+
+unlock:
+       spin_unlock(ptl);
+
+       if (ret == -ENOENT)
+               return hmm_vma_walk_hole_(addr, end, fault, write_fault, walk);
+
+       return ret;
+#else /* CONFIG_HUGETLB_PAGE */
+       return -EINVAL;
+#endif
+}
+
 static void hmm_pfns_clear(struct hmm_range *range,
                           uint64_t *pfns,
                           unsigned long addr,
@@ -676,279 +906,437 @@ static void hmm_pfns_clear(struct hmm_range *range,
                *pfns = range->values[HMM_PFN_NONE];
 }
 
-static void hmm_pfns_special(struct hmm_range *range)
-{
-       unsigned long addr = range->start, i = 0;
-
-       for (; addr < range->end; addr += PAGE_SIZE, i++)
-               range->pfns[i] = range->values[HMM_PFN_SPECIAL];
-}
-
 /*
- * hmm_vma_get_pfns() - snapshot CPU page table for a range of virtual addresses
- * @range: range being snapshotted
- * Returns: -EINVAL if invalid argument, -ENOMEM out of memory, -EPERM invalid
- *          vma permission, 0 success
- *
- * This snapshots the CPU page table for a range of virtual addresses. Snapshot
- * validity is tracked by range struct. See hmm_vma_range_done() for further
- * information.
- *
- * The range struct is initialized here. It tracks the CPU page table, but only
- * if the function returns success (0), in which case the caller must then call
- * hmm_vma_range_done() to stop CPU page table update tracking on this range.
+ * hmm_range_register() - start tracking change to CPU page table over a range
+ * @range: range
+ * @mm: the mm struct for the range of virtual address
+ * @start: start virtual address (inclusive)
+ * @end: end virtual address (exclusive)
+ * @page_shift: expect page shift for the range
+ * Returns 0 on success, -EFAULT if the address space is no longer valid
  *
- * NOT CALLING hmm_vma_range_done() IF FUNCTION RETURNS 0 WILL LEAD TO SERIOUS
- * MEMORY CORRUPTION ! YOU HAVE BEEN WARNED !
+ * Track updates to the CPU page table see include/linux/hmm.h
  */
-int hmm_vma_get_pfns(struct hmm_range *range)
+int hmm_range_register(struct hmm_range *range,
+                      struct mm_struct *mm,
+                      unsigned long start,
+                      unsigned long end,
+                      unsigned page_shift)
 {
-       struct vm_area_struct *vma = range->vma;
-       struct hmm_vma_walk hmm_vma_walk;
-       struct mm_walk mm_walk;
-       struct hmm *hmm;
+       unsigned long mask = ((1UL << page_shift) - 1UL);
+
+       range->valid = false;
+       range->hmm = NULL;
 
-       /* Sanity check, this really should not happen ! */
-       if (range->start < vma->vm_start || range->start >= vma->vm_end)
+       if ((start & mask) || (end & mask))
                return -EINVAL;
-       if (range->end < vma->vm_start || range->end > vma->vm_end)
+       if (start >= end)
                return -EINVAL;
 
-       hmm = hmm_register(vma->vm_mm);
-       if (!hmm)
-               return -ENOMEM;
-       /* Caller must have registered a mirror, via hmm_mirror_register() ! */
-       if (!hmm->mmu_notifier.ops)
-               return -EINVAL;
+       range->page_shift = page_shift;
+       range->start = start;
+       range->end = end;
 
-       /* FIXME support hugetlb fs */
-       if (is_vm_hugetlb_page(vma) || (vma->vm_flags & VM_SPECIAL) ||
-                       vma_is_dax(vma)) {
-               hmm_pfns_special(range);
-               return -EINVAL;
-       }
+       range->hmm = hmm_get_or_create(mm);
+       if (!range->hmm)
+               return -EFAULT;
 
-       if (!(vma->vm_flags & VM_READ)) {
-               /*
-                * If vma do not allow read access, then assume that it does
-                * not allow write access, either. Architecture that allow
-                * write without read access are not supported by HMM, because
-                * operations such has atomic access would not work.
-                */
-               hmm_pfns_clear(range, range->pfns, range->start, range->end);
-               return -EPERM;
+       /* Check if hmm_mm_destroy() was call. */
+       if (range->hmm->mm == NULL || range->hmm->dead) {
+               hmm_put(range->hmm);
+               return -EFAULT;
        }
 
        /* Initialize range to track CPU page table update */
-       spin_lock(&hmm->lock);
-       range->valid = true;
-       list_add_rcu(&range->list, &hmm->ranges);
-       spin_unlock(&hmm->lock);
-
-       hmm_vma_walk.fault = false;
-       hmm_vma_walk.range = range;
-       mm_walk.private = &hmm_vma_walk;
-
-       mm_walk.vma = vma;
-       mm_walk.mm = vma->vm_mm;
-       mm_walk.pte_entry = NULL;
-       mm_walk.test_walk = NULL;
-       mm_walk.hugetlb_entry = NULL;
-       mm_walk.pmd_entry = hmm_vma_walk_pmd;
-       mm_walk.pte_hole = hmm_vma_walk_hole;
-
-       walk_page_range(range->start, range->end, &mm_walk);
+       mutex_lock(&range->hmm->lock);
+
+       list_add_rcu(&range->list, &range->hmm->ranges);
+
+       /*
+        * If there are any concurrent notifiers we have to wait for them for
+        * the range to be valid (see hmm_range_wait_until_valid()).
+        */
+       if (!range->hmm->notifiers)
+               range->valid = true;
+       mutex_unlock(&range->hmm->lock);
+
        return 0;
 }
-EXPORT_SYMBOL(hmm_vma_get_pfns);
+EXPORT_SYMBOL(hmm_range_register);
 
 /*
- * hmm_vma_range_done() - stop tracking change to CPU page table over a range
- * @range: range being tracked
- * Returns: false if range data has been invalidated, true otherwise
+ * hmm_range_unregister() - stop tracking change to CPU page table over a range
+ * @range: range
  *
  * Range struct is used to track updates to the CPU page table after a call to
- * either hmm_vma_get_pfns() or hmm_vma_fault(). Once the device driver is done
- * using the data,  or wants to lock updates to the data it got from those
- * functions, it must call the hmm_vma_range_done() function, which will then
- * stop tracking CPU page table updates.
- *
- * Note that device driver must still implement general CPU page table update
- * tracking either by using hmm_mirror (see hmm_mirror_register()) or by using
- * the mmu_notifier API directly.
- *
- * CPU page table update tracking done through hmm_range is only temporary and
- * to be used while trying to duplicate CPU page table contents for a range of
- * virtual addresses.
- *
- * There are two ways to use this :
- * again:
- *   hmm_vma_get_pfns(range); or hmm_vma_fault(...);
- *   trans = device_build_page_table_update_transaction(pfns);
- *   device_page_table_lock();
- *   if (!hmm_vma_range_done(range)) {
- *     device_page_table_unlock();
- *     goto again;
- *   }
- *   device_commit_transaction(trans);
- *   device_page_table_unlock();
+ * hmm_range_register(). See include/linux/hmm.h for how to use it.
+ */
+void hmm_range_unregister(struct hmm_range *range)
+{
+       /* Sanity check this really should not happen. */
+       if (range->hmm == NULL || range->end <= range->start)
+               return;
+
+       mutex_lock(&range->hmm->lock);
+       list_del_rcu(&range->list);
+       mutex_unlock(&range->hmm->lock);
+
+       /* Drop reference taken by hmm_range_register() */
+       range->valid = false;
+       hmm_put(range->hmm);
+       range->hmm = NULL;
+}
+EXPORT_SYMBOL(hmm_range_unregister);
+
+/*
+ * hmm_range_snapshot() - snapshot CPU page table for a range
+ * @range: range
+ * Returns: -EINVAL if invalid argument, -ENOMEM out of memory, -EPERM invalid
+ *          permission (for instance asking for write and range is read only),
+ *          -EAGAIN if you need to retry, -EFAULT invalid (ie either no valid
+ *          vma or it is illegal to access that range), number of valid pages
+ *          in range->pfns[] (from range start address).
  *
- * Or:
- *   hmm_vma_get_pfns(range); or hmm_vma_fault(...);
- *   device_page_table_lock();
- *   hmm_vma_range_done(range);
- *   device_update_page_table(range->pfns);
- *   device_page_table_unlock();
+ * This snapshots the CPU page table for a range of virtual addresses. Snapshot
+ * validity is tracked by range struct. See in include/linux/hmm.h for example
+ * on how to use.
  */
-bool hmm_vma_range_done(struct hmm_range *range)
+long hmm_range_snapshot(struct hmm_range *range)
 {
-       unsigned long npages = (range->end - range->start) >> PAGE_SHIFT;
-       struct hmm *hmm;
+       const unsigned long device_vma = VM_IO | VM_PFNMAP | VM_MIXEDMAP;
+       unsigned long start = range->start, end;
+       struct hmm_vma_walk hmm_vma_walk;
+       struct hmm *hmm = range->hmm;
+       struct vm_area_struct *vma;
+       struct mm_walk mm_walk;
 
-       if (range->end <= range->start) {
-               BUG();
-               return false;
-       }
+       /* Check if hmm_mm_destroy() was call. */
+       if (hmm->mm == NULL || hmm->dead)
+               return -EFAULT;
 
-       hmm = hmm_register(range->vma->vm_mm);
-       if (!hmm) {
-               memset(range->pfns, 0, sizeof(*range->pfns) * npages);
-               return false;
-       }
+       do {
+               /* If range is no longer valid force retry. */
+               if (!range->valid)
+                       return -EAGAIN;
 
-       spin_lock(&hmm->lock);
-       list_del_rcu(&range->list);
-       spin_unlock(&hmm->lock);
+               vma = find_vma(hmm->mm, start);
+               if (vma == NULL || (vma->vm_flags & device_vma))
+                       return -EFAULT;
+
+               if (is_vm_hugetlb_page(vma)) {
+                       struct hstate *h = hstate_vma(vma);
 
-       return range->valid;
+                       if (huge_page_shift(h) != range->page_shift &&
+                           range->page_shift != PAGE_SHIFT)
+                               return -EINVAL;
+               } else {
+                       if (range->page_shift != PAGE_SHIFT)
+                               return -EINVAL;
+               }
+
+               if (!(vma->vm_flags & VM_READ)) {
+                       /*
+                        * If vma do not allow read access, then assume that it
+                        * does not allow write access, either. HMM does not
+                        * support architecture that allow write without read.
+                        */
+                       hmm_pfns_clear(range, range->pfns,
+                               range->start, range->end);
+                       return -EPERM;
+               }
+
+               range->vma = vma;
+               hmm_vma_walk.pgmap = NULL;
+               hmm_vma_walk.last = start;
+               hmm_vma_walk.fault = false;
+               hmm_vma_walk.range = range;
+               mm_walk.private = &hmm_vma_walk;
+               end = min(range->end, vma->vm_end);
+
+               mm_walk.vma = vma;
+               mm_walk.mm = vma->vm_mm;
+               mm_walk.pte_entry = NULL;
+               mm_walk.test_walk = NULL;
+               mm_walk.hugetlb_entry = NULL;
+               mm_walk.pud_entry = hmm_vma_walk_pud;
+               mm_walk.pmd_entry = hmm_vma_walk_pmd;
+               mm_walk.pte_hole = hmm_vma_walk_hole;
+               mm_walk.hugetlb_entry = hmm_vma_walk_hugetlb_entry;
+
+               walk_page_range(start, end, &mm_walk);
+               start = end;
+       } while (start < range->end);
+
+       return (hmm_vma_walk.last - range->start) >> PAGE_SHIFT;
 }
-EXPORT_SYMBOL(hmm_vma_range_done);
+EXPORT_SYMBOL(hmm_range_snapshot);
 
 /*
- * hmm_vma_fault() - try to fault some address in a virtual address range
+ * hmm_range_fault() - try to fault some address in a virtual address range
  * @range: range being faulted
  * @block: allow blocking on fault (if true it sleeps and do not drop mmap_sem)
- * Returns: 0 success, error otherwise (-EAGAIN means mmap_sem have been drop)
+ * Returns: number of valid pages in range->pfns[] (from range start
+ *          address). This may be zero. If the return value is negative,
+ *          then one of the following values may be returned:
+ *
+ *           -EINVAL  invalid arguments or mm or virtual address are in an
+ *                    invalid vma (for instance device file vma).
+ *           -ENOMEM: Out of memory.
+ *           -EPERM:  Invalid permission (for instance asking for write and
+ *                    range is read only).
+ *           -EAGAIN: If you need to retry and mmap_sem was drop. This can only
+ *                    happens if block argument is false.
+ *           -EBUSY:  If the the range is being invalidated and you should wait
+ *                    for invalidation to finish.
+ *           -EFAULT: Invalid (ie either no valid vma or it is illegal to access
+ *                    that range), number of valid pages in range->pfns[] (from
+ *                    range start address).
  *
  * This is similar to a regular CPU page fault except that it will not trigger
- * any memory migration if the memory being faulted is not accessible by CPUs.
+ * any memory migration if the memory being faulted is not accessible by CPUs
+ * and caller does not ask for migration.
  *
  * On error, for one virtual address in the range, the function will mark the
  * corresponding HMM pfn entry with an error flag.
- *
- * Expected use pattern:
- * retry:
- *   down_read(&mm->mmap_sem);
- *   // Find vma and address device wants to fault, initialize hmm_pfn_t
- *   // array accordingly
- *   ret = hmm_vma_fault(range, write, block);
- *   switch (ret) {
- *   case -EAGAIN:
- *     hmm_vma_range_done(range);
- *     // You might want to rate limit or yield to play nicely, you may
- *     // also commit any valid pfn in the array assuming that you are
- *     // getting true from hmm_vma_range_monitor_end()
- *     goto retry;
- *   case 0:
- *     break;
- *   case -ENOMEM:
- *   case -EINVAL:
- *   case -EPERM:
- *   default:
- *     // Handle error !
- *     up_read(&mm->mmap_sem)
- *     return;
- *   }
- *   // Take device driver lock that serialize device page table update
- *   driver_lock_device_page_table_update();
- *   hmm_vma_range_done(range);
- *   // Commit pfns we got from hmm_vma_fault()
- *   driver_unlock_device_page_table_update();
- *   up_read(&mm->mmap_sem)
- *
- * YOU MUST CALL hmm_vma_range_done() AFTER THIS FUNCTION RETURN SUCCESS (0)
- * BEFORE FREEING THE range struct OR YOU WILL HAVE SERIOUS MEMORY CORRUPTION !
- *
- * YOU HAVE BEEN WARNED !
  */
-int hmm_vma_fault(struct hmm_range *range, bool block)
+long hmm_range_fault(struct hmm_range *range, bool block)
 {
-       struct vm_area_struct *vma = range->vma;
-       unsigned long start = range->start;
+       const unsigned long device_vma = VM_IO | VM_PFNMAP | VM_MIXEDMAP;
+       unsigned long start = range->start, end;
        struct hmm_vma_walk hmm_vma_walk;
+       struct hmm *hmm = range->hmm;
+       struct vm_area_struct *vma;
        struct mm_walk mm_walk;
-       struct hmm *hmm;
        int ret;
 
-       /* Sanity check, this really should not happen ! */
-       if (range->start < vma->vm_start || range->start >= vma->vm_end)
-               return -EINVAL;
-       if (range->end < vma->vm_start || range->end > vma->vm_end)
-               return -EINVAL;
+       /* Check if hmm_mm_destroy() was call. */
+       if (hmm->mm == NULL || hmm->dead)
+               return -EFAULT;
 
-       hmm = hmm_register(vma->vm_mm);
-       if (!hmm) {
-               hmm_pfns_clear(range, range->pfns, range->start, range->end);
-               return -ENOMEM;
-       }
-       /* Caller must have registered a mirror using hmm_mirror_register() */
-       if (!hmm->mmu_notifier.ops)
-               return -EINVAL;
+       do {
+               /* If range is no longer valid force retry. */
+               if (!range->valid) {
+                       up_read(&hmm->mm->mmap_sem);
+                       return -EAGAIN;
+               }
 
-       /* FIXME support hugetlb fs */
-       if (is_vm_hugetlb_page(vma) || (vma->vm_flags & VM_SPECIAL) ||
-                       vma_is_dax(vma)) {
-               hmm_pfns_special(range);
-               return -EINVAL;
-       }
+               vma = find_vma(hmm->mm, start);
+               if (vma == NULL || (vma->vm_flags & device_vma))
+                       return -EFAULT;
+
+               if (is_vm_hugetlb_page(vma)) {
+                       if (huge_page_shift(hstate_vma(vma)) !=
+                           range->page_shift &&
+                           range->page_shift != PAGE_SHIFT)
+                               return -EINVAL;
+               } else {
+                       if (range->page_shift != PAGE_SHIFT)
+                               return -EINVAL;
+               }
+
+               if (!(vma->vm_flags & VM_READ)) {
+                       /*
+                        * If vma do not allow read access, then assume that it
+                        * does not allow write access, either. HMM does not
+                        * support architecture that allow write without read.
+                        */
+                       hmm_pfns_clear(range, range->pfns,
+                               range->start, range->end);
+                       return -EPERM;
+               }
+
+               range->vma = vma;
+               hmm_vma_walk.pgmap = NULL;
+               hmm_vma_walk.last = start;
+               hmm_vma_walk.fault = true;
+               hmm_vma_walk.block = block;
+               hmm_vma_walk.range = range;
+               mm_walk.private = &hmm_vma_walk;
+               end = min(range->end, vma->vm_end);
+
+               mm_walk.vma = vma;
+               mm_walk.mm = vma->vm_mm;
+               mm_walk.pte_entry = NULL;
+               mm_walk.test_walk = NULL;
+               mm_walk.hugetlb_entry = NULL;
+               mm_walk.pud_entry = hmm_vma_walk_pud;
+               mm_walk.pmd_entry = hmm_vma_walk_pmd;
+               mm_walk.pte_hole = hmm_vma_walk_hole;
+               mm_walk.hugetlb_entry = hmm_vma_walk_hugetlb_entry;
+
+               do {
+                       ret = walk_page_range(start, end, &mm_walk);
+                       start = hmm_vma_walk.last;
+
+                       /* Keep trying while the range is valid. */
+               } while (ret == -EBUSY && range->valid);
+
+               if (ret) {
+                       unsigned long i;
+
+                       i = (hmm_vma_walk.last - range->start) >> PAGE_SHIFT;
+                       hmm_pfns_clear(range, &range->pfns[i],
+                               hmm_vma_walk.last, range->end);
+                       return ret;
+               }
+               start = end;
+
+       } while (start < range->end);
+
+       return (hmm_vma_walk.last - range->start) >> PAGE_SHIFT;
+}
+EXPORT_SYMBOL(hmm_range_fault);
+
+/**
+ * hmm_range_dma_map() - hmm_range_fault() and dma map page all in one.
+ * @range: range being faulted
+ * @device: device against to dma map page to
+ * @daddrs: dma address of mapped pages
+ * @block: allow blocking on fault (if true it sleeps and do not drop mmap_sem)
+ * Returns: number of pages mapped on success, -EAGAIN if mmap_sem have been
+ *          drop and you need to try again, some other error value otherwise
+ *
+ * Note same usage pattern as hmm_range_fault().
+ */
+long hmm_range_dma_map(struct hmm_range *range,
+                      struct device *device,
+                      dma_addr_t *daddrs,
+                      bool block)
+{
+       unsigned long i, npages, mapped;
+       long ret;
+
+       ret = hmm_range_fault(range, block);
+       if (ret <= 0)
+               return ret ? ret : -EBUSY;
+
+       npages = (range->end - range->start) >> PAGE_SHIFT;
+       for (i = 0, mapped = 0; i < npages; ++i) {
+               enum dma_data_direction dir = DMA_TO_DEVICE;
+               struct page *page;
 
-       if (!(vma->vm_flags & VM_READ)) {
                /*
-                * If vma do not allow read access, then assume that it does
-                * not allow write access, either. Architecture that allow
-                * write without read access are not supported by HMM, because
-                * operations such has atomic access would not work.
+                * FIXME need to update DMA API to provide invalid DMA address
+                * value instead of a function to test dma address value. This
+                * would remove lot of dumb code duplicated accross many arch.
+                *
+                * For now setting it to 0 here is good enough as the pfns[]
+                * value is what is use to check what is valid and what isn't.
                 */
-               hmm_pfns_clear(range, range->pfns, range->start, range->end);
-               return -EPERM;
+               daddrs[i] = 0;
+
+               page = hmm_device_entry_to_page(range, range->pfns[i]);
+               if (page == NULL)
+                       continue;
+
+               /* Check if range is being invalidated */
+               if (!range->valid) {
+                       ret = -EBUSY;
+                       goto unmap;
+               }
+
+               /* If it is read and write than map bi-directional. */
+               if (range->pfns[i] & range->flags[HMM_PFN_WRITE])
+                       dir = DMA_BIDIRECTIONAL;
+
+               daddrs[i] = dma_map_page(device, page, 0, PAGE_SIZE, dir);
+               if (dma_mapping_error(device, daddrs[i])) {
+                       ret = -EFAULT;
+                       goto unmap;
+               }
+
+               mapped++;
        }
 
-       /* Initialize range to track CPU page table update */
-       spin_lock(&hmm->lock);
-       range->valid = true;
-       list_add_rcu(&range->list, &hmm->ranges);
-       spin_unlock(&hmm->lock);
-
-       hmm_vma_walk.fault = true;
-       hmm_vma_walk.block = block;
-       hmm_vma_walk.range = range;
-       mm_walk.private = &hmm_vma_walk;
-       hmm_vma_walk.last = range->start;
-
-       mm_walk.vma = vma;
-       mm_walk.mm = vma->vm_mm;
-       mm_walk.pte_entry = NULL;
-       mm_walk.test_walk = NULL;
-       mm_walk.hugetlb_entry = NULL;
-       mm_walk.pmd_entry = hmm_vma_walk_pmd;
-       mm_walk.pte_hole = hmm_vma_walk_hole;
+       return mapped;
 
-       do {
-               ret = walk_page_range(start, range->end, &mm_walk);
-               start = hmm_vma_walk.last;
-       } while (ret == -EAGAIN);
+unmap:
+       for (npages = i, i = 0; (i < npages) && mapped; ++i) {
+               enum dma_data_direction dir = DMA_TO_DEVICE;
+               struct page *page;
 
-       if (ret) {
-               unsigned long i;
+               page = hmm_device_entry_to_page(range, range->pfns[i]);
+               if (page == NULL)
+                       continue;
+
+               if (dma_mapping_error(device, daddrs[i]))
+                       continue;
 
-               i = (hmm_vma_walk.last - range->start) >> PAGE_SHIFT;
-               hmm_pfns_clear(range, &range->pfns[i], hmm_vma_walk.last,
-                              range->end);
-               hmm_vma_range_done(range);
+               /* If it is read and write than map bi-directional. */
+               if (range->pfns[i] & range->flags[HMM_PFN_WRITE])
+                       dir = DMA_BIDIRECTIONAL;
+
+               dma_unmap_page(device, daddrs[i], PAGE_SIZE, dir);
+               mapped--;
        }
+
        return ret;
 }
-EXPORT_SYMBOL(hmm_vma_fault);
+EXPORT_SYMBOL(hmm_range_dma_map);
+
+/**
+ * hmm_range_dma_unmap() - unmap range of that was map with hmm_range_dma_map()
+ * @range: range being unmapped
+ * @vma: the vma against which the range (optional)
+ * @device: device against which dma map was done
+ * @daddrs: dma address of mapped pages
+ * @dirty: dirty page if it had the write flag set
+ * Returns: number of page unmapped on success, -EINVAL otherwise
+ *
+ * Note that caller MUST abide by mmu notifier or use HMM mirror and abide
+ * to the sync_cpu_device_pagetables() callback so that it is safe here to
+ * call set_page_dirty(). Caller must also take appropriate locks to avoid
+ * concurrent mmu notifier or sync_cpu_device_pagetables() to make progress.
+ */
+long hmm_range_dma_unmap(struct hmm_range *range,
+                        struct vm_area_struct *vma,
+                        struct device *device,
+                        dma_addr_t *daddrs,
+                        bool dirty)
+{
+       unsigned long i, npages;
+       long cpages = 0;
+
+       /* Sanity check. */
+       if (range->end <= range->start)
+               return -EINVAL;
+       if (!daddrs)
+               return -EINVAL;
+       if (!range->pfns)
+               return -EINVAL;
+
+       npages = (range->end - range->start) >> PAGE_SHIFT;
+       for (i = 0; i < npages; ++i) {
+               enum dma_data_direction dir = DMA_TO_DEVICE;
+               struct page *page;
+
+               page = hmm_device_entry_to_page(range, range->pfns[i]);
+               if (page == NULL)
+                       continue;
+
+               /* If it is read and write than map bi-directional. */
+               if (range->pfns[i] & range->flags[HMM_PFN_WRITE]) {
+                       dir = DMA_BIDIRECTIONAL;
+
+                       /*
+                        * See comments in function description on why it is
+                        * safe here to call set_page_dirty()
+                        */
+                       if (dirty)
+                               set_page_dirty(page);
+               }
+
+               /* Unmap and clear pfns/dma address */
+               dma_unmap_page(device, daddrs[i], PAGE_SIZE, dir);
+               range->pfns[i] = range->values[HMM_PFN_NONE];
+               /* FIXME see comments in hmm_vma_dma_map() */
+               daddrs[i] = 0;
+               cpages++;
+       }
+
+       return cpages;
+}
+EXPORT_SYMBOL(hmm_range_dma_unmap);
 #endif /* IS_ENABLED(CONFIG_HMM_MIRROR) */
 
 
index b6a34b32d8ac96caaea90d5a68b4d090bbc1d85a..9f8bce9a6b32ed2a0f29a51c23e539668acada3b 100644 (file)
@@ -509,7 +509,7 @@ void prep_transhuge_page(struct page *page)
        set_compound_page_dtor(page, TRANSHUGE_PAGE_DTOR);
 }
 
-unsigned long __thp_get_unmapped_area(struct file *filp, unsigned long len,
+static unsigned long __thp_get_unmapped_area(struct file *filp, unsigned long len,
                loff_t off, unsigned long flags, unsigned long size)
 {
        unsigned long addr;
@@ -793,11 +793,13 @@ out_unlock:
                pte_free(mm, pgtable);
 }
 
-vm_fault_t vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
-                       pmd_t *pmd, pfn_t pfn, bool write)
+vm_fault_t vmf_insert_pfn_pmd(struct vm_fault *vmf, pfn_t pfn, bool write)
 {
+       unsigned long addr = vmf->address & PMD_MASK;
+       struct vm_area_struct *vma = vmf->vma;
        pgprot_t pgprot = vma->vm_page_prot;
        pgtable_t pgtable = NULL;
+
        /*
         * If we had pmd_special, we could avoid all these restrictions,
         * but we need to be consistent with PTEs and architectures that
@@ -820,7 +822,7 @@ vm_fault_t vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
 
        track_pfn_insert(vma, &pgprot, pfn);
 
-       insert_pfn_pmd(vma, addr, pmd, pfn, pgprot, write, pgtable);
+       insert_pfn_pmd(vma, addr, vmf->pmd, pfn, pgprot, write, pgtable);
        return VM_FAULT_NOPAGE;
 }
 EXPORT_SYMBOL_GPL(vmf_insert_pfn_pmd);
@@ -869,10 +871,12 @@ out_unlock:
        spin_unlock(ptl);
 }
 
-vm_fault_t vmf_insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr,
-                       pud_t *pud, pfn_t pfn, bool write)
+vm_fault_t vmf_insert_pfn_pud(struct vm_fault *vmf, pfn_t pfn, bool write)
 {
+       unsigned long addr = vmf->address & PUD_MASK;
+       struct vm_area_struct *vma = vmf->vma;
        pgprot_t pgprot = vma->vm_page_prot;
+
        /*
         * If we had pud_special, we could avoid all these restrictions,
         * but we need to be consistent with PTEs and architectures that
@@ -889,7 +893,7 @@ vm_fault_t vmf_insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr,
 
        track_pfn_insert(vma, &pgprot, pfn);
 
-       insert_pfn_pud(vma, addr, pud, pfn, pgprot, write);
+       insert_pfn_pud(vma, addr, vmf->pud, pfn, pgprot, write);
        return VM_FAULT_NOPAGE;
 }
 EXPORT_SYMBOL_GPL(vmf_insert_pfn_pud);
@@ -1220,8 +1224,8 @@ static vm_fault_t do_huge_pmd_wp_page_fallback(struct vm_fault *vmf,
                cond_resched();
        }
 
-       mmu_notifier_range_init(&range, vma->vm_mm, haddr,
-                               haddr + HPAGE_PMD_SIZE);
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, vma->vm_mm,
+                               haddr, haddr + HPAGE_PMD_SIZE);
        mmu_notifier_invalidate_range_start(&range);
 
        vmf->ptl = pmd_lock(vma->vm_mm, vmf->pmd);
@@ -1384,8 +1388,8 @@ alloc:
                                    vma, HPAGE_PMD_NR);
        __SetPageUptodate(new_page);
 
-       mmu_notifier_range_init(&range, vma->vm_mm, haddr,
-                               haddr + HPAGE_PMD_SIZE);
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, vma->vm_mm,
+                               haddr, haddr + HPAGE_PMD_SIZE);
        mmu_notifier_invalidate_range_start(&range);
 
        spin_lock(vmf->ptl);
@@ -2060,7 +2064,8 @@ void __split_huge_pud(struct vm_area_struct *vma, pud_t *pud,
        spinlock_t *ptl;
        struct mmu_notifier_range range;
 
-       mmu_notifier_range_init(&range, vma->vm_mm, address & HPAGE_PUD_MASK,
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, vma->vm_mm,
+                               address & HPAGE_PUD_MASK,
                                (address & HPAGE_PUD_MASK) + HPAGE_PUD_SIZE);
        mmu_notifier_invalidate_range_start(&range);
        ptl = pud_lock(vma->vm_mm, pud);
@@ -2278,7 +2283,8 @@ void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
        spinlock_t *ptl;
        struct mmu_notifier_range range;
 
-       mmu_notifier_range_init(&range, vma->vm_mm, address & HPAGE_PMD_MASK,
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, vma->vm_mm,
+                               address & HPAGE_PMD_MASK,
                                (address & HPAGE_PMD_MASK) + HPAGE_PMD_SIZE);
        mmu_notifier_invalidate_range_start(&range);
        ptl = pmd_lock(vma->vm_mm, pmd);
@@ -2492,6 +2498,9 @@ static void __split_huge_page(struct page *page, struct list_head *list,
                        if (IS_ENABLED(CONFIG_SHMEM) && PageSwapBacked(head))
                                shmem_uncharge(head->mapping->host, 1);
                        put_page(head + i);
+               } else if (!PageAnon(page)) {
+                       __xa_store(&head->mapping->i_pages, head[i].index,
+                                       head + i, 0);
                }
        }
 
index 641cedfc8c0fd0c3d81311ac1bb7abb936e970b3..81718c56b8f5d951cce489e17222bdae1fa2a852 100644 (file)
@@ -740,7 +740,15 @@ void resv_map_release(struct kref *ref)
 
 static inline struct resv_map *inode_resv_map(struct inode *inode)
 {
-       return inode->i_mapping->private_data;
+       /*
+        * At inode evict time, i_mapping may not point to the original
+        * address space within the inode.  This original address space
+        * contains the pointer to the resv_map.  So, always use the
+        * address space embedded within the inode.
+        * The VERY common case is inode->mapping == &inode->i_data but,
+        * this may not be true for device special inodes.
+        */
+       return (struct resv_map *)(&inode->i_data)->private_data;
 }
 
 static struct resv_map *vma_resv_map(struct vm_area_struct *vma)
@@ -1059,6 +1067,7 @@ static void free_gigantic_page(struct page *page, unsigned int order)
        free_contig_range(page_to_pfn(page), 1 << order);
 }
 
+#ifdef CONFIG_CONTIG_ALLOC
 static int __alloc_gigantic_page(unsigned long start_pfn,
                                unsigned long nr_pages, gfp_t gfp_mask)
 {
@@ -1143,11 +1152,20 @@ static struct page *alloc_gigantic_page(struct hstate *h, gfp_t gfp_mask,
 
 static void prep_new_huge_page(struct hstate *h, struct page *page, int nid);
 static void prep_compound_gigantic_page(struct page *page, unsigned int order);
+#else /* !CONFIG_CONTIG_ALLOC */
+static struct page *alloc_gigantic_page(struct hstate *h, gfp_t gfp_mask,
+                                       int nid, nodemask_t *nodemask)
+{
+       return NULL;
+}
+#endif /* CONFIG_CONTIG_ALLOC */
 
 #else /* !CONFIG_ARCH_HAS_GIGANTIC_PAGE */
-static inline bool gigantic_page_supported(void) { return false; }
 static struct page *alloc_gigantic_page(struct hstate *h, gfp_t gfp_mask,
-               int nid, nodemask_t *nodemask) { return NULL; }
+                                       int nid, nodemask_t *nodemask)
+{
+       return NULL;
+}
 static inline void free_gigantic_page(struct page *page, unsigned int order) { }
 static inline void destroy_compound_gigantic_page(struct page *page,
                                                unsigned int order) { }
@@ -1157,7 +1175,7 @@ static void update_and_free_page(struct hstate *h, struct page *page)
 {
        int i;
 
-       if (hstate_is_gigantic(h) && !gigantic_page_supported())
+       if (hstate_is_gigantic(h) && !gigantic_page_runtime_supported())
                return;
 
        h->nr_huge_pages--;
@@ -1258,12 +1276,23 @@ void free_huge_page(struct page *page)
        ClearPagePrivate(page);
 
        /*
-        * A return code of zero implies that the subpool will be under its
-        * minimum size if the reservation is not restored after page is free.
-        * Therefore, force restore_reserve operation.
+        * If PagePrivate() was set on page, page allocation consumed a
+        * reservation.  If the page was associated with a subpool, there
+        * would have been a page reserved in the subpool before allocation
+        * via hugepage_subpool_get_pages().  Since we are 'restoring' the
+        * reservtion, do not call hugepage_subpool_put_pages() as this will
+        * remove the reserved page from the subpool.
         */
-       if (hugepage_subpool_put_pages(spool, 1) == 0)
-               restore_reserve = true;
+       if (!restore_reserve) {
+               /*
+                * A return code of zero implies that the subpool will be
+                * under its minimum size if the reservation is not restored
+                * after page is free.  Therefore, force restore_reserve
+                * operation.
+                */
+               if (hugepage_subpool_put_pages(spool, 1) == 0)
+                       restore_reserve = true;
+       }
 
        spin_lock(&hugetlb_lock);
        clear_page_huge_active(page);
@@ -1574,8 +1603,9 @@ static struct page *alloc_surplus_huge_page(struct hstate *h, gfp_t gfp_mask,
         */
        if (h->surplus_huge_pages >= h->nr_overcommit_huge_pages) {
                SetPageHugeTemporary(page);
+               spin_unlock(&hugetlb_lock);
                put_page(page);
-               page = NULL;
+               return NULL;
        } else {
                h->surplus_huge_pages++;
                h->surplus_huge_pages_node[page_to_nid(page)]++;
@@ -2277,13 +2307,47 @@ found:
 }
 
 #define persistent_huge_pages(h) (h->nr_huge_pages - h->surplus_huge_pages)
-static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
-                                               nodemask_t *nodes_allowed)
+static int set_max_huge_pages(struct hstate *h, unsigned long count, int nid,
+                             nodemask_t *nodes_allowed)
 {
        unsigned long min_count, ret;
 
-       if (hstate_is_gigantic(h) && !gigantic_page_supported())
-               return h->max_huge_pages;
+       spin_lock(&hugetlb_lock);
+
+       /*
+        * Check for a node specific request.
+        * Changing node specific huge page count may require a corresponding
+        * change to the global count.  In any case, the passed node mask
+        * (nodes_allowed) will restrict alloc/free to the specified node.
+        */
+       if (nid != NUMA_NO_NODE) {
+               unsigned long old_count = count;
+
+               count += h->nr_huge_pages - h->nr_huge_pages_node[nid];
+               /*
+                * User may have specified a large count value which caused the
+                * above calculation to overflow.  In this case, they wanted
+                * to allocate as many huge pages as possible.  Set count to
+                * largest possible value to align with their intention.
+                */
+               if (count < old_count)
+                       count = ULONG_MAX;
+       }
+
+       /*
+        * Gigantic pages runtime allocation depend on the capability for large
+        * page range allocation.
+        * If the system does not provide this feature, return an error when
+        * the user tries to allocate gigantic pages but let the user free the
+        * boottime allocated gigantic pages.
+        */
+       if (hstate_is_gigantic(h) && !IS_ENABLED(CONFIG_CONTIG_ALLOC)) {
+               if (count > persistent_huge_pages(h)) {
+                       spin_unlock(&hugetlb_lock);
+                       return -EINVAL;
+               }
+               /* Fall through to decrease pool */
+       }
 
        /*
         * Increase the pool size
@@ -2296,7 +2360,6 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
         * pool might be one hugepage larger than it needs to be, but
         * within all the constraints specified by the sysctls.
         */
-       spin_lock(&hugetlb_lock);
        while (h->surplus_huge_pages && count > persistent_huge_pages(h)) {
                if (!adjust_pool_surplus(h, nodes_allowed, -1))
                        break;
@@ -2351,9 +2414,10 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
                        break;
        }
 out:
-       ret = persistent_huge_pages(h);
+       h->max_huge_pages = persistent_huge_pages(h);
        spin_unlock(&hugetlb_lock);
-       return ret;
+
+       return 0;
 }
 
 #define HSTATE_ATTR_RO(_name) \
@@ -2403,41 +2467,32 @@ static ssize_t __nr_hugepages_store_common(bool obey_mempolicy,
                                           unsigned long count, size_t len)
 {
        int err;
-       NODEMASK_ALLOC(nodemask_t, nodes_allowed, GFP_KERNEL | __GFP_NORETRY);
+       nodemask_t nodes_allowed, *n_mask;
 
-       if (hstate_is_gigantic(h) && !gigantic_page_supported()) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (hstate_is_gigantic(h) && !gigantic_page_runtime_supported())
+               return -EINVAL;
 
        if (nid == NUMA_NO_NODE) {
                /*
                 * global hstate attribute
                 */
                if (!(obey_mempolicy &&
-                               init_nodemask_of_mempolicy(nodes_allowed))) {
-                       NODEMASK_FREE(nodes_allowed);
-                       nodes_allowed = &node_states[N_MEMORY];
-               }
-       } else if (nodes_allowed) {
+                               init_nodemask_of_mempolicy(&nodes_allowed)))
+                       n_mask = &node_states[N_MEMORY];
+               else
+                       n_mask = &nodes_allowed;
+       } else {
                /*
-                * per node hstate attribute: adjust count to global,
-                * but restrict alloc/free to the specified node.
+                * Node specific request.  count adjustment happens in
+                * set_max_huge_pages() after acquiring hugetlb_lock.
                 */
-               count += h->nr_huge_pages - h->nr_huge_pages_node[nid];
-               init_nodemask_of_node(nodes_allowed, nid);
-       } else
-               nodes_allowed = &node_states[N_MEMORY];
-
-       h->max_huge_pages = set_max_huge_pages(h, count, nodes_allowed);
+               init_nodemask_of_node(&nodes_allowed, nid);
+               n_mask = &nodes_allowed;
+       }
 
-       if (nodes_allowed != &node_states[N_MEMORY])
-               NODEMASK_FREE(nodes_allowed);
+       err = set_max_huge_pages(h, count, nid, n_mask);
 
-       return len;
-out:
-       NODEMASK_FREE(nodes_allowed);
-       return err;
+       return err ? err : len;
 }
 
 static ssize_t nr_hugepages_store_common(bool obey_mempolicy,
@@ -3247,7 +3302,8 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
        cow = (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
 
        if (cow) {
-               mmu_notifier_range_init(&range, src, vma->vm_start,
+               mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, src,
+                                       vma->vm_start,
                                        vma->vm_end);
                mmu_notifier_invalidate_range_start(&range);
        }
@@ -3359,7 +3415,8 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
        /*
         * If sharing possible, alert mmu notifiers of worst case.
         */
-       mmu_notifier_range_init(&range, mm, start, end);
+       mmu_notifier_range_init(&range, MMU_NOTIFY_UNMAP, 0, vma, mm, start,
+                               end);
        adjust_range_if_pmd_sharing_possible(vma, &range.start, &range.end);
        mmu_notifier_invalidate_range_start(&range);
        address = start;
@@ -3626,7 +3683,8 @@ retry_avoidcopy:
                            pages_per_huge_page(h));
        __SetPageUptodate(new_page);
 
-       mmu_notifier_range_init(&range, mm, haddr, haddr + huge_page_size(h));
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, mm, haddr,
+                               haddr + huge_page_size(h));
        mmu_notifier_invalidate_range_start(&range);
 
        /*
@@ -3777,8 +3835,7 @@ retry:
                         * handling userfault.  Reacquire after handling
                         * fault to make calling code simpler.
                         */
-                       hash = hugetlb_fault_mutex_hash(h, mm, vma, mapping,
-                                                       idx, haddr);
+                       hash = hugetlb_fault_mutex_hash(h, mapping, idx, haddr);
                        mutex_unlock(&hugetlb_fault_mutex_table[hash]);
                        ret = handle_userfault(&vmf, VM_UFFD_MISSING);
                        mutex_lock(&hugetlb_fault_mutex_table[hash]);
@@ -3886,21 +3943,14 @@ backout_unlocked:
 }
 
 #ifdef CONFIG_SMP
-u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
-                           struct vm_area_struct *vma,
-                           struct address_space *mapping,
+u32 hugetlb_fault_mutex_hash(struct hstate *h, struct address_space *mapping,
                            pgoff_t idx, unsigned long address)
 {
        unsigned long key[2];
        u32 hash;
 
-       if (vma->vm_flags & VM_SHARED) {
-               key[0] = (unsigned long) mapping;
-               key[1] = idx;
-       } else {
-               key[0] = (unsigned long) mm;
-               key[1] = address >> huge_page_shift(h);
-       }
+       key[0] = (unsigned long) mapping;
+       key[1] = idx;
 
        hash = jhash2((u32 *)&key, sizeof(key)/sizeof(u32), 0);
 
@@ -3911,9 +3961,7 @@ u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
  * For uniprocesor systems we always use a single mutex, so just
  * return 0 and avoid the hashing overhead.
  */
-u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
-                           struct vm_area_struct *vma,
-                           struct address_space *mapping,
+u32 hugetlb_fault_mutex_hash(struct hstate *h, struct address_space *mapping,
                            pgoff_t idx, unsigned long address)
 {
        return 0;
@@ -3958,7 +4006,7 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
         * get spurious allocation failures if two CPUs race to instantiate
         * the same page in the page cache.
         */
-       hash = hugetlb_fault_mutex_hash(h, mm, vma, mapping, idx, haddr);
+       hash = hugetlb_fault_mutex_hash(h, mapping, idx, haddr);
        mutex_lock(&hugetlb_fault_mutex_table[hash]);
 
        entry = huge_ptep_get(ptep);
@@ -4371,7 +4419,8 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
         * start/end.  Set range.start/range.end to cover the maximum possible
         * range if PMD sharing is possible.
         */
-       mmu_notifier_range_init(&range, mm, start, end);
+       mmu_notifier_range_init(&range, MMU_NOTIFY_PROTECTION_VMA,
+                               0, vma, mm, start, end);
        adjust_range_if_pmd_sharing_possible(vma, &range.start, &range.end);
 
        BUG_ON(address >= end);
@@ -4477,6 +4526,11 @@ int hugetlb_reserve_pages(struct inode *inode,
         * called to make the mapping read-write. Assume !vma is a shm mapping
         */
        if (!vma || vma->vm_flags & VM_MAYSHARE) {
+               /*
+                * resv_map can not be NULL as hugetlb_reserve_pages is only
+                * called for inodes for which resv_maps were created (see
+                * hugetlbfs_get_inode).
+                */
                resv_map = inode_resv_map(inode);
 
                chg = region_chg(resv_map, from, to);
@@ -4568,6 +4622,10 @@ long hugetlb_unreserve_pages(struct inode *inode, long start, long end,
        struct hugepage_subpool *spool = subpool_inode(inode);
        long gbl_reserve;
 
+       /*
+        * Since this routine can be called in the evict inode path for all
+        * hugetlbfs inodes, resv_map could be NULL.
+        */
        if (resv_map) {
                chg = region_del(resv_map, start, end);
                /*
index 449044378782ffbfb94399a5833cd733d9f0b689..a335f7c1fac428b30d7e352ebaf717e033724f74 100644 (file)
@@ -1016,7 +1016,8 @@ static void collapse_huge_page(struct mm_struct *mm,
        pte = pte_offset_map(pmd, address);
        pte_ptl = pte_lockptr(mm, pmd);
 
-       mmu_notifier_range_init(&range, mm, address, address + HPAGE_PMD_SIZE);
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, NULL, mm,
+                               address, address + HPAGE_PMD_SIZE);
        mmu_notifier_invalidate_range_start(&range);
        pmd_ptl = pmd_lock(mm, pmd); /* probably unnecessary */
        /*
@@ -1374,7 +1375,7 @@ static void collapse_shmem(struct mm_struct *mm,
                                result = SCAN_FAIL;
                                goto xa_locked;
                        }
-                       xas_store(&xas, new_page + (index % HPAGE_PMD_NR));
+                       xas_store(&xas, new_page);
                        nr_none++;
                        continue;
                }
@@ -1450,7 +1451,7 @@ static void collapse_shmem(struct mm_struct *mm,
                list_add_tail(&page->lru, &pagelist);
 
                /* Finally, replace with the new page. */
-               xas_store(&xas, new_page + (index % HPAGE_PMD_NR));
+               xas_store(&xas, new_page);
                continue;
 out_unlock:
                unlock_page(page);
index fc64874dc6f453c03b2bcbae4960cdd02a824214..81c20ed57bf68077041f195e2e2d8283ce8c1eb7 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1066,7 +1066,8 @@ static int write_protect_page(struct vm_area_struct *vma, struct page *page,
 
        BUG_ON(PageTransCompound(page));
 
-       mmu_notifier_range_init(&range, mm, pvmw.address,
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, mm,
+                               pvmw.address,
                                pvmw.address + PAGE_SIZE);
        mmu_notifier_invalidate_range_start(&range);
 
@@ -1154,7 +1155,8 @@ static int replace_page(struct vm_area_struct *vma, struct page *page,
        if (!pmd)
                goto out;
 
-       mmu_notifier_range_init(&range, mm, addr, addr + PAGE_SIZE);
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, mm, addr,
+                               addr + PAGE_SIZE);
        mmu_notifier_invalidate_range_start(&range);
 
        ptep = pte_offset_map_lock(mm, pmd, addr, &ptl);
index bb3a4554d5d56f810f92064b268e8f0e097a9d6b..628022e674a7f52bc8c600106113ac0d8080dbb4 100644 (file)
@@ -472,7 +472,8 @@ static int madvise_free_single_vma(struct vm_area_struct *vma,
        range.end = min(vma->vm_end, end_addr);
        if (range.end <= vma->vm_start)
                return -EINVAL;
-       mmu_notifier_range_init(&range, mm, range.start, range.end);
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, mm,
+                               range.start, range.end);
 
        lru_add_drain();
        tlb_gather_mmu(&tlb, mm, range.start, range.end);
index a48f520c2d01f86637ee6649f0a24adff593dd3d..6bbad46f4d2cb33b6bb0cd9514277da46d918738 100644 (file)
@@ -94,7 +94,7 @@
  * :c:func:`mem_init` function frees all the memory to the buddy page
  * allocator.
  *
- * If an architecure enables %CONFIG_ARCH_DISCARD_MEMBLOCK, the
+ * Unless an architecure enables %CONFIG_ARCH_KEEP_MEMBLOCK, the
  * memblock data structures will be discarded after the system
  * initialization compltes.
  */
@@ -375,7 +375,7 @@ static void __init_memblock memblock_remove_region(struct memblock_type *type, u
        }
 }
 
-#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
+#ifndef CONFIG_ARCH_KEEP_MEMBLOCK
 /**
  * memblock_discard - discard memory and reserved arrays if they were allocated
  */
@@ -1255,6 +1255,70 @@ int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size,
        return 0;
 }
 #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
+#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
+/**
+ * __next_mem_pfn_range_in_zone - iterator for for_each_*_range_in_zone()
+ *
+ * @idx: pointer to u64 loop variable
+ * @zone: zone in which all of the memory blocks reside
+ * @out_spfn: ptr to ulong for start pfn of the range, can be %NULL
+ * @out_epfn: ptr to ulong for end pfn of the range, can be %NULL
+ *
+ * This function is meant to be a zone/pfn specific wrapper for the
+ * for_each_mem_range type iterators. Specifically they are used in the
+ * deferred memory init routines and as such we were duplicating much of
+ * this logic throughout the code. So instead of having it in multiple
+ * locations it seemed like it would make more sense to centralize this to
+ * one new iterator that does everything they need.
+ */
+void __init_memblock
+__next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone,
+                            unsigned long *out_spfn, unsigned long *out_epfn)
+{
+       int zone_nid = zone_to_nid(zone);
+       phys_addr_t spa, epa;
+       int nid;
+
+       __next_mem_range(idx, zone_nid, MEMBLOCK_NONE,
+                        &memblock.memory, &memblock.reserved,
+                        &spa, &epa, &nid);
+
+       while (*idx != U64_MAX) {
+               unsigned long epfn = PFN_DOWN(epa);
+               unsigned long spfn = PFN_UP(spa);
+
+               /*
+                * Verify the end is at least past the start of the zone and
+                * that we have at least one PFN to initialize.
+                */
+               if (zone->zone_start_pfn < epfn && spfn < epfn) {
+                       /* if we went too far just stop searching */
+                       if (zone_end_pfn(zone) <= spfn) {
+                               *idx = U64_MAX;
+                               break;
+                       }
+
+                       if (out_spfn)
+                               *out_spfn = max(zone->zone_start_pfn, spfn);
+                       if (out_epfn)
+                               *out_epfn = min(zone_end_pfn(zone), epfn);
+
+                       return;
+               }
+
+               __next_mem_range(idx, zone_nid, MEMBLOCK_NONE,
+                                &memblock.memory, &memblock.reserved,
+                                &spa, &epa, &nid);
+       }
+
+       /* signal end of iteration */
+       if (out_spfn)
+               *out_spfn = ULONG_MAX;
+       if (out_epfn)
+               *out_epfn = 0;
+}
+
+#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
 
 /**
  * memblock_alloc_range_nid - allocate boot memory block
@@ -1923,7 +1987,7 @@ unsigned long __init memblock_free_all(void)
        return pages;
 }
 
-#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_ARCH_DISCARD_MEMBLOCK)
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_ARCH_KEEP_MEMBLOCK)
 
 static int memblock_debug_show(struct seq_file *m, void *private)
 {
index 81a0d3914ec999efcb36fb590e75c29d059d2b24..e50a2db5b4ff0dcf4bf17b888ea12cfd1284dd56 100644 (file)
@@ -687,10 +687,119 @@ mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_node *mctz)
        return mz;
 }
 
-static unsigned long memcg_sum_events(struct mem_cgroup *memcg,
-                                     int event)
+/**
+ * __mod_memcg_state - update cgroup memory statistics
+ * @memcg: the memory cgroup
+ * @idx: the stat item - can be enum memcg_stat_item or enum node_stat_item
+ * @val: delta to add to the counter, can be negative
+ */
+void __mod_memcg_state(struct mem_cgroup *memcg, int idx, int val)
 {
-       return atomic_long_read(&memcg->events[event]);
+       long x;
+
+       if (mem_cgroup_disabled())
+               return;
+
+       x = val + __this_cpu_read(memcg->vmstats_percpu->stat[idx]);
+       if (unlikely(abs(x) > MEMCG_CHARGE_BATCH)) {
+               struct mem_cgroup *mi;
+
+               atomic_long_add(x, &memcg->vmstats_local[idx]);
+               for (mi = memcg; mi; mi = parent_mem_cgroup(mi))
+                       atomic_long_add(x, &mi->vmstats[idx]);
+               x = 0;
+       }
+       __this_cpu_write(memcg->vmstats_percpu->stat[idx], x);
+}
+
+static struct mem_cgroup_per_node *
+parent_nodeinfo(struct mem_cgroup_per_node *pn, int nid)
+{
+       struct mem_cgroup *parent;
+
+       parent = parent_mem_cgroup(pn->memcg);
+       if (!parent)
+               return NULL;
+       return mem_cgroup_nodeinfo(parent, nid);
+}
+
+/**
+ * __mod_lruvec_state - update lruvec memory statistics
+ * @lruvec: the lruvec
+ * @idx: the stat item
+ * @val: delta to add to the counter, can be negative
+ *
+ * The lruvec is the intersection of the NUMA node and a cgroup. This
+ * function updates the all three counters that are affected by a
+ * change of state at this level: per-node, per-cgroup, per-lruvec.
+ */
+void __mod_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
+                       int val)
+{
+       pg_data_t *pgdat = lruvec_pgdat(lruvec);
+       struct mem_cgroup_per_node *pn;
+       struct mem_cgroup *memcg;
+       long x;
+
+       /* Update node */
+       __mod_node_page_state(pgdat, idx, val);
+
+       if (mem_cgroup_disabled())
+               return;
+
+       pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
+       memcg = pn->memcg;
+
+       /* Update memcg */
+       __mod_memcg_state(memcg, idx, val);
+
+       /* Update lruvec */
+       x = val + __this_cpu_read(pn->lruvec_stat_cpu->count[idx]);
+       if (unlikely(abs(x) > MEMCG_CHARGE_BATCH)) {
+               struct mem_cgroup_per_node *pi;
+
+               atomic_long_add(x, &pn->lruvec_stat_local[idx]);
+               for (pi = pn; pi; pi = parent_nodeinfo(pi, pgdat->node_id))
+                       atomic_long_add(x, &pi->lruvec_stat[idx]);
+               x = 0;
+       }
+       __this_cpu_write(pn->lruvec_stat_cpu->count[idx], x);
+}
+
+/**
+ * __count_memcg_events - account VM events in a cgroup
+ * @memcg: the memory cgroup
+ * @idx: the event item
+ * @count: the number of events that occured
+ */
+void __count_memcg_events(struct mem_cgroup *memcg, enum vm_event_item idx,
+                         unsigned long count)
+{
+       unsigned long x;
+
+       if (mem_cgroup_disabled())
+               return;
+
+       x = count + __this_cpu_read(memcg->vmstats_percpu->events[idx]);
+       if (unlikely(x > MEMCG_CHARGE_BATCH)) {
+               struct mem_cgroup *mi;
+
+               atomic_long_add(x, &memcg->vmevents_local[idx]);
+               for (mi = memcg; mi; mi = parent_mem_cgroup(mi))
+                       atomic_long_add(x, &mi->vmevents[idx]);
+               x = 0;
+       }
+       __this_cpu_write(memcg->vmstats_percpu->events[idx], x);
+}
+
+static unsigned long memcg_events(struct mem_cgroup *memcg, int event)
+{
+       return atomic_long_read(&memcg->vmevents[event]);
+}
+
+static unsigned long memcg_events_local(struct mem_cgroup *memcg, int event)
+{
+       return atomic_long_read(&memcg->vmevents_local[event]);
 }
 
 static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg,
@@ -722,35 +831,7 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg,
                nr_pages = -nr_pages; /* for event */
        }
 
-       __this_cpu_add(memcg->stat_cpu->nr_page_events, nr_pages);
-}
-
-unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
-                                          int nid, unsigned int lru_mask)
-{
-       struct lruvec *lruvec = mem_cgroup_lruvec(NODE_DATA(nid), memcg);
-       unsigned long nr = 0;
-       enum lru_list lru;
-
-       VM_BUG_ON((unsigned)nid >= nr_node_ids);
-
-       for_each_lru(lru) {
-               if (!(BIT(lru) & lru_mask))
-                       continue;
-               nr += mem_cgroup_get_lru_size(lruvec, lru);
-       }
-       return nr;
-}
-
-static unsigned long mem_cgroup_nr_lru_pages(struct mem_cgroup *memcg,
-                       unsigned int lru_mask)
-{
-       unsigned long nr = 0;
-       int nid;
-
-       for_each_node_state(nid, N_MEMORY)
-               nr += mem_cgroup_node_nr_lru_pages(memcg, nid, lru_mask);
-       return nr;
+       __this_cpu_add(memcg->vmstats_percpu->nr_page_events, nr_pages);
 }
 
 static bool mem_cgroup_event_ratelimit(struct mem_cgroup *memcg,
@@ -758,8 +839,8 @@ static bool mem_cgroup_event_ratelimit(struct mem_cgroup *memcg,
 {
        unsigned long val, next;
 
-       val = __this_cpu_read(memcg->stat_cpu->nr_page_events);
-       next = __this_cpu_read(memcg->stat_cpu->targets[target]);
+       val = __this_cpu_read(memcg->vmstats_percpu->nr_page_events);
+       next = __this_cpu_read(memcg->vmstats_percpu->targets[target]);
        /* from time_after() in jiffies.h */
        if ((long)(next - val) < 0) {
                switch (target) {
@@ -775,7 +856,7 @@ static bool mem_cgroup_event_ratelimit(struct mem_cgroup *memcg,
                default:
                        break;
                }
-               __this_cpu_write(memcg->stat_cpu->targets[target], next);
+               __this_cpu_write(memcg->vmstats_percpu->targets[target], next);
                return true;
        }
        return false;
@@ -1353,12 +1434,14 @@ void mem_cgroup_print_oom_meminfo(struct mem_cgroup *memcg)
                        if (memcg1_stats[i] == MEMCG_SWAP && !do_swap_account)
                                continue;
                        pr_cont(" %s:%luKB", memcg1_stat_names[i],
-                               K(memcg_page_state(iter, memcg1_stats[i])));
+                               K(memcg_page_state_local(iter,
+                                                        memcg1_stats[i])));
                }
 
                for (i = 0; i < NR_LRU_LISTS; i++)
                        pr_cont(" %s:%luKB", mem_cgroup_lru_names[i],
-                               K(mem_cgroup_nr_lru_pages(iter, BIT(i))));
+                               K(memcg_page_state_local(iter,
+                                                        NR_LRU_BASE + i)));
 
                pr_cont("\n");
        }
@@ -1422,11 +1505,15 @@ static bool mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
 static bool test_mem_cgroup_node_reclaimable(struct mem_cgroup *memcg,
                int nid, bool noswap)
 {
-       if (mem_cgroup_node_nr_lru_pages(memcg, nid, LRU_ALL_FILE))
+       struct lruvec *lruvec = mem_cgroup_lruvec(NODE_DATA(nid), memcg);
+
+       if (lruvec_page_state(lruvec, NR_INACTIVE_FILE) ||
+           lruvec_page_state(lruvec, NR_ACTIVE_FILE))
                return true;
        if (noswap || !total_swap_pages)
                return false;
-       if (mem_cgroup_node_nr_lru_pages(memcg, nid, LRU_ALL_ANON))
+       if (lruvec_page_state(lruvec, NR_INACTIVE_ANON) ||
+           lruvec_page_state(lruvec, NR_ACTIVE_ANON))
                return true;
        return false;
 
@@ -2100,7 +2187,7 @@ static void drain_all_stock(struct mem_cgroup *root_memcg)
 static int memcg_hotplug_cpu_dead(unsigned int cpu)
 {
        struct memcg_stock_pcp *stock;
-       struct mem_cgroup *memcg;
+       struct mem_cgroup *memcg, *mi;
 
        stock = &per_cpu(memcg_stock, cpu);
        drain_stock(stock);
@@ -2112,9 +2199,12 @@ static int memcg_hotplug_cpu_dead(unsigned int cpu)
                        int nid;
                        long x;
 
-                       x = this_cpu_xchg(memcg->stat_cpu->count[i], 0);
-                       if (x)
-                               atomic_long_add(x, &memcg->stat[i]);
+                       x = this_cpu_xchg(memcg->vmstats_percpu->stat[i], 0);
+                       if (x) {
+                               atomic_long_add(x, &memcg->vmstats_local[i]);
+                               for (mi = memcg; mi; mi = parent_mem_cgroup(mi))
+                                       atomic_long_add(x, &memcg->vmstats[i]);
+                       }
 
                        if (i >= NR_VM_NODE_STAT_ITEMS)
                                continue;
@@ -2124,17 +2214,24 @@ static int memcg_hotplug_cpu_dead(unsigned int cpu)
 
                                pn = mem_cgroup_nodeinfo(memcg, nid);
                                x = this_cpu_xchg(pn->lruvec_stat_cpu->count[i], 0);
-                               if (x)
-                                       atomic_long_add(x, &pn->lruvec_stat[i]);
+                               if (x) {
+                                       atomic_long_add(x, &pn->lruvec_stat_local[i]);
+                                       do {
+                                               atomic_long_add(x, &pn->lruvec_stat[i]);
+                                       } while ((pn = parent_nodeinfo(pn, nid)));
+                               }
                        }
                }
 
                for (i = 0; i < NR_VM_EVENT_ITEMS; i++) {
                        long x;
 
-                       x = this_cpu_xchg(memcg->stat_cpu->events[i], 0);
-                       if (x)
-                               atomic_long_add(x, &memcg->events[i]);
+                       x = this_cpu_xchg(memcg->vmstats_percpu->events[i], 0);
+                       if (x) {
+                               atomic_long_add(x, &memcg->vmevents_local[i]);
+                               for (mi = memcg; mi; mi = parent_mem_cgroup(mi))
+                                       atomic_long_add(x, &memcg->vmevents[i]);
+                       }
                }
        }
 
@@ -2964,50 +3061,15 @@ static int mem_cgroup_hierarchy_write(struct cgroup_subsys_state *css,
        return retval;
 }
 
-struct accumulated_stats {
-       unsigned long stat[MEMCG_NR_STAT];
-       unsigned long events[NR_VM_EVENT_ITEMS];
-       unsigned long lru_pages[NR_LRU_LISTS];
-       const unsigned int *stats_array;
-       const unsigned int *events_array;
-       int stats_size;
-       int events_size;
-};
-
-static void accumulate_memcg_tree(struct mem_cgroup *memcg,
-                                 struct accumulated_stats *acc)
-{
-       struct mem_cgroup *mi;
-       int i;
-
-       for_each_mem_cgroup_tree(mi, memcg) {
-               for (i = 0; i < acc->stats_size; i++)
-                       acc->stat[i] += memcg_page_state(mi,
-                               acc->stats_array ? acc->stats_array[i] : i);
-
-               for (i = 0; i < acc->events_size; i++)
-                       acc->events[i] += memcg_sum_events(mi,
-                               acc->events_array ? acc->events_array[i] : i);
-
-               for (i = 0; i < NR_LRU_LISTS; i++)
-                       acc->lru_pages[i] +=
-                               mem_cgroup_nr_lru_pages(mi, BIT(i));
-       }
-}
-
 static unsigned long mem_cgroup_usage(struct mem_cgroup *memcg, bool swap)
 {
-       unsigned long val = 0;
+       unsigned long val;
 
        if (mem_cgroup_is_root(memcg)) {
-               struct mem_cgroup *iter;
-
-               for_each_mem_cgroup_tree(iter, memcg) {
-                       val += memcg_page_state(iter, MEMCG_CACHE);
-                       val += memcg_page_state(iter, MEMCG_RSS);
-                       if (swap)
-                               val += memcg_page_state(iter, MEMCG_SWAP);
-               }
+               val = memcg_page_state(memcg, MEMCG_CACHE) +
+                       memcg_page_state(memcg, MEMCG_RSS);
+               if (swap)
+                       val += memcg_page_state(memcg, MEMCG_SWAP);
        } else {
                if (!swap)
                        val = page_counter_read(&memcg->memory);
@@ -3331,6 +3393,42 @@ static int mem_cgroup_move_charge_write(struct cgroup_subsys_state *css,
 #endif
 
 #ifdef CONFIG_NUMA
+
+#define LRU_ALL_FILE (BIT(LRU_INACTIVE_FILE) | BIT(LRU_ACTIVE_FILE))
+#define LRU_ALL_ANON (BIT(LRU_INACTIVE_ANON) | BIT(LRU_ACTIVE_ANON))
+#define LRU_ALL             ((1 << NR_LRU_LISTS) - 1)
+
+static unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
+                                          int nid, unsigned int lru_mask)
+{
+       struct lruvec *lruvec = mem_cgroup_lruvec(NODE_DATA(nid), memcg);
+       unsigned long nr = 0;
+       enum lru_list lru;
+
+       VM_BUG_ON((unsigned)nid >= nr_node_ids);
+
+       for_each_lru(lru) {
+               if (!(BIT(lru) & lru_mask))
+                       continue;
+               nr += lruvec_page_state_local(lruvec, NR_LRU_BASE + lru);
+       }
+       return nr;
+}
+
+static unsigned long mem_cgroup_nr_lru_pages(struct mem_cgroup *memcg,
+                                            unsigned int lru_mask)
+{
+       unsigned long nr = 0;
+       enum lru_list lru;
+
+       for_each_lru(lru) {
+               if (!(BIT(lru) & lru_mask))
+                       continue;
+               nr += memcg_page_state_local(memcg, NR_LRU_BASE + lru);
+       }
+       return nr;
+}
+
 static int memcg_numa_stat_show(struct seq_file *m, void *v)
 {
        struct numa_stat {
@@ -3402,7 +3500,6 @@ static int memcg_stat_show(struct seq_file *m, void *v)
        unsigned long memory, memsw;
        struct mem_cgroup *mi;
        unsigned int i;
-       struct accumulated_stats acc;
 
        BUILD_BUG_ON(ARRAY_SIZE(memcg1_stat_names) != ARRAY_SIZE(memcg1_stats));
        BUILD_BUG_ON(ARRAY_SIZE(mem_cgroup_lru_names) != NR_LRU_LISTS);
@@ -3411,17 +3508,18 @@ static int memcg_stat_show(struct seq_file *m, void *v)
                if (memcg1_stats[i] == MEMCG_SWAP && !do_memsw_account())
                        continue;
                seq_printf(m, "%s %lu\n", memcg1_stat_names[i],
-                          memcg_page_state(memcg, memcg1_stats[i]) *
+                          memcg_page_state_local(memcg, memcg1_stats[i]) *
                           PAGE_SIZE);
        }
 
        for (i = 0; i < ARRAY_SIZE(memcg1_events); i++)
                seq_printf(m, "%s %lu\n", memcg1_event_names[i],
-                          memcg_sum_events(memcg, memcg1_events[i]));
+                          memcg_events_local(memcg, memcg1_events[i]));
 
        for (i = 0; i < NR_LRU_LISTS; i++)
                seq_printf(m, "%s %lu\n", mem_cgroup_lru_names[i],
-                          mem_cgroup_nr_lru_pages(memcg, BIT(i)) * PAGE_SIZE);
+                          memcg_page_state_local(memcg, NR_LRU_BASE + i) *
+                          PAGE_SIZE);
 
        /* Hierarchical information */
        memory = memsw = PAGE_COUNTER_MAX;
@@ -3435,27 +3533,21 @@ static int memcg_stat_show(struct seq_file *m, void *v)
                seq_printf(m, "hierarchical_memsw_limit %llu\n",
                           (u64)memsw * PAGE_SIZE);
 
-       memset(&acc, 0, sizeof(acc));
-       acc.stats_size = ARRAY_SIZE(memcg1_stats);
-       acc.stats_array = memcg1_stats;
-       acc.events_size = ARRAY_SIZE(memcg1_events);
-       acc.events_array = memcg1_events;
-       accumulate_memcg_tree(memcg, &acc);
-
        for (i = 0; i < ARRAY_SIZE(memcg1_stats); i++) {
                if (memcg1_stats[i] == MEMCG_SWAP && !do_memsw_account())
                        continue;
                seq_printf(m, "total_%s %llu\n", memcg1_stat_names[i],
-                          (u64)acc.stat[i] * PAGE_SIZE);
+                          (u64)memcg_page_state(memcg, i) * PAGE_SIZE);
        }
 
        for (i = 0; i < ARRAY_SIZE(memcg1_events); i++)
                seq_printf(m, "total_%s %llu\n", memcg1_event_names[i],
-                          (u64)acc.events[i]);
+                          (u64)memcg_events(memcg, i));
 
        for (i = 0; i < NR_LRU_LISTS; i++)
                seq_printf(m, "total_%s %llu\n", mem_cgroup_lru_names[i],
-                          (u64)acc.lru_pages[i] * PAGE_SIZE);
+                          (u64)memcg_page_state(memcg, NR_LRU_BASE + i) *
+                          PAGE_SIZE);
 
 #ifdef CONFIG_DEBUG_VM
        {
@@ -3888,11 +3980,11 @@ struct wb_domain *mem_cgroup_wb_domain(struct bdi_writeback *wb)
  */
 static unsigned long memcg_exact_page_state(struct mem_cgroup *memcg, int idx)
 {
-       long x = atomic_long_read(&memcg->stat[idx]);
+       long x = atomic_long_read(&memcg->vmstats[idx]);
        int cpu;
 
        for_each_online_cpu(cpu)
-               x += per_cpu_ptr(memcg->stat_cpu, cpu)->count[idx];
+               x += per_cpu_ptr(memcg->vmstats_percpu, cpu)->stat[idx];
        if (x < 0)
                x = 0;
        return x;
@@ -3927,8 +4019,8 @@ void mem_cgroup_wb_stats(struct bdi_writeback *wb, unsigned long *pfilepages,
 
        /* this should eventually include NR_UNSTABLE_NFS */
        *pwriteback = memcg_exact_page_state(memcg, NR_WRITEBACK);
-       *pfilepages = mem_cgroup_nr_lru_pages(memcg, (1 << LRU_INACTIVE_FILE) |
-                                                    (1 << LRU_ACTIVE_FILE));
+       *pfilepages = memcg_exact_page_state(memcg, NR_INACTIVE_FILE) +
+                       memcg_exact_page_state(memcg, NR_ACTIVE_FILE);
        *pheadroom = PAGE_COUNTER_MAX;
 
        while ((parent = parent_mem_cgroup(memcg))) {
@@ -4432,7 +4524,7 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg)
 
        for_each_node(node)
                free_mem_cgroup_per_node_info(memcg, node);
-       free_percpu(memcg->stat_cpu);
+       free_percpu(memcg->vmstats_percpu);
        kfree(memcg);
 }
 
@@ -4461,8 +4553,8 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
        if (memcg->id.id < 0)
                goto fail;
 
-       memcg->stat_cpu = alloc_percpu(struct mem_cgroup_stat_cpu);
-       if (!memcg->stat_cpu)
+       memcg->vmstats_percpu = alloc_percpu(struct memcg_vmstats_percpu);
+       if (!memcg->vmstats_percpu)
                goto fail;
 
        for_each_node(node)
@@ -5548,7 +5640,6 @@ static int memory_events_show(struct seq_file *m, void *v)
 static int memory_stat_show(struct seq_file *m, void *v)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
-       struct accumulated_stats acc;
        int i;
 
        /*
@@ -5562,31 +5653,27 @@ static int memory_stat_show(struct seq_file *m, void *v)
         * Current memory state:
         */
 
-       memset(&acc, 0, sizeof(acc));
-       acc.stats_size = MEMCG_NR_STAT;
-       acc.events_size = NR_VM_EVENT_ITEMS;
-       accumulate_memcg_tree(memcg, &acc);
-
        seq_printf(m, "anon %llu\n",
-                  (u64)acc.stat[MEMCG_RSS] * PAGE_SIZE);
+                  (u64)memcg_page_state(memcg, MEMCG_RSS) * PAGE_SIZE);
        seq_printf(m, "file %llu\n",
-                  (u64)acc.stat[MEMCG_CACHE] * PAGE_SIZE);
+                  (u64)memcg_page_state(memcg, MEMCG_CACHE) * PAGE_SIZE);
        seq_printf(m, "kernel_stack %llu\n",
-                  (u64)acc.stat[MEMCG_KERNEL_STACK_KB] * 1024);
+                  (u64)memcg_page_state(memcg, MEMCG_KERNEL_STACK_KB) * 1024);
        seq_printf(m, "slab %llu\n",
-                  (u64)(acc.stat[NR_SLAB_RECLAIMABLE] +
-                        acc.stat[NR_SLAB_UNRECLAIMABLE]) * PAGE_SIZE);
+                  (u64)(memcg_page_state(memcg, NR_SLAB_RECLAIMABLE) +
+                        memcg_page_state(memcg, NR_SLAB_UNRECLAIMABLE)) *
+                  PAGE_SIZE);
        seq_printf(m, "sock %llu\n",
-                  (u64)acc.stat[MEMCG_SOCK] * PAGE_SIZE);
+                  (u64)memcg_page_state(memcg, MEMCG_SOCK) * PAGE_SIZE);
 
        seq_printf(m, "shmem %llu\n",
-                  (u64)acc.stat[NR_SHMEM] * PAGE_SIZE);
+                  (u64)memcg_page_state(memcg, NR_SHMEM) * PAGE_SIZE);
        seq_printf(m, "file_mapped %llu\n",
-                  (u64)acc.stat[NR_FILE_MAPPED] * PAGE_SIZE);
+                  (u64)memcg_page_state(memcg, NR_FILE_MAPPED) * PAGE_SIZE);
        seq_printf(m, "file_dirty %llu\n",
-                  (u64)acc.stat[NR_FILE_DIRTY] * PAGE_SIZE);
+                  (u64)memcg_page_state(memcg, NR_FILE_DIRTY) * PAGE_SIZE);
        seq_printf(m, "file_writeback %llu\n",
-                  (u64)acc.stat[NR_WRITEBACK] * PAGE_SIZE);
+                  (u64)memcg_page_state(memcg, NR_WRITEBACK) * PAGE_SIZE);
 
        /*
         * TODO: We should eventually replace our own MEMCG_RSS_HUGE counter
@@ -5595,43 +5682,47 @@ static int memory_stat_show(struct seq_file *m, void *v)
         * where the page->mem_cgroup is set up and stable.
         */
        seq_printf(m, "anon_thp %llu\n",
-                  (u64)acc.stat[MEMCG_RSS_HUGE] * PAGE_SIZE);
+                  (u64)memcg_page_state(memcg, MEMCG_RSS_HUGE) * PAGE_SIZE);
 
        for (i = 0; i < NR_LRU_LISTS; i++)
                seq_printf(m, "%s %llu\n", mem_cgroup_lru_names[i],
-                          (u64)acc.lru_pages[i] * PAGE_SIZE);
+                          (u64)memcg_page_state(memcg, NR_LRU_BASE + i) *
+                          PAGE_SIZE);
 
        seq_printf(m, "slab_reclaimable %llu\n",
-                  (u64)acc.stat[NR_SLAB_RECLAIMABLE] * PAGE_SIZE);
+                  (u64)memcg_page_state(memcg, NR_SLAB_RECLAIMABLE) *
+                  PAGE_SIZE);
        seq_printf(m, "slab_unreclaimable %llu\n",
-                  (u64)acc.stat[NR_SLAB_UNRECLAIMABLE] * PAGE_SIZE);
+                  (u64)memcg_page_state(memcg, NR_SLAB_UNRECLAIMABLE) *
+                  PAGE_SIZE);
 
        /* Accumulated memory events */
 
-       seq_printf(m, "pgfault %lu\n", acc.events[PGFAULT]);
-       seq_printf(m, "pgmajfault %lu\n", acc.events[PGMAJFAULT]);
+       seq_printf(m, "pgfault %lu\n", memcg_events(memcg, PGFAULT));
+       seq_printf(m, "pgmajfault %lu\n", memcg_events(memcg, PGMAJFAULT));
 
        seq_printf(m, "workingset_refault %lu\n",
-                  acc.stat[WORKINGSET_REFAULT]);
+                  memcg_page_state(memcg, WORKINGSET_REFAULT));
        seq_printf(m, "workingset_activate %lu\n",
-                  acc.stat[WORKINGSET_ACTIVATE]);
+                  memcg_page_state(memcg, WORKINGSET_ACTIVATE));
        seq_printf(m, "workingset_nodereclaim %lu\n",
-                  acc.stat[WORKINGSET_NODERECLAIM]);
-
-       seq_printf(m, "pgrefill %lu\n", acc.events[PGREFILL]);
-       seq_printf(m, "pgscan %lu\n", acc.events[PGSCAN_KSWAPD] +
-                  acc.events[PGSCAN_DIRECT]);
-       seq_printf(m, "pgsteal %lu\n", acc.events[PGSTEAL_KSWAPD] +
-                  acc.events[PGSTEAL_DIRECT]);
-       seq_printf(m, "pgactivate %lu\n", acc.events[PGACTIVATE]);
-       seq_printf(m, "pgdeactivate %lu\n", acc.events[PGDEACTIVATE]);
-       seq_printf(m, "pglazyfree %lu\n", acc.events[PGLAZYFREE]);
-       seq_printf(m, "pglazyfreed %lu\n", acc.events[PGLAZYFREED]);
+                  memcg_page_state(memcg, WORKINGSET_NODERECLAIM));
+
+       seq_printf(m, "pgrefill %lu\n", memcg_events(memcg, PGREFILL));
+       seq_printf(m, "pgscan %lu\n", memcg_events(memcg, PGSCAN_KSWAPD) +
+                  memcg_events(memcg, PGSCAN_DIRECT));
+       seq_printf(m, "pgsteal %lu\n", memcg_events(memcg, PGSTEAL_KSWAPD) +
+                  memcg_events(memcg, PGSTEAL_DIRECT));
+       seq_printf(m, "pgactivate %lu\n", memcg_events(memcg, PGACTIVATE));
+       seq_printf(m, "pgdeactivate %lu\n", memcg_events(memcg, PGDEACTIVATE));
+       seq_printf(m, "pglazyfree %lu\n", memcg_events(memcg, PGLAZYFREE));
+       seq_printf(m, "pglazyfreed %lu\n", memcg_events(memcg, PGLAZYFREED));
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-       seq_printf(m, "thp_fault_alloc %lu\n", acc.events[THP_FAULT_ALLOC]);
+       seq_printf(m, "thp_fault_alloc %lu\n",
+                  memcg_events(memcg, THP_FAULT_ALLOC));
        seq_printf(m, "thp_collapse_alloc %lu\n",
-                  acc.events[THP_COLLAPSE_ALLOC]);
+                  memcg_events(memcg, THP_COLLAPSE_ALLOC));
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
        return 0;
@@ -6067,7 +6158,7 @@ static void uncharge_batch(const struct uncharge_gather *ug)
        __mod_memcg_state(ug->memcg, MEMCG_RSS_HUGE, -ug->nr_huge);
        __mod_memcg_state(ug->memcg, NR_SHMEM, -ug->nr_shmem);
        __count_memcg_events(ug->memcg, PGPGOUT, ug->pgpgout);
-       __this_cpu_add(ug->memcg->stat_cpu->nr_page_events, nr_pages);
+       __this_cpu_add(ug->memcg->vmstats_percpu->nr_page_events, nr_pages);
        memcg_check_events(ug->memcg, ug->dummy_page);
        local_irq_restore(flags);
 
index 650e65a46b9cc7d8cfdc4046a807f30c769ee849..2647c898990c80491b512944a890d47c90f23aca 100644 (file)
@@ -39,6 +39,7 @@ static void memfd_tag_pins(struct xa_state *xas)
        xas_for_each(xas, page, ULONG_MAX) {
                if (xa_is_value(page))
                        continue;
+               page = find_subpage(page, xas->xa_index);
                if (page_count(page) - page_mapcount(page) > 1)
                        xas_set_mark(xas, MEMFD_TAG_PINNED);
 
@@ -88,6 +89,7 @@ static int memfd_wait_for_pins(struct address_space *mapping)
                        bool clear = true;
                        if (xa_is_value(page))
                                continue;
+                       page = find_subpage(page, xas.xa_index);
                        if (page_count(page) - page_mapcount(page) != 1) {
                                /*
                                 * On the last scan, we clean up all those tags
index f7d962d7de1958cf44c80ed3ed43359d3cc11dc7..96f1d473c89ae587006d772480854ef51b3ca7fe 100644 (file)
@@ -1010,7 +1010,8 @@ int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
        is_cow = is_cow_mapping(vma->vm_flags);
 
        if (is_cow) {
-               mmu_notifier_range_init(&range, src_mm, addr, end);
+               mmu_notifier_range_init(&range, MMU_NOTIFY_PROTECTION_PAGE,
+                                       0, vma, src_mm, addr, end);
                mmu_notifier_invalidate_range_start(&range);
        }
 
@@ -1334,7 +1335,8 @@ void unmap_vmas(struct mmu_gather *tlb,
 {
        struct mmu_notifier_range range;
 
-       mmu_notifier_range_init(&range, vma->vm_mm, start_addr, end_addr);
+       mmu_notifier_range_init(&range, MMU_NOTIFY_UNMAP, 0, vma, vma->vm_mm,
+                               start_addr, end_addr);
        mmu_notifier_invalidate_range_start(&range);
        for ( ; vma && vma->vm_start < end_addr; vma = vma->vm_next)
                unmap_single_vma(tlb, vma, start_addr, end_addr, NULL);
@@ -1356,7 +1358,8 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long start,
        struct mmu_gather tlb;
 
        lru_add_drain();
-       mmu_notifier_range_init(&range, vma->vm_mm, start, start + size);
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, vma->vm_mm,
+                               start, start + size);
        tlb_gather_mmu(&tlb, vma->vm_mm, start, range.end);
        update_hiwater_rss(vma->vm_mm);
        mmu_notifier_invalidate_range_start(&range);
@@ -1382,7 +1385,8 @@ static void zap_page_range_single(struct vm_area_struct *vma, unsigned long addr
        struct mmu_gather tlb;
 
        lru_add_drain();
-       mmu_notifier_range_init(&range, vma->vm_mm, address, address + size);
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, vma->vm_mm,
+                               address, address + size);
        tlb_gather_mmu(&tlb, vma->vm_mm, address, range.end);
        update_hiwater_rss(vma->vm_mm);
        mmu_notifier_invalidate_range_start(&range);
@@ -1523,6 +1527,87 @@ int vm_insert_page(struct vm_area_struct *vma, unsigned long addr,
 }
 EXPORT_SYMBOL(vm_insert_page);
 
+/*
+ * __vm_map_pages - maps range of kernel pages into user vma
+ * @vma: user vma to map to
+ * @pages: pointer to array of source kernel pages
+ * @num: number of pages in page array
+ * @offset: user's requested vm_pgoff
+ *
+ * This allows drivers to map range of kernel pages into a user vma.
+ *
+ * Return: 0 on success and error code otherwise.
+ */
+static int __vm_map_pages(struct vm_area_struct *vma, struct page **pages,
+                               unsigned long num, unsigned long offset)
+{
+       unsigned long count = vma_pages(vma);
+       unsigned long uaddr = vma->vm_start;
+       int ret, i;
+
+       /* Fail if the user requested offset is beyond the end of the object */
+       if (offset > num)
+               return -ENXIO;
+
+       /* Fail if the user requested size exceeds available object size */
+       if (count > num - offset)
+               return -ENXIO;
+
+       for (i = 0; i < count; i++) {
+               ret = vm_insert_page(vma, uaddr, pages[offset + i]);
+               if (ret < 0)
+                       return ret;
+               uaddr += PAGE_SIZE;
+       }
+
+       return 0;
+}
+
+/**
+ * vm_map_pages - maps range of kernel pages starts with non zero offset
+ * @vma: user vma to map to
+ * @pages: pointer to array of source kernel pages
+ * @num: number of pages in page array
+ *
+ * Maps an object consisting of @num pages, catering for the user's
+ * requested vm_pgoff
+ *
+ * If we fail to insert any page into the vma, the function will return
+ * immediately leaving any previously inserted pages present.  Callers
+ * from the mmap handler may immediately return the error as their caller
+ * will destroy the vma, removing any successfully inserted pages. Other
+ * callers should make their own arrangements for calling unmap_region().
+ *
+ * Context: Process context. Called by mmap handlers.
+ * Return: 0 on success and error code otherwise.
+ */
+int vm_map_pages(struct vm_area_struct *vma, struct page **pages,
+                               unsigned long num)
+{
+       return __vm_map_pages(vma, pages, num, vma->vm_pgoff);
+}
+EXPORT_SYMBOL(vm_map_pages);
+
+/**
+ * vm_map_pages_zero - map range of kernel pages starts with zero offset
+ * @vma: user vma to map to
+ * @pages: pointer to array of source kernel pages
+ * @num: number of pages in page array
+ *
+ * Similar to vm_map_pages(), except that it explicitly sets the offset
+ * to 0. This function is intended for the drivers that did not consider
+ * vm_pgoff.
+ *
+ * Context: Process context. Called by mmap handlers.
+ * Return: 0 on success and error code otherwise.
+ */
+int vm_map_pages_zero(struct vm_area_struct *vma, struct page **pages,
+                               unsigned long num)
+{
+       return __vm_map_pages(vma, pages, num, 0);
+}
+EXPORT_SYMBOL(vm_map_pages_zero);
+
 static vm_fault_t insert_pfn(struct vm_area_struct *vma, unsigned long addr,
                        pfn_t pfn, pgprot_t prot, bool mkwrite)
 {
@@ -2279,7 +2364,8 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf)
 
        __SetPageUptodate(new_page);
 
-       mmu_notifier_range_init(&range, mm, vmf->address & PAGE_MASK,
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, mm,
+                               vmf->address & PAGE_MASK,
                                (vmf->address & PAGE_MASK) + PAGE_SIZE);
        mmu_notifier_invalidate_range_start(&range);
 
@@ -4104,8 +4190,9 @@ static int __follow_pte_pmd(struct mm_struct *mm, unsigned long address,
                        goto out;
 
                if (range) {
-                       mmu_notifier_range_init(range, mm, address & PMD_MASK,
-                                            (address & PMD_MASK) + PMD_SIZE);
+                       mmu_notifier_range_init(range, MMU_NOTIFY_CLEAR, 0,
+                                               NULL, mm, address & PMD_MASK,
+                                               (address & PMD_MASK) + PMD_SIZE);
                        mmu_notifier_invalidate_range_start(range);
                }
                *ptlp = pmd_lock(mm, pmd);
@@ -4122,8 +4209,9 @@ static int __follow_pte_pmd(struct mm_struct *mm, unsigned long address,
                goto out;
 
        if (range) {
-               mmu_notifier_range_init(range, mm, address & PAGE_MASK,
-                                    (address & PAGE_MASK) + PAGE_SIZE);
+               mmu_notifier_range_init(range, MMU_NOTIFY_CLEAR, 0, NULL, mm,
+                                       address & PAGE_MASK,
+                                       (address & PAGE_MASK) + PAGE_SIZE);
                mmu_notifier_invalidate_range_start(range);
        }
        ptep = pte_offset_map_lock(mm, pmd, address, ptlp);
index b236069ff0d823ce92a84222494d42bdfa97c20c..328878b6799d0c2a6c40cc0b8657341a91b1f059 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/tlbflush.h>
 
 #include "internal.h"
+#include "shuffle.h"
 
 /*
  * online_page_callback contains pointer to current page onlining function.
@@ -273,12 +274,12 @@ static int __meminit __add_section(int nid, unsigned long phys_start_pfn,
  * add the new pages.
  */
 int __ref __add_pages(int nid, unsigned long phys_start_pfn,
-               unsigned long nr_pages, struct vmem_altmap *altmap,
-               bool want_memblock)
+               unsigned long nr_pages, struct mhp_restrictions *restrictions)
 {
        unsigned long i;
        int err = 0;
        int start_sec, end_sec;
+       struct vmem_altmap *altmap = restrictions->altmap;
 
        /* during initialize mem_map, align hot-added range to section */
        start_sec = pfn_to_section_nr(phys_start_pfn);
@@ -299,7 +300,7 @@ int __ref __add_pages(int nid, unsigned long phys_start_pfn,
 
        for (i = start_sec; i <= end_sec; i++) {
                err = __add_section(nid, section_nr_to_pfn(i), altmap,
-                               want_memblock);
+                               restrictions->flags & MHP_MEMBLOCK_API);
 
                /*
                 * EEXIST is finally dealt with by ioresource collision
@@ -516,26 +517,23 @@ static void __remove_zone(struct zone *zone, unsigned long start_pfn)
        pgdat_resize_unlock(zone->zone_pgdat, &flags);
 }
 
-static int __remove_section(struct zone *zone, struct mem_section *ms,
-               unsigned long map_offset, struct vmem_altmap *altmap)
+static void __remove_section(struct zone *zone, struct mem_section *ms,
+                            unsigned long map_offset,
+                            struct vmem_altmap *altmap)
 {
        unsigned long start_pfn;
        int scn_nr;
-       int ret = -EINVAL;
 
-       if (!valid_section(ms))
-               return ret;
+       if (WARN_ON_ONCE(!valid_section(ms)))
+               return;
 
-       ret = unregister_memory_section(ms);
-       if (ret)
-               return ret;
+       unregister_memory_section(ms);
 
        scn_nr = __section_nr(ms);
        start_pfn = section_nr_to_pfn((unsigned long)scn_nr);
        __remove_zone(zone, start_pfn);
 
        sparse_remove_one_section(zone, ms, map_offset, altmap);
-       return 0;
 }
 
 /**
@@ -550,31 +548,17 @@ static int __remove_section(struct zone *zone, struct mem_section *ms,
  * sure that pages are marked reserved and zones are adjust properly by
  * calling offline_pages().
  */
-int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
-                unsigned long nr_pages, struct vmem_altmap *altmap)
+void __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
+                   unsigned long nr_pages, struct vmem_altmap *altmap)
 {
        unsigned long i;
        unsigned long map_offset = 0;
-       int sections_to_remove, ret = 0;
+       int sections_to_remove;
 
        /* In the ZONE_DEVICE case device driver owns the memory region */
        if (is_dev_zone(zone)) {
                if (altmap)
                        map_offset = vmem_altmap_offset(altmap);
-       } else {
-               resource_size_t start, size;
-
-               start = phys_start_pfn << PAGE_SHIFT;
-               size = nr_pages * PAGE_SIZE;
-
-               ret = release_mem_region_adjustable(&iomem_resource, start,
-                                       size);
-               if (ret) {
-                       resource_size_t endres = start + size - 1;
-
-                       pr_warn("Unable to release resource <%pa-%pa> (%d)\n",
-                                       &start, &endres, ret);
-               }
        }
 
        clear_zone_contiguous(zone);
@@ -590,16 +574,12 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
                unsigned long pfn = phys_start_pfn + i*PAGES_PER_SECTION;
 
                cond_resched();
-               ret = __remove_section(zone, __pfn_to_section(pfn), map_offset,
-                               altmap);
+               __remove_section(zone, __pfn_to_section(pfn), map_offset,
+                                altmap);
                map_offset = 0;
-               if (ret)
-                       break;
        }
 
        set_zone_contiguous(zone);
-
-       return ret;
 }
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
@@ -714,7 +694,7 @@ static void node_states_check_changes_online(unsigned long nr_pages,
        if (zone_idx(zone) <= ZONE_NORMAL && !node_state(nid, N_NORMAL_MEMORY))
                arg->status_change_nid_normal = nid;
 #ifdef CONFIG_HIGHMEM
-       if (zone_idx(zone) <= N_HIGH_MEMORY && !node_state(nid, N_HIGH_MEMORY))
+       if (zone_idx(zone) <= ZONE_HIGHMEM && !node_state(nid, N_HIGH_MEMORY))
                arg->status_change_nid_high = nid;
 #endif
 }
@@ -912,6 +892,8 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_typ
        zone->zone_pgdat->node_present_pages += onlined_pages;
        pgdat_resize_unlock(zone->zone_pgdat, &flags);
 
+       shuffle_zone(zone);
+
        if (onlined_pages) {
                node_states_set_node(nid, &arg);
                if (need_zonelists_rebuild)
@@ -1097,6 +1079,9 @@ static int online_memory_block(struct memory_block *mem, void *arg)
  */
 int __ref add_memory_resource(int nid, struct resource *res)
 {
+       struct mhp_restrictions restrictions = {
+               .flags = MHP_MEMBLOCK_API,
+       };
        u64 start, size;
        bool new_node = false;
        int ret;
@@ -1124,7 +1109,7 @@ int __ref add_memory_resource(int nid, struct resource *res)
        new_node = ret;
 
        /* call arch's memory hotadd */
-       ret = arch_add_memory(nid, start, size, NULL, true);
+       ret = arch_add_memory(nid, start, size, &restrictions);
        if (ret < 0)
                goto error;
 
@@ -1341,8 +1326,7 @@ static unsigned long scan_movable_pages(unsigned long start, unsigned long end)
                if (!PageHuge(page))
                        continue;
                head = compound_head(page);
-               if (hugepage_migration_supported(page_hstate(head)) &&
-                   page_huge_active(head))
+               if (page_huge_active(head))
                        return pfn;
                skip = (1 << compound_order(head)) - (page - head);
                pfn += skip - 1;
@@ -1382,10 +1366,6 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
 
                if (PageHuge(page)) {
                        struct page *head = compound_head(page);
-                       if (compound_order(head) > PFN_SECTION_SHIFT) {
-                               ret = -EBUSY;
-                               break;
-                       }
                        pfn = page_to_pfn(head) + (1<<compound_order(head)) - 1;
                        isolate_huge_page(head, &source);
                        continue;
@@ -1454,15 +1434,10 @@ static int
 offline_isolated_pages_cb(unsigned long start, unsigned long nr_pages,
                        void *data)
 {
-       __offline_isolated_pages(start, start + nr_pages);
-       return 0;
-}
+       unsigned long *offlined_pages = (unsigned long *)data;
 
-static void
-offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
-{
-       walk_system_ram_range(start_pfn, end_pfn - start_pfn, NULL,
-                               offline_isolated_pages_cb);
+       *offlined_pages += __offline_isolated_pages(start, start + nr_pages);
+       return 0;
 }
 
 /*
@@ -1472,26 +1447,7 @@ static int
 check_pages_isolated_cb(unsigned long start_pfn, unsigned long nr_pages,
                        void *data)
 {
-       int ret;
-       long offlined = *(long *)data;
-       ret = test_pages_isolated(start_pfn, start_pfn + nr_pages, true);
-       offlined = nr_pages;
-       if (!ret)
-               *(long *)data += offlined;
-       return ret;
-}
-
-static long
-check_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
-{
-       long offlined = 0;
-       int ret;
-
-       ret = walk_system_ram_range(start_pfn, end_pfn - start_pfn, &offlined,
-                       check_pages_isolated_cb);
-       if (ret < 0)
-               offlined = (long)ret;
-       return offlined;
+       return test_pages_isolated(start_pfn, start_pfn + nr_pages, true);
 }
 
 static int __init cmdline_parse_movable_node(char *p)
@@ -1576,7 +1532,7 @@ static int __ref __offline_pages(unsigned long start_pfn,
                  unsigned long end_pfn)
 {
        unsigned long pfn, nr_pages;
-       long offlined_pages;
+       unsigned long offlined_pages = 0;
        int ret, node, nr_isolate_pageblock;
        unsigned long flags;
        unsigned long valid_start, valid_end;
@@ -1652,14 +1608,15 @@ static int __ref __offline_pages(unsigned long start_pfn,
                        goto failed_removal_isolated;
                }
                /* check again */
-               offlined_pages = check_pages_isolated(start_pfn, end_pfn);
-       } while (offlined_pages < 0);
+               ret = walk_system_ram_range(start_pfn, end_pfn - start_pfn,
+                                           NULL, check_pages_isolated_cb);
+       } while (ret);
 
-       pr_info("Offlined Pages %ld\n", offlined_pages);
        /* Ok, all of our target is isolated.
           We cannot do rollback at this point. */
-       offline_isolated_pages(start_pfn, end_pfn);
-
+       walk_system_ram_range(start_pfn, end_pfn - start_pfn,
+                             &offlined_pages, offline_isolated_pages_cb);
+       pr_info("Offlined Pages %ld\n", offlined_pages);
        /*
         * Onlining will reset pagetype flags and makes migrate type
         * MOVABLE, so just need to decrease the number of isolated
@@ -1843,6 +1800,26 @@ void try_offline_node(int nid)
 }
 EXPORT_SYMBOL(try_offline_node);
 
+static void __release_memory_resource(resource_size_t start,
+                                     resource_size_t size)
+{
+       int ret;
+
+       /*
+        * When removing memory in the same granularity as it was added,
+        * this function never fails. It might only fail if resources
+        * have to be adjusted or split. We'll ignore the error, as
+        * removing of memory cannot fail.
+        */
+       ret = release_mem_region_adjustable(&iomem_resource, start, size);
+       if (ret) {
+               resource_size_t endres = start + size - 1;
+
+               pr_warn("Unable to release resource <%pa-%pa> (%d)\n",
+                       &start, &endres, ret);
+       }
+}
+
 /**
  * remove_memory
  * @nid: the node ID
@@ -1877,6 +1854,7 @@ void __ref __remove_memory(int nid, u64 start, u64 size)
        memblock_remove(start, size);
 
        arch_remove_memory(nid, start, size, NULL);
+       __release_memory_resource(start, size);
 
        try_offline_node(nid);
 
index 663a5449367a4204e937491d2d9032b0a3768bdf..f2ecc2855a12d72b43dc73e7914400ee334a06bf 100644 (file)
@@ -463,7 +463,7 @@ int migrate_page_move_mapping(struct address_space *mapping,
 
                for (i = 1; i < HPAGE_PMD_NR; i++) {
                        xas_next(&xas);
-                       xas_store(&xas, newpage + i);
+                       xas_store(&xas, newpage);
                }
        }
 
@@ -2356,7 +2356,8 @@ static void migrate_vma_collect(struct migrate_vma *migrate)
        mm_walk.mm = migrate->vma->vm_mm;
        mm_walk.private = migrate;
 
-       mmu_notifier_range_init(&range, mm_walk.mm, migrate->start,
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, NULL, mm_walk.mm,
+                               migrate->start,
                                migrate->end);
        mmu_notifier_invalidate_range_start(&range);
        walk_page_range(migrate->start, migrate->end, &mm_walk);
@@ -2764,6 +2765,8 @@ static void migrate_vma_pages(struct migrate_vma *migrate)
                                notified = true;
 
                                mmu_notifier_range_init(&range,
+                                                       MMU_NOTIFY_CLEAR, 0,
+                                                       NULL,
                                                        migrate->vma->vm_mm,
                                                        addr, migrate->end);
                                mmu_notifier_invalidate_range_start(&range);
index 218099b5ed31d1e971d8d64b0951a31b8e310c01..c3f058bd0faf3e90857a762dd0828b621139ea5b 100644 (file)
@@ -169,6 +169,22 @@ out:
        return 0;
 }
 
+static inline bool can_do_mincore(struct vm_area_struct *vma)
+{
+       if (vma_is_anonymous(vma))
+               return true;
+       if (!vma->vm_file)
+               return false;
+       /*
+        * Reveal pagecache information only for non-anonymous mappings that
+        * correspond to the files the calling process could (if tried) open
+        * for writing; otherwise we'd be including shared non-exclusive
+        * mappings, which opens a side channel.
+        */
+       return inode_owner_or_capable(file_inode(vma->vm_file)) ||
+               inode_permission(file_inode(vma->vm_file), MAY_WRITE) == 0;
+}
+
 /*
  * Do a chunk of "sys_mincore()". We've already checked
  * all the arguments, we hold the mmap semaphore: we should
@@ -189,8 +205,13 @@ static long do_mincore(unsigned long addr, unsigned long pages, unsigned char *v
        vma = find_vma(current->mm, addr);
        if (!vma || addr < vma->vm_start)
                return -ENOMEM;
-       mincore_walk.mm = vma->vm_mm;
        end = min(vma->vm_end, addr + (pages << PAGE_SHIFT));
+       if (!can_do_mincore(vma)) {
+               unsigned long pages = DIV_ROUND_UP(end - addr, PAGE_SIZE);
+               memset(vec, 1, pages);
+               return pages;
+       }
+       mincore_walk.mm = vma->vm_mm;
        err = walk_page_range(addr, end, &mincore_walk);
        if (err < 0)
                return err;
index 9c884abc785089d596b13a1edf7520ef0ee4123d..ee36068077b6e54b5c94287dafec00a18e88ff75 100644 (file)
@@ -180,7 +180,7 @@ int __mmu_notifier_invalidate_range_start(struct mmu_notifier_range *range)
                        if (_ret) {
                                pr_info("%pS callback failed with %d in %sblockable context.\n",
                                        mn->ops->invalidate_range_start, _ret,
-                                       !range->blockable ? "non-" : "");
+                                       !mmu_notifier_range_blockable(range) ? "non-" : "");
                                ret = _ret;
                        }
                }
@@ -395,3 +395,13 @@ void mmu_notifier_unregister_no_release(struct mmu_notifier *mn,
        mmdrop(mm);
 }
 EXPORT_SYMBOL_GPL(mmu_notifier_unregister_no_release);
+
+bool
+mmu_notifier_range_update_to_read_only(const struct mmu_notifier_range *range)
+{
+       if (!range->vma || range->event != MMU_NOTIFY_PROTECTION_VMA)
+               return false;
+       /* Return true if the vma still have the read flag set. */
+       return range->vma->vm_flags & VM_READ;
+}
+EXPORT_SYMBOL_GPL(mmu_notifier_range_update_to_read_only);
index 028c724dcb1ae47337127517d9f3181caa8f4728..bf38dfbbb4b4748e53913a2a6dde7e2a2b8efee7 100644 (file)
@@ -39,7 +39,6 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                unsigned long addr, unsigned long end, pgprot_t newprot,
                int dirty_accountable, int prot_numa)
 {
-       struct mm_struct *mm = vma->vm_mm;
        pte_t *pte, oldpte;
        spinlock_t *ptl;
        unsigned long pages = 0;
@@ -136,7 +135,7 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                                newpte = swp_entry_to_pte(entry);
                                if (pte_swp_soft_dirty(oldpte))
                                        newpte = pte_swp_mksoft_dirty(newpte);
-                               set_pte_at(mm, addr, pte, newpte);
+                               set_pte_at(vma->vm_mm, addr, pte, newpte);
 
                                pages++;
                        }
@@ -150,7 +149,7 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                                 */
                                make_device_private_entry_read(&entry);
                                newpte = swp_entry_to_pte(entry);
-                               set_pte_at(mm, addr, pte, newpte);
+                               set_pte_at(vma->vm_mm, addr, pte, newpte);
 
                                pages++;
                        }
@@ -185,7 +184,9 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
 
                /* invoke the mmu notifier if the pmd is populated */
                if (!range.start) {
-                       mmu_notifier_range_init(&range, vma->vm_mm, addr, end);
+                       mmu_notifier_range_init(&range,
+                               MMU_NOTIFY_PROTECTION_VMA, 0,
+                               vma, vma->vm_mm, addr, end);
                        mmu_notifier_invalidate_range_start(&range);
                }
 
index e3edef6b7a120a3cae727dceeed0513c8cdbc28b..fc241d23cd97ab34fa73d232e7cb8ce1785f784c 100644 (file)
@@ -249,7 +249,8 @@ unsigned long move_page_tables(struct vm_area_struct *vma,
        old_end = old_addr + len;
        flush_cache_range(vma, old_addr, old_end);
 
-       mmu_notifier_range_init(&range, vma->vm_mm, old_addr, old_end);
+       mmu_notifier_range_init(&range, MMU_NOTIFY_UNMAP, 0, vma, vma->vm_mm,
+                               old_addr, old_end);
        mmu_notifier_invalidate_range_start(&range);
 
        for (; old_addr < old_end; old_addr += extent, new_addr += extent) {
index 749276beb1094d61b28da6a5e82c26a2696647ab..b492fd1fcf9ffe63a9b63920b21548a8312d4e8d 100644 (file)
@@ -473,6 +473,20 @@ int vm_insert_page(struct vm_area_struct *vma, unsigned long addr,
 }
 EXPORT_SYMBOL(vm_insert_page);
 
+int vm_map_pages(struct vm_area_struct *vma, struct page **pages,
+                       unsigned long num)
+{
+       return -EINVAL;
+}
+EXPORT_SYMBOL(vm_map_pages);
+
+int vm_map_pages_zero(struct vm_area_struct *vma, struct page **pages,
+                               unsigned long num)
+{
+       return -EINVAL;
+}
+EXPORT_SYMBOL(vm_map_pages_zero);
+
 /*
  *  sys_brk() for the most part doesn't need the global kernel
  *  lock, except when an application is doing something nasty
index 3a2484884cfd14924bee506cb96aeb65982e48b5..539c91d0b26ad34c2db1ac865e4144c35edc162a 100644 (file)
@@ -531,7 +531,8 @@ bool __oom_reap_task_mm(struct mm_struct *mm)
                        struct mmu_notifier_range range;
                        struct mmu_gather tlb;
 
-                       mmu_notifier_range_init(&range, mm, vma->vm_start,
+                       mmu_notifier_range_init(&range, MMU_NOTIFY_UNMAP, 0,
+                                               vma, mm, vma->vm_start,
                                                vma->vm_end);
                        tlb_gather_mmu(&tlb, mm, range.start, range.end);
                        if (mmu_notifier_invalidate_range_start_nonblock(&range)) {
index 9f61dfec6a1f6bf5d9ef15e52dd107da1b044f6c..07656485c0e61a29018829f579f79e721ed243af 100644 (file)
@@ -2808,6 +2808,18 @@ int __test_set_page_writeback(struct page *page, bool keep_write)
 }
 EXPORT_SYMBOL(__test_set_page_writeback);
 
+/*
+ * Wait for a page to complete writeback
+ */
+void wait_on_page_writeback(struct page *page)
+{
+       if (PageWriteback(page)) {
+               trace_wait_on_page_writeback(page, page_mapping(page));
+               wait_on_page_bit(page, PG_writeback);
+       }
+}
+EXPORT_SYMBOL_GPL(wait_on_page_writeback);
+
 /**
  * wait_for_stable_page() - wait for writeback to finish, if necessary.
  * @page:      The page to wait on.
index 59661106da167d8ad71a345ff387f7935a3e9018..3b13d39141760edf95ab019e4ad52abea83e3b33 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/mempolicy.h>
 #include <linux/memremap.h>
 #include <linux/stop_machine.h>
+#include <linux/random.h>
 #include <linux/sort.h>
 #include <linux/pfn.h>
 #include <linux/backing-dev.h>
@@ -72,6 +73,7 @@
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
 #include "internal.h"
+#include "shuffle.h"
 
 /* prevent >1 _updater_ of zone percpu pageset ->high and ->batch fields */
 static DEFINE_MUTEX(pcp_batch_high_lock);
@@ -755,12 +757,6 @@ static inline void set_page_order(struct page *page, unsigned int order)
        __SetPageBuddy(page);
 }
 
-static inline void rmv_page_order(struct page *page)
-{
-       __ClearPageBuddy(page);
-       set_page_private(page, 0);
-}
-
 /*
  * This function checks whether a page is free && is the buddy
  * we can coalesce a page and its buddy if
@@ -918,13 +914,10 @@ continue_merging:
                 * Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page,
                 * merge with it and move up one order.
                 */
-               if (page_is_guard(buddy)) {
+               if (page_is_guard(buddy))
                        clear_page_guard(zone, buddy, order, migratetype);
-               } else {
-                       list_del(&buddy->lru);
-                       zone->free_area[order].nr_free--;
-                       rmv_page_order(buddy);
-               }
+               else
+                       del_page_from_free_area(buddy, &zone->free_area[order]);
                combined_pfn = buddy_pfn & pfn;
                page = page + (combined_pfn - pfn);
                pfn = combined_pfn;
@@ -966,7 +959,8 @@ done_merging:
         * so it's less likely to be used soon and more likely to be merged
         * as a higher order page
         */
-       if ((order < MAX_ORDER-2) && pfn_valid_within(buddy_pfn)) {
+       if ((order < MAX_ORDER-2) && pfn_valid_within(buddy_pfn)
+                       && !is_shuffle_order(order)) {
                struct page *higher_page, *higher_buddy;
                combined_pfn = buddy_pfn & pfn;
                higher_page = page + (combined_pfn - pfn);
@@ -974,15 +968,18 @@ done_merging:
                higher_buddy = higher_page + (buddy_pfn - combined_pfn);
                if (pfn_valid_within(buddy_pfn) &&
                    page_is_buddy(higher_page, higher_buddy, order + 1)) {
-                       list_add_tail(&page->lru,
-                               &zone->free_area[order].free_list[migratetype]);
-                       goto out;
+                       add_to_free_area_tail(page, &zone->free_area[order],
+                                             migratetype);
+                       return;
                }
        }
 
-       list_add(&page->lru, &zone->free_area[order].free_list[migratetype]);
-out:
-       zone->free_area[order].nr_free++;
+       if (is_shuffle_order(order))
+               add_to_free_area_random(page, &zone->free_area[order],
+                               migratetype);
+       else
+               add_to_free_area(page, &zone->free_area[order], migratetype);
+
 }
 
 /*
@@ -1416,36 +1413,22 @@ int __meminit early_pfn_to_nid(unsigned long pfn)
 #endif
 
 #ifdef CONFIG_NODES_SPAN_OTHER_NODES
-static inline bool __meminit __maybe_unused
-meminit_pfn_in_nid(unsigned long pfn, int node,
-                  struct mminit_pfnnid_cache *state)
+/* Only safe to use early in boot when initialisation is single-threaded */
+static inline bool __meminit early_pfn_in_nid(unsigned long pfn, int node)
 {
        int nid;
 
-       nid = __early_pfn_to_nid(pfn, state);
+       nid = __early_pfn_to_nid(pfn, &early_pfnnid_cache);
        if (nid >= 0 && nid != node)
                return false;
        return true;
 }
 
-/* Only safe to use early in boot when initialisation is single-threaded */
-static inline bool __meminit early_pfn_in_nid(unsigned long pfn, int node)
-{
-       return meminit_pfn_in_nid(pfn, node, &early_pfnnid_cache);
-}
-
 #else
-
 static inline bool __meminit early_pfn_in_nid(unsigned long pfn, int node)
 {
        return true;
 }
-static inline bool __meminit  __maybe_unused
-meminit_pfn_in_nid(unsigned long pfn, int node,
-                  struct mminit_pfnnid_cache *state)
-{
-       return true;
-}
 #endif
 
 
@@ -1574,21 +1557,13 @@ static inline void __init pgdat_init_report_one_done(void)
  *
  * Then, we check if a current large page is valid by only checking the validity
  * of the head pfn.
- *
- * Finally, meminit_pfn_in_nid is checked on systems where pfns can interleave
- * within a node: a pfn is between start and end of a node, but does not belong
- * to this memory node.
  */
-static inline bool __init
-deferred_pfn_valid(int nid, unsigned long pfn,
-                  struct mminit_pfnnid_cache *nid_init_state)
+static inline bool __init deferred_pfn_valid(unsigned long pfn)
 {
        if (!pfn_valid_within(pfn))
                return false;
        if (!(pfn & (pageblock_nr_pages - 1)) && !pfn_valid(pfn))
                return false;
-       if (!meminit_pfn_in_nid(pfn, nid, nid_init_state))
-               return false;
        return true;
 }
 
@@ -1596,15 +1571,14 @@ deferred_pfn_valid(int nid, unsigned long pfn,
  * Free pages to buddy allocator. Try to free aligned pages in
  * pageblock_nr_pages sizes.
  */
-static void __init deferred_free_pages(int nid, int zid, unsigned long pfn,
+static void __init deferred_free_pages(unsigned long pfn,
                                       unsigned long end_pfn)
 {
-       struct mminit_pfnnid_cache nid_init_state = { };
        unsigned long nr_pgmask = pageblock_nr_pages - 1;
        unsigned long nr_free = 0;
 
        for (; pfn < end_pfn; pfn++) {
-               if (!deferred_pfn_valid(nid, pfn, &nid_init_state)) {
+               if (!deferred_pfn_valid(pfn)) {
                        deferred_free_range(pfn - nr_free, nr_free);
                        nr_free = 0;
                } else if (!(pfn & nr_pgmask)) {
@@ -1624,17 +1598,18 @@ static void __init deferred_free_pages(int nid, int zid, unsigned long pfn,
  * by performing it only once every pageblock_nr_pages.
  * Return number of pages initialized.
  */
-static unsigned long  __init deferred_init_pages(int nid, int zid,
+static unsigned long  __init deferred_init_pages(struct zone *zone,
                                                 unsigned long pfn,
                                                 unsigned long end_pfn)
 {
-       struct mminit_pfnnid_cache nid_init_state = { };
        unsigned long nr_pgmask = pageblock_nr_pages - 1;
+       int nid = zone_to_nid(zone);
        unsigned long nr_pages = 0;
+       int zid = zone_idx(zone);
        struct page *page = NULL;
 
        for (; pfn < end_pfn; pfn++) {
-               if (!deferred_pfn_valid(nid, pfn, &nid_init_state)) {
+               if (!deferred_pfn_valid(pfn)) {
                        page = NULL;
                        continue;
                } else if (!page || !(pfn & nr_pgmask)) {
@@ -1649,18 +1624,100 @@ static unsigned long  __init deferred_init_pages(int nid, int zid,
        return (nr_pages);
 }
 
+/*
+ * This function is meant to pre-load the iterator for the zone init.
+ * Specifically it walks through the ranges until we are caught up to the
+ * first_init_pfn value and exits there. If we never encounter the value we
+ * return false indicating there are no valid ranges left.
+ */
+static bool __init
+deferred_init_mem_pfn_range_in_zone(u64 *i, struct zone *zone,
+                                   unsigned long *spfn, unsigned long *epfn,
+                                   unsigned long first_init_pfn)
+{
+       u64 j;
+
+       /*
+        * Start out by walking through the ranges in this zone that have
+        * already been initialized. We don't need to do anything with them
+        * so we just need to flush them out of the system.
+        */
+       for_each_free_mem_pfn_range_in_zone(j, zone, spfn, epfn) {
+               if (*epfn <= first_init_pfn)
+                       continue;
+               if (*spfn < first_init_pfn)
+                       *spfn = first_init_pfn;
+               *i = j;
+               return true;
+       }
+
+       return false;
+}
+
+/*
+ * Initialize and free pages. We do it in two loops: first we initialize
+ * struct page, then free to buddy allocator, because while we are
+ * freeing pages we can access pages that are ahead (computing buddy
+ * page in __free_one_page()).
+ *
+ * In order to try and keep some memory in the cache we have the loop
+ * broken along max page order boundaries. This way we will not cause
+ * any issues with the buddy page computation.
+ */
+static unsigned long __init
+deferred_init_maxorder(u64 *i, struct zone *zone, unsigned long *start_pfn,
+                      unsigned long *end_pfn)
+{
+       unsigned long mo_pfn = ALIGN(*start_pfn + 1, MAX_ORDER_NR_PAGES);
+       unsigned long spfn = *start_pfn, epfn = *end_pfn;
+       unsigned long nr_pages = 0;
+       u64 j = *i;
+
+       /* First we loop through and initialize the page values */
+       for_each_free_mem_pfn_range_in_zone_from(j, zone, start_pfn, end_pfn) {
+               unsigned long t;
+
+               if (mo_pfn <= *start_pfn)
+                       break;
+
+               t = min(mo_pfn, *end_pfn);
+               nr_pages += deferred_init_pages(zone, *start_pfn, t);
+
+               if (mo_pfn < *end_pfn) {
+                       *start_pfn = mo_pfn;
+                       break;
+               }
+       }
+
+       /* Reset values and now loop through freeing pages as needed */
+       swap(j, *i);
+
+       for_each_free_mem_pfn_range_in_zone_from(j, zone, &spfn, &epfn) {
+               unsigned long t;
+
+               if (mo_pfn <= spfn)
+                       break;
+
+               t = min(mo_pfn, epfn);
+               deferred_free_pages(spfn, t);
+
+               if (mo_pfn <= epfn)
+                       break;
+       }
+
+       return nr_pages;
+}
+
 /* Initialise remaining memory on a node */
 static int __init deferred_init_memmap(void *data)
 {
        pg_data_t *pgdat = data;
-       int nid = pgdat->node_id;
+       const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id);
+       unsigned long spfn = 0, epfn = 0, nr_pages = 0;
+       unsigned long first_init_pfn, flags;
        unsigned long start = jiffies;
-       unsigned long nr_pages = 0;
-       unsigned long spfn, epfn, first_init_pfn, flags;
-       phys_addr_t spa, epa;
-       int zid;
        struct zone *zone;
-       const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id);
+       int zid;
        u64 i;
 
        /* Bind memory initialisation thread to a local node if possible */
@@ -1686,31 +1743,27 @@ static int __init deferred_init_memmap(void *data)
                if (first_init_pfn < zone_end_pfn(zone))
                        break;
        }
-       first_init_pfn = max(zone->zone_start_pfn, first_init_pfn);
+
+       /* If the zone is empty somebody else may have cleared out the zone */
+       if (!deferred_init_mem_pfn_range_in_zone(&i, zone, &spfn, &epfn,
+                                                first_init_pfn))
+               goto zone_empty;
 
        /*
-        * Initialize and free pages. We do it in two loops: first we initialize
-        * struct page, than free to buddy allocator, because while we are
-        * freeing pages we can access pages that are ahead (computing buddy
-        * page in __free_one_page()).
+        * Initialize and free pages in MAX_ORDER sized increments so
+        * that we can avoid introducing any issues with the buddy
+        * allocator.
         */
-       for_each_free_mem_range(i, nid, MEMBLOCK_NONE, &spa, &epa, NULL) {
-               spfn = max_t(unsigned long, first_init_pfn, PFN_UP(spa));
-               epfn = min_t(unsigned long, zone_end_pfn(zone), PFN_DOWN(epa));
-               nr_pages += deferred_init_pages(nid, zid, spfn, epfn);
-       }
-       for_each_free_mem_range(i, nid, MEMBLOCK_NONE, &spa, &epa, NULL) {
-               spfn = max_t(unsigned long, first_init_pfn, PFN_UP(spa));
-               epfn = min_t(unsigned long, zone_end_pfn(zone), PFN_DOWN(epa));
-               deferred_free_pages(nid, zid, spfn, epfn);
-       }
+       while (spfn < epfn)
+               nr_pages += deferred_init_maxorder(&i, zone, &spfn, &epfn);
+zone_empty:
        pgdat_resize_unlock(pgdat, &flags);
 
        /* Sanity check that the next zone really is unpopulated */
        WARN_ON(++zid < MAX_NR_ZONES && populated_zone(++zone));
 
-       pr_info("node %d initialised, %lu pages in %ums\n", nid, nr_pages,
-                                       jiffies_to_msecs(jiffies - start));
+       pr_info("node %d initialised, %lu pages in %ums\n",
+               pgdat->node_id, nr_pages, jiffies_to_msecs(jiffies - start));
 
        pgdat_init_report_one_done();
        return 0;
@@ -1734,14 +1787,11 @@ static int __init deferred_init_memmap(void *data)
 static noinline bool __init
 deferred_grow_zone(struct zone *zone, unsigned int order)
 {
-       int zid = zone_idx(zone);
-       int nid = zone_to_nid(zone);
-       pg_data_t *pgdat = NODE_DATA(nid);
        unsigned long nr_pages_needed = ALIGN(1 << order, PAGES_PER_SECTION);
-       unsigned long nr_pages = 0;
-       unsigned long first_init_pfn, spfn, epfn, t, flags;
+       pg_data_t *pgdat = zone->zone_pgdat;
        unsigned long first_deferred_pfn = pgdat->first_deferred_pfn;
-       phys_addr_t spa, epa;
+       unsigned long spfn, epfn, flags;
+       unsigned long nr_pages = 0;
        u64 i;
 
        /* Only the last zone may have deferred pages */
@@ -1770,38 +1820,35 @@ deferred_grow_zone(struct zone *zone, unsigned int order)
                return true;
        }
 
-       first_init_pfn = max(zone->zone_start_pfn, first_deferred_pfn);
-
-       if (first_init_pfn >= pgdat_end_pfn(pgdat)) {
+       /* If the zone is empty somebody else may have cleared out the zone */
+       if (!deferred_init_mem_pfn_range_in_zone(&i, zone, &spfn, &epfn,
+                                                first_deferred_pfn)) {
+               pgdat->first_deferred_pfn = ULONG_MAX;
                pgdat_resize_unlock(pgdat, &flags);
-               return false;
+               return true;
        }
 
-       for_each_free_mem_range(i, nid, MEMBLOCK_NONE, &spa, &epa, NULL) {
-               spfn = max_t(unsigned long, first_init_pfn, PFN_UP(spa));
-               epfn = min_t(unsigned long, zone_end_pfn(zone), PFN_DOWN(epa));
+       /*
+        * Initialize and free pages in MAX_ORDER sized increments so
+        * that we can avoid introducing any issues with the buddy
+        * allocator.
+        */
+       while (spfn < epfn) {
+               /* update our first deferred PFN for this section */
+               first_deferred_pfn = spfn;
 
-               while (spfn < epfn && nr_pages < nr_pages_needed) {
-                       t = ALIGN(spfn + PAGES_PER_SECTION, PAGES_PER_SECTION);
-                       first_deferred_pfn = min(t, epfn);
-                       nr_pages += deferred_init_pages(nid, zid, spfn,
-                                                       first_deferred_pfn);
-                       spfn = first_deferred_pfn;
-               }
+               nr_pages += deferred_init_maxorder(&i, zone, &spfn, &epfn);
 
+               /* We should only stop along section boundaries */
+               if ((first_deferred_pfn ^ spfn) < PAGES_PER_SECTION)
+                       continue;
+
+               /* If our quota has been met we can stop here */
                if (nr_pages >= nr_pages_needed)
                        break;
        }
 
-       for_each_free_mem_range(i, nid, MEMBLOCK_NONE, &spa, &epa, NULL) {
-               spfn = max_t(unsigned long, first_init_pfn, PFN_UP(spa));
-               epfn = min_t(unsigned long, first_deferred_pfn, PFN_DOWN(epa));
-               deferred_free_pages(nid, zid, spfn, epfn);
-
-               if (first_deferred_pfn == epfn)
-                       break;
-       }
-       pgdat->first_deferred_pfn = first_deferred_pfn;
+       pgdat->first_deferred_pfn = spfn;
        pgdat_resize_unlock(pgdat, &flags);
 
        return nr_pages > 0;
@@ -1824,9 +1871,9 @@ _deferred_grow_zone(struct zone *zone, unsigned int order)
 void __init page_alloc_init_late(void)
 {
        struct zone *zone;
+       int nid;
 
 #ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
-       int nid;
 
        /* There will be num_node_state(N_MEMORY) threads */
        atomic_set(&pgdat_init_n_undone, num_node_state(N_MEMORY));
@@ -1846,10 +1893,12 @@ void __init page_alloc_init_late(void)
        /* Reinit limits that are based on free pages after the kernel is up */
        files_maxfiles_init();
 #endif
-#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
+
        /* Discard memblock private memory */
        memblock_discard();
-#endif
+
+       for_each_node_state(nid, N_MEMORY)
+               shuffle_free_memory(NODE_DATA(nid));
 
        for_each_populated_zone(zone)
                set_zone_contiguous(zone);
@@ -1921,8 +1970,7 @@ static inline void expand(struct zone *zone, struct page *page,
                if (set_page_guard(zone, &page[size], high, migratetype))
                        continue;
 
-               list_add(&page[size].lru, &area->free_list[migratetype]);
-               area->nr_free++;
+               add_to_free_area(&page[size], area, migratetype);
                set_page_order(&page[size], high);
        }
 }
@@ -1937,7 +1985,7 @@ static void check_new_page_bad(struct page *page)
        if (unlikely(page->mapping != NULL))
                bad_reason = "non-NULL mapping";
        if (unlikely(page_ref_count(page) != 0))
-               bad_reason = "nonzero _count";
+               bad_reason = "nonzero _refcount";
        if (unlikely(page->flags & __PG_HWPOISON)) {
                bad_reason = "HWPoisoned (hardware-corrupted)";
                bad_flags = __PG_HWPOISON;
@@ -2064,13 +2112,10 @@ struct page *__rmqueue_smallest(struct zone *zone, unsigned int order,
        /* Find a page of the appropriate size in the preferred list */
        for (current_order = order; current_order < MAX_ORDER; ++current_order) {
                area = &(zone->free_area[current_order]);
-               page = list_first_entry_or_null(&area->free_list[migratetype],
-                                                       struct page, lru);
+               page = get_page_from_free_area(area, migratetype);
                if (!page)
                        continue;
-               list_del(&page->lru);
-               rmv_page_order(page);
-               area->nr_free--;
+               del_page_from_free_area(page, area);
                expand(zone, page, order, current_order, area, migratetype);
                set_pcppage_migratetype(page, migratetype);
                return page;
@@ -2156,8 +2201,7 @@ static int move_freepages(struct zone *zone,
                }
 
                order = page_order(page);
-               list_move(&page->lru,
-                         &zone->free_area[order].free_list[migratetype]);
+               move_to_free_area(page, &zone->free_area[order], migratetype);
                page += 1 << order;
                pages_moved += 1 << order;
        }
@@ -2345,7 +2389,7 @@ static void steal_suitable_fallback(struct zone *zone, struct page *page,
 
 single_page:
        area = &zone->free_area[current_order];
-       list_move(&page->lru, &area->free_list[start_type]);
+       move_to_free_area(page, area, start_type);
 }
 
 /*
@@ -2369,7 +2413,7 @@ int find_suitable_fallback(struct free_area *area, unsigned int order,
                if (fallback_mt == MIGRATE_TYPES)
                        break;
 
-               if (list_empty(&area->free_list[fallback_mt]))
+               if (free_area_empty(area, fallback_mt))
                        continue;
 
                if (can_steal_fallback(order, migratetype))
@@ -2456,9 +2500,7 @@ static bool unreserve_highatomic_pageblock(const struct alloc_context *ac,
                for (order = 0; order < MAX_ORDER; order++) {
                        struct free_area *area = &(zone->free_area[order]);
 
-                       page = list_first_entry_or_null(
-                                       &area->free_list[MIGRATE_HIGHATOMIC],
-                                       struct page, lru);
+                       page = get_page_from_free_area(area, MIGRATE_HIGHATOMIC);
                        if (!page)
                                continue;
 
@@ -2581,8 +2623,7 @@ find_smallest:
        VM_BUG_ON(current_order == MAX_ORDER);
 
 do_steal:
-       page = list_first_entry(&area->free_list[fallback_mt],
-                                                       struct page, lru);
+       page = get_page_from_free_area(area, fallback_mt);
 
        steal_suitable_fallback(zone, page, alloc_flags, start_migratetype,
                                                                can_steal);
@@ -3019,6 +3060,7 @@ EXPORT_SYMBOL_GPL(split_page);
 
 int __isolate_free_page(struct page *page, unsigned int order)
 {
+       struct free_area *area = &page_zone(page)->free_area[order];
        unsigned long watermark;
        struct zone *zone;
        int mt;
@@ -3043,9 +3085,8 @@ int __isolate_free_page(struct page *page, unsigned int order)
        }
 
        /* Remove page from free list */
-       list_del(&page->lru);
-       zone->free_area[order].nr_free--;
-       rmv_page_order(page);
+
+       del_page_from_free_area(page, area);
 
        /*
         * Set the pageblock if the isolated page is at least half of a
@@ -3120,9 +3161,8 @@ static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype,
 
 /* Lock and remove page from the per-cpu list */
 static struct page *rmqueue_pcplist(struct zone *preferred_zone,
-                       struct zone *zone, unsigned int order,
-                       gfp_t gfp_flags, int migratetype,
-                       unsigned int alloc_flags)
+                       struct zone *zone, gfp_t gfp_flags,
+                       int migratetype, unsigned int alloc_flags)
 {
        struct per_cpu_pages *pcp;
        struct list_head *list;
@@ -3134,7 +3174,7 @@ static struct page *rmqueue_pcplist(struct zone *preferred_zone,
        list = &pcp->lists[migratetype];
        page = __rmqueue_pcplist(zone,  migratetype, alloc_flags, pcp, list);
        if (page) {
-               __count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order);
+               __count_zid_vm_events(PGALLOC, page_zonenum(page), 1);
                zone_statistics(preferred_zone, zone);
        }
        local_irq_restore(flags);
@@ -3154,8 +3194,8 @@ struct page *rmqueue(struct zone *preferred_zone,
        struct page *page;
 
        if (likely(order == 0)) {
-               page = rmqueue_pcplist(preferred_zone, zone, order,
-                               gfp_flags, migratetype, alloc_flags);
+               page = rmqueue_pcplist(preferred_zone, zone, gfp_flags,
+                                       migratetype, alloc_flags);
                goto out;
        }
 
@@ -3343,13 +3383,13 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,
                        continue;
 
                for (mt = 0; mt < MIGRATE_PCPTYPES; mt++) {
-                       if (!list_empty(&area->free_list[mt]))
+                       if (!free_area_empty(area, mt))
                                return true;
                }
 
 #ifdef CONFIG_CMA
                if ((alloc_flags & ALLOC_CMA) &&
-                   !list_empty(&area->free_list[MIGRATE_CMA])) {
+                   !free_area_empty(area, MIGRATE_CMA)) {
                        return true;
                }
 #endif
@@ -4821,7 +4861,7 @@ static void *make_alloc_exact(unsigned long addr, unsigned int order,
 /**
  * alloc_pages_exact - allocate an exact number physically-contiguous pages.
  * @size: the number of bytes to allocate
- * @gfp_mask: GFP flags for the allocation
+ * @gfp_mask: GFP flags for the allocation, must not contain __GFP_COMP
  *
  * This function is similar to alloc_pages(), except that it allocates the
  * minimum number of pages to satisfy the request.  alloc_pages() can only
@@ -4838,6 +4878,9 @@ void *alloc_pages_exact(size_t size, gfp_t gfp_mask)
        unsigned int order = get_order(size);
        unsigned long addr;
 
+       if (WARN_ON_ONCE(gfp_mask & __GFP_COMP))
+               gfp_mask &= ~__GFP_COMP;
+
        addr = __get_free_pages(gfp_mask, order);
        return make_alloc_exact(addr, order, size);
 }
@@ -4848,7 +4891,7 @@ EXPORT_SYMBOL(alloc_pages_exact);
  *                        pages on a node.
  * @nid: the preferred node ID where memory should be allocated
  * @size: the number of bytes to allocate
- * @gfp_mask: GFP flags for the allocation
+ * @gfp_mask: GFP flags for the allocation, must not contain __GFP_COMP
  *
  * Like alloc_pages_exact(), but try to allocate on node nid first before falling
  * back.
@@ -4858,7 +4901,12 @@ EXPORT_SYMBOL(alloc_pages_exact);
 void * __meminit alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask)
 {
        unsigned int order = get_order(size);
-       struct page *p = alloc_pages_node(nid, gfp_mask, order);
+       struct page *p;
+
+       if (WARN_ON_ONCE(gfp_mask & __GFP_COMP))
+               gfp_mask &= ~__GFP_COMP;
+
+       p = alloc_pages_node(nid, gfp_mask, order);
        if (!p)
                return NULL;
        return make_alloc_exact((unsigned long)page_address(p), order, size);
@@ -5268,7 +5316,7 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask)
 
                        types[order] = 0;
                        for (type = 0; type < MIGRATE_TYPES; type++) {
-                               if (!list_empty(&area->free_list[type]))
+                               if (!free_area_empty(area, type))
                                        types[order] |= 1 << type;
                        }
                }
@@ -6247,13 +6295,15 @@ static unsigned long __init zone_spanned_pages_in_node(int nid,
                                        unsigned long *zone_end_pfn,
                                        unsigned long *ignored)
 {
+       unsigned long zone_low = arch_zone_lowest_possible_pfn[zone_type];
+       unsigned long zone_high = arch_zone_highest_possible_pfn[zone_type];
        /* When hotadd a new node from cpu_up(), the node should be empty */
        if (!node_start_pfn && !node_end_pfn)
                return 0;
 
        /* Get the start and end of the zone */
-       *zone_start_pfn = arch_zone_lowest_possible_pfn[zone_type];
-       *zone_end_pfn = arch_zone_highest_possible_pfn[zone_type];
+       *zone_start_pfn = clamp(node_start_pfn, zone_low, zone_high);
+       *zone_end_pfn = clamp(node_end_pfn, zone_low, zone_high);
        adjust_zone_range_for_zone_movable(nid, zone_type,
                                node_start_pfn, node_end_pfn,
                                zone_start_pfn, zone_end_pfn);
@@ -8129,8 +8179,7 @@ unmovable:
        return true;
 }
 
-#if (defined(CONFIG_MEMORY_ISOLATION) && defined(CONFIG_COMPACTION)) || defined(CONFIG_CMA)
-
+#ifdef CONFIG_CONTIG_ALLOC
 static unsigned long pfn_max_align_down(unsigned long pfn)
 {
        return pfn & ~(max_t(unsigned long, MAX_ORDER_NR_PAGES,
@@ -8339,8 +8388,9 @@ done:
                                pfn_max_align_up(end), migratetype);
        return ret;
 }
+#endif /* CONFIG_CONTIG_ALLOC */
 
-void free_contig_range(unsigned long pfn, unsigned nr_pages)
+void free_contig_range(unsigned long pfn, unsigned int nr_pages)
 {
        unsigned int count = 0;
 
@@ -8352,7 +8402,6 @@ void free_contig_range(unsigned long pfn, unsigned nr_pages)
        }
        WARN(count != 0, "%d pages are still in use!\n", count);
 }
-#endif
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 /*
@@ -8394,7 +8443,7 @@ void zone_pcp_reset(struct zone *zone)
  * All pages in the range must be in a single zone and isolated
  * before calling this.
  */
-void
+unsigned long
 __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
 {
        struct page *page;
@@ -8402,12 +8451,15 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
        unsigned int order, i;
        unsigned long pfn;
        unsigned long flags;
+       unsigned long offlined_pages = 0;
+
        /* find the first valid pfn */
        for (pfn = start_pfn; pfn < end_pfn; pfn++)
                if (pfn_valid(pfn))
                        break;
        if (pfn == end_pfn)
-               return;
+               return offlined_pages;
+
        offline_mem_sections(pfn, end_pfn);
        zone = page_zone(pfn_to_page(pfn));
        spin_lock_irqsave(&zone->lock, flags);
@@ -8425,24 +8477,26 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
                if (unlikely(!PageBuddy(page) && PageHWPoison(page))) {
                        pfn++;
                        SetPageReserved(page);
+                       offlined_pages++;
                        continue;
                }
 
                BUG_ON(page_count(page));
                BUG_ON(!PageBuddy(page));
                order = page_order(page);
+               offlined_pages += 1 << order;
 #ifdef CONFIG_DEBUG_VM
                pr_info("remove from free list %lx %d %lx\n",
                        pfn, 1 << order, end_pfn);
 #endif
-               list_del(&page->lru);
-               rmv_page_order(page);
-               zone->free_area[order].nr_free--;
+               del_page_from_free_area(page, &zone->free_area[order]);
                for (i = 0; i < (1 << order); i++)
                        SetPageReserved((page+i));
                pfn += (1 << order);
        }
        spin_unlock_irqrestore(&zone->lock, flags);
+
+       return offlined_pages;
 }
 #endif
 
index 019280712e1b8b7e075b51573b5c56d07aef3922..e3638a5bafff9b7058e4176973bc965fbb11a4cd 100644 (file)
@@ -151,8 +151,6 @@ __first_valid_page(unsigned long pfn, unsigned long nr_pages)
        for (i = 0; i < nr_pages; i++) {
                struct page *page;
 
-               if (!pfn_valid_within(pfn + i))
-                       continue;
                page = pfn_to_online_page(pfn + i);
                if (!page)
                        continue;
index b1739dc06b73a8458199827b7c00027ef56165ae..0468ba500bd4913173589150979b4127eafbe5ce 100644 (file)
@@ -9,8 +9,17 @@
  * pcpu_block_md is the metadata block struct.
  * Each chunk's bitmap is split into a number of full blocks.
  * All units are in terms of bits.
+ *
+ * The scan hint is the largest known contiguous area before the contig hint.
+ * It is not necessarily the actual largest contig hint though.  There is an
+ * invariant that the scan_hint_start > contig_hint_start iff
+ * scan_hint == contig_hint.  This is necessary because when scanning forward,
+ * we don't know if a new contig hint would be better than the current one.
  */
 struct pcpu_block_md {
+       int                     scan_hint;      /* scan hint for block */
+       int                     scan_hint_start; /* block relative starting
+                                                   position of the scan hint */
        int                     contig_hint;    /* contig hint for block */
        int                     contig_hint_start; /* block relative starting
                                                      position of the contig hint */
@@ -19,6 +28,7 @@ struct pcpu_block_md {
        int                     right_free;     /* size of free space along
                                                   the right side of the block */
        int                     first_free;     /* block position of first free */
+       int                     nr_bits;        /* total bits responsible for */
 };
 
 struct pcpu_chunk {
@@ -29,9 +39,7 @@ struct pcpu_chunk {
 
        struct list_head        list;           /* linked to pcpu_slot lists */
        int                     free_bytes;     /* free bytes in the chunk */
-       int                     contig_bits;    /* max contiguous size hint */
-       int                     contig_bits_start; /* contig_bits starting
-                                                     offset */
+       struct pcpu_block_md    chunk_md;
        void                    *base_addr;     /* base address of this chunk */
 
        unsigned long           *alloc_map;     /* allocation map */
@@ -39,7 +47,6 @@ struct pcpu_chunk {
        struct pcpu_block_md    *md_blocks;     /* metadata blocks */
 
        void                    *data;          /* chunk data */
-       int                     first_bit;      /* no free below this */
        bool                    immutable;      /* no [de]population allowed */
        int                     start_offset;   /* the overlap with the previous
                                                   region to have a page aligned
index b68d5df147317295514e61ccae2b9f65f5311895..3a2ff5c9192c60728068c91defc32a026e235d05 100644 (file)
@@ -70,7 +70,7 @@ static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp)
        chunk->base_addr = page_address(pages);
 
        spin_lock_irqsave(&pcpu_lock, flags);
-       pcpu_chunk_populated(chunk, 0, nr_pages, false);
+       pcpu_chunk_populated(chunk, 0, nr_pages);
        spin_unlock_irqrestore(&pcpu_lock, flags);
 
        pcpu_stats_chunk_alloc();
index b5fdd43b60c9088de4779b2c3c02e0a08caf81ae..ef5034a0464e5f3d7acdf07e6bd672804931de98 100644 (file)
@@ -53,6 +53,7 @@ static int find_max_nr_alloc(void)
 static void chunk_map_stats(struct seq_file *m, struct pcpu_chunk *chunk,
                            int *buffer)
 {
+       struct pcpu_block_md *chunk_md = &chunk->chunk_md;
        int i, last_alloc, as_len, start, end;
        int *alloc_sizes, *p;
        /* statistics */
@@ -121,9 +122,9 @@ static void chunk_map_stats(struct seq_file *m, struct pcpu_chunk *chunk,
        P("nr_alloc", chunk->nr_alloc);
        P("max_alloc_size", chunk->max_alloc_size);
        P("empty_pop_pages", chunk->nr_empty_pop_pages);
-       P("first_bit", chunk->first_bit);
+       P("first_bit", chunk_md->first_free);
        P("free_bytes", chunk->free_bytes);
-       P("contig_bytes", chunk->contig_bits * PCPU_MIN_ALLOC_SIZE);
+       P("contig_bytes", chunk_md->contig_hint * PCPU_MIN_ALLOC_SIZE);
        P("sum_frag", sum_frag);
        P("max_frag", max_frag);
        P("cur_min_alloc", cur_min_alloc);
index 68dd2e7e73b5f29b2d3dfd2bd9e4b984244d7dc9..2df0ee680ea6924796179be7dc005de363251d71 100644 (file)
@@ -94,6 +94,8 @@
 
 /* the slots are sorted by free bytes left, 1-31 bytes share the same slot */
 #define PCPU_SLOT_BASE_SHIFT           5
+/* chunks in slots below this are subject to being sidelined on failed alloc */
+#define PCPU_SLOT_FAIL_THRESHOLD       3
 
 #define PCPU_EMPTY_POP_PAGES_LOW       2
 #define PCPU_EMPTY_POP_PAGES_HIGH      4
@@ -231,10 +233,13 @@ static int pcpu_size_to_slot(int size)
 
 static int pcpu_chunk_slot(const struct pcpu_chunk *chunk)
 {
-       if (chunk->free_bytes < PCPU_MIN_ALLOC_SIZE || chunk->contig_bits == 0)
+       const struct pcpu_block_md *chunk_md = &chunk->chunk_md;
+
+       if (chunk->free_bytes < PCPU_MIN_ALLOC_SIZE ||
+           chunk_md->contig_hint == 0)
                return 0;
 
-       return pcpu_size_to_slot(chunk->free_bytes);
+       return pcpu_size_to_slot(chunk_md->contig_hint * PCPU_MIN_ALLOC_SIZE);
 }
 
 /* set the pointer to a chunk in a page struct */
@@ -318,6 +323,34 @@ static unsigned long pcpu_block_off_to_off(int index, int off)
        return index * PCPU_BITMAP_BLOCK_BITS + off;
 }
 
+/*
+ * pcpu_next_hint - determine which hint to use
+ * @block: block of interest
+ * @alloc_bits: size of allocation
+ *
+ * This determines if we should scan based on the scan_hint or first_free.
+ * In general, we want to scan from first_free to fulfill allocations by
+ * first fit.  However, if we know a scan_hint at position scan_hint_start
+ * cannot fulfill an allocation, we can begin scanning from there knowing
+ * the contig_hint will be our fallback.
+ */
+static int pcpu_next_hint(struct pcpu_block_md *block, int alloc_bits)
+{
+       /*
+        * The three conditions below determine if we can skip past the
+        * scan_hint.  First, does the scan hint exist.  Second, is the
+        * contig_hint after the scan_hint (possibly not true iff
+        * contig_hint == scan_hint).  Third, is the allocation request
+        * larger than the scan_hint.
+        */
+       if (block->scan_hint &&
+           block->contig_hint_start > block->scan_hint_start &&
+           alloc_bits > block->scan_hint)
+               return block->scan_hint_start + block->scan_hint;
+
+       return block->first_free;
+}
+
 /**
  * pcpu_next_md_free_region - finds the next hint free area
  * @chunk: chunk of interest
@@ -413,9 +446,11 @@ static void pcpu_next_fit_region(struct pcpu_chunk *chunk, int alloc_bits,
                if (block->contig_hint &&
                    block->contig_hint_start >= block_off &&
                    block->contig_hint >= *bits + alloc_bits) {
+                       int start = pcpu_next_hint(block, alloc_bits);
+
                        *bits += alloc_bits + block->contig_hint_start -
-                                block->first_free;
-                       *bit_off = pcpu_block_off_to_off(i, block->first_free);
+                                start;
+                       *bit_off = pcpu_block_off_to_off(i, start);
                        return;
                }
                /* reset to satisfy the second predicate above */
@@ -488,6 +523,22 @@ static void pcpu_mem_free(void *ptr)
        kvfree(ptr);
 }
 
+static void __pcpu_chunk_move(struct pcpu_chunk *chunk, int slot,
+                             bool move_front)
+{
+       if (chunk != pcpu_reserved_chunk) {
+               if (move_front)
+                       list_move(&chunk->list, &pcpu_slot[slot]);
+               else
+                       list_move_tail(&chunk->list, &pcpu_slot[slot]);
+       }
+}
+
+static void pcpu_chunk_move(struct pcpu_chunk *chunk, int slot)
+{
+       __pcpu_chunk_move(chunk, slot, true);
+}
+
 /**
  * pcpu_chunk_relocate - put chunk in the appropriate chunk slot
  * @chunk: chunk of interest
@@ -505,110 +556,39 @@ static void pcpu_chunk_relocate(struct pcpu_chunk *chunk, int oslot)
 {
        int nslot = pcpu_chunk_slot(chunk);
 
-       if (chunk != pcpu_reserved_chunk && oslot != nslot) {
-               if (oslot < nslot)
-                       list_move(&chunk->list, &pcpu_slot[nslot]);
-               else
-                       list_move_tail(&chunk->list, &pcpu_slot[nslot]);
-       }
+       if (oslot != nslot)
+               __pcpu_chunk_move(chunk, nslot, oslot < nslot);
 }
 
-/**
- * pcpu_cnt_pop_pages- counts populated backing pages in range
+/*
+ * pcpu_update_empty_pages - update empty page counters
  * @chunk: chunk of interest
- * @bit_off: start offset
- * @bits: size of area to check
- *
- * Calculates the number of populated pages in the region
- * [page_start, page_end).  This keeps track of how many empty populated
- * pages are available and decide if async work should be scheduled.
+ * @nr: nr of empty pages
  *
- * RETURNS:
- * The nr of populated pages.
+ * This is used to keep track of the empty pages now based on the premise
+ * a md_block covers a page.  The hint update functions recognize if a block
+ * is made full or broken to calculate deltas for keeping track of free pages.
  */
-static inline int pcpu_cnt_pop_pages(struct pcpu_chunk *chunk, int bit_off,
-                                    int bits)
+static inline void pcpu_update_empty_pages(struct pcpu_chunk *chunk, int nr)
 {
-       int page_start = PFN_UP(bit_off * PCPU_MIN_ALLOC_SIZE);
-       int page_end = PFN_DOWN((bit_off + bits) * PCPU_MIN_ALLOC_SIZE);
-
-       if (page_start >= page_end)
-               return 0;
-
-       /*
-        * bitmap_weight counts the number of bits set in a bitmap up to
-        * the specified number of bits.  This is counting the populated
-        * pages up to page_end and then subtracting the populated pages
-        * up to page_start to count the populated pages in
-        * [page_start, page_end).
-        */
-       return bitmap_weight(chunk->populated, page_end) -
-              bitmap_weight(chunk->populated, page_start);
-}
-
-/**
- * pcpu_chunk_update - updates the chunk metadata given a free area
- * @chunk: chunk of interest
- * @bit_off: chunk offset
- * @bits: size of free area
- *
- * This updates the chunk's contig hint and starting offset given a free area.
- * Choose the best starting offset if the contig hint is equal.
- */
-static void pcpu_chunk_update(struct pcpu_chunk *chunk, int bit_off, int bits)
-{
-       if (bits > chunk->contig_bits) {
-               chunk->contig_bits_start = bit_off;
-               chunk->contig_bits = bits;
-       } else if (bits == chunk->contig_bits && chunk->contig_bits_start &&
-                  (!bit_off ||
-                   __ffs(bit_off) > __ffs(chunk->contig_bits_start))) {
-               /* use the start with the best alignment */
-               chunk->contig_bits_start = bit_off;
-       }
+       chunk->nr_empty_pop_pages += nr;
+       if (chunk != pcpu_reserved_chunk)
+               pcpu_nr_empty_pop_pages += nr;
 }
 
-/**
- * pcpu_chunk_refresh_hint - updates metadata about a chunk
- * @chunk: chunk of interest
- *
- * Iterates over the metadata blocks to find the largest contig area.
- * It also counts the populated pages and uses the delta to update the
- * global count.
- *
- * Updates:
- *      chunk->contig_bits
- *      chunk->contig_bits_start
- *      nr_empty_pop_pages (chunk and global)
+/*
+ * pcpu_region_overlap - determines if two regions overlap
+ * @a: start of first region, inclusive
+ * @b: end of first region, exclusive
+ * @x: start of second region, inclusive
+ * @y: end of second region, exclusive
+ *
+ * This is used to determine if the hint region [a, b) overlaps with the
+ * allocated region [x, y).
  */
-static void pcpu_chunk_refresh_hint(struct pcpu_chunk *chunk)
+static inline bool pcpu_region_overlap(int a, int b, int x, int y)
 {
-       int bit_off, bits, nr_empty_pop_pages;
-
-       /* clear metadata */
-       chunk->contig_bits = 0;
-
-       bit_off = chunk->first_bit;
-       bits = nr_empty_pop_pages = 0;
-       pcpu_for_each_md_free_region(chunk, bit_off, bits) {
-               pcpu_chunk_update(chunk, bit_off, bits);
-
-               nr_empty_pop_pages += pcpu_cnt_pop_pages(chunk, bit_off, bits);
-       }
-
-       /*
-        * Keep track of nr_empty_pop_pages.
-        *
-        * The chunk maintains the previous number of free pages it held,
-        * so the delta is used to update the global counter.  The reserved
-        * chunk is not part of the free page count as they are populated
-        * at init and are special to serving reserved allocations.
-        */
-       if (chunk != pcpu_reserved_chunk)
-               pcpu_nr_empty_pop_pages +=
-                       (nr_empty_pop_pages - chunk->nr_empty_pop_pages);
-
-       chunk->nr_empty_pop_pages = nr_empty_pop_pages;
+       return (a < y) && (x < b);
 }
 
 /**
@@ -629,16 +609,132 @@ static void pcpu_block_update(struct pcpu_block_md *block, int start, int end)
        if (start == 0)
                block->left_free = contig;
 
-       if (end == PCPU_BITMAP_BLOCK_BITS)
+       if (end == block->nr_bits)
                block->right_free = contig;
 
        if (contig > block->contig_hint) {
+               /* promote the old contig_hint to be the new scan_hint */
+               if (start > block->contig_hint_start) {
+                       if (block->contig_hint > block->scan_hint) {
+                               block->scan_hint_start =
+                                       block->contig_hint_start;
+                               block->scan_hint = block->contig_hint;
+                       } else if (start < block->scan_hint_start) {
+                               /*
+                                * The old contig_hint == scan_hint.  But, the
+                                * new contig is larger so hold the invariant
+                                * scan_hint_start < contig_hint_start.
+                                */
+                               block->scan_hint = 0;
+                       }
+               } else {
+                       block->scan_hint = 0;
+               }
                block->contig_hint_start = start;
                block->contig_hint = contig;
-       } else if (block->contig_hint_start && contig == block->contig_hint &&
-                  (!start || __ffs(start) > __ffs(block->contig_hint_start))) {
-               /* use the start with the best alignment */
-               block->contig_hint_start = start;
+       } else if (contig == block->contig_hint) {
+               if (block->contig_hint_start &&
+                   (!start ||
+                    __ffs(start) > __ffs(block->contig_hint_start))) {
+                       /* start has a better alignment so use it */
+                       block->contig_hint_start = start;
+                       if (start < block->scan_hint_start &&
+                           block->contig_hint > block->scan_hint)
+                               block->scan_hint = 0;
+               } else if (start > block->scan_hint_start ||
+                          block->contig_hint > block->scan_hint) {
+                       /*
+                        * Knowing contig == contig_hint, update the scan_hint
+                        * if it is farther than or larger than the current
+                        * scan_hint.
+                        */
+                       block->scan_hint_start = start;
+                       block->scan_hint = contig;
+               }
+       } else {
+               /*
+                * The region is smaller than the contig_hint.  So only update
+                * the scan_hint if it is larger than or equal and farther than
+                * the current scan_hint.
+                */
+               if ((start < block->contig_hint_start &&
+                    (contig > block->scan_hint ||
+                     (contig == block->scan_hint &&
+                      start > block->scan_hint_start)))) {
+                       block->scan_hint_start = start;
+                       block->scan_hint = contig;
+               }
+       }
+}
+
+/*
+ * pcpu_block_update_scan - update a block given a free area from a scan
+ * @chunk: chunk of interest
+ * @bit_off: chunk offset
+ * @bits: size of free area
+ *
+ * Finding the final allocation spot first goes through pcpu_find_block_fit()
+ * to find a block that can hold the allocation and then pcpu_alloc_area()
+ * where a scan is used.  When allocations require specific alignments,
+ * we can inadvertently create holes which will not be seen in the alloc
+ * or free paths.
+ *
+ * This takes a given free area hole and updates a block as it may change the
+ * scan_hint.  We need to scan backwards to ensure we don't miss free bits
+ * from alignment.
+ */
+static void pcpu_block_update_scan(struct pcpu_chunk *chunk, int bit_off,
+                                  int bits)
+{
+       int s_off = pcpu_off_to_block_off(bit_off);
+       int e_off = s_off + bits;
+       int s_index, l_bit;
+       struct pcpu_block_md *block;
+
+       if (e_off > PCPU_BITMAP_BLOCK_BITS)
+               return;
+
+       s_index = pcpu_off_to_block_index(bit_off);
+       block = chunk->md_blocks + s_index;
+
+       /* scan backwards in case of alignment skipping free bits */
+       l_bit = find_last_bit(pcpu_index_alloc_map(chunk, s_index), s_off);
+       s_off = (s_off == l_bit) ? 0 : l_bit + 1;
+
+       pcpu_block_update(block, s_off, e_off);
+}
+
+/**
+ * pcpu_chunk_refresh_hint - updates metadata about a chunk
+ * @chunk: chunk of interest
+ * @full_scan: if we should scan from the beginning
+ *
+ * Iterates over the metadata blocks to find the largest contig area.
+ * A full scan can be avoided on the allocation path as this is triggered
+ * if we broke the contig_hint.  In doing so, the scan_hint will be before
+ * the contig_hint or after if the scan_hint == contig_hint.  This cannot
+ * be prevented on freeing as we want to find the largest area possibly
+ * spanning blocks.
+ */
+static void pcpu_chunk_refresh_hint(struct pcpu_chunk *chunk, bool full_scan)
+{
+       struct pcpu_block_md *chunk_md = &chunk->chunk_md;
+       int bit_off, bits;
+
+       /* promote scan_hint to contig_hint */
+       if (!full_scan && chunk_md->scan_hint) {
+               bit_off = chunk_md->scan_hint_start + chunk_md->scan_hint;
+               chunk_md->contig_hint_start = chunk_md->scan_hint_start;
+               chunk_md->contig_hint = chunk_md->scan_hint;
+               chunk_md->scan_hint = 0;
+       } else {
+               bit_off = chunk_md->first_free;
+               chunk_md->contig_hint = 0;
+       }
+
+       bits = 0;
+       pcpu_for_each_md_free_region(chunk, bit_off, bits) {
+               pcpu_block_update(chunk_md, bit_off, bit_off + bits);
        }
 }
 
@@ -654,14 +750,23 @@ static void pcpu_block_refresh_hint(struct pcpu_chunk *chunk, int index)
 {
        struct pcpu_block_md *block = chunk->md_blocks + index;
        unsigned long *alloc_map = pcpu_index_alloc_map(chunk, index);
-       int rs, re;     /* region start, region end */
+       int rs, re, start;      /* region start, region end */
+
+       /* promote scan_hint to contig_hint */
+       if (block->scan_hint) {
+               start = block->scan_hint_start + block->scan_hint;
+               block->contig_hint_start = block->scan_hint_start;
+               block->contig_hint = block->scan_hint;
+               block->scan_hint = 0;
+       } else {
+               start = block->first_free;
+               block->contig_hint = 0;
+       }
 
-       /* clear hints */
-       block->contig_hint = 0;
-       block->left_free = block->right_free = 0;
+       block->right_free = 0;
 
        /* iterate over free areas and update the contig hints */
-       pcpu_for_each_unpop_region(alloc_map, rs, re, block->first_free,
+       pcpu_for_each_unpop_region(alloc_map, rs, re, start,
                                   PCPU_BITMAP_BLOCK_BITS) {
                pcpu_block_update(block, rs, re);
        }
@@ -680,6 +785,8 @@ static void pcpu_block_refresh_hint(struct pcpu_chunk *chunk, int index)
 static void pcpu_block_update_hint_alloc(struct pcpu_chunk *chunk, int bit_off,
                                         int bits)
 {
+       struct pcpu_block_md *chunk_md = &chunk->chunk_md;
+       int nr_empty_pages = 0;
        struct pcpu_block_md *s_block, *e_block, *block;
        int s_index, e_index;   /* block indexes of the freed allocation */
        int s_off, e_off;       /* block offsets of the freed allocation */
@@ -704,15 +811,29 @@ static void pcpu_block_update_hint_alloc(struct pcpu_chunk *chunk, int bit_off,
         * If the allocation breaks the contig_hint, a scan is required to
         * restore this hint.
         */
+       if (s_block->contig_hint == PCPU_BITMAP_BLOCK_BITS)
+               nr_empty_pages++;
+
        if (s_off == s_block->first_free)
                s_block->first_free = find_next_zero_bit(
                                        pcpu_index_alloc_map(chunk, s_index),
                                        PCPU_BITMAP_BLOCK_BITS,
                                        s_off + bits);
 
-       if (s_off >= s_block->contig_hint_start &&
-           s_off < s_block->contig_hint_start + s_block->contig_hint) {
+       if (pcpu_region_overlap(s_block->scan_hint_start,
+                               s_block->scan_hint_start + s_block->scan_hint,
+                               s_off,
+                               s_off + bits))
+               s_block->scan_hint = 0;
+
+       if (pcpu_region_overlap(s_block->contig_hint_start,
+                               s_block->contig_hint_start +
+                               s_block->contig_hint,
+                               s_off,
+                               s_off + bits)) {
                /* block contig hint is broken - scan to fix it */
+               if (!s_off)
+                       s_block->left_free = 0;
                pcpu_block_refresh_hint(chunk, s_index);
        } else {
                /* update left and right contig manually */
@@ -728,6 +849,9 @@ static void pcpu_block_update_hint_alloc(struct pcpu_chunk *chunk, int bit_off,
         * Update e_block.
         */
        if (s_index != e_index) {
+               if (e_block->contig_hint == PCPU_BITMAP_BLOCK_BITS)
+                       nr_empty_pages++;
+
                /*
                 * When the allocation is across blocks, the end is along
                 * the left part of the e_block.
@@ -740,11 +864,14 @@ static void pcpu_block_update_hint_alloc(struct pcpu_chunk *chunk, int bit_off,
                        /* reset the block */
                        e_block++;
                } else {
+                       if (e_off > e_block->scan_hint_start)
+                               e_block->scan_hint = 0;
+
+                       e_block->left_free = 0;
                        if (e_off > e_block->contig_hint_start) {
                                /* contig hint is broken - scan to fix it */
                                pcpu_block_refresh_hint(chunk, e_index);
                        } else {
-                               e_block->left_free = 0;
                                e_block->right_free =
                                        min_t(int, e_block->right_free,
                                              PCPU_BITMAP_BLOCK_BITS - e_off);
@@ -752,21 +879,36 @@ static void pcpu_block_update_hint_alloc(struct pcpu_chunk *chunk, int bit_off,
                }
 
                /* update in-between md_blocks */
+               nr_empty_pages += (e_index - s_index - 1);
                for (block = s_block + 1; block < e_block; block++) {
+                       block->scan_hint = 0;
                        block->contig_hint = 0;
                        block->left_free = 0;
                        block->right_free = 0;
                }
        }
 
+       if (nr_empty_pages)
+               pcpu_update_empty_pages(chunk, -nr_empty_pages);
+
+       if (pcpu_region_overlap(chunk_md->scan_hint_start,
+                               chunk_md->scan_hint_start +
+                               chunk_md->scan_hint,
+                               bit_off,
+                               bit_off + bits))
+               chunk_md->scan_hint = 0;
+
        /*
         * The only time a full chunk scan is required is if the chunk
         * contig hint is broken.  Otherwise, it means a smaller space
         * was used and therefore the chunk contig hint is still correct.
         */
-       if (bit_off >= chunk->contig_bits_start  &&
-           bit_off < chunk->contig_bits_start + chunk->contig_bits)
-               pcpu_chunk_refresh_hint(chunk);
+       if (pcpu_region_overlap(chunk_md->contig_hint_start,
+                               chunk_md->contig_hint_start +
+                               chunk_md->contig_hint,
+                               bit_off,
+                               bit_off + bits))
+               pcpu_chunk_refresh_hint(chunk, false);
 }
 
 /**
@@ -782,13 +924,15 @@ static void pcpu_block_update_hint_alloc(struct pcpu_chunk *chunk, int bit_off,
  *
  * A chunk update is triggered if a page becomes free, a block becomes free,
  * or the free spans across blocks.  This tradeoff is to minimize iterating
- * over the block metadata to update chunk->contig_bits.  chunk->contig_bits
- * may be off by up to a page, but it will never be more than the available
- * space.  If the contig hint is contained in one block, it will be accurate.
+ * over the block metadata to update chunk_md->contig_hint.
+ * chunk_md->contig_hint may be off by up to a page, but it will never be more
+ * than the available space.  If the contig hint is contained in one block, it
+ * will be accurate.
  */
 static void pcpu_block_update_hint_free(struct pcpu_chunk *chunk, int bit_off,
                                        int bits)
 {
+       int nr_empty_pages = 0;
        struct pcpu_block_md *s_block, *e_block, *block;
        int s_index, e_index;   /* block indexes of the freed allocation */
        int s_off, e_off;       /* block offsets of the freed allocation */
@@ -842,16 +986,22 @@ static void pcpu_block_update_hint_free(struct pcpu_chunk *chunk, int bit_off,
 
        /* update s_block */
        e_off = (s_index == e_index) ? end : PCPU_BITMAP_BLOCK_BITS;
+       if (!start && e_off == PCPU_BITMAP_BLOCK_BITS)
+               nr_empty_pages++;
        pcpu_block_update(s_block, start, e_off);
 
        /* freeing in the same block */
        if (s_index != e_index) {
                /* update e_block */
+               if (end == PCPU_BITMAP_BLOCK_BITS)
+                       nr_empty_pages++;
                pcpu_block_update(e_block, 0, end);
 
                /* reset md_blocks in the middle */
+               nr_empty_pages += (e_index - s_index - 1);
                for (block = s_block + 1; block < e_block; block++) {
                        block->first_free = 0;
+                       block->scan_hint = 0;
                        block->contig_hint_start = 0;
                        block->contig_hint = PCPU_BITMAP_BLOCK_BITS;
                        block->left_free = PCPU_BITMAP_BLOCK_BITS;
@@ -859,19 +1009,21 @@ static void pcpu_block_update_hint_free(struct pcpu_chunk *chunk, int bit_off,
                }
        }
 
+       if (nr_empty_pages)
+               pcpu_update_empty_pages(chunk, nr_empty_pages);
+
        /*
-        * Refresh chunk metadata when the free makes a page free, a block
-        * free, or spans across blocks.  The contig hint may be off by up to
-        * a page, but if the hint is contained in a block, it will be accurate
-        * with the else condition below.
+        * Refresh chunk metadata when the free makes a block free or spans
+        * across blocks.  The contig_hint may be off by up to a page, but if
+        * the contig_hint is contained in a block, it will be accurate with
+        * the else condition below.
         */
-       if ((ALIGN_DOWN(end, min(PCPU_BITS_PER_PAGE, PCPU_BITMAP_BLOCK_BITS)) >
-            ALIGN(start, min(PCPU_BITS_PER_PAGE, PCPU_BITMAP_BLOCK_BITS))) ||
-           s_index != e_index)
-               pcpu_chunk_refresh_hint(chunk);
+       if (((end - start) >= PCPU_BITMAP_BLOCK_BITS) || s_index != e_index)
+               pcpu_chunk_refresh_hint(chunk, true);
        else
-               pcpu_chunk_update(chunk, pcpu_block_off_to_off(s_index, start),
-                                 s_block->contig_hint);
+               pcpu_block_update(&chunk->chunk_md,
+                                 pcpu_block_off_to_off(s_index, start),
+                                 end);
 }
 
 /**
@@ -926,6 +1078,7 @@ static bool pcpu_is_populated(struct pcpu_chunk *chunk, int bit_off, int bits,
 static int pcpu_find_block_fit(struct pcpu_chunk *chunk, int alloc_bits,
                               size_t align, bool pop_only)
 {
+       struct pcpu_block_md *chunk_md = &chunk->chunk_md;
        int bit_off, bits, next_off;
 
        /*
@@ -934,12 +1087,12 @@ static int pcpu_find_block_fit(struct pcpu_chunk *chunk, int alloc_bits,
         * cannot fit in the global hint, there is memory pressure and creating
         * a new chunk would happen soon.
         */
-       bit_off = ALIGN(chunk->contig_bits_start, align) -
-                 chunk->contig_bits_start;
-       if (bit_off + alloc_bits > chunk->contig_bits)
+       bit_off = ALIGN(chunk_md->contig_hint_start, align) -
+                 chunk_md->contig_hint_start;
+       if (bit_off + alloc_bits > chunk_md->contig_hint)
                return -1;
 
-       bit_off = chunk->first_bit;
+       bit_off = pcpu_next_hint(chunk_md, alloc_bits);
        bits = 0;
        pcpu_for_each_fit_region(chunk, alloc_bits, align, bit_off, bits) {
                if (!pop_only || pcpu_is_populated(chunk, bit_off, bits,
@@ -956,6 +1109,62 @@ static int pcpu_find_block_fit(struct pcpu_chunk *chunk, int alloc_bits,
        return bit_off;
 }
 
+/*
+ * pcpu_find_zero_area - modified from bitmap_find_next_zero_area_off()
+ * @map: the address to base the search on
+ * @size: the bitmap size in bits
+ * @start: the bitnumber to start searching at
+ * @nr: the number of zeroed bits we're looking for
+ * @align_mask: alignment mask for zero area
+ * @largest_off: offset of the largest area skipped
+ * @largest_bits: size of the largest area skipped
+ *
+ * The @align_mask should be one less than a power of 2.
+ *
+ * This is a modified version of bitmap_find_next_zero_area_off() to remember
+ * the largest area that was skipped.  This is imperfect, but in general is
+ * good enough.  The largest remembered region is the largest failed region
+ * seen.  This does not include anything we possibly skipped due to alignment.
+ * pcpu_block_update_scan() does scan backwards to try and recover what was
+ * lost to alignment.  While this can cause scanning to miss earlier possible
+ * free areas, smaller allocations will eventually fill those holes.
+ */
+static unsigned long pcpu_find_zero_area(unsigned long *map,
+                                        unsigned long size,
+                                        unsigned long start,
+                                        unsigned long nr,
+                                        unsigned long align_mask,
+                                        unsigned long *largest_off,
+                                        unsigned long *largest_bits)
+{
+       unsigned long index, end, i, area_off, area_bits;
+again:
+       index = find_next_zero_bit(map, size, start);
+
+       /* Align allocation */
+       index = __ALIGN_MASK(index, align_mask);
+       area_off = index;
+
+       end = index + nr;
+       if (end > size)
+               return end;
+       i = find_next_bit(map, end, index);
+       if (i < end) {
+               area_bits = i - area_off;
+               /* remember largest unused area with best alignment */
+               if (area_bits > *largest_bits ||
+                   (area_bits == *largest_bits && *largest_off &&
+                    (!area_off || __ffs(area_off) > __ffs(*largest_off)))) {
+                       *largest_off = area_off;
+                       *largest_bits = area_bits;
+               }
+
+               start = i + 1;
+               goto again;
+       }
+       return index;
+}
+
 /**
  * pcpu_alloc_area - allocates an area from a pcpu_chunk
  * @chunk: chunk of interest
@@ -978,7 +1187,9 @@ static int pcpu_find_block_fit(struct pcpu_chunk *chunk, int alloc_bits,
 static int pcpu_alloc_area(struct pcpu_chunk *chunk, int alloc_bits,
                           size_t align, int start)
 {
+       struct pcpu_block_md *chunk_md = &chunk->chunk_md;
        size_t align_mask = (align) ? (align - 1) : 0;
+       unsigned long area_off = 0, area_bits = 0;
        int bit_off, end, oslot;
 
        lockdep_assert_held(&pcpu_lock);
@@ -988,12 +1199,16 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int alloc_bits,
        /*
         * Search to find a fit.
         */
-       end = start + alloc_bits + PCPU_BITMAP_BLOCK_BITS;
-       bit_off = bitmap_find_next_zero_area(chunk->alloc_map, end, start,
-                                            alloc_bits, align_mask);
+       end = min_t(int, start + alloc_bits + PCPU_BITMAP_BLOCK_BITS,
+                   pcpu_chunk_map_bits(chunk));
+       bit_off = pcpu_find_zero_area(chunk->alloc_map, end, start, alloc_bits,
+                                     align_mask, &area_off, &area_bits);
        if (bit_off >= end)
                return -1;
 
+       if (area_bits)
+               pcpu_block_update_scan(chunk, area_off, area_bits);
+
        /* update alloc map */
        bitmap_set(chunk->alloc_map, bit_off, alloc_bits);
 
@@ -1005,8 +1220,8 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int alloc_bits,
        chunk->free_bytes -= alloc_bits * PCPU_MIN_ALLOC_SIZE;
 
        /* update first free bit */
-       if (bit_off == chunk->first_bit)
-               chunk->first_bit = find_next_zero_bit(
+       if (bit_off == chunk_md->first_free)
+               chunk_md->first_free = find_next_zero_bit(
                                        chunk->alloc_map,
                                        pcpu_chunk_map_bits(chunk),
                                        bit_off + alloc_bits);
@@ -1028,6 +1243,7 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int alloc_bits,
  */
 static void pcpu_free_area(struct pcpu_chunk *chunk, int off)
 {
+       struct pcpu_block_md *chunk_md = &chunk->chunk_md;
        int bit_off, bits, end, oslot;
 
        lockdep_assert_held(&pcpu_lock);
@@ -1047,24 +1263,34 @@ static void pcpu_free_area(struct pcpu_chunk *chunk, int off)
        chunk->free_bytes += bits * PCPU_MIN_ALLOC_SIZE;
 
        /* update first free bit */
-       chunk->first_bit = min(chunk->first_bit, bit_off);
+       chunk_md->first_free = min(chunk_md->first_free, bit_off);
 
        pcpu_block_update_hint_free(chunk, bit_off, bits);
 
        pcpu_chunk_relocate(chunk, oslot);
 }
 
+static void pcpu_init_md_block(struct pcpu_block_md *block, int nr_bits)
+{
+       block->scan_hint = 0;
+       block->contig_hint = nr_bits;
+       block->left_free = nr_bits;
+       block->right_free = nr_bits;
+       block->first_free = 0;
+       block->nr_bits = nr_bits;
+}
+
 static void pcpu_init_md_blocks(struct pcpu_chunk *chunk)
 {
        struct pcpu_block_md *md_block;
 
+       /* init the chunk's block */
+       pcpu_init_md_block(&chunk->chunk_md, pcpu_chunk_map_bits(chunk));
+
        for (md_block = chunk->md_blocks;
             md_block != chunk->md_blocks + pcpu_chunk_nr_blocks(chunk);
-            md_block++) {
-               md_block->contig_hint = PCPU_BITMAP_BLOCK_BITS;
-               md_block->left_free = PCPU_BITMAP_BLOCK_BITS;
-               md_block->right_free = PCPU_BITMAP_BLOCK_BITS;
-       }
+            md_block++)
+               pcpu_init_md_block(md_block, PCPU_BITMAP_BLOCK_BITS);
 }
 
 /**
@@ -1143,11 +1369,8 @@ static struct pcpu_chunk * __init pcpu_alloc_first_chunk(unsigned long tmp_addr,
        chunk->immutable = true;
        bitmap_fill(chunk->populated, chunk->nr_pages);
        chunk->nr_populated = chunk->nr_pages;
-       chunk->nr_empty_pop_pages =
-               pcpu_cnt_pop_pages(chunk, start_offset / PCPU_MIN_ALLOC_SIZE,
-                                  map_size / PCPU_MIN_ALLOC_SIZE);
+       chunk->nr_empty_pop_pages = chunk->nr_pages;
 
-       chunk->contig_bits = map_size / PCPU_MIN_ALLOC_SIZE;
        chunk->free_bytes = map_size;
 
        if (chunk->start_offset) {
@@ -1157,7 +1380,7 @@ static struct pcpu_chunk * __init pcpu_alloc_first_chunk(unsigned long tmp_addr,
                set_bit(0, chunk->bound_map);
                set_bit(offset_bits, chunk->bound_map);
 
-               chunk->first_bit = offset_bits;
+               chunk->chunk_md.first_free = offset_bits;
 
                pcpu_block_update_hint_alloc(chunk, 0, offset_bits);
        }
@@ -1210,7 +1433,6 @@ static struct pcpu_chunk *pcpu_alloc_chunk(gfp_t gfp)
        pcpu_init_md_blocks(chunk);
 
        /* init metadata */
-       chunk->contig_bits = region_bits;
        chunk->free_bytes = chunk->nr_pages * PAGE_SIZE;
 
        return chunk;
@@ -1240,7 +1462,6 @@ static void pcpu_free_chunk(struct pcpu_chunk *chunk)
  * @chunk: pcpu_chunk which got populated
  * @page_start: the start page
  * @page_end: the end page
- * @for_alloc: if this is to populate for allocation
  *
  * Pages in [@page_start,@page_end) have been populated to @chunk.  Update
  * the bookkeeping information accordingly.  Must be called after each
@@ -1250,7 +1471,7 @@ static void pcpu_free_chunk(struct pcpu_chunk *chunk)
  * is to serve an allocation in that area.
  */
 static void pcpu_chunk_populated(struct pcpu_chunk *chunk, int page_start,
-                                int page_end, bool for_alloc)
+                                int page_end)
 {
        int nr = page_end - page_start;
 
@@ -1260,10 +1481,7 @@ static void pcpu_chunk_populated(struct pcpu_chunk *chunk, int page_start,
        chunk->nr_populated += nr;
        pcpu_nr_populated += nr;
 
-       if (!for_alloc) {
-               chunk->nr_empty_pop_pages += nr;
-               pcpu_nr_empty_pop_pages += nr;
-       }
+       pcpu_update_empty_pages(chunk, nr);
 }
 
 /**
@@ -1285,9 +1503,9 @@ static void pcpu_chunk_depopulated(struct pcpu_chunk *chunk,
 
        bitmap_clear(chunk->populated, page_start, nr);
        chunk->nr_populated -= nr;
-       chunk->nr_empty_pop_pages -= nr;
-       pcpu_nr_empty_pop_pages -= nr;
        pcpu_nr_populated -= nr;
+
+       pcpu_update_empty_pages(chunk, -nr);
 }
 
 /*
@@ -1374,7 +1592,7 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
        bool is_atomic = (gfp & GFP_KERNEL) != GFP_KERNEL;
        bool do_warn = !(gfp & __GFP_NOWARN);
        static int warn_limit = 10;
-       struct pcpu_chunk *chunk;
+       struct pcpu_chunk *chunk, *next;
        const char *err;
        int slot, off, cpu, ret;
        unsigned long flags;
@@ -1436,11 +1654,14 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
 restart:
        /* search through normal chunks */
        for (slot = pcpu_size_to_slot(size); slot < pcpu_nr_slots; slot++) {
-               list_for_each_entry(chunk, &pcpu_slot[slot], list) {
+               list_for_each_entry_safe(chunk, next, &pcpu_slot[slot], list) {
                        off = pcpu_find_block_fit(chunk, bits, bit_align,
                                                  is_atomic);
-                       if (off < 0)
+                       if (off < 0) {
+                               if (slot < PCPU_SLOT_FAIL_THRESHOLD)
+                                       pcpu_chunk_move(chunk, 0);
                                continue;
+                       }
 
                        off = pcpu_alloc_area(chunk, bits, bit_align, off);
                        if (off >= 0)
@@ -1499,7 +1720,7 @@ area_found:
                                err = "failed to populate";
                                goto fail_unlock;
                        }
-                       pcpu_chunk_populated(chunk, rs, re, true);
+                       pcpu_chunk_populated(chunk, rs, re);
                        spin_unlock_irqrestore(&pcpu_lock, flags);
                }
 
@@ -1698,7 +1919,7 @@ retry_pop:
                        if (!ret) {
                                nr_to_pop -= nr;
                                spin_lock_irq(&pcpu_lock);
-                               pcpu_chunk_populated(chunk, rs, rs + nr, false);
+                               pcpu_chunk_populated(chunk, rs, rs + nr);
                                spin_unlock_irq(&pcpu_lock);
                        } else {
                                nr_to_pop = 0;
@@ -1738,6 +1959,7 @@ void free_percpu(void __percpu *ptr)
        struct pcpu_chunk *chunk;
        unsigned long flags;
        int off;
+       bool need_balance = false;
 
        if (!ptr)
                return;
@@ -1759,7 +1981,7 @@ void free_percpu(void __percpu *ptr)
 
                list_for_each_entry(pos, &pcpu_slot[pcpu_nr_slots - 1], list)
                        if (pos != chunk) {
-                               pcpu_schedule_balance_work();
+                               need_balance = true;
                                break;
                        }
        }
@@ -1767,6 +1989,9 @@ void free_percpu(void __percpu *ptr)
        trace_percpu_free_percpu(chunk->base_addr, off, ptr);
 
        spin_unlock_irqrestore(&pcpu_lock, flags);
+
+       if (need_balance)
+               pcpu_schedule_balance_work();
 }
 EXPORT_SYMBOL_GPL(free_percpu);
 
index b30c7c71d1d92fe9754ace7951be370f3130d93b..e5dfe2ae6b0d5dfc4a0b38c58c8e2c762b0b7696 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -850,7 +850,7 @@ int page_referenced(struct page *page,
        };
 
        *vm_flags = 0;
-       if (!page_mapped(page))
+       if (!pra.mapcount)
                return 0;
 
        if (!page_rmapping(page))
@@ -896,7 +896,8 @@ static bool page_mkclean_one(struct page *page, struct vm_area_struct *vma,
         * We have to assume the worse case ie pmd for invalidation. Note that
         * the page can not be free from this function.
         */
-       mmu_notifier_range_init(&range, vma->vm_mm, address,
+       mmu_notifier_range_init(&range, MMU_NOTIFY_PROTECTION_PAGE,
+                               0, vma, vma->vm_mm, address,
                                min(vma->vm_end, address +
                                    (PAGE_SIZE << compound_order(page))));
        mmu_notifier_invalidate_range_start(&range);
@@ -928,7 +929,7 @@ static bool page_mkclean_one(struct page *page, struct vm_area_struct *vma,
                                continue;
 
                        flush_cache_page(vma, address, page_to_pfn(page));
-                       entry = pmdp_huge_clear_flush(vma, address, pmd);
+                       entry = pmdp_invalidate(vma, address, pmd);
                        entry = pmd_wrprotect(entry);
                        entry = pmd_mkclean(entry);
                        set_pmd_at(vma->vm_mm, address, pmd, entry);
@@ -1371,7 +1372,8 @@ static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
         * Note that the page can not be free in this function as call of
         * try_to_unmap() must hold a reference on the page.
         */
-       mmu_notifier_range_init(&range, vma->vm_mm, address,
+       mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, vma->vm_mm,
+                               address,
                                min(vma->vm_end, address +
                                    (PAGE_SIZE << compound_order(page))));
        if (PageHuge(page)) {
index f4dce9c8670dc2fff58c8ea6e41445c5b7a4269a..1bb3b8dc8bb2113a8232153d3ba9fc5e8c453471 100644 (file)
@@ -614,7 +614,7 @@ static int shmem_add_to_page_cache(struct page *page,
                if (xas_error(&xas))
                        goto unlock;
 next:
-               xas_store(&xas, page + i);
+               xas_store(&xas, page);
                if (++i < nr) {
                        xas_next(&xas);
                        goto next;
diff --git a/mm/shuffle.c b/mm/shuffle.c
new file mode 100644 (file)
index 0000000..3ce1248
--- /dev/null
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2018 Intel Corporation. All rights reserved.
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/mmzone.h>
+#include <linux/random.h>
+#include <linux/moduleparam.h>
+#include "internal.h"
+#include "shuffle.h"
+
+DEFINE_STATIC_KEY_FALSE(page_alloc_shuffle_key);
+static unsigned long shuffle_state __ro_after_init;
+
+/*
+ * Depending on the architecture, module parameter parsing may run
+ * before, or after the cache detection. SHUFFLE_FORCE_DISABLE prevents,
+ * or reverts the enabling of the shuffle implementation. SHUFFLE_ENABLE
+ * attempts to turn on the implementation, but aborts if it finds
+ * SHUFFLE_FORCE_DISABLE already set.
+ */
+__meminit void page_alloc_shuffle(enum mm_shuffle_ctl ctl)
+{
+       if (ctl == SHUFFLE_FORCE_DISABLE)
+               set_bit(SHUFFLE_FORCE_DISABLE, &shuffle_state);
+
+       if (test_bit(SHUFFLE_FORCE_DISABLE, &shuffle_state)) {
+               if (test_and_clear_bit(SHUFFLE_ENABLE, &shuffle_state))
+                       static_branch_disable(&page_alloc_shuffle_key);
+       } else if (ctl == SHUFFLE_ENABLE
+                       && !test_and_set_bit(SHUFFLE_ENABLE, &shuffle_state))
+               static_branch_enable(&page_alloc_shuffle_key);
+}
+
+static bool shuffle_param;
+extern int shuffle_show(char *buffer, const struct kernel_param *kp)
+{
+       return sprintf(buffer, "%c\n", test_bit(SHUFFLE_ENABLE, &shuffle_state)
+                       ? 'Y' : 'N');
+}
+
+static __meminit int shuffle_store(const char *val,
+               const struct kernel_param *kp)
+{
+       int rc = param_set_bool(val, kp);
+
+       if (rc < 0)
+               return rc;
+       if (shuffle_param)
+               page_alloc_shuffle(SHUFFLE_ENABLE);
+       else
+               page_alloc_shuffle(SHUFFLE_FORCE_DISABLE);
+       return 0;
+}
+module_param_call(shuffle, shuffle_store, shuffle_show, &shuffle_param, 0400);
+
+/*
+ * For two pages to be swapped in the shuffle, they must be free (on a
+ * 'free_area' lru), have the same order, and have the same migratetype.
+ */
+static struct page * __meminit shuffle_valid_page(unsigned long pfn, int order)
+{
+       struct page *page;
+
+       /*
+        * Given we're dealing with randomly selected pfns in a zone we
+        * need to ask questions like...
+        */
+
+       /* ...is the pfn even in the memmap? */
+       if (!pfn_valid_within(pfn))
+               return NULL;
+
+       /* ...is the pfn in a present section or a hole? */
+       if (!pfn_present(pfn))
+               return NULL;
+
+       /* ...is the page free and currently on a free_area list? */
+       page = pfn_to_page(pfn);
+       if (!PageBuddy(page))
+               return NULL;
+
+       /*
+        * ...is the page on the same list as the page we will
+        * shuffle it with?
+        */
+       if (page_order(page) != order)
+               return NULL;
+
+       return page;
+}
+
+/*
+ * Fisher-Yates shuffle the freelist which prescribes iterating through an
+ * array, pfns in this case, and randomly swapping each entry with another in
+ * the span, end_pfn - start_pfn.
+ *
+ * To keep the implementation simple it does not attempt to correct for sources
+ * of bias in the distribution, like modulo bias or pseudo-random number
+ * generator bias. I.e. the expectation is that this shuffling raises the bar
+ * for attacks that exploit the predictability of page allocations, but need not
+ * be a perfect shuffle.
+ */
+#define SHUFFLE_RETRY 10
+void __meminit __shuffle_zone(struct zone *z)
+{
+       unsigned long i, flags;
+       unsigned long start_pfn = z->zone_start_pfn;
+       unsigned long end_pfn = zone_end_pfn(z);
+       const int order = SHUFFLE_ORDER;
+       const int order_pages = 1 << order;
+
+       spin_lock_irqsave(&z->lock, flags);
+       start_pfn = ALIGN(start_pfn, order_pages);
+       for (i = start_pfn; i < end_pfn; i += order_pages) {
+               unsigned long j;
+               int migratetype, retry;
+               struct page *page_i, *page_j;
+
+               /*
+                * We expect page_i, in the sub-range of a zone being added
+                * (@start_pfn to @end_pfn), to more likely be valid compared to
+                * page_j randomly selected in the span @zone_start_pfn to
+                * @spanned_pages.
+                */
+               page_i = shuffle_valid_page(i, order);
+               if (!page_i)
+                       continue;
+
+               for (retry = 0; retry < SHUFFLE_RETRY; retry++) {
+                       /*
+                        * Pick a random order aligned page in the zone span as
+                        * a swap target. If the selected pfn is a hole, retry
+                        * up to SHUFFLE_RETRY attempts find a random valid pfn
+                        * in the zone.
+                        */
+                       j = z->zone_start_pfn +
+                               ALIGN_DOWN(get_random_long() % z->spanned_pages,
+                                               order_pages);
+                       page_j = shuffle_valid_page(j, order);
+                       if (page_j && page_j != page_i)
+                               break;
+               }
+               if (retry >= SHUFFLE_RETRY) {
+                       pr_debug("%s: failed to swap %#lx\n", __func__, i);
+                       continue;
+               }
+
+               /*
+                * Each migratetype corresponds to its own list, make sure the
+                * types match otherwise we're moving pages to lists where they
+                * do not belong.
+                */
+               migratetype = get_pageblock_migratetype(page_i);
+               if (get_pageblock_migratetype(page_j) != migratetype) {
+                       pr_debug("%s: migratetype mismatch %#lx\n", __func__, i);
+                       continue;
+               }
+
+               list_swap(&page_i->lru, &page_j->lru);
+
+               pr_debug("%s: swap: %#lx -> %#lx\n", __func__, i, j);
+
+               /* take it easy on the zone lock */
+               if ((i % (100 * order_pages)) == 0) {
+                       spin_unlock_irqrestore(&z->lock, flags);
+                       cond_resched();
+                       spin_lock_irqsave(&z->lock, flags);
+               }
+       }
+       spin_unlock_irqrestore(&z->lock, flags);
+}
+
+/**
+ * shuffle_free_memory - reduce the predictability of the page allocator
+ * @pgdat: node page data
+ */
+void __meminit __shuffle_free_memory(pg_data_t *pgdat)
+{
+       struct zone *z;
+
+       for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++)
+               shuffle_zone(z);
+}
+
+void add_to_free_area_random(struct page *page, struct free_area *area,
+               int migratetype)
+{
+       static u64 rand;
+       static u8 rand_bits;
+
+       /*
+        * The lack of locking is deliberate. If 2 threads race to
+        * update the rand state it just adds to the entropy.
+        */
+       if (rand_bits == 0) {
+               rand_bits = 64;
+               rand = get_random_u64();
+       }
+
+       if (rand & 1)
+               add_to_free_area(page, area, migratetype);
+       else
+               add_to_free_area_tail(page, area, migratetype);
+       rand_bits--;
+       rand >>= 1;
+}
diff --git a/mm/shuffle.h b/mm/shuffle.h
new file mode 100644 (file)
index 0000000..777a257
--- /dev/null
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2018 Intel Corporation. All rights reserved.
+#ifndef _MM_SHUFFLE_H
+#define _MM_SHUFFLE_H
+#include <linux/jump_label.h>
+
+/*
+ * SHUFFLE_ENABLE is called from the command line enabling path, or by
+ * platform-firmware enabling that indicates the presence of a
+ * direct-mapped memory-side-cache. SHUFFLE_FORCE_DISABLE is called from
+ * the command line path and overrides any previous or future
+ * SHUFFLE_ENABLE.
+ */
+enum mm_shuffle_ctl {
+       SHUFFLE_ENABLE,
+       SHUFFLE_FORCE_DISABLE,
+};
+
+#define SHUFFLE_ORDER (MAX_ORDER-1)
+
+#ifdef CONFIG_SHUFFLE_PAGE_ALLOCATOR
+DECLARE_STATIC_KEY_FALSE(page_alloc_shuffle_key);
+extern void page_alloc_shuffle(enum mm_shuffle_ctl ctl);
+extern void __shuffle_free_memory(pg_data_t *pgdat);
+static inline void shuffle_free_memory(pg_data_t *pgdat)
+{
+       if (!static_branch_unlikely(&page_alloc_shuffle_key))
+               return;
+       __shuffle_free_memory(pgdat);
+}
+
+extern void __shuffle_zone(struct zone *z);
+static inline void shuffle_zone(struct zone *z)
+{
+       if (!static_branch_unlikely(&page_alloc_shuffle_key))
+               return;
+       __shuffle_zone(z);
+}
+
+static inline bool is_shuffle_order(int order)
+{
+       if (!static_branch_unlikely(&page_alloc_shuffle_key))
+               return false;
+       return order >= SHUFFLE_ORDER;
+}
+#else
+static inline void shuffle_free_memory(pg_data_t *pgdat)
+{
+}
+
+static inline void shuffle_zone(struct zone *z)
+{
+}
+
+static inline void page_alloc_shuffle(enum mm_shuffle_ctl ctl)
+{
+}
+
+static inline bool is_shuffle_order(int order)
+{
+       return false;
+}
+#endif
+#endif /* _MM_SHUFFLE_H */
index 284ab737faee01f1aa3d3178fa123ff08f8f27bf..f7117ad9b3a34ddf3ce6cc12689eef6ebd155763 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -362,29 +362,6 @@ static void **dbg_userword(struct kmem_cache *cachep, void *objp)
 
 #endif
 
-#ifdef CONFIG_DEBUG_SLAB_LEAK
-
-static inline bool is_store_user_clean(struct kmem_cache *cachep)
-{
-       return atomic_read(&cachep->store_user_clean) == 1;
-}
-
-static inline void set_store_user_clean(struct kmem_cache *cachep)
-{
-       atomic_set(&cachep->store_user_clean, 1);
-}
-
-static inline void set_store_user_dirty(struct kmem_cache *cachep)
-{
-       if (is_store_user_clean(cachep))
-               atomic_set(&cachep->store_user_clean, 0);
-}
-
-#else
-static inline void set_store_user_dirty(struct kmem_cache *cachep) {}
-
-#endif
-
 /*
  * Do not go above this order unless 0 objects fit into the slab or
  * overridden on the command line.
@@ -990,10 +967,8 @@ static void cpuup_canceled(long cpu)
 
                /* cpu is dead; no one can alloc from it. */
                nc = per_cpu_ptr(cachep->cpu_cache, cpu);
-               if (nc) {
-                       free_block(cachep, nc->entry, nc->avail, node, &list);
-                       nc->avail = 0;
-               }
+               free_block(cachep, nc->entry, nc->avail, node, &list);
+               nc->avail = 0;
 
                if (!cpumask_empty(mask)) {
                        spin_unlock_irq(&n->list_lock);
@@ -1674,8 +1649,8 @@ static void slabs_destroy(struct kmem_cache *cachep, struct list_head *list)
 {
        struct page *page, *n;
 
-       list_for_each_entry_safe(page, n, list, lru) {
-               list_del(&page->lru);
+       list_for_each_entry_safe(page, n, list, slab_list) {
+               list_del(&page->slab_list);
                slab_destroy(cachep, page);
        }
 }
@@ -2231,8 +2206,8 @@ static int drain_freelist(struct kmem_cache *cache,
                        goto out;
                }
 
-               page = list_entry(p, struct page, lru);
-               list_del(&page->lru);
+               page = list_entry(p, struct page, slab_list);
+               list_del(&page->slab_list);
                n->free_slabs--;
                n->total_slabs--;
                /*
@@ -2554,11 +2529,6 @@ static void *slab_get_obj(struct kmem_cache *cachep, struct page *page)
        objp = index_to_obj(cachep, page, get_free_obj(page, page->active));
        page->active++;
 
-#if DEBUG
-       if (cachep->flags & SLAB_STORE_USER)
-               set_store_user_dirty(cachep);
-#endif
-
        return objp;
 }
 
@@ -2691,13 +2661,13 @@ static void cache_grow_end(struct kmem_cache *cachep, struct page *page)
        if (!page)
                return;
 
-       INIT_LIST_HEAD(&page->lru);
+       INIT_LIST_HEAD(&page->slab_list);
        n = get_node(cachep, page_to_nid(page));
 
        spin_lock(&n->list_lock);
        n->total_slabs++;
        if (!page->active) {
-               list_add_tail(&page->lru, &(n->slabs_free));
+               list_add_tail(&page->slab_list, &n->slabs_free);
                n->free_slabs++;
        } else
                fixup_slab_list(cachep, n, page, &list);
@@ -2764,10 +2734,8 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
                *dbg_redzone1(cachep, objp) = RED_INACTIVE;
                *dbg_redzone2(cachep, objp) = RED_INACTIVE;
        }
-       if (cachep->flags & SLAB_STORE_USER) {
-               set_store_user_dirty(cachep);
+       if (cachep->flags & SLAB_STORE_USER)
                *dbg_userword(cachep, objp) = (void *)caller;
-       }
 
        objnr = obj_to_index(cachep, page, objp);
 
@@ -2806,9 +2774,9 @@ static inline void fixup_slab_list(struct kmem_cache *cachep,
                                void **list)
 {
        /* move slabp to correct slabp list: */
-       list_del(&page->lru);
+       list_del(&page->slab_list);
        if (page->active == cachep->num) {
-               list_add(&page->lru, &n->slabs_full);
+               list_add(&page->slab_list, &n->slabs_full);
                if (OBJFREELIST_SLAB(cachep)) {
 #if DEBUG
                        /* Poisoning will be done without holding the lock */
@@ -2822,7 +2790,7 @@ static inline void fixup_slab_list(struct kmem_cache *cachep,
                        page->freelist = NULL;
                }
        } else
-               list_add(&page->lru, &n->slabs_partial);
+               list_add(&page->slab_list, &n->slabs_partial);
 }
 
 /* Try to find non-pfmemalloc slab if needed */
@@ -2845,20 +2813,20 @@ static noinline struct page *get_valid_first_slab(struct kmem_cache_node *n,
        }
 
        /* Move pfmemalloc slab to the end of list to speed up next search */
-       list_del(&page->lru);
+       list_del(&page->slab_list);
        if (!page->active) {
-               list_add_tail(&page->lru, &n->slabs_free);
+               list_add_tail(&page->slab_list, &n->slabs_free);
                n->free_slabs++;
        } else
-               list_add_tail(&page->lru, &n->slabs_partial);
+               list_add_tail(&page->slab_list, &n->slabs_partial);
 
-       list_for_each_entry(page, &n->slabs_partial, lru) {
+       list_for_each_entry(page, &n->slabs_partial, slab_list) {
                if (!PageSlabPfmemalloc(page))
                        return page;
        }
 
        n->free_touched = 1;
-       list_for_each_entry(page, &n->slabs_free, lru) {
+       list_for_each_entry(page, &n->slabs_free, slab_list) {
                if (!PageSlabPfmemalloc(page)) {
                        n->free_slabs--;
                        return page;
@@ -2873,11 +2841,12 @@ static struct page *get_first_slab(struct kmem_cache_node *n, bool pfmemalloc)
        struct page *page;
 
        assert_spin_locked(&n->list_lock);
-       page = list_first_entry_or_null(&n->slabs_partial, struct page, lru);
+       page = list_first_entry_or_null(&n->slabs_partial, struct page,
+                                       slab_list);
        if (!page) {
                n->free_touched = 1;
                page = list_first_entry_or_null(&n->slabs_free, struct page,
-                                               lru);
+                                               slab_list);
                if (page)
                        n->free_slabs--;
        }
@@ -3378,29 +3347,29 @@ static void free_block(struct kmem_cache *cachep, void **objpp,
                objp = objpp[i];
 
                page = virt_to_head_page(objp);
-               list_del(&page->lru);
+               list_del(&page->slab_list);
                check_spinlock_acquired_node(cachep, node);
                slab_put_obj(cachep, page, objp);
                STATS_DEC_ACTIVE(cachep);
 
                /* fixup slab chains */
                if (page->active == 0) {
-                       list_add(&page->lru, &n->slabs_free);
+                       list_add(&page->slab_list, &n->slabs_free);
                        n->free_slabs++;
                } else {
                        /* Unconditionally move a slab to the end of the
                         * partial list on free - maximum time for the
                         * other objects to be freed, too.
                         */
-                       list_add_tail(&page->lru, &n->slabs_partial);
+                       list_add_tail(&page->slab_list, &n->slabs_partial);
                }
        }
 
        while (n->free_objects > n->free_limit && !list_empty(&n->slabs_free)) {
                n->free_objects -= cachep->num;
 
-               page = list_last_entry(&n->slabs_free, struct page, lru);
-               list_move(&page->lru, list);
+               page = list_last_entry(&n->slabs_free, struct page, slab_list);
+               list_move(&page->slab_list, list);
                n->free_slabs--;
                n->total_slabs--;
        }
@@ -3438,7 +3407,7 @@ free_done:
                int i = 0;
                struct page *page;
 
-               list_for_each_entry(page, &n->slabs_free, lru) {
+               list_for_each_entry(page, &n->slabs_free, slab_list) {
                        BUG_ON(page->active);
 
                        i++;
@@ -4185,196 +4154,6 @@ ssize_t slabinfo_write(struct file *file, const char __user *buffer,
        return res;
 }
 
-#ifdef CONFIG_DEBUG_SLAB_LEAK
-
-static inline int add_caller(unsigned long *n, unsigned long v)
-{
-       unsigned long *p;
-       int l;
-       if (!v)
-               return 1;
-       l = n[1];
-       p = n + 2;
-       while (l) {
-               int i = l/2;
-               unsigned long *q = p + 2 * i;
-               if (*q == v) {
-                       q[1]++;
-                       return 1;
-               }
-               if (*q > v) {
-                       l = i;
-               } else {
-                       p = q + 2;
-                       l -= i + 1;
-               }
-       }
-       if (++n[1] == n[0])
-               return 0;
-       memmove(p + 2, p, n[1] * 2 * sizeof(unsigned long) - ((void *)p - (void *)n));
-       p[0] = v;
-       p[1] = 1;
-       return 1;
-}
-
-static void handle_slab(unsigned long *n, struct kmem_cache *c,
-                                               struct page *page)
-{
-       void *p;
-       int i, j;
-       unsigned long v;
-
-       if (n[0] == n[1])
-               return;
-       for (i = 0, p = page->s_mem; i < c->num; i++, p += c->size) {
-               bool active = true;
-
-               for (j = page->active; j < c->num; j++) {
-                       if (get_free_obj(page, j) == i) {
-                               active = false;
-                               break;
-                       }
-               }
-
-               if (!active)
-                       continue;
-
-               /*
-                * probe_kernel_read() is used for DEBUG_PAGEALLOC. page table
-                * mapping is established when actual object allocation and
-                * we could mistakenly access the unmapped object in the cpu
-                * cache.
-                */
-               if (probe_kernel_read(&v, dbg_userword(c, p), sizeof(v)))
-                       continue;
-
-               if (!add_caller(n, v))
-                       return;
-       }
-}
-
-static void show_symbol(struct seq_file *m, unsigned long address)
-{
-#ifdef CONFIG_KALLSYMS
-       unsigned long offset, size;
-       char modname[MODULE_NAME_LEN], name[KSYM_NAME_LEN];
-
-       if (lookup_symbol_attrs(address, &size, &offset, modname, name) == 0) {
-               seq_printf(m, "%s+%#lx/%#lx", name, offset, size);
-               if (modname[0])
-                       seq_printf(m, " [%s]", modname);
-               return;
-       }
-#endif
-       seq_printf(m, "%px", (void *)address);
-}
-
-static int leaks_show(struct seq_file *m, void *p)
-{
-       struct kmem_cache *cachep = list_entry(p, struct kmem_cache,
-                                              root_caches_node);
-       struct page *page;
-       struct kmem_cache_node *n;
-       const char *name;
-       unsigned long *x = m->private;
-       int node;
-       int i;
-
-       if (!(cachep->flags & SLAB_STORE_USER))
-               return 0;
-       if (!(cachep->flags & SLAB_RED_ZONE))
-               return 0;
-
-       /*
-        * Set store_user_clean and start to grab stored user information
-        * for all objects on this cache. If some alloc/free requests comes
-        * during the processing, information would be wrong so restart
-        * whole processing.
-        */
-       do {
-               set_store_user_clean(cachep);
-               drain_cpu_caches(cachep);
-
-               x[1] = 0;
-
-               for_each_kmem_cache_node(cachep, node, n) {
-
-                       check_irq_on();
-                       spin_lock_irq(&n->list_lock);
-
-                       list_for_each_entry(page, &n->slabs_full, lru)
-                               handle_slab(x, cachep, page);
-                       list_for_each_entry(page, &n->slabs_partial, lru)
-                               handle_slab(x, cachep, page);
-                       spin_unlock_irq(&n->list_lock);
-               }
-       } while (!is_store_user_clean(cachep));
-
-       name = cachep->name;
-       if (x[0] == x[1]) {
-               /* Increase the buffer size */
-               mutex_unlock(&slab_mutex);
-               m->private = kcalloc(x[0] * 4, sizeof(unsigned long),
-                                    GFP_KERNEL);
-               if (!m->private) {
-                       /* Too bad, we are really out */
-                       m->private = x;
-                       mutex_lock(&slab_mutex);
-                       return -ENOMEM;
-               }
-               *(unsigned long *)m->private = x[0] * 2;
-               kfree(x);
-               mutex_lock(&slab_mutex);
-               /* Now make sure this entry will be retried */
-               m->count = m->size;
-               return 0;
-       }
-       for (i = 0; i < x[1]; i++) {
-               seq_printf(m, "%s: %lu ", name, x[2*i+3]);
-               show_symbol(m, x[2*i+2]);
-               seq_putc(m, '\n');
-       }
-
-       return 0;
-}
-
-static const struct seq_operations slabstats_op = {
-       .start = slab_start,
-       .next = slab_next,
-       .stop = slab_stop,
-       .show = leaks_show,
-};
-
-static int slabstats_open(struct inode *inode, struct file *file)
-{
-       unsigned long *n;
-
-       n = __seq_open_private(file, &slabstats_op, PAGE_SIZE);
-       if (!n)
-               return -ENOMEM;
-
-       *n = PAGE_SIZE / (2 * sizeof(unsigned long));
-
-       return 0;
-}
-
-static const struct file_operations proc_slabstats_operations = {
-       .open           = slabstats_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release_private,
-};
-#endif
-
-static int __init slab_proc_init(void)
-{
-#ifdef CONFIG_DEBUG_SLAB_LEAK
-       proc_create("slab_allocators", 0, NULL, &proc_slabstats_operations);
-#endif
-       return 0;
-}
-module_init(slab_proc_init);
-
 #ifdef CONFIG_HARDENED_USERCOPY
 /*
  * Rejects incorrectly sized objects and objects that are to be copied
index 307c2c9feb441d99789f031b9bdc6eaf46234618..84aefd9b91ee302749a9b480e6164f53bfaeda6b 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -112,13 +112,13 @@ static inline int slob_page_free(struct page *sp)
 
 static void set_slob_page_free(struct page *sp, struct list_head *list)
 {
-       list_add(&sp->lru, list);
+       list_add(&sp->slab_list, list);
        __SetPageSlobFree(sp);
 }
 
 static inline void clear_slob_page_free(struct page *sp)
 {
-       list_del(&sp->lru);
+       list_del(&sp->slab_list);
        __ClearPageSlobFree(sp);
 }
 
@@ -213,13 +213,26 @@ static void slob_free_pages(void *b, int order)
 }
 
 /*
- * Allocate a slob block within a given slob_page sp.
+ * slob_page_alloc() - Allocate a slob block within a given slob_page sp.
+ * @sp: Page to look in.
+ * @size: Size of the allocation.
+ * @align: Allocation alignment.
+ * @page_removed_from_list: Return parameter.
+ *
+ * Tries to find a chunk of memory at least @size bytes big within @page.
+ *
+ * Return: Pointer to memory if allocated, %NULL otherwise.  If the
+ *         allocation fills up @page then the page is removed from the
+ *         freelist, in this case @page_removed_from_list will be set to
+ *         true (set to false otherwise).
  */
-static void *slob_page_alloc(struct page *sp, size_t size, int align)
+static void *slob_page_alloc(struct page *sp, size_t size, int align,
+                            bool *page_removed_from_list)
 {
        slob_t *prev, *cur, *aligned = NULL;
        int delta = 0, units = SLOB_UNITS(size);
 
+       *page_removed_from_list = false;
        for (prev = NULL, cur = sp->freelist; ; prev = cur, cur = slob_next(cur)) {
                slobidx_t avail = slob_units(cur);
 
@@ -254,8 +267,10 @@ static void *slob_page_alloc(struct page *sp, size_t size, int align)
                        }
 
                        sp->units -= units;
-                       if (!sp->units)
+                       if (!sp->units) {
                                clear_slob_page_free(sp);
+                               *page_removed_from_list = true;
+                       }
                        return cur;
                }
                if (slob_last(cur))
@@ -269,10 +284,10 @@ static void *slob_page_alloc(struct page *sp, size_t size, int align)
 static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
 {
        struct page *sp;
-       struct list_head *prev;
        struct list_head *slob_list;
        slob_t *b = NULL;
        unsigned long flags;
+       bool _unused;
 
        if (size < SLOB_BREAK1)
                slob_list = &free_slob_small;
@@ -283,7 +298,8 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
 
        spin_lock_irqsave(&slob_lock, flags);
        /* Iterate through each partially free page, try to find room */
-       list_for_each_entry(sp, slob_list, lru) {
+       list_for_each_entry(sp, slob_list, slab_list) {
+               bool page_removed_from_list = false;
 #ifdef CONFIG_NUMA
                /*
                 * If there's a node specification, search for a partial
@@ -296,18 +312,25 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
                if (sp->units < SLOB_UNITS(size))
                        continue;
 
-               /* Attempt to alloc */
-               prev = sp->lru.prev;
-               b = slob_page_alloc(sp, size, align);
+               b = slob_page_alloc(sp, size, align, &page_removed_from_list);
                if (!b)
                        continue;
 
-               /* Improve fragment distribution and reduce our average
-                * search time by starting our next search here. (see
-                * Knuth vol 1, sec 2.5, pg 449) */
-               if (prev != slob_list->prev &&
-                               slob_list->next != prev->next)
-                       list_move_tail(slob_list, prev->next);
+               /*
+                * If slob_page_alloc() removed sp from the list then we
+                * cannot call list functions on sp.  If so allocation
+                * did not fragment the page anyway so optimisation is
+                * unnecessary.
+                */
+               if (!page_removed_from_list) {
+                       /*
+                        * Improve fragment distribution and reduce our average
+                        * search time by starting our next search here. (see
+                        * Knuth vol 1, sec 2.5, pg 449)
+                        */
+                       if (!list_is_first(&sp->slab_list, slob_list))
+                               list_rotate_to_front(&sp->slab_list, slob_list);
+               }
                break;
        }
        spin_unlock_irqrestore(&slob_lock, flags);
@@ -323,10 +346,10 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
                spin_lock_irqsave(&slob_lock, flags);
                sp->units = SLOB_UNITS(PAGE_SIZE);
                sp->freelist = b;
-               INIT_LIST_HEAD(&sp->lru);
+               INIT_LIST_HEAD(&sp->slab_list);
                set_slob(b, SLOB_UNITS(PAGE_SIZE), b + SLOB_UNITS(PAGE_SIZE));
                set_slob_page_free(sp, slob_list);
-               b = slob_page_alloc(sp, size, align);
+               b = slob_page_alloc(sp, size, align, &_unused);
                BUG_ON(!b);
                spin_unlock_irqrestore(&slob_lock, flags);
        }
index 6b28cd2b5a58c9f09f81beae1972d9a229ec65e2..cd04dbd2b5d0533c1ecd3919f4b067ee9047e693 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
  *     D. page->frozen         -> frozen state
  *
  *   If a slab is frozen then it is exempt from list management. It is not
- *   on any list. The processor that froze the slab is the one who can
- *   perform list operations on the page. Other processors may put objects
- *   onto the freelist but the processor that froze the slab is the only
- *   one that can retrieve the objects from the page's freelist.
+ *   on any list except per cpu partial list. The processor that froze the
+ *   slab is the one who can perform list operations on the page. Other
+ *   processors may put objects onto the freelist but the processor that
+ *   froze the slab is the only one that can retrieve the objects from the
+ *   page's freelist.
  *
  *   The list_lock protects the partial and full list on each node and
  *   the partial slab counter. If taken then no new slabs may be added or
@@ -1014,7 +1015,7 @@ static void add_full(struct kmem_cache *s,
                return;
 
        lockdep_assert_held(&n->list_lock);
-       list_add(&page->lru, &n->full);
+       list_add(&page->slab_list, &n->full);
 }
 
 static void remove_full(struct kmem_cache *s, struct kmem_cache_node *n, struct page *page)
@@ -1023,7 +1024,7 @@ static void remove_full(struct kmem_cache *s, struct kmem_cache_node *n, struct
                return;
 
        lockdep_assert_held(&n->list_lock);
-       list_del(&page->lru);
+       list_del(&page->slab_list);
 }
 
 /* Tracking of the number of slabs for debugging purposes */
@@ -1764,9 +1765,9 @@ __add_partial(struct kmem_cache_node *n, struct page *page, int tail)
 {
        n->nr_partial++;
        if (tail == DEACTIVATE_TO_TAIL)
-               list_add_tail(&page->lru, &n->partial);
+               list_add_tail(&page->slab_list, &n->partial);
        else
-               list_add(&page->lru, &n->partial);
+               list_add(&page->slab_list, &n->partial);
 }
 
 static inline void add_partial(struct kmem_cache_node *n,
@@ -1780,7 +1781,7 @@ static inline void remove_partial(struct kmem_cache_node *n,
                                        struct page *page)
 {
        lockdep_assert_held(&n->list_lock);
-       list_del(&page->lru);
+       list_del(&page->slab_list);
        n->nr_partial--;
 }
 
@@ -1854,7 +1855,7 @@ static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
                return NULL;
 
        spin_lock(&n->list_lock);
-       list_for_each_entry_safe(page, page2, &n->partial, lru) {
+       list_for_each_entry_safe(page, page2, &n->partial, slab_list) {
                void *t;
 
                if (!pfmemalloc_match(page, flags))
@@ -1942,7 +1943,7 @@ static void *get_any_partial(struct kmem_cache *s, gfp_t flags,
                        }
                }
        } while (read_mems_allowed_retry(cpuset_mems_cookie));
-#endif
+#endif /* CONFIG_NUMA */
        return NULL;
 }
 
@@ -2240,7 +2241,7 @@ static void unfreeze_partials(struct kmem_cache *s,
                discard_slab(s, page);
                stat(s, FREE_SLAB);
        }
-#endif
+#endif /* CONFIG_SLUB_CPU_PARTIAL */
 }
 
 /*
@@ -2299,7 +2300,7 @@ static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
                local_irq_restore(flags);
        }
        preempt_enable();
-#endif
+#endif /* CONFIG_SLUB_CPU_PARTIAL */
 }
 
 static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
@@ -2398,7 +2399,7 @@ static unsigned long count_partial(struct kmem_cache_node *n,
        struct page *page;
 
        spin_lock_irqsave(&n->list_lock, flags);
-       list_for_each_entry(page, &n->partial, lru)
+       list_for_each_entry(page, &n->partial, slab_list)
                x += get_count(page);
        spin_unlock_irqrestore(&n->list_lock, flags);
        return x;
@@ -2804,7 +2805,7 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *s,
 }
 EXPORT_SYMBOL(kmem_cache_alloc_node_trace);
 #endif
-#endif
+#endif /* CONFIG_NUMA */
 
 /*
  * Slow path handling. This may still be called frequently since objects
@@ -2903,8 +2904,7 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
         * then add it.
         */
        if (!kmem_cache_has_cpu_partial(s) && unlikely(!prior)) {
-               if (kmem_cache_debug(s))
-                       remove_full(s, n, page);
+               remove_full(s, n, page);
                add_partial(n, page, DEACTIVATE_TO_TAIL);
                stat(s, FREE_ADD_PARTIAL);
        }
@@ -3696,10 +3696,10 @@ static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n)
 
        BUG_ON(irqs_disabled());
        spin_lock_irq(&n->list_lock);
-       list_for_each_entry_safe(page, h, &n->partial, lru) {
+       list_for_each_entry_safe(page, h, &n->partial, slab_list) {
                if (!page->inuse) {
                        remove_partial(n, page);
-                       list_add(&page->lru, &discard);
+                       list_add(&page->slab_list, &discard);
                } else {
                        list_slab_objects(s, page,
                        "Objects remaining in %s on __kmem_cache_shutdown()");
@@ -3707,7 +3707,7 @@ static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n)
        }
        spin_unlock_irq(&n->list_lock);
 
-       list_for_each_entry_safe(page, h, &discard, lru)
+       list_for_each_entry_safe(page, h, &discard, slab_list)
                discard_slab(s, page);
 }
 
@@ -3839,7 +3839,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
        return ret;
 }
 EXPORT_SYMBOL(__kmalloc_node);
-#endif
+#endif /* CONFIG_NUMA */
 
 #ifdef CONFIG_HARDENED_USERCOPY
 /*
@@ -3987,7 +3987,7 @@ int __kmem_cache_shrink(struct kmem_cache *s)
                 * Note that concurrent frees may occur while we hold the
                 * list_lock. page->inuse here is the upper limit.
                 */
-               list_for_each_entry_safe(page, t, &n->partial, lru) {
+               list_for_each_entry_safe(page, t, &n->partial, slab_list) {
                        int free = page->objects - page->inuse;
 
                        /* Do not reread page->inuse */
@@ -3997,10 +3997,10 @@ int __kmem_cache_shrink(struct kmem_cache *s)
                        BUG_ON(free <= 0);
 
                        if (free == page->objects) {
-                               list_move(&page->lru, &discard);
+                               list_move(&page->slab_list, &discard);
                                n->nr_partial--;
                        } else if (free <= SHRINK_PROMOTE_MAX)
-                               list_move(&page->lru, promote + free - 1);
+                               list_move(&page->slab_list, promote + free - 1);
                }
 
                /*
@@ -4013,7 +4013,7 @@ int __kmem_cache_shrink(struct kmem_cache *s)
                spin_unlock_irqrestore(&n->list_lock, flags);
 
                /* Release empty slabs */
-               list_for_each_entry_safe(page, t, &discard, lru)
+               list_for_each_entry_safe(page, t, &discard, slab_list)
                        discard_slab(s, page);
 
                if (slabs_node(s, node))
@@ -4057,7 +4057,7 @@ void __kmemcg_cache_deactivate(struct kmem_cache *s)
         */
        slab_deactivate_memcg_cache_rcu_sched(s, kmemcg_cache_deact_after_rcu);
 }
-#endif
+#endif /* CONFIG_MEMCG */
 
 static int slab_mem_going_offline_callback(void *arg)
 {
@@ -4205,11 +4205,11 @@ static struct kmem_cache * __init bootstrap(struct kmem_cache *static_cache)
        for_each_kmem_cache_node(s, node, n) {
                struct page *p;
 
-               list_for_each_entry(p, &n->partial, lru)
+               list_for_each_entry(p, &n->partial, slab_list)
                        p->slab_cache = s;
 
 #ifdef CONFIG_SLUB_DEBUG
-               list_for_each_entry(p, &n->full, lru)
+               list_for_each_entry(p, &n->full, slab_list)
                        p->slab_cache = s;
 #endif
        }
@@ -4426,7 +4426,7 @@ static int validate_slab_node(struct kmem_cache *s,
 
        spin_lock_irqsave(&n->list_lock, flags);
 
-       list_for_each_entry(page, &n->partial, lru) {
+       list_for_each_entry(page, &n->partial, slab_list) {
                validate_slab_slab(s, page, map);
                count++;
        }
@@ -4437,7 +4437,7 @@ static int validate_slab_node(struct kmem_cache *s,
        if (!(s->flags & SLAB_STORE_USER))
                goto out;
 
-       list_for_each_entry(page, &n->full, lru) {
+       list_for_each_entry(page, &n->full, slab_list) {
                validate_slab_slab(s, page, map);
                count++;
        }
@@ -4633,9 +4633,9 @@ static int list_locations(struct kmem_cache *s, char *buf,
                        continue;
 
                spin_lock_irqsave(&n->list_lock, flags);
-               list_for_each_entry(page, &n->partial, lru)
+               list_for_each_entry(page, &n->partial, slab_list)
                        process_slab(&t, s, page, alloc, map);
-               list_for_each_entry(page, &n->full, lru)
+               list_for_each_entry(page, &n->full, slab_list)
                        process_slab(&t, s, page, alloc, map);
                spin_unlock_irqrestore(&n->list_lock, flags);
        }
@@ -4690,7 +4690,7 @@ static int list_locations(struct kmem_cache *s, char *buf,
                len += sprintf(buf, "No data\n");
        return len;
 }
-#endif
+#endif /* CONFIG_SLUB_DEBUG */
 
 #ifdef SLUB_RESILIENCY_TEST
 static void __init resiliency_test(void)
@@ -4750,7 +4750,7 @@ static void __init resiliency_test(void)
 #ifdef CONFIG_SYSFS
 static void resiliency_test(void) {};
 #endif
-#endif
+#endif /* SLUB_RESILIENCY_TEST */
 
 #ifdef CONFIG_SYSFS
 enum slab_stat_type {
@@ -5407,7 +5407,7 @@ STAT_ATTR(CPU_PARTIAL_ALLOC, cpu_partial_alloc);
 STAT_ATTR(CPU_PARTIAL_FREE, cpu_partial_free);
 STAT_ATTR(CPU_PARTIAL_NODE, cpu_partial_node);
 STAT_ATTR(CPU_PARTIAL_DRAIN, cpu_partial_drain);
-#endif
+#endif /* CONFIG_SLUB_STATS */
 
 static struct attribute *slab_attrs[] = {
        &slab_size_attr.attr,
@@ -5608,7 +5608,7 @@ static void memcg_propagate_slab_attrs(struct kmem_cache *s)
 
        if (buffer)
                free_page((unsigned long)buffer);
-#endif
+#endif /* CONFIG_MEMCG */
 }
 
 static void kmem_cache_release(struct kobject *k)
index 56e057c432f9663439c4cfd38f8cad8f2e6e2c3d..fd13166949b52c81e725fdda3b413516aa251fe3 100644 (file)
@@ -684,10 +684,18 @@ static void free_map_bootmem(struct page *memmap)
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
 
-/*
- * returns the number of sections whose mem_maps were properly
- * set.  If this is <=0, then that means that the passed-in
- * map was not consumed and must be freed.
+/**
+ * sparse_add_one_section - add a memory section
+ * @nid: The node to add section on
+ * @start_pfn: start pfn of the memory range
+ * @altmap: device page map
+ *
+ * This is only intended for hotplug.
+ *
+ * Return:
+ * * 0         - On success.
+ * * -EEXIST   - Section has been present.
+ * * -ENOMEM   - Out of memory.
  */
 int __meminit sparse_add_one_section(int nid, unsigned long start_pfn,
                                     struct vmem_altmap *altmap)
index 301ed4e04320588e66823b08e74a3000f379b7a9..3a75722e68a9ee5c0ec618e36332232f085d8d36 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -867,7 +867,7 @@ static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec,
        SetPageLRU(page);
        /*
         * Page becomes evictable in two ways:
-        * 1) Within LRU lock [munlock_vma_pages() and __munlock_pagevec()].
+        * 1) Within LRU lock [munlock_vma_page() and __munlock_pagevec()].
         * 2) Before acquiring LRU lock to put the page to correct LRU and then
         *   a) do PageLRU check with lock [check_move_unevictable_pages]
         *   b) do PageLRU check before lock [clear_page_mlock]
index 85245fdec8d9a34ff74176da9f0d6b59fde901b7..eb714165afd25e13aed1586fe8a94208cdb6683a 100644 (file)
@@ -132,7 +132,7 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp)
                for (i = 0; i < nr; i++) {
                        VM_BUG_ON_PAGE(xas.xa_index != idx + i, page);
                        set_page_private(page + i, entry.val + i);
-                       xas_store(&xas, page + i);
+                       xas_store(&xas, page);
                        xas_next(&xas);
                }
                address_space->nrpages += nr;
@@ -167,7 +167,7 @@ void __delete_from_swap_cache(struct page *page, swp_entry_t entry)
 
        for (i = 0; i < nr; i++) {
                void *entry = xas_store(&xas, NULL);
-               VM_BUG_ON_PAGE(entry != page + i, entry);
+               VM_BUG_ON_PAGE(entry != page, entry);
                set_page_private(page + i, 0);
                xas_next(&xas);
        }
index d59b5a73dfb38b1301092578c6704eb10eb5ecb2..9932d5755e4cba2a7e9b42df7918b5c5c123d6ec 100644 (file)
@@ -271,8 +271,7 @@ retry:
                 */
                idx = linear_page_index(dst_vma, dst_addr);
                mapping = dst_vma->vm_file->f_mapping;
-               hash = hugetlb_fault_mutex_hash(h, dst_mm, dst_vma, mapping,
-                                                               idx, dst_addr);
+               hash = hugetlb_fault_mutex_hash(h, mapping, idx, dst_addr);
                mutex_lock(&hugetlb_fault_mutex_table[hash]);
 
                err = -ENOMEM;
index 43a2984bccaab6525afb6e7c61ce8d903f45f24e..e2e4f8c3fa12ab96778f9308b7e2571f991f33af 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -318,7 +318,7 @@ EXPORT_SYMBOL_GPL(__get_user_pages_fast);
  * get_user_pages_fast() - pin user pages in memory
  * @start:     starting user address
  * @nr_pages:  number of pages from start to pin
- * @write:     whether pages will be written to
+ * @gup_flags: flags modifying pin behaviour
  * @pages:     array that receives pointers to the pages pinned.
  *             Should be at least nr_pages long.
  *
@@ -339,10 +339,10 @@ EXPORT_SYMBOL_GPL(__get_user_pages_fast);
  * were pinned, returns -errno.
  */
 int __weak get_user_pages_fast(unsigned long start,
-                               int nr_pages, int write, struct page **pages)
+                               int nr_pages, unsigned int gup_flags,
+                               struct page **pages)
 {
-       return get_user_pages_unlocked(start, nr_pages, pages,
-                                      write ? FOLL_WRITE : 0);
+       return get_user_pages_unlocked(start, nr_pages, pages, gup_flags);
 }
 EXPORT_SYMBOL_GPL(get_user_pages_fast);
 
@@ -652,7 +652,7 @@ EXPORT_SYMBOL_GPL(vm_memory_committed);
  */
 int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
 {
-       long free, allowed, reserve;
+       long allowed;
 
        VM_WARN_ONCE(percpu_counter_read(&vm_committed_as) <
                        -(s64)vm_committed_as_batch * num_online_cpus(),
@@ -667,51 +667,9 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
                return 0;
 
        if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) {
-               free = global_zone_page_state(NR_FREE_PAGES);
-               free += global_node_page_state(NR_FILE_PAGES);
-
-               /*
-                * shmem pages shouldn't be counted as free in this
-                * case, they can't be purged, only swapped out, and
-                * that won't affect the overall amount of available
-                * memory in the system.
-                */
-               free -= global_node_page_state(NR_SHMEM);
-
-               free += get_nr_swap_pages();
-
-               /*
-                * Any slabs which are created with the
-                * SLAB_RECLAIM_ACCOUNT flag claim to have contents
-                * which are reclaimable, under pressure.  The dentry
-                * cache and most inode caches should fall into this
-                */
-               free += global_node_page_state(NR_SLAB_RECLAIMABLE);
-
-               /*
-                * Part of the kernel memory, which can be released
-                * under memory pressure.
-                */
-               free += global_node_page_state(NR_KERNEL_MISC_RECLAIMABLE);
-
-               /*
-                * Leave reserved pages. The pages are not for anonymous pages.
-                */
-               if (free <= totalreserve_pages)
+               if (pages > totalram_pages() + total_swap_pages)
                        goto error;
-               else
-                       free -= totalreserve_pages;
-
-               /*
-                * Reserve some for root
-                */
-               if (!cap_sys_admin)
-                       free -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
-
-               if (free > pages)
-                       return 0;
-
-               goto error;
+               return 0;
        }
 
        allowed = vm_commit_limit();
@@ -725,7 +683,8 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
         * Don't let a single process grow so big a user can't recover
         */
        if (mm) {
-               reserve = sysctl_user_reserve_kbytes >> (PAGE_SHIFT - 10);
+               long reserve = sysctl_user_reserve_kbytes >> (PAGE_SHIFT - 10);
+
                allowed -= min_t(long, mm->total_vm / 32, reserve);
        }
 
index e5e9e1fcac014b5ad8c98da2f807259ad70754de..67bbb8d2a0a84c8cf1f4e8d212893bfdcdb12952 100644 (file)
@@ -633,7 +633,7 @@ static unsigned long lazy_max_pages(void)
        return log * (32UL * 1024 * 1024 / PAGE_SIZE);
 }
 
-static atomic_t vmap_lazy_nr = ATOMIC_INIT(0);
+static atomic_long_t vmap_lazy_nr = ATOMIC_LONG_INIT(0);
 
 /*
  * Serialize vmap purging.  There is no actual criticial section protected
@@ -651,7 +651,7 @@ static void purge_fragmented_blocks_allcpus(void);
  */
 void set_iounmap_nonlazy(void)
 {
-       atomic_set(&vmap_lazy_nr, lazy_max_pages()+1);
+       atomic_long_set(&vmap_lazy_nr, lazy_max_pages()+1);
 }
 
 /*
@@ -659,34 +659,40 @@ void set_iounmap_nonlazy(void)
  */
 static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)
 {
+       unsigned long resched_threshold;
        struct llist_node *valist;
        struct vmap_area *va;
        struct vmap_area *n_va;
-       bool do_free = false;
 
        lockdep_assert_held(&vmap_purge_lock);
 
        valist = llist_del_all(&vmap_purge_list);
+       if (unlikely(valist == NULL))
+               return false;
+
+       /*
+        * TODO: to calculate a flush range without looping.
+        * The list can be up to lazy_max_pages() elements.
+        */
        llist_for_each_entry(va, valist, purge_list) {
                if (va->va_start < start)
                        start = va->va_start;
                if (va->va_end > end)
                        end = va->va_end;
-               do_free = true;
        }
 
-       if (!do_free)
-               return false;
-
        flush_tlb_kernel_range(start, end);
+       resched_threshold = lazy_max_pages() << 1;
 
        spin_lock(&vmap_area_lock);
        llist_for_each_entry_safe(va, n_va, valist, purge_list) {
-               int nr = (va->va_end - va->va_start) >> PAGE_SHIFT;
+               unsigned long nr = (va->va_end - va->va_start) >> PAGE_SHIFT;
 
                __free_vmap_area(va);
-               atomic_sub(nr, &vmap_lazy_nr);
-               cond_resched_lock(&vmap_area_lock);
+               atomic_long_sub(nr, &vmap_lazy_nr);
+
+               if (atomic_long_read(&vmap_lazy_nr) < resched_threshold)
+                       cond_resched_lock(&vmap_area_lock);
        }
        spin_unlock(&vmap_area_lock);
        return true;
@@ -722,10 +728,10 @@ static void purge_vmap_area_lazy(void)
  */
 static void free_vmap_area_noflush(struct vmap_area *va)
 {
-       int nr_lazy;
+       unsigned long nr_lazy;
 
-       nr_lazy = atomic_add_return((va->va_end - va->va_start) >> PAGE_SHIFT,
-                                   &vmap_lazy_nr);
+       nr_lazy = atomic_long_add_return((va->va_end - va->va_start) >>
+                               PAGE_SHIFT, &vmap_lazy_nr);
 
        /* After this point, we may free va at any time */
        llist_add(&va->purge_list, &vmap_purge_list);
index fd9de504e516cf176a94eccb18cf5e0a4e9e0f31..7acd0afdfc2a707843c21fa59e6a91a2f22f2a43 100644 (file)
@@ -346,7 +346,7 @@ unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru, int zone
        int zid;
 
        if (!mem_cgroup_disabled())
-               lru_size = mem_cgroup_get_lru_size(lruvec, lru);
+               lru_size = lruvec_page_state_local(lruvec, NR_LRU_BASE + lru);
        else
                lru_size = node_page_state(lruvec_pgdat(lruvec), NR_LRU_BASE + lru);
 
@@ -1107,6 +1107,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
        LIST_HEAD(ret_pages);
        LIST_HEAD(free_pages);
        unsigned nr_reclaimed = 0;
+       unsigned pgactivate = 0;
 
        memset(stat, 0, sizeof(*stat));
        cond_resched();
@@ -1466,8 +1467,10 @@ activate_locked:
                        try_to_free_swap(page);
                VM_BUG_ON_PAGE(PageActive(page), page);
                if (!PageMlocked(page)) {
+                       int type = page_is_file_cache(page);
                        SetPageActive(page);
-                       stat->nr_activate++;
+                       pgactivate++;
+                       stat->nr_activate[type] += hpage_nr_pages(page);
                        count_memcg_page_event(page, PGACTIVATE);
                }
 keep_locked:
@@ -1482,7 +1485,7 @@ keep:
        free_unref_page_list(&free_pages);
 
        list_splice(&ret_pages, page_list);
-       count_vm_events(PGACTIVATE, stat->nr_activate);
+       count_vm_events(PGACTIVATE, pgactivate);
 
        return nr_reclaimed;
 }
@@ -1804,40 +1807,54 @@ static int too_many_isolated(struct pglist_data *pgdat, int file,
        return isolated > inactive;
 }
 
-static noinline_for_stack void
-putback_inactive_pages(struct lruvec *lruvec, struct list_head *page_list)
+/*
+ * This moves pages from @list to corresponding LRU list.
+ *
+ * We move them the other way if the page is referenced by one or more
+ * processes, from rmap.
+ *
+ * If the pages are mostly unmapped, the processing is fast and it is
+ * appropriate to hold zone_lru_lock across the whole operation.  But if
+ * the pages are mapped, the processing is slow (page_referenced()) so we
+ * should drop zone_lru_lock around each page.  It's impossible to balance
+ * this, so instead we remove the pages from the LRU while processing them.
+ * It is safe to rely on PG_active against the non-LRU pages in here because
+ * nobody will play with that bit on a non-LRU page.
+ *
+ * The downside is that we have to touch page->_refcount against each page.
+ * But we had to alter page->flags anyway.
+ *
+ * Returns the number of pages moved to the given lruvec.
+ */
+
+static unsigned noinline_for_stack move_pages_to_lru(struct lruvec *lruvec,
+                                                    struct list_head *list)
 {
-       struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat;
        struct pglist_data *pgdat = lruvec_pgdat(lruvec);
+       int nr_pages, nr_moved = 0;
        LIST_HEAD(pages_to_free);
+       struct page *page;
+       enum lru_list lru;
 
-       /*
-        * Put back any unfreeable pages.
-        */
-       while (!list_empty(page_list)) {
-               struct page *page = lru_to_page(page_list);
-               int lru;
-
+       while (!list_empty(list)) {
+               page = lru_to_page(list);
                VM_BUG_ON_PAGE(PageLRU(page), page);
-               list_del(&page->lru);
                if (unlikely(!page_evictable(page))) {
+                       list_del(&page->lru);
                        spin_unlock_irq(&pgdat->lru_lock);
                        putback_lru_page(page);
                        spin_lock_irq(&pgdat->lru_lock);
                        continue;
                }
-
                lruvec = mem_cgroup_page_lruvec(page, pgdat);
 
                SetPageLRU(page);
                lru = page_lru(page);
-               add_page_to_lru_list(page, lruvec, lru);
 
-               if (is_active_lru(lru)) {
-                       int file = is_file_lru(lru);
-                       int numpages = hpage_nr_pages(page);
-                       reclaim_stat->recent_rotated[file] += numpages;
-               }
+               nr_pages = hpage_nr_pages(page);
+               update_lru_size(lruvec, lru, page_zonenum(page), nr_pages);
+               list_move(&page->lru, &lruvec->lists[lru]);
+
                if (put_page_testzero(page)) {
                        __ClearPageLRU(page);
                        __ClearPageActive(page);
@@ -1850,13 +1867,17 @@ putback_inactive_pages(struct lruvec *lruvec, struct list_head *page_list)
                                spin_lock_irq(&pgdat->lru_lock);
                        } else
                                list_add(&page->lru, &pages_to_free);
+               } else {
+                       nr_moved += nr_pages;
                }
        }
 
        /*
         * To save our caller's stack, now use input list for pages to free.
         */
-       list_splice(&pages_to_free, page_list);
+       list_splice(&pages_to_free, list);
+
+       return nr_moved;
 }
 
 /*
@@ -1886,6 +1907,7 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
        unsigned long nr_taken;
        struct reclaim_stat stat;
        int file = is_file_lru(lru);
+       enum vm_event_item item;
        struct pglist_data *pgdat = lruvec_pgdat(lruvec);
        struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat;
        bool stalled = false;
@@ -1913,17 +1935,10 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
        __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, nr_taken);
        reclaim_stat->recent_scanned[file] += nr_taken;
 
-       if (current_is_kswapd()) {
-               if (global_reclaim(sc))
-                       __count_vm_events(PGSCAN_KSWAPD, nr_scanned);
-               count_memcg_events(lruvec_memcg(lruvec), PGSCAN_KSWAPD,
-                                  nr_scanned);
-       } else {
-               if (global_reclaim(sc))
-                       __count_vm_events(PGSCAN_DIRECT, nr_scanned);
-               count_memcg_events(lruvec_memcg(lruvec), PGSCAN_DIRECT,
-                                  nr_scanned);
-       }
+       item = current_is_kswapd() ? PGSCAN_KSWAPD : PGSCAN_DIRECT;
+       if (global_reclaim(sc))
+               __count_vm_events(item, nr_scanned);
+       __count_memcg_events(lruvec_memcg(lruvec), item, nr_scanned);
        spin_unlock_irq(&pgdat->lru_lock);
 
        if (nr_taken == 0)
@@ -1934,19 +1949,14 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
 
        spin_lock_irq(&pgdat->lru_lock);
 
-       if (current_is_kswapd()) {
-               if (global_reclaim(sc))
-                       __count_vm_events(PGSTEAL_KSWAPD, nr_reclaimed);
-               count_memcg_events(lruvec_memcg(lruvec), PGSTEAL_KSWAPD,
-                                  nr_reclaimed);
-       } else {
-               if (global_reclaim(sc))
-                       __count_vm_events(PGSTEAL_DIRECT, nr_reclaimed);
-               count_memcg_events(lruvec_memcg(lruvec), PGSTEAL_DIRECT,
-                                  nr_reclaimed);
-       }
+       item = current_is_kswapd() ? PGSTEAL_KSWAPD : PGSTEAL_DIRECT;
+       if (global_reclaim(sc))
+               __count_vm_events(item, nr_reclaimed);
+       __count_memcg_events(lruvec_memcg(lruvec), item, nr_reclaimed);
+       reclaim_stat->recent_rotated[0] = stat.nr_activate[0];
+       reclaim_stat->recent_rotated[1] = stat.nr_activate[1];
 
-       putback_inactive_pages(lruvec, &page_list);
+       move_pages_to_lru(lruvec, &page_list);
 
        __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, -nr_taken);
 
@@ -1983,73 +1993,6 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
        return nr_reclaimed;
 }
 
-/*
- * This moves pages from the active list to the inactive list.
- *
- * We move them the other way if the page is referenced by one or more
- * processes, from rmap.
- *
- * If the pages are mostly unmapped, the processing is fast and it is
- * appropriate to hold pgdat->lru_lock across the whole operation.  But if
- * the pages are mapped, the processing is slow (page_referenced()) so we
- * should drop pgdat->lru_lock around each page.  It's impossible to balance
- * this, so instead we remove the pages from the LRU while processing them.
- * It is safe to rely on PG_active against the non-LRU pages in here because
- * nobody will play with that bit on a non-LRU page.
- *
- * The downside is that we have to touch page->_refcount against each page.
- * But we had to alter page->flags anyway.
- *
- * Returns the number of pages moved to the given lru.
- */
-
-static unsigned move_active_pages_to_lru(struct lruvec *lruvec,
-                                    struct list_head *list,
-                                    struct list_head *pages_to_free,
-                                    enum lru_list lru)
-{
-       struct pglist_data *pgdat = lruvec_pgdat(lruvec);
-       struct page *page;
-       int nr_pages;
-       int nr_moved = 0;
-
-       while (!list_empty(list)) {
-               page = lru_to_page(list);
-               lruvec = mem_cgroup_page_lruvec(page, pgdat);
-
-               VM_BUG_ON_PAGE(PageLRU(page), page);
-               SetPageLRU(page);
-
-               nr_pages = hpage_nr_pages(page);
-               update_lru_size(lruvec, lru, page_zonenum(page), nr_pages);
-               list_move(&page->lru, &lruvec->lists[lru]);
-
-               if (put_page_testzero(page)) {
-                       __ClearPageLRU(page);
-                       __ClearPageActive(page);
-                       del_page_from_lru_list(page, lruvec, lru);
-
-                       if (unlikely(PageCompound(page))) {
-                               spin_unlock_irq(&pgdat->lru_lock);
-                               mem_cgroup_uncharge(page);
-                               (*get_compound_page_dtor(page))(page);
-                               spin_lock_irq(&pgdat->lru_lock);
-                       } else
-                               list_add(&page->lru, pages_to_free);
-               } else {
-                       nr_moved += nr_pages;
-               }
-       }
-
-       if (!is_active_lru(lru)) {
-               __count_vm_events(PGDEACTIVATE, nr_moved);
-               count_memcg_events(lruvec_memcg(lruvec), PGDEACTIVATE,
-                                  nr_moved);
-       }
-
-       return nr_moved;
-}
-
 static void shrink_active_list(unsigned long nr_to_scan,
                               struct lruvec *lruvec,
                               struct scan_control *sc,
@@ -2079,7 +2022,7 @@ static void shrink_active_list(unsigned long nr_to_scan,
        reclaim_stat->recent_scanned[file] += nr_taken;
 
        __count_vm_events(PGREFILL, nr_scanned);
-       count_memcg_events(lruvec_memcg(lruvec), PGREFILL, nr_scanned);
+       __count_memcg_events(lruvec_memcg(lruvec), PGREFILL, nr_scanned);
 
        spin_unlock_irq(&pgdat->lru_lock);
 
@@ -2136,13 +2079,19 @@ static void shrink_active_list(unsigned long nr_to_scan,
         */
        reclaim_stat->recent_rotated[file] += nr_rotated;
 
-       nr_activate = move_active_pages_to_lru(lruvec, &l_active, &l_hold, lru);
-       nr_deactivate = move_active_pages_to_lru(lruvec, &l_inactive, &l_hold, lru - LRU_ACTIVE);
+       nr_activate = move_pages_to_lru(lruvec, &l_active);
+       nr_deactivate = move_pages_to_lru(lruvec, &l_inactive);
+       /* Keep all free pages in l_active list */
+       list_splice(&l_inactive, &l_active);
+
+       __count_vm_events(PGDEACTIVATE, nr_deactivate);
+       __count_memcg_events(lruvec_memcg(lruvec), PGDEACTIVATE, nr_deactivate);
+
        __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, -nr_taken);
        spin_unlock_irq(&pgdat->lru_lock);
 
-       mem_cgroup_uncharge_list(&l_hold);
-       free_unref_page_list(&l_hold);
+       mem_cgroup_uncharge_list(&l_active);
+       free_unref_page_list(&l_active);
        trace_mm_vmscan_lru_shrink_active(pgdat->node_id, nr_taken, nr_activate,
                        nr_deactivate, nr_rotated, sc->priority, file);
 }
@@ -2201,7 +2150,7 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file,
         * is being established. Disable active list protection to get
         * rid of the stale workingset quickly.
         */
-       refaults = lruvec_page_state(lruvec, WORKINGSET_ACTIVATE);
+       refaults = lruvec_page_state_local(lruvec, WORKINGSET_ACTIVATE);
        if (file && actual_reclaim && lruvec->refaults != refaults) {
                inactive_ratio = 0;
        } else {
@@ -2963,7 +2912,7 @@ static void snapshot_refaults(struct mem_cgroup *root_memcg, pg_data_t *pgdat)
                struct lruvec *lruvec;
 
                lruvec = mem_cgroup_lruvec(pgdat, memcg);
-               refaults = lruvec_page_state(lruvec, WORKINGSET_ACTIVATE);
+               refaults = lruvec_page_state_local(lruvec, WORKINGSET_ACTIVATE);
                lruvec->refaults = refaults;
        } while ((memcg = mem_cgroup_iter(root_memcg, memcg, NULL)));
 }
@@ -3212,10 +3161,7 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
        if (throttle_direct_reclaim(sc.gfp_mask, zonelist, nodemask))
                return 1;
 
-       trace_mm_vmscan_direct_reclaim_begin(order,
-                               sc.may_writepage,
-                               sc.gfp_mask,
-                               sc.reclaim_idx);
+       trace_mm_vmscan_direct_reclaim_begin(order, sc.gfp_mask);
 
        nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
 
@@ -3246,9 +3192,7 @@ unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
                        (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
 
        trace_mm_vmscan_memcg_softlimit_reclaim_begin(sc.order,
-                                                     sc.may_writepage,
-                                                     sc.gfp_mask,
-                                                     sc.reclaim_idx);
+                                                     sc.gfp_mask);
 
        /*
         * NOTE: Although we can get the priority field, using it
@@ -3297,10 +3241,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
 
        zonelist = &NODE_DATA(nid)->node_zonelists[ZONELIST_FALLBACK];
 
-       trace_mm_vmscan_memcg_reclaim_begin(0,
-                                           sc.may_writepage,
-                                           sc.gfp_mask,
-                                           sc.reclaim_idx);
+       trace_mm_vmscan_memcg_reclaim_begin(0, sc.gfp_mask);
 
        psi_memstall_enter(&pflags);
        noreclaim_flag = memalloc_noreclaim_save();
@@ -4149,6 +4090,9 @@ static int __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned in
                .reclaim_idx = gfp_zone(gfp_mask),
        };
 
+       trace_mm_vmscan_node_reclaim_begin(pgdat->node_id, order,
+                                          sc.gfp_mask);
+
        cond_resched();
        fs_reclaim_acquire(sc.gfp_mask);
        /*
@@ -4175,6 +4119,9 @@ static int __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned in
        current->flags &= ~PF_SWAPWRITE;
        memalloc_noreclaim_restore(noreclaim_flag);
        fs_reclaim_release(sc.gfp_mask);
+
+       trace_mm_vmscan_node_reclaim_end(sc.nr_reclaimed);
+
        return sc.nr_reclaimed >= nr_pages;
 }
 
index 0bedf67502d54525fb7ac9626dbceb84572c26ca..e0b4edcb88c8c63dd307b0648ad34e3a27ce0ee8 100644 (file)
@@ -426,12 +426,14 @@ static unsigned long count_shadow_nodes(struct shrinker *shrinker,
 #ifdef CONFIG_MEMCG
        if (sc->memcg) {
                struct lruvec *lruvec;
+               int i;
 
-               pages = mem_cgroup_node_nr_lru_pages(sc->memcg, sc->nid,
-                                                    LRU_ALL);
                lruvec = mem_cgroup_lruvec(NODE_DATA(sc->nid), sc->memcg);
-               pages += lruvec_page_state(lruvec, NR_SLAB_RECLAIMABLE);
-               pages += lruvec_page_state(lruvec, NR_SLAB_UNRECLAIMABLE);
+               for (pages = 0, i = 0; i < NR_LRU_LISTS; i++)
+                       pages += lruvec_page_state_local(lruvec,
+                                                        NR_LRU_BASE + i);
+               pages += lruvec_page_state_local(lruvec, NR_SLAB_RECLAIMABLE);
+               pages += lruvec_page_state_local(lruvec, NR_SLAB_UNRECLAIMABLE);
        } else
 #endif
                pages = node_present_pages(sc->nid);
index aee9b0b8d9078a0bbf59a06509c6f7f7aa1360f3..1ffecd6333e53de006d3b47dfc91f8cfebe43515 100644 (file)
 
 #include <linux/atomic.h>
 #include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/dcache.h>
 #include <linux/list.h>
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/page-flags.h>
+#include <linux/migrate.h>
+#include <linux/node.h>
+#include <linux/compaction.h>
 #include <linux/percpu.h>
+#include <linux/mount.h>
+#include <linux/fs.h>
 #include <linux/preempt.h>
 #include <linux/workqueue.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/zpool.h>
 
+/*
+ * NCHUNKS_ORDER determines the internal allocation granularity, effectively
+ * adjusting internal fragmentation.  It also determines the number of
+ * freelists maintained in each pool. NCHUNKS_ORDER of 6 means that the
+ * allocation granularity will be in chunks of size PAGE_SIZE/64. Some chunks
+ * in the beginning of an allocated page are occupied by z3fold header, so
+ * NCHUNKS will be calculated to 63 (or 62 in case CONFIG_DEBUG_SPINLOCK=y),
+ * which shows the max number of free chunks in z3fold page, also there will
+ * be 63, or 62, respectively, freelists per pool.
+ */
+#define NCHUNKS_ORDER  6
+
+#define CHUNK_SHIFT    (PAGE_SHIFT - NCHUNKS_ORDER)
+#define CHUNK_SIZE     (1 << CHUNK_SHIFT)
+#define ZHDR_SIZE_ALIGNED round_up(sizeof(struct z3fold_header), CHUNK_SIZE)
+#define ZHDR_CHUNKS    (ZHDR_SIZE_ALIGNED >> CHUNK_SHIFT)
+#define TOTAL_CHUNKS   (PAGE_SIZE >> CHUNK_SHIFT)
+#define NCHUNKS                ((PAGE_SIZE - ZHDR_SIZE_ALIGNED) >> CHUNK_SHIFT)
+
+#define BUDDY_MASK     (0x3)
+#define BUDDY_SHIFT    2
+#define SLOTS_ALIGN    (0x40)
+
 /*****************
  * Structures
 *****************/
@@ -47,8 +78,18 @@ enum buddy {
        FIRST,
        MIDDLE,
        LAST,
-       BUDDIES_MAX
+       BUDDIES_MAX = LAST
+};
+
+struct z3fold_buddy_slots {
+       /*
+        * we are using BUDDY_MASK in handle_to_buddy etc. so there should
+        * be enough slots to hold all possible variants
+        */
+       unsigned long slot[BUDDY_MASK + 1];
+       unsigned long pool; /* back link + flags */
 };
+#define HANDLE_FLAG_MASK       (0x03)
 
 /*
  * struct z3fold_header - z3fold page metadata occupying first chunks of each
@@ -58,49 +99,29 @@ enum buddy {
  * @page_lock:         per-page lock
  * @refcount:          reference count for the z3fold page
  * @work:              work_struct for page layout optimization
- * @pool:              pointer to the pool which this page belongs to
+ * @slots:             pointer to the structure holding buddy slots
  * @cpu:               CPU which this page "belongs" to
  * @first_chunks:      the size of the first buddy in chunks, 0 if free
  * @middle_chunks:     the size of the middle buddy in chunks, 0 if free
  * @last_chunks:       the size of the last buddy in chunks, 0 if free
  * @first_num:         the starting number (for the first handle)
+ * @mapped_count:      the number of objects currently mapped
  */
 struct z3fold_header {
        struct list_head buddy;
        spinlock_t page_lock;
        struct kref refcount;
        struct work_struct work;
-       struct z3fold_pool *pool;
+       struct z3fold_buddy_slots *slots;
        short cpu;
        unsigned short first_chunks;
        unsigned short middle_chunks;
        unsigned short last_chunks;
        unsigned short start_middle;
        unsigned short first_num:2;
+       unsigned short mapped_count:2;
 };
 
-/*
- * NCHUNKS_ORDER determines the internal allocation granularity, effectively
- * adjusting internal fragmentation.  It also determines the number of
- * freelists maintained in each pool. NCHUNKS_ORDER of 6 means that the
- * allocation granularity will be in chunks of size PAGE_SIZE/64. Some chunks
- * in the beginning of an allocated page are occupied by z3fold header, so
- * NCHUNKS will be calculated to 63 (or 62 in case CONFIG_DEBUG_SPINLOCK=y),
- * which shows the max number of free chunks in z3fold page, also there will
- * be 63, or 62, respectively, freelists per pool.
- */
-#define NCHUNKS_ORDER  6
-
-#define CHUNK_SHIFT    (PAGE_SHIFT - NCHUNKS_ORDER)
-#define CHUNK_SIZE     (1 << CHUNK_SHIFT)
-#define ZHDR_SIZE_ALIGNED round_up(sizeof(struct z3fold_header), CHUNK_SIZE)
-#define ZHDR_CHUNKS    (ZHDR_SIZE_ALIGNED >> CHUNK_SHIFT)
-#define TOTAL_CHUNKS   (PAGE_SIZE >> CHUNK_SHIFT)
-#define NCHUNKS                ((PAGE_SIZE - ZHDR_SIZE_ALIGNED) >> CHUNK_SHIFT)
-
-#define BUDDY_MASK     (0x3)
-#define BUDDY_SHIFT    2
-
 /**
  * struct z3fold_pool - stores metadata for each z3fold pool
  * @name:      pool name
@@ -113,11 +134,13 @@ struct z3fold_header {
  *             added buddy.
  * @stale:     list of pages marked for freeing
  * @pages_nr:  number of z3fold pages in the pool.
+ * @c_handle:  cache for z3fold_buddy_slots allocation
  * @ops:       pointer to a structure of user defined operations specified at
  *             pool creation time.
  * @compact_wq:        workqueue for page layout background optimization
  * @release_wq:        workqueue for safe page release
  * @work:      work_struct for safe page release
+ * @inode:     inode for z3fold pseudo filesystem
  *
  * This structure is allocated at pool creation time and maintains metadata
  * pertaining to a particular z3fold pool.
@@ -130,12 +153,14 @@ struct z3fold_pool {
        struct list_head lru;
        struct list_head stale;
        atomic64_t pages_nr;
+       struct kmem_cache *c_handle;
        const struct z3fold_ops *ops;
        struct zpool *zpool;
        const struct zpool_ops *zpool_ops;
        struct workqueue_struct *compact_wq;
        struct workqueue_struct *release_wq;
        struct work_struct work;
+       struct inode *inode;
 };
 
 /*
@@ -164,11 +189,118 @@ static int size_to_chunks(size_t size)
 
 static void compact_page_work(struct work_struct *w);
 
+static inline struct z3fold_buddy_slots *alloc_slots(struct z3fold_pool *pool)
+{
+       struct z3fold_buddy_slots *slots = kmem_cache_alloc(pool->c_handle,
+                                                       GFP_KERNEL);
+
+       if (slots) {
+               memset(slots->slot, 0, sizeof(slots->slot));
+               slots->pool = (unsigned long)pool;
+       }
+
+       return slots;
+}
+
+static inline struct z3fold_pool *slots_to_pool(struct z3fold_buddy_slots *s)
+{
+       return (struct z3fold_pool *)(s->pool & ~HANDLE_FLAG_MASK);
+}
+
+static inline struct z3fold_buddy_slots *handle_to_slots(unsigned long handle)
+{
+       return (struct z3fold_buddy_slots *)(handle & ~(SLOTS_ALIGN - 1));
+}
+
+static inline void free_handle(unsigned long handle)
+{
+       struct z3fold_buddy_slots *slots;
+       int i;
+       bool is_free;
+
+       if (handle & (1 << PAGE_HEADLESS))
+               return;
+
+       WARN_ON(*(unsigned long *)handle == 0);
+       *(unsigned long *)handle = 0;
+       slots = handle_to_slots(handle);
+       is_free = true;
+       for (i = 0; i <= BUDDY_MASK; i++) {
+               if (slots->slot[i]) {
+                       is_free = false;
+                       break;
+               }
+       }
+
+       if (is_free) {
+               struct z3fold_pool *pool = slots_to_pool(slots);
+
+               kmem_cache_free(pool->c_handle, slots);
+       }
+}
+
+static struct dentry *z3fold_do_mount(struct file_system_type *fs_type,
+                               int flags, const char *dev_name, void *data)
+{
+       static const struct dentry_operations ops = {
+               .d_dname = simple_dname,
+       };
+
+       return mount_pseudo(fs_type, "z3fold:", NULL, &ops, 0x33);
+}
+
+static struct file_system_type z3fold_fs = {
+       .name           = "z3fold",
+       .mount          = z3fold_do_mount,
+       .kill_sb        = kill_anon_super,
+};
+
+static struct vfsmount *z3fold_mnt;
+static int z3fold_mount(void)
+{
+       int ret = 0;
+
+       z3fold_mnt = kern_mount(&z3fold_fs);
+       if (IS_ERR(z3fold_mnt))
+               ret = PTR_ERR(z3fold_mnt);
+
+       return ret;
+}
+
+static void z3fold_unmount(void)
+{
+       kern_unmount(z3fold_mnt);
+}
+
+static const struct address_space_operations z3fold_aops;
+static int z3fold_register_migration(struct z3fold_pool *pool)
+{
+       pool->inode = alloc_anon_inode(z3fold_mnt->mnt_sb);
+       if (IS_ERR(pool->inode)) {
+               pool->inode = NULL;
+               return 1;
+       }
+
+       pool->inode->i_mapping->private_data = pool;
+       pool->inode->i_mapping->a_ops = &z3fold_aops;
+       return 0;
+}
+
+static void z3fold_unregister_migration(struct z3fold_pool *pool)
+{
+       if (pool->inode)
+               iput(pool->inode);
+ }
+
 /* Initializes the z3fold header of a newly allocated z3fold page */
 static struct z3fold_header *init_z3fold_page(struct page *page,
                                        struct z3fold_pool *pool)
 {
        struct z3fold_header *zhdr = page_address(page);
+       struct z3fold_buddy_slots *slots = alloc_slots(pool);
+
+       if (!slots)
+               return NULL;
 
        INIT_LIST_HEAD(&page->lru);
        clear_bit(PAGE_HEADLESS, &page->private);
@@ -185,15 +317,21 @@ static struct z3fold_header *init_z3fold_page(struct page *page,
        zhdr->first_num = 0;
        zhdr->start_middle = 0;
        zhdr->cpu = -1;
-       zhdr->pool = pool;
+       zhdr->slots = slots;
        INIT_LIST_HEAD(&zhdr->buddy);
        INIT_WORK(&zhdr->work, compact_page_work);
        return zhdr;
 }
 
 /* Resets the struct page fields and frees the page */
-static void free_z3fold_page(struct page *page)
+static void free_z3fold_page(struct page *page, bool headless)
 {
+       if (!headless) {
+               lock_page(page);
+               __ClearPageMovable(page);
+               unlock_page(page);
+       }
+       ClearPagePrivate(page);
        __free_page(page);
 }
 
@@ -215,33 +353,57 @@ static inline void z3fold_page_unlock(struct z3fold_header *zhdr)
        spin_unlock(&zhdr->page_lock);
 }
 
+/* Helper function to build the index */
+static inline int __idx(struct z3fold_header *zhdr, enum buddy bud)
+{
+       return (bud + zhdr->first_num) & BUDDY_MASK;
+}
+
 /*
  * Encodes the handle of a particular buddy within a z3fold page
  * Pool lock should be held as this function accesses first_num
  */
 static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud)
 {
-       unsigned long handle;
+       struct z3fold_buddy_slots *slots;
+       unsigned long h = (unsigned long)zhdr;
+       int idx = 0;
 
-       handle = (unsigned long)zhdr;
-       if (bud != HEADLESS) {
-               handle |= (bud + zhdr->first_num) & BUDDY_MASK;
-               if (bud == LAST)
-                       handle |= (zhdr->last_chunks << BUDDY_SHIFT);
-       }
-       return handle;
+       /*
+        * For a headless page, its handle is its pointer with the extra
+        * PAGE_HEADLESS bit set
+        */
+       if (bud == HEADLESS)
+               return h | (1 << PAGE_HEADLESS);
+
+       /* otherwise, return pointer to encoded handle */
+       idx = __idx(zhdr, bud);
+       h += idx;
+       if (bud == LAST)
+               h |= (zhdr->last_chunks << BUDDY_SHIFT);
+
+       slots = zhdr->slots;
+       slots->slot[idx] = h;
+       return (unsigned long)&slots->slot[idx];
 }
 
 /* Returns the z3fold page where a given handle is stored */
-static struct z3fold_header *handle_to_z3fold_header(unsigned long handle)
+static inline struct z3fold_header *handle_to_z3fold_header(unsigned long h)
 {
-       return (struct z3fold_header *)(handle & PAGE_MASK);
+       unsigned long addr = h;
+
+       if (!(addr & (1 << PAGE_HEADLESS)))
+               addr = *(unsigned long *)h;
+
+       return (struct z3fold_header *)(addr & PAGE_MASK);
 }
 
 /* only for LAST bud, returns zero otherwise */
 static unsigned short handle_to_chunks(unsigned long handle)
 {
-       return (handle & ~PAGE_MASK) >> BUDDY_SHIFT;
+       unsigned long addr = *(unsigned long *)handle;
+
+       return (addr & ~PAGE_MASK) >> BUDDY_SHIFT;
 }
 
 /*
@@ -251,21 +413,31 @@ static unsigned short handle_to_chunks(unsigned long handle)
  */
 static enum buddy handle_to_buddy(unsigned long handle)
 {
-       struct z3fold_header *zhdr = handle_to_z3fold_header(handle);
-       return (handle - zhdr->first_num) & BUDDY_MASK;
+       struct z3fold_header *zhdr;
+       unsigned long addr;
+
+       WARN_ON(handle & (1 << PAGE_HEADLESS));
+       addr = *(unsigned long *)handle;
+       zhdr = (struct z3fold_header *)(addr & PAGE_MASK);
+       return (addr - zhdr->first_num) & BUDDY_MASK;
+}
+
+static inline struct z3fold_pool *zhdr_to_pool(struct z3fold_header *zhdr)
+{
+       return slots_to_pool(zhdr->slots);
 }
 
 static void __release_z3fold_page(struct z3fold_header *zhdr, bool locked)
 {
        struct page *page = virt_to_page(zhdr);
-       struct z3fold_pool *pool = zhdr->pool;
+       struct z3fold_pool *pool = zhdr_to_pool(zhdr);
 
        WARN_ON(!list_empty(&zhdr->buddy));
        set_bit(PAGE_STALE, &page->private);
        clear_bit(NEEDS_COMPACTING, &page->private);
        spin_lock(&pool->lock);
        if (!list_empty(&page->lru))
-               list_del(&page->lru);
+               list_del_init(&page->lru);
        spin_unlock(&pool->lock);
        if (locked)
                z3fold_page_unlock(zhdr);
@@ -295,9 +467,10 @@ static void release_z3fold_page_locked_list(struct kref *ref)
 {
        struct z3fold_header *zhdr = container_of(ref, struct z3fold_header,
                                               refcount);
-       spin_lock(&zhdr->pool->lock);
+       struct z3fold_pool *pool = zhdr_to_pool(zhdr);
+       spin_lock(&pool->lock);
        list_del_init(&zhdr->buddy);
-       spin_unlock(&zhdr->pool->lock);
+       spin_unlock(&pool->lock);
 
        WARN_ON(z3fold_page_trylock(zhdr));
        __release_z3fold_page(zhdr, true);
@@ -318,7 +491,7 @@ static void free_pages_work(struct work_struct *w)
                        continue;
                spin_unlock(&pool->stale_lock);
                cancel_work_sync(&zhdr->work);
-               free_z3fold_page(page);
+               free_z3fold_page(page, false);
                cond_resched();
                spin_lock(&pool->stale_lock);
        }
@@ -349,6 +522,23 @@ static int num_free_chunks(struct z3fold_header *zhdr)
        return nfree;
 }
 
+/* Add to the appropriate unbuddied list */
+static inline void add_to_unbuddied(struct z3fold_pool *pool,
+                               struct z3fold_header *zhdr)
+{
+       if (zhdr->first_chunks == 0 || zhdr->last_chunks == 0 ||
+                       zhdr->middle_chunks == 0) {
+               struct list_head *unbuddied = get_cpu_ptr(pool->unbuddied);
+
+               int freechunks = num_free_chunks(zhdr);
+               spin_lock(&pool->lock);
+               list_add(&zhdr->buddy, &unbuddied[freechunks]);
+               spin_unlock(&pool->lock);
+               zhdr->cpu = smp_processor_id();
+               put_cpu_ptr(pool->unbuddied);
+       }
+}
+
 static inline void *mchunk_memmove(struct z3fold_header *zhdr,
                                unsigned short dst_chunk)
 {
@@ -367,6 +557,9 @@ static int z3fold_compact_page(struct z3fold_header *zhdr)
        if (test_bit(MIDDLE_CHUNK_MAPPED, &page->private))
                return 0; /* can't move middle chunk, it's used */
 
+       if (unlikely(PageIsolated(page)))
+               return 0;
+
        if (zhdr->middle_chunks == 0)
                return 0; /* nothing to compact */
 
@@ -406,10 +599,8 @@ static int z3fold_compact_page(struct z3fold_header *zhdr)
 
 static void do_compact_page(struct z3fold_header *zhdr, bool locked)
 {
-       struct z3fold_pool *pool = zhdr->pool;
+       struct z3fold_pool *pool = zhdr_to_pool(zhdr);
        struct page *page;
-       struct list_head *unbuddied;
-       int fchunks;
 
        page = virt_to_page(zhdr);
        if (locked)
@@ -429,19 +620,14 @@ static void do_compact_page(struct z3fold_header *zhdr, bool locked)
                return;
        }
 
-       z3fold_compact_page(zhdr);
-       unbuddied = get_cpu_ptr(pool->unbuddied);
-       fchunks = num_free_chunks(zhdr);
-       if (fchunks < NCHUNKS &&
-           (!zhdr->first_chunks || !zhdr->middle_chunks ||
-                       !zhdr->last_chunks)) {
-               /* the page's not completely free and it's unbuddied */
-               spin_lock(&pool->lock);
-               list_add(&zhdr->buddy, &unbuddied[fchunks]);
-               spin_unlock(&pool->lock);
-               zhdr->cpu = smp_processor_id();
+       if (unlikely(PageIsolated(page) ||
+                    test_bit(PAGE_STALE, &page->private))) {
+               z3fold_page_unlock(zhdr);
+               return;
        }
-       put_cpu_ptr(pool->unbuddied);
+
+       z3fold_compact_page(zhdr);
+       add_to_unbuddied(pool, zhdr);
        z3fold_page_unlock(zhdr);
 }
 
@@ -453,6 +639,103 @@ static void compact_page_work(struct work_struct *w)
        do_compact_page(zhdr, false);
 }
 
+/* returns _locked_ z3fold page header or NULL */
+static inline struct z3fold_header *__z3fold_alloc(struct z3fold_pool *pool,
+                                               size_t size, bool can_sleep)
+{
+       struct z3fold_header *zhdr = NULL;
+       struct page *page;
+       struct list_head *unbuddied;
+       int chunks = size_to_chunks(size), i;
+
+lookup:
+       /* First, try to find an unbuddied z3fold page. */
+       unbuddied = get_cpu_ptr(pool->unbuddied);
+       for_each_unbuddied_list(i, chunks) {
+               struct list_head *l = &unbuddied[i];
+
+               zhdr = list_first_entry_or_null(READ_ONCE(l),
+                                       struct z3fold_header, buddy);
+
+               if (!zhdr)
+                       continue;
+
+               /* Re-check under lock. */
+               spin_lock(&pool->lock);
+               l = &unbuddied[i];
+               if (unlikely(zhdr != list_first_entry(READ_ONCE(l),
+                                               struct z3fold_header, buddy)) ||
+                   !z3fold_page_trylock(zhdr)) {
+                       spin_unlock(&pool->lock);
+                       zhdr = NULL;
+                       put_cpu_ptr(pool->unbuddied);
+                       if (can_sleep)
+                               cond_resched();
+                       goto lookup;
+               }
+               list_del_init(&zhdr->buddy);
+               zhdr->cpu = -1;
+               spin_unlock(&pool->lock);
+
+               page = virt_to_page(zhdr);
+               if (test_bit(NEEDS_COMPACTING, &page->private)) {
+                       z3fold_page_unlock(zhdr);
+                       zhdr = NULL;
+                       put_cpu_ptr(pool->unbuddied);
+                       if (can_sleep)
+                               cond_resched();
+                       goto lookup;
+               }
+
+               /*
+                * this page could not be removed from its unbuddied
+                * list while pool lock was held, and then we've taken
+                * page lock so kref_put could not be called before
+                * we got here, so it's safe to just call kref_get()
+                */
+               kref_get(&zhdr->refcount);
+               break;
+       }
+       put_cpu_ptr(pool->unbuddied);
+
+       if (!zhdr) {
+               int cpu;
+
+               /* look for _exact_ match on other cpus' lists */
+               for_each_online_cpu(cpu) {
+                       struct list_head *l;
+
+                       unbuddied = per_cpu_ptr(pool->unbuddied, cpu);
+                       spin_lock(&pool->lock);
+                       l = &unbuddied[chunks];
+
+                       zhdr = list_first_entry_or_null(READ_ONCE(l),
+                                               struct z3fold_header, buddy);
+
+                       if (!zhdr || !z3fold_page_trylock(zhdr)) {
+                               spin_unlock(&pool->lock);
+                               zhdr = NULL;
+                               continue;
+                       }
+                       list_del_init(&zhdr->buddy);
+                       zhdr->cpu = -1;
+                       spin_unlock(&pool->lock);
+
+                       page = virt_to_page(zhdr);
+                       if (test_bit(NEEDS_COMPACTING, &page->private)) {
+                               z3fold_page_unlock(zhdr);
+                               zhdr = NULL;
+                               if (can_sleep)
+                                       cond_resched();
+                               continue;
+                       }
+                       kref_get(&zhdr->refcount);
+                       break;
+               }
+       }
+
+       return zhdr;
+}
 
 /*
  * API Functions
@@ -476,6 +759,11 @@ static struct z3fold_pool *z3fold_create_pool(const char *name, gfp_t gfp,
        pool = kzalloc(sizeof(struct z3fold_pool), gfp);
        if (!pool)
                goto out;
+       pool->c_handle = kmem_cache_create("z3fold_handle",
+                               sizeof(struct z3fold_buddy_slots),
+                               SLOTS_ALIGN, 0, NULL);
+       if (!pool->c_handle)
+               goto out_c;
        spin_lock_init(&pool->lock);
        spin_lock_init(&pool->stale_lock);
        pool->unbuddied = __alloc_percpu(sizeof(struct list_head)*NCHUNKS, 2);
@@ -497,15 +785,21 @@ static struct z3fold_pool *z3fold_create_pool(const char *name, gfp_t gfp,
        pool->release_wq = create_singlethread_workqueue(pool->name);
        if (!pool->release_wq)
                goto out_wq;
+       if (z3fold_register_migration(pool))
+               goto out_rwq;
        INIT_WORK(&pool->work, free_pages_work);
        pool->ops = ops;
        return pool;
 
+out_rwq:
+       destroy_workqueue(pool->release_wq);
 out_wq:
        destroy_workqueue(pool->compact_wq);
 out_unbuddied:
        free_percpu(pool->unbuddied);
 out_pool:
+       kmem_cache_destroy(pool->c_handle);
+out_c:
        kfree(pool);
 out:
        return NULL;
@@ -519,6 +813,8 @@ out:
  */
 static void z3fold_destroy_pool(struct z3fold_pool *pool)
 {
+       kmem_cache_destroy(pool->c_handle);
+       z3fold_unregister_migration(pool);
        destroy_workqueue(pool->release_wq);
        destroy_workqueue(pool->compact_wq);
        kfree(pool);
@@ -546,7 +842,7 @@ static void z3fold_destroy_pool(struct z3fold_pool *pool)
 static int z3fold_alloc(struct z3fold_pool *pool, size_t size, gfp_t gfp,
                        unsigned long *handle)
 {
-       int chunks = 0, i, freechunks;
+       int chunks = size_to_chunks(size);
        struct z3fold_header *zhdr = NULL;
        struct page *page = NULL;
        enum buddy bud;
@@ -561,56 +857,8 @@ static int z3fold_alloc(struct z3fold_pool *pool, size_t size, gfp_t gfp,
        if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE)
                bud = HEADLESS;
        else {
-               struct list_head *unbuddied;
-               chunks = size_to_chunks(size);
-
-lookup:
-               /* First, try to find an unbuddied z3fold page. */
-               unbuddied = get_cpu_ptr(pool->unbuddied);
-               for_each_unbuddied_list(i, chunks) {
-                       struct list_head *l = &unbuddied[i];
-
-                       zhdr = list_first_entry_or_null(READ_ONCE(l),
-                                               struct z3fold_header, buddy);
-
-                       if (!zhdr)
-                               continue;
-
-                       /* Re-check under lock. */
-                       spin_lock(&pool->lock);
-                       l = &unbuddied[i];
-                       if (unlikely(zhdr != list_first_entry(READ_ONCE(l),
-                                       struct z3fold_header, buddy)) ||
-                           !z3fold_page_trylock(zhdr)) {
-                               spin_unlock(&pool->lock);
-                               put_cpu_ptr(pool->unbuddied);
-                               goto lookup;
-                       }
-                       list_del_init(&zhdr->buddy);
-                       zhdr->cpu = -1;
-                       spin_unlock(&pool->lock);
-
-                       page = virt_to_page(zhdr);
-                       if (test_bit(NEEDS_COMPACTING, &page->private)) {
-                               z3fold_page_unlock(zhdr);
-                               zhdr = NULL;
-                               put_cpu_ptr(pool->unbuddied);
-                               if (can_sleep)
-                                       cond_resched();
-                               goto lookup;
-                       }
-
-                       /*
-                        * this page could not be removed from its unbuddied
-                        * list while pool lock was held, and then we've taken
-                        * page lock so kref_put could not be called before
-                        * we got here, so it's safe to just call kref_get()
-                        */
-                       kref_get(&zhdr->refcount);
-                       break;
-               }
-               put_cpu_ptr(pool->unbuddied);
-
+retry:
+               zhdr = __z3fold_alloc(pool, size, can_sleep);
                if (zhdr) {
                        if (zhdr->first_chunks == 0) {
                                if (zhdr->middle_chunks != 0 &&
@@ -630,8 +878,9 @@ lookup:
                                        z3fold_page_unlock(zhdr);
                                pr_err("No free chunks in unbuddied\n");
                                WARN_ON(1);
-                               goto lookup;
+                               goto retry;
                        }
+                       page = virt_to_page(zhdr);
                        goto found;
                }
                bud = FIRST;
@@ -662,13 +911,18 @@ lookup:
        if (!page)
                return -ENOMEM;
 
-       atomic64_inc(&pool->pages_nr);
        zhdr = init_z3fold_page(page, pool);
+       if (!zhdr) {
+               __free_page(page);
+               return -ENOMEM;
+       }
+       atomic64_inc(&pool->pages_nr);
 
        if (bud == HEADLESS) {
                set_bit(PAGE_HEADLESS, &page->private);
                goto headless;
        }
+       __SetPageMovable(page, pool->inode->i_mapping);
        z3fold_page_lock(zhdr);
 
 found:
@@ -680,19 +934,7 @@ found:
                zhdr->middle_chunks = chunks;
                zhdr->start_middle = zhdr->first_chunks + ZHDR_CHUNKS;
        }
-
-       if (zhdr->first_chunks == 0 || zhdr->last_chunks == 0 ||
-                       zhdr->middle_chunks == 0) {
-               struct list_head *unbuddied = get_cpu_ptr(pool->unbuddied);
-
-               /* Add to unbuddied list */
-               freechunks = num_free_chunks(zhdr);
-               spin_lock(&pool->lock);
-               list_add(&zhdr->buddy, &unbuddied[freechunks]);
-               spin_unlock(&pool->lock);
-               zhdr->cpu = smp_processor_id();
-               put_cpu_ptr(pool->unbuddied);
-       }
+       add_to_unbuddied(pool, zhdr);
 
 headless:
        spin_lock(&pool->lock);
@@ -739,7 +981,7 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
                        spin_lock(&pool->lock);
                        list_del(&page->lru);
                        spin_unlock(&pool->lock);
-                       free_z3fold_page(page);
+                       free_z3fold_page(page, true);
                        atomic64_dec(&pool->pages_nr);
                }
                return;
@@ -766,6 +1008,7 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
                return;
        }
 
+       free_handle(handle);
        if (kref_put(&zhdr->refcount, release_z3fold_page_locked_list)) {
                atomic64_dec(&pool->pages_nr);
                return;
@@ -774,7 +1017,8 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
                z3fold_page_unlock(zhdr);
                return;
        }
-       if (test_and_set_bit(NEEDS_COMPACTING, &page->private)) {
+       if (unlikely(PageIsolated(page)) ||
+           test_and_set_bit(NEEDS_COMPACTING, &page->private)) {
                z3fold_page_unlock(zhdr);
                return;
        }
@@ -855,10 +1099,12 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
                        if (test_and_set_bit(PAGE_CLAIMED, &page->private))
                                continue;
 
-                       zhdr = page_address(page);
+                       if (unlikely(PageIsolated(page)))
+                               continue;
                        if (test_bit(PAGE_HEADLESS, &page->private))
                                break;
 
+                       zhdr = page_address(page);
                        if (!z3fold_page_trylock(zhdr)) {
                                zhdr = NULL;
                                continue; /* can't evict at this point */
@@ -919,7 +1165,7 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
 next:
                if (test_bit(PAGE_HEADLESS, &page->private)) {
                        if (ret == 0) {
-                               free_z3fold_page(page);
+                               free_z3fold_page(page, true);
                                atomic64_dec(&pool->pages_nr);
                                return 0;
                        }
@@ -996,6 +1242,8 @@ static void *z3fold_map(struct z3fold_pool *pool, unsigned long handle)
                break;
        }
 
+       if (addr)
+               zhdr->mapped_count++;
        z3fold_page_unlock(zhdr);
 out:
        return addr;
@@ -1022,6 +1270,7 @@ static void z3fold_unmap(struct z3fold_pool *pool, unsigned long handle)
        buddy = handle_to_buddy(handle);
        if (buddy == MIDDLE)
                clear_bit(MIDDLE_CHUNK_MAPPED, &page->private);
+       zhdr->mapped_count--;
        z3fold_page_unlock(zhdr);
 }
 
@@ -1036,6 +1285,128 @@ static u64 z3fold_get_pool_size(struct z3fold_pool *pool)
        return atomic64_read(&pool->pages_nr);
 }
 
+static bool z3fold_page_isolate(struct page *page, isolate_mode_t mode)
+{
+       struct z3fold_header *zhdr;
+       struct z3fold_pool *pool;
+
+       VM_BUG_ON_PAGE(!PageMovable(page), page);
+       VM_BUG_ON_PAGE(PageIsolated(page), page);
+
+       if (test_bit(PAGE_HEADLESS, &page->private))
+               return false;
+
+       zhdr = page_address(page);
+       z3fold_page_lock(zhdr);
+       if (test_bit(NEEDS_COMPACTING, &page->private) ||
+           test_bit(PAGE_STALE, &page->private))
+               goto out;
+
+       pool = zhdr_to_pool(zhdr);
+
+       if (zhdr->mapped_count == 0) {
+               kref_get(&zhdr->refcount);
+               if (!list_empty(&zhdr->buddy))
+                       list_del_init(&zhdr->buddy);
+               spin_lock(&pool->lock);
+               if (!list_empty(&page->lru))
+                       list_del(&page->lru);
+               spin_unlock(&pool->lock);
+               z3fold_page_unlock(zhdr);
+               return true;
+       }
+out:
+       z3fold_page_unlock(zhdr);
+       return false;
+}
+
+static int z3fold_page_migrate(struct address_space *mapping, struct page *newpage,
+                              struct page *page, enum migrate_mode mode)
+{
+       struct z3fold_header *zhdr, *new_zhdr;
+       struct z3fold_pool *pool;
+       struct address_space *new_mapping;
+
+       VM_BUG_ON_PAGE(!PageMovable(page), page);
+       VM_BUG_ON_PAGE(!PageIsolated(page), page);
+
+       zhdr = page_address(page);
+       pool = zhdr_to_pool(zhdr);
+
+       if (!trylock_page(page))
+               return -EAGAIN;
+
+       if (!z3fold_page_trylock(zhdr)) {
+               unlock_page(page);
+               return -EAGAIN;
+       }
+       if (zhdr->mapped_count != 0) {
+               z3fold_page_unlock(zhdr);
+               unlock_page(page);
+               return -EBUSY;
+       }
+       new_zhdr = page_address(newpage);
+       memcpy(new_zhdr, zhdr, PAGE_SIZE);
+       newpage->private = page->private;
+       page->private = 0;
+       z3fold_page_unlock(zhdr);
+       spin_lock_init(&new_zhdr->page_lock);
+       new_mapping = page_mapping(page);
+       __ClearPageMovable(page);
+       ClearPagePrivate(page);
+
+       get_page(newpage);
+       z3fold_page_lock(new_zhdr);
+       if (new_zhdr->first_chunks)
+               encode_handle(new_zhdr, FIRST);
+       if (new_zhdr->last_chunks)
+               encode_handle(new_zhdr, LAST);
+       if (new_zhdr->middle_chunks)
+               encode_handle(new_zhdr, MIDDLE);
+       set_bit(NEEDS_COMPACTING, &newpage->private);
+       new_zhdr->cpu = smp_processor_id();
+       spin_lock(&pool->lock);
+       list_add(&newpage->lru, &pool->lru);
+       spin_unlock(&pool->lock);
+       __SetPageMovable(newpage, new_mapping);
+       z3fold_page_unlock(new_zhdr);
+
+       queue_work_on(new_zhdr->cpu, pool->compact_wq, &new_zhdr->work);
+
+       page_mapcount_reset(page);
+       unlock_page(page);
+       put_page(page);
+       return 0;
+}
+
+static void z3fold_page_putback(struct page *page)
+{
+       struct z3fold_header *zhdr;
+       struct z3fold_pool *pool;
+
+       zhdr = page_address(page);
+       pool = zhdr_to_pool(zhdr);
+
+       z3fold_page_lock(zhdr);
+       if (!list_empty(&zhdr->buddy))
+               list_del_init(&zhdr->buddy);
+       INIT_LIST_HEAD(&page->lru);
+       if (kref_put(&zhdr->refcount, release_z3fold_page_locked)) {
+               atomic64_dec(&pool->pages_nr);
+               return;
+       }
+       spin_lock(&pool->lock);
+       list_add(&page->lru, &pool->lru);
+       spin_unlock(&pool->lock);
+       z3fold_page_unlock(zhdr);
+}
+
+static const struct address_space_operations z3fold_aops = {
+       .isolate_page = z3fold_page_isolate,
+       .migratepage = z3fold_page_migrate,
+       .putback_page = z3fold_page_putback,
+};
+
 /*****************
  * zpool
  ****************/
@@ -1133,8 +1504,14 @@ MODULE_ALIAS("zpool-z3fold");
 
 static int __init init_z3fold(void)
 {
+       int ret;
+
        /* Make sure the z3fold header is not larger than the page size */
        BUILD_BUG_ON(ZHDR_SIZE_ALIGNED > PAGE_SIZE);
+       ret = z3fold_mount();
+       if (ret)
+               return ret;
+
        zpool_register_driver(&z3fold_zpool_driver);
 
        return 0;
@@ -1142,6 +1519,7 @@ static int __init init_z3fold(void)
 
 static void __exit exit_z3fold(void)
 {
+       z3fold_unmount();
        zpool_unregister_driver(&z3fold_zpool_driver);
 }
 
index 4a9aaa3fac8fdfa39a66a6712baa3c1e35722d80..6d4a24a7534b8e568ccb9d6633e50f8e2f8720a7 100644 (file)
@@ -602,13 +602,15 @@ int br_add_if(struct net_bridge *br, struct net_device *dev,
        call_netdevice_notifiers(NETDEV_JOIN, dev);
 
        err = dev_set_allmulti(dev, 1);
-       if (err)
-               goto put_back;
+       if (err) {
+               kfree(p);       /* kobject not yet init'd, manually free */
+               goto err1;
+       }
 
        err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj),
                                   SYSFS_BRIDGE_PORT_ATTR);
        if (err)
-               goto err1;
+               goto err2;
 
        err = br_sysfs_addif(p);
        if (err)
@@ -700,12 +702,9 @@ err3:
        sysfs_remove_link(br->ifobj, p->dev->name);
 err2:
        kobject_put(&p->kobj);
-       p = NULL; /* kobject_put frees */
-err1:
        dev_set_allmulti(dev, -1);
-put_back:
+err1:
        dev_put(dev);
-       kfree(p);
        return err;
 }
 
index 4e0091311d40227694704db18b42e6911544cfc5..6b07e4978eb3f9af753e7683bd3b7518e3594b03 100644 (file)
@@ -2153,7 +2153,9 @@ static int compat_copy_entries(unsigned char *data, unsigned int size_user,
        if (ret < 0)
                return ret;
 
-       WARN_ON(size_remaining);
+       if (size_remaining)
+               return -EINVAL;
+
        return state->buf_kern_offset;
 }
 
index 2105a6eaa66cdaa038e43363341d3dff2896d1a9..4cc28541281befa29f67317c399e376b33c99624 100644 (file)
@@ -271,7 +271,7 @@ static int decode_locker(void **p, void *end, struct ceph_locker *locker)
 
        dout("%s %s%llu cookie %s addr %s\n", __func__,
             ENTITY_NAME(locker->id.name), locker->id.cookie,
-            ceph_pr_addr(&locker->info.addr.in_addr));
+            ceph_pr_addr(&locker->info.addr));
        return 0;
 }
 
index 46f65709a6ff8556f00517d462c1abc053aae8a0..63aef9915f759bd447fc6ae365367d2e770afad5 100644 (file)
@@ -46,7 +46,7 @@ static int monmap_show(struct seq_file *s, void *p)
 
                seq_printf(s, "\t%s%lld\t%s\n",
                           ENTITY_NAME(inst->name),
-                          ceph_pr_addr(&inst->addr.in_addr));
+                          ceph_pr_addr(&inst->addr));
        }
        return 0;
 }
@@ -82,7 +82,7 @@ static int osdmap_show(struct seq_file *s, void *p)
                char sb[64];
 
                seq_printf(s, "osd%d\t%s\t%3d%%\t(%s)\t%3d%%\n",
-                          i, ceph_pr_addr(&addr->in_addr),
+                          i, ceph_pr_addr(addr),
                           ((map->osd_weight[i]*100) >> 16),
                           ceph_osdmap_state_str(sb, sizeof(sb), state),
                           ((ceph_get_primary_affinity(map, i)*100) >> 16));
index 3083988ce729dbe01771e9433b7de72e484394f9..cd0b094468b612b7bdb8231ddef8fa9847cf2dd5 100644 (file)
@@ -186,17 +186,18 @@ static atomic_t addr_str_seq = ATOMIC_INIT(0);
 
 static struct page *zero_page;         /* used in certain error cases */
 
-const char *ceph_pr_addr(const struct sockaddr_storage *ss)
+const char *ceph_pr_addr(const struct ceph_entity_addr *addr)
 {
        int i;
        char *s;
-       struct sockaddr_in *in4 = (struct sockaddr_in *) ss;
-       struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) ss;
+       struct sockaddr_storage ss = addr->in_addr; /* align */
+       struct sockaddr_in *in4 = (struct sockaddr_in *)&ss;
+       struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&ss;
 
        i = atomic_inc_return(&addr_str_seq) & ADDR_STR_COUNT_MASK;
        s = addr_str[i];
 
-       switch (ss->ss_family) {
+       switch (ss.ss_family) {
        case AF_INET:
                snprintf(s, MAX_ADDR_STR_LEN, "%pI4:%hu", &in4->sin_addr,
                         ntohs(in4->sin_port));
@@ -209,7 +210,7 @@ const char *ceph_pr_addr(const struct sockaddr_storage *ss)
 
        default:
                snprintf(s, MAX_ADDR_STR_LEN, "(unknown sockaddr family %hu)",
-                        ss->ss_family);
+                        ss.ss_family);
        }
 
        return s;
@@ -449,7 +450,7 @@ static void set_sock_callbacks(struct socket *sock,
  */
 static int ceph_tcp_connect(struct ceph_connection *con)
 {
-       struct sockaddr_storage *paddr = &con->peer_addr.in_addr;
+       struct sockaddr_storage ss = con->peer_addr.in_addr; /* align */
        struct socket *sock;
        unsigned int noio_flag;
        int ret;
@@ -458,7 +459,7 @@ static int ceph_tcp_connect(struct ceph_connection *con)
 
        /* sock_create_kern() allocates with GFP_KERNEL */
        noio_flag = memalloc_noio_save();
-       ret = sock_create_kern(read_pnet(&con->msgr->net), paddr->ss_family,
+       ret = sock_create_kern(read_pnet(&con->msgr->net), ss.ss_family,
                               SOCK_STREAM, IPPROTO_TCP, &sock);
        memalloc_noio_restore(noio_flag);
        if (ret)
@@ -471,18 +472,18 @@ static int ceph_tcp_connect(struct ceph_connection *con)
 
        set_sock_callbacks(sock, con);
 
-       dout("connect %s\n", ceph_pr_addr(&con->peer_addr.in_addr));
+       dout("connect %s\n", ceph_pr_addr(&con->peer_addr));
 
        con_sock_state_connecting(con);
-       ret = sock->ops->connect(sock, (struct sockaddr *)paddr, sizeof(*paddr),
+       ret = sock->ops->connect(sock, (struct sockaddr *)&ss, sizeof(ss),
                                 O_NONBLOCK);
        if (ret == -EINPROGRESS) {
                dout("connect %s EINPROGRESS sk_state = %u\n",
-                    ceph_pr_addr(&con->peer_addr.in_addr),
+                    ceph_pr_addr(&con->peer_addr),
                     sock->sk->sk_state);
        } else if (ret < 0) {
                pr_err("connect %s error %d\n",
-                      ceph_pr_addr(&con->peer_addr.in_addr), ret);
+                      ceph_pr_addr(&con->peer_addr), ret);
                sock_release(sock);
                return ret;
        }
@@ -669,8 +670,7 @@ static void reset_connection(struct ceph_connection *con)
 void ceph_con_close(struct ceph_connection *con)
 {
        mutex_lock(&con->mutex);
-       dout("con_close %p peer %s\n", con,
-            ceph_pr_addr(&con->peer_addr.in_addr));
+       dout("con_close %p peer %s\n", con, ceph_pr_addr(&con->peer_addr));
        con->state = CON_STATE_CLOSED;
 
        con_flag_clear(con, CON_FLAG_LOSSYTX);  /* so we retry next connect */
@@ -694,7 +694,7 @@ void ceph_con_open(struct ceph_connection *con,
                   struct ceph_entity_addr *addr)
 {
        mutex_lock(&con->mutex);
-       dout("con_open %p %s\n", con, ceph_pr_addr(&addr->in_addr));
+       dout("con_open %p %s\n", con, ceph_pr_addr(addr));
 
        WARN_ON(con->state != CON_STATE_CLOSED);
        con->state = CON_STATE_PREOPEN;
@@ -1788,21 +1788,22 @@ static int verify_hello(struct ceph_connection *con)
 {
        if (memcmp(con->in_banner, CEPH_BANNER, strlen(CEPH_BANNER))) {
                pr_err("connect to %s got bad banner\n",
-                      ceph_pr_addr(&con->peer_addr.in_addr));
+                      ceph_pr_addr(&con->peer_addr));
                con->error_msg = "protocol error, bad banner";
                return -1;
        }
        return 0;
 }
 
-static bool addr_is_blank(struct sockaddr_storage *ss)
+static bool addr_is_blank(struct ceph_entity_addr *addr)
 {
-       struct in_addr *addr = &((struct sockaddr_in *)ss)->sin_addr;
-       struct in6_addr *addr6 = &((struct sockaddr_in6 *)ss)->sin6_addr;
+       struct sockaddr_storage ss = addr->in_addr; /* align */
+       struct in_addr *addr4 = &((struct sockaddr_in *)&ss)->sin_addr;
+       struct in6_addr *addr6 = &((struct sockaddr_in6 *)&ss)->sin6_addr;
 
-       switch (ss->ss_family) {
+       switch (ss.ss_family) {
        case AF_INET:
-               return addr->s_addr == htonl(INADDR_ANY);
+               return addr4->s_addr == htonl(INADDR_ANY);
        case AF_INET6:
                return ipv6_addr_any(addr6);
        default:
@@ -1810,25 +1811,25 @@ static bool addr_is_blank(struct sockaddr_storage *ss)
        }
 }
 
-static int addr_port(struct sockaddr_storage *ss)
+static int addr_port(struct ceph_entity_addr *addr)
 {
-       switch (ss->ss_family) {
+       switch (get_unaligned(&addr->in_addr.ss_family)) {
        case AF_INET:
-               return ntohs(((struct sockaddr_in *)ss)->sin_port);
+               return ntohs(get_unaligned(&((struct sockaddr_in *)&addr->in_addr)->sin_port));
        case AF_INET6:
-               return ntohs(((struct sockaddr_in6 *)ss)->sin6_port);
+               return ntohs(get_unaligned(&((struct sockaddr_in6 *)&addr->in_addr)->sin6_port));
        }
        return 0;
 }
 
-static void addr_set_port(struct sockaddr_storage *ss, int p)
+static void addr_set_port(struct ceph_entity_addr *addr, int p)
 {
-       switch (ss->ss_family) {
+       switch (get_unaligned(&addr->in_addr.ss_family)) {
        case AF_INET:
-               ((struct sockaddr_in *)ss)->sin_port = htons(p);
+               put_unaligned(htons(p), &((struct sockaddr_in *)&addr->in_addr)->sin_port);
                break;
        case AF_INET6:
-               ((struct sockaddr_in6 *)ss)->sin6_port = htons(p);
+               put_unaligned(htons(p), &((struct sockaddr_in6 *)&addr->in_addr)->sin6_port);
                break;
        }
 }
@@ -1836,21 +1837,18 @@ static void addr_set_port(struct sockaddr_storage *ss, int p)
 /*
  * Unlike other *_pton function semantics, zero indicates success.
  */
-static int ceph_pton(const char *str, size_t len, struct sockaddr_storage *ss,
+static int ceph_pton(const char *str, size_t len, struct ceph_entity_addr *addr,
                char delim, const char **ipend)
 {
-       struct sockaddr_in *in4 = (struct sockaddr_in *) ss;
-       struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) ss;
+       memset(&addr->in_addr, 0, sizeof(addr->in_addr));
 
-       memset(ss, 0, sizeof(*ss));
-
-       if (in4_pton(str, len, (u8 *)&in4->sin_addr.s_addr, delim, ipend)) {
-               ss->ss_family = AF_INET;
+       if (in4_pton(str, len, (u8 *)&((struct sockaddr_in *)&addr->in_addr)->sin_addr.s_addr, delim, ipend)) {
+               put_unaligned(AF_INET, &addr->in_addr.ss_family);
                return 0;
        }
 
-       if (in6_pton(str, len, (u8 *)&in6->sin6_addr.s6_addr, delim, ipend)) {
-               ss->ss_family = AF_INET6;
+       if (in6_pton(str, len, (u8 *)&((struct sockaddr_in6 *)&addr->in_addr)->sin6_addr.s6_addr, delim, ipend)) {
+               put_unaligned(AF_INET6, &addr->in_addr.ss_family);
                return 0;
        }
 
@@ -1862,7 +1860,7 @@ static int ceph_pton(const char *str, size_t len, struct sockaddr_storage *ss,
  */
 #ifdef CONFIG_CEPH_LIB_USE_DNS_RESOLVER
 static int ceph_dns_resolve_name(const char *name, size_t namelen,
-               struct sockaddr_storage *ss, char delim, const char **ipend)
+               struct ceph_entity_addr *addr, char delim, const char **ipend)
 {
        const char *end, *delim_p;
        char *colon_p, *ip_addr = NULL;
@@ -1889,9 +1887,9 @@ static int ceph_dns_resolve_name(const char *name, size_t namelen,
                return -EINVAL;
 
        /* do dns_resolve upcall */
-       ip_len = dns_query(NULL, name, end - name, NULL, &ip_addr, NULL);
+       ip_len = dns_query(NULL, name, end - name, NULL, &ip_addr, NULL, false);
        if (ip_len > 0)
-               ret = ceph_pton(ip_addr, ip_len, ss, -1, NULL);
+               ret = ceph_pton(ip_addr, ip_len, addr, -1, NULL);
        else
                ret = -ESRCH;
 
@@ -1900,13 +1898,13 @@ static int ceph_dns_resolve_name(const char *name, size_t namelen,
        *ipend = end;
 
        pr_info("resolve '%.*s' (ret=%d): %s\n", (int)(end - name), name,
-                       ret, ret ? "failed" : ceph_pr_addr(ss));
+                       ret, ret ? "failed" : ceph_pr_addr(addr));
 
        return ret;
 }
 #else
 static inline int ceph_dns_resolve_name(const char *name, size_t namelen,
-               struct sockaddr_storage *ss, char delim, const char **ipend)
+               struct ceph_entity_addr *addr, char delim, const char **ipend)
 {
        return -EINVAL;
 }
@@ -1917,13 +1915,13 @@ static inline int ceph_dns_resolve_name(const char *name, size_t namelen,
  * then try to extract a hostname to resolve using userspace DNS upcall.
  */
 static int ceph_parse_server_name(const char *name, size_t namelen,
-                       struct sockaddr_storage *ss, char delim, const char **ipend)
+               struct ceph_entity_addr *addr, char delim, const char **ipend)
 {
        int ret;
 
-       ret = ceph_pton(name, namelen, ss, delim, ipend);
+       ret = ceph_pton(name, namelen, addr, delim, ipend);
        if (ret)
-               ret = ceph_dns_resolve_name(name, namelen, ss, delim, ipend);
+               ret = ceph_dns_resolve_name(name, namelen, addr, delim, ipend);
 
        return ret;
 }
@@ -1942,7 +1940,6 @@ int ceph_parse_ips(const char *c, const char *end,
        dout("parse_ips on '%.*s'\n", (int)(end-c), c);
        for (i = 0; i < max_count; i++) {
                const char *ipend;
-               struct sockaddr_storage *ss = &addr[i].in_addr;
                int port;
                char delim = ',';
 
@@ -1951,7 +1948,7 @@ int ceph_parse_ips(const char *c, const char *end,
                        p++;
                }
 
-               ret = ceph_parse_server_name(p, end - p, ss, delim, &ipend);
+               ret = ceph_parse_server_name(p, end - p, &addr[i], delim, &ipend);
                if (ret)
                        goto bad;
                ret = -EINVAL;
@@ -1982,9 +1979,9 @@ int ceph_parse_ips(const char *c, const char *end,
                        port = CEPH_MON_PORT;
                }
 
-               addr_set_port(ss, port);
+               addr_set_port(&addr[i], port);
 
-               dout("parse_ips got %s\n", ceph_pr_addr(ss));
+               dout("parse_ips got %s\n", ceph_pr_addr(&addr[i]));
 
                if (p == end)
                        break;
@@ -2023,12 +2020,12 @@ static int process_banner(struct ceph_connection *con)
         */
        if (memcmp(&con->peer_addr, &con->actual_peer_addr,
                   sizeof(con->peer_addr)) != 0 &&
-           !(addr_is_blank(&con->actual_peer_addr.in_addr) &&
+           !(addr_is_blank(&con->actual_peer_addr) &&
              con->actual_peer_addr.nonce == con->peer_addr.nonce)) {
                pr_warn("wrong peer, want %s/%d, got %s/%d\n",
-                       ceph_pr_addr(&con->peer_addr.in_addr),
+                       ceph_pr_addr(&con->peer_addr),
                        (int)le32_to_cpu(con->peer_addr.nonce),
-                       ceph_pr_addr(&con->actual_peer_addr.in_addr),
+                       ceph_pr_addr(&con->actual_peer_addr),
                        (int)le32_to_cpu(con->actual_peer_addr.nonce));
                con->error_msg = "wrong peer at address";
                return -1;
@@ -2037,16 +2034,16 @@ static int process_banner(struct ceph_connection *con)
        /*
         * did we learn our address?
         */
-       if (addr_is_blank(&con->msgr->inst.addr.in_addr)) {
-               int port = addr_port(&con->msgr->inst.addr.in_addr);
+       if (addr_is_blank(&con->msgr->inst.addr)) {
+               int port = addr_port(&con->msgr->inst.addr);
 
                memcpy(&con->msgr->inst.addr.in_addr,
                       &con->peer_addr_for_me.in_addr,
                       sizeof(con->peer_addr_for_me.in_addr));
-               addr_set_port(&con->msgr->inst.addr.in_addr, port);
+               addr_set_port(&con->msgr->inst.addr, port);
                encode_my_addr(con->msgr);
                dout("process_banner learned my addr is %s\n",
-                    ceph_pr_addr(&con->msgr->inst.addr.in_addr));
+                    ceph_pr_addr(&con->msgr->inst.addr));
        }
 
        return 0;
@@ -2097,7 +2094,7 @@ static int process_connect(struct ceph_connection *con)
                pr_err("%s%lld %s feature set mismatch,"
                       " my %llx < server's %llx, missing %llx\n",
                       ENTITY_NAME(con->peer_name),
-                      ceph_pr_addr(&con->peer_addr.in_addr),
+                      ceph_pr_addr(&con->peer_addr),
                       sup_feat, server_feat, server_feat & ~sup_feat);
                con->error_msg = "missing required protocol features";
                reset_connection(con);
@@ -2107,7 +2104,7 @@ static int process_connect(struct ceph_connection *con)
                pr_err("%s%lld %s protocol version mismatch,"
                       " my %d != server's %d\n",
                       ENTITY_NAME(con->peer_name),
-                      ceph_pr_addr(&con->peer_addr.in_addr),
+                      ceph_pr_addr(&con->peer_addr),
                       le32_to_cpu(con->out_connect.protocol_version),
                       le32_to_cpu(con->in_reply.protocol_version));
                con->error_msg = "protocol version mismatch";
@@ -2141,7 +2138,7 @@ static int process_connect(struct ceph_connection *con)
                     le32_to_cpu(con->in_reply.connect_seq));
                pr_err("%s%lld %s connection reset\n",
                       ENTITY_NAME(con->peer_name),
-                      ceph_pr_addr(&con->peer_addr.in_addr));
+                      ceph_pr_addr(&con->peer_addr));
                reset_connection(con);
                con_out_kvec_reset(con);
                ret = prepare_write_connect(con);
@@ -2198,7 +2195,7 @@ static int process_connect(struct ceph_connection *con)
                        pr_err("%s%lld %s protocol feature mismatch,"
                               " my required %llx > server's %llx, need %llx\n",
                               ENTITY_NAME(con->peer_name),
-                              ceph_pr_addr(&con->peer_addr.in_addr),
+                              ceph_pr_addr(&con->peer_addr),
                               req_feat, server_feat, req_feat & ~server_feat);
                        con->error_msg = "missing required protocol features";
                        reset_connection(con);
@@ -2405,7 +2402,7 @@ static int read_partial_message(struct ceph_connection *con)
        if ((s64)seq - (s64)con->in_seq < 1) {
                pr_info("skipping %s%lld %s seq %lld expected %lld\n",
                        ENTITY_NAME(con->peer_name),
-                       ceph_pr_addr(&con->peer_addr.in_addr),
+                       ceph_pr_addr(&con->peer_addr),
                        seq, con->in_seq + 1);
                con->in_base_pos = -front_len - middle_len - data_len -
                        sizeof_footer(con);
@@ -2984,10 +2981,10 @@ static void ceph_con_workfn(struct work_struct *work)
 static void con_fault(struct ceph_connection *con)
 {
        dout("fault %p state %lu to peer %s\n",
-            con, con->state, ceph_pr_addr(&con->peer_addr.in_addr));
+            con, con->state, ceph_pr_addr(&con->peer_addr));
 
        pr_warn("%s%lld %s %s\n", ENTITY_NAME(con->peer_name),
-               ceph_pr_addr(&con->peer_addr.in_addr), con->error_msg);
+               ceph_pr_addr(&con->peer_addr), con->error_msg);
        con->error_msg = NULL;
 
        WARN_ON(con->state != CON_STATE_CONNECTING &&
index a53e4fbb631918ccf94536849e5e25acad2dfdc6..895679d3529b8e3b77fcbcc3f9b88c5204239087 100644 (file)
@@ -76,7 +76,7 @@ struct ceph_monmap *ceph_monmap_decode(void *p, void *end)
             m->num_mon);
        for (i = 0; i < m->num_mon; i++)
                dout("monmap_decode  mon%d is %s\n", i,
-                    ceph_pr_addr(&m->mon_inst[i].addr.in_addr));
+                    ceph_pr_addr(&m->mon_inst[i].addr));
        return m;
 
 bad:
@@ -203,7 +203,7 @@ static void reopen_session(struct ceph_mon_client *monc)
 {
        if (!monc->hunting)
                pr_info("mon%d %s session lost, hunting for new mon\n",
-                   monc->cur_mon, ceph_pr_addr(&monc->con.peer_addr.in_addr));
+                   monc->cur_mon, ceph_pr_addr(&monc->con.peer_addr));
 
        __close_session(monc);
        __open_session(monc);
@@ -1178,7 +1178,7 @@ static void handle_auth_reply(struct ceph_mon_client *monc,
                __resend_generic_request(monc);
 
                pr_info("mon%d %s session established\n", monc->cur_mon,
-                       ceph_pr_addr(&monc->con.peer_addr.in_addr));
+                       ceph_pr_addr(&monc->con.peer_addr));
        }
 
 out:
index 6f739de28918638f737bc13f6ed53a786883781e..9a8eca5eda654d8bdc9ba1480d826453917078e1 100644 (file)
@@ -4926,7 +4926,7 @@ static int decode_watcher(void **p, void *end, struct ceph_watch_item *item)
 
        dout("%s %s%llu cookie %llu addr %s\n", __func__,
             ENTITY_NAME(item->name), item->cookie,
-            ceph_pr_addr(&item->addr.in_addr));
+            ceph_pr_addr(&item->addr));
        return 0;
 }
 
index d3736f5bffec695aa94ea6dfb05be8319a3d195f..74cafc0142ea70890176803f001acf9a0565c448 100644 (file)
@@ -27,7 +27,7 @@ struct page **ceph_get_direct_page_vector(const void __user *data,
        while (got < num_pages) {
                rc = get_user_pages_fast(
                    (unsigned long)data + ((unsigned long)got * PAGE_SIZE),
-                   num_pages - got, write_page, pages + got);
+                   num_pages - got, write_page ? FOLL_WRITE : 0, pages + got);
                if (rc < 0)
                        break;
                BUG_ON(rc == 0);
index 9ca784c592ac8c9c58282289a81889fbe4658a9e..548f39dde30711ac5be9e921993a6d8e53f74161 100644 (file)
@@ -734,7 +734,9 @@ bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx,
        flow_keys->nhoff = nhoff;
        flow_keys->thoff = flow_keys->nhoff;
 
+       preempt_disable();
        result = BPF_PROG_RUN(prog, ctx);
+       preempt_enable();
 
        flow_keys->nhoff = clamp_t(u16, flow_keys->nhoff, nhoff, hlen);
        flow_keys->thoff = clamp_t(u16, flow_keys->thoff,
index 0e2f71ab8367794ac3b059120713cb7495079ee2..5dd85ec51bfef3552dc6bfd3e7697bd42ef99bd6 100644 (file)
@@ -263,7 +263,6 @@ int dccp_disconnect(struct sock *sk, int flags)
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct inet_sock *inet = inet_sk(sk);
        struct dccp_sock *dp = dccp_sk(sk);
-       int err = 0;
        const int old_state = sk->sk_state;
 
        if (old_state != DCCP_CLOSED)
@@ -307,7 +306,7 @@ int dccp_disconnect(struct sock *sk, int flags)
        WARN_ON(inet->inet_num && !icsk->icsk_bind_hash);
 
        sk->sk_error_report(sk);
-       return err;
+       return 0;
 }
 
 EXPORT_SYMBOL_GPL(dccp_disconnect);
index 19aa32fc1802b44a971eecd6f7b9f967ec2900d9..2d260432b3be0a7ddefbd6cb68c2bb2b18163525 100644 (file)
@@ -54,6 +54,7 @@
  * @options: Request options (or NULL if no options)
  * @_result: Where to place the returned data (or NULL)
  * @_expiry: Where to store the result expiry time (or NULL)
+ * @invalidate: Always invalidate the key after use
  *
  * The data will be returned in the pointer at *result, if provided, and the
  * caller is responsible for freeing it.
@@ -69,7 +70,8 @@
  * Returns the size of the result on success, -ve error code otherwise.
  */
 int dns_query(const char *type, const char *name, size_t namelen,
-             const char *options, char **_result, time64_t *_expiry)
+             const char *options, char **_result, time64_t *_expiry,
+             bool invalidate)
 {
        struct key *rkey;
        struct user_key_payload *upayload;
@@ -157,6 +159,8 @@ int dns_query(const char *type, const char *name, size_t namelen,
        ret = len;
 put:
        up_read(&rkey->sem);
+       if (invalidate)
+               key_invalidate(rkey);
        key_put(rkey);
 out:
        kleave(" = %d", ret);
index fe7b6a62e8f1dba6857cdc051826d71ee67fdb8c..9892ca1f6859a81b360dddd8b162d843b019b4b7 100644 (file)
@@ -463,6 +463,8 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
        s->tx_bytes += skb->len;
        u64_stats_update_end(&s->syncp);
 
+       DSA_SKB_CB(skb)->deferred_xmit = false;
+
        /* Identify PTP protocol packets, clone them, and pass them to the
         * switch driver
         */
index d52db5f2c72171cdc8f5a1b389642362170a4913..9c311417969072c415f2896a966d32f4b6a36d12 100644 (file)
@@ -206,10 +206,10 @@ static const struct dsa_device_ops brcm_prepend_netdev_ops = {
        .rcv    = brcm_tag_rcv_prepend,
        .overhead = BRCM_TAG_LEN,
 };
-#endif
 
 DSA_TAG_DRIVER(brcm_prepend_netdev_ops);
 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_PREPEND);
+#endif
 
 static struct dsa_tag_driver *dsa_tag_driver_array[] = {
 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM)
index 71f06900473e9181b2d58b1daa9d42352c7382e6..b96fd3f5470582c28d231438ce0cd5695c308d1b 100644 (file)
@@ -163,7 +163,7 @@ nf_hook_entries_grow(const struct nf_hook_entries *old,
 
 static void hooks_validate(const struct nf_hook_entries *hooks)
 {
-#ifdef CONFIG_DEBUG_KERNEL
+#ifdef CONFIG_DEBUG_MISC
        struct nf_hook_ops **orig_ops;
        int prio = INT_MIN;
        size_t i = 0;
index 1601275efe2d10491c9e05f4892518deca0fa527..4c2ef42e189cbdffef8708cfac9ab55a90a1c275 100644 (file)
@@ -172,7 +172,7 @@ static int nf_h323_error_boundary(struct bitstr *bs, size_t bytes, size_t bits)
        if (bits % BITS_PER_BYTE > 0)
                bytes++;
 
-       if (*bs->cur + bytes > *bs->end)
+       if (bs->cur + bytes > bs->end)
                return 1;
 
        return 0;
index 005589c6d0f6a19b0ea9a6b3ff97948bd483d17e..12de40390e9745f484cc3e6d9de2cb8fc8db364f 100644 (file)
@@ -748,24 +748,19 @@ static int callforward_do_filter(struct net *net,
                }
                break;
        }
-#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
+#if IS_ENABLED(CONFIG_IPV6)
        case AF_INET6: {
-               const struct nf_ipv6_ops *v6ops;
                struct rt6_info *rt1, *rt2;
                struct flowi6 fl1, fl2;
 
-               v6ops = nf_get_ipv6_ops();
-               if (!v6ops)
-                       return 0;
-
                memset(&fl1, 0, sizeof(fl1));
                fl1.daddr = src->in6;
 
                memset(&fl2, 0, sizeof(fl2));
                fl2.daddr = dst->in6;
-               if (!v6ops->route(net, (struct dst_entry **)&rt1,
+               if (!nf_ip6_route(net, (struct dst_entry **)&rt1,
                                  flowi6_to_flowi(&fl1), false)) {
-                       if (!v6ops->route(net, (struct dst_entry **)&rt2,
+                       if (!nf_ip6_route(net, (struct dst_entry **)&rt2,
                                          flowi6_to_flowi(&fl2), false)) {
                                if (ipv6_addr_equal(rt6_nexthop(rt1, &fl1.daddr),
                                                    rt6_nexthop(rt2, &fl2.daddr)) &&
index 8dcc064d518dc8e779ef3d77b278bce7f0b7d6c6..7db79c1b80847c072da6bd8b3008b4d61ac6b55a 100644 (file)
@@ -1256,7 +1256,7 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
        struct nf_conntrack_tuple tuple;
        struct nf_conn *ct;
        struct nfgenmsg *nfmsg = nlmsg_data(nlh);
-       u_int8_t u3 = nfmsg->nfgen_family;
+       u_int8_t u3 = nfmsg->version ? nfmsg->nfgen_family : AF_UNSPEC;
        struct nf_conntrack_zone zone;
        int err;
 
index 7aabfd4b1e50b72183d4fe2ff3072228f12fed16..4469519a48790aff617c15581d7472fed59939cb 100644 (file)
@@ -185,14 +185,25 @@ static const struct rhashtable_params nf_flow_offload_rhash_params = {
 
 int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
 {
-       flow->timeout = (u32)jiffies;
+       int err;
 
-       rhashtable_insert_fast(&flow_table->rhashtable,
-                              &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node,
-                              nf_flow_offload_rhash_params);
-       rhashtable_insert_fast(&flow_table->rhashtable,
-                              &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node,
-                              nf_flow_offload_rhash_params);
+       err = rhashtable_insert_fast(&flow_table->rhashtable,
+                                    &flow->tuplehash[0].node,
+                                    nf_flow_offload_rhash_params);
+       if (err < 0)
+               return err;
+
+       err = rhashtable_insert_fast(&flow_table->rhashtable,
+                                    &flow->tuplehash[1].node,
+                                    nf_flow_offload_rhash_params);
+       if (err < 0) {
+               rhashtable_remove_fast(&flow_table->rhashtable,
+                                      &flow->tuplehash[0].node,
+                                      nf_flow_offload_rhash_params);
+               return err;
+       }
+
+       flow->timeout = (u32)jiffies;
        return 0;
 }
 EXPORT_SYMBOL_GPL(flow_offload_add);
@@ -232,6 +243,7 @@ flow_offload_lookup(struct nf_flowtable *flow_table,
 {
        struct flow_offload_tuple_rhash *tuplehash;
        struct flow_offload *flow;
+       struct flow_offload_entry *e;
        int dir;
 
        tuplehash = rhashtable_lookup(&flow_table->rhashtable, tuple,
@@ -244,6 +256,10 @@ flow_offload_lookup(struct nf_flowtable *flow_table,
        if (flow->flags & (FLOW_OFFLOAD_DYING | FLOW_OFFLOAD_TEARDOWN))
                return NULL;
 
+       e = container_of(flow, struct flow_offload_entry, flow);
+       if (unlikely(nf_ct_is_dying(e->ct)))
+               return NULL;
+
        return tuplehash;
 }
 EXPORT_SYMBOL_GPL(flow_offload_lookup);
@@ -290,8 +306,10 @@ static inline bool nf_flow_has_expired(const struct flow_offload *flow)
 static void nf_flow_offload_gc_step(struct flow_offload *flow, void *data)
 {
        struct nf_flowtable *flow_table = data;
+       struct flow_offload_entry *e;
 
-       if (nf_flow_has_expired(flow) ||
+       e = container_of(flow, struct flow_offload_entry, flow);
+       if (nf_flow_has_expired(flow) || nf_ct_is_dying(e->ct) ||
            (flow->flags & (FLOW_OFFLOAD_DYING | FLOW_OFFLOAD_TEARDOWN)))
                flow_offload_del(flow_table, flow);
 }
index 6452550d187fecd919c483cea627ed1adbf274cc..0d603e20b519fe082a32c3fb31a74819a0acb8ef 100644 (file)
@@ -181,6 +181,9 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
            iph->protocol != IPPROTO_UDP)
                return -1;
 
+       if (iph->ttl <= 1)
+               return -1;
+
        thoff = iph->ihl * 4;
        if (!pskb_may_pull(skb, thoff + sizeof(*ports)))
                return -1;
@@ -408,6 +411,9 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
            ip6h->nexthdr != IPPROTO_UDP)
                return -1;
 
+       if (ip6h->hop_limit <= 1)
+               return -1;
+
        thoff = sizeof(*ip6h);
        if (!pskb_may_pull(skb, thoff + sizeof(*ports)))
                return -1;
index d98416e83d4ef2299d24c341c76642cef5f8e15d..28241e82fd150c5aff18c8079118e7f2769ca09a 100644 (file)
@@ -213,33 +213,33 @@ static int nft_deltable(struct nft_ctx *ctx)
        return err;
 }
 
-static int nft_trans_chain_add(struct nft_ctx *ctx, int msg_type)
+static struct nft_trans *nft_trans_chain_add(struct nft_ctx *ctx, int msg_type)
 {
        struct nft_trans *trans;
 
        trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_chain));
        if (trans == NULL)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        if (msg_type == NFT_MSG_NEWCHAIN)
                nft_activate_next(ctx->net, ctx->chain);
 
        list_add_tail(&trans->list, &ctx->net->nft.commit_list);
-       return 0;
+       return trans;
 }
 
 static int nft_delchain(struct nft_ctx *ctx)
 {
-       int err;
+       struct nft_trans *trans;
 
-       err = nft_trans_chain_add(ctx, NFT_MSG_DELCHAIN);
-       if (err < 0)
-               return err;
+       trans = nft_trans_chain_add(ctx, NFT_MSG_DELCHAIN);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
 
        ctx->table->use--;
        nft_deactivate_next(ctx->net, ctx->chain);
 
-       return err;
+       return 0;
 }
 
 static void nft_rule_expr_activate(const struct nft_ctx *ctx,
@@ -1189,6 +1189,9 @@ static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats)
        u64 pkts, bytes;
        int cpu;
 
+       if (!stats)
+               return 0;
+
        memset(&total, 0, sizeof(total));
        for_each_possible_cpu(cpu) {
                cpu_stats = per_cpu_ptr(stats, cpu);
@@ -1246,6 +1249,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
        if (nft_is_base_chain(chain)) {
                const struct nft_base_chain *basechain = nft_base_chain(chain);
                const struct nf_hook_ops *ops = &basechain->ops;
+               struct nft_stats __percpu *stats;
                struct nlattr *nest;
 
                nest = nla_nest_start_noflag(skb, NFTA_CHAIN_HOOK);
@@ -1267,8 +1271,9 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
                if (nla_put_string(skb, NFTA_CHAIN_TYPE, basechain->type->name))
                        goto nla_put_failure;
 
-               if (rcu_access_pointer(basechain->stats) &&
-                   nft_dump_stats(skb, rcu_dereference(basechain->stats)))
+               stats = rcu_dereference_check(basechain->stats,
+                                             lockdep_commit_lock_is_held(net));
+               if (nft_dump_stats(skb, stats))
                        goto nla_put_failure;
        }
 
@@ -1615,6 +1620,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
        struct nft_base_chain *basechain;
        struct nft_stats __percpu *stats;
        struct net *net = ctx->net;
+       struct nft_trans *trans;
        struct nft_chain *chain;
        struct nft_rule **rules;
        int err;
@@ -1662,7 +1668,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
                ops->dev        = hook.dev;
 
                chain->flags |= NFT_BASE_CHAIN;
-               basechain->policy = policy;
+               basechain->policy = NF_ACCEPT;
        } else {
                chain = kzalloc(sizeof(*chain), GFP_KERNEL);
                if (chain == NULL)
@@ -1698,13 +1704,18 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
        if (err)
                goto err2;
 
-       err = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN);
-       if (err < 0) {
+       trans = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN);
+       if (IS_ERR(trans)) {
+               err = PTR_ERR(trans);
                rhltable_remove(&table->chains_ht, &chain->rhlhead,
                                nft_chain_ht_params);
                goto err2;
        }
 
+       nft_trans_chain_policy(trans) = -1;
+       if (nft_is_base_chain(chain))
+               nft_trans_chain_policy(trans) = policy;
+
        table->use++;
        list_add_tail_rcu(&chain->list, &table->chains);
 
@@ -6310,6 +6321,27 @@ static int nf_tables_validate(struct net *net)
        return 0;
 }
 
+/* a drop policy has to be deferred until all rules have been activated,
+ * otherwise a large ruleset that contains a drop-policy base chain will
+ * cause all packets to get dropped until the full transaction has been
+ * processed.
+ *
+ * We defer the drop policy until the transaction has been finalized.
+ */
+static void nft_chain_commit_drop_policy(struct nft_trans *trans)
+{
+       struct nft_base_chain *basechain;
+
+       if (nft_trans_chain_policy(trans) != NF_DROP)
+               return;
+
+       if (!nft_is_base_chain(trans->ctx.chain))
+               return;
+
+       basechain = nft_base_chain(trans->ctx.chain);
+       basechain->policy = NF_DROP;
+}
+
 static void nft_chain_commit_update(struct nft_trans *trans)
 {
        struct nft_base_chain *basechain;
@@ -6631,6 +6663,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
                                nf_tables_chain_notify(&trans->ctx, NFT_MSG_NEWCHAIN);
                                /* trans destroyed after rcu grace period */
                        } else {
+                               nft_chain_commit_drop_policy(trans);
                                nft_clear(net, trans->ctx.chain);
                                nf_tables_chain_notify(&trans->ctx, NFT_MSG_NEWCHAIN);
                                nft_trans_destroy(trans);
index 6e6b9adf7d387717ff6f99a87093e41478c9889f..69d7a8439c7a11f4d151a428a89e46e9540d3f76 100644 (file)
@@ -94,8 +94,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
        if (help)
                goto out;
 
-       if (ctinfo == IP_CT_NEW ||
-           ctinfo == IP_CT_RELATED)
+       if (!nf_ct_is_confirmed(ct))
                goto out;
 
        if (test_and_set_bit(IPS_OFFLOAD_BIT, &ct->status))
@@ -113,6 +112,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
        if (ret < 0)
                goto err_flow_add;
 
+       dst_release(route.tuple[!dir].dst);
        return;
 
 err_flow_add:
index dd0e97f4f6c021092c3472beab58fde32d35edb5..801872a2e7aa54c22a022ccf275d34deb4a734b1 100644 (file)
@@ -728,12 +728,13 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
        DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, msg->msg_name);
        int (*enqueue_fn)(struct qrtr_node *, struct sk_buff *, int,
                          struct sockaddr_qrtr *, struct sockaddr_qrtr *);
+       __le32 qrtr_type = cpu_to_le32(QRTR_TYPE_DATA);
        struct qrtr_sock *ipc = qrtr_sk(sock->sk);
        struct sock *sk = sock->sk;
        struct qrtr_node *node;
        struct sk_buff *skb;
+       u32 type = 0;
        size_t plen;
-       u32 type = QRTR_TYPE_DATA;
        int rc;
 
        if (msg->msg_flags & ~(MSG_DONTWAIT))
@@ -807,8 +808,8 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
                }
 
                /* control messages already require the type as 'command' */
-               skb_copy_bits(skb, 0, &type, 4);
-               type = le32_to_cpu(type);
+               skb_copy_bits(skb, 0, &qrtr_type, 4);
+               type = le32_to_cpu(qrtr_type);
        }
 
        rc = enqueue_fn(node, skb, type, &ipc->us, addr);
index e367a97a18c805f7e0c6c473e5e273d280acc2fb..03f6fd56d2371c31ea2c1dd12d4a66e9b60a7f53 100644 (file)
@@ -193,7 +193,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
                ret = -ENOMEM;
                goto out;
        }
-       ret = get_user_pages_fast(start, nr_pages, 1, pages);
+       ret = get_user_pages_fast(start, nr_pages, FOLL_WRITE, pages);
        if (ret != nr_pages) {
                if (ret > 0)
                        nr_pages = ret;
index 182ab8430594a967533fe64b44ebe41a97fab83c..b340ed4fc43a89e9199e7265d1b409f470bd17d3 100644 (file)
@@ -158,7 +158,8 @@ static int rds_pin_pages(unsigned long user_addr, unsigned int nr_pages,
 {
        int ret;
 
-       ret = get_user_pages_fast(user_addr, nr_pages, write, pages);
+       ret = get_user_pages_fast(user_addr, nr_pages, write ? FOLL_WRITE : 0,
+                                 pages);
 
        if (ret >= 0 && ret < nr_pages) {
                while (ret--)
index ae8c5d7f3bf1e29460e5b96b05b7b1b1ecd4ce15..ffde5b187f5d19d9975594d1826a2ace1a9fe71c 100644 (file)
@@ -270,6 +270,7 @@ static int rxrpc_listen(struct socket *sock, int backlog)
  * @gfp: The allocation constraints
  * @notify_rx: Where to send notifications instead of socket queue
  * @upgrade: Request service upgrade for call
+ * @intr: The call is interruptible
  * @debug_id: The debug ID for tracing to be assigned to the call
  *
  * Allow a kernel service to begin a call on the nominated socket.  This just
@@ -287,6 +288,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
                                           gfp_t gfp,
                                           rxrpc_notify_rx_t notify_rx,
                                           bool upgrade,
+                                          bool intr,
                                           unsigned int debug_id)
 {
        struct rxrpc_conn_parameters cp;
@@ -311,6 +313,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
        memset(&p, 0, sizeof(p));
        p.user_call_ID = user_call_ID;
        p.tx_total_len = tx_total_len;
+       p.intr = intr;
 
        memset(&cp, 0, sizeof(cp));
        cp.local                = rx->local;
@@ -443,6 +446,31 @@ void rxrpc_kernel_new_call_notification(
 }
 EXPORT_SYMBOL(rxrpc_kernel_new_call_notification);
 
+/**
+ * rxrpc_kernel_set_max_life - Set maximum lifespan on a call
+ * @sock: The socket the call is on
+ * @call: The call to configure
+ * @hard_timeout: The maximum lifespan of the call in jiffies
+ *
+ * Set the maximum lifespan of a call.  The call will end with ETIME or
+ * ETIMEDOUT if it takes longer than this.
+ */
+void rxrpc_kernel_set_max_life(struct socket *sock, struct rxrpc_call *call,
+                              unsigned long hard_timeout)
+{
+       unsigned long now;
+
+       mutex_lock(&call->user_mutex);
+
+       now = jiffies;
+       hard_timeout += now;
+       WRITE_ONCE(call->expect_term_by, hard_timeout);
+       rxrpc_reduce_call_timer(call, hard_timeout, now, rxrpc_timer_set_for_hard);
+
+       mutex_unlock(&call->user_mutex);
+}
+EXPORT_SYMBOL(rxrpc_kernel_set_max_life);
+
 /*
  * connect an RxRPC socket
  * - this just targets it at a specific destination; no actual connection
index 062ca9dc29b8ab2fa7381c606791d4fd39657962..07fc1dfa487890e800598755d2c2c9202be86ccf 100644 (file)
@@ -482,6 +482,7 @@ enum rxrpc_call_flag {
        RXRPC_CALL_BEGAN_RX_TIMER,      /* We began the expect_rx_by timer */
        RXRPC_CALL_RX_HEARD,            /* The peer responded at least once to this call */
        RXRPC_CALL_RX_UNDERRUN,         /* Got data underrun */
+       RXRPC_CALL_IS_INTR,             /* The call is interruptible */
 };
 
 /*
@@ -711,6 +712,7 @@ struct rxrpc_call_params {
                u32             normal;         /* Max time since last call packet (msec) */
        } timeouts;
        u8                      nr_timeouts;    /* Number of timeouts specified */
+       bool                    intr;           /* The call is interruptible */
 };
 
 struct rxrpc_send_params {
index fe96881a334daff644a1f9d01497771f745e9fc8..d0ca98d7aef57691664b2c91350bcae210252332 100644 (file)
@@ -241,6 +241,8 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
                return call;
        }
 
+       if (p->intr)
+               __set_bit(RXRPC_CALL_IS_INTR, &call->flags);
        call->tx_total_len = p->tx_total_len;
        trace_rxrpc_call(call, rxrpc_call_new_client, atomic_read(&call->usage),
                         here, (const void *)p->user_call_ID);
index 83797b3949e2f0122d87d15a48651b3b540ab156..5cf5595a14d8e73408de49bab6765b4c7057a69a 100644 (file)
@@ -656,10 +656,14 @@ static int rxrpc_wait_for_channel(struct rxrpc_call *call, gfp_t gfp)
 
                add_wait_queue_exclusive(&call->waitq, &myself);
                for (;;) {
-                       set_current_state(TASK_INTERRUPTIBLE);
+                       if (test_bit(RXRPC_CALL_IS_INTR, &call->flags))
+                               set_current_state(TASK_INTERRUPTIBLE);
+                       else
+                               set_current_state(TASK_UNINTERRUPTIBLE);
                        if (call->call_id)
                                break;
-                       if (signal_pending(current)) {
+                       if (test_bit(RXRPC_CALL_IS_INTR, &call->flags) &&
+                           signal_pending(current)) {
                                ret = -ERESTARTSYS;
                                break;
                        }
index bec64deb7b0a2794345c896827846fa8bac57e19..45a05d9a27fa122dc03440d6734b229be7c15991 100644 (file)
@@ -80,7 +80,8 @@ static int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx,
                if (call->state >= RXRPC_CALL_COMPLETE)
                        return call->error;
 
-               if (timeout == 0 &&
+               if (test_bit(RXRPC_CALL_IS_INTR, &call->flags) &&
+                   timeout == 0 &&
                    tx_win == tx_start && signal_pending(current))
                        return -EINTR;
 
@@ -620,6 +621,7 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
                .call.tx_total_len      = -1,
                .call.user_call_ID      = 0,
                .call.nr_timeouts       = 0,
+               .call.intr              = true,
                .abort_code             = 0,
                .command                = RXRPC_CMD_SEND_DATA,
                .exclusive              = false,
index 0c5d7896d6dd66eacb23dc1b864abb2592910123..8be2f209982be4b06cad3c3ab7658bd7a1e4aa2e 100644 (file)
@@ -474,12 +474,12 @@ static int rsc_parse(struct cache_detail *cd,
                 * treatment so are checked for validity here.)
                 */
                /* uid */
-               rsci.cred.cr_uid = make_kuid(&init_user_ns, id);
+               rsci.cred.cr_uid = make_kuid(current_user_ns(), id);
 
                /* gid */
                if (get_int(&mesg, &id))
                        goto out;
-               rsci.cred.cr_gid = make_kgid(&init_user_ns, id);
+               rsci.cred.cr_gid = make_kgid(current_user_ns(), id);
 
                /* number of additional gid's */
                if (get_int(&mesg, &N))
@@ -497,7 +497,7 @@ static int rsc_parse(struct cache_detail *cd,
                        kgid_t kgid;
                        if (get_int(&mesg, &id))
                                goto out;
-                       kgid = make_kgid(&init_user_ns, id);
+                       kgid = make_kgid(current_user_ns(), id);
                        if (!gid_valid(kgid))
                                goto out;
                        rsci.cred.cr_group_info->gid[i] = kgid;
index 261131dfa1f1ba3900d85088a6cfde659bbe231a..d223289848537809c0cbde147ade893f7bdd38c2 100644 (file)
@@ -40,6 +40,7 @@
 
 static bool cache_defer_req(struct cache_req *req, struct cache_head *item);
 static void cache_revisit_request(struct cache_head *item);
+static bool cache_listeners_exist(struct cache_detail *detail);
 
 static void cache_init(struct cache_head *h, struct cache_detail *detail)
 {
@@ -306,7 +307,8 @@ int cache_check(struct cache_detail *detail,
                                cache_fresh_unlocked(h, detail);
                                break;
                        }
-               }
+               } else if (!cache_listeners_exist(detail))
+                       rv = try_to_negate_entry(detail, h);
        }
 
        if (rv == -EAGAIN) {
index dbd19697ee38e40d5670e31d2b0392beb66aea2e..2be8278202471360192abe5661fc2ef016945f6d 100644 (file)
@@ -993,6 +993,58 @@ static int __svc_register(struct net *net, const char *progname,
        return error;
 }
 
+int svc_rpcbind_set_version(struct net *net,
+                           const struct svc_program *progp,
+                           u32 version, int family,
+                           unsigned short proto,
+                           unsigned short port)
+{
+       dprintk("svc: svc_register(%sv%d, %s, %u, %u)\n",
+               progp->pg_name, version,
+               proto == IPPROTO_UDP?  "udp" : "tcp",
+               port, family);
+
+       return __svc_register(net, progp->pg_name, progp->pg_prog,
+                               version, family, proto, port);
+
+}
+EXPORT_SYMBOL_GPL(svc_rpcbind_set_version);
+
+int svc_generic_rpcbind_set(struct net *net,
+                           const struct svc_program *progp,
+                           u32 version, int family,
+                           unsigned short proto,
+                           unsigned short port)
+{
+       const struct svc_version *vers = progp->pg_vers[version];
+       int error;
+
+       if (vers == NULL)
+               return 0;
+
+       if (vers->vs_hidden) {
+               dprintk("svc: svc_register(%sv%d, %s, %u, %u)"
+                       " (but not telling portmap)\n",
+                       progp->pg_name, version,
+                       proto == IPPROTO_UDP?  "udp" : "tcp",
+                       port, family);
+               return 0;
+       }
+
+       /*
+        * Don't register a UDP port if we need congestion
+        * control.
+        */
+       if (vers->vs_need_cong_ctrl && proto == IPPROTO_UDP)
+               return 0;
+
+       error = svc_rpcbind_set_version(net, progp, version,
+                                       family, proto, port);
+
+       return (vers->vs_rpcb_optnl) ? 0 : error;
+}
+EXPORT_SYMBOL_GPL(svc_generic_rpcbind_set);
+
 /**
  * svc_register - register an RPC service with the local portmapper
  * @serv: svc_serv struct for the service to register
@@ -1008,7 +1060,6 @@ int svc_register(const struct svc_serv *serv, struct net *net,
                 const unsigned short port)
 {
        struct svc_program      *progp;
-       const struct svc_version *vers;
        unsigned int            i;
        int                     error = 0;
 
@@ -1018,37 +1069,9 @@ int svc_register(const struct svc_serv *serv, struct net *net,
 
        for (progp = serv->sv_program; progp; progp = progp->pg_next) {
                for (i = 0; i < progp->pg_nvers; i++) {
-                       vers = progp->pg_vers[i];
-                       if (vers == NULL)
-                               continue;
-
-                       dprintk("svc: svc_register(%sv%d, %s, %u, %u)%s\n",
-                                       progp->pg_name,
-                                       i,
-                                       proto == IPPROTO_UDP?  "udp" : "tcp",
-                                       port,
-                                       family,
-                                       vers->vs_hidden ?
-                                       " (but not telling portmap)" : "");
-
-                       if (vers->vs_hidden)
-                               continue;
-
-                       /*
-                        * Don't register a UDP port if we need congestion
-                        * control.
-                        */
-                       if (vers->vs_need_cong_ctrl && proto == IPPROTO_UDP)
-                               continue;
-
-                       error = __svc_register(net, progp->pg_name, progp->pg_prog,
-                                               i, family, proto, port);
-
-                       if (vers->vs_rpcb_optnl) {
-                               error = 0;
-                               continue;
-                       }
 
+                       error = progp->pg_rpcbind_set(net, progp, i,
+                                       family, proto, port);
                        if (error < 0) {
                                printk(KERN_WARNING "svc: failed to register "
                                        "%sv%u RPC service (errno %d).\n",
@@ -1144,6 +1167,114 @@ void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...)
 static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {}
 #endif
 
+__be32
+svc_return_autherr(struct svc_rqst *rqstp, __be32 auth_err)
+{
+       set_bit(RQ_AUTHERR, &rqstp->rq_flags);
+       return auth_err;
+}
+EXPORT_SYMBOL_GPL(svc_return_autherr);
+
+static __be32
+svc_get_autherr(struct svc_rqst *rqstp, __be32 *statp)
+{
+       if (test_and_clear_bit(RQ_AUTHERR, &rqstp->rq_flags))
+               return *statp;
+       return rpc_auth_ok;
+}
+
+static int
+svc_generic_dispatch(struct svc_rqst *rqstp, __be32 *statp)
+{
+       struct kvec *argv = &rqstp->rq_arg.head[0];
+       struct kvec *resv = &rqstp->rq_res.head[0];
+       const struct svc_procedure *procp = rqstp->rq_procinfo;
+
+       /*
+        * Decode arguments
+        * XXX: why do we ignore the return value?
+        */
+       if (procp->pc_decode &&
+           !procp->pc_decode(rqstp, argv->iov_base)) {
+               *statp = rpc_garbage_args;
+               return 1;
+       }
+
+       *statp = procp->pc_func(rqstp);
+
+       if (*statp == rpc_drop_reply ||
+           test_bit(RQ_DROPME, &rqstp->rq_flags))
+               return 0;
+
+       if (test_bit(RQ_AUTHERR, &rqstp->rq_flags))
+               return 1;
+
+       if (*statp != rpc_success)
+               return 1;
+
+       /* Encode reply */
+       if (procp->pc_encode &&
+           !procp->pc_encode(rqstp, resv->iov_base + resv->iov_len)) {
+               dprintk("svc: failed to encode reply\n");
+               /* serv->sv_stats->rpcsystemerr++; */
+               *statp = rpc_system_err;
+       }
+       return 1;
+}
+
+__be32
+svc_generic_init_request(struct svc_rqst *rqstp,
+               const struct svc_program *progp,
+               struct svc_process_info *ret)
+{
+       const struct svc_version *versp = NULL; /* compiler food */
+       const struct svc_procedure *procp = NULL;
+
+       if (rqstp->rq_vers >= progp->pg_nvers )
+               goto err_bad_vers;
+         versp = progp->pg_vers[rqstp->rq_vers];
+         if (!versp)
+               goto err_bad_vers;
+
+       /*
+        * Some protocol versions (namely NFSv4) require some form of
+        * congestion control.  (See RFC 7530 section 3.1 paragraph 2)
+        * In other words, UDP is not allowed. We mark those when setting
+        * up the svc_xprt, and verify that here.
+        *
+        * The spec is not very clear about what error should be returned
+        * when someone tries to access a server that is listening on UDP
+        * for lower versions. RPC_PROG_MISMATCH seems to be the closest
+        * fit.
+        */
+       if (versp->vs_need_cong_ctrl && rqstp->rq_xprt &&
+           !test_bit(XPT_CONG_CTRL, &rqstp->rq_xprt->xpt_flags))
+               goto err_bad_vers;
+
+       if (rqstp->rq_proc >= versp->vs_nproc)
+               goto err_bad_proc;
+       rqstp->rq_procinfo = procp = &versp->vs_proc[rqstp->rq_proc];
+       if (!procp)
+               goto err_bad_proc;
+
+       /* Initialize storage for argp and resp */
+       memset(rqstp->rq_argp, 0, procp->pc_argsize);
+       memset(rqstp->rq_resp, 0, procp->pc_ressize);
+
+       /* Bump per-procedure stats counter */
+       versp->vs_count[rqstp->rq_proc]++;
+
+       ret->dispatch = versp->vs_dispatch;
+       return rpc_success;
+err_bad_vers:
+       ret->mismatch.lovers = progp->pg_lovers;
+       ret->mismatch.hivers = progp->pg_hivers;
+       return rpc_prog_mismatch;
+err_bad_proc:
+       return rpc_proc_unavail;
+}
+EXPORT_SYMBOL_GPL(svc_generic_init_request);
+
 /*
  * Common routine for processing the RPC request.
  */
@@ -1151,11 +1282,11 @@ static int
 svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
 {
        struct svc_program      *progp;
-       const struct svc_version *versp = NULL; /* compiler food */
        const struct svc_procedure *procp = NULL;
        struct svc_serv         *serv = rqstp->rq_server;
+       struct svc_process_info process;
        __be32                  *statp;
-       u32                     prog, vers, proc;
+       u32                     prog, vers;
        __be32                  auth_stat, rpc_stat;
        int                     auth_res;
        __be32                  *reply_statp;
@@ -1187,8 +1318,8 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
        svc_putnl(resv, 0);             /* ACCEPT */
 
        rqstp->rq_prog = prog = svc_getnl(argv);        /* program number */
-       rqstp->rq_vers = vers = svc_getnl(argv);        /* version number */
-       rqstp->rq_proc = proc = svc_getnl(argv);        /* procedure number */
+       rqstp->rq_vers = svc_getnl(argv);       /* version number */
+       rqstp->rq_proc = svc_getnl(argv);       /* procedure number */
 
        for (progp = serv->sv_program; progp; progp = progp->pg_next)
                if (prog == progp->pg_prog)
@@ -1226,29 +1357,22 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
        if (progp == NULL)
                goto err_bad_prog;
 
-       if (vers >= progp->pg_nvers ||
-         !(versp = progp->pg_vers[vers]))
-               goto err_bad_vers;
-
-       /*
-        * Some protocol versions (namely NFSv4) require some form of
-        * congestion control.  (See RFC 7530 section 3.1 paragraph 2)
-        * In other words, UDP is not allowed. We mark those when setting
-        * up the svc_xprt, and verify that here.
-        *
-        * The spec is not very clear about what error should be returned
-        * when someone tries to access a server that is listening on UDP
-        * for lower versions. RPC_PROG_MISMATCH seems to be the closest
-        * fit.
-        */
-       if (versp->vs_need_cong_ctrl && rqstp->rq_xprt &&
-           !test_bit(XPT_CONG_CTRL, &rqstp->rq_xprt->xpt_flags))
+       rpc_stat = progp->pg_init_request(rqstp, progp, &process);
+       switch (rpc_stat) {
+       case rpc_success:
+               break;
+       case rpc_prog_unavail:
+               goto err_bad_prog;
+       case rpc_prog_mismatch:
                goto err_bad_vers;
+       case rpc_proc_unavail:
+               goto err_bad_proc;
+       }
 
-       procp = versp->vs_proc + proc;
-       if (proc >= versp->vs_nproc || !procp->pc_func)
+       procp = rqstp->rq_procinfo;
+       /* Should this check go into the dispatcher? */
+       if (!procp || !procp->pc_func)
                goto err_bad_proc;
-       rqstp->rq_procinfo = procp;
 
        /* Syntactic check complete */
        serv->sv_stats->rpccnt++;
@@ -1258,13 +1382,6 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
        statp = resv->iov_base +resv->iov_len;
        svc_putnl(resv, RPC_SUCCESS);
 
-       /* Bump per-procedure stats counter */
-       versp->vs_count[proc]++;
-
-       /* Initialize storage for argp and resp */
-       memset(rqstp->rq_argp, 0, procp->pc_argsize);
-       memset(rqstp->rq_resp, 0, procp->pc_ressize);
-
        /* un-reserve some of the out-queue now that we have a
         * better idea of reply size
         */
@@ -1272,43 +1389,18 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
                svc_reserve_auth(rqstp, procp->pc_xdrressize<<2);
 
        /* Call the function that processes the request. */
-       if (!versp->vs_dispatch) {
-               /*
-                * Decode arguments
-                * XXX: why do we ignore the return value?
-                */
-               if (procp->pc_decode &&
-                   !procp->pc_decode(rqstp, argv->iov_base))
+       if (!process.dispatch) {
+               if (!svc_generic_dispatch(rqstp, statp))
+                       goto release_dropit;
+               if (*statp == rpc_garbage_args)
                        goto err_garbage;
-
-               *statp = procp->pc_func(rqstp);
-
-               /* Encode reply */
-               if (*statp == rpc_drop_reply ||
-                   test_bit(RQ_DROPME, &rqstp->rq_flags)) {
-                       if (procp->pc_release)
-                               procp->pc_release(rqstp);
-                       goto dropit;
-               }
-               if (*statp == rpc_autherr_badcred) {
-                       if (procp->pc_release)
-                               procp->pc_release(rqstp);
-                       goto err_bad_auth;
-               }
-               if (*statp == rpc_success && procp->pc_encode &&
-                   !procp->pc_encode(rqstp, resv->iov_base + resv->iov_len)) {
-                       dprintk("svc: failed to encode reply\n");
-                       /* serv->sv_stats->rpcsystemerr++; */
-                       *statp = rpc_system_err;
-               }
+               auth_stat = svc_get_autherr(rqstp, statp);
+               if (auth_stat != rpc_auth_ok)
+                       goto err_release_bad_auth;
        } else {
                dprintk("svc: calling dispatcher\n");
-               if (!versp->vs_dispatch(rqstp, statp)) {
-                       /* Release reply info */
-                       if (procp->pc_release)
-                               procp->pc_release(rqstp);
-                       goto dropit;
-               }
+               if (!process.dispatch(rqstp, statp))
+                       goto release_dropit; /* Release reply info */
        }
 
        /* Check RPC status result */
@@ -1327,6 +1419,9 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
                goto close;
        return 1;               /* Caller can now send it */
 
+release_dropit:
+       if (procp->pc_release)
+               procp->pc_release(rqstp);
  dropit:
        svc_authorise(rqstp);   /* doesn't hurt to call this twice */
        dprintk("svc: svc_process dropit\n");
@@ -1351,6 +1446,9 @@ err_bad_rpc:
        svc_putnl(resv, 2);
        goto sendit;
 
+err_release_bad_auth:
+       if (procp->pc_release)
+               procp->pc_release(rqstp);
 err_bad_auth:
        dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat));
        serv->sv_stats->rpcbadauth++;
@@ -1369,16 +1467,16 @@ err_bad_prog:
 
 err_bad_vers:
        svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n",
-                      vers, prog, progp->pg_name);
+                      rqstp->rq_vers, rqstp->rq_prog, progp->pg_name);
 
        serv->sv_stats->rpcbadfmt++;
        svc_putnl(resv, RPC_PROG_MISMATCH);
-       svc_putnl(resv, progp->pg_lovers);
-       svc_putnl(resv, progp->pg_hivers);
+       svc_putnl(resv, process.mismatch.lovers);
+       svc_putnl(resv, process.mismatch.hivers);
        goto sendit;
 
 err_bad_proc:
-       svc_printk(rqstp, "unknown procedure (%d)\n", proc);
+       svc_printk(rqstp, "unknown procedure (%d)\n", rqstp->rq_proc);
 
        serv->sv_stats->rpcbadfmt++;
        svc_putnl(resv, RPC_PROC_UNAVAIL);
index 61530b1b7754e53bbc08e54031da2bf9d94090b4..9429b28e9ba0d14b06dbdc65b064809b7aa33947 100644 (file)
@@ -136,6 +136,7 @@ static void svc_xprt_free(struct kref *kref)
        struct module *owner = xprt->xpt_class->xcl_owner;
        if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags))
                svcauth_unix_info_release(xprt);
+       put_cred(xprt->xpt_cred);
        put_net(xprt->xpt_net);
        /* See comment on corresponding get in xs_setup_bc_tcp(): */
        if (xprt->xpt_bc_xprt)
@@ -252,7 +253,8 @@ void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new)
 
 static int _svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
                            struct net *net, const int family,
-                           const unsigned short port, int flags)
+                           const unsigned short port, int flags,
+                           const struct cred *cred)
 {
        struct svc_xprt_class *xcl;
 
@@ -273,6 +275,7 @@ static int _svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
                        module_put(xcl->xcl_owner);
                        return PTR_ERR(newxprt);
                }
+               newxprt->xpt_cred = get_cred(cred);
                svc_add_new_perm_xprt(serv, newxprt);
                newport = svc_xprt_local_port(newxprt);
                return newport;
@@ -286,15 +289,16 @@ static int _svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
 
 int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
                    struct net *net, const int family,
-                   const unsigned short port, int flags)
+                   const unsigned short port, int flags,
+                   const struct cred *cred)
 {
        int err;
 
        dprintk("svc: creating transport %s[%d]\n", xprt_name, port);
-       err = _svc_create_xprt(serv, xprt_name, net, family, port, flags);
+       err = _svc_create_xprt(serv, xprt_name, net, family, port, flags, cred);
        if (err == -EPROTONOSUPPORT) {
                request_module("svc%s", xprt_name);
-               err = _svc_create_xprt(serv, xprt_name, net, family, port, flags);
+               err = _svc_create_xprt(serv, xprt_name, net, family, port, flags, cred);
        }
        if (err < 0)
                dprintk("svc: transport %s not found, err %d\n",
@@ -782,9 +786,10 @@ static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt)
                __module_get(xprt->xpt_class->xcl_owner);
                svc_check_conn_limits(xprt->xpt_server);
                newxpt = xprt->xpt_ops->xpo_accept(xprt);
-               if (newxpt)
+               if (newxpt) {
+                       newxpt->xpt_cred = get_cred(xprt->xpt_cred);
                        svc_add_new_temp_xprt(serv, newxpt);
-               else
+               else
                        module_put(xprt->xpt_class->xcl_owner);
        } else if (svc_xprt_reserve_slot(rqstp, xprt)) {
                /* XPT_DATA|XPT_DEFERRED case: */
index fb9041b92f72233841cf1d173aa1b1cafe91e623..f92ef79c8ea56c70933c5018ae4ae7969fd8d13d 100644 (file)
@@ -500,7 +500,7 @@ static int unix_gid_parse(struct cache_detail *cd,
        rv = get_int(&mesg, &id);
        if (rv)
                return -EINVAL;
-       uid = make_kuid(&init_user_ns, id);
+       uid = make_kuid(current_user_ns(), id);
        ug.uid = uid;
 
        expiry = get_expiry(&mesg);
@@ -522,7 +522,7 @@ static int unix_gid_parse(struct cache_detail *cd,
                err = -EINVAL;
                if (rv)
                        goto out;
-               kgid = make_kgid(&init_user_ns, gid);
+               kgid = make_kgid(current_user_ns(), gid);
                if (!gid_valid(kgid))
                        goto out;
                ug.gi->gid[i] = kgid;
@@ -555,7 +555,7 @@ static int unix_gid_show(struct seq_file *m,
                         struct cache_detail *cd,
                         struct cache_head *h)
 {
-       struct user_namespace *user_ns = &init_user_ns;
+       struct user_namespace *user_ns = m->file->f_cred->user_ns;
        struct unix_gid *ug;
        int i;
        int glen;
@@ -796,6 +796,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
        struct kvec     *argv = &rqstp->rq_arg.head[0];
        struct kvec     *resv = &rqstp->rq_res.head[0];
        struct svc_cred *cred = &rqstp->rq_cred;
+       struct user_namespace *userns;
        u32             slen, i;
        int             len   = argv->iov_len;
 
@@ -816,8 +817,10 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
         * (export-specific) anonymous id by nfsd_setuser.
         * Supplementary gid's will be left alone.
         */
-       cred->cr_uid = make_kuid(&init_user_ns, svc_getnl(argv)); /* uid */
-       cred->cr_gid = make_kgid(&init_user_ns, svc_getnl(argv)); /* gid */
+       userns = (rqstp->rq_xprt && rqstp->rq_xprt->xpt_cred) ?
+               rqstp->rq_xprt->xpt_cred->user_ns : &init_user_ns;
+       cred->cr_uid = make_kuid(userns, svc_getnl(argv)); /* uid */
+       cred->cr_gid = make_kgid(userns, svc_getnl(argv)); /* gid */
        slen = svc_getnl(argv);                 /* gids length */
        if (slen > UNX_NGROUPS || (len -= (slen + 2)*4) < 0)
                goto badcred;
@@ -825,7 +828,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
        if (cred->cr_group_info == NULL)
                return SVC_CLOSE;
        for (i = 0; i < slen; i++) {
-               kgid_t kgid = make_kgid(&init_user_ns, svc_getnl(argv));
+               kgid_t kgid = make_kgid(userns, svc_getnl(argv));
                cred->cr_group_info->gid[i] = kgid;
        }
        groups_sort(cred->cr_group_info);
index 43590a968b734b41b89c55f9fa72366ad1cb01f7..540fde2804d025009b46f8369eecbff9dbffeb13 100644 (file)
@@ -1332,13 +1332,14 @@ EXPORT_SYMBOL_GPL(svc_alien_sock);
  * @fd: file descriptor of the new listener
  * @name_return: pointer to buffer to fill in with name of listener
  * @len: size of the buffer
+ * @cred: credential
  *
  * Fills in socket name and returns positive length of name if successful.
  * Name is terminated with '\n'.  On error, returns a negative errno
  * value.
  */
 int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
-               const size_t len)
+               const size_t len, const struct cred *cred)
 {
        int err = 0;
        struct socket *so = sockfd_lookup(fd, &err);
@@ -1371,6 +1372,7 @@ int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
        salen = kernel_getsockname(svsk->sk_sock, sin);
        if (salen >= 0)
                svc_xprt_set_local(&svsk->sk_xprt, sin, salen);
+       svsk->sk_xprt.xpt_cred = get_cred(cred);
        svc_add_new_perm_xprt(serv, &svsk->sk_xprt);
        return svc_one_sock_name(svsk, name_return, len);
 out:
index 989e52386c358a34a566660933002827ba165068..2b18223e7eb8cd3691290b4d0e7bdf17843bd683 100644 (file)
@@ -253,8 +253,8 @@ static int xdp_umem_pin_pages(struct xdp_umem *umem)
                return -ENOMEM;
 
        down_read(&current->mm->mmap_sem);
-       npgs = get_user_pages_longterm(umem->address, umem->npgs,
-                                      gup_flags, &umem->pgs[0], NULL);
+       npgs = get_user_pages(umem->address, umem->npgs,
+                             gup_flags | FOLL_LONGTERM, &umem->pgs[0], NULL);
        up_read(&current->mm->mmap_sem);
 
        if (npgs != umem->npgs) {
diff --git a/samples/pidfd/.gitignore b/samples/pidfd/.gitignore
new file mode 100644 (file)
index 0000000..be52b3b
--- /dev/null
@@ -0,0 +1 @@
+pidfd-metadata
diff --git a/samples/vfs/.gitignore b/samples/vfs/.gitignore
new file mode 100644 (file)
index 0000000..0806eb0
--- /dev/null
@@ -0,0 +1,2 @@
+test-fsmount
+test-statx
index 5010a4d5bfbabf68af666e1b43693e8656b12789..894cc58c1a0341e76c7b6a117a7f1abefc9ef305 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/python3
 # SPDX-License-Identifier: GPL-2.0-only
 #
-# Copyright (C) 2018 Netronome Systems, Inc.
+# Copyright (C) 2018-2019 Netronome Systems, Inc.
 
 # In case user attempts to run with Python 2.
 from __future__ import print_function
@@ -39,7 +39,7 @@ class Helper(object):
         Break down helper function protocol into smaller chunks: return type,
         name, distincts arguments.
         """
-        arg_re = re.compile('((const )?(struct )?(\w+|...))( (\**)(\w+))?$')
+        arg_re = re.compile('((\w+ )*?(\w+|...))( (\**)(\w+))?$')
         res = {}
         proto_re = re.compile('(.+) (\**)(\w+)\(((([^,]+)(, )?){1,5})\)$')
 
@@ -54,8 +54,8 @@ class Helper(object):
             capture = arg_re.match(a)
             res['args'].append({
                 'type' : capture.group(1),
-                'star' : capture.group(6),
-                'name' : capture.group(7)
+                'star' : capture.group(5),
+                'name' : capture.group(6)
             })
 
         return res
index 89c47f57d1ce14476ca7c2638e89e31926c3d7fb..8c1af9bdcb1bbaadb419e876717cded98ae9c408 100644 (file)
@@ -36,7 +36,7 @@ static unsigned int arm_pertask_ssp_rtl_execute(void)
                mask = GEN_INT(sext_hwi(sp_mask, GET_MODE_PRECISION(Pmode)));
                masked_sp = gen_reg_rtx(Pmode);
 
-               emit_insn_before(gen_rtx_SET(masked_sp,
+               emit_insn_before(gen_rtx_set(masked_sp,
                                             gen_rtx_AND(Pmode,
                                                         stack_pointer_rtx,
                                                         mask)),
diff --git a/scripts/gdb/linux/clk.py b/scripts/gdb/linux/clk.py
new file mode 100644 (file)
index 0000000..061aecf
--- /dev/null
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) NXP 2019
+
+import gdb
+import sys
+
+from linux import utils, lists, constants
+
+clk_core_type = utils.CachedType("struct clk_core")
+
+
+def clk_core_for_each_child(hlist_head):
+    return lists.hlist_for_each_entry(hlist_head,
+            clk_core_type.get_type().pointer(), "child_node")
+
+
+class LxClkSummary(gdb.Command):
+    """Print clk tree summary
+
+Output is a subset of /sys/kernel/debug/clk/clk_summary
+
+No calls are made during printing, instead a (c) if printed after values which
+are cached and potentially out of date"""
+
+    def __init__(self):
+        super(LxClkSummary, self).__init__("lx-clk-summary", gdb.COMMAND_DATA)
+
+    def show_subtree(self, clk, level):
+        gdb.write("%*s%-*s %7d %8d %8d %11lu%s\n" % (
+                level * 3 + 1, "",
+                30 - level * 3,
+                clk['name'].string(),
+                clk['enable_count'],
+                clk['prepare_count'],
+                clk['protect_count'],
+                clk['rate'],
+                '(c)' if clk['flags'] & constants.LX_CLK_GET_RATE_NOCACHE else '   '))
+
+        for child in clk_core_for_each_child(clk['children']):
+            self.show_subtree(child, level + 1)
+
+    def invoke(self, arg, from_tty):
+        gdb.write("                                 enable  prepare  protect               \n")
+        gdb.write("   clock                          count    count    count        rate   \n")
+        gdb.write("------------------------------------------------------------------------\n")
+        for clk in clk_core_for_each_child(gdb.parse_and_eval("clk_root_list")):
+            self.show_subtree(clk, 0)
+        for clk in clk_core_for_each_child(gdb.parse_and_eval("clk_orphan_list")):
+            self.show_subtree(clk, 0)
+
+
+LxClkSummary()
+
+
+class LxClkCoreLookup(gdb.Function):
+    """Find struct clk_core by name"""
+
+    def __init__(self):
+        super(LxClkCoreLookup, self).__init__("lx_clk_core_lookup")
+
+    def lookup_hlist(self, hlist_head, name):
+        for child in clk_core_for_each_child(hlist_head):
+            if child['name'].string() == name:
+                return child
+            result = self.lookup_hlist(child['children'], name)
+            if result:
+                return result
+
+    def invoke(self, name):
+        name = name.string()
+        return (self.lookup_hlist(gdb.parse_and_eval("clk_root_list"), name) or
+                self.lookup_hlist(gdb.parse_and_eval("clk_orphan_list"), name))
+
+
+LxClkCoreLookup()
diff --git a/scripts/gdb/linux/config.py b/scripts/gdb/linux/config.py
new file mode 100644 (file)
index 0000000..90e1565
--- /dev/null
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright 2019 Google LLC.
+
+import gdb
+import zlib
+
+from linux import utils
+
+
+class LxConfigDump(gdb.Command):
+    """Output kernel config to the filename specified as the command
+       argument. Equivalent to 'zcat /proc/config.gz > config.txt' on
+       a running target"""
+
+    def __init__(self):
+        super(LxConfigDump, self).__init__("lx-configdump", gdb.COMMAND_DATA,
+                                           gdb.COMPLETE_FILENAME)
+
+    def invoke(self, arg, from_tty):
+        if len(arg) == 0:
+            filename = "config.txt"
+        else:
+            filename = arg
+
+        try:
+            py_config_ptr = gdb.parse_and_eval("kernel_config_data + 8")
+            py_config_size = gdb.parse_and_eval(
+                    "sizeof(kernel_config_data) - 1 - 8 * 2")
+        except gdb.error as e:
+            raise gdb.GdbError("Can't find config, enable CONFIG_IKCONFIG?")
+
+        inf = gdb.inferiors()[0]
+        zconfig_buf = utils.read_memoryview(inf, py_config_ptr,
+                                            py_config_size).tobytes()
+
+        config_buf = zlib.decompress(zconfig_buf, 16)
+        with open(filename, 'wb') as f:
+            f.write(config_buf)
+
+        gdb.write("Dumped config to " + filename + "\n")
+
+
+LxConfigDump()
index d3319a80788a332387023ec5ace5cd74e9de841e..1d73083da6cb2f6f36d10f8ef9af350cfaef2ee1 100644 (file)
  *
  */
 
+#include <linux/clk-provider.h>
 #include <linux/fs.h>
+#include <linux/hrtimer.h>
 #include <linux/mount.h>
 #include <linux/of_fdt.h>
+#include <linux/threads.h>
 
 /* We need to stringify expanded macros so that they can be parsed */
 
@@ -36,6 +39,9 @@
 
 import gdb
 
+/* linux/clk-provider.h */
+LX_GDBPARSED(CLK_GET_RATE_NOCACHE)
+
 /* linux/fs.h */
 LX_VALUE(SB_RDONLY)
 LX_VALUE(SB_SYNCHRONOUS)
@@ -44,6 +50,9 @@ LX_VALUE(SB_DIRSYNC)
 LX_VALUE(SB_NOATIME)
 LX_VALUE(SB_NODIRATIME)
 
+/* linux/htimer.h */
+LX_GDBPARSED(hrtimer_resolution)
+
 /* linux/mount.h */
 LX_VALUE(MNT_NOSUID)
 LX_VALUE(MNT_NODEV)
@@ -52,8 +61,16 @@ LX_VALUE(MNT_NOATIME)
 LX_VALUE(MNT_NODIRATIME)
 LX_VALUE(MNT_RELATIME)
 
+/* linux/threads.h */
+LX_VALUE(NR_CPUS)
+
 /* linux/of_fdt.h> */
 LX_VALUE(OF_DT_HEADER)
 
 /* Kernel Configs */
+LX_CONFIG(CONFIG_GENERIC_CLOCKEVENTS)
+LX_CONFIG(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+LX_CONFIG(CONFIG_HIGH_RES_TIMERS)
+LX_CONFIG(CONFIG_NR_CPUS)
 LX_CONFIG(CONFIG_OF)
+LX_CONFIG(CONFIG_TICK_ONESHOT)
index ca11e8df31b6b7f4107e2b14e06aa7ef866f1859..008e62f3190df4f6e315d5450af3cf6bdf0a2e96 100644 (file)
@@ -135,6 +135,7 @@ and can help identify the state of hotplugged CPUs"""
         gdb.write("Online CPUs   : {}\n".format(list(each_online_cpu())))
         gdb.write("Active CPUs   : {}\n".format(list(each_active_cpu())))
 
+
 LxCpus()
 
 
index 2f335fbd86fd5b79d575f12f38319573e9bfb1f6..c487ddf09d380fef38f37e7ac88a10618fe1cc84 100644 (file)
@@ -16,13 +16,15 @@ import gdb
 from linux import utils
 
 list_head = utils.CachedType("struct list_head")
+hlist_head = utils.CachedType("struct hlist_head")
+hlist_node = utils.CachedType("struct hlist_node")
 
 
 def list_for_each(head):
     if head.type == list_head.get_type().pointer():
         head = head.dereference()
     elif head.type != list_head.get_type():
-        raise gdb.GdbError("Must be struct list_head not {}"
+        raise TypeError("Must be struct list_head not {}"
                            .format(head.type))
 
     node = head['next'].dereference()
@@ -33,9 +35,24 @@ def list_for_each(head):
 
 def list_for_each_entry(head, gdbtype, member):
     for node in list_for_each(head):
-        if node.type != list_head.get_type().pointer():
-            raise TypeError("Type {} found. Expected struct list_head *."
-                            .format(node.type))
+        yield utils.container_of(node, gdbtype, member)
+
+
+def hlist_for_each(head):
+    if head.type == hlist_head.get_type().pointer():
+        head = head.dereference()
+    elif head.type != hlist_head.get_type():
+        raise TypeError("Must be struct hlist_head not {}"
+                           .format(head.type))
+
+    node = head['first'].dereference()
+    while node.address:
+        yield node.address
+        node = node['next'].dereference()
+
+
+def hlist_for_each_entry(head, gdbtype, member):
+    for node in hlist_for_each(head):
         yield utils.container_of(node, gdbtype, member)
 
 
@@ -110,4 +127,5 @@ class LxListChk(gdb.Command):
             raise gdb.GdbError("lx-list-check takes one argument")
         list_check(gdb.parse_and_eval(argv[0]))
 
+
 LxListChk()
index 2f01a958eb22e3ac6ea044a54633d38a2486b0ec..6a56bba233a9236dcd617501e1e1b51ff559d843 100644 (file)
@@ -29,6 +29,7 @@ class LxCmdLine(gdb.Command):
     def invoke(self, arg, from_tty):
         gdb.write(gdb.parse_and_eval("saved_command_line").string() + "\n")
 
+
 LxCmdLine()
 
 
@@ -43,6 +44,7 @@ class LxVersion(gdb.Command):
         # linux_banner should contain a newline
         gdb.write(gdb.parse_and_eval("(char *)linux_banner").string())
 
+
 LxVersion()
 
 
@@ -86,6 +88,7 @@ Equivalent to cat /proc/iomem on a running target"""
     def invoke(self, arg, from_tty):
         return show_lx_resources("iomem_resource")
 
+
 LxIOMem()
 
 
@@ -100,6 +103,7 @@ Equivalent to cat /proc/ioports on a running target"""
     def invoke(self, arg, from_tty):
         return show_lx_resources("ioport_resource")
 
+
 LxIOPorts()
 
 
@@ -149,7 +153,7 @@ values of that process namespace"""
         if len(argv) >= 1:
             try:
                 pid = int(argv[0])
-            except:
+            except gdb.error:
                 raise gdb.GdbError("Provide a PID as integer value")
         else:
             pid = 1
@@ -195,6 +199,7 @@ values of that process namespace"""
                         info_opts(FS_INFO, s_flags),
                         info_opts(MNT_INFO, m_flags)))
 
+
 LxMounts()
 
 
@@ -259,7 +264,7 @@ class LxFdtDump(gdb.Command):
 
         try:
             f = open(filename, 'wb')
-        except:
+        except gdb.error:
             raise gdb.GdbError("Could not open file to dump fdt")
 
         f.write(fdt_buf)
@@ -267,4 +272,5 @@ class LxFdtDump(gdb.Command):
 
         gdb.write("Dumped fdt blob to " + filename + "\n")
 
+
 LxFdtDump()
diff --git a/scripts/gdb/linux/rbtree.py b/scripts/gdb/linux/rbtree.py
new file mode 100644 (file)
index 0000000..39db889
--- /dev/null
@@ -0,0 +1,177 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright 2019 Google LLC.
+
+import gdb
+
+from linux import utils
+
+rb_root_type = utils.CachedType("struct rb_root")
+rb_node_type = utils.CachedType("struct rb_node")
+
+
+def rb_first(root):
+    if root.type == rb_root_type.get_type():
+        node = node.address.cast(rb_root_type.get_type().pointer())
+    elif root.type != rb_root_type.get_type().pointer():
+        raise gdb.GdbError("Must be struct rb_root not {}".format(root.type))
+
+    node = root['rb_node']
+    if node is 0:
+        return None
+
+    while node['rb_left']:
+        node = node['rb_left']
+
+    return node
+
+
+def rb_last(root):
+    if root.type == rb_root_type.get_type():
+        node = node.address.cast(rb_root_type.get_type().pointer())
+    elif root.type != rb_root_type.get_type().pointer():
+        raise gdb.GdbError("Must be struct rb_root not {}".format(root.type))
+
+    node = root['rb_node']
+    if node is 0:
+        return None
+
+    while node['rb_right']:
+        node = node['rb_right']
+
+    return node
+
+
+def rb_parent(node):
+    parent = gdb.Value(node['__rb_parent_color'] & ~3)
+    return parent.cast(rb_node_type.get_type().pointer())
+
+
+def rb_empty_node(node):
+    return node['__rb_parent_color'] == node.address
+
+
+def rb_next(node):
+    if node.type == rb_node_type.get_type():
+        node = node.address.cast(rb_node_type.get_type().pointer())
+    elif node.type != rb_node_type.get_type().pointer():
+        raise gdb.GdbError("Must be struct rb_node not {}".format(node.type))
+
+    if rb_empty_node(node):
+        return None
+
+    if node['rb_right']:
+        node = node['rb_right']
+        while node['rb_left']:
+            node = node['rb_left']
+        return node
+
+    parent = rb_parent(node)
+    while parent and node == parent['rb_right']:
+            node = parent
+            parent = rb_parent(node)
+
+    return parent
+
+
+def rb_prev(node):
+    if node.type == rb_node_type.get_type():
+        node = node.address.cast(rb_node_type.get_type().pointer())
+    elif node.type != rb_node_type.get_type().pointer():
+        raise gdb.GdbError("Must be struct rb_node not {}".format(node.type))
+
+    if rb_empty_node(node):
+        return None
+
+    if node['rb_left']:
+        node = node['rb_left']
+        while node['rb_right']:
+            node = node['rb_right']
+        return node.dereference()
+
+    parent = rb_parent(node)
+    while parent and node == parent['rb_left'].dereference():
+            node = parent
+            parent = rb_parent(node)
+
+    return parent
+
+
+class LxRbFirst(gdb.Function):
+    """Lookup and return a node from an RBTree
+
+$lx_rb_first(root): Return the node at the given index.
+If index is omitted, the root node is dereferenced and returned."""
+
+    def __init__(self):
+        super(LxRbFirst, self).__init__("lx_rb_first")
+
+    def invoke(self, root):
+        result = rb_first(root)
+        if result is None:
+            raise gdb.GdbError("No entry in tree")
+
+        return result
+
+
+LxRbFirst()
+
+
+class LxRbLast(gdb.Function):
+    """Lookup and return a node from an RBTree.
+
+$lx_rb_last(root): Return the node at the given index.
+If index is omitted, the root node is dereferenced and returned."""
+
+    def __init__(self):
+        super(LxRbLast, self).__init__("lx_rb_last")
+
+    def invoke(self, root):
+        result = rb_last(root)
+        if result is None:
+            raise gdb.GdbError("No entry in tree")
+
+        return result
+
+
+LxRbLast()
+
+
+class LxRbNext(gdb.Function):
+    """Lookup and return a node from an RBTree.
+
+$lx_rb_next(node): Return the node at the given index.
+If index is omitted, the root node is dereferenced and returned."""
+
+    def __init__(self):
+        super(LxRbNext, self).__init__("lx_rb_next")
+
+    def invoke(self, node):
+        result = rb_next(node)
+        if result is None:
+            raise gdb.GdbError("No entry in tree")
+
+        return result
+
+
+LxRbNext()
+
+
+class LxRbPrev(gdb.Function):
+    """Lookup and return a node from an RBTree.
+
+$lx_rb_prev(node): Return the node at the given index.
+If index is omitted, the root node is dereferenced and returned."""
+
+    def __init__(self):
+        super(LxRbPrev, self).__init__("lx_rb_prev")
+
+    def invoke(self, node):
+        result = rb_prev(node)
+        if result is None:
+            raise gdb.GdbError("No entry in tree")
+
+        return result
+
+
+LxRbPrev()
index 004b0ac7fa72d25598d26fbab4b2035e3e882305..2f5b95f09fa03d11a7f075645835369279d36821 100644 (file)
@@ -139,8 +139,12 @@ lx-symbols command."""
                 saved_states.append({'breakpoint': bp, 'enabled': bp.enabled})
 
         # drop all current symbols and reload vmlinux
+        orig_vmlinux = 'vmlinux'
+        for obj in gdb.objfiles():
+            if obj.filename.endswith('vmlinux'):
+                orig_vmlinux = obj.filename
         gdb.execute("symbol-file", to_string=True)
-        gdb.execute("symbol-file vmlinux")
+        gdb.execute("symbol-file {0}".format(orig_vmlinux))
 
         self.loaded_modules = []
         module_list = modules.module_list()
index f6ab3ccf698ff4e4279e959829eb3e87da8cb2bc..0301dc1e01381c94a7d650849ed7791dfb0ba38b 100644 (file)
@@ -79,6 +79,7 @@ class LxPs(gdb.Command):
                 pid=task["pid"],
                 comm=task["comm"].string()))
 
+
 LxPs()
 
 
@@ -134,4 +135,5 @@ variable."""
         else:
             raise gdb.GdbError("No task of PID " + str(pid))
 
+
 LxThreadInfoByPidFunc()
diff --git a/scripts/gdb/linux/timerlist.py b/scripts/gdb/linux/timerlist.py
new file mode 100644 (file)
index 0000000..071d0dd
--- /dev/null
@@ -0,0 +1,219 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright 2019 Google LLC.
+
+import binascii
+import gdb
+
+from linux import constants
+from linux import cpus
+from linux import rbtree
+from linux import utils
+
+timerqueue_node_type = utils.CachedType("struct timerqueue_node").get_type()
+hrtimer_type = utils.CachedType("struct hrtimer").get_type()
+
+
+def ktime_get():
+    """Returns the current time, but not very accurately
+
+    We can't read the hardware timer itself to add any nanoseconds
+    that need to be added since we last stored the time in the
+    timekeeper. But this is probably good enough for debug purposes."""
+    tk_core = gdb.parse_and_eval("&tk_core")
+
+    return tk_core['timekeeper']['tkr_mono']['base']
+
+
+def print_timer(rb_node, idx):
+    timerqueue = utils.container_of(rb_node, timerqueue_node_type.pointer(),
+                                    "node")
+    timer = utils.container_of(timerqueue, hrtimer_type.pointer(), "node")
+
+    function = str(timer['function']).split(" ")[1].strip("<>")
+    softexpires = timer['_softexpires']
+    expires = timer['node']['expires']
+    now = ktime_get()
+
+    text = " #{}: <{}>, {}, ".format(idx, timer, function)
+    text += "S:{:02x}\n".format(int(timer['state']))
+    text += " # expires at {}-{} nsecs [in {} to {} nsecs]\n".format(
+            softexpires, expires, softexpires - now, expires - now)
+    return text
+
+
+def print_active_timers(base):
+    curr = base['active']['next']['node']
+    curr = curr.address.cast(rbtree.rb_node_type.get_type().pointer())
+    idx = 0
+    while curr:
+        yield print_timer(curr, idx)
+        curr = rbtree.rb_next(curr)
+        idx += 1
+
+
+def print_base(base):
+    text = " .base:       {}\n".format(base.address)
+    text += " .index:      {}\n".format(base['index'])
+
+    text += " .resolution: {} nsecs\n".format(constants.LX_hrtimer_resolution)
+
+    text += " .get_time:   {}\n".format(base['get_time'])
+    if constants.LX_CONFIG_HIGH_RES_TIMERS:
+        text += "  .offset:     {} nsecs\n".format(base['offset'])
+    text += "active timers:\n"
+    text += "".join([x for x in print_active_timers(base)])
+    return text
+
+
+def print_cpu(hrtimer_bases, cpu, max_clock_bases):
+    cpu_base = cpus.per_cpu(hrtimer_bases, cpu)
+    jiffies = gdb.parse_and_eval("jiffies_64")
+    tick_sched_ptr = gdb.parse_and_eval("&tick_cpu_sched")
+    ts = cpus.per_cpu(tick_sched_ptr, cpu)
+
+    text = "cpu: {}\n".format(cpu)
+    for i in xrange(max_clock_bases):
+        text += " clock {}:\n".format(i)
+        text += print_base(cpu_base['clock_base'][i])
+
+        if constants.LX_CONFIG_HIGH_RES_TIMERS:
+            fmts = [("  .{}   : {} nsecs", 'expires_next'),
+                    ("  .{}    : {}", 'hres_active'),
+                    ("  .{}      : {}", 'nr_events'),
+                    ("  .{}     : {}", 'nr_retries'),
+                    ("  .{}       : {}", 'nr_hangs'),
+                    ("  .{}  : {}", 'max_hang_time')]
+            text += "\n".join([s.format(f, cpu_base[f]) for s, f in fmts])
+            text += "\n"
+
+        if constants.LX_CONFIG_TICK_ONESHOT:
+            fmts = [("  .{}      : {}", 'nohz_mode'),
+                    ("  .{}      : {} nsecs", 'last_tick'),
+                    ("  .{}   : {}", 'tick_stopped'),
+                    ("  .{}   : {}", 'idle_jiffies'),
+                    ("  .{}     : {}", 'idle_calls'),
+                    ("  .{}    : {}", 'idle_sleeps'),
+                    ("  .{} : {} nsecs", 'idle_entrytime'),
+                    ("  .{}  : {} nsecs", 'idle_waketime'),
+                    ("  .{}  : {} nsecs", 'idle_exittime'),
+                    ("  .{} : {} nsecs", 'idle_sleeptime'),
+                    ("  .{}: {} nsecs", 'iowait_sleeptime'),
+                    ("  .{}   : {}", 'last_jiffies'),
+                    ("  .{}     : {}", 'next_timer'),
+                    ("  .{}   : {} nsecs", 'idle_expires')]
+            text += "\n".join([s.format(f, ts[f]) for s, f in fmts])
+            text += "\njiffies: {}\n".format(jiffies)
+
+        text += "\n"
+
+    return text
+
+
+def print_tickdevice(td, cpu):
+    dev = td['evtdev']
+    text = "Tick Device: mode:     {}\n".format(td['mode'])
+    if cpu < 0:
+            text += "Broadcast device\n"
+    else:
+            text += "Per CPU device: {}\n".format(cpu)
+
+    text += "Clock Event Device: "
+    if dev == 0:
+            text += "<NULL>\n"
+            return text
+
+    text += "{}\n".format(dev['name'])
+    text += " max_delta_ns:   {}\n".format(dev['max_delta_ns'])
+    text += " min_delta_ns:   {}\n".format(dev['min_delta_ns'])
+    text += " mult:           {}\n".format(dev['mult'])
+    text += " shift:          {}\n".format(dev['shift'])
+    text += " mode:           {}\n".format(dev['state_use_accessors'])
+    text += " next_event:     {} nsecs\n".format(dev['next_event'])
+
+    text += " set_next_event: {}\n".format(dev['set_next_event'])
+
+    members = [('set_state_shutdown', " shutdown: {}\n"),
+               ('set_state_periodic', " periodic: {}\n"),
+               ('set_state_oneshot', " oneshot:  {}\n"),
+               ('set_state_oneshot_stopped', " oneshot stopped: {}\n"),
+               ('tick_resume', " resume:   {}\n")]
+    for member, fmt in members:
+        if dev[member]:
+            text += fmt.format(dev[member])
+
+    text += " event_handler:  {}\n".format(dev['event_handler'])
+    text += " retries:        {}\n".format(dev['retries'])
+
+    return text
+
+
+def pr_cpumask(mask):
+    nr_cpu_ids = 1
+    if constants.LX_NR_CPUS > 1:
+        nr_cpu_ids = gdb.parse_and_eval("nr_cpu_ids")
+
+    inf = gdb.inferiors()[0]
+    bits = mask['bits']
+    num_bytes = (nr_cpu_ids + 7) / 8
+    buf = utils.read_memoryview(inf, bits, num_bytes).tobytes()
+    buf = binascii.b2a_hex(buf)
+
+    chunks = []
+    i = num_bytes
+    while i > 0:
+        i -= 1
+        start = i * 2
+        end = start + 2
+        chunks.append(buf[start:end])
+        if i != 0 and i % 4 == 0:
+            chunks.append(',')
+
+    extra = nr_cpu_ids % 8
+    if 0 < extra <= 4:
+        chunks[0] = chunks[0][0]  # Cut off the first 0
+
+    return "".join(chunks)
+
+
+class LxTimerList(gdb.Command):
+    """Print /proc/timer_list"""
+
+    def __init__(self):
+        super(LxTimerList, self).__init__("lx-timerlist", gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        hrtimer_bases = gdb.parse_and_eval("&hrtimer_bases")
+        max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES")
+
+        text = "Timer List Version: gdb scripts\n"
+        text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(max_clock_bases)
+        text += "now at {} nsecs\n".format(ktime_get())
+
+        for cpu in cpus.each_online_cpu():
+            text += print_cpu(hrtimer_bases, cpu, max_clock_bases)
+
+        if constants.LX_CONFIG_GENERIC_CLOCKEVENTS:
+            if constants.LX_CONFIG_GENERIC_CLOCKEVENTS_BROADCAST:
+                bc_dev = gdb.parse_and_eval("&tick_broadcast_device")
+                text += print_tickdevice(bc_dev, -1)
+                text += "\n"
+                mask = gdb.parse_and_eval("tick_broadcast_mask")
+                mask = pr_cpumask(mask)
+                text += "tick_broadcast_mask: {}\n".format(mask)
+                if constants.LX_CONFIG_TICK_ONESHOT:
+                    mask = gdb.parse_and_eval("tick_broadcast_oneshot_mask")
+                    mask = pr_cpumask(mask)
+                    text += "tick_broadcast_oneshot_mask: {}\n".format(mask)
+                text += "\n"
+
+            tick_cpu_devices = gdb.parse_and_eval("&tick_cpu_device")
+            for cpu in cpus.each_online_cpu():
+                tick_dev = cpus.per_cpu(tick_cpu_devices, cpu)
+                text += print_tickdevice(tick_dev, cpu)
+                text += "\n"
+
+        gdb.write(text)
+
+
+LxTimerList()
index 50805874cfc38b1cd820f60ae8340a60e2da7a89..bc67126118c4d50ff1b6d567525eb9b40090e54d 100644 (file)
@@ -66,6 +66,7 @@ Note that TYPE and ELEMENT have to be quoted as strings."""
         return container_of(ptr, gdb.lookup_type(typename.string()).pointer(),
                             elementname.string())
 
+
 ContainerOf()
 
 
@@ -148,14 +149,14 @@ def get_gdbserver_type():
     def probe_qemu():
         try:
             return gdb.execute("monitor info version", to_string=True) != ""
-        except:
+        except gdb.error:
             return False
 
     def probe_kgdb():
         try:
             thread_info = gdb.execute("info thread 2", to_string=True)
             return "shadowCPU0" in thread_info
-        except:
+        except gdb.error:
             return False
 
     global gdbserver_type
@@ -172,7 +173,7 @@ def get_gdbserver_type():
 def gdb_eval_or_none(expresssion):
     try:
         return gdb.parse_and_eval(expresssion)
-    except:
+    except gdb.error:
         return None
 
 
index 6e0b0afd888ade32768edba8e659b61a4f396ac0..eff5a48ac026dde7aea0e0a2a3b528dceb221845 100644 (file)
@@ -27,7 +27,11 @@ else:
     import linux.modules
     import linux.dmesg
     import linux.tasks
+    import linux.config
     import linux.cpus
     import linux.lists
+    import linux.rbtree
     import linux.proc
     import linux.constants
+    import linux.timerlist
+    import linux.clk
index 08ba146a83c547db9e5607f407de08128656bc40..492ac3410147496a131d92ddba2d51e098aa765f 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
  */
 
+#include <sys/mman.h>
 #include <sys/stat.h>
 #include <ctype.h>
 #include <errno.h>
@@ -36,6 +37,52 @@ static bool is_dir(const char *path)
        return S_ISDIR(st.st_mode);
 }
 
+/* return true if the given two files are the same, false otherwise */
+static bool is_same(const char *file1, const char *file2)
+{
+       int fd1, fd2;
+       struct stat st1, st2;
+       void *map1, *map2;
+       bool ret = false;
+
+       fd1 = open(file1, O_RDONLY);
+       if (fd1 < 0)
+               return ret;
+
+       fd2 = open(file2, O_RDONLY);
+       if (fd2 < 0)
+               goto close1;
+
+       ret = fstat(fd1, &st1);
+       if (ret)
+               goto close2;
+       ret = fstat(fd2, &st2);
+       if (ret)
+               goto close2;
+
+       if (st1.st_size != st2.st_size)
+               goto close2;
+
+       map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
+       if (map1 == MAP_FAILED)
+               goto close2;
+
+       map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
+       if (map2 == MAP_FAILED)
+               goto close2;
+
+       if (bcmp(map1, map2, st1.st_size))
+               goto close2;
+
+       ret = true;
+close2:
+       close(fd2);
+close1:
+       close(fd1);
+
+       return ret;
+}
+
 /*
  * Create the parent directory of the given path.
  *
@@ -179,7 +226,7 @@ const char *conf_get_configname(void)
        return name ? name : ".config";
 }
 
-const char *conf_get_autoconfig_name(void)
+static const char *conf_get_autoconfig_name(void)
 {
        char *name = getenv("KCONFIG_AUTOCONFIG");
 
@@ -194,7 +241,7 @@ char *conf_get_default_confname(void)
        name = expand_string(conf_defname);
        env = getenv(SRCTREE);
        if (env) {
-               sprintf(fullname, "%s/%s", env, name);
+               snprintf(fullname, sizeof(fullname), "%s/%s", env, name);
                if (is_present(fullname))
                        return fullname;
        }
@@ -817,40 +864,34 @@ int conf_write(const char *name)
        FILE *out;
        struct symbol *sym;
        struct menu *menu;
-       const char *basename;
        const char *str;
-       char dirname[PATH_MAX+1], tmpname[PATH_MAX+22], newname[PATH_MAX+8];
+       char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
        char *env;
 
-       dirname[0] = 0;
-       if (name && name[0]) {
-               char *slash;
-
-               if (is_dir(name)) {
-                       strcpy(dirname, name);
-                       strcat(dirname, "/");
-                       basename = conf_get_configname();
-               } else if ((slash = strrchr(name, '/'))) {
-                       int size = slash - name + 1;
-                       memcpy(dirname, name, size);
-                       dirname[size] = 0;
-                       if (slash[1])
-                               basename = slash + 1;
-                       else
-                               basename = conf_get_configname();
-               } else
-                       basename = name;
-       } else
-               basename = conf_get_configname();
-
-       sprintf(newname, "%s%s", dirname, basename);
+       if (!name)
+               name = conf_get_configname();
+
+       if (!*name) {
+               fprintf(stderr, "config name is empty\n");
+               return -1;
+       }
+
+       if (is_dir(name)) {
+               fprintf(stderr, "%s: Is a directory\n", name);
+               return -1;
+       }
+
+       if (make_parent_dir(name))
+               return -1;
+
        env = getenv("KCONFIG_OVERWRITECONFIG");
-       if (!env || !*env) {
-               sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
-               out = fopen(tmpname, "w");
-       } else {
+       if (env && *env) {
                *tmpname = 0;
-               out = fopen(newname, "w");
+               out = fopen(name, "w");
+       } else {
+               snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
+                        name, (int)getpid());
+               out = fopen(tmpname, "w");
        }
        if (!out)
                return 1;
@@ -897,14 +938,20 @@ next:
        fclose(out);
 
        if (*tmpname) {
-               strcat(dirname, basename);
-               strcat(dirname, ".old");
-               rename(newname, dirname);
-               if (rename(tmpname, newname))
+               if (is_same(name, tmpname)) {
+                       conf_message("No change to %s", name);
+                       unlink(tmpname);
+                       sym_set_change_count(0);
+                       return 0;
+               }
+
+               snprintf(oldname, sizeof(oldname), "%s.old", name);
+               rename(name, oldname);
+               if (rename(tmpname, name))
                        return 1;
        }
 
-       conf_message("configuration written to %s", newname);
+       conf_message("configuration written to %s", name);
 
        sym_set_change_count(0);
 
@@ -917,8 +964,6 @@ static int conf_write_dep(const char *name)
        struct file *file;
        FILE *out;
 
-       if (!name)
-               name = ".kconfig.d";
        out = fopen("..config.tmp", "w");
        if (!out)
                return 1;
index 5d4ecf309ee40188ba85652a1008be3abc206e0f..e36b342f1065b750b4e0f9105a015c66bb38d94f 100644 (file)
@@ -638,7 +638,7 @@ on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
 void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
 {
        GtkWidget *dialog;
-       const gchar *intro_text = 
+       const gchar *intro_text =
            "Welcome to gkc, the GTK+ graphical configuration tool\n"
            "For each option, a blank box indicates the feature is disabled, a\n"
            "check indicates it is enabled, and a dot indicates that it is to\n"
index c9df1c8b982494cecdf8751ccf0275e14c07d35e..6354c905b006f66e673d9b098c2ae50ef29271c4 100644 (file)
@@ -378,7 +378,8 @@ FILE *zconf_fopen(const char *name)
        if (!f && name != NULL && name[0] != '/') {
                env = getenv(SRCTREE);
                if (env) {
-                       sprintf(fullname, "%s/%s", env, name);
+                       snprintf(fullname, sizeof(fullname),
+                                "%s/%s", env, name);
                        f = fopen(fullname, "r");
                }
        }
index d871539e4b457f517627e7f3f47a86134959dc77..cbc7658ee27d5d279ea1d17230071c47505ba8eb 100644 (file)
@@ -49,7 +49,6 @@ const char *zconf_curname(void);
 
 /* confdata.c */
 const char *conf_get_configname(void);
-const char *conf_get_autoconfig_name(void);
 char *conf_get_default_confname(void);
 void sym_set_change_count(int count);
 void sym_add_change_count(int count);
index a8999d82bdb3b5c00a9668de8f5da89b91c0cc08..7cb5a7ec93d27ec6c98b2565e6399d3f342a813a 100644 (file)
@@ -1,4 +1,4 @@
 This is NOT the official version of dialog.  This version has been
 significantly modified from the original.  It is for use by the Linux
-kernel configuration script.  Please do not bother Savio Lam with 
+kernel configuration script.  Please do not bother Savio Lam with
 questions about this program.
index 5f8c82a4cb08c1e877d8054db9bc857640c4aaca..694091f3ef9d29cd1c36326a11aba3c4a54685d9 100644 (file)
@@ -936,7 +936,7 @@ static void conf_save(void)
                                set_config_filename(dialog_input_result);
                                return;
                        }
-                       show_textbox(NULL, "Can't create file!  Probably a nonexistent directory.", 5, 60);
+                       show_textbox(NULL, "Can't create file!", 5, 60);
                        break;
                case 1:
                        show_helptext("Save Alternate Configuration", save_config_help);
old mode 100644 (file)
new mode 100755 (executable)
index ac92c0ded6c5c627e974679ef967d4bc37b25a53..cbafe3bf082ec78f82388a8f138a35f76da711ea 100644 (file)
@@ -1438,8 +1438,7 @@ static void conf_save(void)
                                set_config_filename(dialog_input_result);
                                return;
                        }
-                       btn_dialog(main_window, "Can't create file! "
-                               "Probably a nonexistent directory.",
+                       btn_dialog(main_window, "Can't create file!",
                                1, "<OK>");
                        break;
                case 1:
index d82b87c16b0abb3cae919aaf8b5f28a56faad170..c61787b15f27b2b0bd0ed7d448fd6ba2d73ca07a 100644 (file)
@@ -4649,7 +4649,7 @@ static int selinux_socket_connect_helper(struct socket *sock,
                struct lsm_network_audit net = {0,};
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
-               unsigned short snum = 0;
+               unsigned short snum;
                u32 sid, perm;
 
                /* sctp_connectx(3) calls via selinux_sctp_bind_connect()
@@ -4674,12 +4674,12 @@ static int selinux_socket_connect_helper(struct socket *sock,
                        break;
                default:
                        /* Note that SCTP services expect -EINVAL, whereas
-                        * others must handle this at the protocol level:
-                        * connect(AF_UNSPEC) on a connected socket is
-                        * a documented way disconnect the socket.
+                        * others expect -EAFNOSUPPORT.
                         */
                        if (sksec->sclass == SECCLASS_SCTP_SOCKET)
                                return -EINVAL;
+                       else
+                               return -EAFNOSUPPORT;
                }
 
                err = sel_netport_sid(sk->sk_protocol, snum, &sid);
index 404dce66952a0b06297da70e41b7acafad026647..a00ab7eb6181ef6b6b1fcb9f0051a515876f2868 100644 (file)
@@ -74,3 +74,13 @@ config SECURITY_TOMOYO_ACTIVATION_TRIGGER
          You can override this setting via TOMOYO_trigger= kernel command line
          option. For example, if you pass init=/bin/systemd option, you may
          want to also pass TOMOYO_trigger=/bin/systemd option.
+
+config SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING
+       bool "Use insecure built-in settings for fuzzing tests."
+       default n
+       depends on SECURITY_TOMOYO
+       select SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
+       help
+         Enabling this option forces minimal built-in policy and disables
+         domain/program checks for run-time policy modifications. Please enable
+         this option only if this kernel is built for doing fuzzing tests.
index 57988d95d33de2050bacd73cfc6252cf8d836861..dd3d5942e6692457b505e137e0bd30ef6cb90dab 100644 (file)
@@ -940,7 +940,7 @@ static bool tomoyo_manager(void)
        const char *exe;
        const struct task_struct *task = current;
        const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname;
-       bool found = false;
+       bool found = IS_ENABLED(CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING);
 
        if (!tomoyo_policy_loaded)
                return true;
@@ -2810,6 +2810,16 @@ void tomoyo_check_profile(void)
  */
 void __init tomoyo_load_builtin_policy(void)
 {
+#ifdef CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING
+       static char tomoyo_builtin_profile[] __initdata =
+               "PROFILE_VERSION=20150505\n"
+               "0-CONFIG={ mode=learning grant_log=no reject_log=yes }\n";
+       static char tomoyo_builtin_exception_policy[] __initdata =
+               "aggregator proc:/self/exe /proc/self/exe\n";
+       static char tomoyo_builtin_domain_policy[] __initdata = "";
+       static char tomoyo_builtin_manager[] __initdata = "";
+       static char tomoyo_builtin_stat[] __initdata = "";
+#else
        /*
         * This include file is manually created and contains built-in policy
         * named "tomoyo_builtin_profile", "tomoyo_builtin_exception_policy",
@@ -2817,6 +2827,7 @@ void __init tomoyo_load_builtin_policy(void)
         * "tomoyo_builtin_stat" in the form of "static char [] __initdata".
         */
 #include "builtin-policy.h"
+#endif
        u8 i;
        const int idx = tomoyo_read_lock();
 
index 9094f4b3b367b5d37332727d11722602bed03e5a..f9ff121d7e1eb4e9251d43d43f1f90bbd1a76cd1 100644 (file)
@@ -505,6 +505,8 @@ static int tomoyo_check_inet_address(const struct sockaddr *addr,
 {
        struct tomoyo_inet_addr_info *i = &address->inet;
 
+       if (addr_len < offsetofend(struct sockaddr, sa_family))
+               return 0;
        switch (addr->sa_family) {
        case AF_INET6:
                if (addr_len < SIN6_LEN_RFC2133)
@@ -594,6 +596,8 @@ static int tomoyo_check_unix_address(struct sockaddr *addr,
 {
        struct tomoyo_unix_addr_info *u = &address->unix0;
 
+       if (addr_len < offsetofend(struct sockaddr, sa_family))
+               return 0;
        if (addr->sa_family != AF_UNIX)
                return 0;
        u->addr = ((struct sockaddr_un *) addr)->sun_path;
index 85e6e31dd1e5d29c7465c6475e1790a907ba72c2..e7832448d721d5acaa502b3a47f17a4fa0a94e86 100644 (file)
@@ -295,7 +295,8 @@ char *tomoyo_realpath_from_path(const struct path *path)
                 * or dentry without vfsmount.
                 */
                if (!path->mnt ||
-                   (!inode->i_op->rename))
+                   (!inode->i_op->rename &&
+                    !(sb->s_type->fs_flags & FS_REQUIRES_DEV)))
                        pos = tomoyo_get_local_path(path->dentry, buf,
                                                    buf_len - 1);
                /* Get absolute name for the rest. */
index 0517cbdd72756eb35e95e797edc607a182f6e01e..52752e1a84ed8f9131d303896e3a3af7504247da 100644 (file)
@@ -1076,8 +1076,10 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
                domain->flags[TOMOYO_DIF_QUOTA_WARNED] = true;
                /* r->granted = false; */
                tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]);
+#ifndef CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING
                pr_warn("WARNING: Domain '%s' has too many ACLs to hold. Stopped learning mode.\n",
                        domain->domainname->name);
+#endif
        }
        return false;
 }
index 95b073ee4b32bbefa29cf3aeaac68fc4ca9d6447..4769f4c03e148a567288a61a92d833c8e983bef9 100644 (file)
@@ -55,6 +55,7 @@ int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus,
        codec->bus = bus;
        codec->addr = addr;
        codec->type = HDA_DEV_CORE;
+       mutex_init(&codec->widget_lock);
        pm_runtime_set_active(&codec->dev);
        pm_runtime_get_noresume(&codec->dev);
        atomic_set(&codec->in_pm, 0);
@@ -141,7 +142,9 @@ int snd_hdac_device_register(struct hdac_device *codec)
        err = device_add(&codec->dev);
        if (err < 0)
                return err;
+       mutex_lock(&codec->widget_lock);
        err = hda_widget_sysfs_init(codec);
+       mutex_unlock(&codec->widget_lock);
        if (err < 0) {
                device_del(&codec->dev);
                return err;
@@ -158,7 +161,9 @@ EXPORT_SYMBOL_GPL(snd_hdac_device_register);
 void snd_hdac_device_unregister(struct hdac_device *codec)
 {
        if (device_is_registered(&codec->dev)) {
+               mutex_lock(&codec->widget_lock);
                hda_widget_sysfs_exit(codec);
+               mutex_unlock(&codec->widget_lock);
                device_del(&codec->dev);
                snd_hdac_bus_remove_device(codec->bus, codec);
        }
@@ -404,7 +409,9 @@ int snd_hdac_refresh_widgets(struct hdac_device *codec, bool sysfs)
        }
 
        if (sysfs) {
+               mutex_lock(&codec->widget_lock);
                err = hda_widget_sysfs_reinit(codec, start_nid, nums);
+               mutex_unlock(&codec->widget_lock);
                if (err < 0)
                        return err;
        }
index fb2aa344981e67e65db2aaf6da0fd0af922d0c2d..909d5ef1179c92d3d33f5bb60aa5a5378e30db0b 100644 (file)
@@ -395,6 +395,7 @@ static int widget_tree_create(struct hdac_device *codec)
        return 0;
 }
 
+/* call with codec->widget_lock held */
 int hda_widget_sysfs_init(struct hdac_device *codec)
 {
        int err;
@@ -411,11 +412,13 @@ int hda_widget_sysfs_init(struct hdac_device *codec)
        return 0;
 }
 
+/* call with codec->widget_lock held */
 void hda_widget_sysfs_exit(struct hdac_device *codec)
 {
        widget_tree_free(codec);
 }
 
+/* call with codec->widget_lock held */
 int hda_widget_sysfs_reinit(struct hdac_device *codec,
                            hda_nid_t start_nid, int num_nodes)
 {
index c53ca589c930b6c222762a81e9737e10a919839c..f83f21d64dd42a3788dada529ad7f89b7a039ad5 100644 (file)
@@ -478,12 +478,45 @@ static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
                set_eapd(codec, *p, on);
 }
 
+static int find_ext_mic_pin(struct hda_codec *codec);
+
+static void alc_headset_mic_no_shutup(struct hda_codec *codec)
+{
+       const struct hda_pincfg *pin;
+       int mic_pin = find_ext_mic_pin(codec);
+       int i;
+
+       /* don't shut up pins when unloading the driver; otherwise it breaks
+        * the default pin setup at the next load of the driver
+        */
+       if (codec->bus->shutdown)
+               return;
+
+       snd_array_for_each(&codec->init_pins, i, pin) {
+               /* use read here for syncing after issuing each verb */
+               if (pin->nid != mic_pin)
+                       snd_hda_codec_read(codec, pin->nid, 0,
+                                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+       }
+
+       codec->pins_shutup = 1;
+}
+
 static void alc_shutup_pins(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
 
-       if (!spec->no_shutup_pins)
-               snd_hda_shutup_pins(codec);
+       switch (codec->core.vendor_id) {
+       case 0x10ec0286:
+       case 0x10ec0288:
+       case 0x10ec0298:
+               alc_headset_mic_no_shutup(codec);
+               break;
+       default:
+               if (!spec->no_shutup_pins)
+                       snd_hda_shutup_pins(codec);
+               break;
+       }
 }
 
 /* generic shutup callback;
@@ -502,7 +535,6 @@ static void alc_eapd_shutup(struct hda_codec *codec)
 /* generic EAPD initialization */
 static void alc_auto_init_amp(struct hda_codec *codec, int type)
 {
-       alc_fill_eapd_coef(codec);
        alc_auto_setup_eapd(codec, true);
        alc_write_gpio(codec);
        switch (type) {
@@ -797,10 +829,22 @@ static int alc_build_controls(struct hda_codec *codec)
  * Common callbacks
  */
 
+static void alc_pre_init(struct hda_codec *codec)
+{
+       alc_fill_eapd_coef(codec);
+}
+
+#define is_s4_resume(codec) \
+       ((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE)
+
 static int alc_init(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
 
+       /* hibernation resume needs the full chip initialization */
+       if (is_s4_resume(codec))
+               alc_pre_init(codec);
+
        if (spec->init_hook)
                spec->init_hook(codec);
 
@@ -1538,6 +1582,8 @@ static int patch_alc880(struct hda_codec *codec)
 
        codec->patch_ops.unsol_event = alc880_unsol_event;
 
+       alc_pre_init(codec);
+
        snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
                       alc880_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
@@ -1789,6 +1835,8 @@ static int patch_alc260(struct hda_codec *codec)
 
        spec->shutup = alc_eapd_shutup;
 
+       alc_pre_init(codec);
+
        snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl,
                           alc260_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
@@ -2492,6 +2540,8 @@ static int patch_alc882(struct hda_codec *codec)
                break;
        }
 
+       alc_pre_init(codec);
+
        snd_hda_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl,
                       alc882_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
@@ -2666,6 +2716,8 @@ static int patch_alc262(struct hda_codec *codec)
 #endif
        alc_fix_pll_init(codec, 0x20, 0x0a, 10);
 
+       alc_pre_init(codec);
+
        snd_hda_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl,
                       alc262_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
@@ -2810,6 +2862,8 @@ static int patch_alc268(struct hda_codec *codec)
 
        spec->shutup = alc_eapd_shutup;
 
+       alc_pre_init(codec);
+
        snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
@@ -2924,27 +2978,6 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        return alc_parse_auto_config(codec, alc269_ignore, ssids);
 }
 
-static int find_ext_mic_pin(struct hda_codec *codec);
-
-static void alc286_shutup(struct hda_codec *codec)
-{
-       const struct hda_pincfg *pin;
-       int i;
-       int mic_pin = find_ext_mic_pin(codec);
-       /* don't shut up pins when unloading the driver; otherwise it breaks
-        * the default pin setup at the next load of the driver
-        */
-       if (codec->bus->shutdown)
-               return;
-       snd_array_for_each(&codec->init_pins, i, pin) {
-               /* use read here for syncing after issuing each verb */
-               if (pin->nid != mic_pin)
-                       snd_hda_codec_read(codec, pin->nid, 0,
-                                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-       }
-       codec->pins_shutup = 1;
-}
-
 static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up)
 {
        alc_update_coef_idx(codec, 0x04, 1 << 11, power_up ? (1 << 11) : 0);
@@ -6964,7 +6997,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC),
        SND_PCI_QUIRK(0x1558, 0x1325, "System76 Darter Pro (darp5)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8550, "System76 Gazelle (gaze14)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8560, "System76 Gazelle (gaze14)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8551, "System76 Gazelle (gaze14)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8560, "System76 Gazelle (gaze14)", ALC269_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1558, 0x8561, "System76 Gazelle (gaze14)", ALC269_FIXUP_HEADSET_MIC),
        SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC233_FIXUP_LENOVO_MULTI_CODECS),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
@@ -7007,7 +7042,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x313c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
        SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
        SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
-       SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
+       SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
        SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK),
@@ -7736,7 +7771,6 @@ static int patch_alc269(struct hda_codec *codec)
        case 0x10ec0286:
        case 0x10ec0288:
                spec->codec_variant = ALC269_TYPE_ALC286;
-               spec->shutup = alc286_shutup;
                break;
        case 0x10ec0298:
                spec->codec_variant = ALC269_TYPE_ALC298;
@@ -7805,6 +7839,8 @@ static int patch_alc269(struct hda_codec *codec)
                spec->init_hook = alc5505_dsp_init;
        }
 
+       alc_pre_init(codec);
+
        snd_hda_pick_fixup(codec, alc269_fixup_models,
                       alc269_fixup_tbl, alc269_fixups);
        snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups);
@@ -7947,6 +7983,8 @@ static int patch_alc861(struct hda_codec *codec)
        spec->power_hook = alc_power_eapd;
 #endif
 
+       alc_pre_init(codec);
+
        snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
@@ -8044,6 +8082,8 @@ static int patch_alc861vd(struct hda_codec *codec)
 
        spec->shutup = alc_eapd_shutup;
 
+       alc_pre_init(codec);
+
        snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
@@ -8779,6 +8819,8 @@ static int patch_alc662(struct hda_codec *codec)
                break;
        }
 
+       alc_pre_init(codec);
+
        snd_hda_pick_fixup(codec, alc662_fixup_models,
                       alc662_fixup_tbl, alc662_fixups);
        snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups);
index 3d011abaa2660a7cc92b4690006c107352862007..f678b4c1514afd64df690b8c746eaa35b3766c40 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
+#include <linux/soc/cirrus/ep93xx.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <asm/mach-types.h>
-#include <mach/hardware.h>
 
 static int edb93xx_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
index cd5a939ad6081a2394f3acbc5a030a99d5790310..c6bc447429af491a4bac7c1f54f295bda4632bf8 100644 (file)
@@ -24,6 +24,7 @@
 #include <sound/soc.h>
 
 #include <linux/platform_data/dma-ep93xx.h>
+#include <linux/soc/cirrus/ep93xx.h>
 
 #include "ep93xx-pcm.h"
 
index 0918c5da575aba1feedb4cf73f23cbdc7d380940..beab7c51685584e0ca68dfb49915ad2d916a1408 100644 (file)
@@ -27,9 +27,8 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include <mach/hardware.h>
-#include <mach/ep93xx-regs.h>
 #include <linux/platform_data/dma-ep93xx.h>
+#include <linux/soc/cirrus/ep93xx.h>
 
 #include "ep93xx-pcm.h"
 
index 1ec661834e5a82c77385caa96f154333e9e03cfc..cb850530331b75129c06d674f5c64b9ce7037885 100644 (file)
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/soc/cirrus/ep93xx.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 
 #include <asm/mach-types.h>
-#include <mach/hardware.h>
 
 static struct snd_soc_dai_link simone_dai = {
        .name           = "AC97",
index 11ff7b2672b2250318ea17652054619bb7fb897f..dea4909154c893cdbbd66283641aa83c25414c1d 100644 (file)
 
 #include <linux/platform_device.h>
 #include <linux/module.h>
+#include <linux/soc/cirrus/ep93xx.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 
 #include <asm/mach-types.h>
-#include <mach/hardware.h>
 
 #include "../codecs/tlv320aic23.h"
 
index 156aa7c00787860b1f26267ffcf4267601433acf..2bbb92ed96c8d3dcd8787dac1af79152f8c301c1 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
index 16511d97e8dc037c8c0b9a60b09a0adf409e6d20..09652eabe7690dc3a80b9525eec1d615f1cbbae6 100644 (file)
@@ -152,7 +152,8 @@ struct kvm_s390_vm_cpu_subfunc {
        __u8 pcc[16];           /* with MSA4 */
        __u8 ppno[16];          /* with MSA5 */
        __u8 kma[16];           /* with MSA8 */
-       __u8 reserved[1808];
+       __u8 kdsa[16];          /* with MSA9 */
+       __u8 reserved[1792];
 };
 
 /* kvm attributes for crypto */
index 72336bac7573368e7bce974626b68569c46eaabb..63e0cf66f01a9698ff6bc41ac5492809bb83d834 100644 (file)
@@ -629,7 +629,7 @@ union bpf_attr {
  *             **BPF_F_INVALIDATE_HASH** (set *skb*\ **->hash**, *skb*\
  *             **->swhash** and *skb*\ **->l4hash** to 0).
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -654,7 +654,7 @@ union bpf_attr {
  *             flexibility and can handle sizes larger than 2 or 4 for the
  *             checksum to update.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -686,7 +686,7 @@ union bpf_attr {
  *             flexibility and can handle sizes larger than 2 or 4 for the
  *             checksum to update.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -741,7 +741,7 @@ union bpf_attr {
  *             efficient, but it is handled through an action code where the
  *             redirection happens only after the eBPF program has returned.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -806,7 +806,7 @@ union bpf_attr {
  *             **ETH_P_8021Q** and **ETH_P_8021AD**, it is considered to
  *             be **ETH_P_8021Q**.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -818,7 +818,7 @@ union bpf_attr {
  *     Description
  *             Pop a VLAN header from the packet associated to *skb*.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1168,7 +1168,7 @@ union bpf_attr {
  *             All values for *flags* are reserved for future usage, and must
  *             be left at zero.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1281,7 +1281,7 @@ union bpf_attr {
  *             implicitly linearizes, unclones and drops offloads from the
  *             *skb*.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1317,7 +1317,7 @@ union bpf_attr {
  *             **bpf_skb_pull_data()** to effectively unclone the *skb* from
  *             the very beginning in case it is indeed cloned.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1369,7 +1369,7 @@ union bpf_attr {
  *             All values for *flags* are reserved for future usage, and must
  *             be left at zero.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1384,7 +1384,7 @@ union bpf_attr {
  *             can be used to prepare the packet for pushing or popping
  *             headers.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1518,20 +1518,20 @@ union bpf_attr {
  *             * **BPF_F_ADJ_ROOM_FIXED_GSO**: Do not adjust gso_size.
  *               Adjusting mss in this way is not allowed for datagrams.
  *
- *             * **BPF_F_ADJ_ROOM_ENCAP_L3_IPV4 **:
- *             * **BPF_F_ADJ_ROOM_ENCAP_L3_IPV6 **:
+ *             * **BPF_F_ADJ_ROOM_ENCAP_L3_IPV4**,
+ *               **BPF_F_ADJ_ROOM_ENCAP_L3_IPV6**:
  *               Any new space is reserved to hold a tunnel header.
  *               Configure skb offsets and other fields accordingly.
  *
- *             * **BPF_F_ADJ_ROOM_ENCAP_L4_GRE **:
- *             * **BPF_F_ADJ_ROOM_ENCAP_L4_UDP **:
+ *             * **BPF_F_ADJ_ROOM_ENCAP_L4_GRE**,
+ *               **BPF_F_ADJ_ROOM_ENCAP_L4_UDP**:
  *               Use with ENCAP_L3 flags to further specify the tunnel type.
  *
- *             * **BPF_F_ADJ_ROOM_ENCAP_L2(len) **:
+ *             * **BPF_F_ADJ_ROOM_ENCAP_L2**\ (*len*):
  *               Use with ENCAP_L3/L4 flags to further specify the tunnel
- *               type; **len** is the length of the inner MAC header.
+ *               type; *len* is the length of the inner MAC header.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1610,7 +1610,7 @@ union bpf_attr {
  *             more flexibility as the user is free to store whatever meta
  *             data they need.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1852,7 +1852,7 @@ union bpf_attr {
  *             copied if necessary (i.e. if data was not linear and if start
  *             and end pointers do not point to the same chunk).
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -1886,7 +1886,7 @@ union bpf_attr {
  *             only possible to shrink the packet as of this writing,
  *             therefore *delta* must be a negative integer.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -2061,18 +2061,18 @@ union bpf_attr {
  *             **BPF_LWT_ENCAP_IP**
  *                     IP encapsulation (GRE/GUE/IPIP/etc). The outer header
  *                     must be IPv4 or IPv6, followed by zero or more
- *                     additional headers, up to LWT_BPF_MAX_HEADROOM total
- *                     bytes in all prepended headers. Please note that
- *                     if skb_is_gso(skb) is true, no more than two headers
- *                     can be prepended, and the inner header, if present,
- *                     should be either GRE or UDP/GUE.
- *
- *             BPF_LWT_ENCAP_SEG6*** types can be called by bpf programs of
- *             type BPF_PROG_TYPE_LWT_IN; BPF_LWT_ENCAP_IP type can be called
- *             by bpf programs of types BPF_PROG_TYPE_LWT_IN and
- *             BPF_PROG_TYPE_LWT_XMIT.
- *
- *             A call to this helper is susceptible to change the underlaying
+ *                     additional headers, up to **LWT_BPF_MAX_HEADROOM**
+ *                     total bytes in all prepended headers. Please note that
+ *                     if **skb_is_gso**\ (*skb*) is true, no more than two
+ *                     headers can be prepended, and the inner header, if
+ *                     present, should be either GRE or UDP/GUE.
+ *
+ *             **BPF_LWT_ENCAP_SEG6**\ \* types can be called by BPF programs
+ *             of type **BPF_PROG_TYPE_LWT_IN**; **BPF_LWT_ENCAP_IP** type can
+ *             be called by bpf programs of types **BPF_PROG_TYPE_LWT_IN** and
+ *             **BPF_PROG_TYPE_LWT_XMIT**.
+ *
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -2087,7 +2087,7 @@ union bpf_attr {
  *             inside the outermost IPv6 Segment Routing Header can be
  *             modified through this helper.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -2103,7 +2103,7 @@ union bpf_attr {
  *             after the segments are accepted. *delta* can be as well
  *             positive (growing) as negative (shrinking).
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -2126,13 +2126,13 @@ union bpf_attr {
  *                     Type of *param*: **int**.
  *             **SEG6_LOCAL_ACTION_END_B6**
  *                     End.B6 action: Endpoint bound to an SRv6 policy.
- *                     Type of param: **struct ipv6_sr_hdr**.
+ *                     Type of *param*: **struct ipv6_sr_hdr**.
  *             **SEG6_LOCAL_ACTION_END_B6_ENCAP**
  *                     End.B6.Encap action: Endpoint bound to an SRv6
  *                     encapsulation policy.
- *                     Type of param: **struct ipv6_sr_hdr**.
+ *                     Type of *param*: **struct ipv6_sr_hdr**.
  *
- *             A call to this helper is susceptible to change the underlaying
+ *             A call to this helper is susceptible to change the underlying
  *             packet buffer. Therefore, at load time, all checks on pointers
  *             previously done by the verifier are invalidated and must be
  *             performed again, if the helper is used in combination with
@@ -2285,7 +2285,8 @@ union bpf_attr {
  *     Return
  *             Pointer to **struct bpf_sock**, or **NULL** in case of failure.
  *             For sockets with reuseport option, the **struct bpf_sock**
- *             result is from **reuse->socks**\ [] using the hash of the tuple.
+ *             result is from *reuse*\ **->socks**\ [] using the hash of the
+ *             tuple.
  *
  * struct bpf_sock *bpf_sk_lookup_udp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u64 netns, u64 flags)
  *     Description
@@ -2321,7 +2322,8 @@ union bpf_attr {
  *     Return
  *             Pointer to **struct bpf_sock**, or **NULL** in case of failure.
  *             For sockets with reuseport option, the **struct bpf_sock**
- *             result is from **reuse->socks**\ [] using the hash of the tuple.
+ *             result is from *reuse*\ **->socks**\ [] using the hash of the
+ *             tuple.
  *
  * int bpf_sk_release(struct bpf_sock *sock)
  *     Description
@@ -2490,31 +2492,34 @@ union bpf_attr {
  *             network namespace *netns*. The return value must be checked,
  *             and if non-**NULL**, released via **bpf_sk_release**\ ().
  *
- *             This function is identical to bpf_sk_lookup_tcp, except that it
- *             also returns timewait or request sockets. Use bpf_sk_fullsock
- *             or bpf_tcp_socket to access the full structure.
+ *             This function is identical to **bpf_sk_lookup_tcp**\ (), except
+ *             that it also returns timewait or request sockets. Use
+ *             **bpf_sk_fullsock**\ () or **bpf_tcp_sock**\ () to access the
+ *             full structure.
  *
  *             This helper is available only if the kernel was compiled with
  *             **CONFIG_NET** configuration option.
  *     Return
  *             Pointer to **struct bpf_sock**, or **NULL** in case of failure.
  *             For sockets with reuseport option, the **struct bpf_sock**
- *             result is from **reuse->socks**\ [] using the hash of the tuple.
+ *             result is from *reuse*\ **->socks**\ [] using the hash of the
+ *             tuple.
  *
  * int bpf_tcp_check_syncookie(struct bpf_sock *sk, void *iph, u32 iph_len, struct tcphdr *th, u32 th_len)
  *     Description
- *             Check whether iph and th contain a valid SYN cookie ACK for
- *             the listening socket in sk.
+ *             Check whether *iph* and *th* contain a valid SYN cookie ACK for
+ *             the listening socket in *sk*.
  *
- *             iph points to the start of the IPv4 or IPv6 header, while
- *             iph_len contains sizeof(struct iphdr) or sizeof(struct ip6hdr).
+ *             *iph* points to the start of the IPv4 or IPv6 header, while
+ *             *iph_len* contains **sizeof**\ (**struct iphdr**) or
+ *             **sizeof**\ (**struct ip6hdr**).
  *
- *             th points to the start of the TCP header, while th_len contains
- *             sizeof(struct tcphdr).
+ *             *th* points to the start of the TCP header, while *th_len*
+ *             contains **sizeof**\ (**struct tcphdr**).
  *
  *     Return
- *             0 if iph and th are a valid SYN cookie ACK, or a negative error
- *             otherwise.
+ *             0 if *iph* and *th* are a valid SYN cookie ACK, or a negative
+ *             error otherwise.
  *
  * int bpf_sysctl_get_name(struct bpf_sysctl *ctx, char *buf, size_t buf_len, u64 flags)
  *     Description
@@ -2592,17 +2597,17 @@ union bpf_attr {
  *             and save the result in *res*.
  *
  *             The string may begin with an arbitrary amount of white space
- *             (as determined by isspace(3)) followed by a single optional '-'
- *             sign.
+ *             (as determined by **isspace**\ (3)) followed by a single
+ *             optional '**-**' sign.
  *
  *             Five least significant bits of *flags* encode base, other bits
  *             are currently unused.
  *
  *             Base must be either 8, 10, 16 or 0 to detect it automatically
- *             similar to user space strtol(3).
+ *             similar to user space **strtol**\ (3).
  *     Return
  *             Number of characters consumed on success. Must be positive but
- *             no more than buf_len.
+ *             no more than *buf_len*.
  *
  *             **-EINVAL** if no valid digits were found or unsupported base
  *             was provided.
@@ -2616,16 +2621,16 @@ union bpf_attr {
  *             given base and save the result in *res*.
  *
  *             The string may begin with an arbitrary amount of white space
- *             (as determined by isspace(3)).
+ *             (as determined by **isspace**\ (3)).
  *
  *             Five least significant bits of *flags* encode base, other bits
  *             are currently unused.
  *
  *             Base must be either 8, 10, 16 or 0 to detect it automatically
- *             similar to user space strtoul(3).
+ *             similar to user space **strtoul**\ (3).
  *     Return
  *             Number of characters consumed on success. Must be positive but
- *             no more than buf_len.
+ *             no more than *buf_len*.
  *
  *             **-EINVAL** if no valid digits were found or unsupported base
  *             was provided.
@@ -2634,26 +2639,26 @@ union bpf_attr {
  *
  * void *bpf_sk_storage_get(struct bpf_map *map, struct bpf_sock *sk, void *value, u64 flags)
  *     Description
- *             Get a bpf-local-storage from a sk.
+ *             Get a bpf-local-storage from a *sk*.
  *
  *             Logically, it could be thought of getting the value from
  *             a *map* with *sk* as the **key**.  From this
  *             perspective,  the usage is not much different from
- *             **bpf_map_lookup_elem(map, &sk)** except this
- *             helper enforces the key must be a **bpf_fullsock()**
- *             and the map must be a BPF_MAP_TYPE_SK_STORAGE also.
+ *             **bpf_map_lookup_elem**\ (*map*, **&**\ *sk*) except this
+ *             helper enforces the key must be a full socket and the map must
+ *             be a **BPF_MAP_TYPE_SK_STORAGE** also.
  *
  *             Underneath, the value is stored locally at *sk* instead of
- *             the map.  The *map* is used as the bpf-local-storage **type**.
- *             The bpf-local-storage **type** (i.e. the *map*) is searched
- *             against all bpf-local-storages residing at sk.
+ *             the *map*.  The *map* is used as the bpf-local-storage
+ *             "type". The bpf-local-storage "type" (i.e. the *map*) is
+ *             searched against all bpf-local-storages residing at *sk*.
  *
- *             An optional *flags* (BPF_SK_STORAGE_GET_F_CREATE) can be
+ *             An optional *flags* (**BPF_SK_STORAGE_GET_F_CREATE**) can be
  *             used such that a new bpf-local-storage will be
  *             created if one does not exist.  *value* can be used
- *             together with BPF_SK_STORAGE_GET_F_CREATE to specify
+ *             together with **BPF_SK_STORAGE_GET_F_CREATE** to specify
  *             the initial value of a bpf-local-storage.  If *value* is
- *             NULL, the new bpf-local-storage will be zero initialized.
+ *             **NULL**, the new bpf-local-storage will be zero initialized.
  *     Return
  *             A bpf-local-storage pointer is returned on success.
  *
@@ -2662,7 +2667,7 @@ union bpf_attr {
  *
  * int bpf_sk_storage_delete(struct bpf_map *map, struct bpf_sock *sk)
  *     Description
- *             Delete a bpf-local-storage from a sk.
+ *             Delete a bpf-local-storage from a *sk*.
  *     Return
  *             0 on success.
  *
index 11a65db4b93fbf15320148c5f8a05da84febe385..7e3b79d7c25f68487285d6f3b218da6c4f45a481 100644 (file)
@@ -44,6 +44,7 @@
 #include "btf.h"
 #include "str_error.h"
 #include "libbpf_util.h"
+#include "libbpf_internal.h"
 
 #ifndef EM_BPF
 #define EM_BPF 247
@@ -128,6 +129,10 @@ struct bpf_capabilities {
        __u32 name:1;
        /* v5.2: kernel support for global data sections. */
        __u32 global_data:1;
+       /* BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO support */
+       __u32 btf_func:1;
+       /* BTF_KIND_VAR and BTF_KIND_DATASEC support */
+       __u32 btf_datasec:1;
 };
 
 /*
@@ -1021,6 +1026,74 @@ static bool section_have_execinstr(struct bpf_object *obj, int idx)
        return false;
 }
 
+static void bpf_object__sanitize_btf(struct bpf_object *obj)
+{
+       bool has_datasec = obj->caps.btf_datasec;
+       bool has_func = obj->caps.btf_func;
+       struct btf *btf = obj->btf;
+       struct btf_type *t;
+       int i, j, vlen;
+       __u16 kind;
+
+       if (!obj->btf || (has_func && has_datasec))
+               return;
+
+       for (i = 1; i <= btf__get_nr_types(btf); i++) {
+               t = (struct btf_type *)btf__type_by_id(btf, i);
+               kind = BTF_INFO_KIND(t->info);
+
+               if (!has_datasec && kind == BTF_KIND_VAR) {
+                       /* replace VAR with INT */
+                       t->info = BTF_INFO_ENC(BTF_KIND_INT, 0, 0);
+                       t->size = sizeof(int);
+                       *(int *)(t+1) = BTF_INT_ENC(0, 0, 32);
+               } else if (!has_datasec && kind == BTF_KIND_DATASEC) {
+                       /* replace DATASEC with STRUCT */
+                       struct btf_var_secinfo *v = (void *)(t + 1);
+                       struct btf_member *m = (void *)(t + 1);
+                       struct btf_type *vt;
+                       char *name;
+
+                       name = (char *)btf__name_by_offset(btf, t->name_off);
+                       while (*name) {
+                               if (*name == '.')
+                                       *name = '_';
+                               name++;
+                       }
+
+                       vlen = BTF_INFO_VLEN(t->info);
+                       t->info = BTF_INFO_ENC(BTF_KIND_STRUCT, 0, vlen);
+                       for (j = 0; j < vlen; j++, v++, m++) {
+                               /* order of field assignments is important */
+                               m->offset = v->offset * 8;
+                               m->type = v->type;
+                               /* preserve variable name as member name */
+                               vt = (void *)btf__type_by_id(btf, v->type);
+                               m->name_off = vt->name_off;
+                       }
+               } else if (!has_func && kind == BTF_KIND_FUNC_PROTO) {
+                       /* replace FUNC_PROTO with ENUM */
+                       vlen = BTF_INFO_VLEN(t->info);
+                       t->info = BTF_INFO_ENC(BTF_KIND_ENUM, 0, vlen);
+                       t->size = sizeof(__u32); /* kernel enforced */
+               } else if (!has_func && kind == BTF_KIND_FUNC) {
+                       /* replace FUNC with TYPEDEF */
+                       t->info = BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, 0);
+               }
+       }
+}
+
+static void bpf_object__sanitize_btf_ext(struct bpf_object *obj)
+{
+       if (!obj->btf_ext)
+               return;
+
+       if (!obj->caps.btf_func) {
+               btf_ext__free(obj->btf_ext);
+               obj->btf_ext = NULL;
+       }
+}
+
 static int bpf_object__elf_collect(struct bpf_object *obj, int flags)
 {
        Elf *elf = obj->efile.elf;
@@ -1164,8 +1237,10 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)
                        obj->btf = NULL;
                } else {
                        err = btf__finalize_data(obj, obj->btf);
-                       if (!err)
+                       if (!err) {
+                               bpf_object__sanitize_btf(obj);
                                err = btf__load(obj->btf);
+                       }
                        if (err) {
                                pr_warning("Error finalizing and loading %s into kernel: %d. Ignored and continue.\n",
                                           BTF_ELF_SEC, err);
@@ -1187,6 +1262,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)
                                           BTF_EXT_ELF_SEC,
                                           PTR_ERR(obj->btf_ext));
                                obj->btf_ext = NULL;
+                       } else {
+                               bpf_object__sanitize_btf_ext(obj);
                        }
                }
        }
@@ -1556,12 +1633,63 @@ bpf_object__probe_global_data(struct bpf_object *obj)
        return 0;
 }
 
+static int bpf_object__probe_btf_func(struct bpf_object *obj)
+{
+       const char strs[] = "\0int\0x\0a";
+       /* void x(int a) {} */
+       __u32 types[] = {
+               /* int */
+               BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4),  /* [1] */
+               /* FUNC_PROTO */                                /* [2] */
+               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0),
+               BTF_PARAM_ENC(7, 1),
+               /* FUNC x */                                    /* [3] */
+               BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 0), 2),
+       };
+       int res;
+
+       res = libbpf__probe_raw_btf((char *)types, sizeof(types),
+                                   strs, sizeof(strs));
+       if (res < 0)
+               return res;
+       if (res > 0)
+               obj->caps.btf_func = 1;
+       return 0;
+}
+
+static int bpf_object__probe_btf_datasec(struct bpf_object *obj)
+{
+       const char strs[] = "\0x\0.data";
+       /* static int a; */
+       __u32 types[] = {
+               /* int */
+               BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),  /* [1] */
+               /* VAR x */                                     /* [2] */
+               BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1),
+               BTF_VAR_STATIC,
+               /* DATASEC val */                               /* [3] */
+               BTF_TYPE_ENC(3, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
+               BTF_VAR_SECINFO_ENC(2, 0, 4),
+       };
+       int res;
+
+       res = libbpf__probe_raw_btf((char *)types, sizeof(types),
+                                   strs, sizeof(strs));
+       if (res < 0)
+               return res;
+       if (res > 0)
+               obj->caps.btf_datasec = 1;
+       return 0;
+}
+
 static int
 bpf_object__probe_caps(struct bpf_object *obj)
 {
        int (*probe_fn[])(struct bpf_object *obj) = {
                bpf_object__probe_name,
                bpf_object__probe_global_data,
+               bpf_object__probe_btf_func,
+               bpf_object__probe_btf_datasec,
        };
        int i, ret;
 
diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
new file mode 100644 (file)
index 0000000..789e435
--- /dev/null
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
+
+/*
+ * Internal libbpf helpers.
+ *
+ * Copyright (c) 2019 Facebook
+ */
+
+#ifndef __LIBBPF_LIBBPF_INTERNAL_H
+#define __LIBBPF_LIBBPF_INTERNAL_H
+
+#define BTF_INFO_ENC(kind, kind_flag, vlen) \
+       ((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
+#define BTF_TYPE_ENC(name, info, size_or_type) (name), (info), (size_or_type)
+#define BTF_INT_ENC(encoding, bits_offset, nr_bits) \
+       ((encoding) << 24 | (bits_offset) << 16 | (nr_bits))
+#define BTF_TYPE_INT_ENC(name, encoding, bits_offset, bits, sz) \
+       BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), sz), \
+       BTF_INT_ENC(encoding, bits_offset, bits)
+#define BTF_MEMBER_ENC(name, type, bits_offset) (name), (type), (bits_offset)
+#define BTF_PARAM_ENC(name, type) (name), (type)
+#define BTF_VAR_SECINFO_ENC(type, offset, size) (type), (offset), (size)
+
+int libbpf__probe_raw_btf(const char *raw_types, size_t types_len,
+                         const char *str_sec, size_t str_len);
+
+#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
index a2c64a9ce1a63cf40306d7a70f6f607624dd8de1..5e2aa83f637a4726dd9b6c0b8628f1cd83bc225d 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "bpf.h"
 #include "libbpf.h"
+#include "libbpf_internal.h"
 
 static bool grep(const char *buffer, const char *pattern)
 {
@@ -132,21 +133,43 @@ bool bpf_probe_prog_type(enum bpf_prog_type prog_type, __u32 ifindex)
        return errno != EINVAL && errno != EOPNOTSUPP;
 }
 
-static int load_btf(void)
+int libbpf__probe_raw_btf(const char *raw_types, size_t types_len,
+                         const char *str_sec, size_t str_len)
 {
-#define BTF_INFO_ENC(kind, kind_flag, vlen) \
-       ((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
-#define BTF_TYPE_ENC(name, info, size_or_type) \
-       (name), (info), (size_or_type)
-#define BTF_INT_ENC(encoding, bits_offset, nr_bits) \
-       ((encoding) << 24 | (bits_offset) << 16 | (nr_bits))
-#define BTF_TYPE_INT_ENC(name, encoding, bits_offset, bits, sz) \
-       BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), sz), \
-       BTF_INT_ENC(encoding, bits_offset, bits)
-#define BTF_MEMBER_ENC(name, type, bits_offset) \
-       (name), (type), (bits_offset)
-
-       const char btf_str_sec[] = "\0bpf_spin_lock\0val\0cnt\0l";
+       struct btf_header hdr = {
+               .magic = BTF_MAGIC,
+               .version = BTF_VERSION,
+               .hdr_len = sizeof(struct btf_header),
+               .type_len = types_len,
+               .str_off = types_len,
+               .str_len = str_len,
+       };
+       int btf_fd, btf_len;
+       __u8 *raw_btf;
+
+       btf_len = hdr.hdr_len + hdr.type_len + hdr.str_len;
+       raw_btf = malloc(btf_len);
+       if (!raw_btf)
+               return -ENOMEM;
+
+       memcpy(raw_btf, &hdr, sizeof(hdr));
+       memcpy(raw_btf + hdr.hdr_len, raw_types, hdr.type_len);
+       memcpy(raw_btf + hdr.hdr_len + hdr.type_len, str_sec, hdr.str_len);
+
+       btf_fd = bpf_load_btf(raw_btf, btf_len, NULL, 0, false);
+       if (btf_fd < 0) {
+               free(raw_btf);
+               return 0;
+       }
+
+       close(btf_fd);
+       free(raw_btf);
+       return 1;
+}
+
+static int load_sk_storage_btf(void)
+{
+       const char strs[] = "\0bpf_spin_lock\0val\0cnt\0l";
        /* struct bpf_spin_lock {
         *   int val;
         * };
@@ -155,7 +178,7 @@ static int load_btf(void)
         *   struct bpf_spin_lock l;
         * };
         */
-       __u32 btf_raw_types[] = {
+       __u32 types[] = {
                /* int */
                BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),  /* [1] */
                /* struct bpf_spin_lock */                      /* [2] */
@@ -166,23 +189,9 @@ static int load_btf(void)
                BTF_MEMBER_ENC(19, 1, 0), /* int cnt; */
                BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */
        };
-       struct btf_header btf_hdr = {
-               .magic = BTF_MAGIC,
-               .version = BTF_VERSION,
-               .hdr_len = sizeof(struct btf_header),
-               .type_len = sizeof(btf_raw_types),
-               .str_off = sizeof(btf_raw_types),
-               .str_len = sizeof(btf_str_sec),
-       };
-       __u8 raw_btf[sizeof(struct btf_header) + sizeof(btf_raw_types) +
-                    sizeof(btf_str_sec)];
-
-       memcpy(raw_btf, &btf_hdr, sizeof(btf_hdr));
-       memcpy(raw_btf + sizeof(btf_hdr), btf_raw_types, sizeof(btf_raw_types));
-       memcpy(raw_btf + sizeof(btf_hdr) + sizeof(btf_raw_types),
-              btf_str_sec, sizeof(btf_str_sec));
 
-       return bpf_load_btf(raw_btf, sizeof(raw_btf), 0, 0, 0);
+       return libbpf__probe_raw_btf((char *)types, sizeof(types),
+                                    strs, sizeof(strs));
 }
 
 bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
@@ -222,7 +231,7 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
                value_size = 8;
                max_entries = 0;
                map_flags = BPF_F_NO_PREALLOC;
-               btf_fd = load_btf();
+               btf_fd = load_sk_storage_btf();
                if (btf_fd < 0)
                        return false;
                break;
index 8df526c80b6575b97c8bfe72317cc628633c323a..4dd11a554b9b2f7509c1bb8725e7217df33e898f 100644 (file)
@@ -306,7 +306,7 @@ ignore it:
 
 - To skip validation of a file, add
 
-    OBJECT_FILES_NON_STANDARD_filename.o := n
+    OBJECT_FILES_NON_STANDARD_filename.o := y
 
   to the Makefile.
 
index ac743a1d53ab321a8a664fab6ef9a4f3a04b6dfa..7325d89ccad93dec63603d850da0d7a6f50f863a 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/hashtable.h>
 #include <linux/kernel.h>
 
+#define FAKE_JUMP_OFFSET -1
+
 struct alternative {
        struct list_head list;
        struct instruction *insn;
@@ -568,7 +570,7 @@ static int add_jump_destinations(struct objtool_file *file)
                    insn->type != INSN_JUMP_UNCONDITIONAL)
                        continue;
 
-               if (insn->ignore)
+               if (insn->ignore || insn->offset == FAKE_JUMP_OFFSET)
                        continue;
 
                rela = find_rela_by_dest_range(insn->sec, insn->offset,
@@ -745,10 +747,10 @@ static int handle_group_alt(struct objtool_file *file,
                clear_insn_state(&fake_jump->state);
 
                fake_jump->sec = special_alt->new_sec;
-               fake_jump->offset = -1;
+               fake_jump->offset = FAKE_JUMP_OFFSET;
                fake_jump->type = INSN_JUMP_UNCONDITIONAL;
                fake_jump->jump_dest = list_next_entry(last_orig_insn, list);
-               fake_jump->ignore = true;
+               fake_jump->func = orig_insn->func;
        }
 
        if (!special_alt->new_len) {
@@ -1957,7 +1959,8 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
                        return 1;
                }
 
-               func = insn->func ? insn->func->pfunc : NULL;
+               if (insn->func)
+                       func = insn->func->pfunc;
 
                if (func && insn->ignore) {
                        WARN_FUNC("BUG: why am I validating an ignored function?",
index 46e4c2f318c902274b6786b9b5ab83ee2ece8fa6..9b7534457060e378b38bf639625204a18f3796d2 100644 (file)
@@ -14,9 +14,12 @@ MAKEFLAGS += -r
 
 CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
 
-ALL_TARGETS := pcitest pcitest.sh
+ALL_TARGETS := pcitest
 ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
 
+SCRIPTS := pcitest.sh
+ALL_SCRIPTS := $(patsubst %,$(OUTPUT)%,$(SCRIPTS))
+
 all: $(ALL_PROGRAMS)
 
 export srctree OUTPUT CC LD CFLAGS
@@ -46,6 +49,9 @@ install: $(ALL_PROGRAMS)
        install -d -m 755 $(DESTDIR)$(bindir);          \
        for program in $(ALL_PROGRAMS); do              \
                install $$program $(DESTDIR)$(bindir);  \
+       done;                                           \
+       for script in $(ALL_SCRIPTS); do                \
+               install $$script $(DESTDIR)$(bindir);   \
        done
 
 FORCE:
index ec4d51f3308b87be876693086ba57dc1cf6498e4..5fa5c2bdd427c0d05f2787f362a685876f448c32 100644 (file)
@@ -140,6 +140,7 @@ static void run_test(struct pci_test *test)
        }
 
        fflush(stdout);
+       return (ret < 0) ? ret : 1 - ret; /* return 0 if test succeeded */
 }
 
 int main(int argc, char **argv)
@@ -162,7 +163,7 @@ int main(int argc, char **argv)
        /* set default endpoint device */
        test->device = "/dev/pci-endpoint-test.0";
 
-       while ((c = getopt(argc, argv, "D:b:m:x:i:Ilrwcs:")) != EOF)
+       while ((c = getopt(argc, argv, "D:b:m:x:i:Ilhrwcs:")) != EOF)
        switch (c) {
        case 'D':
                test->device = optarg;
@@ -206,7 +207,6 @@ int main(int argc, char **argv)
        case 's':
                test->size = strtoul(optarg, NULL, 0);
                continue;
-       case '?':
        case 'h':
        default:
 usage:
@@ -224,10 +224,10 @@ usage:
                        "\t-w                   Write buffer test\n"
                        "\t-c                   Copy buffer test\n"
                        "\t-s <size>            Size of buffer {default: 100KB}\n",
+                       "\t-h                   Print this help message\n",
                        argv[0]);
                return -EINVAL;
        }
 
-       run_test(test);
-       return 0;
+       return run_test(test);
 }
index 1598b4fa0b11222bef515bcaa056df609a6a856f..045f5f7d68ab5d9836a3abe5170ab14ad172b379 100644 (file)
@@ -9,7 +9,7 @@ ifeq ("$(origin O)", "command line")
 endif
 
 turbostat : turbostat.c
-override CFLAGS +=     -Wall
+override CFLAGS +=     -Wall -I../../../include
 override CFLAGS +=     -DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
 override CFLAGS +=     -DINTEL_FAMILY_HEADER='"../../../../arch/x86/include/asm/intel-family.h"'
 
index ae7a0e09b72276219f302517a7b1e0660ded3fcb..1fdeef864e7c1b43a97ad5b3d8a47523f98a5027 100644 (file)
@@ -9,7 +9,7 @@ ifeq ("$(origin O)", "command line")
 endif
 
 x86_energy_perf_policy : x86_energy_perf_policy.c
-override CFLAGS +=     -Wall
+override CFLAGS +=     -Wall -I../../../include
 override CFLAGS +=     -DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
 
 %: %.c
index 275ad8ac8872c67e2ba0e3c34fc566a48adb5bb3..4711f57e809af6d2eb31ec9d05201728143b10b9 100755 (executable)
@@ -64,6 +64,7 @@ my %default = (
     "STOP_TEST_AFTER"          => 600,
     "MAX_MONITOR_WAIT"         => 1800,
     "GRUB_REBOOT"              => "grub2-reboot",
+    "GRUB_BLS_GET"             => "grubby --info=ALL",
     "SYSLINUX"                 => "extlinux",
     "SYSLINUX_PATH"            => "/boot/extlinux",
     "CONNECT_TIMEOUT"          => 25,
@@ -125,6 +126,7 @@ my $last_grub_menu;
 my $grub_file;
 my $grub_number;
 my $grub_reboot;
+my $grub_bls_get;
 my $syslinux;
 my $syslinux_path;
 my $syslinux_label;
@@ -295,6 +297,7 @@ my %option_map = (
     "GRUB_MENU"                        => \$grub_menu,
     "GRUB_FILE"                        => \$grub_file,
     "GRUB_REBOOT"              => \$grub_reboot,
+    "GRUB_BLS_GET"             => \$grub_bls_get,
     "SYSLINUX"                 => \$syslinux,
     "SYSLINUX_PATH"            => \$syslinux_path,
     "SYSLINUX_LABEL"           => \$syslinux_label,
@@ -440,7 +443,7 @@ EOF
     ;
 $config_help{"REBOOT_TYPE"} = << "EOF"
  Way to reboot the box to the test kernel.
- Only valid options so far are "grub", "grub2", "syslinux", and "script".
+ Only valid options so far are "grub", "grub2", "grub2bls", "syslinux", and "script".
 
  If you specify grub, it will assume grub version 1
  and will search in /boot/grub/menu.lst for the title \$GRUB_MENU
@@ -454,6 +457,8 @@ $config_help{"REBOOT_TYPE"} = << "EOF"
  If you specify grub2, then you also need to specify both \$GRUB_MENU
  and \$GRUB_FILE.
 
+ If you specify grub2bls, then you also need to specify \$GRUB_MENU.
+
  If you specify syslinux, then you may use SYSLINUX to define the syslinux
  command (defaults to extlinux), and SYSLINUX_PATH to specify the path to
  the syslinux install (defaults to /boot/extlinux). But you have to specify
@@ -479,6 +484,9 @@ $config_help{"GRUB_MENU"} = << "EOF"
  menu must be a non-nested menu. Add the quotes used in the menu
  to guarantee your selection, as the first menuentry with the content
  of \$GRUB_MENU that is found will be used.
+
+ For grub2bls, \$GRUB_MENU is searched on the result of \$GRUB_BLS_GET
+ command for the lines that begin with "title".
 EOF
     ;
 $config_help{"GRUB_FILE"} = << "EOF"
@@ -695,7 +703,7 @@ sub get_mandatory_configs {
        }
     }
 
-    if ($rtype eq "grub") {
+    if (($rtype eq "grub") or ($rtype eq "grub2bls")) {
        get_mandatory_config("GRUB_MENU");
     }
 
@@ -1871,36 +1879,37 @@ sub run_scp_mod {
     return run_scp($src, $dst, $cp_scp);
 }
 
-sub get_grub2_index {
+sub _get_grub_index {
+
+    my ($command, $target, $skip) = @_;
 
     return if (defined($grub_number) && defined($last_grub_menu) &&
               $last_grub_menu eq $grub_menu && defined($last_machine) &&
               $last_machine eq $machine);
 
-    doprint "Find grub2 menu ... ";
+    doprint "Find $reboot_type menu ... ";
     $grub_number = -1;
 
     my $ssh_grub = $ssh_exec;
-    $ssh_grub =~ s,\$SSH_COMMAND,cat $grub_file,g;
+    $ssh_grub =~ s,\$SSH_COMMAND,$command,g;
 
     open(IN, "$ssh_grub |")
-       or dodie "unable to get $grub_file";
+       or dodie "unable to execute $command";
 
     my $found = 0;
-    my $grub_menu_qt = quotemeta($grub_menu);
 
     while (<IN>) {
-       if (/^menuentry.*$grub_menu_qt/) {
+       if (/$target/) {
            $grub_number++;
            $found = 1;
            last;
-       } elsif (/^menuentry\s|^submenu\s/) {
+       } elsif (/$skip/) {
            $grub_number++;
        }
     }
     close(IN);
 
-    dodie "Could not find '$grub_menu' in $grub_file on $machine"
+    dodie "Could not find '$grub_menu' through $command on $machine"
        if (!$found);
     doprint "$grub_number\n";
     $last_grub_menu = $grub_menu;
@@ -1909,46 +1918,34 @@ sub get_grub2_index {
 
 sub get_grub_index {
 
-    if ($reboot_type eq "grub2") {
-       get_grub2_index;
-       return;
-    }
+    my $command;
+    my $target;
+    my $skip;
+    my $grub_menu_qt;
 
-    if ($reboot_type ne "grub") {
+    if ($reboot_type !~ /^grub/) {
        return;
     }
-    return if (defined($grub_number) && defined($last_grub_menu) &&
-              $last_grub_menu eq $grub_menu && defined($last_machine) &&
-              $last_machine eq $machine);
 
-    doprint "Find grub menu ... ";
-    $grub_number = -1;
-
-    my $ssh_grub = $ssh_exec;
-    $ssh_grub =~ s,\$SSH_COMMAND,cat /boot/grub/menu.lst,g;
-
-    open(IN, "$ssh_grub |")
-       or dodie "unable to get menu.lst";
-
-    my $found = 0;
-    my $grub_menu_qt = quotemeta($grub_menu);
+    $grub_menu_qt = quotemeta($grub_menu);
 
-    while (<IN>) {
-       if (/^\s*title\s+$grub_menu_qt\s*$/) {
-           $grub_number++;
-           $found = 1;
-           last;
-       } elsif (/^\s*title\s/) {
-           $grub_number++;
-       }
+    if ($reboot_type eq "grub") {
+       $command = "cat /boot/grub/menu.lst";
+       $target = '^\s*title\s+' . $grub_menu_qt . '\s*$';
+       $skip = '^\s*title\s';
+    } elsif ($reboot_type eq "grub2") {
+       $command = "cat $grub_file";
+       $target = '^menuentry.*' . $grub_menu_qt;
+       $skip = '^menuentry\s|^submenu\s';
+    } elsif ($reboot_type eq "grub2bls") {
+        $command = $grub_bls_get;
+        $target = '^title=.*' . $grub_menu_qt;
+        $skip = '^title=';
+    } else {
+       return;
     }
-    close(IN);
 
-    dodie "Could not find '$grub_menu' in /boot/grub/menu on $machine"
-       if (!$found);
-    doprint "$grub_number\n";
-    $last_grub_menu = $grub_menu;
-    $last_machine = $machine;
+    _get_grub_index($command, $target, $skip);
 }
 
 sub wait_for_input
@@ -4303,7 +4300,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
 
     if (!$buildonly) {
        $target = "$ssh_user\@$machine";
-       if ($reboot_type eq "grub") {
+       if (($reboot_type eq "grub") or ($reboot_type eq "grub2bls")) {
            dodie "GRUB_MENU not defined" if (!defined($grub_menu));
        } elsif ($reboot_type eq "grub2") {
            dodie "GRUB_MENU not defined" if (!defined($grub_menu));
@@ -4423,7 +4420,9 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
 }
 
 if (defined($final_post_ktest)) {
-    run_command $final_post_ktest;
+
+    my $cp_final_post_ktest = eval_kernel_version $final_post_ktest;
+    run_command $cp_final_post_ktest;
 }
 
 if ($opt{"POWEROFF_ON_SUCCESS"}) {
index 8c893a58b68eea9fba9b5530b46e8ab3b2e89ff7..c3bc933d437b34d3f9e77029908517d6a53b0e32 100644 (file)
 # option to boot to with GRUB_REBOOT
 #GRUB_FILE = /boot/grub2/grub.cfg
 
-# The tool for REBOOT_TYPE = grub2 to set the next reboot kernel
+# The tool for REBOOT_TYPE = grub2 or grub2bls to set the next reboot kernel
 # to boot into (one shot mode).
 # (default grub2_reboot)
 #GRUB_REBOOT = grub2_reboot
 
 # The grub title name for the test kernel to boot
-# (Only mandatory if REBOOT_TYPE = grub or grub2)
+# (Only mandatory if REBOOT_TYPE = grub or grub2 or grub2bls)
 #
 # Note, ktest.pl will not update the grub menu.lst, you need to
 # manually add an option for the test. ktest.pl will search
 # do a: GRUB_MENU = 'Test Kernel'
 # For customizing, add your entry in /etc/grub.d/40_custom.
 #
+# For grub2bls, a search of "title"s are done. The menu is found
+# by searching for the contents of GRUB_MENU in the line that starts
+# with "title".
+#
 #GRUB_MENU = Test Kernel
 
 # For REBOOT_TYPE = syslinux, the name of the syslinux executable
 # default (undefined)
 #POST_KTEST = ${SSH} ~/dismantle_test
 
+# If you want to remove the kernel entry in Boot Loader Specification (BLS)
+# environment, use kernel-install command.
+# Here's the example:
+#POST_KTEST = ssh root@Test "/usr/bin/kernel-install remove $KERNEL_VERSION"
+
 # The default test type (default test)
 # The test types may be:
 #   build   - only build the kernel, do nothing else
 # or on some systems:
 #POST_INSTALL = ssh user@target /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION
 
+# If you want to add the kernel entry in Boot Loader Specification (BLS)
+# environment, use kernel-install command.
+# Here's the example:
+#POST_INSTALL = ssh root@Test "/usr/bin/kernel-install add $KERNEL_VERSION /boot/vmlinuz-$KERNEL_VERSION"
+
 # If for some reason you just want to boot the kernel and you do not
 # want the test to install anything new. For example, you may just want
 # to boot test the same kernel over and over and do not want to go through
 # For REBOOT_TYPE = grub2, you must define both GRUB_MENU and
 # GRUB_FILE.
 #
+# For REBOOT_TYPE = grub2bls, you must define GRUB_MENU.
+#
 # For REBOOT_TYPE = syslinux, you must define SYSLINUX_LABEL, and
 # perhaps modify SYSLINUX (default extlinux) and SYSLINUX_PATH
 # (default /boot/extlinux)
index e1286d2cdfbf928d9f419996baa90ac95e50f6af..c4a9196d794c9d42251400122884a28b3ef9b492 100644 (file)
@@ -68,8 +68,11 @@ device_dax-y += device_dax_test.o
 device_dax-y += config_check.o
 
 dax_pmem-y := $(DAX_SRC)/pmem/pmem.o
+dax_pmem-y += dax_pmem_test.o
 dax_pmem_core-y := $(DAX_SRC)/pmem/core.o
+dax_pmem_core-y += dax_pmem_core_test.o
 dax_pmem_compat-y := $(DAX_SRC)/pmem/compat.o
+dax_pmem_compat-y += dax_pmem_compat_test.o
 dax_pmem-y += config_check.o
 
 libnvdimm-y := $(NVDIMM_SRC)/core.o
diff --git a/tools/testing/nvdimm/dax_pmem_compat_test.c b/tools/testing/nvdimm/dax_pmem_compat_test.c
new file mode 100644 (file)
index 0000000..7cd1877
--- /dev/null
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2019 Intel Corporation. All rights reserved.
+
+#include <linux/module.h>
+#include <linux/printk.h>
+#include "watermark.h"
+
+nfit_test_watermark(dax_pmem_compat);
diff --git a/tools/testing/nvdimm/dax_pmem_core_test.c b/tools/testing/nvdimm/dax_pmem_core_test.c
new file mode 100644 (file)
index 0000000..a4249cd
--- /dev/null
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2019 Intel Corporation. All rights reserved.
+
+#include <linux/module.h>
+#include <linux/printk.h>
+#include "watermark.h"
+
+nfit_test_watermark(dax_pmem_core);
diff --git a/tools/testing/nvdimm/dax_pmem_test.c b/tools/testing/nvdimm/dax_pmem_test.c
new file mode 100644 (file)
index 0000000..fd4c94a
--- /dev/null
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2019 Intel Corporation. All rights reserved.
+
+#include <linux/module.h>
+#include <linux/printk.h>
+#include "watermark.h"
+
+nfit_test_watermark(dax_pmem);
index 85ffdcfa596b5011b93abf3c65e90cd33cceb61f..bb4225cdf666cc95b13b2bf90267a50a44524d5c 100644 (file)
@@ -3171,6 +3171,9 @@ static __init int nfit_test_init(void)
        acpi_nfit_test();
        device_dax_test();
        mcsafe_test();
+       dax_pmem_test();
+       dax_pmem_core_test();
+       dax_pmem_compat_test();
 
        nfit_test_setup(nfit_test_lookup, nfit_test_evaluate_dsm);
 
index ed0528757bd47f2fa94be31804aa97c0c66aff22..43fc4f3e7927d4e73ae29eece95ad364b75397b2 100644 (file)
@@ -6,6 +6,9 @@ int pmem_test(void);
 int libnvdimm_test(void);
 int acpi_nfit_test(void);
 int device_dax_test(void);
+int dax_pmem_test(void);
+int dax_pmem_core_test(void);
+int dax_pmem_compat_test(void);
 
 /*
  * dummy routine for nfit_test to validate it is linking to the properly
index 91750352459dfd9c3cc2bb81f99f5f9ef74ed7f3..8059ce8342477fce62e68f1205554bf7e9189525 100644 (file)
@@ -1,4 +1,3 @@
-kselftest
 gpiogpio-event-mon
 gpiogpio-hammer
 gpioinclude/
index f2ebf8cf46869fb151dd4feb96477c9374563a68..9781ca79794af774ca86b3ef0708283cfa73db0a 100644 (file)
@@ -71,6 +71,9 @@ override LDFLAGS =
 override MAKEFLAGS =
 endif
 
+# Append kselftest to KBUILD_OUTPUT to avoid cluttering
+# KBUILD_OUTPUT with selftest objects and headers installed
+# by selftests Makefile or lib.mk.
 ifneq ($(KBUILD_SRC),)
 override LDFLAGS =
 endif
@@ -79,19 +82,13 @@ ifneq ($(O),)
        BUILD := $(O)
 else
        ifneq ($(KBUILD_OUTPUT),)
-               BUILD := $(KBUILD_OUTPUT)
+               BUILD := $(KBUILD_OUTPUT)/kselftest
        else
                BUILD := $(shell pwd)
                DEFAULT_INSTALL_HDR_PATH := 1
        endif
 endif
 
-# KSFT_TAP_LEVEL is used from KSFT framework to prevent nested TAP header
-# printing from tests. Applicable to run_tests case where run_tests adds
-# TAP header prior running tests and when a test program invokes another
-# with system() call. Export it here to cover override RUN_TESTS defines.
-export KSFT_TAP_LEVEL=`echo 1`
-
 # Prepare for headers install
 top_srcdir ?= ../../..
 include $(top_srcdir)/scripts/subarch.include
@@ -169,14 +166,22 @@ clean_hotplug:
 run_pstore_crash:
        make -C pstore run_crash
 
-INSTALL_PATH ?= install
+# Use $BUILD as the default install root. $BUILD points to the
+# right output location for the following cases:
+# 1. output_dir=kernel_src
+# 2. a separate output directory is specified using O= KBUILD_OUTPUT
+# 3. a separate output directory is specified using KBUILD_OUTPUT
+#
+INSTALL_PATH ?= $(BUILD)/install
 INSTALL_PATH := $(abspath $(INSTALL_PATH))
 ALL_SCRIPT := $(INSTALL_PATH)/run_kselftest.sh
 
-install:
+install: all
 ifdef INSTALL_PATH
        @# Ask all targets to install their files
-       mkdir -p $(INSTALL_PATH)
+       mkdir -p $(INSTALL_PATH)/kselftest
+       install -m 744 kselftest/runner.sh $(INSTALL_PATH)/kselftest/
+       install -m 744 kselftest/prefix.pl $(INSTALL_PATH)/kselftest/
        @for TARGET in $(TARGETS); do \
                BUILD_TARGET=$$BUILD/$$TARGET;  \
                make OUTPUT=$$BUILD_TARGET -C $$TARGET INSTALL_PATH=$(INSTALL_PATH)/$$TARGET install; \
@@ -186,24 +191,20 @@ ifdef INSTALL_PATH
        echo "#!/bin/sh" > $(ALL_SCRIPT)
        echo "BASE_DIR=\$$(realpath \$$(dirname \$$0))" >> $(ALL_SCRIPT)
        echo "cd \$$BASE_DIR" >> $(ALL_SCRIPT)
+       echo ". ./kselftest/runner.sh" >> $(ALL_SCRIPT)
        echo "ROOT=\$$PWD" >> $(ALL_SCRIPT)
        echo "if [ \"\$$1\" = \"--summary\" ]; then" >> $(ALL_SCRIPT)
-       echo "  OUTPUT=\$$BASE_DIR/output.log" >> $(ALL_SCRIPT)
-       echo "  cat /dev/null > \$$OUTPUT" >> $(ALL_SCRIPT)
-       echo "else" >> $(ALL_SCRIPT)
-       echo "  OUTPUT=/dev/stdout" >> $(ALL_SCRIPT)
+       echo "  logfile=\$$BASE_DIR/output.log" >> $(ALL_SCRIPT)
+       echo "  cat /dev/null > \$$logfile" >> $(ALL_SCRIPT)
        echo "fi" >> $(ALL_SCRIPT)
-       echo "export KSFT_TAP_LEVEL=1" >> $(ALL_SCRIPT)
-       echo "export skip=4" >> $(ALL_SCRIPT)
 
        for TARGET in $(TARGETS); do \
                BUILD_TARGET=$$BUILD/$$TARGET;  \
-               echo "echo ; echo TAP version 13" >> $(ALL_SCRIPT);     \
-               echo "echo Running tests in $$TARGET" >> $(ALL_SCRIPT); \
-               echo "echo ========================================" >> $(ALL_SCRIPT); \
                echo "[ -w /dev/kmsg ] && echo \"kselftest: Running tests in $$TARGET\" >> /dev/kmsg" >> $(ALL_SCRIPT); \
                echo "cd $$TARGET" >> $(ALL_SCRIPT); \
+               echo -n "run_many" >> $(ALL_SCRIPT); \
                make -s --no-print-directory OUTPUT=$$BUILD_TARGET -C $$TARGET emit_tests >> $(ALL_SCRIPT); \
+               echo "" >> $(ALL_SCRIPT);           \
                echo "cd \$$ROOT" >> $(ALL_SCRIPT); \
        done;
 
index 41e8a689aa77744e91282bd14a98c9d16a20dc2a..a877803e4ba8fae9f30779fa18d308297e1d4e3b 100644 (file)
@@ -32,3 +32,5 @@ test_tcpnotify_user
 test_libbpf
 test_tcp_check_syncookie_user
 alu32
+libbpf.pc
+libbpf.so.*
index 8e6fcc8940f0e57643edfe7cc2ddb9c7e54b4f54..6f951d1ff0a44b3e02351f139cf64fdd8e648bfd 100644 (file)
        .result_unpriv = REJECT,
        .result = ACCEPT,
 },
+{
+       "jump test 6",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_MOV64_IMM(BPF_REG_1, 2),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 2),
+       BPF_MOV64_IMM(BPF_REG_0, 2),
+       BPF_EXIT_INSN(),
+       BPF_JMP_REG(BPF_JNE, BPF_REG_0, BPF_REG_1, 16),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+       BPF_JMP_IMM(BPF_JA, 0, 0, -20),
+       },
+       .result = ACCEPT,
+       .retval = 2,
+},
+{
+       "jump test 7",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 2),
+       BPF_MOV64_IMM(BPF_REG_0, 3),
+       BPF_EXIT_INSN(),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 2, 16),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_JMP_IMM(BPF_JA, 0, 0, -20),
+       },
+       .result = ACCEPT,
+       .retval = 3,
+},
+{
+       "jump test 8",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_MOV64_IMM(BPF_REG_1, 2),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 2),
+       BPF_MOV64_IMM(BPF_REG_0, 3),
+       BPF_EXIT_INSN(),
+       BPF_JMP_REG(BPF_JNE, BPF_REG_0, BPF_REG_1, 16),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_JMP_IMM(BPF_JA, 0, 0, -20),
+       },
+       .result = ACCEPT,
+       .retval = 3,
+},
+{
+       "jump/call test 9",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 2),
+       BPF_MOV64_IMM(BPF_REG_0, 3),
+       BPF_EXIT_INSN(),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 2, 16),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, -20),
+       BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+       .result = REJECT,
+       .errstr = "jump out of range from insn 1 to 4",
+},
+{
+       "jump/call test 10",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2),
+       BPF_MOV64_IMM(BPF_REG_0, 3),
+       BPF_EXIT_INSN(),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 2, 16),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, -20),
+       BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+       .result = REJECT,
+       .errstr = "last insn is not an exit or jmp",
+},
+{
+       "jump/call test 11",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4),
+       BPF_MOV64_IMM(BPF_REG_0, 3),
+       BPF_EXIT_INSN(),
+       BPF_MOV64_IMM(BPF_REG_0, 3),
+       BPF_EXIT_INSN(),
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 2, 26),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_MOV64_IMM(BPF_REG_0, 42),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, -31),
+       BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+       .result = ACCEPT,
+       .retval = 3,
+},
index 901b85ea6a590c1c0e042fd784ea60f75d676a6f..8f3655e590201458055af9380f271709f1502440 100644 (file)
@@ -21,6 +21,8 @@
 
 #include "../kselftest.h"
 
+#define COUNT_ISN_BPS  4
+#define COUNT_WPS      4
 
 /* Breakpoint access modes */
 enum {
@@ -220,7 +222,7 @@ static void trigger_tests(void)
                        if (!local && !global)
                                continue;
 
-                       for (i = 0; i < 4; i++) {
+                       for (i = 0; i < COUNT_ISN_BPS; i++) {
                                dummy_funcs[i]();
                                check_trapped();
                        }
@@ -292,7 +294,7 @@ static void launch_instruction_breakpoints(char *buf, int local, int global)
 {
        int i;
 
-       for (i = 0; i < 4; i++) {
+       for (i = 0; i < COUNT_ISN_BPS; i++) {
                set_breakpoint_addr(dummy_funcs[i], i);
                toggle_breakpoint(i, BP_X, 1, local, global, 1);
                ptrace(PTRACE_CONT, child_pid, NULL, 0);
@@ -314,7 +316,7 @@ static void launch_watchpoints(char *buf, int mode, int len,
        else
                mode_str = "read";
 
-       for (i = 0; i < 4; i++) {
+       for (i = 0; i < COUNT_WPS; i++) {
                set_breakpoint_addr(&dummy_var[i], i);
                toggle_breakpoint(i, mode, len, local, global, 1);
                ptrace(PTRACE_CONT, child_pid, NULL, 0);
@@ -330,8 +332,15 @@ static void launch_watchpoints(char *buf, int mode, int len,
 static void launch_tests(void)
 {
        char buf[1024];
+       unsigned int tests = 0;
        int len, local, global, i;
 
+       tests += 3 * COUNT_ISN_BPS;
+       tests += sizeof(long) / 2 * 3 * COUNT_WPS;
+       tests += sizeof(long) / 2 * 3 * COUNT_WPS;
+       tests += 2;
+       ksft_set_plan(tests);
+
        /* Instruction breakpoints */
        for (local = 0; local < 2; local++) {
                for (global = 0; global < 2; global++) {
index 2d95e5adde726fb388b26de8e0db87343110d036..ab59d814341a8a33ae66676c1233b0c837016892 100644 (file)
@@ -118,7 +118,7 @@ static bool set_watchpoint(pid_t pid, int size, int wp)
        return false;
 }
 
-static bool run_test(int wr_size, int wp_size, int wr, int wp)
+static bool arun_test(int wr_size, int wp_size, int wr, int wp)
 {
        int status;
        siginfo_t siginfo;
@@ -214,6 +214,7 @@ int main(int argc, char **argv)
        bool result;
 
        ksft_print_header();
+       ksft_set_plan(213);
 
        act.sa_handler = sigalrm;
        sigemptyset(&act.sa_mask);
index f82dcc1f8841e74b950257e2b96c3b0914987a12..cf868b5e00f79fec541e86c4c9320168449e8ca2 100644 (file)
@@ -173,6 +173,7 @@ int main(int argc, char **argv)
        int opt;
        bool do_suspend = true;
        bool succeeded = true;
+       unsigned int tests = 0;
        cpu_set_t available_cpus;
        int err;
        int cpu;
@@ -191,6 +192,13 @@ int main(int argc, char **argv)
                }
        }
 
+       for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
+               if (!CPU_ISSET(cpu, &available_cpus))
+                       continue;
+               tests++;
+       }
+       ksft_set_plan(tests);
+
        if (do_suspend)
                suspend();
 
index 3ab39a61b95bdcc0bb5dc7d70e7fd0bb563e26d8..df0ef02b403670925ae14e42fc396fdd5945aa3f 100644 (file)
@@ -430,8 +430,6 @@ int main(int argc, char **argv)
 {
        char *tmp1, *tmp2, *our_path;
 
-       ksft_print_header();
-
        /* Find our path */
        tmp1 = strdup(argv[0]);
        if (!tmp1)
@@ -445,6 +443,8 @@ int main(int argc, char **argv)
        mpid = getpid();
 
        if (fork_wait()) {
+               ksft_print_header();
+               ksft_set_plan(12);
                ksft_print_msg("[RUN]\t+++ Tests with uid == 0 +++\n");
                return do_tests(0, our_path);
        }
@@ -452,6 +452,8 @@ int main(int argc, char **argv)
        ksft_print_msg("==================================================\n");
 
        if (fork_wait()) {
+               ksft_print_header();
+               ksft_set_plan(9);
                ksft_print_msg("[RUN]\t+++ Tests with uid != 0 +++\n");
                return do_tests(1, our_path);
        }
diff --git a/tools/testing/selftests/drivers/.gitignore b/tools/testing/selftests/drivers/.gitignore
new file mode 100644 (file)
index 0000000..f6aebcc
--- /dev/null
@@ -0,0 +1 @@
+/dma-buf/udmabuf
index 64073e050c6a44a0120a81c426414c38165b536f..b02279da6fa12978474a794821cf60624e81e5e8 100644 (file)
@@ -6,4 +6,5 @@ execveat.moved
 execveat.path.ephemeral
 execveat.ephemeral
 execveat.denatured
-xxxxxxxx*
\ No newline at end of file
+/recursion-depth
+xxxxxxxx*
index 427c41ba51513617883cee81cbe943bb6c523f67..33339e31e36526b169470f56f7bf05b891891202 100644 (file)
@@ -1,11 +1,15 @@
 # SPDX-License-Identifier: GPL-2.0
 CFLAGS = -Wall
+CFLAGS += -Wno-nonnull
+CFLAGS += -D_GNU_SOURCE
 
 TEST_GEN_PROGS := execveat
 TEST_GEN_FILES := execveat.symlink execveat.denatured script subdir
 # Makefile is a run-time dependency, since it's accessed by the execveat test
 TEST_FILES := Makefile
 
+TEST_GEN_PROGS += recursion-depth
+
 EXTRA_CLEAN := $(OUTPUT)/subdir.moved $(OUTPUT)/execveat.moved $(OUTPUT)/xxxxx*
 
 include ../lib.mk
diff --git a/tools/testing/selftests/exec/recursion-depth.c b/tools/testing/selftests/exec/recursion-depth.c
new file mode 100644 (file)
index 0000000..2dbd5bc
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2019 Alexey Dobriyan <adobriyan@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/* Test that pointing #! script interpreter to self doesn't recurse. */
+#include <errno.h>
+#include <sched.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <unistd.h>
+
+int main(void)
+{
+       if (unshare(CLONE_NEWNS) == -1) {
+               if (errno == ENOSYS || errno == EPERM) {
+                       fprintf(stderr, "error: unshare, errno %d\n", errno);
+                       return 4;
+               }
+               fprintf(stderr, "error: unshare, errno %d\n", errno);
+               return 1;
+       }
+       if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) == -1) {
+               fprintf(stderr, "error: mount '/', errno %d\n", errno);
+               return 1;
+       }
+       /* Require "exec" filesystem. */
+       if (mount(NULL, "/tmp", "ramfs", 0, NULL) == -1) {
+               fprintf(stderr, "error: mount ramfs, errno %d\n", errno);
+               return 1;
+       }
+
+#define FILENAME "/tmp/1"
+
+       int fd = creat(FILENAME, 0700);
+       if (fd == -1) {
+               fprintf(stderr, "error: creat, errno %d\n", errno);
+               return 1;
+       }
+#define S "#!" FILENAME "\n"
+       if (write(fd, S, strlen(S)) != strlen(S)) {
+               fprintf(stderr, "error: write, errno %d\n", errno);
+               return 1;
+       }
+       close(fd);
+
+       int rv = execve(FILENAME, NULL, NULL);
+       if (rv == -1 && errno == ELOOP) {
+               return 0;
+       }
+       fprintf(stderr, "error: execve, rv %d, errno %d\n", rv, errno);
+       return 1;
+}
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/tracing-error-log.tc b/tools/testing/selftests/ftrace/test.d/ftrace/tracing-error-log.tc
new file mode 100644 (file)
index 0000000..021c03f
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: ftrace - test tracing error log support
+
+fail() { #msg
+    echo $1
+    exit_fail
+}
+
+# event tracing is currently the only ftrace tracer that uses the
+# tracing error_log, hence this check
+if [ ! -f set_event ]; then
+    echo "event tracing is not supported"
+    exit_unsupported
+fi
+
+ftrace_errlog_check 'event filter parse error' '((sig >= 10 && sig < 15) || dsig ^== 17) && comm != bash' 'events/signal/signal_generate/filter'
+
+exit 0
index 7b96e80e6b8ab31a456539e7151bcbe44471eae9..779ec11f61bda8f88502ea04430d4fd89e1d575b 100644 (file)
@@ -109,3 +109,15 @@ LOCALHOST=127.0.0.1
 yield() {
     ping $LOCALHOST -c 1 || sleep .001 || usleep 1 || sleep 1
 }
+
+ftrace_errlog_check() { # err-prefix command-with-error-pos-by-^ command-file
+    pos=$(echo -n "${2%^*}" | wc -c) # error position
+    command=$(echo "$2" | tr -d ^)
+    echo "Test command: $command"
+    echo > error_log
+    (! echo "$command" > "$3" ) 2> /dev/null
+    grep "$1: error:" -A 3 error_log
+    N=$(tail -n 1 error_log | wc -c)
+    # "  Command: " and "^\n" => 13
+    test $(expr 13 + $pos) -eq $N
+}
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
new file mode 100644 (file)
index 0000000..29faaec
--- /dev/null
@@ -0,0 +1,85 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Kprobe event parser error log check
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+[ -f error_log ] || exit_unsupported
+
+check_error() { # command-with-error-pos-by-^
+    ftrace_errlog_check 'trace_kprobe' "$1" 'kprobe_events'
+}
+
+if grep -q 'r\[maxactive\]' README; then
+check_error 'p^100 vfs_read'           # MAXACT_NO_KPROBE
+check_error 'r^1a111 vfs_read'         # BAD_MAXACT
+check_error 'r^100000 vfs_read'                # MAXACT_TOO_BIG
+fi
+
+check_error 'p ^non_exist_func'                # BAD_PROBE_ADDR (enoent)
+check_error 'p ^hoge-fuga'             # BAD_PROBE_ADDR (bad syntax)
+check_error 'p ^hoge+1000-1000'                # BAD_PROBE_ADDR (bad syntax)
+check_error 'r ^vfs_read+10'           # BAD_RETPROBE
+check_error 'p:^/bar vfs_read'         # NO_GROUP_NAME
+check_error 'p:^12345678901234567890123456789012345678901234567890123456789012345/bar vfs_read'        # GROUP_TOO_LONG
+
+check_error 'p:^foo.1/bar vfs_read'    # BAD_GROUP_NAME
+check_error 'p:foo/^ vfs_read'         # NO_EVENT_NAME
+check_error 'p:foo/^12345678901234567890123456789012345678901234567890123456789012345 vfs_read'        # EVENT_TOO_LONG
+check_error 'p:foo/^bar.1 vfs_read'    # BAD_EVENT_NAME
+
+check_error 'p vfs_read ^$retval'      # RETVAL_ON_PROBE
+check_error 'p vfs_read ^$stack10000'  # BAD_STACK_NUM
+
+if grep -q '$arg<N>' README; then
+check_error 'p vfs_read ^$arg10000'    # BAD_ARG_NUM
+fi
+
+check_error 'p vfs_read ^$none_var'    # BAD_VAR
+
+check_error 'p vfs_read ^%none_reg'    # BAD_REG_NAME
+check_error 'p vfs_read ^@12345678abcde'       # BAD_MEM_ADDR
+check_error 'p vfs_read ^@+10'         # FILE_ON_KPROBE
+
+check_error 'p vfs_read ^+0@0)'                # DEREF_NEED_BRACE
+check_error 'p vfs_read ^+0ab1(@0)'    # BAD_DEREF_OFFS
+check_error 'p vfs_read +0(+0(@0^)'    # DEREF_OPEN_BRACE
+
+if grep -A1 "fetcharg:" README | grep -q '\$comm' ; then
+check_error 'p vfs_read +0(^$comm)'    # COMM_CANT_DEREF
+fi
+
+check_error 'p vfs_read ^&1'           # BAD_FETCH_ARG
+
+
+# We've introduced this limitation with array support
+if grep -q ' <type>\\\[<array-size>\\\]' README; then
+check_error 'p vfs_read +0(^+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(@0))))))))))))))'   # TOO_MANY_OPS?
+check_error 'p vfs_read +0(@11):u8[10^'                # ARRAY_NO_CLOSE
+check_error 'p vfs_read +0(@11):u8[10]^a'      # BAD_ARRAY_SUFFIX
+check_error 'p vfs_read +0(@11):u8[^10a]'      # BAD_ARRAY_NUM
+check_error 'p vfs_read +0(@11):u8[^256]'      # ARRAY_TOO_BIG
+fi
+
+check_error 'p vfs_read @11:^unknown_type'     # BAD_TYPE
+check_error 'p vfs_read $stack0:^string'       # BAD_STRING
+check_error 'p vfs_read @11:^b10@a/16'         # BAD_BITFIELD
+
+check_error 'p vfs_read ^arg123456789012345678901234567890=@11'        # ARG_NAME_TOO_LOG
+check_error 'p vfs_read ^=@11'                 # NO_ARG_NAME
+check_error 'p vfs_read ^var.1=@11'            # BAD_ARG_NAME
+check_error 'p vfs_read var1=@11 ^var1=@12'    # USED_ARG_NAME
+check_error 'p vfs_read ^+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(@1234))))))'    # ARG_TOO_LONG
+check_error 'p vfs_read arg1=^'                        # NO_ARG_BODY
+
+# instruction boundary check is valid on x86 (at this moment)
+case $(uname -m) in
+  x86_64|i[3456]86)
+    echo 'p vfs_read' > kprobe_events
+    if grep -q FTRACE ../kprobes/list ; then
+       check_error 'p ^vfs_read+3'             # BAD_INSN_BNDRY (only if function-tracer is enabled)
+    fi
+    ;;
+esac
+
+exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc b/tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc
new file mode 100644 (file)
index 0000000..14229d5
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Uprobe event parser error log check
+
+[ -f uprobe_events ] || exit_unsupported # this is configurable
+
+[ -f error_log ] || exit_unsupported
+
+check_error() { # command-with-error-pos-by-^
+    ftrace_errlog_check 'trace_uprobe' "$1" 'uprobe_events'
+}
+
+check_error 'p ^/non_exist_file:100'   # FILE_NOT_FOUND
+check_error 'p ^/sys:100'              # NO_REGULAR_FILE
+check_error 'p /bin/sh:^10a'           # BAD_UPROBE_OFFS
+check_error 'p /bin/sh:10(^1a)'                # BAD_REFCNT
+check_error 'p /bin/sh:10(10^'         # REFCNT_OPEN_BRACE
+check_error 'p /bin/sh:10(10)^a'       # BAD_REFCNT_SUFFIX
+
+check_error 'p /bin/sh:10 ^@+ab'       # BAD_FILE_OFFS
+check_error 'p /bin/sh:10 ^@symbol'    # SYM_ON_UPROBE
+
+exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-extended-error-support.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-extended-error-support.tc
deleted file mode 100644 (file)
index 9912616..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# description: event trigger - test extended error support
-
-
-fail() { #msg
-    echo $1
-    exit_fail
-}
-
-if [ ! -f set_event ]; then
-    echo "event tracing is not supported"
-    exit_unsupported
-fi
-
-if [ ! -f synthetic_events ]; then
-    echo "synthetic event is not supported"
-    exit_unsupported
-fi
-
-echo "Test extended error support"
-echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' > events/sched/sched_wakeup/trigger
-! echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' >> events/sched/sched_wakeup/trigger 2> /dev/null
-if ! grep -q "ERROR:" events/sched/sched_wakeup/hist; then
-    fail "Failed to generate extended error in histogram"
-fi
-
-exit 0
index 54cd5c414e82c487f3c57094b84f5ab5cf960604..8d20957f758695fde13d78e96536e127ad32d8f6 100644 (file)
@@ -395,6 +395,7 @@ int main(int argc, char *argv[])
        }
 
        ksft_print_header();
+       ksft_set_plan(1);
        ksft_print_msg("%s: Test requeue functionality\n", basename(argv[0]));
        ksft_print_msg(
                "\tArguments: broadcast=%d locked=%d owner=%d timeout=%ldns\n",
index 08187a16507ff8afc3dd02c958e22327024fbcf9..742624c59ba7d96a2e30571d20f942d674ef4c24 100644 (file)
@@ -79,6 +79,7 @@ int main(int argc, char *argv[])
        }
 
        ksft_print_header();
+       ksft_set_plan(1);
        ksft_print_msg("%s: Detect mismatched requeue_pi operations\n",
               basename(argv[0]));
 
index f0542a344d95fa9656b325623473b851149f9cd6..a0f5934707ffcb0f9f622e43bcfb930b13461820 100644 (file)
@@ -144,6 +144,7 @@ int main(int argc, char *argv[])
        }
 
        ksft_print_header();
+       ksft_set_plan(1);
        ksft_print_msg("%s: Test signal handling during requeue_pi\n",
               basename(argv[0]));
        ksft_print_msg("\tArguments: <none>\n");
index 6216de828093a079a3afeafe06ff21d9bd6e15ee..a458d42ff86ec5f5b98bb75762b67edd90e3e141 100644 (file)
@@ -98,6 +98,7 @@ int main(int argc, char **argv)
        }
 
        ksft_print_header();
+       ksft_set_plan(1);
        ksft_print_msg(
                "%s: Test the futex value of private file mappings in FUTEX_WAIT\n",
                basename(argv[0]));
index bab3dfe1787f9bd724bd75f02625efd0d08b7d50..04b95478059cdec40890e35c3fe053117e86f3b9 100644 (file)
@@ -69,6 +69,7 @@ int main(int argc, char *argv[])
        }
 
        ksft_print_header();
+       ksft_set_plan(1);
        ksft_print_msg("%s: Block on a futex and wait for timeout\n",
               basename(argv[0]));
        ksft_print_msg("\tArguments: timeout=%ldns\n", timeout_ns);
index 26975322545b4173083d082311651210501989c2..3a1d12a14921d77f977b154dbe309beaddb91f08 100644 (file)
@@ -100,6 +100,7 @@ int main(int argc, char **argv)
        }
 
        ksft_print_header();
+       ksft_set_plan(1);
        ksft_print_msg("%s: Test the uninitialized futex value in FUTEX_WAIT\n",
               basename(argv[0]));
 
index da15a63269b4c7f3059bcac284ca2fdb89602847..a34a6bbc30cecbce095299e113bda441c84cb849 100644 (file)
@@ -65,6 +65,7 @@ int main(int argc, char *argv[])
        }
 
        ksft_print_header();
+       ksft_set_plan(1);
        ksft_print_msg("%s: Test the unexpected futex value in FUTEX_WAIT\n",
               basename(argv[0]));
 
index 47e1d995c1822903499e6597bc863f3b41402e6a..ec15c4f6af552d57a5584e18abb7cb9bb17cc90f 100644 (file)
@@ -33,6 +33,7 @@ struct ksft_count {
 };
 
 static struct ksft_count ksft_cnt;
+static unsigned int ksft_plan;
 
 static inline int ksft_test_num(void)
 {
@@ -61,13 +62,21 @@ static inline void ksft_print_header(void)
                printf("TAP version 13\n");
 }
 
+static inline void ksft_set_plan(unsigned int plan)
+{
+       ksft_plan = plan;
+       printf("1..%d\n", ksft_plan);
+}
+
 static inline void ksft_print_cnts(void)
 {
-       printf("Pass %d Fail %d Xfail %d Xpass %d Skip %d Error %d\n",
+       if (ksft_plan != ksft_test_num())
+               printf("# Planned tests != run tests (%u != %u)\n",
+                       ksft_plan, ksft_test_num());
+       printf("# Pass %d Fail %d Xfail %d Xpass %d Skip %d Error %d\n",
                ksft_cnt.ksft_pass, ksft_cnt.ksft_fail,
                ksft_cnt.ksft_xfail, ksft_cnt.ksft_xpass,
                ksft_cnt.ksft_xskip, ksft_cnt.ksft_error);
-       printf("1..%d\n", ksft_test_num());
 }
 
 static inline void ksft_print_msg(const char *msg, ...)
@@ -111,7 +120,7 @@ static inline void ksft_test_result_skip(const char *msg, ...)
        ksft_cnt.ksft_xskip++;
 
        va_start(args, msg);
-       printf("ok %d # skip ", ksft_test_num());
+       printf("not ok %d # SKIP ", ksft_test_num());
        vprintf(msg, args);
        va_end(args);
 }
@@ -172,7 +181,7 @@ static inline int ksft_exit_skip(const char *msg, ...)
                va_list args;
 
                va_start(args, msg);
-               printf("1..%d # Skipped: ", ksft_test_num());
+               printf("not ok %d # SKIP ", 1 + ksft_test_num());
                vprintf(msg, args);
                va_end(args);
        } else {
diff --git a/tools/testing/selftests/kselftest/prefix.pl b/tools/testing/selftests/kselftest/prefix.pl
new file mode 100755 (executable)
index 0000000..ec7e481
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+# SPDX-License-Identifier: GPL-2.0
+# Prefix all lines with "# ", unbuffered. Command being piped in may need
+# to have unbuffering forced with "stdbuf -i0 -o0 -e0 $cmd".
+use strict;
+
+binmode STDIN;
+binmode STDOUT;
+
+STDOUT->autoflush(1);
+
+my $needed = 1;
+while (1) {
+       my $char;
+       my $bytes = sysread(STDIN, $char, 1);
+       exit 0 if ($bytes == 0);
+       if ($needed) {
+               print "# ";
+               $needed = 0;
+       }
+       print $char;
+       $needed = 1 if ($char eq "\n");
+}
diff --git a/tools/testing/selftests/kselftest/runner.sh b/tools/testing/selftests/kselftest/runner.sh
new file mode 100644 (file)
index 0000000..eff3ee3
--- /dev/null
@@ -0,0 +1,86 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# Runs a set of tests in a given subdirectory.
+export skip_rc=4
+export logfile=/dev/stdout
+export per_test_logging=
+
+# There isn't a shell-agnostic way to find the path of a sourced file,
+# so we must rely on BASE_DIR being set to find other tools.
+if [ -z "$BASE_DIR" ]; then
+       echo "Error: BASE_DIR must be set before sourcing." >&2
+       exit 1
+fi
+
+# If Perl is unavailable, we must fall back to line-at-a-time prefixing
+# with sed instead of unbuffered output.
+tap_prefix()
+{
+       if [ ! -x /usr/bin/perl ]; then
+               sed -e 's/^/# /'
+       else
+               "$BASE_DIR"/kselftest/prefix.pl
+       fi
+}
+
+# If stdbuf is unavailable, we must fall back to line-at-a-time piping.
+tap_unbuffer()
+{
+       if ! which stdbuf >/dev/null ; then
+               "$@"
+       else
+               stdbuf -i0 -o0 -e0 "$@"
+       fi
+}
+
+run_one()
+{
+       DIR="$1"
+       TEST="$2"
+       NUM="$3"
+
+       BASENAME_TEST=$(basename $TEST)
+
+       TEST_HDR_MSG="selftests: $DIR: $BASENAME_TEST"
+       echo "# $TEST_HDR_MSG"
+       if [ ! -x "$TEST" ]; then
+               echo -n "# Warning: file $TEST is "
+               if [ ! -e "$TEST" ]; then
+                       echo "missing!"
+               else
+                       echo "not executable, correct this."
+               fi
+               echo "not ok $test_num $TEST_HDR_MSG"
+       else
+               cd `dirname $TEST` > /dev/null
+               (((((tap_unbuffer ./$BASENAME_TEST 2>&1; echo $? >&3) |
+                       tap_prefix >&4) 3>&1) |
+                       (read xs; exit $xs)) 4>>"$logfile" &&
+               echo "ok $test_num $TEST_HDR_MSG") ||
+               (if [ $? -eq $skip_rc ]; then   \
+                       echo "not ok $test_num $TEST_HDR_MSG # SKIP"
+               else
+                       echo "not ok $test_num $TEST_HDR_MSG"
+               fi)
+               cd - >/dev/null
+       fi
+}
+
+run_many()
+{
+       echo "TAP version 13"
+       DIR=$(basename "$PWD")
+       test_num=0
+       total=$(echo "$@" | wc -w)
+       echo "1..$total"
+       for TEST in "$@"; do
+               BASENAME_TEST=$(basename $TEST)
+               test_num=$(( test_num + 1 ))
+               if [ -n "$per_test_logging" ]; then
+                       logfile="/tmp/$BASENAME_TEST"
+                       cat /dev/null > "$logfile"
+               fi
+               run_one "$DIR" "$TEST" "$test_num"
+       done
+}
index 2689d1ea6d7aab48474e027b8b6a8fb28822e431..df1bf9230a7406c56368dc446898780444a7c5b2 100644 (file)
@@ -1,9 +1,14 @@
 /x86_64/cr4_cpuid_sync_test
 /x86_64/evmcs_test
+/x86_64/hyperv_cpuid
+/x86_64/kvm_create_max_vcpus
 /x86_64/platform_info_test
 /x86_64/set_sregs_test
+/x86_64/smm_test
+/x86_64/state_test
 /x86_64/sync_regs_test
 /x86_64/vmx_close_while_nested_test
+/x86_64/vmx_set_nested_state_test
 /x86_64/vmx_tsc_adjust_test
-/x86_64/state_test
+/clear_dirty_log_test
 /dirty_log_test
index f8588cca2bef4bfe4d3cdf2afdb6586f21e67894..79c524395ebec4989545a0eebc82b26d28325ac3 100644 (file)
@@ -20,6 +20,8 @@ TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test
 TEST_GEN_PROGS_x86_64 += x86_64/hyperv_cpuid
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_close_while_nested_test
 TEST_GEN_PROGS_x86_64 += x86_64/smm_test
+TEST_GEN_PROGS_x86_64 += x86_64/kvm_create_max_vcpus
+TEST_GEN_PROGS_x86_64 += x86_64/vmx_set_nested_state_test
 TEST_GEN_PROGS_x86_64 += dirty_log_test
 TEST_GEN_PROGS_x86_64 += clear_dirty_log_test
 
index 93f99c6b7d79ee11964457b5a845cef4380bab27..f50a15c38f9b068205850c94f5805a1a2c4d7b74 100644 (file)
@@ -314,7 +314,7 @@ static void run_test(enum vm_guest_mode mode, unsigned long iterations,
 #ifdef USE_CLEAR_DIRTY_LOG
        struct kvm_enable_cap cap = {};
 
-       cap.cap = KVM_CAP_MANUAL_DIRTY_LOG_PROTECT;
+       cap.cap = KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2;
        cap.args[0] = 1;
        vm_enable_cap(vm, &cap);
 #endif
@@ -430,7 +430,7 @@ int main(int argc, char *argv[])
        int opt, i;
 
 #ifdef USE_CLEAR_DIRTY_LOG
-       if (!kvm_check_cap(KVM_CAP_MANUAL_DIRTY_LOG_PROTECT)) {
+       if (!kvm_check_cap(KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2)) {
                fprintf(stderr, "KVM_CLEAR_DIRTY_LOG not available, skipping tests\n");
                exit(KSFT_SKIP);
        }
index 07b71ad9734af57f101f0f96fdc57b741b41b0e7..8c6b9619797dc18efdd2d226c205877d929416e2 100644 (file)
@@ -118,6 +118,10 @@ void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid,
                     struct kvm_vcpu_events *events);
 void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid,
                     struct kvm_vcpu_events *events);
+void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid,
+                          struct kvm_nested_state *state);
+int vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid,
+                         struct kvm_nested_state *state, bool ignore_error);
 
 const char *exit_reason_str(unsigned int exit_reason);
 
index 4ca96b228e46ba248476803583cb94d14410ff16..e9113857f44e9498bcfdeeead148f1ad11862dd4 100644 (file)
@@ -1250,6 +1250,38 @@ void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid,
                ret, errno);
 }
 
+void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid,
+                          struct kvm_nested_state *state)
+{
+       struct vcpu *vcpu = vcpu_find(vm, vcpuid);
+       int ret;
+
+       TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid);
+
+       ret = ioctl(vcpu->fd, KVM_GET_NESTED_STATE, state);
+       TEST_ASSERT(ret == 0,
+               "KVM_SET_NESTED_STATE failed, ret: %i errno: %i",
+               ret, errno);
+}
+
+int vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid,
+                         struct kvm_nested_state *state, bool ignore_error)
+{
+       struct vcpu *vcpu = vcpu_find(vm, vcpuid);
+       int ret;
+
+       TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid);
+
+       ret = ioctl(vcpu->fd, KVM_SET_NESTED_STATE, state);
+       if (!ignore_error) {
+               TEST_ASSERT(ret == 0,
+                       "KVM_SET_NESTED_STATE failed, ret: %i errno: %i",
+                       ret, errno);
+       }
+
+       return ret;
+}
+
 /*
  * VM VCPU System Regs Get
  *
diff --git a/tools/testing/selftests/kvm/x86_64/kvm_create_max_vcpus.c b/tools/testing/selftests/kvm/x86_64/kvm_create_max_vcpus.c
new file mode 100644 (file)
index 0000000..50e9299
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * kvm_create_max_vcpus
+ *
+ * Copyright (C) 2019, Google LLC.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * Test for KVM_CAP_MAX_VCPUS and KVM_CAP_MAX_VCPU_ID.
+ */
+
+#define _GNU_SOURCE /* for program_invocation_short_name */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test_util.h"
+
+#include "kvm_util.h"
+#include "asm/kvm.h"
+#include "linux/kvm.h"
+
+void test_vcpu_creation(int first_vcpu_id, int num_vcpus)
+{
+       struct kvm_vm *vm;
+       int i;
+
+       printf("Testing creating %d vCPUs, with IDs %d...%d.\n",
+              num_vcpus, first_vcpu_id, first_vcpu_id + num_vcpus - 1);
+
+       vm = vm_create(VM_MODE_P52V48_4K, DEFAULT_GUEST_PHY_PAGES, O_RDWR);
+
+       for (i = 0; i < num_vcpus; i++) {
+               int vcpu_id = first_vcpu_id + i;
+
+               /* This asserts that the vCPU was created. */
+               vm_vcpu_add(vm, vcpu_id, 0, 0);
+       }
+
+       kvm_vm_free(vm);
+}
+
+int main(int argc, char *argv[])
+{
+       int kvm_max_vcpu_id = kvm_check_cap(KVM_CAP_MAX_VCPU_ID);
+       int kvm_max_vcpus = kvm_check_cap(KVM_CAP_MAX_VCPUS);
+
+       printf("KVM_CAP_MAX_VCPU_ID: %d\n", kvm_max_vcpu_id);
+       printf("KVM_CAP_MAX_VCPUS: %d\n", kvm_max_vcpus);
+
+       /*
+        * Upstream KVM prior to 4.8 does not support KVM_CAP_MAX_VCPU_ID.
+        * Userspace is supposed to use KVM_CAP_MAX_VCPUS as the maximum ID
+        * in this case.
+        */
+       if (!kvm_max_vcpu_id)
+               kvm_max_vcpu_id = kvm_max_vcpus;
+
+       TEST_ASSERT(kvm_max_vcpu_id >= kvm_max_vcpus,
+                   "KVM_MAX_VCPU_ID (%d) must be at least as large as KVM_MAX_VCPUS (%d).",
+                   kvm_max_vcpu_id, kvm_max_vcpus);
+
+       test_vcpu_creation(0, kvm_max_vcpus);
+
+       if (kvm_max_vcpu_id > kvm_max_vcpus)
+               test_vcpu_creation(
+                       kvm_max_vcpu_id - kvm_max_vcpus, kvm_max_vcpus);
+
+       return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c
new file mode 100644 (file)
index 0000000..61a2163
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * vmx_set_nested_state_test
+ *
+ * Copyright (C) 2019, Google LLC.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * This test verifies the integrity of calling the ioctl KVM_SET_NESTED_STATE.
+ */
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+#include "vmx.h"
+
+#include <errno.h>
+#include <linux/kvm.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+/*
+ * Mirror of VMCS12_REVISION in arch/x86/kvm/vmx/vmcs12.h. If that value
+ * changes this should be updated.
+ */
+#define VMCS12_REVISION 0x11e57ed0
+#define VCPU_ID 5
+
+void test_nested_state(struct kvm_vm *vm, struct kvm_nested_state *state)
+{
+       volatile struct kvm_run *run;
+
+       vcpu_nested_state_set(vm, VCPU_ID, state, false);
+       run = vcpu_state(vm, VCPU_ID);
+       vcpu_run(vm, VCPU_ID);
+       TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN,
+               "Got exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s),\n",
+               run->exit_reason,
+               exit_reason_str(run->exit_reason));
+}
+
+void test_nested_state_expect_errno(struct kvm_vm *vm,
+                                   struct kvm_nested_state *state,
+                                   int expected_errno)
+{
+       volatile struct kvm_run *run;
+       int rv;
+
+       rv = vcpu_nested_state_set(vm, VCPU_ID, state, true);
+       TEST_ASSERT(rv == -1 && errno == expected_errno,
+               "Expected %s (%d) from vcpu_nested_state_set but got rv: %i errno: %s (%d)",
+               strerror(expected_errno), expected_errno, rv, strerror(errno),
+               errno);
+       run = vcpu_state(vm, VCPU_ID);
+       vcpu_run(vm, VCPU_ID);
+       TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN,
+               "Got exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s),\n",
+               run->exit_reason,
+               exit_reason_str(run->exit_reason));
+}
+
+void test_nested_state_expect_einval(struct kvm_vm *vm,
+                                    struct kvm_nested_state *state)
+{
+       test_nested_state_expect_errno(vm, state, EINVAL);
+}
+
+void test_nested_state_expect_efault(struct kvm_vm *vm,
+                                    struct kvm_nested_state *state)
+{
+       test_nested_state_expect_errno(vm, state, EFAULT);
+}
+
+void set_revision_id_for_vmcs12(struct kvm_nested_state *state,
+                               u32 vmcs12_revision)
+{
+       /* Set revision_id in vmcs12 to vmcs12_revision. */
+       *(u32 *)(state->data) = vmcs12_revision;
+}
+
+void set_default_state(struct kvm_nested_state *state)
+{
+       memset(state, 0, sizeof(*state));
+       state->flags = KVM_STATE_NESTED_RUN_PENDING |
+                      KVM_STATE_NESTED_GUEST_MODE;
+       state->format = 0;
+       state->size = sizeof(*state);
+}
+
+void set_default_vmx_state(struct kvm_nested_state *state, int size)
+{
+       memset(state, 0, size);
+       state->flags = KVM_STATE_NESTED_GUEST_MODE  |
+                       KVM_STATE_NESTED_RUN_PENDING |
+                       KVM_STATE_NESTED_EVMCS;
+       state->format = 0;
+       state->size = size;
+       state->vmx.vmxon_pa = 0x1000;
+       state->vmx.vmcs_pa = 0x2000;
+       state->vmx.smm.flags = 0;
+       set_revision_id_for_vmcs12(state, VMCS12_REVISION);
+}
+
+void test_vmx_nested_state(struct kvm_vm *vm)
+{
+       /* Add a page for VMCS12. */
+       const int state_sz = sizeof(struct kvm_nested_state) + getpagesize();
+       struct kvm_nested_state *state =
+               (struct kvm_nested_state *)malloc(state_sz);
+
+       /* The format must be set to 0. 0 for VMX, 1 for SVM. */
+       set_default_vmx_state(state, state_sz);
+       state->format = 1;
+       test_nested_state_expect_einval(vm, state);
+
+       /*
+        * We cannot virtualize anything if the guest does not have VMX
+        * enabled.
+        */
+       set_default_vmx_state(state, state_sz);
+       test_nested_state_expect_einval(vm, state);
+
+       /*
+        * We cannot virtualize anything if the guest does not have VMX
+        * enabled.  We expect KVM_SET_NESTED_STATE to return 0 if vmxon_pa
+        * is set to -1ull.
+        */
+       set_default_vmx_state(state, state_sz);
+       state->vmx.vmxon_pa = -1ull;
+       test_nested_state(vm, state);
+
+       /* Enable VMX in the guest CPUID. */
+       vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
+
+       /* It is invalid to have vmxon_pa == -1ull and SMM flags non-zero. */
+       set_default_vmx_state(state, state_sz);
+       state->vmx.vmxon_pa = -1ull;
+       state->vmx.smm.flags = 1;
+       test_nested_state_expect_einval(vm, state);
+
+       /* It is invalid to have vmxon_pa == -1ull and vmcs_pa != -1ull. */
+       set_default_vmx_state(state, state_sz);
+       state->vmx.vmxon_pa = -1ull;
+       state->vmx.vmcs_pa = 0;
+       test_nested_state_expect_einval(vm, state);
+
+       /*
+        * Setting vmxon_pa == -1ull and vmcs_pa == -1ull exits early without
+        * setting the nested state.
+        */
+       set_default_vmx_state(state, state_sz);
+       state->vmx.vmxon_pa = -1ull;
+       state->vmx.vmcs_pa = -1ull;
+       test_nested_state(vm, state);
+
+       /* It is invalid to have vmxon_pa set to a non-page aligned address. */
+       set_default_vmx_state(state, state_sz);
+       state->vmx.vmxon_pa = 1;
+       test_nested_state_expect_einval(vm, state);
+
+       /*
+        * It is invalid to have KVM_STATE_NESTED_SMM_GUEST_MODE and
+        * KVM_STATE_NESTED_GUEST_MODE set together.
+        */
+       set_default_vmx_state(state, state_sz);
+       state->flags = KVM_STATE_NESTED_GUEST_MODE  |
+                     KVM_STATE_NESTED_RUN_PENDING;
+       state->vmx.smm.flags = KVM_STATE_NESTED_SMM_GUEST_MODE;
+       test_nested_state_expect_einval(vm, state);
+
+       /*
+        * It is invalid to have any of the SMM flags set besides:
+        *      KVM_STATE_NESTED_SMM_GUEST_MODE
+        *      KVM_STATE_NESTED_SMM_VMXON
+        */
+       set_default_vmx_state(state, state_sz);
+       state->vmx.smm.flags = ~(KVM_STATE_NESTED_SMM_GUEST_MODE |
+                               KVM_STATE_NESTED_SMM_VMXON);
+       test_nested_state_expect_einval(vm, state);
+
+       /* Outside SMM, SMM flags must be zero. */
+       set_default_vmx_state(state, state_sz);
+       state->flags = 0;
+       state->vmx.smm.flags = KVM_STATE_NESTED_SMM_GUEST_MODE;
+       test_nested_state_expect_einval(vm, state);
+
+       /* Size must be large enough to fit kvm_nested_state and vmcs12. */
+       set_default_vmx_state(state, state_sz);
+       state->size = sizeof(*state);
+       test_nested_state(vm, state);
+
+       /* vmxon_pa cannot be the same address as vmcs_pa. */
+       set_default_vmx_state(state, state_sz);
+       state->vmx.vmxon_pa = 0;
+       state->vmx.vmcs_pa = 0;
+       test_nested_state_expect_einval(vm, state);
+
+       /* The revision id for vmcs12 must be VMCS12_REVISION. */
+       set_default_vmx_state(state, state_sz);
+       set_revision_id_for_vmcs12(state, 0);
+       test_nested_state_expect_einval(vm, state);
+
+       /*
+        * Test that if we leave nesting the state reflects that when we get
+        * it again.
+        */
+       set_default_vmx_state(state, state_sz);
+       state->vmx.vmxon_pa = -1ull;
+       state->vmx.vmcs_pa = -1ull;
+       state->flags = 0;
+       test_nested_state(vm, state);
+       vcpu_nested_state_get(vm, VCPU_ID, state);
+       TEST_ASSERT(state->size >= sizeof(*state) && state->size <= state_sz,
+                   "Size must be between %d and %d.  The size returned was %d.",
+                   sizeof(*state), state_sz, state->size);
+       TEST_ASSERT(state->vmx.vmxon_pa == -1ull, "vmxon_pa must be -1ull.");
+       TEST_ASSERT(state->vmx.vmcs_pa == -1ull, "vmcs_pa must be -1ull.");
+
+       free(state);
+}
+
+int main(int argc, char *argv[])
+{
+       struct kvm_vm *vm;
+       struct kvm_nested_state state;
+       struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1);
+
+       if (!kvm_check_cap(KVM_CAP_NESTED_STATE)) {
+               printf("KVM_CAP_NESTED_STATE not available, skipping test\n");
+               exit(KSFT_SKIP);
+       }
+
+       /*
+        * AMD currently does not implement set_nested_state, so for now we
+        * just early out.
+        */
+       if (!(entry->ecx & CPUID_VMX)) {
+               fprintf(stderr, "nested VMX not enabled, skipping test\n");
+               exit(KSFT_SKIP);
+       }
+
+       vm = vm_create_default(VCPU_ID, 0, 0);
+
+       /* Passing a NULL kvm_nested_state causes a EFAULT. */
+       test_nested_state_expect_efault(vm, NULL);
+
+       /* 'size' cannot be smaller than sizeof(kvm_nested_state). */
+       set_default_state(&state);
+       state.size = 0;
+       test_nested_state_expect_einval(vm, &state);
+
+       /*
+        * Setting the flags 0xf fails the flags check.  The only flags that
+        * can be used are:
+        *     KVM_STATE_NESTED_GUEST_MODE
+        *     KVM_STATE_NESTED_RUN_PENDING
+        *     KVM_STATE_NESTED_EVMCS
+        */
+       set_default_state(&state);
+       state.flags = 0xf;
+       test_nested_state_expect_einval(vm, &state);
+
+       /*
+        * If KVM_STATE_NESTED_RUN_PENDING is set then
+        * KVM_STATE_NESTED_GUEST_MODE has to be set as well.
+        */
+       set_default_state(&state);
+       state.flags = KVM_STATE_NESTED_RUN_PENDING;
+       test_nested_state_expect_einval(vm, &state);
+
+       /*
+        * TODO: When SVM support is added for KVM_SET_NESTED_STATE
+        *       add tests here to support it like VMX.
+        */
+       if (entry->ecx & CPUID_VMX)
+               test_vmx_nested_state(vm);
+
+       kvm_vm_free(vm);
+       return 0;
+}
index 5979fdc4f36cf3729373509a2bcce8a8576aa362..07733719578358bf6c983eabe192dd38ae59cf58 100644 (file)
@@ -3,17 +3,12 @@
 CC := $(CROSS_COMPILE)gcc
 
 ifeq (0,$(MAKELEVEL))
-    ifneq ($(O),)
-       OUTPUT := $(O)
-    else
-       ifneq ($(KBUILD_OUTPUT),)
-               OUTPUT := $(KBUILD_OUTPUT)
-       else
-               OUTPUT := $(shell pwd)
-               DEFAULT_INSTALL_HDR_PATH := 1
-       endif
+    ifeq ($(OUTPUT),)
+       OUTPUT := $(shell pwd)
+       DEFAULT_INSTALL_HDR_PATH := 1
     endif
 endif
+selfdir = $(realpath $(dir $(filter %/lib.mk,$(MAKEFILE_LIST))))
 
 # The following are built by lib.mk common compile rules.
 # TEST_CUSTOM_PROGS should be used by tests that require
@@ -65,44 +60,13 @@ all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES)
 endif
 
 .ONESHELL:
-define RUN_TEST_PRINT_RESULT
-       TEST_HDR_MSG="selftests: "`basename $$PWD`:" $$BASENAME_TEST";  \
-       echo $$TEST_HDR_MSG;                                    \
-       echo "========================================";        \
-       if [ ! -x $$TEST ]; then        \
-               echo "$$TEST_HDR_MSG: Warning: file $$BASENAME_TEST is not executable, correct this.";\
-               echo "not ok 1..$$test_num $$TEST_HDR_MSG [FAIL]"; \
-       else                                    \
-               cd `dirname $$TEST` > /dev/null; \
-               if [ "X$(summary)" != "X" ]; then       \
-                       (./$$BASENAME_TEST > /tmp/$$BASENAME_TEST 2>&1 && \
-                       echo "ok 1..$$test_num $$TEST_HDR_MSG [PASS]") || \
-                       (if [ $$? -eq $$skip ]; then    \
-                               echo "not ok 1..$$test_num $$TEST_HDR_MSG [SKIP]";                              \
-                       else echo "not ok 1..$$test_num $$TEST_HDR_MSG [FAIL]";                                 \
-                       fi;)                    \
-               else                            \
-                       (./$$BASENAME_TEST &&   \
-                       echo "ok 1..$$test_num $$TEST_HDR_MSG [PASS]") ||                                               \
-                       (if [ $$? -eq $$skip ]; then \
-                               echo "not ok 1..$$test_num $$TEST_HDR_MSG [SKIP]"; \
-                       else echo "not ok 1..$$test_num $$TEST_HDR_MSG [FAIL]";                         \
-                       fi;)            \
-               fi;                             \
-               cd - > /dev/null;               \
-       fi;
-endef
-
 define RUN_TESTS
-       @export KSFT_TAP_LEVEL=`echo 1`;                \
-       test_num=`echo 0`;                              \
-       skip=`echo 4`;                                  \
-       echo "TAP version 13";                          \
-       for TEST in $(1); do                            \
-               BASENAME_TEST=`basename $$TEST`;        \
-               test_num=`echo $$test_num+1 | bc`;      \
-               $(call RUN_TEST_PRINT_RESULT,$(TEST),$(BASENAME_TEST),$(test_num),$(skip))                                              \
-       done;
+       @BASE_DIR="$(selfdir)";                 \
+       . $(selfdir)/kselftest/runner.sh;       \
+       if [ "X$(summary)" != "X" ]; then       \
+               per_test_logging=1;             \
+       fi;                                     \
+       run_many $(1)
 endef
 
 run_tests: all
@@ -139,24 +103,12 @@ else
        $(error Error: set INSTALL_PATH to use install)
 endif
 
-define EMIT_TESTS
-       @test_num=`echo 0`;                             \
+emit_tests:
        for TEST in $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_PROGS); do \
                BASENAME_TEST=`basename $$TEST`;        \
-               test_num=`echo $$test_num+1 | bc`;      \
-               TEST_HDR_MSG="selftests: "`basename $$PWD`:" $$BASENAME_TEST";  \
-               echo "echo $$TEST_HDR_MSG";     \
-               if [ ! -x $$TEST ]; then        \
-                       echo "echo \"$$TEST_HDR_MSG: Warning: file $$BASENAME_TEST is not executable, correct this.\"";         \
-                       echo "echo \"not ok 1..$$test_num $$TEST_HDR_MSG [FAIL]\""; \
-               else
-                       echo "(./$$BASENAME_TEST >> \$$OUTPUT 2>&1 && echo \"ok 1..$$test_num $$TEST_HDR_MSG [PASS]\") || (if [ \$$? -eq \$$skip ]; then echo \"not ok 1..$$test_num $$TEST_HDR_MSG [SKIP]\"; else echo \"not ok 1..$$test_num $$TEST_HDR_MSG [FAIL]\"; fi;)"; \
-               fi;             \
-       done;
-endef
-
-emit_tests:
-       $(EMIT_TESTS)
+               echo "  \\";                            \
+               echo -n "       \"$$BASENAME_TEST\"";   \
+       done;                                           \
 
 # define if isn't already. It is undefined in make O= case.
 ifeq ($(RM),)
index 6793f8ecc8e7fc55d2eb1f16bdc04449f7df0a54..70b4ddbf126b059e3336d0e25f74409b59fe52fb 100644 (file)
@@ -304,6 +304,7 @@ static int test_membarrier_query(void)
 int main(int argc, char **argv)
 {
        ksft_print_header();
+       ksft_set_plan(13);
 
        test_membarrier_query();
        test_membarrier();
diff --git a/tools/testing/selftests/pidfd/.gitignore b/tools/testing/selftests/pidfd/.gitignore
new file mode 100644 (file)
index 0000000..822a1e6
--- /dev/null
@@ -0,0 +1 @@
+pidfd_test
index d59378a93782ed4edc2c80e737b178baaa816736..5bae1792e3d6372570e60c733506c2df9ea0ab50 100644 (file)
@@ -371,6 +371,7 @@ static int test_pidfd_send_signal_syscall_support(void)
 int main(int argc, char **argv)
 {
        ksft_print_header();
+       ksft_set_plan(4);
 
        test_pidfd_send_signal_syscall_support();
        test_pidfd_send_signal_simple_success();
index c30c52e1d0d28e28f9743bbe4e043122cf075414..d6469535630af888051a9c50e8059a8a2abfac8a 100644 (file)
@@ -1,5 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0+ OR MIT
-CFLAGS += -O2 -Wall -g -I./ -I../../../../usr/include/ -L./ -Wl,-rpath=./
+
+ifneq ($(shell $(CC) --version 2>&1 | head -n 1 | grep clang),)
+CLANG_FLAGS += -no-integrated-as
+endif
+
+CFLAGS += -O2 -Wall -g -I./ -I../../../../usr/include/ -L./ -Wl,-rpath=./ \
+         $(CLANG_FLAGS)
 LDLIBS += -lpthread
 
 # Own dependencies because we only want to build against 1st prerequisite, but
index 3cea19877227a03c4c501bffa6a687cbe32ad126..84f28f147fb6696a55a4f6bb7bd194368bb1bded 100644 (file)
@@ -5,7 +5,54 @@
  * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
  */
 
-#define RSEQ_SIG       0x53053053
+/*
+ * RSEQ_SIG uses the udf A32 instruction with an uncommon immediate operand
+ * value 0x5de3. This traps if user-space reaches this instruction by mistake,
+ * and the uncommon operand ensures the kernel does not move the instruction
+ * pointer to attacker-controlled code on rseq abort.
+ *
+ * The instruction pattern in the A32 instruction set is:
+ *
+ * e7f5def3    udf    #24035    ; 0x5de3
+ *
+ * This translates to the following instruction pattern in the T16 instruction
+ * set:
+ *
+ * little endian:
+ * def3        udf    #243      ; 0xf3
+ * e7f5        b.n    <7f5>
+ *
+ * pre-ARMv6 big endian code:
+ * e7f5        b.n    <7f5>
+ * def3        udf    #243      ; 0xf3
+ *
+ * ARMv6+ -mbig-endian generates mixed endianness code vs data: little-endian
+ * code and big-endian data. Ensure the RSEQ_SIG data signature matches code
+ * endianness. Prior to ARMv6, -mbig-endian generates big-endian code and data
+ * (which match), so there is no need to reverse the endianness of the data
+ * representation of the signature. However, the choice between BE32 and BE8
+ * is done by the linker, so we cannot know whether code and data endianness
+ * will be mixed before the linker is invoked.
+ */
+
+#define RSEQ_SIG_CODE  0xe7f5def3
+
+#ifndef __ASSEMBLER__
+
+#define RSEQ_SIG_DATA                                                  \
+       ({                                                              \
+               int sig;                                                \
+               asm volatile ("b 2f\n\t"                                \
+                             "1: .inst " __rseq_str(RSEQ_SIG_CODE) "\n\t" \
+                             "2:\n\t"                                  \
+                             "ldr %[sig], 1b\n\t"                      \
+                             : [sig] "=r" (sig));                      \
+               sig;                                                    \
+       })
+
+#define RSEQ_SIG       RSEQ_SIG_DATA
+
+#endif
 
 #define rseq_smp_mb()  __asm__ __volatile__ ("dmb" ::: "memory", "cc")
 #define rseq_smp_rmb() __asm__ __volatile__ ("dmb" ::: "memory", "cc")
@@ -30,18 +77,35 @@ do {                                                                        \
 #include "rseq-skip.h"
 #else /* !RSEQ_SKIP_FASTPATH */
 
-#define __RSEQ_ASM_DEFINE_TABLE(version, flags,        start_ip,               \
+#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip,       \
                                post_commit_offset, abort_ip)           \
-               ".pushsection __rseq_table, \"aw\"\n\t"                 \
+               ".pushsection __rseq_cs, \"aw\"\n\t"                    \
                ".balign 32\n\t"                                        \
+               __rseq_str(label) ":\n\t"                                       \
                ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
                ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
+               ".popsection\n\t"                                       \
+               ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t"          \
+               ".word " __rseq_str(label) "b, 0x0\n\t"                 \
                ".popsection\n\t"
 
-#define RSEQ_ASM_DEFINE_TABLE(start_ip, post_commit_ip, abort_ip)      \
-       __RSEQ_ASM_DEFINE_TABLE(0x0, 0x0, start_ip,                     \
+#define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
+       __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip,              \
                                (post_commit_ip - start_ip), abort_ip)
 
+/*
+ * Exit points of a rseq critical section consist of all instructions outside
+ * of the critical section where a critical section can either branch to or
+ * reach through the normal course of its execution. The abort IP and the
+ * post-commit IP are already part of the __rseq_cs section and should not be
+ * explicitly defined as additional exit points. Knowing all exit points is
+ * useful to assist debuggers stepping over the critical section.
+ */
+#define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip)                  \
+               ".pushsection __rseq_exit_point_array, \"aw\"\n\t"      \
+               ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) ", 0x0\n\t" \
+               ".popsection\n\t"
+
 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs)               \
                RSEQ_INJECT_ASM(1)                                      \
                "adr r0, " __rseq_str(cs_label) "\n\t"                  \
@@ -61,7 +125,8 @@ do {                                                                 \
                __rseq_str(table_label) ":\n\t"                         \
                ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
                ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
-               ".word " __rseq_str(RSEQ_SIG) "\n\t"                    \
+               ".arm\n\t"                                              \
+               ".inst " __rseq_str(RSEQ_SIG_CODE) "\n\t"               \
                __rseq_str(label) ":\n\t"                               \
                teardown                                                \
                "b %l[" __rseq_str(abort_label) "]\n\t"
@@ -86,7 +151,12 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -148,7 +218,12 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -214,7 +289,10 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu)
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -266,7 +344,12 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -336,7 +419,12 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -407,7 +495,13 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -485,7 +579,12 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                "str %[src], %[rseq_scratch0]\n\t"
                "str %[dst], %[rseq_scratch1]\n\t"
                "str %[len], %[rseq_scratch2]\n\t"
@@ -604,7 +703,12 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                "str %[src], %[rseq_scratch0]\n\t"
                "str %[dst], %[rseq_scratch1]\n\t"
                "str %[len], %[rseq_scratch2]\n\t"
index 954f34671ca6bec6cbebc7de44d4a3653d573a71..200dae9e4208c49fc3262d3cc4a5a96cefecf305 100644 (file)
@@ -6,7 +6,20 @@
  * (C) Copyright 2018 - Will Deacon <will.deacon@arm.com>
  */
 
-#define RSEQ_SIG       0xd428bc00      /* BRK #0x45E0 */
+/*
+ * aarch64 -mbig-endian generates mixed endianness code vs data:
+ * little-endian code and big-endian data. Ensure the RSEQ_SIG signature
+ * matches code endianness.
+ */
+#define RSEQ_SIG_CODE  0xd428bc00      /* BRK #0x45E0.  */
+
+#ifdef __AARCH64EB__
+#define RSEQ_SIG_DATA  0x00bc28d4      /* BRK #0x45E0.  */
+#else
+#define RSEQ_SIG_DATA  RSEQ_SIG_CODE
+#endif
+
+#define RSEQ_SIG       RSEQ_SIG_DATA
 
 #define rseq_smp_mb()  __asm__ __volatile__ ("dmb ish" ::: "memory")
 #define rseq_smp_rmb() __asm__ __volatile__ ("dmb ishld" ::: "memory")
@@ -82,19 +95,35 @@ do {                                                                                \
 
 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip,               \
                                post_commit_offset, abort_ip)                   \
-       "       .pushsection    __rseq_table, \"aw\"\n"                         \
+       "       .pushsection    __rseq_cs, \"aw\"\n"                            \
        "       .balign 32\n"                                                   \
        __rseq_str(label) ":\n"                                                 \
        "       .long   " __rseq_str(version) ", " __rseq_str(flags) "\n"       \
        "       .quad   " __rseq_str(start_ip) ", "                             \
                          __rseq_str(post_commit_offset) ", "                   \
                          __rseq_str(abort_ip) "\n"                             \
+       "       .popsection\n\t"                                                \
+       "       .pushsection __rseq_cs_ptr_array, \"aw\"\n"                             \
+       "       .quad " __rseq_str(label) "b\n"                                 \
        "       .popsection\n"
 
 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip)       \
        __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip,                      \
                                (post_commit_ip - start_ip), abort_ip)
 
+/*
+ * Exit points of a rseq critical section consist of all instructions outside
+ * of the critical section where a critical section can either branch to or
+ * reach through the normal course of its execution. The abort IP and the
+ * post-commit IP are already part of the __rseq_cs section and should not be
+ * explicitly defined as additional exit points. Knowing all exit points is
+ * useful to assist debuggers stepping over the critical section.
+ */
+#define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip)                          \
+       "       .pushsection __rseq_exit_point_array, \"aw\"\n"                 \
+       "       .quad " __rseq_str(start_ip) ", " __rseq_str(exit_ip) "\n"      \
+       "       .popsection\n"
+
 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs)                       \
        RSEQ_INJECT_ASM(1)                                                      \
        "       adrp    " RSEQ_ASM_TMP_REG ", " __rseq_str(cs_label) "\n"       \
@@ -105,7 +134,7 @@ do {                                                                                \
 
 #define RSEQ_ASM_DEFINE_ABORT(label, abort_label)                              \
        "       b       222f\n"                                                 \
-       "       .inst   "       __rseq_str(RSEQ_SIG) "\n"                       \
+       "       .inst   "       __rseq_str(RSEQ_SIG_CODE) "\n"                  \
        __rseq_str(label) ":\n"                                                 \
        "       b       %l[" __rseq_str(abort_label) "]\n"                      \
        "222:\n"
@@ -182,6 +211,11 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
+#endif
                RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
                RSEQ_INJECT_ASM(3)
@@ -231,6 +265,11 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
+#endif
                RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
                RSEQ_INJECT_ASM(3)
@@ -282,6 +321,9 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu)
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
+#endif
                RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
                RSEQ_INJECT_ASM(3)
@@ -325,6 +367,11 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
+#endif
                RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
                RSEQ_INJECT_ASM(3)
@@ -379,6 +426,11 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
+#endif
                RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
                RSEQ_INJECT_ASM(3)
@@ -433,6 +485,12 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error3])
+#endif
                RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
                RSEQ_INJECT_ASM(3)
@@ -490,6 +548,11 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
+#endif
                RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
                RSEQ_INJECT_ASM(3)
@@ -545,6 +608,11 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
+#endif
                RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
                RSEQ_INJECT_ASM(3)
index 7f48ecf469941299c68e40bafdc35fae815f5f43..e989e7c14b0972e52c66aba3a676d0e2cc41b448 100644 (file)
@@ -7,7 +7,39 @@
  * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
  */
 
-#define RSEQ_SIG       0x53053053
+/*
+ * RSEQ_SIG uses the break instruction. The instruction pattern is:
+ *
+ * On MIPS:
+ *     0350000d        break     0x350
+ *
+ * On nanoMIPS:
+ *      00100350        break     0x350
+ *
+ * On microMIPS:
+ *      0000d407        break     0x350
+ *
+ * For nanoMIPS32 and microMIPS, the instruction stream is encoded as 16-bit
+ * halfwords, so the signature halfwords need to be swapped accordingly for
+ * little-endian.
+ */
+#if defined(__nanomips__)
+# ifdef __MIPSEL__
+#  define RSEQ_SIG     0x03500010
+# else
+#  define RSEQ_SIG     0x00100350
+# endif
+#elif defined(__mips_micromips)
+# ifdef __MIPSEL__
+#  define RSEQ_SIG     0xd4070000
+# else
+#  define RSEQ_SIG     0x0000d407
+# endif
+#elif defined(__mips__)
+# define RSEQ_SIG      0x0350000d
+#else
+/* Unknown MIPS architecture. */
+#endif
 
 #define rseq_smp_mb()  __asm__ __volatile__ ("sync" ::: "memory")
 #define rseq_smp_rmb() rseq_smp_mb()
@@ -54,20 +86,38 @@ do {                                                                        \
 # error unsupported _MIPS_SZLONG
 #endif
 
-#define __RSEQ_ASM_DEFINE_TABLE(version, flags,        start_ip, \
+#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip, \
                                post_commit_offset, abort_ip) \
-               ".pushsection __rseq_table, \"aw\"\n\t" \
+               ".pushsection __rseq_cs, \"aw\"\n\t" \
                ".balign 32\n\t" \
+               __rseq_str(label) ":\n\t"                                       \
                ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
                LONG " " U32_U64_PAD(__rseq_str(start_ip)) "\n\t" \
                LONG " " U32_U64_PAD(__rseq_str(post_commit_offset)) "\n\t" \
                LONG " " U32_U64_PAD(__rseq_str(abort_ip)) "\n\t" \
+               ".popsection\n\t" \
+               ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
+               LONG " " U32_U64_PAD(__rseq_str(label) "b") "\n\t" \
                ".popsection\n\t"
 
-#define RSEQ_ASM_DEFINE_TABLE(start_ip, post_commit_ip, abort_ip) \
-       __RSEQ_ASM_DEFINE_TABLE(0x0, 0x0, start_ip, \
+#define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
+       __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
                                (post_commit_ip - start_ip), abort_ip)
 
+/*
+ * Exit points of a rseq critical section consist of all instructions outside
+ * of the critical section where a critical section can either branch to or
+ * reach through the normal course of its execution. The abort IP and the
+ * post-commit IP are already part of the __rseq_cs section and should not be
+ * explicitly defined as additional exit points. Knowing all exit points is
+ * useful to assist debuggers stepping over the critical section.
+ */
+#define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
+               ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
+               LONG " " U32_U64_PAD(__rseq_str(start_ip)) "\n\t" \
+               LONG " " U32_U64_PAD(__rseq_str(exit_ip)) "\n\t" \
+               ".popsection\n\t"
+
 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
                RSEQ_INJECT_ASM(1) \
                LONG_LA " $4, " __rseq_str(cs_label) "\n\t" \
@@ -113,7 +163,12 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -173,7 +228,12 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -237,7 +297,10 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu)
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -289,7 +352,12 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -357,7 +425,12 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -426,7 +499,13 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -500,7 +579,12 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                LONG_S " %[src], %[rseq_scratch0]\n\t"
                LONG_S "  %[dst], %[rseq_scratch1]\n\t"
                LONG_S " %[len], %[rseq_scratch2]\n\t"
@@ -616,7 +700,12 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
 
        rseq_workaround_gcc_asm_size_guess();
        __asm__ __volatile__ goto (
-               RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                LONG_S " %[src], %[rseq_scratch0]\n\t"
                LONG_S " %[dst], %[rseq_scratch1]\n\t"
                LONG_S " %[len], %[rseq_scratch2]\n\t"
index 52630c9f42be2998f04a77a9cba702cb72bd16b6..76be90196fe4f1fc09038b5f1a19fa93af91793c 100644 (file)
@@ -6,7 +6,15 @@
  * (C) Copyright 2016-2018 - Boqun Feng <boqun.feng@gmail.com>
  */
 
-#define RSEQ_SIG       0x53053053
+/*
+ * RSEQ_SIG is used with the following trap instruction:
+ *
+ * powerpc-be:    0f e5 00 0b           twui   r5,11
+ * powerpc64-le:  0b 00 e5 0f           twui   r5,11
+ * powerpc64-be:  0f e5 00 0b           twui   r5,11
+ */
+
+#define RSEQ_SIG       0x0fe5000b
 
 #define rseq_smp_mb()          __asm__ __volatile__ ("sync"    ::: "memory", "cc")
 #define rseq_smp_lwsync()      __asm__ __volatile__ ("lwsync"  ::: "memory", "cc")
@@ -33,8 +41,8 @@ do {                                                                  \
 #else /* !RSEQ_SKIP_FASTPATH */
 
 /*
- * The __rseq_table section can be used by debuggers to better handle
- * single-stepping through the restartable critical sections.
+ * The __rseq_cs_ptr_array and __rseq_cs sections can be used by debuggers to
+ * better handle single-stepping through the restartable critical sections.
  */
 
 #ifdef __PPC64__
@@ -46,11 +54,14 @@ do {                                                                        \
 
 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags,                         \
                        start_ip, post_commit_offset, abort_ip)                 \
-               ".pushsection __rseq_table, \"aw\"\n\t"                         \
+               ".pushsection __rseq_cs, \"aw\"\n\t"                            \
                ".balign 32\n\t"                                                \
                __rseq_str(label) ":\n\t"                                       \
                ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t"      \
                ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \
+               ".popsection\n\t"                                               \
+               ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t"                  \
+               ".quad " __rseq_str(label) "b\n\t"                              \
                ".popsection\n\t"
 
 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs)                       \
@@ -63,6 +74,19 @@ do {                                                                 \
                "std %%r17, %[" __rseq_str(rseq_cs) "]\n\t"                     \
                __rseq_str(label) ":\n\t"
 
+/*
+ * Exit points of a rseq critical section consist of all instructions outside
+ * of the critical section where a critical section can either branch to or
+ * reach through the normal course of its execution. The abort IP and the
+ * post-commit IP are already part of the __rseq_cs section and should not be
+ * explicitly defined as additional exit points. Knowing all exit points is
+ * useful to assist debuggers stepping over the critical section.
+ */
+#define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip)                  \
+               ".pushsection __rseq_exit_point_array, \"aw\"\n\t"      \
+               ".quad " __rseq_str(start_ip) ", " __rseq_str(exit_ip) "\n\t" \
+               ".popsection\n\t"
+
 #else /* #ifdef __PPC64__ */
 
 #define STORE_WORD     "stw "
@@ -72,12 +96,29 @@ do {                                                                        \
 
 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags,                         \
                        start_ip, post_commit_offset, abort_ip)                 \
-               ".pushsection __rseq_table, \"aw\"\n\t"                         \
+               ".pushsection __rseq_cs, \"aw\"\n\t"                            \
                ".balign 32\n\t"                                                \
                __rseq_str(label) ":\n\t"                                       \
                ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t"      \
                /* 32-bit only supported on BE */                               \
                ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) "\n\t" \
+               ".popsection\n\t"                                       \
+               ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t"          \
+               ".long 0x0, " __rseq_str(label) "b\n\t"                 \
+               ".popsection\n\t"
+
+/*
+ * Exit points of a rseq critical section consist of all instructions outside
+ * of the critical section where a critical section can either branch to or
+ * reach through the normal course of its execution. The abort IP and the
+ * post-commit IP are already part of the __rseq_cs section and should not be
+ * explicitly defined as additional exit points. Knowing all exit points is
+ * useful to assist debuggers stepping over the critical section.
+ */
+#define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip)                          \
+               ".pushsection __rseq_exit_point_array, \"aw\"\n\t"              \
+               /* 32-bit only supported on BE */                               \
+               ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) "\n\t" \
                ".popsection\n\t"
 
 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs)                       \
@@ -169,6 +210,11 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
                /* cmp cpuid */
@@ -224,6 +270,11 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
                /* cmp cpuid */
@@ -286,6 +337,9 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu)
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
                /* cmp cpuid */
@@ -337,6 +391,11 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
                /* cmp cpuid */
@@ -400,6 +459,11 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
                /* cmp cpuid */
@@ -465,6 +529,12 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
                /* cmp cpuid */
@@ -532,6 +602,11 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* setup for mempcy */
                "mr %%r19, %[len]\n\t"
                "mr %%r20, %[src]\n\t"
@@ -601,6 +676,11 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* setup for mempcy */
                "mr %%r19, %[len]\n\t"
                "mr %%r20, %[src]\n\t"
index 0afdf795797455f8ac61c5e186931a20e588e570..8ef94ad1cbb45224f7eef950a9d51a3e4816f1cf 100644 (file)
@@ -44,22 +44,54 @@ do {                                                                        \
 
 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags,                 \
                                start_ip, post_commit_offset, abort_ip) \
-               ".pushsection __rseq_table, \"aw\"\n\t"                 \
+               ".pushsection __rseq_cs, \"aw\"\n\t"                    \
                ".balign 32\n\t"                                        \
                __rseq_str(label) ":\n\t"                               \
                ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
                ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \
+               ".popsection\n\t"                                       \
+               ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t"          \
+               ".quad " __rseq_str(label) "b\n\t"                      \
+               ".popsection\n\t"
+
+/*
+ * Exit points of a rseq critical section consist of all instructions outside
+ * of the critical section where a critical section can either branch to or
+ * reach through the normal course of its execution. The abort IP and the
+ * post-commit IP are already part of the __rseq_cs section and should not be
+ * explicitly defined as additional exit points. Knowing all exit points is
+ * useful to assist debuggers stepping over the critical section.
+ */
+#define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip)                  \
+               ".pushsection __rseq_exit_point_array, \"aw\"\n\t"      \
+               ".quad " __rseq_str(start_ip) ", " __rseq_str(exit_ip) "\n\t" \
                ".popsection\n\t"
 
 #elif __s390__
 
 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags,                 \
                                start_ip, post_commit_offset, abort_ip) \
-               ".pushsection __rseq_table, \"aw\"\n\t"                 \
+               ".pushsection __rseq_cs, \"aw\"\n\t"                    \
                ".balign 32\n\t"                                        \
                __rseq_str(label) ":\n\t"                               \
                ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
                ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) "\n\t" \
+               ".popsection\n\t"                                       \
+               ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t"          \
+               ".long 0x0, " __rseq_str(label) "b\n\t"                 \
+               ".popsection\n\t"
+
+/*
+ * Exit points of a rseq critical section consist of all instructions outside
+ * of the critical section where a critical section can either branch to or
+ * reach through the normal course of its execution. The abort IP and the
+ * post-commit IP are already part of the __rseq_cs section and should not be
+ * explicitly defined as additional exit points. Knowing all exit points is
+ * useful to assist debuggers stepping over the critical section.
+ */
+#define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip)                  \
+               ".pushsection __rseq_exit_point_array, \"aw\"\n\t"      \
+               ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) "\n\t" \
                ".popsection\n\t"
 
 #define LONG_L                 "l"
@@ -92,14 +124,14 @@ do {                                                                       \
                ".long " __rseq_str(RSEQ_SIG) "\n\t"                    \
                __rseq_str(label) ":\n\t"                               \
                teardown                                                \
-               "j %l[" __rseq_str(abort_label) "]\n\t"                 \
+               "jg %l[" __rseq_str(abort_label) "]\n\t"                \
                ".popsection\n\t"
 
 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label)                \
                ".pushsection __rseq_failure, \"ax\"\n\t"               \
                __rseq_str(label) ":\n\t"                               \
                teardown                                                \
-               "j %l[" __rseq_str(cmpfail_label) "]\n\t"               \
+               "jg %l[" __rseq_str(cmpfail_label) "]\n\t"              \
                ".popsection\n\t"
 
 static inline __attribute__((always_inline))
@@ -109,6 +141,11 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -167,6 +204,11 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -227,6 +269,9 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu)
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -275,6 +320,11 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -346,6 +396,12 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
                RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
                RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
@@ -414,6 +470,11 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                LONG_S " %[src], %[rseq_scratch0]\n\t"
                LONG_S " %[dst], %[rseq_scratch1]\n\t"
                LONG_S " %[len], %[rseq_scratch2]\n\t"
index 089410a314e9df814a0e94cc08cdc2ddfe1f019d..b2da6004fe307931a500d0b50eba52cb46a06645 100644 (file)
@@ -7,8 +7,25 @@
 
 #include <stdint.h>
 
+/*
+ * RSEQ_SIG is used with the following reserved undefined instructions, which
+ * trap in user-space:
+ *
+ * x86-32:    0f b9 3d 53 30 05 53      ud1    0x53053053,%edi
+ * x86-64:    0f b9 3d 53 30 05 53      ud1    0x53053053(%rip),%edi
+ */
 #define RSEQ_SIG       0x53053053
 
+/*
+ * Due to a compiler optimization bug in gcc-8 with asm goto and TLS asm input
+ * operands, we cannot use "m" input operands, and rather pass the __rseq_abi
+ * address through a "r" input operand.
+ */
+
+/* Offset of cpu_id and rseq_cs fields in struct rseq. */
+#define RSEQ_CPU_ID_OFFSET     4
+#define RSEQ_CS_OFFSET         8
+
 #ifdef __x86_64__
 
 #define rseq_smp_mb()  \
@@ -37,32 +54,49 @@ do {                                                                        \
 
 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags,                 \
                                start_ip, post_commit_offset, abort_ip) \
-               ".pushsection __rseq_table, \"aw\"\n\t"                 \
+               ".pushsection __rseq_cs, \"aw\"\n\t"                    \
                ".balign 32\n\t"                                        \
                __rseq_str(label) ":\n\t"                               \
                ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
                ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \
+               ".popsection\n\t"                                       \
+               ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t"          \
+               ".quad " __rseq_str(label) "b\n\t"                      \
                ".popsection\n\t"
 
+
 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
        __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip,              \
                                (post_commit_ip - start_ip), abort_ip)
 
+/*
+ * Exit points of a rseq critical section consist of all instructions outside
+ * of the critical section where a critical section can either branch to or
+ * reach through the normal course of its execution. The abort IP and the
+ * post-commit IP are already part of the __rseq_cs section and should not be
+ * explicitly defined as additional exit points. Knowing all exit points is
+ * useful to assist debuggers stepping over the critical section.
+ */
+#define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip)                  \
+               ".pushsection __rseq_exit_point_array, \"aw\"\n\t"      \
+               ".quad " __rseq_str(start_ip) ", " __rseq_str(exit_ip) "\n\t" \
+               ".popsection\n\t"
+
 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs)               \
                RSEQ_INJECT_ASM(1)                                      \
                "leaq " __rseq_str(cs_label) "(%%rip), %%rax\n\t"       \
-               "movq %%rax, %[" __rseq_str(rseq_cs) "]\n\t"            \
+               "movq %%rax, " __rseq_str(rseq_cs) "\n\t"               \
                __rseq_str(label) ":\n\t"
 
 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label)             \
                RSEQ_INJECT_ASM(2)                                      \
-               "cmpl %[" __rseq_str(cpu_id) "], %[" __rseq_str(current_cpu_id) "]\n\t" \
+               "cmpl %[" __rseq_str(cpu_id) "], " __rseq_str(current_cpu_id) "\n\t" \
                "jnz " __rseq_str(label) "\n\t"
 
 #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label)            \
                ".pushsection __rseq_failure, \"ax\"\n\t"               \
-               /* Disassembler-friendly signature: nopl <sig>(%rip). */\
-               ".byte 0x0f, 0x1f, 0x05\n\t"                            \
+               /* Disassembler-friendly signature: ud1 <sig>(%rip),%edi. */ \
+               ".byte 0x0f, 0xb9, 0x3d\n\t"                            \
                ".long " __rseq_str(RSEQ_SIG) "\n\t"                    \
                __rseq_str(label) ":\n\t"                               \
                teardown                                                \
@@ -83,15 +117,20 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
-               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
                RSEQ_INJECT_ASM(3)
                "cmpq %[v], %[expect]\n\t"
                "jnz %l[cmpfail]\n\t"
                RSEQ_INJECT_ASM(4)
 #ifdef RSEQ_COMPARE_TWICE
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
                "cmpq %[v], %[expect]\n\t"
                "jnz %l[error2]\n\t"
 #endif
@@ -102,8 +141,7 @@ 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),
+                 [rseq_abi]            "r" (&__rseq_abi),
                  [v]                   "m" (*v),
                  [expect]              "r" (expect),
                  [newv]                "r" (newv)
@@ -140,16 +178,21 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
-               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
                RSEQ_INJECT_ASM(3)
                "movq %[v], %%rbx\n\t"
                "cmpq %%rbx, %[expectnot]\n\t"
                "je %l[cmpfail]\n\t"
                RSEQ_INJECT_ASM(4)
 #ifdef RSEQ_COMPARE_TWICE
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
                "movq %[v], %%rbx\n\t"
                "cmpq %%rbx, %[expectnot]\n\t"
                "je %l[error2]\n\t"
@@ -164,8 +207,7 @@ 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),
+                 [rseq_abi]            "r" (&__rseq_abi),
                  /* final store input */
                  [v]                   "m" (*v),
                  [expectnot]           "r" (expectnot),
@@ -199,12 +241,15 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu)
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
-               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
                RSEQ_INJECT_ASM(3)
 #ifdef RSEQ_COMPARE_TWICE
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
 #endif
                /* final store */
                "addq %[count], %[v]\n\t"
@@ -213,8 +258,7 @@ 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),
+                 [rseq_abi]            "r" (&__rseq_abi),
                  /* final store input */
                  [v]                   "m" (*v),
                  [count]               "er" (count)
@@ -244,15 +288,20 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
-               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
                RSEQ_INJECT_ASM(3)
                "cmpq %[v], %[expect]\n\t"
                "jnz %l[cmpfail]\n\t"
                RSEQ_INJECT_ASM(4)
 #ifdef RSEQ_COMPARE_TWICE
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
                "cmpq %[v], %[expect]\n\t"
                "jnz %l[error2]\n\t"
 #endif
@@ -266,8 +315,7 @@ 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),
+                 [rseq_abi]            "r" (&__rseq_abi),
                  /* try store input */
                  [v2]                  "m" (*v2),
                  [newv2]               "r" (newv2),
@@ -314,9 +362,15 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
-               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
                RSEQ_INJECT_ASM(3)
                "cmpq %[v], %[expect]\n\t"
                "jnz %l[cmpfail]\n\t"
@@ -325,7 +379,7 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
                "jnz %l[cmpfail]\n\t"
                RSEQ_INJECT_ASM(5)
 #ifdef RSEQ_COMPARE_TWICE
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
                "cmpq %[v], %[expect]\n\t"
                "jnz %l[error2]\n\t"
                "cmpq %[v2], %[expect2]\n\t"
@@ -338,8 +392,7 @@ 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),
+                 [rseq_abi]            "r" (&__rseq_abi),
                  /* cmp2 input */
                  [v2]                  "m" (*v2),
                  [expect2]             "r" (expect2),
@@ -381,18 +434,23 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                "movq %[src], %[rseq_scratch0]\n\t"
                "movq %[dst], %[rseq_scratch1]\n\t"
                "movq %[len], %[rseq_scratch2]\n\t"
                /* Start rseq by storing table entry pointer into rseq_cs. */
-               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
                RSEQ_INJECT_ASM(3)
                "cmpq %[v], %[expect]\n\t"
                "jnz 5f\n\t"
                RSEQ_INJECT_ASM(4)
 #ifdef RSEQ_COMPARE_TWICE
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f)
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 6f)
                "cmpq %[v], %[expect]\n\t"
                "jnz 7f\n\t"
 #endif
@@ -440,8 +498,7 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
 #endif
                : /* 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),
+                 [rseq_abi]            "r" (&__rseq_abi),
                  /* final store input */
                  [v]                   "m" (*v),
                  [expect]              "r" (expect),
@@ -520,31 +577,47 @@ do {                                                                      \
  */
 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags,                 \
                                start_ip, post_commit_offset, abort_ip) \
-               ".pushsection __rseq_table, \"aw\"\n\t"                 \
+               ".pushsection __rseq_cs, \"aw\"\n\t"                    \
                ".balign 32\n\t"                                        \
                __rseq_str(label) ":\n\t"                               \
                ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
                ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
+               ".popsection\n\t"                                       \
+               ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t"          \
+               ".long " __rseq_str(label) "b, 0x0\n\t"                 \
                ".popsection\n\t"
 
 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
        __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip,              \
                                (post_commit_ip - start_ip), abort_ip)
 
+/*
+ * Exit points of a rseq critical section consist of all instructions outside
+ * of the critical section where a critical section can either branch to or
+ * reach through the normal course of its execution. The abort IP and the
+ * post-commit IP are already part of the __rseq_cs section and should not be
+ * explicitly defined as additional exit points. Knowing all exit points is
+ * useful to assist debuggers stepping over the critical section.
+ */
+#define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip)                  \
+               ".pushsection __rseq_exit_point_array, \"aw\"\n\t"      \
+               ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) ", 0x0\n\t" \
+               ".popsection\n\t"
+
 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs)               \
                RSEQ_INJECT_ASM(1)                                      \
-               "movl $" __rseq_str(cs_label) ", %[rseq_cs]\n\t"        \
+               "movl $" __rseq_str(cs_label) ", " __rseq_str(rseq_cs) "\n\t"   \
                __rseq_str(label) ":\n\t"
 
 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label)             \
                RSEQ_INJECT_ASM(2)                                      \
-               "cmpl %[" __rseq_str(cpu_id) "], %[" __rseq_str(current_cpu_id) "]\n\t" \
+               "cmpl %[" __rseq_str(cpu_id) "], " __rseq_str(current_cpu_id) "\n\t" \
                "jnz " __rseq_str(label) "\n\t"
 
 #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label)            \
                ".pushsection __rseq_failure, \"ax\"\n\t"               \
-               /* Disassembler-friendly signature: nopl <sig>. */      \
-               ".byte 0x0f, 0x1f, 0x05\n\t"                            \
+               /* Disassembler-friendly signature: ud1 <sig>,%edi. */  \
+               ".byte 0x0f, 0xb9, 0x3d\n\t"                            \
                ".long " __rseq_str(RSEQ_SIG) "\n\t"                    \
                __rseq_str(label) ":\n\t"                               \
                teardown                                                \
@@ -565,15 +638,20 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
-               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
                RSEQ_INJECT_ASM(3)
                "cmpl %[v], %[expect]\n\t"
                "jnz %l[cmpfail]\n\t"
                RSEQ_INJECT_ASM(4)
 #ifdef RSEQ_COMPARE_TWICE
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
                "cmpl %[v], %[expect]\n\t"
                "jnz %l[error2]\n\t"
 #endif
@@ -584,8 +662,7 @@ 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),
+                 [rseq_abi]            "r" (&__rseq_abi),
                  [v]                   "m" (*v),
                  [expect]              "r" (expect),
                  [newv]                "r" (newv)
@@ -622,16 +699,21 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
-               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
                RSEQ_INJECT_ASM(3)
                "movl %[v], %%ebx\n\t"
                "cmpl %%ebx, %[expectnot]\n\t"
                "je %l[cmpfail]\n\t"
                RSEQ_INJECT_ASM(4)
 #ifdef RSEQ_COMPARE_TWICE
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
                "movl %[v], %%ebx\n\t"
                "cmpl %%ebx, %[expectnot]\n\t"
                "je %l[error2]\n\t"
@@ -646,8 +728,7 @@ 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),
+                 [rseq_abi]            "r" (&__rseq_abi),
                  /* final store input */
                  [v]                   "m" (*v),
                  [expectnot]           "r" (expectnot),
@@ -681,12 +762,15 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu)
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
-               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
                RSEQ_INJECT_ASM(3)
 #ifdef RSEQ_COMPARE_TWICE
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
 #endif
                /* final store */
                "addl %[count], %[v]\n\t"
@@ -695,8 +779,7 @@ 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),
+                 [rseq_abi]            "r" (&__rseq_abi),
                  /* final store input */
                  [v]                   "m" (*v),
                  [count]               "ir" (count)
@@ -726,15 +809,20 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
-               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
                RSEQ_INJECT_ASM(3)
                "cmpl %[v], %[expect]\n\t"
                "jnz %l[cmpfail]\n\t"
                RSEQ_INJECT_ASM(4)
 #ifdef RSEQ_COMPARE_TWICE
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
                "cmpl %[v], %[expect]\n\t"
                "jnz %l[error2]\n\t"
 #endif
@@ -749,8 +837,7 @@ 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),
+                 [rseq_abi]            "r" (&__rseq_abi),
                  /* try store input */
                  [v2]                  "m" (*v2),
                  [newv2]               "m" (newv2),
@@ -788,16 +875,21 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
-               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
                RSEQ_INJECT_ASM(3)
                "movl %[expect], %%eax\n\t"
                "cmpl %[v], %%eax\n\t"
                "jnz %l[cmpfail]\n\t"
                RSEQ_INJECT_ASM(4)
 #ifdef RSEQ_COMPARE_TWICE
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
                "movl %[expect], %%eax\n\t"
                "cmpl %[v], %%eax\n\t"
                "jnz %l[error2]\n\t"
@@ -813,8 +905,7 @@ 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),
+                 [rseq_abi]            "r" (&__rseq_abi),
                  /* try store input */
                  [v2]                  "m" (*v2),
                  [newv2]               "r" (newv2),
@@ -853,9 +944,15 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
+#endif
                /* Start rseq by storing table entry pointer into rseq_cs. */
-               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
                RSEQ_INJECT_ASM(3)
                "cmpl %[v], %[expect]\n\t"
                "jnz %l[cmpfail]\n\t"
@@ -864,7 +961,7 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
                "jnz %l[cmpfail]\n\t"
                RSEQ_INJECT_ASM(5)
 #ifdef RSEQ_COMPARE_TWICE
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
                "cmpl %[v], %[expect]\n\t"
                "jnz %l[error2]\n\t"
                "cmpl %[expect2], %[v2]\n\t"
@@ -878,8 +975,7 @@ 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),
+                 [rseq_abi]            "r" (&__rseq_abi),
                  /* cmp2 input */
                  [v2]                  "m" (*v2),
                  [expect2]             "r" (expect2),
@@ -922,19 +1018,24 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                "movl %[src], %[rseq_scratch0]\n\t"
                "movl %[dst], %[rseq_scratch1]\n\t"
                "movl %[len], %[rseq_scratch2]\n\t"
                /* Start rseq by storing table entry pointer into rseq_cs. */
-               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
                RSEQ_INJECT_ASM(3)
                "movl %[expect], %%eax\n\t"
                "cmpl %%eax, %[v]\n\t"
                "jnz 5f\n\t"
                RSEQ_INJECT_ASM(4)
 #ifdef RSEQ_COMPARE_TWICE
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f)
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 6f)
                "movl %[expect], %%eax\n\t"
                "cmpl %%eax, %[v]\n\t"
                "jnz 7f\n\t"
@@ -984,8 +1085,7 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
 #endif
                : /* 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),
+                 [rseq_abi]            "r" (&__rseq_abi),
                  /* final store input */
                  [v]                   "m" (*v),
                  [expect]              "m" (expect),
@@ -1030,19 +1130,24 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
 
        __asm__ __volatile__ goto (
                RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
+#endif
                "movl %[src], %[rseq_scratch0]\n\t"
                "movl %[dst], %[rseq_scratch1]\n\t"
                "movl %[len], %[rseq_scratch2]\n\t"
                /* Start rseq by storing table entry pointer into rseq_cs. */
-               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
                RSEQ_INJECT_ASM(3)
                "movl %[expect], %%eax\n\t"
                "cmpl %%eax, %[v]\n\t"
                "jnz 5f\n\t"
                RSEQ_INJECT_ASM(4)
 #ifdef RSEQ_COMPARE_TWICE
-               RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f)
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 6f)
                "movl %[expect], %%eax\n\t"
                "cmpl %%eax, %[v]\n\t"
                "jnz 7f\n\t"
@@ -1093,8 +1198,7 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
 #endif
                : /* 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),
+                 [rseq_abi]            "r" (&__rseq_abi),
                  /* final store input */
                  [v]                   "m" (*v),
                  [expect]              "m" (expect),
index 4847e97ed0498d7dfc3dc8b5c1236d323fa9b454..7159eb777fd34ab7cf128ff2d00744eae1ac0b03 100644 (file)
 #include <syscall.h>
 #include <assert.h>
 #include <signal.h>
+#include <limits.h>
 
 #include "rseq.h"
 
 #define ARRAY_SIZE(arr)        (sizeof(arr) / sizeof((arr)[0]))
 
-__attribute__((tls_model("initial-exec"))) __thread
-volatile struct rseq __rseq_abi = {
+__thread volatile struct rseq __rseq_abi = {
        .cpu_id = RSEQ_CPU_ID_UNINITIALIZED,
 };
 
-static __attribute__((tls_model("initial-exec"))) __thread
-volatile int refcount;
+/*
+ * Shared with other libraries. This library may take rseq ownership if it is
+ * still 0 when executing the library constructor. Set to 1 by library
+ * constructor when handling rseq. Set to 0 in destructor if handling rseq.
+ */
+int __rseq_handled;
+
+/* Whether this library have ownership of rseq registration. */
+static int rseq_ownership;
+
+static __thread volatile uint32_t __rseq_refcount;
 
 static void signal_off_save(sigset_t *oldset)
 {
@@ -69,8 +78,14 @@ int rseq_register_current_thread(void)
        int rc, ret = 0;
        sigset_t oldset;
 
+       if (!rseq_ownership)
+               return 0;
        signal_off_save(&oldset);
-       if (refcount++)
+       if (__rseq_refcount == UINT_MAX) {
+               ret = -1;
+               goto end;
+       }
+       if (__rseq_refcount++)
                goto end;
        rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG);
        if (!rc) {
@@ -78,9 +93,9 @@ int rseq_register_current_thread(void)
                goto end;
        }
        if (errno != EBUSY)
-               __rseq_abi.cpu_id = -2;
+               __rseq_abi.cpu_id = RSEQ_CPU_ID_REGISTRATION_FAILED;
        ret = -1;
-       refcount--;
+       __rseq_refcount--;
 end:
        signal_restore(oldset);
        return ret;
@@ -91,13 +106,20 @@ int rseq_unregister_current_thread(void)
        int rc, ret = 0;
        sigset_t oldset;
 
+       if (!rseq_ownership)
+               return 0;
        signal_off_save(&oldset);
-       if (--refcount)
+       if (!__rseq_refcount) {
+               ret = -1;
+               goto end;
+       }
+       if (--__rseq_refcount)
                goto end;
        rc = sys_rseq(&__rseq_abi, sizeof(struct rseq),
                      RSEQ_FLAG_UNREGISTER, RSEQ_SIG);
        if (!rc)
                goto end;
+       __rseq_refcount = 1;
        ret = -1;
 end:
        signal_restore(oldset);
@@ -115,3 +137,20 @@ int32_t rseq_fallback_current_cpu(void)
        }
        return cpu;
 }
+
+void __attribute__((constructor)) rseq_init(void)
+{
+       /* Check whether rseq is handled by another library. */
+       if (__rseq_handled)
+               return;
+       __rseq_handled = 1;
+       rseq_ownership = 1;
+}
+
+void __attribute__((destructor)) rseq_fini(void)
+{
+       if (!rseq_ownership)
+               return;
+       __rseq_handled = 0;
+       rseq_ownership = 0;
+}
index 6c1126e7f685f6d538a0204bffddb6da1d7bdde8..d40d60e7499e8aa2f814f7282092692db84fcf73 100644 (file)
@@ -44,6 +44,7 @@
 #endif
 
 extern __thread volatile struct rseq __rseq_abi;
+extern int __rseq_handled;
 
 #define rseq_likely(x)         __builtin_expect(!!(x), 1)
 #define rseq_unlikely(x)       __builtin_expect(!!(x), 0)
index 228c2ae47687dd753250e696456f7fcedb99b17a..ad0f8df2ca0af7bccd6a6bd46d36d22480503675 100644 (file)
@@ -109,6 +109,7 @@ int main(void)
        int err;
 
        ksft_print_header();
+       ksft_set_plan(3);
 
        sigemptyset(&act.sa_mask);
        act.sa_flags = SA_ONSTACK | SA_SIGINFO;
index 7f7938263c5c5d84ac0914f7ab4e012cd882f4ed..3824b66f41a095d6bb84a82048105ca8b4343df9 100644 (file)
@@ -86,6 +86,7 @@ int main(void)
        int err;
 
        ksft_print_header();
+       ksft_set_plan(3 + 7);
 
        sync_api_supported();
 
index 780ce71233743f4c3b9b36e9435f9eae2d676641..6a970b127c9b3c2d979255b35ada380ba88fe281 100755 (executable)
@@ -24,19 +24,21 @@ TEST_FILE=$(mktemp)
 
 # This represents
 #
-# TEST_ID:TEST_COUNT:ENABLED
+# TEST_ID:TEST_COUNT:ENABLED:TARGET
 #
 # TEST_ID: is the test id number
 # TEST_COUNT: number of times we should run the test
 # ENABLED: 1 if enabled, 0 otherwise
+# TARGET: test target file required on the test_sysctl module
 #
 # Once these are enabled please leave them as-is. Write your own test,
 # we have tons of space.
-ALL_TESTS="0001:1:1"
-ALL_TESTS="$ALL_TESTS 0002:1:1"
-ALL_TESTS="$ALL_TESTS 0003:1:1"
-ALL_TESTS="$ALL_TESTS 0004:1:1"
-ALL_TESTS="$ALL_TESTS 0005:3:1"
+ALL_TESTS="0001:1:1:int_0001"
+ALL_TESTS="$ALL_TESTS 0002:1:1:string_0001"
+ALL_TESTS="$ALL_TESTS 0003:1:1:int_0002"
+ALL_TESTS="$ALL_TESTS 0004:1:1:uint_0001"
+ALL_TESTS="$ALL_TESTS 0005:3:1:int_0003"
+ALL_TESTS="$ALL_TESTS 0006:50:1:bitmap_0001"
 
 test_modprobe()
 {
@@ -149,6 +151,9 @@ reset_vals()
                string_0001)
                        VAL="(none)"
                        ;;
+               bitmap_0001)
+                       VAL=""
+                       ;;
                *)
                        ;;
        esac
@@ -157,8 +162,10 @@ reset_vals()
 
 set_orig()
 {
-       if [ ! -z $TARGET ]; then
-               echo "${ORIG}" > "${TARGET}"
+       if [ ! -z $TARGET ] && [ ! -z $ORIG ]; then
+               if [ -f ${TARGET} ]; then
+                       echo "${ORIG}" > "${TARGET}"
+               fi
        fi
 }
 
@@ -177,9 +184,25 @@ verify()
        return 0
 }
 
+# proc files get read a page at a time, which can confuse diff,
+# and get you incorrect results on proc files with long data. To use
+# diff against them you must first extract the output to a file, and
+# then compare against that file.
+verify_diff_proc_file()
+{
+       TMP_DUMP_FILE=$(mktemp)
+       cat $1 > $TMP_DUMP_FILE
+
+       if ! diff -w -q $TMP_DUMP_FILE $2; then
+               return 1
+       else
+               return 0
+       fi
+}
+
 verify_diff_w()
 {
-       echo "$TEST_STR" | diff -q -w -u - $1
+       echo "$TEST_STR" | diff -q -w -u - $1 > /dev/null
        return $?
 }
 
@@ -600,9 +623,70 @@ run_stringtests()
        test_rc
 }
 
+target_exists()
+{
+       TARGET="${SYSCTL}/$1"
+       TEST_ID="$2"
+
+       if [ ! -f ${TARGET} ] ; then
+               echo "Target for test $TEST_ID: $TARGET not exist, skipping test ..."
+               return 0
+       fi
+       return 1
+}
+
+run_bitmaptest() {
+       # Total length of bitmaps string to use, a bit under
+       # the maximum input size of the test node
+       LENGTH=$((RANDOM % 65000))
+
+       # First bit to set
+       BIT=$((RANDOM % 1024))
+
+       # String containing our list of bits to set
+       TEST_STR=$BIT
+
+       # build up the string
+       while [ "${#TEST_STR}" -le "$LENGTH" ]; do
+               # Make sure next entry is discontiguous,
+               # skip ahead at least 2
+               BIT=$((BIT + $((2 + RANDOM % 10))))
+
+               # Add new bit to the list
+               TEST_STR="${TEST_STR},${BIT}"
+
+               # Randomly make it a range
+               if [ "$((RANDOM % 2))" -eq "1" ]; then
+                       RANGE_END=$((BIT + $((1 + RANDOM % 10))))
+                       TEST_STR="${TEST_STR}-${RANGE_END}"
+                       BIT=$RANGE_END
+               fi
+       done
+
+       echo -n "Checking bitmap handler... "
+       TEST_FILE=$(mktemp)
+       echo -n "$TEST_STR" > $TEST_FILE
+
+       cat $TEST_FILE > $TARGET 2> /dev/null
+       if [ $? -ne 0 ]; then
+               echo "FAIL" >&2
+               rc=1
+               test_rc
+       fi
+
+       if ! verify_diff_proc_file "$TARGET" "$TEST_FILE"; then
+               echo "FAIL" >&2
+               rc=1
+       else
+               echo "ok"
+               rc=0
+       fi
+       test_rc
+}
+
 sysctl_test_0001()
 {
-       TARGET="${SYSCTL}/int_0001"
+       TARGET="${SYSCTL}/$(get_test_target 0001)"
        reset_vals
        ORIG=$(cat "${TARGET}")
        TEST_STR=$(( $ORIG + 1 ))
@@ -614,7 +698,7 @@ sysctl_test_0001()
 
 sysctl_test_0002()
 {
-       TARGET="${SYSCTL}/string_0001"
+       TARGET="${SYSCTL}/$(get_test_target 0002)"
        reset_vals
        ORIG=$(cat "${TARGET}")
        TEST_STR="Testing sysctl"
@@ -627,7 +711,7 @@ sysctl_test_0002()
 
 sysctl_test_0003()
 {
-       TARGET="${SYSCTL}/int_0002"
+       TARGET="${SYSCTL}/$(get_test_target 0003)"
        reset_vals
        ORIG=$(cat "${TARGET}")
        TEST_STR=$(( $ORIG + 1 ))
@@ -640,7 +724,7 @@ sysctl_test_0003()
 
 sysctl_test_0004()
 {
-       TARGET="${SYSCTL}/uint_0001"
+       TARGET="${SYSCTL}/$(get_test_target 0004)"
        reset_vals
        ORIG=$(cat "${TARGET}")
        TEST_STR=$(( $ORIG + 1 ))
@@ -653,13 +737,21 @@ sysctl_test_0004()
 
 sysctl_test_0005()
 {
-       TARGET="${SYSCTL}/int_0003"
+       TARGET="${SYSCTL}/$(get_test_target 0005)"
        reset_vals
        ORIG=$(cat "${TARGET}")
 
        run_limit_digit_int_array
 }
 
+sysctl_test_0006()
+{
+       TARGET="${SYSCTL}/bitmap_0001"
+       reset_vals
+       ORIG=""
+       run_bitmaptest
+}
+
 list_tests()
 {
        echo "Test ID list:"
@@ -673,10 +765,9 @@ list_tests()
        echo "0003 x $(get_test_count 0003) - tests proc_dointvec()"
        echo "0004 x $(get_test_count 0004) - tests proc_douintvec()"
        echo "0005 x $(get_test_count 0005) - tests proc_douintvec() array"
+       echo "0006 x $(get_test_count 0006) - tests proc_do_large_bitmap()"
 }
 
-test_reqs
-
 usage()
 {
        NUM_TESTS=$(grep -o ' ' <<<"$ALL_TESTS" | grep -c .)
@@ -724,25 +815,35 @@ function get_test_count()
 {
        test_num $1
        TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
-       LAST_TWO=${TEST_DATA#*:*}
-       echo ${LAST_TWO%:*}
+       echo ${TEST_DATA} | awk -F":" '{print $2}'
 }
 
 function get_test_enabled()
 {
        test_num $1
        TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
-       echo ${TEST_DATA#*:*:}
+       echo ${TEST_DATA} | awk -F":" '{print $3}'
+}
+
+function get_test_target()
+{
+       test_num $1
+       TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
+       echo ${TEST_DATA} | awk -F":" '{print $4}'
 }
 
 function run_all_tests()
 {
        for i in $ALL_TESTS ; do
-               TEST_ID=${i%:*:*}
+               TEST_ID=${i%:*:*:*}
                ENABLED=$(get_test_enabled $TEST_ID)
                TEST_COUNT=$(get_test_count $TEST_ID)
+               TEST_TARGET=$(get_test_target $TEST_ID)
+               if target_exists $TEST_TARGET $TEST_ID; then
+                       continue
+               fi
                if [[ $ENABLED -eq "1" ]]; then
-                       test_case $TEST_ID $TEST_COUNT
+                       test_case $TEST_ID $TEST_COUNT $TEST_TARGET
                fi
        done
 }
@@ -775,12 +876,14 @@ function watch_case()
 
 function test_case()
 {
-       NUM_TESTS=$DEFAULT_NUM_TESTS
-       if [ $# -eq 2 ]; then
-               NUM_TESTS=$2
-       fi
+       NUM_TESTS=$2
 
        i=0
+
+       if target_exists $3 $1; then
+               continue
+       fi
+
        while [ $i -lt $NUM_TESTS ]; do
                test_num $1
                watch_log $i ${TEST_NAME}_test_$1 noclear
@@ -803,15 +906,15 @@ function parse_args()
                elif [[ "$1" = "-t" ]]; then
                        shift
                        test_num $1
-                       test_case $1 $(get_test_count $1)
+                       test_case $1 $(get_test_count $1) $(get_test_target $1)
                elif [[ "$1" = "-c" ]]; then
                        shift
                        test_num $1
                        test_num $2
-                       test_case $1 $2
+                       test_case $1 $2 $(get_test_target $1)
                elif [[ "$1" = "-s" ]]; then
                        shift
-                       test_case $1 1
+                       test_case $1 1 $(get_test_target $1)
                elif [[ "$1" = "-l" ]]; then
                        list_tests
                elif [[ "$1" = "-h" || "$1" = "--help" ]]; then
@@ -825,8 +928,8 @@ function parse_args()
 test_reqs
 allow_user_defaults
 check_production_sysctl_writes_strict
-test_modprobe
 load_req_mod
+test_modprobe
 
 trap "test_finish" EXIT
 
index 2d566fbd236bed5d3f7d600e7d4bde628f2df8ae..c9b26335f891452c168d00487ff92634a9ac6a14 100644 (file)
@@ -18,7 +18,6 @@
 #define ALIGN(x, a) (((x) + (a) - 1) / (a) * (a))
 #define SIZE_MAX        (~(size_t)0)
 #define KMALLOC_MAX_SIZE SIZE_MAX
-#define BUG_ON(x) assert(x)
 
 typedef pthread_spinlock_t  spinlock_t;
 
index ea434ddc849925c6e2577a9ed6acea906ea8eafd..aad9284c043a029481072a8d802400902fd730fb 100644 (file)
@@ -57,3 +57,6 @@ config HAVE_KVM_VCPU_ASYNC_IOCTL
 
 config HAVE_KVM_VCPU_RUN_PID_CHANGE
        bool
+
+config HAVE_KVM_NO_POLL
+       bool
index f412ebc906100e4b5df5e4d30ef1ab9cc68d1c07..90cedebaeb9418cb830dbd33cf58fa51840d4d00 100644 (file)
@@ -56,7 +56,7 @@
 __asm__(".arch_extension       virt");
 #endif
 
-DEFINE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state);
+DEFINE_PER_CPU(kvm_host_data_t, kvm_host_data);
 static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page);
 
 /* Per-CPU variable containing the currently running vcpu. */
@@ -224,9 +224,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_MAX_VCPUS:
                r = KVM_MAX_VCPUS;
                break;
-       case KVM_CAP_NR_MEMSLOTS:
-               r = KVM_USER_MEM_SLOTS;
-               break;
        case KVM_CAP_MSI_DEVID:
                if (!kvm)
                        r = -EINVAL;
@@ -360,8 +357,10 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
        int *last_ran;
+       kvm_host_data_t *cpu_data;
 
        last_ran = this_cpu_ptr(vcpu->kvm->arch.last_vcpu_ran);
+       cpu_data = this_cpu_ptr(&kvm_host_data);
 
        /*
         * We might get preempted before the vCPU actually runs, but
@@ -373,18 +372,21 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        }
 
        vcpu->cpu = cpu;
-       vcpu->arch.host_cpu_context = this_cpu_ptr(&kvm_host_cpu_state);
+       vcpu->arch.host_cpu_context = &cpu_data->host_ctxt;
 
        kvm_arm_set_running_vcpu(vcpu);
        kvm_vgic_load(vcpu);
        kvm_timer_vcpu_load(vcpu);
        kvm_vcpu_load_sysregs(vcpu);
        kvm_arch_vcpu_load_fp(vcpu);
+       kvm_vcpu_pmu_restore_guest(vcpu);
 
        if (single_task_running())
                vcpu_clear_wfe_traps(vcpu);
        else
                vcpu_set_wfe_traps(vcpu);
+
+       vcpu_ptrauth_setup_lazy(vcpu);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
@@ -393,6 +395,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
        kvm_vcpu_put_sysregs(vcpu);
        kvm_timer_vcpu_put(vcpu);
        kvm_vgic_put(vcpu);
+       kvm_vcpu_pmu_restore_host(vcpu);
 
        vcpu->cpu = -1;
 
@@ -545,6 +548,9 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
        if (likely(vcpu->arch.has_run_once))
                return 0;
 
+       if (!kvm_arm_vcpu_is_finalized(vcpu))
+               return -EPERM;
+
        vcpu->arch.has_run_once = true;
 
        if (likely(irqchip_in_kernel(kvm))) {
@@ -1121,6 +1127,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                if (unlikely(!kvm_vcpu_initialized(vcpu)))
                        break;
 
+               r = -EPERM;
+               if (!kvm_arm_vcpu_is_finalized(vcpu))
+                       break;
+
                r = -EFAULT;
                if (copy_from_user(&reg_list, user_list, sizeof(reg_list)))
                        break;
@@ -1174,6 +1184,17 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 
                return kvm_arm_vcpu_set_events(vcpu, &events);
        }
+       case KVM_ARM_VCPU_FINALIZE: {
+               int what;
+
+               if (!kvm_vcpu_initialized(vcpu))
+                       return -ENOEXEC;
+
+               if (get_user(what, (const int __user *)argp))
+                       return -EFAULT;
+
+               return kvm_arm_vcpu_finalize(vcpu, what);
+       }
        default:
                r = -EINVAL;
        }
@@ -1554,11 +1575,11 @@ static int init_hyp_mode(void)
        }
 
        for_each_possible_cpu(cpu) {
-               kvm_cpu_context_t *cpu_ctxt;
+               kvm_host_data_t *cpu_data;
 
-               cpu_ctxt = per_cpu_ptr(&kvm_host_cpu_state, cpu);
-               kvm_init_host_cpu_context(cpu_ctxt, cpu);
-               err = create_hyp_mappings(cpu_ctxt, cpu_ctxt + 1, PAGE_HYP);
+               cpu_data = per_cpu_ptr(&kvm_host_data, cpu);
+               kvm_init_host_cpu_context(&cpu_data->host_ctxt, cpu);
+               err = create_hyp_mappings(cpu_data, cpu_data + 1, PAGE_HYP);
 
                if (err) {
                        kvm_err("Cannot map host CPU state: %d\n", err);
@@ -1669,6 +1690,10 @@ int kvm_arch_init(void *opaque)
        if (err)
                return err;
 
+       err = kvm_arm_init_sve();
+       if (err)
+               return err;
+
        if (!in_hyp_mode) {
                err = init_hyp_mode();
                if (err)
index a704d1f9bd962e99d3b6fb927cbf0d3574dc1f41..f0d13d9d125ddc46e016a5dc5fdbcc10dff3a160 100644 (file)
@@ -51,9 +51,9 @@
 #include <linux/slab.h>
 #include <linux/sort.h>
 #include <linux/bsearch.h>
+#include <linux/io.h>
 
 #include <asm/processor.h>
-#include <asm/io.h>
 #include <asm/ioctl.h>
 #include <linux/uaccess.h>
 #include <asm/pgtable.h>
@@ -391,7 +391,8 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
        spin_unlock(&kvm->mmu_lock);
 
        ret = kvm_arch_mmu_notifier_invalidate_range(kvm, range->start,
-                                       range->end, range->blockable);
+                                       range->end,
+                                       mmu_notifier_range_blockable(range));
 
        srcu_read_unlock(&kvm->srcu, idx);
 
@@ -1134,11 +1135,11 @@ EXPORT_SYMBOL_GPL(kvm_get_dirty_log);
 
 #ifdef CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT
 /**
- * kvm_get_dirty_log_protect - get a snapshot of dirty pages, and if any pages
+ * kvm_get_dirty_log_protect - get a snapshot of dirty pages
  *     and reenable dirty page tracking for the corresponding pages.
  * @kvm:       pointer to kvm instance
  * @log:       slot id and address to which we copy the log
- * @is_dirty:  flag set if any page is dirty
+ * @flush:     true if TLB flush is needed by caller
  *
  * We need to keep it in mind that VCPU threads can write to the bitmap
  * concurrently. So, to avoid losing track of dirty pages we keep the
@@ -1223,6 +1224,7 @@ EXPORT_SYMBOL_GPL(kvm_get_dirty_log_protect);
  *     and reenable dirty page tracking for the corresponding pages.
  * @kvm:       pointer to kvm instance
  * @log:       slot id and address from which to fetch the bitmap of dirty pages
+ * @flush:     true if TLB flush is needed by caller
  */
 int kvm_clear_dirty_log_protect(struct kvm *kvm,
                                struct kvm_clear_dirty_log *log, bool *flush)
@@ -1250,7 +1252,7 @@ int kvm_clear_dirty_log_protect(struct kvm *kvm,
        if (!dirty_bitmap)
                return -ENOENT;
 
-       n = kvm_dirty_bitmap_bytes(memslot);
+       n = ALIGN(log->num_pages, BITS_PER_LONG) / 8;
 
        if (log->first_page > memslot->npages ||
            log->num_pages > memslot->npages - log->first_page ||
@@ -1263,8 +1265,8 @@ int kvm_clear_dirty_log_protect(struct kvm *kvm,
                return -EFAULT;
 
        spin_lock(&kvm->mmu_lock);
-       for (offset = log->first_page,
-            i = offset / BITS_PER_LONG, n = log->num_pages / BITS_PER_LONG; n--;
+       for (offset = log->first_page, i = offset / BITS_PER_LONG,
+                n = DIV_ROUND_UP(log->num_pages, BITS_PER_LONG); n--;
             i++, offset += BITS_PER_LONG) {
                unsigned long mask = *dirty_bitmap_buffer++;
                atomic_long_t *p = (atomic_long_t *) &dirty_bitmap[i];
@@ -1741,6 +1743,70 @@ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
 }
 EXPORT_SYMBOL_GPL(gfn_to_page);
 
+static int __kvm_map_gfn(struct kvm_memory_slot *slot, gfn_t gfn,
+                        struct kvm_host_map *map)
+{
+       kvm_pfn_t pfn;
+       void *hva = NULL;
+       struct page *page = KVM_UNMAPPED_PAGE;
+
+       if (!map)
+               return -EINVAL;
+
+       pfn = gfn_to_pfn_memslot(slot, gfn);
+       if (is_error_noslot_pfn(pfn))
+               return -EINVAL;
+
+       if (pfn_valid(pfn)) {
+               page = pfn_to_page(pfn);
+               hva = kmap(page);
+       } else {
+               hva = memremap(pfn_to_hpa(pfn), PAGE_SIZE, MEMREMAP_WB);
+       }
+
+       if (!hva)
+               return -EFAULT;
+
+       map->page = page;
+       map->hva = hva;
+       map->pfn = pfn;
+       map->gfn = gfn;
+
+       return 0;
+}
+
+int kvm_vcpu_map(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map)
+{
+       return __kvm_map_gfn(kvm_vcpu_gfn_to_memslot(vcpu, gfn), gfn, map);
+}
+EXPORT_SYMBOL_GPL(kvm_vcpu_map);
+
+void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map,
+                   bool dirty)
+{
+       if (!map)
+               return;
+
+       if (!map->hva)
+               return;
+
+       if (map->page)
+               kunmap(map->page);
+       else
+               memunmap(map->hva);
+
+       if (dirty) {
+               kvm_vcpu_mark_page_dirty(vcpu, map->gfn);
+               kvm_release_pfn_dirty(map->pfn);
+       } else {
+               kvm_release_pfn_clean(map->pfn);
+       }
+
+       map->hva = NULL;
+       map->page = NULL;
+}
+EXPORT_SYMBOL_GPL(kvm_vcpu_unmap);
+
 struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn)
 {
        kvm_pfn_t pfn;
@@ -2254,7 +2320,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
        u64 block_ns;
 
        start = cur = ktime_get();
-       if (vcpu->halt_poll_ns) {
+       if (vcpu->halt_poll_ns && !kvm_arch_no_poll(vcpu)) {
                ktime_t stop = ktime_add_ns(ktime_get(), vcpu->halt_poll_ns);
 
                ++vcpu->stat.halt_attempted_poll;
@@ -2885,6 +2951,16 @@ out:
 }
 #endif
 
+static int kvm_device_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct kvm_device *dev = filp->private_data;
+
+       if (dev->ops->mmap)
+               return dev->ops->mmap(dev, vma);
+
+       return -ENODEV;
+}
+
 static int kvm_device_ioctl_attr(struct kvm_device *dev,
                                 int (*accessor)(struct kvm_device *dev,
                                                 struct kvm_device_attr *attr),
@@ -2929,6 +3005,13 @@ static int kvm_device_release(struct inode *inode, struct file *filp)
        struct kvm_device *dev = filp->private_data;
        struct kvm *kvm = dev->kvm;
 
+       if (dev->ops->release) {
+               mutex_lock(&kvm->lock);
+               list_del(&dev->vm_node);
+               dev->ops->release(dev);
+               mutex_unlock(&kvm->lock);
+       }
+
        kvm_put_kvm(kvm);
        return 0;
 }
@@ -2937,6 +3020,7 @@ static const struct file_operations kvm_device_fops = {
        .unlocked_ioctl = kvm_device_ioctl,
        .release = kvm_device_release,
        KVM_COMPAT(kvm_device_ioctl),
+       .mmap = kvm_device_mmap,
 };
 
 struct kvm_device *kvm_device_from_filp(struct file *filp)
@@ -3045,7 +3129,7 @@ static long kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
        case KVM_CAP_CHECK_EXTENSION_VM:
        case KVM_CAP_ENABLE_CAP_VM:
 #ifdef CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT
-       case KVM_CAP_MANUAL_DIRTY_LOG_PROTECT:
+       case KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2:
 #endif
                return 1;
 #ifdef CONFIG_KVM_MMIO
@@ -3064,6 +3148,8 @@ static long kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
 #endif
        case KVM_CAP_MAX_VCPU_ID:
                return KVM_MAX_VCPU_ID;
+       case KVM_CAP_NR_MEMSLOTS:
+               return KVM_USER_MEM_SLOTS;
        default:
                break;
        }
@@ -3081,7 +3167,7 @@ static int kvm_vm_ioctl_enable_cap_generic(struct kvm *kvm,
 {
        switch (cap->cap) {
 #ifdef CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT
-       case KVM_CAP_MANUAL_DIRTY_LOG_PROTECT:
+       case KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2:
                if (cap->flags || (cap->args[0] & ~1))
                        return -EINVAL;
                kvm->manual_dirty_log_protect = cap->args[0];